diff --git a/internal/config/config_validation_internal_test.go b/internal/config/config_validation_internal_test.go index abfdee7..2e06fc9 100644 --- a/internal/config/config_validation_internal_test.go +++ b/internal/config/config_validation_internal_test.go @@ -135,6 +135,55 @@ func TestDefaultDBURLOpensTheDatabaseInWALMode(t *testing.T) { } } +// TestDerivedDBURLOpensStateDirHoldingURLCharacters opens the db_url +// derived from a state_dir whose name holds %41, ? and #, and checks that +// the database is state.sqlite3 in that directory, in WAL mode. Put into +// a file: URL as it is, the name would lose its meaning: %41 is read as +// A, and the path ends at the ?, which also loses the journal mode. +func TestDerivedDBURLOpensStateDirHoldingURLCharacters(t *testing.T) { + t.Parallel() + + stateDir := filepath.Join(t.TempDir(), "a%41b?c#d") + + err := os.Mkdir(stateDir, 0o750) + if err != nil { + t.Fatalf("failed to create %q: %v", stateDir, err) + } + + // Quoted so YAML takes the whole name as it is. + c, err := configFromYAML(t, signingKeyLine+"state_dir: '"+stateDir+"'\n") + if err != nil { + t.Fatalf("config with state_dir %q should be valid, got: %v", stateDir, err) + } + + t.Logf("state_dir %q gives db_url %q", stateDir, c.DBURL) + + db, err := sql.Open("sqlite", c.DBURL) + if err != nil { + t.Fatalf("failed to open %q: %v", c.DBURL, err) + } + + t.Cleanup(func() { _ = db.Close() }) + + var journalMode string + + err = db.QueryRowContext(t.Context(), "PRAGMA journal_mode").Scan(&journalMode) + if err != nil { + t.Fatalf("failed to read the journal mode of %q: %v", c.DBURL, err) + } + + if journalMode != "wal" { + t.Errorf("journal mode of %q = %q, want wal", c.DBURL, journalMode) + } + + dbFile := filepath.Join(stateDir, "state.sqlite3") + + _, err = os.Stat(dbFile) + if err != nil { + t.Errorf("opening %q did not create %q: %v", c.DBURL, dbFile, err) + } +} + func TestExplicitValidValuesAreUsed(t *testing.T) { t.Parallel()