diff --git a/agent/grpc-external/services/resource/read.go b/agent/grpc-external/services/resource/read.go index cab8a2d6f2af1..8c178b863e67c 100644 --- a/agent/grpc-external/services/resource/read.go +++ b/agent/grpc-external/services/resource/read.go @@ -60,7 +60,7 @@ func (s *Server) Read(ctx context.Context, req *pbresource.ReadRequest) (*pbreso } // Check tenancy exists for the V2 resource. - if err = tenancyExists(reg, s.TenancyBridge, req.Id.Tenancy, codes.NotFound); err != nil { + if err = tenancyExists(reg, s.TenancyBridge, req.Id.Tenancy, codes.InvalidArgument); err != nil { return nil, err } diff --git a/internal/tenancy/tenancytest/namespace_test.go b/internal/tenancy/tenancytest/namespace_test.go index 56b0c7049a200..45b078b1f61f0 100644 --- a/internal/tenancy/tenancytest/namespace_test.go +++ b/internal/tenancy/tenancytest/namespace_test.go @@ -5,11 +5,13 @@ package tenancytest import ( "context" + "fmt" + "testing" + "github.com/hashicorp/consul/agent/grpc-external/services/resource" svctest "github.com/hashicorp/consul/agent/grpc-external/services/resource/testing" resource2 "github.com/hashicorp/consul/internal/resource" "github.com/hashicorp/consul/internal/tenancy" - "testing" rtest "github.com/hashicorp/consul/internal/resource/resourcetest" "github.com/hashicorp/consul/proto/private/prototest" @@ -21,19 +23,65 @@ import ( "github.com/stretchr/testify/require" ) -func TestReadNamespace_Success(t *testing.T) { +func TestWriteNamespace_Success(t *testing.T) { v2TenancyBridge := tenancy.NewV2TenancyBridge() config := resource.Config{TenancyBridge: v2TenancyBridge} client := svctest.RunResourceServiceWithConfig(t, config, tenancy.RegisterTypes) cl := rtest.NewClient(client) res := rtest.Resource(pbtenancy.NamespaceType, "ns1"). + WithTenancy(resource2.DefaultPartitionedTenancy()). WithData(t, validNamespace()). - Write(t, cl) + Build() - readRsp, err := cl.Read(context.Background(), &pbresource.ReadRequest{Id: res.Id}) + writeRsp, err := cl.Write(context.Background(), &pbresource.WriteRequest{Resource: res}) require.NoError(t, err) - prototest.AssertDeepEqual(t, res.Id, readRsp.Resource.Id) + prototest.AssertDeepEqual(t, res.Id.Type, writeRsp.Resource.Id.Type) + prototest.AssertDeepEqual(t, res.Id.Tenancy, writeRsp.Resource.Id.Tenancy) + prototest.AssertDeepEqual(t, res.Id.Name, writeRsp.Resource.Id.Name) + prototest.AssertDeepEqual(t, res.Data, writeRsp.Resource.Data) +} + +func TestReadNamespace_Success(t *testing.T) { + v2TenancyBridge := tenancy.NewV2TenancyBridge() + config := resource.Config{TenancyBridge: v2TenancyBridge} + client := svctest.RunResourceServiceWithConfig(t, config, tenancy.RegisterTypes) + cl := rtest.NewClient(client) + + writeResp := rtest.Resource(pbtenancy.NamespaceType, "ns1"). + WithData(t, validNamespace()). + Write(t, cl) + + cases := []struct { + name string + resource *pbresource.Resource + errMsg string + }{ + { + name: "read namespace", + resource: rtest.Resource(pbtenancy.NamespaceType, "ns1"). + WithData(t, validNamespace()). + Build(), + }, + { + name: "tenancy units: empty namespace is allowed", + resource: rtest.Resource(pbtenancy.NamespaceType, "ns1"). + WithTenancy(&pbresource.Tenancy{ + Namespace: "", + }). + WithData(t, validNamespace()). + Build(), + }, + } + + for _, tc := range cases { + t.Run(tc.name, func(t *testing.T) { + readRsp, err := cl.Read(context.Background(), &pbresource.ReadRequest{Id: tc.resource.Id}) + require.NoError(t, err) + prototest.AssertDeepEqual(t, writeResp.Id, readRsp.Resource.Id) + prototest.AssertDeepEqual(t, writeResp.Data, readRsp.Resource.Data) + }) + } } func TestReadNamespace_NotFound(t *testing.T) { @@ -50,6 +98,50 @@ func TestReadNamespace_NotFound(t *testing.T) { require.Equal(t, codes.NotFound.String(), status.Code(err).String()) } +func TestReadNamespace_InvalidArgument(t *testing.T) { + v2TenancyBridge := tenancy.NewV2TenancyBridge() + config := resource.Config{TenancyBridge: v2TenancyBridge} + client := svctest.RunResourceServiceWithConfig(t, config, tenancy.RegisterTypes) + cl := rtest.NewClient(client) + + cases := []struct { + name string + resource *pbresource.Resource + errMsg string + }{ + { + name: "tenancy units: namespace not empty", + resource: rtest.Resource(pbtenancy.NamespaceType, "ns1"). + WithTenancy(&pbresource.Tenancy{ + Partition: "default", + Namespace: "ns2", + }). + WithData(t, validNamespace()). + Build(), + errMsg: fmt.Sprintf("partition scoped resource %s.%s.%s cannot have a namespace. got: ns2", pbtenancy.NamespaceType.Group, pbtenancy.NamespaceType.GroupVersion, pbtenancy.NamespaceType.Kind), + }, + { + name: "tenancy units: partition not present", + resource: rtest.Resource(pbtenancy.NamespaceType, "ns1"). + WithTenancy(&pbresource.Tenancy{ + Partition: "partition1", + }). + WithData(t, validNamespace()). + Build(), + errMsg: "partition not found: partition1", + }, + } + + for _, tc := range cases { + t.Run(tc.name, func(t *testing.T) { + _, err := cl.Read(context.Background(), &pbresource.ReadRequest{Id: tc.resource.Id}) + require.Error(t, err) + require.Equal(t, codes.InvalidArgument.String(), status.Code(err).String()) + require.Contains(t, err.Error(), tc.errMsg) + }) + } +} + func TestDeleteNamespace_Success(t *testing.T) { v2TenancyBridge := tenancy.NewV2TenancyBridge() config := resource.Config{TenancyBridge: v2TenancyBridge}