diff --git a/internal/api/grpc/instance/v2/converter.go b/internal/api/grpc/instance/v2/converter.go index 30abf90dbf4..753f28e8266 100644 --- a/internal/api/grpc/instance/v2/converter.go +++ b/internal/api/grpc/instance/v2/converter.go @@ -12,8 +12,8 @@ import ( func InstancesToPb(instances []*query.Instance) []*instance.Instance { list := []*instance.Instance{} - for i, instance := range instances { - list[i] = ToProtoObject(instance) + for _, instance := range instances { + list = append(list, ToProtoObject(instance)) } return list } @@ -88,12 +88,13 @@ func fieldNameToInstanceColumn(fieldName instance.FieldName) query.Column { } func instanceQueriesToModel(queries []*instance.Query) (_ []query.SearchQuery, err error) { - q := make([]query.SearchQuery, len(queries)) - for i, query := range queries { - q[i], err = instanceQueryToModel(query) + q := []query.SearchQuery{} + for _, query := range queries { + model, err := instanceQueryToModel(query) if err != nil { return nil, err } + q = append(q, model) } return q, nil } diff --git a/internal/api/grpc/instance/v2/converter_test.go b/internal/api/grpc/instance/v2/converter_test.go new file mode 100644 index 00000000000..0678ba64011 --- /dev/null +++ b/internal/api/grpc/instance/v2/converter_test.go @@ -0,0 +1,228 @@ +package instance + +import ( + "errors" + "testing" + "time" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "github.com/zitadel/zitadel/cmd/build" + "github.com/zitadel/zitadel/internal/config/systemdefaults" + "github.com/zitadel/zitadel/internal/query" + "github.com/zitadel/zitadel/internal/zerrors" + filter "github.com/zitadel/zitadel/pkg/grpc/filter/v2beta" + "github.com/zitadel/zitadel/pkg/grpc/instance/v2" + "github.com/zitadel/zitadel/pkg/grpc/object/v2" + "google.golang.org/protobuf/types/known/timestamppb" +) + +func Test_InstancesToPb(t *testing.T) { + instances := []*query.Instance{ + { + ID: "instance1", + Name: "Instance One", + Domains: []*query.InstanceDomain{ + { + Domain: "example.com", + IsPrimary: true, + IsGenerated: false, + Sequence: 1, + CreationDate: time.Unix(123, 0), + ChangeDate: time.Unix(124, 0), + InstanceID: "instance1", + }, + }, + Sequence: 1, + CreationDate: time.Unix(123, 0), + ChangeDate: time.Unix(124, 0), + }, + } + + want := []*instance.Instance{ + { + Id: "instance1", + Name: "Instance One", + Domains: []*instance.Domain{ + { + Domain: "example.com", + Primary: true, + Generated: false, + Details: &object.Details{ + Sequence: 1, + ChangeDate: ×tamppb.Timestamp{Seconds: 124}, + CreationDate: ×tamppb.Timestamp{Seconds: 123}, + ResourceOwner: "instance1", + }, + }, + }, + Version: build.Version(), + Details: &object.Details{ + Sequence: 1, + ChangeDate: ×tamppb.Timestamp{Seconds: 124}, + CreationDate: ×tamppb.Timestamp{Seconds: 123}, + ResourceOwner: "instance1", + }, + }, + } + + got := InstancesToPb(instances) + assert.Equal(t, want, got) +} + +func Test_ListInstancesRequestToModel(t *testing.T) { + t.Parallel() + + searchInstanceByID, err := query.NewInstanceIDsListSearchQuery("instance1", "instance2") + require.Nil(t, err) + + tt := []struct { + testName string + inputRequest *instance.ListInstancesRequest + maxQueryLimit uint64 + expectedResult *query.InstanceSearchQueries + expectedError error + }{ + { + testName: "when query limit exceeds max query limit should return invalid argument error", + maxQueryLimit: 1, + inputRequest: &instance.ListInstancesRequest{ + Pagination: &filter.PaginationRequest{Limit: 10, Offset: 0, Asc: true}, + SortingColumn: instance.FieldName_FIELD_NAME_ID, + Queries: []*instance.Query{{Query: &instance.Query_IdQuery{IdQuery: &instance.IdsQuery{Ids: []string{"instance1", "instance2"}}}}}, + }, + expectedError: zerrors.ThrowInvalidArgumentf(errors.New("given: 10, allowed: 1"), "QUERY-4M0fs", "Errors.Query.LimitExceeded"), + }, + { + testName: "when valid request should return instance search query model", + inputRequest: &instance.ListInstancesRequest{ + Pagination: &filter.PaginationRequest{Limit: 10, Offset: 0, Asc: true}, + SortingColumn: instance.FieldName_FIELD_NAME_ID, + Queries: []*instance.Query{{Query: &instance.Query_IdQuery{IdQuery: &instance.IdsQuery{Ids: []string{"instance1", "instance2"}}}}}, + }, + expectedResult: &query.InstanceSearchQueries{ + SearchRequest: query.SearchRequest{ + Offset: 0, + Limit: 10, + Asc: true, + SortingColumn: query.InstanceColumnID, + }, + Queries: []query.SearchQuery{searchInstanceByID}, + }, + }, + } + + for _, tc := range tt { + t.Run(tc.testName, func(t *testing.T) { + t.Parallel() + sysDefaults := systemdefaults.SystemDefaults{MaxQueryLimit: tc.maxQueryLimit} + + got, err := ListInstancesRequestToModel(tc.inputRequest, sysDefaults) + assert.Equal(t, tc.expectedError, err) + assert.Equal(t, tc.expectedResult, got) + + }) + } +} + +func Test_fieldNameToInstanceColumn(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + fieldName instance.FieldName + want query.Column + }{ + { + name: "ID field", + fieldName: instance.FieldName_FIELD_NAME_ID, + want: query.InstanceColumnID, + }, + { + name: "Name field", + fieldName: instance.FieldName_FIELD_NAME_NAME, + want: query.InstanceColumnName, + }, + { + name: "Creation Date field", + fieldName: instance.FieldName_FIELD_NAME_CREATION_DATE, + want: query.InstanceColumnCreationDate, + }, + { + name: "Unknown field", + fieldName: instance.FieldName(99), + want: query.Column{}, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + got := fieldNameToInstanceColumn(tt.fieldName) + assert.Equal(t, tt.want, got) + }) + } +} + +func Test_instanceQueryToModel(t *testing.T) { + t.Parallel() + + searchInstanceByID, err := query.NewInstanceIDsListSearchQuery("instance1") + require.Nil(t, err) + + searchInstanceByDomain, err := query.NewInstanceDomainsListSearchQuery("example.com") + require.Nil(t, err) + + tests := []struct { + name string + searchQuery *instance.Query + want query.SearchQuery + wantErr bool + }{ + { + name: "ID Query", + searchQuery: &instance.Query{ + Query: &instance.Query_IdQuery{ + IdQuery: &instance.IdsQuery{ + Ids: []string{"instance1"}, + }, + }, + }, + want: searchInstanceByID, + wantErr: false, + }, + { + name: "Domain Query", + searchQuery: &instance.Query{ + Query: &instance.Query_DomainQuery{ + DomainQuery: &instance.DomainsQuery{ + Domains: []string{"example.com"}, + }, + }, + }, + want: searchInstanceByDomain, + wantErr: false, + }, + { + name: "Invalid Query", + searchQuery: &instance.Query{ + Query: nil, + }, + want: nil, + wantErr: true, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + got, err := instanceQueryToModel(tt.searchQuery) + if tt.wantErr { + assert.Error(t, err) + } else { + assert.NoError(t, err) + assert.Equal(t, tt.want, got) + } + }) + } +}