diff --git a/pkg/state/fixtures/test-plugin-config.json b/pkg/state/fixtures/test-plugin-config.json new file mode 100644 index 00000000..ebfc04c9 --- /dev/null +++ b/pkg/state/fixtures/test-plugin-config.json @@ -0,0 +1,225 @@ +{ + "fields": [ + { + "config": { + "fields": [ + { + "primitive_str": { + "description": "The primitive string field.", + "type": "string" + } + }, + { + "record_of_array_of_str": { + "fields": [ + { + "headers": { + "default": [], + "elements": { + "type": "string" + }, + "required": true, + "type": "array" + } + } + ], + "required": true, + "type": "record" + } + }, + { + "map_type": { + "description": "The custom query params to be added in the callout HTTP request. Values can contain Lua expressions in the form `$(some_lua_expression)`. The syntax is based on `request-transformer-advanced` templates.", + "keys": { + "type": "string" + }, + "required": false, + "type": "map", + "values": { + "referenceable": true, + "required": false, + "type": "string" + } + } + }, + { + "array_of_record": { + "description": "Sentinel node addresses to use for Redis connections when the `redis` strategy is defined. Defining this field implies using a Redis Sentinel. The minimum length of the array is 1 element.", + "elements": { + "fields": [ + { + "host": { + "default": "127.0.0.1", + "description": "A string representing a host name, such as example.com.", + "required": true, + "type": "string" + } + }, + { + "port": { + "default": 6379, + "description": "An integer representing a port number between 0 and 65535, inclusive.", + "type": "integer" + } + } + ], + "type": "record" + }, + "len_min": 1, + "required": false, + "type": "array" + } + }, + { + "nested_array_of_array_of_str": { + "type": "array", + "required": false, + "description": "List of list of strings.", + "elements": { + "type": "array", + "elements": { + "type": "string" + } + } + } + }, + { + "nested_array_of_set_of_str": { + "type": "array", + "required": false, + "description": "List of list of strings.", + "elements": { + "type": "set", + "elements": { + "type": "string" + } + } + } + }, + { + "nested_set_of_array_of_str": { + "type": "set", + "required": false, + "description": "List of list of strings.", + "elements": { + "type": "array", + "elements": { + "type": "string" + } + } + } + }, + { + "nested_set_of_set_of_str": { + "type": "set", + "required": false, + "description": "List of list of strings.", + "elements": { + "type": "set", + "elements": { + "type": "string" + } + } + } + }, + { + "nested_array_of_record_of_array": { + "type": "array", + "required": false, + "description": "List of list of strings.", + "elements": { + "type": "array", + "elements": { + "fields": [ + { + "ports": { + "elements": { + "type": "number" + }, + "type": "array" + } + } + ], + "type": "record" + } + } + } + }, + { + "nested_array_of_record_of_set": { + "type": "array", + "required": false, + "description": "List of list of strings.", + "elements": { + "type": "array", + "elements": { + "fields": [ + { + "ports": { + "elements": { + "type": "number" + }, + "type": "set" + } + } + ], + "type": "record" + } + } + } + }, + { + "nested_set_of_record_of_set": { + "type": "array", + "required": false, + "description": "List of list of strings.", + "elements": { + "type": "set", + "elements": { + "fields": [ + { + "ports": { + "elements": { + "type": "number" + }, + "type": "set" + } + } + ], + "type": "record" + } + } + } + } + ], + "required": true, + "type": "record", + "shorthand_fields": [ + { + "shorthand_record_of_set_array": { + "fields": [ + { + "set_hosts": { + "elements": { + "type": "string" + }, + "type": "set" + } + }, + { + "array_hosts": { + "elements": { + "type": "string" + }, + "type": "array" + } + } + ], + "type": "record" + } + } + ] + } + } + ] +} \ No newline at end of file diff --git a/pkg/state/types.go b/pkg/state/types.go index ae5923c1..2a752251 100644 --- a/pkg/state/types.go +++ b/pkg/state/types.go @@ -9,6 +9,7 @@ import ( "strings" "github.com/kong/go-kong/kong" + "github.com/tidwall/gjson" ) // entity abstracts out common fields in a credentials. @@ -565,14 +566,14 @@ func (p1 *Plugin) Console() string { // Equal returns true if r1 and r2 are equal. // TODO add compare array without position func (p1 *Plugin) Equal(p2 *Plugin) bool { - return p1.EqualWithOpts(p2, false, false, false) + return p1.EqualWithOpts(p2, false, false, false, gjson.Result{}) } // EqualWithOpts returns true if p1 and p2 are equal. // If ignoreID is set to true, IDs will be ignored while comparison. // If ignoreTS is set to true, timestamp fields will be ignored. func (p1 *Plugin) EqualWithOpts(p2 *Plugin, ignoreID, - ignoreTS, ignoreForeign bool, + ignoreTS, ignoreForeign bool, schema gjson.Result, ) bool { p1Copy := p1.Plugin.DeepCopy() p2Copy := p2.Plugin.DeepCopy() @@ -590,8 +591,10 @@ func (p1 *Plugin) EqualWithOpts(p2 *Plugin, ignoreID, sort.Slice(p1Copy.Protocols, func(i, j int) bool { return *(p1Copy.Protocols[i]) < *(p1Copy.Protocols[j]) }) sort.Slice(p2Copy.Protocols, func(i, j int) bool { return *(p2Copy.Protocols[i]) < *(p2Copy.Protocols[j]) }) - p1Copy.Config = sortNestedArrays(p1Copy.Config) - p2Copy.Config = sortNestedArrays(p2Copy.Config) + const pluginConfigKey = "fields.#(config).config" + configSchema := schema.Get(pluginConfigKey) + p1Copy.Config = sortNestedArraysBasedOnSchema(p1Copy.Config, configSchema) + p2Copy.Config = sortNestedArraysBasedOnSchema(p2Copy.Config, configSchema) if ignoreID { p1Copy.ID = nil @@ -672,26 +675,61 @@ func (e EmptyInterfaceUsingUnderlyingType) Less(i, j int) bool { return strings.Compare(objI, objJ) == -1 } -// Helper function to sort nested arrays in a map -func sortNestedArrays(m map[string]interface{}) map[string]interface{} { - sortedMap := make(map[string]interface{}) +// Helper function to get schema for a field name +func getSchemaForFieldName(schema gjson.Result, fieldName string) gjson.Result { + const fieldsQueryTemplate = "fields.#(%s).%s" + const shorthandFieldsQueryTemplate = "shorthand_fields.#(%s).%s" + fieldsQuery := fmt.Sprintf(fieldsQueryTemplate, fieldName, fieldName) + result := schema.Get(fieldsQuery) + if !result.Exists() { + // try shorthand fields + shorthandQuery := fmt.Sprintf(shorthandFieldsQueryTemplate, fieldName, fieldName) + result = schema.Get(shorthandQuery) + } + return result +} + +// Helper function to determine if we should sort based on schema +func shouldSort(schema gjson.Result) bool { + if !schema.Exists() { + return true + } + + typeResult := schema.Get("type") + if !typeResult.Exists() { + return true + } + + return typeResult.String() != "array" +} + +// Helper function to sort nested arrays in a map referring to schema +func sortNestedArraysBasedOnSchema(m map[string]interface{}, schema gjson.Result) map[string]interface{} { + sortedMap := make(map[string]interface{}, len(m)) for k, v := range m { switch value := v.(type) { case []interface{}: + currSchema := getSchemaForFieldName(schema, k) + // For list types like array or set, get the element schema + elementsSchema := currSchema.Get("elements") // Recursively sort each element if it's a map or array for i, elem := range value { switch elemType := elem.(type) { case map[string]interface{}: - value[i] = sortNestedArrays(elemType) + value[i] = sortNestedArraysBasedOnSchema(elemType, elementsSchema) case []interface{}: - value[i] = sortArrayElementsRecursively(elemType) + value[i] = sortArrayElementsRecursivelyBasedOnSchema(elemType, elementsSchema) } } - sort.Sort(EmptyInterfaceUsingUnderlyingType(value)) + + if shouldSort(currSchema) { + sort.Sort(EmptyInterfaceUsingUnderlyingType(value)) + } sortedMap[k] = value case map[string]interface{}: - sortedMap[k] = sortNestedArrays(value) + currSchema := getSchemaForFieldName(schema, k) + sortedMap[k] = sortNestedArraysBasedOnSchema(value, currSchema) default: sortedMap[k] = value } @@ -701,17 +739,21 @@ func sortNestedArrays(m map[string]interface{}) map[string]interface{} { } // Helper function to sort array elements recursively -func sortArrayElementsRecursively(arr []interface{}) []interface{} { +func sortArrayElementsRecursivelyBasedOnSchema(arr []interface{}, parentSchema gjson.Result) []interface{} { + elementsSchema := parentSchema.Get("elements") + for i, elem := range arr { switch elemType := elem.(type) { case map[string]interface{}: - arr[i] = sortNestedArrays(elemType) + arr[i] = sortNestedArraysBasedOnSchema(elemType, elementsSchema) case []interface{}: - arr[i] = sortArrayElementsRecursively(elemType) + arr[i] = sortArrayElementsRecursivelyBasedOnSchema(elemType, elementsSchema) } } - sort.Sort(EmptyInterfaceUsingUnderlyingType(arr)) + if shouldSort(parentSchema) { + sort.Sort(EmptyInterfaceUsingUnderlyingType(arr)) + } return arr } diff --git a/pkg/state/types_test.go b/pkg/state/types_test.go index adba2082..94b22af2 100644 --- a/pkg/state/types_test.go +++ b/pkg/state/types_test.go @@ -1,6 +1,7 @@ package state import ( + "os" "reflect" "sort" "testing" @@ -8,6 +9,7 @@ import ( "github.com/kong/go-kong/kong" "github.com/samber/lo" "github.com/stretchr/testify/assert" + "github.com/tidwall/gjson" ) // getTags returns a slice of test tags. If reversed is true, the tags are backwards! @@ -300,56 +302,51 @@ func TestPluginEqual(t *testing.T) { p2.Name = kong.String("baz") assert.False(p1.Equal(&p2)) - assert.False(p1.EqualWithOpts(&p2, false, false, false)) + assert.False(p1.EqualWithOpts(&p2, false, false, false, gjson.Result{})) p2.Name = kong.String("bar") assert.True(p1.Equal(&p2)) - assert.True(p1.EqualWithOpts(&p2, false, false, false)) + assert.True(p1.EqualWithOpts(&p2, false, false, false, gjson.Result{})) p1.Tags = getTags(true) p2.Tags = getTags(false) - assert.True(p1.EqualWithOpts(&p2, false, false, false)) + assert.True(p1.EqualWithOpts(&p2, false, false, false, gjson.Result{})) // Verify that plugins are equal even if protocols are out of order p1.Protocols = getProtocols(true) p2.Protocols = getProtocols(false) - assert.True(p1.EqualWithOpts(&p2, false, false, false)) + assert.True(p1.EqualWithOpts(&p2, false, false, false, gjson.Result{})) p1.ID = kong.String("fuu") - assert.False(p1.EqualWithOpts(&p2, false, false, false)) - assert.True(p1.EqualWithOpts(&p2, true, false, false)) - + assert.False(p1.EqualWithOpts(&p2, false, false, false, gjson.Result{})) + assert.True(p1.EqualWithOpts(&p2, true, false, false, gjson.Result{})) timestamp := 1 p2.CreatedAt = ×tamp - assert.False(p1.EqualWithOpts(&p2, false, false, false)) - assert.False(p1.EqualWithOpts(&p2, false, true, false)) - + assert.False(p1.EqualWithOpts(&p2, false, false, false, gjson.Result{})) + assert.False(p1.EqualWithOpts(&p2, false, true, false, gjson.Result{})) p1.Service = &kong.Service{ID: kong.String("1")} p2.Service = &kong.Service{ID: kong.String("2")} - assert.False(p1.EqualWithOpts(&p2, true, true, false)) - assert.True(p1.EqualWithOpts(&p2, true, true, true)) - + assert.False(p1.EqualWithOpts(&p2, true, true, false, gjson.Result{})) + assert.True(p1.EqualWithOpts(&p2, true, true, true, gjson.Result{})) p1.Service = &kong.Service{ID: kong.String("2")} - assert.True(p1.EqualWithOpts(&p2, true, true, false)) + assert.True(p1.EqualWithOpts(&p2, true, true, false, gjson.Result{})) p1.Config = kong.Configuration{"foo": "bar"} p2.Config = kong.Configuration{"foo": "bar"} - assert.True(p1.EqualWithOpts(&p2, true, true, false)) - + assert.True(p1.EqualWithOpts(&p2, true, true, false, gjson.Result{})) p2.Config = kong.Configuration{"foo": "baz"} - assert.False(p1.EqualWithOpts(&p2, true, true, false)) + assert.False(p1.EqualWithOpts(&p2, true, true, false, gjson.Result{})) p1.Config = kong.Configuration{"foo": []interface{}{"b", "a", "c"}, "bar": "baz"} p2.Config = kong.Configuration{"foo": []interface{}{"a", "b", "c"}, "bar": "baz"} - assert.True(p1.EqualWithOpts(&p2, true, true, false)) - + assert.True(p1.EqualWithOpts(&p2, true, true, false, gjson.Result{})) p2.Config = kong.Configuration{"foo": []interface{}{"a", "c", "b"}, "bar": "baz"} - assert.True(p1.EqualWithOpts(&p2, true, true, false)) + assert.True(p1.EqualWithOpts(&p2, true, true, false, gjson.Result{})) p2.Config = kong.Configuration{"foo": []interface{}{"a", "c", "b"}, "bar": "baz"} - assert.True(p1.EqualWithOpts(&p2, true, true, false)) + assert.True(p1.EqualWithOpts(&p2, true, true, false, gjson.Result{})) p2.Config = kong.Configuration{"foo": []interface{}{"a", "c", "b"}, "bar": "bar"} - assert.False(p1.EqualWithOpts(&p2, true, true, false)) + assert.False(p1.EqualWithOpts(&p2, true, true, false, gjson.Result{})) p1.Config = kong.Configuration{ "foo": []interface{}{"b", "a", "c"}, @@ -365,7 +362,7 @@ func TestPluginEqual(t *testing.T) { "key1": []interface{}{"a", "b", "c"}, }, } - assert.True(p1.EqualWithOpts(&p2, true, true, false)) + assert.True(p1.EqualWithOpts(&p2, true, true, false, gjson.Result{})) p2.Config = kong.Configuration{ "foo": []interface{}{"a", "c", "c"}, @@ -374,7 +371,7 @@ func TestPluginEqual(t *testing.T) { "key1": []interface{}{"a", "b", "c"}, }, } - assert.False(p1.EqualWithOpts(&p2, true, true, false)) + assert.False(p1.EqualWithOpts(&p2, true, true, false, gjson.Result{})) } func TestConsumerEqual(t *testing.T) { @@ -699,7 +696,7 @@ func TestSortNestedArrays(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - result := sortNestedArrays(tt.input) + result := sortNestedArraysBasedOnSchema(tt.input, gjson.Result{}) if !reflect.DeepEqual(result, tt.expected) { t.Errorf("expected %v, got %v", tt.expected, result) } @@ -722,8 +719,8 @@ func TestDeepEqualWithSorting(t *testing.T) { }, } - sortedMap1 := sortNestedArrays(map1) - sortedMap2 := sortNestedArrays(map2) + sortedMap1 := sortNestedArraysBasedOnSchema(map1, gjson.Result{}) + sortedMap2 := sortNestedArraysBasedOnSchema(map2, gjson.Result{}) if !reflect.DeepEqual(sortedMap1, sortedMap2) { t.Errorf("expected maps to be equal, but they are not") @@ -792,3 +789,162 @@ func TestPluginConsole(t *testing.T) { }) } } + +func TestSortNestedArraysBasedOnSchema(t *testing.T) { + // Load a custom plugin schema with a variety of field types + filePath := "./fixtures/test-plugin-config.json" + fileBytes, err := os.ReadFile(filePath) + if err != nil { + t.Fatalf("failed to open file: %v", err) + } + + gjsonRes := gjson.ParseBytes(fileBytes) + configSchema := gjsonRes.Get("fields.#(config).config") + + // Create a plugin config with all field types from the schema + originalPluginConfig := kong.Configuration{ + "primitive_str": "test-value", + "record_of_array_of_str": map[string]interface{}{ + "headers": []interface{}{ + "header-z", + "header-a", + "header-m", + }, + }, + "map_type": map[string]interface{}{ + "key": "value", + }, + "array_of_record": []interface{}{ + map[string]interface{}{ + "host": "host2.example.com", + "port": float64(6380), + }, + map[string]interface{}{ + "host": "host1.example.com", + "port": float64(6379), + }, + }, + "nested_array_of_array_of_str": []interface{}{ + []interface{}{"z", "a", "m"}, + []interface{}{"b", "y", "c"}, + }, + "nested_array_of_set_of_str": []interface{}{ + []interface{}{"z", "a", "m"}, + []interface{}{"b", "y", "c"}, + }, + "nested_set_of_array_of_str": []interface{}{ + []interface{}{"z", "a", "m"}, + []interface{}{"b", "y", "c"}, + }, + "nested_set_of_set_of_str": []interface{}{ + []interface{}{"z", "a", "m"}, + []interface{}{"b", "y", "c"}, + }, + "nested_array_of_record_of_array": []interface{}{ + []interface{}{ + map[string]interface{}{"ports": []interface{}{float64(9096), float64(9091), float64(9092)}}, + map[string]interface{}{"ports": []interface{}{float64(8086), float64(8081), float64(8082)}}, + }, + }, + "nested_array_of_record_of_set": []interface{}{ + []interface{}{ + map[string]interface{}{"ports": []interface{}{float64(9096), float64(9091), float64(9092)}}, + map[string]interface{}{"ports": []interface{}{float64(8086), float64(8081), float64(8082)}}, + }, + }, + "nested_set_of_record_of_set": []interface{}{ + []interface{}{ + map[string]interface{}{"ports": []interface{}{float64(9096), float64(9091), float64(9092)}}, + map[string]interface{}{"ports": []interface{}{float64(8086), float64(8081), float64(8082)}}, + }, + }, + "shorthand_record_of_set_array": map[string]interface{}{ + "set_hosts": []interface{}{ + "example.com", + "abcgefgh.com", + "zzz.com", + }, + "array_hosts": []interface{}{ + "example.com", + "abcgefgh.com", + "zzz.com", + }, + }, + } + expectedPluginConfig := kong.Configuration{ + "primitive_str": "test-value", + "record_of_array_of_str": map[string]interface{}{ + "headers": []interface{}{ // not sorted + "header-z", + "header-a", + "header-m", + }, + }, + "map_type": map[string]interface{}{ + "key": "value", + }, + "array_of_record": []interface{}{ // not sorted + map[string]interface{}{ + "host": "host2.example.com", + "port": float64(6380), + }, + map[string]interface{}{ + "host": "host1.example.com", + "port": float64(6379), + }, + }, + "nested_array_of_array_of_str": []interface{}{ // not sorted + []interface{}{"z", "a", "m"}, // not sorted + []interface{}{"b", "y", "c"}, // not sorted + }, + "nested_array_of_set_of_str": []interface{}{ // not sorted + []interface{}{"a", "m", "z"}, // sorted + []interface{}{"b", "c", "y"}, // sorted + }, + "nested_set_of_array_of_str": []interface{}{ // sorted + []interface{}{"b", "y", "c"}, // not sorted + []interface{}{"z", "a", "m"}, // not sorted + }, + "nested_set_of_set_of_str": []interface{}{ // sorted + []interface{}{"a", "m", "z"}, // sorted + []interface{}{"b", "c", "y"}, // sorted + }, + "nested_array_of_record_of_array": []interface{}{ + []interface{}{ // not sorted + map[string]interface{}{"ports": []interface{}{float64(9096), float64(9091), float64(9092)}}, // not sorted + map[string]interface{}{"ports": []interface{}{float64(8086), float64(8081), float64(8082)}}, // not sorted + }, + }, + "nested_array_of_record_of_set": []interface{}{ + []interface{}{ // not sorted + map[string]interface{}{"ports": []interface{}{float64(9091), float64(9092), float64(9096)}}, // sorted + map[string]interface{}{"ports": []interface{}{float64(8081), float64(8082), float64(8086)}}, // sorted + }, + }, + "nested_set_of_record_of_set": []interface{}{ + []interface{}{ // sorted + map[string]interface{}{"ports": []interface{}{float64(8081), float64(8082), float64(8086)}}, // sorted + map[string]interface{}{"ports": []interface{}{float64(9091), float64(9092), float64(9096)}}, // sorted + }, + }, + "shorthand_record_of_set_array": map[string]interface{}{ + "set_hosts": []interface{}{ // sorted + "abcgefgh.com", + "example.com", + "zzz.com", + }, + "array_hosts": []interface{}{ // not sorted + "example.com", + "abcgefgh.com", + "zzz.com", + }, + }, + } + + // Sort the cloned config + var sortedConfig kong.Configuration = sortNestedArraysBasedOnSchema(originalPluginConfig, configSchema) + + if !reflect.DeepEqual(sortedConfig, expectedPluginConfig) { + t.Errorf("expected %v, got %v", expectedPluginConfig, sortedConfig) + } +} diff --git a/pkg/types/plugin.go b/pkg/types/plugin.go index 215b25b9..01fdb14f 100644 --- a/pkg/types/plugin.go +++ b/pkg/types/plugin.go @@ -2,6 +2,7 @@ package types import ( "context" + "encoding/json" "errors" "fmt" @@ -9,6 +10,7 @@ import ( "github.com/kong/go-database-reconciler/pkg/state" "github.com/kong/go-database-reconciler/pkg/utils" "github.com/kong/go-kong/kong" + "github.com/tidwall/gjson" ) // pluginCRUD implements crud.Actions interface. @@ -209,7 +211,10 @@ func (d *pluginDiffer) createUpdatePlugin(plugin *state.Plugin) (*crud.Event, er return nil, fmt.Errorf("failed clearing unmatching deprecations fields: %w", err) } - if !currentPlugin.EqualWithOpts(pluginWithDefaults, false, true, false) { + jsonb, _ := json.Marshal(&schema) + gjsonSchema := gjson.ParseBytes(jsonb) + + if !currentPlugin.EqualWithOpts(pluginWithDefaults, false, true, false, gjsonSchema) { return &crud.Event{ Op: crud.Update, Kind: d.kind, diff --git a/tests/integration/diff_test.go b/tests/integration/diff_test.go index 15dbbd40..9eefc924 100644 --- a/tests/integration/diff_test.go +++ b/tests/integration/diff_test.go @@ -2336,6 +2336,68 @@ Summary: ] } +Summary: + Created: 0 + Updated: 1 + Deleted: 0 +` + expectedOutputRequestTransformerArrayReorder = `updating plugin request-transformer (global) { + "config": { + "add": { + "body": [ + ], + "headers": [ + ], + "querystring": [ + ] + }, + "append": { + "body": [ + ], + "headers": [ + ], + "querystring": [ + ] + }, + "http_method": null, + "remove": { + "body": [ + ], + "headers": [ + ], + "querystring": [ + ] + }, + "rename": { + "body": [ + ], + "headers": [ + "Authorization:something-else", + ], + "querystring": [ + ] + }, + "replace": { + "body": [ + ], + "headers": [ + ], + "querystring": [ + ], + "uri": null + } + }, + "enabled": true, + "id": "bc364672-3032-45e3-aac2-7eb921da8515", + "name": "request-transformer", + "protocols": [ + "grpc", + "grpcs", + "http", + "https" + ] + } + Summary: Created: 0 Updated: 1 @@ -3106,3 +3168,45 @@ func Test_Diff_PluginConfig_Nested_Arrays(t *testing.T) { require.NoError(t, err) assert.Equal(t, expectedOutputNoChange, out) } + +func Test_Diff_PluginConfigReorderArraySetValues(t *testing.T) { + setup(t) + + tests := []struct { + name string + initialStateFile string + stateFile string + isDiffExpected bool + expectedDiff string + }{ + { + name: "Reordering plugin config values of type array should show diff", + initialStateFile: "testdata/diff/004-plugin-update/initial-request-transformer-reorder-array.yaml", + stateFile: "testdata/diff/004-plugin-update/final-request-transformer-reorder-array.yaml", + isDiffExpected: true, + expectedDiff: expectedOutputRequestTransformerArrayReorder, + }, + { + name: "Reordering plugin config values of type set should not show diff", + initialStateFile: "testdata/diff/004-plugin-update/initial-jwt-reorder-set.yaml", + stateFile: "testdata/diff/004-plugin-update/final-jwt-reorder-set.yaml", + isDiffExpected: false, + }, + } + + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + reset(t) + // initialize state + require.NoError(t, sync(tc.initialStateFile)) + + out, err := diff(tc.stateFile) + require.NoError(t, err) + if tc.isDiffExpected { + assert.Equal(t, tc.expectedDiff, out) + } else { + assert.Equal(t, expectedOutputNoChange, out) + } + }) + } +} diff --git a/tests/integration/testdata/diff/004-plugin-update/final-jwt-reorder-set.yaml b/tests/integration/testdata/diff/004-plugin-update/final-jwt-reorder-set.yaml new file mode 100644 index 00000000..920e2dc2 --- /dev/null +++ b/tests/integration/testdata/diff/004-plugin-update/final-jwt-reorder-set.yaml @@ -0,0 +1,7 @@ +_format_version: "3.0" +plugins: + - name: jwt + config: + cookie_names: + - awt + - bwt \ No newline at end of file diff --git a/tests/integration/testdata/diff/004-plugin-update/final-request-transformer-reorder-array.yaml b/tests/integration/testdata/diff/004-plugin-update/final-request-transformer-reorder-array.yaml new file mode 100644 index 00000000..bed877cc --- /dev/null +++ b/tests/integration/testdata/diff/004-plugin-update/final-request-transformer-reorder-array.yaml @@ -0,0 +1,14 @@ +_format_version: "3.0" +plugins: + - name: request-transformer + protocols: + - grpc + - grpcs + - http + - https + id: bc364672-3032-45e3-aac2-7eb921da8515 + config: + rename: + headers: + - Authorization:something-else + - custom-token:Authorization diff --git a/tests/integration/testdata/diff/004-plugin-update/initial-jwt-reorder-set.yaml b/tests/integration/testdata/diff/004-plugin-update/initial-jwt-reorder-set.yaml new file mode 100644 index 00000000..87c97f83 --- /dev/null +++ b/tests/integration/testdata/diff/004-plugin-update/initial-jwt-reorder-set.yaml @@ -0,0 +1,7 @@ +_format_version: "3.0" +plugins: + - name: jwt + config: + cookie_names: + - bwt + - awt \ No newline at end of file diff --git a/tests/integration/testdata/diff/004-plugin-update/initial-request-transformer-reorder-array.yaml b/tests/integration/testdata/diff/004-plugin-update/initial-request-transformer-reorder-array.yaml new file mode 100644 index 00000000..7b5f3615 --- /dev/null +++ b/tests/integration/testdata/diff/004-plugin-update/initial-request-transformer-reorder-array.yaml @@ -0,0 +1,14 @@ +_format_version: "3.0" +plugins: + - name: request-transformer + protocols: + - grpc + - grpcs + - http + - https + id: bc364672-3032-45e3-aac2-7eb921da8515 + config: + rename: + headers: + - custom-token:Authorization + - Authorization:something-else