From 1c146f70e9cab2af74e35fba0983002d1c614225 Mon Sep 17 00:00:00 2001 From: Kristoffer Dalby Date: Thu, 13 Nov 2025 15:49:27 +0100 Subject: [PATCH] db: remove _schema from migration tests Previously we tested migrations on schemas and dumps of old databases. The problems with testing migrations against the schemas is that the migration table is empty, so we try to run migrations that are already ran on that schema, which might blow up. This commit removes the schema approach and just leaves all the dumps, which include the migration table. Signed-off-by: Kristoffer Dalby --- hscontrol/db/db_test.go | 9 ++++--- .../sqlite/headscale_0.26.0-beta.1_schema.sql | 12 ---------- .../sqlite/headscale_0.26.0-beta.2_schema.sql | 12 ---------- .../sqlite/headscale_0.26.0_schema.sql | 12 ---------- ...l => headscale_0.26.1_dump-litestream.sql} | 24 +++++++++++++++++-- .../sqlite/headscale_0.26.1_schema.sql | 12 ---------- 6 files changed, 26 insertions(+), 55 deletions(-) delete mode 100644 hscontrol/db/testdata/sqlite/headscale_0.26.0-beta.1_schema.sql delete mode 100644 hscontrol/db/testdata/sqlite/headscale_0.26.0-beta.2_schema.sql delete mode 100644 hscontrol/db/testdata/sqlite/headscale_0.26.0_schema.sql rename hscontrol/db/testdata/sqlite/{headscale_0.26.1_schema-litestream.sql => headscale_0.26.1_dump-litestream.sql} (72%) delete mode 100644 hscontrol/db/testdata/sqlite/headscale_0.26.1_schema.sql diff --git a/hscontrol/db/db_test.go b/hscontrol/db/db_test.go index a0d0a4ca..2a30027e 100644 --- a/hscontrol/db/db_test.go +++ b/hscontrol/db/db_test.go @@ -315,11 +315,10 @@ func dbForTestWithPath(t *testing.T, sqlFilePath string) *HSDatabase { // in the testdata directory. It verifies they can be successfully migrated to the current // schema version. This test only validates migration success, not data integrity. // -// A lot of the schemas have been automatically generated with old Headscale binaries on empty databases -// (no user/node data): -// - `headscale__schema.sql` (created with `sqlite3 headscale.db .schema`) -// - `headscale__dump.sql` (created with `sqlite3 headscale.db .dump`) -// where `_dump.sql` contains the migration steps that have been applied to the database. +// All test database files are SQL dumps (created with `sqlite3 headscale.db .dump`) generated +// with old Headscale binaries on empty databases (no user/node data). These dumps include the +// migration history in the `migrations` table, which allows the migration system to correctly +// skip already-applied migrations and only run new ones. func TestSQLiteAllTestdataMigrations(t *testing.T) { t.Parallel() schemas, err := os.ReadDir("testdata/sqlite") diff --git a/hscontrol/db/testdata/sqlite/headscale_0.26.0-beta.1_schema.sql b/hscontrol/db/testdata/sqlite/headscale_0.26.0-beta.1_schema.sql deleted file mode 100644 index 9cdab563..00000000 --- a/hscontrol/db/testdata/sqlite/headscale_0.26.0-beta.1_schema.sql +++ /dev/null @@ -1,12 +0,0 @@ -CREATE TABLE `migrations` (`id` text,PRIMARY KEY (`id`)); -CREATE TABLE `users` (`id` integer PRIMARY KEY AUTOINCREMENT,`created_at` datetime,`updated_at` datetime,`deleted_at` datetime,`name` text,`display_name` text,`email` text,`provider_identifier` text,`provider` text,`profile_pic_url` text); -CREATE INDEX `idx_users_deleted_at` ON `users`(`deleted_at`); -CREATE TABLE `pre_auth_keys` (`id` integer PRIMARY KEY AUTOINCREMENT,`key` text,`user_id` integer,`reusable` numeric,`ephemeral` numeric DEFAULT false,`used` numeric DEFAULT false,`tags` text,`created_at` datetime,`expiration` datetime,CONSTRAINT `fk_pre_auth_keys_user` FOREIGN KEY (`user_id`) REFERENCES `users`(`id`) ON DELETE SET NULL); -CREATE TABLE `api_keys` (`id` integer PRIMARY KEY AUTOINCREMENT,`prefix` text,`hash` blob,`created_at` datetime,`expiration` datetime,`last_seen` datetime); -CREATE UNIQUE INDEX `idx_api_keys_prefix` ON `api_keys`(`prefix`); -CREATE TABLE `policies` (`id` integer PRIMARY KEY AUTOINCREMENT,`created_at` datetime,`updated_at` datetime,`deleted_at` datetime,`data` text); -CREATE INDEX `idx_policies_deleted_at` ON `policies`(`deleted_at`); -CREATE UNIQUE INDEX idx_provider_identifier ON users (provider_identifier) WHERE provider_identifier IS NOT NULL; -CREATE UNIQUE INDEX idx_name_provider_identifier ON users (name,provider_identifier); -CREATE UNIQUE INDEX idx_name_no_provider_identifier ON users (name) WHERE provider_identifier IS NULL; -CREATE TABLE IF NOT EXISTS "nodes" (`id` integer PRIMARY KEY AUTOINCREMENT,`machine_key` text,`node_key` text,`disco_key` text,`endpoints` text,`host_info` text,`ipv4` text,`ipv6` text,`hostname` text,`given_name` varchar(63),`user_id` integer,`register_method` text,`forced_tags` text,`auth_key_id` integer,`expiry` datetime,`approved_routes` text,`created_at` datetime,`updated_at` datetime,`deleted_at` datetime,CONSTRAINT `fk_nodes_auth_key` FOREIGN KEY (`auth_key_id`) REFERENCES `pre_auth_keys`(`id`),CONSTRAINT `fk_nodes_user` FOREIGN KEY (`user_id`) REFERENCES `users`(`id`) ON DELETE CASCADE); diff --git a/hscontrol/db/testdata/sqlite/headscale_0.26.0-beta.2_schema.sql b/hscontrol/db/testdata/sqlite/headscale_0.26.0-beta.2_schema.sql deleted file mode 100644 index 2a5c360d..00000000 --- a/hscontrol/db/testdata/sqlite/headscale_0.26.0-beta.2_schema.sql +++ /dev/null @@ -1,12 +0,0 @@ -CREATE TABLE `migrations` (`id` text,PRIMARY KEY (`id`)); -CREATE TABLE `users` (`id` integer PRIMARY KEY AUTOINCREMENT,`created_at` datetime,`updated_at` datetime,`deleted_at` datetime,`name` text,`display_name` text,`email` text,`provider_identifier` text,`provider` text,`profile_pic_url` text); -CREATE INDEX `idx_users_deleted_at` ON `users`(`deleted_at`); -CREATE TABLE `pre_auth_keys` (`id` integer PRIMARY KEY AUTOINCREMENT,`key` text,`user_id` integer,`reusable` numeric,`ephemeral` numeric DEFAULT false,`used` numeric DEFAULT false,`tags` text,`created_at` datetime,`expiration` datetime,CONSTRAINT `fk_pre_auth_keys_user` FOREIGN KEY (`user_id`) REFERENCES `users`(`id`) ON DELETE SET NULL); -CREATE TABLE `api_keys` (`id` integer PRIMARY KEY AUTOINCREMENT,`prefix` text,`hash` blob,`created_at` datetime,`expiration` datetime,`last_seen` datetime); -CREATE UNIQUE INDEX `idx_api_keys_prefix` ON `api_keys`(`prefix`); -CREATE TABLE IF NOT EXISTS "nodes" (`id` integer PRIMARY KEY AUTOINCREMENT,`machine_key` text,`node_key` text,`disco_key` text,`endpoints` text,`host_info` text,`ipv4` text,`ipv6` text,`hostname` text,`given_name` varchar(63),`user_id` integer,`register_method` text,`forced_tags` text,`auth_key_id` integer,`expiry` datetime,`last_seen` datetime,`approved_routes` text,`created_at` datetime,`updated_at` datetime,`deleted_at` datetime,CONSTRAINT `fk_nodes_user` FOREIGN KEY (`user_id`) REFERENCES `users`(`id`) ON DELETE CASCADE,CONSTRAINT `fk_nodes_auth_key` FOREIGN KEY (`auth_key_id`) REFERENCES `pre_auth_keys`(`id`)); -CREATE TABLE `policies` (`id` integer PRIMARY KEY AUTOINCREMENT,`created_at` datetime,`updated_at` datetime,`deleted_at` datetime,`data` text); -CREATE INDEX `idx_policies_deleted_at` ON `policies`(`deleted_at`); -CREATE UNIQUE INDEX idx_provider_identifier ON users (provider_identifier) WHERE provider_identifier IS NOT NULL; -CREATE UNIQUE INDEX idx_name_provider_identifier ON users (name,provider_identifier); -CREATE UNIQUE INDEX idx_name_no_provider_identifier ON users (name) WHERE provider_identifier IS NULL; diff --git a/hscontrol/db/testdata/sqlite/headscale_0.26.0_schema.sql b/hscontrol/db/testdata/sqlite/headscale_0.26.0_schema.sql deleted file mode 100644 index 2a5c360d..00000000 --- a/hscontrol/db/testdata/sqlite/headscale_0.26.0_schema.sql +++ /dev/null @@ -1,12 +0,0 @@ -CREATE TABLE `migrations` (`id` text,PRIMARY KEY (`id`)); -CREATE TABLE `users` (`id` integer PRIMARY KEY AUTOINCREMENT,`created_at` datetime,`updated_at` datetime,`deleted_at` datetime,`name` text,`display_name` text,`email` text,`provider_identifier` text,`provider` text,`profile_pic_url` text); -CREATE INDEX `idx_users_deleted_at` ON `users`(`deleted_at`); -CREATE TABLE `pre_auth_keys` (`id` integer PRIMARY KEY AUTOINCREMENT,`key` text,`user_id` integer,`reusable` numeric,`ephemeral` numeric DEFAULT false,`used` numeric DEFAULT false,`tags` text,`created_at` datetime,`expiration` datetime,CONSTRAINT `fk_pre_auth_keys_user` FOREIGN KEY (`user_id`) REFERENCES `users`(`id`) ON DELETE SET NULL); -CREATE TABLE `api_keys` (`id` integer PRIMARY KEY AUTOINCREMENT,`prefix` text,`hash` blob,`created_at` datetime,`expiration` datetime,`last_seen` datetime); -CREATE UNIQUE INDEX `idx_api_keys_prefix` ON `api_keys`(`prefix`); -CREATE TABLE IF NOT EXISTS "nodes" (`id` integer PRIMARY KEY AUTOINCREMENT,`machine_key` text,`node_key` text,`disco_key` text,`endpoints` text,`host_info` text,`ipv4` text,`ipv6` text,`hostname` text,`given_name` varchar(63),`user_id` integer,`register_method` text,`forced_tags` text,`auth_key_id` integer,`expiry` datetime,`last_seen` datetime,`approved_routes` text,`created_at` datetime,`updated_at` datetime,`deleted_at` datetime,CONSTRAINT `fk_nodes_user` FOREIGN KEY (`user_id`) REFERENCES `users`(`id`) ON DELETE CASCADE,CONSTRAINT `fk_nodes_auth_key` FOREIGN KEY (`auth_key_id`) REFERENCES `pre_auth_keys`(`id`)); -CREATE TABLE `policies` (`id` integer PRIMARY KEY AUTOINCREMENT,`created_at` datetime,`updated_at` datetime,`deleted_at` datetime,`data` text); -CREATE INDEX `idx_policies_deleted_at` ON `policies`(`deleted_at`); -CREATE UNIQUE INDEX idx_provider_identifier ON users (provider_identifier) WHERE provider_identifier IS NOT NULL; -CREATE UNIQUE INDEX idx_name_provider_identifier ON users (name,provider_identifier); -CREATE UNIQUE INDEX idx_name_no_provider_identifier ON users (name) WHERE provider_identifier IS NULL; diff --git a/hscontrol/db/testdata/sqlite/headscale_0.26.1_schema-litestream.sql b/hscontrol/db/testdata/sqlite/headscale_0.26.1_dump-litestream.sql similarity index 72% rename from hscontrol/db/testdata/sqlite/headscale_0.26.1_schema-litestream.sql rename to hscontrol/db/testdata/sqlite/headscale_0.26.1_dump-litestream.sql index 3fc2b319..c8c05755 100644 --- a/hscontrol/db/testdata/sqlite/headscale_0.26.1_schema-litestream.sql +++ b/hscontrol/db/testdata/sqlite/headscale_0.26.1_dump-litestream.sql @@ -1,14 +1,34 @@ +PRAGMA foreign_keys=OFF; +BEGIN TRANSACTION; CREATE TABLE `migrations` (`id` text,PRIMARY KEY (`id`)); +INSERT INTO migrations VALUES('202312101416'); +INSERT INTO migrations VALUES('202312101430'); +INSERT INTO migrations VALUES('202402151347'); +INSERT INTO migrations VALUES('2024041121742'); +INSERT INTO migrations VALUES('202406021630'); +INSERT INTO migrations VALUES('202409271400'); +INSERT INTO migrations VALUES('202407191627'); +INSERT INTO migrations VALUES('202408181235'); +INSERT INTO migrations VALUES('202501221827'); +INSERT INTO migrations VALUES('202501311657'); +INSERT INTO migrations VALUES('202502070949'); +INSERT INTO migrations VALUES('202502131714'); +INSERT INTO migrations VALUES('202502171819'); +INSERT INTO migrations VALUES('202505091439'); +INSERT INTO migrations VALUES('202505141324'); CREATE TABLE `users` (`id` integer PRIMARY KEY AUTOINCREMENT,`created_at` datetime,`updated_at` datetime,`deleted_at` datetime,`name` text,`display_name` text,`email` text,`provider_identifier` text,`provider` text,`profile_pic_url` text); -CREATE INDEX `idx_users_deleted_at` ON `users`(`deleted_at`); CREATE TABLE `pre_auth_keys` (`id` integer PRIMARY KEY AUTOINCREMENT,`key` text,`user_id` integer,`reusable` numeric,`ephemeral` numeric DEFAULT false,`used` numeric DEFAULT false,`tags` text,`created_at` datetime,`expiration` datetime,CONSTRAINT `fk_pre_auth_keys_user` FOREIGN KEY (`user_id`) REFERENCES `users`(`id`) ON DELETE SET NULL); CREATE TABLE `api_keys` (`id` integer PRIMARY KEY AUTOINCREMENT,`prefix` text,`hash` blob,`created_at` datetime,`expiration` datetime,`last_seen` datetime); -CREATE UNIQUE INDEX `idx_api_keys_prefix` ON `api_keys`(`prefix`); CREATE TABLE IF NOT EXISTS "nodes" (`id` integer PRIMARY KEY AUTOINCREMENT,`machine_key` text,`node_key` text,`disco_key` text,`endpoints` text,`host_info` text,`ipv4` text,`ipv6` text,`hostname` text,`given_name` varchar(63),`user_id` integer,`register_method` text,`forced_tags` text,`auth_key_id` integer,`expiry` datetime,`last_seen` datetime,`approved_routes` text,`created_at` datetime,`updated_at` datetime,`deleted_at` datetime,CONSTRAINT `fk_nodes_user` FOREIGN KEY (`user_id`) REFERENCES `users`(`id`) ON DELETE CASCADE,CONSTRAINT `fk_nodes_auth_key` FOREIGN KEY (`auth_key_id`) REFERENCES `pre_auth_keys`(`id`)); CREATE TABLE `policies` (`id` integer PRIMARY KEY AUTOINCREMENT,`created_at` datetime,`updated_at` datetime,`deleted_at` datetime,`data` text); +DELETE FROM sqlite_sequence; +INSERT INTO sqlite_sequence VALUES('nodes',0); +CREATE INDEX `idx_users_deleted_at` ON `users`(`deleted_at`); +CREATE UNIQUE INDEX `idx_api_keys_prefix` ON `api_keys`(`prefix`); CREATE INDEX `idx_policies_deleted_at` ON `policies`(`deleted_at`); CREATE UNIQUE INDEX idx_provider_identifier ON users (provider_identifier) WHERE provider_identifier IS NOT NULL; CREATE UNIQUE INDEX idx_name_provider_identifier ON users (name,provider_identifier); CREATE UNIQUE INDEX idx_name_no_provider_identifier ON users (name) WHERE provider_identifier IS NULL; CREATE TABLE _litestream_seq (id INTEGER PRIMARY KEY, seq INTEGER); CREATE TABLE _litestream_lock (id INTEGER); +COMMIT; diff --git a/hscontrol/db/testdata/sqlite/headscale_0.26.1_schema.sql b/hscontrol/db/testdata/sqlite/headscale_0.26.1_schema.sql deleted file mode 100644 index 2a5c360d..00000000 --- a/hscontrol/db/testdata/sqlite/headscale_0.26.1_schema.sql +++ /dev/null @@ -1,12 +0,0 @@ -CREATE TABLE `migrations` (`id` text,PRIMARY KEY (`id`)); -CREATE TABLE `users` (`id` integer PRIMARY KEY AUTOINCREMENT,`created_at` datetime,`updated_at` datetime,`deleted_at` datetime,`name` text,`display_name` text,`email` text,`provider_identifier` text,`provider` text,`profile_pic_url` text); -CREATE INDEX `idx_users_deleted_at` ON `users`(`deleted_at`); -CREATE TABLE `pre_auth_keys` (`id` integer PRIMARY KEY AUTOINCREMENT,`key` text,`user_id` integer,`reusable` numeric,`ephemeral` numeric DEFAULT false,`used` numeric DEFAULT false,`tags` text,`created_at` datetime,`expiration` datetime,CONSTRAINT `fk_pre_auth_keys_user` FOREIGN KEY (`user_id`) REFERENCES `users`(`id`) ON DELETE SET NULL); -CREATE TABLE `api_keys` (`id` integer PRIMARY KEY AUTOINCREMENT,`prefix` text,`hash` blob,`created_at` datetime,`expiration` datetime,`last_seen` datetime); -CREATE UNIQUE INDEX `idx_api_keys_prefix` ON `api_keys`(`prefix`); -CREATE TABLE IF NOT EXISTS "nodes" (`id` integer PRIMARY KEY AUTOINCREMENT,`machine_key` text,`node_key` text,`disco_key` text,`endpoints` text,`host_info` text,`ipv4` text,`ipv6` text,`hostname` text,`given_name` varchar(63),`user_id` integer,`register_method` text,`forced_tags` text,`auth_key_id` integer,`expiry` datetime,`last_seen` datetime,`approved_routes` text,`created_at` datetime,`updated_at` datetime,`deleted_at` datetime,CONSTRAINT `fk_nodes_user` FOREIGN KEY (`user_id`) REFERENCES `users`(`id`) ON DELETE CASCADE,CONSTRAINT `fk_nodes_auth_key` FOREIGN KEY (`auth_key_id`) REFERENCES `pre_auth_keys`(`id`)); -CREATE TABLE `policies` (`id` integer PRIMARY KEY AUTOINCREMENT,`created_at` datetime,`updated_at` datetime,`deleted_at` datetime,`data` text); -CREATE INDEX `idx_policies_deleted_at` ON `policies`(`deleted_at`); -CREATE UNIQUE INDEX idx_provider_identifier ON users (provider_identifier) WHERE provider_identifier IS NOT NULL; -CREATE UNIQUE INDEX idx_name_provider_identifier ON users (name,provider_identifier); -CREATE UNIQUE INDEX idx_name_no_provider_identifier ON users (name) WHERE provider_identifier IS NULL;