From 70774d9622264349eef2b9c2ad1c9cef3064e7ee Mon Sep 17 00:00:00 2001 From: Steph Date: Tue, 1 Jul 2025 09:23:35 +0200 Subject: [PATCH] populate and return ListResources in GetMetadata --- .../proto5server/server_getmetadata_test.go | 308 +++++++++++++++--- .../proto6server/server_getmetadata_test.go | 294 +++++++++++++++-- internal/toproto5/getmetadata.go | 5 + internal/toproto5/getmetadata_test.go | 36 +- internal/toproto6/getmetadata.go | 5 + internal/toproto6/getmetadata_test.go | 36 +- 6 files changed, 613 insertions(+), 71 deletions(-) diff --git a/internal/proto5server/server_getmetadata_test.go b/internal/proto5server/server_getmetadata_test.go index 9f8baf1fc..d1505e0e4 100644 --- a/internal/proto5server/server_getmetadata_test.go +++ b/internal/proto5server/server_getmetadata_test.go @@ -14,6 +14,7 @@ import ( "github.com/hashicorp/terraform-plugin-framework/function" "github.com/hashicorp/terraform-plugin-framework/internal/fwserver" "github.com/hashicorp/terraform-plugin-framework/internal/testing/testprovider" + "github.com/hashicorp/terraform-plugin-framework/list" "github.com/hashicorp/terraform-plugin-framework/resource" "github.com/hashicorp/terraform-plugin-go/tfprotov5" ) @@ -64,6 +65,7 @@ func TestServerGetMetadata(t *testing.T) { }, EphemeralResources: []tfprotov5.EphemeralResourceMetadata{}, Functions: []tfprotov5.FunctionMetadata{}, + ListResources: []tfprotov5.ListResourceMetadata{}, Resources: []tfprotov5.ResourceMetadata{}, ServerCapabilities: &tfprotov5.ServerCapabilities{ GetProviderSchemaOptional: true, @@ -99,8 +101,7 @@ func TestServerGetMetadata(t *testing.T) { }, request: &tfprotov5.GetMetadataRequest{}, expectedResponse: &tfprotov5.GetMetadataResponse{ - DataSources: []tfprotov5.DataSourceMetadata{}, - EphemeralResources: []tfprotov5.EphemeralResourceMetadata{}, + DataSources: []tfprotov5.DataSourceMetadata{}, Diagnostics: []*tfprotov5.Diagnostic{ { Severity: tfprotov5.DiagnosticSeverityError, @@ -110,8 +111,10 @@ func TestServerGetMetadata(t *testing.T) { "This is always an issue with the provider and should be reported to the provider developers.", }, }, - Functions: []tfprotov5.FunctionMetadata{}, - Resources: []tfprotov5.ResourceMetadata{}, + EphemeralResources: []tfprotov5.EphemeralResourceMetadata{}, + Functions: []tfprotov5.FunctionMetadata{}, + ListResources: []tfprotov5.ListResourceMetadata{}, + Resources: []tfprotov5.ResourceMetadata{}, ServerCapabilities: &tfprotov5.ServerCapabilities{ GetProviderSchemaOptional: true, MoveResourceState: true, @@ -139,8 +142,7 @@ func TestServerGetMetadata(t *testing.T) { }, request: &tfprotov5.GetMetadataRequest{}, expectedResponse: &tfprotov5.GetMetadataResponse{ - DataSources: []tfprotov5.DataSourceMetadata{}, - EphemeralResources: []tfprotov5.EphemeralResourceMetadata{}, + DataSources: []tfprotov5.DataSourceMetadata{}, Diagnostics: []*tfprotov5.Diagnostic{ { Severity: tfprotov5.DiagnosticSeverityError, @@ -149,8 +151,10 @@ func TestServerGetMetadata(t *testing.T) { "This is always an issue with the provider and should be reported to the provider developers.", }, }, - Functions: []tfprotov5.FunctionMetadata{}, - Resources: []tfprotov5.ResourceMetadata{}, + EphemeralResources: []tfprotov5.EphemeralResourceMetadata{}, + Functions: []tfprotov5.FunctionMetadata{}, + ListResources: []tfprotov5.ListResourceMetadata{}, + Resources: []tfprotov5.ResourceMetadata{}, ServerCapabilities: &tfprotov5.ServerCapabilities{ GetProviderSchemaOptional: true, MoveResourceState: true, @@ -186,6 +190,7 @@ func TestServerGetMetadata(t *testing.T) { request: &tfprotov5.GetMetadataRequest{}, expectedResponse: &tfprotov5.GetMetadataResponse{ DataSources: []tfprotov5.DataSourceMetadata{}, + Functions: []tfprotov5.FunctionMetadata{}, EphemeralResources: []tfprotov5.EphemeralResourceMetadata{ { TypeName: "test_ephemeral_resource1", @@ -194,8 +199,8 @@ func TestServerGetMetadata(t *testing.T) { TypeName: "test_ephemeral_resource2", }, }, - Functions: []tfprotov5.FunctionMetadata{}, - Resources: []tfprotov5.ResourceMetadata{}, + ListResources: []tfprotov5.ListResourceMetadata{}, + Resources: []tfprotov5.ResourceMetadata{}, ServerCapabilities: &tfprotov5.ServerCapabilities{ GetProviderSchemaOptional: true, MoveResourceState: true, @@ -230,8 +235,7 @@ func TestServerGetMetadata(t *testing.T) { }, request: &tfprotov5.GetMetadataRequest{}, expectedResponse: &tfprotov5.GetMetadataResponse{ - DataSources: []tfprotov5.DataSourceMetadata{}, - EphemeralResources: []tfprotov5.EphemeralResourceMetadata{}, + DataSources: []tfprotov5.DataSourceMetadata{}, Diagnostics: []*tfprotov5.Diagnostic{ { Severity: tfprotov5.DiagnosticSeverityError, @@ -241,8 +245,10 @@ func TestServerGetMetadata(t *testing.T) { "This is always an issue with the provider and should be reported to the provider developers.", }, }, - Functions: []tfprotov5.FunctionMetadata{}, - Resources: []tfprotov5.ResourceMetadata{}, + EphemeralResources: []tfprotov5.EphemeralResourceMetadata{}, + Functions: []tfprotov5.FunctionMetadata{}, + ListResources: []tfprotov5.ListResourceMetadata{}, + Resources: []tfprotov5.ResourceMetadata{}, ServerCapabilities: &tfprotov5.ServerCapabilities{ GetProviderSchemaOptional: true, MoveResourceState: true, @@ -270,8 +276,7 @@ func TestServerGetMetadata(t *testing.T) { }, request: &tfprotov5.GetMetadataRequest{}, expectedResponse: &tfprotov5.GetMetadataResponse{ - DataSources: []tfprotov5.DataSourceMetadata{}, - EphemeralResources: []tfprotov5.EphemeralResourceMetadata{}, + DataSources: []tfprotov5.DataSourceMetadata{}, Diagnostics: []*tfprotov5.Diagnostic{ { Severity: tfprotov5.DiagnosticSeverityError, @@ -280,8 +285,10 @@ func TestServerGetMetadata(t *testing.T) { "This is always an issue with the provider and should be reported to the provider developers.", }, }, - Functions: []tfprotov5.FunctionMetadata{}, - Resources: []tfprotov5.ResourceMetadata{}, + EphemeralResources: []tfprotov5.EphemeralResourceMetadata{}, + Functions: []tfprotov5.FunctionMetadata{}, + ListResources: []tfprotov5.ListResourceMetadata{}, + Resources: []tfprotov5.ResourceMetadata{}, ServerCapabilities: &tfprotov5.ServerCapabilities{ GetProviderSchemaOptional: true, MoveResourceState: true, @@ -316,8 +323,7 @@ func TestServerGetMetadata(t *testing.T) { }, request: &tfprotov5.GetMetadataRequest{}, expectedResponse: &tfprotov5.GetMetadataResponse{ - DataSources: []tfprotov5.DataSourceMetadata{}, - EphemeralResources: []tfprotov5.EphemeralResourceMetadata{}, + DataSources: []tfprotov5.DataSourceMetadata{}, Functions: []tfprotov5.FunctionMetadata{ { Name: "function1", @@ -326,7 +332,9 @@ func TestServerGetMetadata(t *testing.T) { Name: "function2", }, }, - Resources: []tfprotov5.ResourceMetadata{}, + EphemeralResources: []tfprotov5.EphemeralResourceMetadata{}, + ListResources: []tfprotov5.ListResourceMetadata{}, + Resources: []tfprotov5.ResourceMetadata{}, ServerCapabilities: &tfprotov5.ServerCapabilities{ GetProviderSchemaOptional: true, MoveResourceState: true, @@ -361,8 +369,7 @@ func TestServerGetMetadata(t *testing.T) { }, request: &tfprotov5.GetMetadataRequest{}, expectedResponse: &tfprotov5.GetMetadataResponse{ - DataSources: []tfprotov5.DataSourceMetadata{}, - EphemeralResources: []tfprotov5.EphemeralResourceMetadata{}, + DataSources: []tfprotov5.DataSourceMetadata{}, Diagnostics: []*tfprotov5.Diagnostic{ { Severity: tfprotov5.DiagnosticSeverityError, @@ -372,8 +379,10 @@ func TestServerGetMetadata(t *testing.T) { "This is always an issue with the provider and should be reported to the provider developers.", }, }, - Functions: []tfprotov5.FunctionMetadata{}, - Resources: []tfprotov5.ResourceMetadata{}, + EphemeralResources: []tfprotov5.EphemeralResourceMetadata{}, + Functions: []tfprotov5.FunctionMetadata{}, + ListResources: []tfprotov5.ListResourceMetadata{}, + Resources: []tfprotov5.ResourceMetadata{}, ServerCapabilities: &tfprotov5.ServerCapabilities{ GetProviderSchemaOptional: true, MoveResourceState: true, @@ -401,8 +410,7 @@ func TestServerGetMetadata(t *testing.T) { }, request: &tfprotov5.GetMetadataRequest{}, expectedResponse: &tfprotov5.GetMetadataResponse{ - DataSources: []tfprotov5.DataSourceMetadata{}, - EphemeralResources: []tfprotov5.EphemeralResourceMetadata{}, + DataSources: []tfprotov5.DataSourceMetadata{}, Diagnostics: []*tfprotov5.Diagnostic{ { Severity: tfprotov5.DiagnosticSeverityError, @@ -411,8 +419,231 @@ func TestServerGetMetadata(t *testing.T) { "This is always an issue with the provider and should be reported to the provider developers.", }, }, - Functions: []tfprotov5.FunctionMetadata{}, - Resources: []tfprotov5.ResourceMetadata{}, + EphemeralResources: []tfprotov5.EphemeralResourceMetadata{}, + Functions: []tfprotov5.FunctionMetadata{}, + ListResources: []tfprotov5.ListResourceMetadata{}, + Resources: []tfprotov5.ResourceMetadata{}, + ServerCapabilities: &tfprotov5.ServerCapabilities{ + GetProviderSchemaOptional: true, + MoveResourceState: true, + PlanDestroy: true, + }, + }, + }, + "listresources": { + server: &Server{ + FrameworkServer: fwserver.Server{ + Provider: &testprovider.Provider{ + ListResourcesMethod: func(_ context.Context) []func() list.ListResource { + return []func() list.ListResource{ + func() list.ListResource { + return &testprovider.ListResource{ + MetadataMethod: func(_ context.Context, _ resource.MetadataRequest, resp *resource.MetadataResponse) { + resp.TypeName = "test_list_resource1" + }, + } + }, + func() list.ListResource { + return &testprovider.ListResource{ + MetadataMethod: func(_ context.Context, _ resource.MetadataRequest, resp *resource.MetadataResponse) { + resp.TypeName = "test_list_resource2" + }, + } + }, + } + }, + ResourcesMethod: func(_ context.Context) []func() resource.Resource { + return []func() resource.Resource{ + func() resource.Resource { + return &testprovider.Resource{ + MetadataMethod: func(_ context.Context, _ resource.MetadataRequest, resp *resource.MetadataResponse) { + resp.TypeName = "test_list_resource1" + }, + } + }, + func() resource.Resource { + return &testprovider.Resource{ + MetadataMethod: func(_ context.Context, _ resource.MetadataRequest, resp *resource.MetadataResponse) { + resp.TypeName = "test_list_resource2" + }, + } + }, + } + }, + }, + }, + }, + request: &tfprotov5.GetMetadataRequest{}, + expectedResponse: &tfprotov5.GetMetadataResponse{ + DataSources: []tfprotov5.DataSourceMetadata{}, + Functions: []tfprotov5.FunctionMetadata{}, + EphemeralResources: []tfprotov5.EphemeralResourceMetadata{}, + ListResources: []tfprotov5.ListResourceMetadata{ + { + TypeName: "test_list_resource1", + }, + { + TypeName: "test_list_resource2", + }, + }, + Resources: []tfprotov5.ResourceMetadata{ + { + TypeName: "test_list_resource1", + }, + { + TypeName: "test_list_resource2", + }, + }, + ServerCapabilities: &tfprotov5.ServerCapabilities{ + GetProviderSchemaOptional: true, + MoveResourceState: true, + PlanDestroy: true, + }, + }, + }, + "listresources-duplicate-type-name": { + server: &Server{ + FrameworkServer: fwserver.Server{ + Provider: &testprovider.Provider{ + ListResourcesMethod: func(_ context.Context) []func() list.ListResource { + return []func() list.ListResource{ + func() list.ListResource { + return &testprovider.ListResource{ + MetadataMethod: func(_ context.Context, _ resource.MetadataRequest, resp *resource.MetadataResponse) { + resp.TypeName = "test_list_resource" + }, + } + }, + func() list.ListResource { + return &testprovider.ListResource{ + MetadataMethod: func(_ context.Context, _ resource.MetadataRequest, resp *resource.MetadataResponse) { + resp.TypeName = "test_list_resource" + }, + } + }, + } + }, + ResourcesMethod: func(_ context.Context) []func() resource.Resource { + return []func() resource.Resource{ + func() resource.Resource { + return &testprovider.Resource{ + MetadataMethod: func(_ context.Context, _ resource.MetadataRequest, resp *resource.MetadataResponse) { + resp.TypeName = "test_list_resource" + }, + } + }, + } + }, + }, + }, + }, + request: &tfprotov5.GetMetadataRequest{}, + expectedResponse: &tfprotov5.GetMetadataResponse{ + DataSources: []tfprotov5.DataSourceMetadata{}, + Diagnostics: []*tfprotov5.Diagnostic{ + { + Severity: tfprotov5.DiagnosticSeverityError, + Summary: "Duplicate ListResource Type Defined", + Detail: "The test_list_resource ListResource type name was returned for multiple list resources. " + + "ListResource type names must be unique. " + + "This is always an issue with the provider and should be reported to the provider developers.", + }, + }, + EphemeralResources: []tfprotov5.EphemeralResourceMetadata{}, + Functions: []tfprotov5.FunctionMetadata{}, + ListResources: []tfprotov5.ListResourceMetadata{}, + Resources: []tfprotov5.ResourceMetadata{}, + ServerCapabilities: &tfprotov5.ServerCapabilities{ + GetProviderSchemaOptional: true, + MoveResourceState: true, + PlanDestroy: true, + }, + }, + }, + "listresources-empty-type-name": { + server: &Server{ + FrameworkServer: fwserver.Server{ + Provider: &testprovider.Provider{ + ListResourcesMethod: func(_ context.Context) []func() list.ListResource { + return []func() list.ListResource{ + func() list.ListResource { + return &testprovider.ListResource{ + MetadataMethod: func(_ context.Context, _ resource.MetadataRequest, resp *resource.MetadataResponse) { + resp.TypeName = "" + }, + } + }, + } + }, + ResourcesMethod: func(_ context.Context) []func() resource.Resource { + return []func() resource.Resource{ + func() resource.Resource { + return &testprovider.Resource{ + MetadataMethod: func(_ context.Context, _ resource.MetadataRequest, resp *resource.MetadataResponse) { + resp.TypeName = "test_list_resource" + }, + } + }, + } + }, + }, + }, + }, + request: &tfprotov5.GetMetadataRequest{}, + expectedResponse: &tfprotov5.GetMetadataResponse{ + DataSources: []tfprotov5.DataSourceMetadata{}, + Diagnostics: []*tfprotov5.Diagnostic{ + { + Severity: tfprotov5.DiagnosticSeverityError, + Summary: "ListResource Type Name Missing", + Detail: "The *testprovider.ListResource ListResource returned an empty string from the Metadata method. " + + "This is always an issue with the provider and should be reported to the provider developers.", + }, + }, + EphemeralResources: []tfprotov5.EphemeralResourceMetadata{}, + Functions: []tfprotov5.FunctionMetadata{}, + ListResources: []tfprotov5.ListResourceMetadata{}, + Resources: []tfprotov5.ResourceMetadata{}, + ServerCapabilities: &tfprotov5.ServerCapabilities{ + GetProviderSchemaOptional: true, + MoveResourceState: true, + PlanDestroy: true, + }, + }, + }, + "listresources-missing-resource-definition": { + server: &Server{ + FrameworkServer: fwserver.Server{ + Provider: &testprovider.Provider{ + ListResourcesMethod: func(_ context.Context) []func() list.ListResource { + return []func() list.ListResource{ + func() list.ListResource { + return &testprovider.ListResource{ + MetadataMethod: func(_ context.Context, _ resource.MetadataRequest, resp *resource.MetadataResponse) { + resp.TypeName = "test_list_resource" + }, + } + }, + } + }, + }, + }, + }, + request: &tfprotov5.GetMetadataRequest{}, + expectedResponse: &tfprotov5.GetMetadataResponse{ + DataSources: []tfprotov5.DataSourceMetadata{}, + Diagnostics: []*tfprotov5.Diagnostic{ + { + Severity: tfprotov5.DiagnosticSeverityError, + Summary: "ListResource Type Defined without a Matching Managed Resource Type", + Detail: "The test_list_resource ListResource type name was returned, but no matching managed Resource type was defined. " + + "This is always an issue with the provider and should be reported to the provider developers.", + }, + }, + EphemeralResources: []tfprotov5.EphemeralResourceMetadata{}, + Functions: []tfprotov5.FunctionMetadata{}, + ListResources: []tfprotov5.ListResourceMetadata{}, + Resources: []tfprotov5.ResourceMetadata{}, ServerCapabilities: &tfprotov5.ServerCapabilities{ GetProviderSchemaOptional: true, MoveResourceState: true, @@ -450,6 +681,7 @@ func TestServerGetMetadata(t *testing.T) { DataSources: []tfprotov5.DataSourceMetadata{}, EphemeralResources: []tfprotov5.EphemeralResourceMetadata{}, Functions: []tfprotov5.FunctionMetadata{}, + ListResources: []tfprotov5.ListResourceMetadata{}, Resources: []tfprotov5.ResourceMetadata{ { TypeName: "test_resource1", @@ -492,8 +724,7 @@ func TestServerGetMetadata(t *testing.T) { }, request: &tfprotov5.GetMetadataRequest{}, expectedResponse: &tfprotov5.GetMetadataResponse{ - DataSources: []tfprotov5.DataSourceMetadata{}, - EphemeralResources: []tfprotov5.EphemeralResourceMetadata{}, + DataSources: []tfprotov5.DataSourceMetadata{}, Diagnostics: []*tfprotov5.Diagnostic{ { Severity: tfprotov5.DiagnosticSeverityError, @@ -503,8 +734,10 @@ func TestServerGetMetadata(t *testing.T) { "This is always an issue with the provider and should be reported to the provider developers.", }, }, - Functions: []tfprotov5.FunctionMetadata{}, - Resources: []tfprotov5.ResourceMetadata{}, + EphemeralResources: []tfprotov5.EphemeralResourceMetadata{}, + Functions: []tfprotov5.FunctionMetadata{}, + ListResources: []tfprotov5.ListResourceMetadata{}, + Resources: []tfprotov5.ResourceMetadata{}, ServerCapabilities: &tfprotov5.ServerCapabilities{ GetProviderSchemaOptional: true, MoveResourceState: true, @@ -532,8 +765,7 @@ func TestServerGetMetadata(t *testing.T) { }, request: &tfprotov5.GetMetadataRequest{}, expectedResponse: &tfprotov5.GetMetadataResponse{ - DataSources: []tfprotov5.DataSourceMetadata{}, - EphemeralResources: []tfprotov5.EphemeralResourceMetadata{}, + DataSources: []tfprotov5.DataSourceMetadata{}, Diagnostics: []*tfprotov5.Diagnostic{ { Severity: tfprotov5.DiagnosticSeverityError, @@ -542,8 +774,10 @@ func TestServerGetMetadata(t *testing.T) { "This is always an issue with the provider and should be reported to the provider developers.", }, }, - Functions: []tfprotov5.FunctionMetadata{}, - Resources: []tfprotov5.ResourceMetadata{}, + EphemeralResources: []tfprotov5.EphemeralResourceMetadata{}, + Functions: []tfprotov5.FunctionMetadata{}, + ListResources: []tfprotov5.ListResourceMetadata{}, + Resources: []tfprotov5.ResourceMetadata{}, ServerCapabilities: &tfprotov5.ServerCapabilities{ GetProviderSchemaOptional: true, MoveResourceState: true, diff --git a/internal/proto6server/server_getmetadata_test.go b/internal/proto6server/server_getmetadata_test.go index b32933a65..e103314fc 100644 --- a/internal/proto6server/server_getmetadata_test.go +++ b/internal/proto6server/server_getmetadata_test.go @@ -14,6 +14,7 @@ import ( "github.com/hashicorp/terraform-plugin-framework/function" "github.com/hashicorp/terraform-plugin-framework/internal/fwserver" "github.com/hashicorp/terraform-plugin-framework/internal/testing/testprovider" + "github.com/hashicorp/terraform-plugin-framework/list" "github.com/hashicorp/terraform-plugin-framework/resource" "github.com/hashicorp/terraform-plugin-go/tfprotov6" ) @@ -62,8 +63,9 @@ func TestServerGetMetadata(t *testing.T) { TypeName: "test_data_source2", }, }, - Functions: []tfprotov6.FunctionMetadata{}, EphemeralResources: []tfprotov6.EphemeralResourceMetadata{}, + Functions: []tfprotov6.FunctionMetadata{}, + ListResources: []tfprotov6.ListResourceMetadata{}, Resources: []tfprotov6.ResourceMetadata{}, ServerCapabilities: &tfprotov6.ServerCapabilities{ GetProviderSchemaOptional: true, @@ -109,8 +111,9 @@ func TestServerGetMetadata(t *testing.T) { "This is always an issue with the provider and should be reported to the provider developers.", }, }, - Functions: []tfprotov6.FunctionMetadata{}, EphemeralResources: []tfprotov6.EphemeralResourceMetadata{}, + Functions: []tfprotov6.FunctionMetadata{}, + ListResources: []tfprotov6.ListResourceMetadata{}, Resources: []tfprotov6.ResourceMetadata{}, ServerCapabilities: &tfprotov6.ServerCapabilities{ GetProviderSchemaOptional: true, @@ -148,8 +151,9 @@ func TestServerGetMetadata(t *testing.T) { "This is always an issue with the provider and should be reported to the provider developers.", }, }, - Functions: []tfprotov6.FunctionMetadata{}, EphemeralResources: []tfprotov6.EphemeralResourceMetadata{}, + Functions: []tfprotov6.FunctionMetadata{}, + ListResources: []tfprotov6.ListResourceMetadata{}, Resources: []tfprotov6.ResourceMetadata{}, ServerCapabilities: &tfprotov6.ServerCapabilities{ GetProviderSchemaOptional: true, @@ -194,8 +198,9 @@ func TestServerGetMetadata(t *testing.T) { TypeName: "test_ephemeral_resource2", }, }, - Functions: []tfprotov6.FunctionMetadata{}, - Resources: []tfprotov6.ResourceMetadata{}, + Functions: []tfprotov6.FunctionMetadata{}, + ListResources: []tfprotov6.ListResourceMetadata{}, + Resources: []tfprotov6.ResourceMetadata{}, ServerCapabilities: &tfprotov6.ServerCapabilities{ GetProviderSchemaOptional: true, MoveResourceState: true, @@ -230,8 +235,7 @@ func TestServerGetMetadata(t *testing.T) { }, request: &tfprotov6.GetMetadataRequest{}, expectedResponse: &tfprotov6.GetMetadataResponse{ - DataSources: []tfprotov6.DataSourceMetadata{}, - EphemeralResources: []tfprotov6.EphemeralResourceMetadata{}, + DataSources: []tfprotov6.DataSourceMetadata{}, Diagnostics: []*tfprotov6.Diagnostic{ { Severity: tfprotov6.DiagnosticSeverityError, @@ -241,8 +245,10 @@ func TestServerGetMetadata(t *testing.T) { "This is always an issue with the provider and should be reported to the provider developers.", }, }, - Functions: []tfprotov6.FunctionMetadata{}, - Resources: []tfprotov6.ResourceMetadata{}, + EphemeralResources: []tfprotov6.EphemeralResourceMetadata{}, + Functions: []tfprotov6.FunctionMetadata{}, + ListResources: []tfprotov6.ListResourceMetadata{}, + Resources: []tfprotov6.ResourceMetadata{}, ServerCapabilities: &tfprotov6.ServerCapabilities{ GetProviderSchemaOptional: true, MoveResourceState: true, @@ -270,8 +276,7 @@ func TestServerGetMetadata(t *testing.T) { }, request: &tfprotov6.GetMetadataRequest{}, expectedResponse: &tfprotov6.GetMetadataResponse{ - DataSources: []tfprotov6.DataSourceMetadata{}, - EphemeralResources: []tfprotov6.EphemeralResourceMetadata{}, + DataSources: []tfprotov6.DataSourceMetadata{}, Diagnostics: []*tfprotov6.Diagnostic{ { Severity: tfprotov6.DiagnosticSeverityError, @@ -280,8 +285,10 @@ func TestServerGetMetadata(t *testing.T) { "This is always an issue with the provider and should be reported to the provider developers.", }, }, - Functions: []tfprotov6.FunctionMetadata{}, - Resources: []tfprotov6.ResourceMetadata{}, + EphemeralResources: []tfprotov6.EphemeralResourceMetadata{}, + Functions: []tfprotov6.FunctionMetadata{}, + ListResources: []tfprotov6.ListResourceMetadata{}, + Resources: []tfprotov6.ResourceMetadata{}, ServerCapabilities: &tfprotov6.ServerCapabilities{ GetProviderSchemaOptional: true, MoveResourceState: true, @@ -326,7 +333,8 @@ func TestServerGetMetadata(t *testing.T) { Name: "function2", }, }, - Resources: []tfprotov6.ResourceMetadata{}, + ListResources: []tfprotov6.ListResourceMetadata{}, + Resources: []tfprotov6.ResourceMetadata{}, ServerCapabilities: &tfprotov6.ServerCapabilities{ GetProviderSchemaOptional: true, MoveResourceState: true, @@ -361,8 +369,7 @@ func TestServerGetMetadata(t *testing.T) { }, request: &tfprotov6.GetMetadataRequest{}, expectedResponse: &tfprotov6.GetMetadataResponse{ - DataSources: []tfprotov6.DataSourceMetadata{}, - EphemeralResources: []tfprotov6.EphemeralResourceMetadata{}, + DataSources: []tfprotov6.DataSourceMetadata{}, Diagnostics: []*tfprotov6.Diagnostic{ { Severity: tfprotov6.DiagnosticSeverityError, @@ -372,8 +379,10 @@ func TestServerGetMetadata(t *testing.T) { "This is always an issue with the provider and should be reported to the provider developers.", }, }, - Functions: []tfprotov6.FunctionMetadata{}, - Resources: []tfprotov6.ResourceMetadata{}, + EphemeralResources: []tfprotov6.EphemeralResourceMetadata{}, + Functions: []tfprotov6.FunctionMetadata{}, + ListResources: []tfprotov6.ListResourceMetadata{}, + Resources: []tfprotov6.ResourceMetadata{}, ServerCapabilities: &tfprotov6.ServerCapabilities{ GetProviderSchemaOptional: true, MoveResourceState: true, @@ -401,8 +410,7 @@ func TestServerGetMetadata(t *testing.T) { }, request: &tfprotov6.GetMetadataRequest{}, expectedResponse: &tfprotov6.GetMetadataResponse{ - DataSources: []tfprotov6.DataSourceMetadata{}, - EphemeralResources: []tfprotov6.EphemeralResourceMetadata{}, + DataSources: []tfprotov6.DataSourceMetadata{}, Diagnostics: []*tfprotov6.Diagnostic{ { Severity: tfprotov6.DiagnosticSeverityError, @@ -411,8 +419,231 @@ func TestServerGetMetadata(t *testing.T) { "This is always an issue with the provider and should be reported to the provider developers.", }, }, - Functions: []tfprotov6.FunctionMetadata{}, - Resources: []tfprotov6.ResourceMetadata{}, + EphemeralResources: []tfprotov6.EphemeralResourceMetadata{}, + Functions: []tfprotov6.FunctionMetadata{}, + ListResources: []tfprotov6.ListResourceMetadata{}, + Resources: []tfprotov6.ResourceMetadata{}, + ServerCapabilities: &tfprotov6.ServerCapabilities{ + GetProviderSchemaOptional: true, + MoveResourceState: true, + PlanDestroy: true, + }, + }, + }, + "listresources": { + server: &Server{ + FrameworkServer: fwserver.Server{ + Provider: &testprovider.Provider{ + ListResourcesMethod: func(_ context.Context) []func() list.ListResource { + return []func() list.ListResource{ + func() list.ListResource { + return &testprovider.ListResource{ + MetadataMethod: func(_ context.Context, _ resource.MetadataRequest, resp *resource.MetadataResponse) { + resp.TypeName = "test_list_resource1" + }, + } + }, + func() list.ListResource { + return &testprovider.ListResource{ + MetadataMethod: func(_ context.Context, _ resource.MetadataRequest, resp *resource.MetadataResponse) { + resp.TypeName = "test_list_resource2" + }, + } + }, + } + }, + ResourcesMethod: func(_ context.Context) []func() resource.Resource { + return []func() resource.Resource{ + func() resource.Resource { + return &testprovider.Resource{ + MetadataMethod: func(_ context.Context, _ resource.MetadataRequest, resp *resource.MetadataResponse) { + resp.TypeName = "test_list_resource1" + }, + } + }, + func() resource.Resource { + return &testprovider.Resource{ + MetadataMethod: func(_ context.Context, _ resource.MetadataRequest, resp *resource.MetadataResponse) { + resp.TypeName = "test_list_resource2" + }, + } + }, + } + }, + }, + }, + }, + request: &tfprotov6.GetMetadataRequest{}, + expectedResponse: &tfprotov6.GetMetadataResponse{ + DataSources: []tfprotov6.DataSourceMetadata{}, + EphemeralResources: []tfprotov6.EphemeralResourceMetadata{}, + Functions: []tfprotov6.FunctionMetadata{}, + ListResources: []tfprotov6.ListResourceMetadata{ + { + TypeName: "test_list_resource1", + }, + { + TypeName: "test_list_resource2", + }, + }, + Resources: []tfprotov6.ResourceMetadata{ + { + TypeName: "test_list_resource1", + }, + { + TypeName: "test_list_resource2", + }, + }, + ServerCapabilities: &tfprotov6.ServerCapabilities{ + GetProviderSchemaOptional: true, + MoveResourceState: true, + PlanDestroy: true, + }, + }, + }, + "listresources-duplicate-type-name": { + server: &Server{ + FrameworkServer: fwserver.Server{ + Provider: &testprovider.Provider{ + ListResourcesMethod: func(_ context.Context) []func() list.ListResource { + return []func() list.ListResource{ + func() list.ListResource { + return &testprovider.ListResource{ + MetadataMethod: func(_ context.Context, _ resource.MetadataRequest, resp *resource.MetadataResponse) { + resp.TypeName = "test_list_resource" + }, + } + }, + func() list.ListResource { + return &testprovider.ListResource{ + MetadataMethod: func(_ context.Context, _ resource.MetadataRequest, resp *resource.MetadataResponse) { + resp.TypeName = "test_list_resource" + }, + } + }, + } + }, + ResourcesMethod: func(_ context.Context) []func() resource.Resource { + return []func() resource.Resource{ + func() resource.Resource { + return &testprovider.Resource{ + MetadataMethod: func(_ context.Context, _ resource.MetadataRequest, resp *resource.MetadataResponse) { + resp.TypeName = "test_list_resource" + }, + } + }, + } + }, + }, + }, + }, + request: &tfprotov6.GetMetadataRequest{}, + expectedResponse: &tfprotov6.GetMetadataResponse{ + DataSources: []tfprotov6.DataSourceMetadata{}, + Diagnostics: []*tfprotov6.Diagnostic{ + { + Severity: tfprotov6.DiagnosticSeverityError, + Summary: "Duplicate ListResource Type Defined", + Detail: "The test_list_resource ListResource type name was returned for multiple list resources. " + + "ListResource type names must be unique. " + + "This is always an issue with the provider and should be reported to the provider developers.", + }, + }, + EphemeralResources: []tfprotov6.EphemeralResourceMetadata{}, + Functions: []tfprotov6.FunctionMetadata{}, + ListResources: []tfprotov6.ListResourceMetadata{}, + Resources: []tfprotov6.ResourceMetadata{}, + ServerCapabilities: &tfprotov6.ServerCapabilities{ + GetProviderSchemaOptional: true, + MoveResourceState: true, + PlanDestroy: true, + }, + }, + }, + "listresources-empty-type-name": { + server: &Server{ + FrameworkServer: fwserver.Server{ + Provider: &testprovider.Provider{ + ListResourcesMethod: func(_ context.Context) []func() list.ListResource { + return []func() list.ListResource{ + func() list.ListResource { + return &testprovider.ListResource{ + MetadataMethod: func(_ context.Context, _ resource.MetadataRequest, resp *resource.MetadataResponse) { + resp.TypeName = "" + }, + } + }, + } + }, + ResourcesMethod: func(_ context.Context) []func() resource.Resource { + return []func() resource.Resource{ + func() resource.Resource { + return &testprovider.Resource{ + MetadataMethod: func(_ context.Context, _ resource.MetadataRequest, resp *resource.MetadataResponse) { + resp.TypeName = "test_list_resource" + }, + } + }, + } + }, + }, + }, + }, + request: &tfprotov6.GetMetadataRequest{}, + expectedResponse: &tfprotov6.GetMetadataResponse{ + DataSources: []tfprotov6.DataSourceMetadata{}, + Diagnostics: []*tfprotov6.Diagnostic{ + { + Severity: tfprotov6.DiagnosticSeverityError, + Summary: "ListResource Type Name Missing", + Detail: "The *testprovider.ListResource ListResource returned an empty string from the Metadata method. " + + "This is always an issue with the provider and should be reported to the provider developers.", + }, + }, + EphemeralResources: []tfprotov6.EphemeralResourceMetadata{}, + Functions: []tfprotov6.FunctionMetadata{}, + ListResources: []tfprotov6.ListResourceMetadata{}, + Resources: []tfprotov6.ResourceMetadata{}, + ServerCapabilities: &tfprotov6.ServerCapabilities{ + GetProviderSchemaOptional: true, + MoveResourceState: true, + PlanDestroy: true, + }, + }, + }, + "listresources-missing-resource-definition": { + server: &Server{ + FrameworkServer: fwserver.Server{ + Provider: &testprovider.Provider{ + ListResourcesMethod: func(_ context.Context) []func() list.ListResource { + return []func() list.ListResource{ + func() list.ListResource { + return &testprovider.ListResource{ + MetadataMethod: func(_ context.Context, _ resource.MetadataRequest, resp *resource.MetadataResponse) { + resp.TypeName = "test_list_resource" + }, + } + }, + } + }, + }, + }, + }, + request: &tfprotov6.GetMetadataRequest{}, + expectedResponse: &tfprotov6.GetMetadataResponse{ + DataSources: []tfprotov6.DataSourceMetadata{}, + Diagnostics: []*tfprotov6.Diagnostic{ + { + Severity: tfprotov6.DiagnosticSeverityError, + Summary: "ListResource Type Defined without a Matching Managed Resource Type", + Detail: "The test_list_resource ListResource type name was returned, but no matching managed Resource type was defined. " + + "This is always an issue with the provider and should be reported to the provider developers.", + }, + }, + EphemeralResources: []tfprotov6.EphemeralResourceMetadata{}, + Functions: []tfprotov6.FunctionMetadata{}, + ListResources: []tfprotov6.ListResourceMetadata{}, + Resources: []tfprotov6.ResourceMetadata{}, ServerCapabilities: &tfprotov6.ServerCapabilities{ GetProviderSchemaOptional: true, MoveResourceState: true, @@ -450,6 +681,7 @@ func TestServerGetMetadata(t *testing.T) { DataSources: []tfprotov6.DataSourceMetadata{}, EphemeralResources: []tfprotov6.EphemeralResourceMetadata{}, Functions: []tfprotov6.FunctionMetadata{}, + ListResources: []tfprotov6.ListResourceMetadata{}, Resources: []tfprotov6.ResourceMetadata{ { TypeName: "test_resource1", @@ -492,8 +724,7 @@ func TestServerGetMetadata(t *testing.T) { }, request: &tfprotov6.GetMetadataRequest{}, expectedResponse: &tfprotov6.GetMetadataResponse{ - DataSources: []tfprotov6.DataSourceMetadata{}, - EphemeralResources: []tfprotov6.EphemeralResourceMetadata{}, + DataSources: []tfprotov6.DataSourceMetadata{}, Diagnostics: []*tfprotov6.Diagnostic{ { Severity: tfprotov6.DiagnosticSeverityError, @@ -503,8 +734,10 @@ func TestServerGetMetadata(t *testing.T) { "This is always an issue with the provider and should be reported to the provider developers.", }, }, - Functions: []tfprotov6.FunctionMetadata{}, - Resources: []tfprotov6.ResourceMetadata{}, + EphemeralResources: []tfprotov6.EphemeralResourceMetadata{}, + Functions: []tfprotov6.FunctionMetadata{}, + ListResources: []tfprotov6.ListResourceMetadata{}, + Resources: []tfprotov6.ResourceMetadata{}, ServerCapabilities: &tfprotov6.ServerCapabilities{ GetProviderSchemaOptional: true, MoveResourceState: true, @@ -532,8 +765,7 @@ func TestServerGetMetadata(t *testing.T) { }, request: &tfprotov6.GetMetadataRequest{}, expectedResponse: &tfprotov6.GetMetadataResponse{ - DataSources: []tfprotov6.DataSourceMetadata{}, - EphemeralResources: []tfprotov6.EphemeralResourceMetadata{}, + DataSources: []tfprotov6.DataSourceMetadata{}, Diagnostics: []*tfprotov6.Diagnostic{ { Severity: tfprotov6.DiagnosticSeverityError, @@ -542,8 +774,10 @@ func TestServerGetMetadata(t *testing.T) { "This is always an issue with the provider and should be reported to the provider developers.", }, }, - Functions: []tfprotov6.FunctionMetadata{}, - Resources: []tfprotov6.ResourceMetadata{}, + EphemeralResources: []tfprotov6.EphemeralResourceMetadata{}, + Functions: []tfprotov6.FunctionMetadata{}, + ListResources: []tfprotov6.ListResourceMetadata{}, + Resources: []tfprotov6.ResourceMetadata{}, ServerCapabilities: &tfprotov6.ServerCapabilities{ GetProviderSchemaOptional: true, MoveResourceState: true, diff --git a/internal/toproto5/getmetadata.go b/internal/toproto5/getmetadata.go index 4150c2473..8039a892c 100644 --- a/internal/toproto5/getmetadata.go +++ b/internal/toproto5/getmetadata.go @@ -22,6 +22,7 @@ func GetMetadataResponse(ctx context.Context, fw *fwserver.GetMetadataResponse) Diagnostics: Diagnostics(ctx, fw.Diagnostics), EphemeralResources: make([]tfprotov5.EphemeralResourceMetadata, 0, len(fw.EphemeralResources)), Functions: make([]tfprotov5.FunctionMetadata, 0, len(fw.Functions)), + ListResources: make([]tfprotov5.ListResourceMetadata, 0, len(fw.ListResources)), Resources: make([]tfprotov5.ResourceMetadata, 0, len(fw.Resources)), ServerCapabilities: ServerCapabilities(ctx, fw.ServerCapabilities), } @@ -38,6 +39,10 @@ func GetMetadataResponse(ctx context.Context, fw *fwserver.GetMetadataResponse) protov5.Functions = append(protov5.Functions, FunctionMetadata(ctx, function)) } + for _, listResource := range fw.ListResources { + protov5.ListResources = append(protov5.ListResources, ListResourceMetadata(ctx, listResource)) + } + for _, resource := range fw.Resources { protov5.Resources = append(protov5.Resources, ResourceMetadata(ctx, resource)) } diff --git a/internal/toproto5/getmetadata_test.go b/internal/toproto5/getmetadata_test.go index a2d0c2bdc..2180ec781 100644 --- a/internal/toproto5/getmetadata_test.go +++ b/internal/toproto5/getmetadata_test.go @@ -47,6 +47,7 @@ func TestGetMetadataResponse(t *testing.T) { }, EphemeralResources: []tfprotov5.EphemeralResourceMetadata{}, Functions: []tfprotov5.FunctionMetadata{}, + ListResources: []tfprotov5.ListResourceMetadata{}, Resources: []tfprotov5.ResourceMetadata{}, }, }, @@ -71,8 +72,9 @@ func TestGetMetadataResponse(t *testing.T) { TypeName: "test_ephemeral_resource_2", }, }, - Functions: []tfprotov5.FunctionMetadata{}, - Resources: []tfprotov5.ResourceMetadata{}, + Functions: []tfprotov5.FunctionMetadata{}, + ListResources: []tfprotov5.ListResourceMetadata{}, + Resources: []tfprotov5.ResourceMetadata{}, }, }, "diagnostics": { @@ -99,6 +101,7 @@ func TestGetMetadataResponse(t *testing.T) { }, EphemeralResources: []tfprotov5.EphemeralResourceMetadata{}, Functions: []tfprotov5.FunctionMetadata{}, + ListResources: []tfprotov5.ListResourceMetadata{}, Resources: []tfprotov5.ResourceMetadata{}, }, }, @@ -124,6 +127,33 @@ func TestGetMetadataResponse(t *testing.T) { Name: "function2", }, }, + ListResources: []tfprotov5.ListResourceMetadata{}, + Resources: []tfprotov5.ResourceMetadata{}, + }, + }, + "listresources": { + input: &fwserver.GetMetadataResponse{ + ListResources: []fwserver.ListResourceMetadata{ + { + TypeName: "test_list_resource_1", + }, + { + TypeName: "test_list_resource_2", + }, + }, + }, + expected: &tfprotov5.GetMetadataResponse{ + DataSources: []tfprotov5.DataSourceMetadata{}, + EphemeralResources: []tfprotov5.EphemeralResourceMetadata{}, + Functions: []tfprotov5.FunctionMetadata{}, + ListResources: []tfprotov5.ListResourceMetadata{ + { + TypeName: "test_list_resource_1", + }, + { + TypeName: "test_list_resource_2", + }, + }, Resources: []tfprotov5.ResourceMetadata{}, }, }, @@ -142,6 +172,7 @@ func TestGetMetadataResponse(t *testing.T) { DataSources: []tfprotov5.DataSourceMetadata{}, EphemeralResources: []tfprotov5.EphemeralResourceMetadata{}, Functions: []tfprotov5.FunctionMetadata{}, + ListResources: []tfprotov5.ListResourceMetadata{}, Resources: []tfprotov5.ResourceMetadata{ { TypeName: "test_resource_1", @@ -164,6 +195,7 @@ func TestGetMetadataResponse(t *testing.T) { EphemeralResources: []tfprotov5.EphemeralResourceMetadata{}, Functions: []tfprotov5.FunctionMetadata{}, Resources: []tfprotov5.ResourceMetadata{}, + ListResources: []tfprotov5.ListResourceMetadata{}, ServerCapabilities: &tfprotov5.ServerCapabilities{ GetProviderSchemaOptional: true, PlanDestroy: true, diff --git a/internal/toproto6/getmetadata.go b/internal/toproto6/getmetadata.go index 314072392..bf235fe21 100644 --- a/internal/toproto6/getmetadata.go +++ b/internal/toproto6/getmetadata.go @@ -22,6 +22,7 @@ func GetMetadataResponse(ctx context.Context, fw *fwserver.GetMetadataResponse) Diagnostics: Diagnostics(ctx, fw.Diagnostics), EphemeralResources: make([]tfprotov6.EphemeralResourceMetadata, 0, len(fw.EphemeralResources)), Functions: make([]tfprotov6.FunctionMetadata, 0, len(fw.Functions)), + ListResources: make([]tfprotov6.ListResourceMetadata, 0, len(fw.ListResources)), Resources: make([]tfprotov6.ResourceMetadata, 0, len(fw.Resources)), ServerCapabilities: ServerCapabilities(ctx, fw.ServerCapabilities), } @@ -38,6 +39,10 @@ func GetMetadataResponse(ctx context.Context, fw *fwserver.GetMetadataResponse) protov6.Functions = append(protov6.Functions, FunctionMetadata(ctx, function)) } + for _, listResource := range fw.ListResources { + protov6.ListResources = append(protov6.ListResources, ListResourceMetadata(ctx, listResource)) + } + for _, resource := range fw.Resources { protov6.Resources = append(protov6.Resources, ResourceMetadata(ctx, resource)) } diff --git a/internal/toproto6/getmetadata_test.go b/internal/toproto6/getmetadata_test.go index fe02ebf1c..ee601823d 100644 --- a/internal/toproto6/getmetadata_test.go +++ b/internal/toproto6/getmetadata_test.go @@ -47,6 +47,7 @@ func TestGetMetadataResponse(t *testing.T) { }, EphemeralResources: []tfprotov6.EphemeralResourceMetadata{}, Functions: []tfprotov6.FunctionMetadata{}, + ListResources: []tfprotov6.ListResourceMetadata{}, Resources: []tfprotov6.ResourceMetadata{}, }, }, @@ -74,6 +75,7 @@ func TestGetMetadataResponse(t *testing.T) { }, EphemeralResources: []tfprotov6.EphemeralResourceMetadata{}, Functions: []tfprotov6.FunctionMetadata{}, + ListResources: []tfprotov6.ListResourceMetadata{}, Resources: []tfprotov6.ResourceMetadata{}, }, }, @@ -98,8 +100,9 @@ func TestGetMetadataResponse(t *testing.T) { TypeName: "test_ephemeral_resource_2", }, }, - Functions: []tfprotov6.FunctionMetadata{}, - Resources: []tfprotov6.ResourceMetadata{}, + Functions: []tfprotov6.FunctionMetadata{}, + ListResources: []tfprotov6.ListResourceMetadata{}, + Resources: []tfprotov6.ResourceMetadata{}, }, }, "functions": { @@ -124,6 +127,33 @@ func TestGetMetadataResponse(t *testing.T) { Name: "function2", }, }, + ListResources: []tfprotov6.ListResourceMetadata{}, + Resources: []tfprotov6.ResourceMetadata{}, + }, + }, + "listresources": { + input: &fwserver.GetMetadataResponse{ + ListResources: []fwserver.ListResourceMetadata{ + { + TypeName: "test_list_resource_1", + }, + { + TypeName: "test_list_resource_2", + }, + }, + }, + expected: &tfprotov6.GetMetadataResponse{ + DataSources: []tfprotov6.DataSourceMetadata{}, + EphemeralResources: []tfprotov6.EphemeralResourceMetadata{}, + Functions: []tfprotov6.FunctionMetadata{}, + ListResources: []tfprotov6.ListResourceMetadata{ + { + TypeName: "test_list_resource_1", + }, + { + TypeName: "test_list_resource_2", + }, + }, Resources: []tfprotov6.ResourceMetadata{}, }, }, @@ -142,6 +172,7 @@ func TestGetMetadataResponse(t *testing.T) { DataSources: []tfprotov6.DataSourceMetadata{}, EphemeralResources: []tfprotov6.EphemeralResourceMetadata{}, Functions: []tfprotov6.FunctionMetadata{}, + ListResources: []tfprotov6.ListResourceMetadata{}, Resources: []tfprotov6.ResourceMetadata{ { TypeName: "test_resource_1", @@ -163,6 +194,7 @@ func TestGetMetadataResponse(t *testing.T) { DataSources: []tfprotov6.DataSourceMetadata{}, EphemeralResources: []tfprotov6.EphemeralResourceMetadata{}, Functions: []tfprotov6.FunctionMetadata{}, + ListResources: []tfprotov6.ListResourceMetadata{}, Resources: []tfprotov6.ResourceMetadata{}, ServerCapabilities: &tfprotov6.ServerCapabilities{ GetProviderSchemaOptional: true,