Skip to content

Commit c3a7e2e

Browse files
committed
test(acceptance): add end-to-end tests for filter flag JSON parsing (issue #192)
1 parent 8875dde commit c3a7e2e

1 file changed

Lines changed: 131 additions & 0 deletions

File tree

test/acceptance/connection_upsert_test.go

Lines changed: 131 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -441,4 +441,135 @@ func TestConnectionUpsertPartialUpdates(t *testing.T) {
441441

442442
t.Logf("Successfully upserted connection %s with source-name only", connID)
443443
})
444+
445+
// Regression test for https://github.com/hookdeck/hookdeck-cli/issues/192:
446+
// --rule-filter-headers (and other filter flags) should store JSON as a parsed
447+
// object, not as an escaped string.
448+
t.Run("FilterHeadersJSONStoredAsObject", func(t *testing.T) {
449+
if testing.Short() {
450+
t.Skip("Skipping acceptance test in short mode")
451+
}
452+
453+
cli := NewCLIRunner(t)
454+
timestamp := generateTimestamp()
455+
456+
connName := "test-filter-headers-" + timestamp
457+
sourceName := "test-filter-src-" + timestamp
458+
destName := "test-filter-dst-" + timestamp
459+
460+
// Create a connection using --rule-filter-headers with a JSON object
461+
var createResp map[string]interface{}
462+
err := cli.RunJSON(&createResp,
463+
"gateway", "connection", "upsert", connName,
464+
"--source-name", sourceName,
465+
"--source-type", "WEBHOOK",
466+
"--destination-name", destName,
467+
"--destination-type", "HTTP",
468+
"--destination-url", "https://example.com/webhook",
469+
"--rule-filter-headers", `{"x-shopify-topic":{"$startsWith":"order/"}}`,
470+
)
471+
require.NoError(t, err, "Should create connection with --rule-filter-headers JSON")
472+
473+
connID, ok := createResp["id"].(string)
474+
require.True(t, ok && connID != "", "Expected connection ID in response")
475+
476+
t.Cleanup(func() {
477+
deleteConnection(t, cli, connID)
478+
})
479+
480+
// Verify source and destination were created correctly
481+
source, ok := createResp["source"].(map[string]interface{})
482+
require.True(t, ok, "Expected source object in response")
483+
assert.Equal(t, sourceName, source["name"], "Source name should match")
484+
485+
dest, ok := createResp["destination"].(map[string]interface{})
486+
require.True(t, ok, "Expected destination object in response")
487+
assert.Equal(t, destName, dest["name"], "Destination name should match")
488+
489+
// Verify the filter rule has headers as a JSON object, not an escaped string
490+
rules, ok := createResp["rules"].([]interface{})
491+
require.True(t, ok, "Expected rules array in response")
492+
493+
foundFilter := false
494+
for _, r := range rules {
495+
rule, ok := r.(map[string]interface{})
496+
if !ok || rule["type"] != "filter" {
497+
continue
498+
}
499+
foundFilter = true
500+
501+
headers := rule["headers"]
502+
_, isString := headers.(string)
503+
assert.False(t, isString,
504+
"--rule-filter-headers should store JSON as an object, not an escaped string; got: %v", headers)
505+
506+
headersMap, isMap := headers.(map[string]interface{})
507+
assert.True(t, isMap,
508+
"headers should be a JSON object (map[string]interface{}), got %T", headers)
509+
assert.Contains(t, headersMap, "x-shopify-topic",
510+
"headers object should contain the expected key")
511+
break
512+
}
513+
assert.True(t, foundFilter, "Should have a filter rule")
514+
515+
t.Logf("Successfully verified --rule-filter-headers stores JSON as object for connection %s", connID)
516+
})
517+
518+
// Verify that --rule-filter-body JSON is also stored as an object.
519+
t.Run("FilterBodyJSONStoredAsObject", func(t *testing.T) {
520+
if testing.Short() {
521+
t.Skip("Skipping acceptance test in short mode")
522+
}
523+
524+
cli := NewCLIRunner(t)
525+
timestamp := generateTimestamp()
526+
527+
connName := "test-filter-body-" + timestamp
528+
sourceName := "test-filter-body-src-" + timestamp
529+
destName := "test-filter-body-dst-" + timestamp
530+
531+
var createResp map[string]interface{}
532+
err := cli.RunJSON(&createResp,
533+
"gateway", "connection", "upsert", connName,
534+
"--source-name", sourceName,
535+
"--source-type", "WEBHOOK",
536+
"--destination-name", destName,
537+
"--destination-type", "HTTP",
538+
"--destination-url", "https://example.com/webhook",
539+
"--rule-filter-body", `{"event_type":"payment"}`,
540+
)
541+
require.NoError(t, err, "Should create connection with --rule-filter-body JSON")
542+
543+
connID, ok := createResp["id"].(string)
544+
require.True(t, ok && connID != "", "Expected connection ID in response")
545+
546+
t.Cleanup(func() {
547+
deleteConnection(t, cli, connID)
548+
})
549+
550+
rules, ok := createResp["rules"].([]interface{})
551+
require.True(t, ok, "Expected rules array in response")
552+
553+
foundFilter := false
554+
for _, r := range rules {
555+
rule, ok := r.(map[string]interface{})
556+
if !ok || rule["type"] != "filter" {
557+
continue
558+
}
559+
foundFilter = true
560+
561+
body := rule["body"]
562+
_, isString := body.(string)
563+
assert.False(t, isString,
564+
"--rule-filter-body should store JSON as an object, not an escaped string; got: %v", body)
565+
566+
bodyMap, isMap := body.(map[string]interface{})
567+
assert.True(t, isMap, "body should be a JSON object, got %T", body)
568+
assert.Contains(t, bodyMap, "event_type", "body object should contain the expected key")
569+
break
570+
}
571+
assert.True(t, foundFilter, "Should have a filter rule")
572+
573+
t.Logf("Successfully verified --rule-filter-body stores JSON as object for connection %s", connID)
574+
})
444575
}

0 commit comments

Comments
 (0)