package queryd import ( "strings" "testing" "git.agentview.dev/profit/golangLAKEHOUSE/internal/secrets" "git.agentview.dev/profit/golangLAKEHOUSE/internal/shared" ) // Closes R-008: db.go owns sqlEscape + redactCreds + buildBootstrap, // none of which had tests. The first two are pure functions trivial // to table-test; buildBootstrap is also pure (S3Config + creds → SQL // strings) so we can exercise its endpoint-normalization branches // without booting DuckDB. func TestSqlEscape(t *testing.T) { cases := []struct { name string in string want string }{ {"no quotes", "hello", "hello"}, {"single quote", "O'Reilly", "O''Reilly"}, {"double quote pair", "''", "''''"}, {"trailing quote", "foo'", "foo''"}, {"leading quote", "'foo", "''foo"}, {"empty string", "", ""}, {"only quotes", "'''", "''''''"}, {"mixed punctuation", "it's a 'test'", "it''s a ''test''"}, } for _, tc := range cases { t.Run(tc.name, func(t *testing.T) { got := sqlEscape(tc.in) if got != tc.want { t.Errorf("sqlEscape(%q) = %q, want %q", tc.in, got, tc.want) } }) } } func TestRedactCreds(t *testing.T) { cases := []struct { name string creds secrets.S3Credentials msg string want string }{ { "both keys redacted", secrets.S3Credentials{AccessKeyID: "AKIATEST", SecretAccessKey: "topsecret"}, "failed: KEY_ID 'AKIATEST' SECRET 'topsecret'", "failed: KEY_ID '[REDACTED-KEY]' SECRET '[REDACTED-SECRET]'", }, { "only access key present", secrets.S3Credentials{AccessKeyID: "AKIATEST", SecretAccessKey: ""}, "echo: AKIATEST again", "echo: [REDACTED-KEY] again", }, { "only secret present", secrets.S3Credentials{AccessKeyID: "", SecretAccessKey: "mysecret"}, "echo: mysecret here", "echo: [REDACTED-SECRET] here", }, { "empty creds = no change", secrets.S3Credentials{}, "failed: nothing to scrub", "failed: nothing to scrub", }, { "value appears multiple times", secrets.S3Credentials{AccessKeyID: "AKIATEST"}, "AKIATEST failed because AKIATEST", "[REDACTED-KEY] failed because [REDACTED-KEY]", }, { "key value collision with placeholder string is lossy but safe", secrets.S3Credentials{AccessKeyID: "[REDACTED-KEY]"}, "loop: [REDACTED-KEY]", "loop: [REDACTED-KEY]", }, } for _, tc := range cases { t.Run(tc.name, func(t *testing.T) { got := redactCreds(tc.msg, tc.creds) if got != tc.want { t.Errorf("redactCreds:\n msg=%q\n got=%q\n want=%q", tc.msg, got, tc.want) } }) } } func TestBuildBootstrap_StatementOrder(t *testing.T) { stmts := buildBootstrap( shared.S3Config{Endpoint: "http://localhost:9000", Region: "us-east-1", UsePathStyle: true}, secrets.S3Credentials{AccessKeyID: "key", SecretAccessKey: "secret"}, ) if len(stmts) != 3 { t.Fatalf("want 3 statements, got %d: %v", len(stmts), stmts) } if stmts[0] != "INSTALL httpfs" { t.Errorf("stmt[0] = %q, want INSTALL httpfs", stmts[0]) } if stmts[1] != "LOAD httpfs" { t.Errorf("stmt[1] = %q, want LOAD httpfs", stmts[1]) } if !strings.HasPrefix(stmts[2], "CREATE OR REPLACE SECRET") { t.Errorf("stmt[2] should start with CREATE OR REPLACE SECRET, got %q", stmts[2]) } } func TestBuildBootstrap_EndpointSchemes(t *testing.T) { cases := []struct { name string endpoint string wantHostInSQL string wantUseSSLTrue bool }{ {"http strips scheme, USE_SSL false", "http://minio:9000", "minio:9000", false}, {"https keeps SSL true", "https://s3.example.com", "s3.example.com", true}, {"no scheme defaults SSL true (ambient prod)", "s3.amazonaws.com", "s3.amazonaws.com", true}, } for _, tc := range cases { t.Run(tc.name, func(t *testing.T) { stmts := buildBootstrap( shared.S3Config{Endpoint: tc.endpoint, Region: "us-east-1"}, secrets.S3Credentials{AccessKeyID: "k", SecretAccessKey: "s"}, ) secret := stmts[2] wantEndpointFrag := "ENDPOINT '" + tc.wantHostInSQL + "'" if !strings.Contains(secret, wantEndpointFrag) { t.Errorf("secret SQL missing %q\n got: %s", wantEndpointFrag, secret) } wantSSL := "USE_SSL false" if tc.wantUseSSLTrue { wantSSL = "USE_SSL true" } if !strings.Contains(secret, wantSSL) { t.Errorf("secret SQL missing %q\n got: %s", wantSSL, secret) } }) } } func TestBuildBootstrap_URLStyle(t *testing.T) { pathStmts := buildBootstrap( shared.S3Config{Endpoint: "http://m:9000", UsePathStyle: true}, secrets.S3Credentials{AccessKeyID: "k", SecretAccessKey: "s"}, ) if !strings.Contains(pathStmts[2], "URL_STYLE 'path'") { t.Errorf("UsePathStyle=true should produce URL_STYLE 'path'\n got: %s", pathStmts[2]) } vhostStmts := buildBootstrap( shared.S3Config{Endpoint: "https://m", UsePathStyle: false}, secrets.S3Credentials{AccessKeyID: "k", SecretAccessKey: "s"}, ) if !strings.Contains(vhostStmts[2], "URL_STYLE 'vhost'") { t.Errorf("UsePathStyle=false should produce URL_STYLE 'vhost'\n got: %s", vhostStmts[2]) } } func TestBuildBootstrap_EscapesCredentialQuotes(t *testing.T) { // Per the inline comment: "creds shouldn't contain ' but a future // SSO token might." This is the test that asserts the belt holds // when the suspenders snap. stmts := buildBootstrap( shared.S3Config{Endpoint: "https://m", Region: "us-east-1"}, secrets.S3Credentials{ AccessKeyID: "key'with'quotes", SecretAccessKey: "secret", }, ) secret := stmts[2] // Escaped form: each ' became ''. want := "KEY_ID 'key''with''quotes'" if !strings.Contains(secret, want) { t.Errorf("expected escaped key in SQL\n want fragment: %s\n got: %s", want, secret) } }