diff --git a/go.mod b/go.mod index 87db2f47a..14314921d 100644 --- a/go.mod +++ b/go.mod @@ -13,7 +13,7 @@ require ( github.com/ettle/strcase v0.2.0 github.com/fatih/color v1.18.0 github.com/google/go-cmp v0.7.0 - github.com/kong/go-apiops v0.2.1 + github.com/kong/go-apiops v0.2.2 github.com/kong/go-database-reconciler v1.31.0 github.com/kong/go-kong v0.71.0 github.com/mitchellh/go-homedir v1.1.0 diff --git a/go.sum b/go.sum index 8f44a6c2c..2a8b07092 100644 --- a/go.sum +++ b/go.sum @@ -242,8 +242,8 @@ github.com/klauspost/cpuid/v2 v2.0.10/go.mod h1:g2LTdtYhdyuGPqyWyv7qRAmj1WBqxuOb github.com/klauspost/cpuid/v2 v2.0.12/go.mod h1:g2LTdtYhdyuGPqyWyv7qRAmj1WBqxuObKfj5c0PQa7c= github.com/klauspost/cpuid/v2 v2.2.5 h1:0E5MSMDEoAulmXNFquVs//DdoomxaoTY1kUhbc/qbZg= github.com/klauspost/cpuid/v2 v2.2.5/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws= -github.com/kong/go-apiops v0.2.1 h1:6HtyQyOj+CLA86iRtXA6rpTqemp7VqJJ6gpHyNHdB7o= -github.com/kong/go-apiops v0.2.1/go.mod h1:yPwbl3P2eQinVGAEA0d3legaYmzPJ+WtJf9fSeGF4b8= +github.com/kong/go-apiops v0.2.2 h1:Owdcl/PxTdtciqyZKgPScVhTKHgY2b8dGIC1Bms8NpI= +github.com/kong/go-apiops v0.2.2/go.mod h1:yPwbl3P2eQinVGAEA0d3legaYmzPJ+WtJf9fSeGF4b8= github.com/kong/go-database-reconciler v1.31.0 h1:LITt0L/EhajVaSNDMj/TOxh4Cst7CRhiTykYMMlOoLk= github.com/kong/go-database-reconciler v1.31.0/go.mod h1:kw4+JGF6iv70LcLBmuY2UuMr8KSdqop77IR86B1mYvU= github.com/kong/go-kong v0.71.0 h1:unPik6osV1DD3DF+jLs9oMedxWQsnepPYTm1dRQSIa4= diff --git a/kong2tf/generate_resource.go b/kong2tf/generate_resource.go index 98c0cdcaa..0df946e82 100644 --- a/kong2tf/generate_resource.go +++ b/kong2tf/generate_resource.go @@ -141,7 +141,7 @@ func generateRelationship( s := fmt.Sprintf(`resource "konnect_%s" "%s" {`, entityType, name) // Extract keys to iterate in a deterministic order - keys := make([]string, 0) + keys := make([]string, 0, len(relations)) for k := range relations { keys = append(keys, k) } diff --git a/tests/integration/dump_test.go b/tests/integration/dump_test.go index c22445a79..99d64c822 100644 --- a/tests/integration/dump_test.go +++ b/tests/integration/dump_test.go @@ -301,7 +301,8 @@ func Test_Dump_KonnectRename(t *testing.T) { output string err error ) - flags := []string{"-o", "-", "--with-id"} + flags := make([]string, 0, 3+len(tc.flags)) + flags = append(flags, "-o", "-", "--with-id") flags = append(flags, tc.flags...) output, err = dump(flags...) diff --git a/tests/integration/render_test.go b/tests/integration/render_test.go index cb776613a..8f91ee9fb 100644 --- a/tests/integration/render_test.go +++ b/tests/integration/render_test.go @@ -51,9 +51,8 @@ func Test_RenderPlain(t *testing.T) { } for _, tc := range tests { t.Run(tc.name, func(t *testing.T) { - renderOpts := []string{ - tc.stateFile, - } + renderOpts := make([]string, 0, 1+len(tc.additionalArgs)) + renderOpts = append(renderOpts, tc.stateFile) renderOpts = append(renderOpts, tc.additionalArgs...) for k, v := range tc.envVars { diff --git a/tests/integration/sync_test.go b/tests/integration/sync_test.go index 388250189..7ebff87c5 100644 --- a/tests/integration/sync_test.go +++ b/tests/integration/sync_test.go @@ -8540,7 +8540,146 @@ func Test_Sync_SkipConsumersWithConsumerGroups_Konnect(t *testing.T) { } func Test_Sync_Partials_Plugins(t *testing.T) { - runWhenEnterpriseOrKonnect(t, ">=3.10.0") + runWhen(t, "enterprise", ">=3.10.0") + + client, err := getTestClient() + require.NoError(t, err) + + ctx := context.Background() + + dumpConfig := deckDump.Config{} + + partialConfig := kong.Configuration{ + "cluster_max_redirections": float64(5), + "cluster_nodes": nil, + "connect_timeout": float64(2000), + "connection_is_proxied": bool(false), + "database": float64(0), + "host": string("127.0.0.1"), + "keepalive_backlog": nil, + "keepalive_pool_size": float64(256), + "password": nil, + "port": float64(6379), + "read_timeout": float64(3001), + "send_timeout": float64(2004), + "sentinel_master": nil, + "sentinel_nodes": nil, + "sentinel_password": nil, + "sentinel_role": nil, + "sentinel_username": nil, + "server_name": nil, + "ssl": bool(false), + "ssl_verify": bool(false), + "username": nil, + } + + t.Run("create a partial and link to a plugin via name", func(t *testing.T) { + require.NoError(t, sync(ctx, "testdata/sync/039-partials/kong.yaml")) + t.Cleanup(func() { + reset(t) + }) + + newState, err := fetchCurrentState(ctx, client, dumpConfig, t) + require.NoError(t, err) + + // check for partial + partials, err := newState.Partials.GetAll() + require.NoError(t, err) + require.NotNil(t, partials) + + require.Len(t, partials, 1) + assert.Equal(t, "my-ee-partial", *partials[0].Name) + assert.Equal(t, "redis-ee", *partials[0].Type) + assert.IsType(t, kong.Configuration{}, partials[0].Config) + assert.Equal(t, partialConfig, partials[0].Config) + + // check for plugin + plugins, err := newState.Plugins.GetAll() + require.NoError(t, err) + require.NotNil(t, plugins) + require.Len(t, plugins, 1) + assert.Equal(t, "rate-limiting-advanced", *plugins[0].Name) + assert.IsType(t, []*kong.PartialLink{}, plugins[0].Partials) + require.Len(t, plugins[0].Partials, 1) + assert.Equal(t, *partials[0].ID, *plugins[0].Partials[0].ID) + assert.Equal(t, "config.redis", *plugins[0].Partials[0].Path) + }) + + t.Run("partial id is preserved if passed and linking can be done via id", func(t *testing.T) { + require.NoError(t, sync(ctx, "testdata/sync/039-partials/kong-ids.yaml")) + t.Cleanup(func() { + reset(t) + }) + + newState, err := fetchCurrentState(ctx, client, dumpConfig, t) + require.NoError(t, err) + + // check for partial + partials, err := newState.Partials.GetAll() + require.NoError(t, err) + require.NotNil(t, partials) + + require.Len(t, partials, 1) + assert.Equal(t, "13dc230d-d65e-439a-9f05-9fd71abfee4d", *partials[0].ID) + assert.Equal(t, "my-ee-partial", *partials[0].Name) + assert.Equal(t, "redis-ee", *partials[0].Type) + assert.IsType(t, kong.Configuration{}, partials[0].Config) + assert.Equal(t, partialConfig, partials[0].Config) + + // check for plugin + plugins, err := newState.Plugins.GetAll() + require.NoError(t, err) + require.NotNil(t, plugins) + require.Len(t, plugins, 1) + assert.Equal(t, "rate-limiting-advanced", *plugins[0].Name) + assert.IsType(t, []*kong.PartialLink{}, plugins[0].Partials) + require.Len(t, plugins[0].Partials, 1) + assert.Equal(t, "13dc230d-d65e-439a-9f05-9fd71abfee4d", *plugins[0].Partials[0].ID) + assert.Equal(t, "config.redis", *plugins[0].Partials[0].Path) + }) + + t.Run("linking to a plugin fails in case of non-existent partial", func(t *testing.T) { + err := sync(ctx, "testdata/sync/039-partials/kong-wrong.yaml") + require.Error(t, err) + assert.ErrorContains(t, err, "partial non-existent-partial for plugin rate-limiting-advanced: entity not found") + }) + + t.Run("partial linking with a consumer-group scoped plugin works fine", func(t *testing.T) { + require.NoError(t, sync(ctx, "testdata/sync/039-partials/cg-plugin-partial.yaml")) + t.Cleanup(func() { + reset(t) + }) + + newState, err := fetchCurrentState(ctx, client, dumpConfig, t) + require.NoError(t, err) + + // check for partial + partials, err := newState.Partials.GetAll() + require.NoError(t, err) + require.NotNil(t, partials) + + require.Len(t, partials, 1) + assert.Equal(t, "my-redis-ee", *partials[0].Name) + assert.Equal(t, "redis-ee", *partials[0].Type) + + // check for plugin + plugins, err := newState.Plugins.GetAll() + require.NoError(t, err) + require.NotNil(t, plugins) + require.Len(t, plugins, 1) + assert.Equal(t, "rate-limiting-advanced", *plugins[0].Name) + assert.IsType(t, []*kong.PartialLink{}, plugins[0].Partials) + require.Len(t, plugins[0].Partials, 1) + assert.Equal(t, *partials[0].ID, *plugins[0].Partials[0].ID) + assert.Equal(t, "config.redis", *plugins[0].Partials[0].Path) + assert.Equal(t, "foo", *plugins[0].ConsumerGroup.Name) + }) +} + +func Test_Sync_Partials_Plugins_Konnect(t *testing.T) { + runWhenKonnect(t) + setDefaultKonnectControlPlane(t) + setup(t) client, err := getTestClient() require.NoError(t, err) @@ -8550,6 +8689,7 @@ func Test_Sync_Partials_Plugins(t *testing.T) { dumpConfig := deckDump.Config{} partialConfig := kong.Configuration{ + "cloud_authentication": nil, "cluster_max_redirections": float64(5), "cluster_nodes": nil, "connect_timeout": float64(2000), @@ -10063,6 +10203,7 @@ func Test_Sync_Partials_Tagging_Konnect(t *testing.T) { Name: kong.String("redis-ee-common"), Type: kong.String("redis-ee"), Config: kong.Configuration{ + "cloud_authentication": nil, "cluster_max_redirections": float64(5), "cluster_nodes": nil, "connect_timeout": float64(2000), @@ -10092,6 +10233,7 @@ func Test_Sync_Partials_Tagging_Konnect(t *testing.T) { Name: kong.String("redis-ee-sentinel"), Type: kong.String("redis-ee"), Config: kong.Configuration{ + "cloud_authentication": nil, "cluster_max_redirections": float64(5), "cluster_nodes": nil, "connect_timeout": float64(2000), diff --git a/tests/integration/test_utils.go b/tests/integration/test_utils.go index 123f1e890..96fd2f675 100644 --- a/tests/integration/test_utils.go +++ b/tests/integration/test_utils.go @@ -242,7 +242,8 @@ func testKongState(t *testing.T, client *kong.Client, isKonnect bool, kongState, err := deckDump.Get(ctx, client, dumpConfig) require.NoError(t, err) - opt := []cmp.Option{ + opt := make([]cmp.Option, 0, 22+len(ignoreFields)) + opt = append(opt, cmpopts.IgnoreFields(kong.Service{}, "CreatedAt", "UpdatedAt"), cmpopts.IgnoreFields(kong.Route{}, "CreatedAt", "UpdatedAt"), cmpopts.IgnoreFields(kong.Plugin{}, "ID", "CreatedAt"), @@ -265,7 +266,7 @@ func testKongState(t *testing.T, client *kong.Client, isKonnect bool, cmpopts.SortSlices(sortSlices), cmpopts.SortSlices(func(a, b *string) bool { return *a < *b }), cmpopts.EquateEmpty(), - } + ) opt = append(opt, ignoreFields...) if diff := cmp.Diff(kongState, &expectedState, opt...); diff != "" { diff --git a/tests/integration/validate_test.go b/tests/integration/validate_test.go index 2e2e974b0..388055147 100644 --- a/tests/integration/validate_test.go +++ b/tests/integration/validate_test.go @@ -155,9 +155,8 @@ func Test_Validate_File(t *testing.T) { for _, tc := range tests { t.Run(tc.name, func(t *testing.T) { - validateOpts := []string{ - tc.stateFile, - } + validateOpts := make([]string, 0, 1+len(tc.additionalArgs)) + validateOpts = append(validateOpts, tc.stateFile) validateOpts = append(validateOpts, tc.additionalArgs...) err := validate(OFFLINE, validateOpts...) @@ -205,9 +204,8 @@ func Test_Validate_Gateway(t *testing.T) { for _, tc := range tests { t.Run(tc.name, func(t *testing.T) { - validateOpts := []string{ - tc.stateFile, - } + validateOpts := make([]string, 0, 1+len(tc.additionalArgs)) + validateOpts = append(validateOpts, tc.stateFile) validateOpts = append(validateOpts, tc.additionalArgs...) err := validate(ONLINE, validateOpts...) @@ -284,9 +282,8 @@ func Test_Validate_Gateway_EE(t *testing.T) { require.NoError(t, sync(ctx, tc.priorStateFile)) } - validateOpts := []string{ - tc.stateFile, - } + validateOpts := make([]string, 0, 1+len(tc.additionalArgs)) + validateOpts = append(validateOpts, tc.stateFile) validateOpts = append(validateOpts, tc.additionalArgs...) err := validate(ONLINE, validateOpts...) @@ -353,9 +350,8 @@ func Test_Validate_PartialLookupTags(t *testing.T) { t.Run(tc.name, func(t *testing.T) { require.NoError(t, sync(ctx, "testdata/validate/001-partials/partials.yaml")) - validateOpts := []string{ - tc.stateFile, - } + validateOpts := make([]string, 0, 1+len(tc.additionalArgs)) + validateOpts = append(validateOpts, tc.stateFile) validateOpts = append(validateOpts, tc.additionalArgs...) err := validate(tc.mode, validateOpts...)