mirror of
https://github.com/andwati/zitadel.git
synced 2026-11-09 15:45:12 +00:00
feat: instance domain APIs with relational tables (#11051)
# Which Problems Are Solved This PR implements the endpoints listed in https://github.com/zitadel/zitadel/issues/10444 . # How the Problems Are Solved The implementation follows the same pattern as the Instance one. The `Add` and `Remove` are implementing the `Commander` interface, while `List` Domains endpoints are implementing the `Querier` interace. The PR adds also some forgotten calls to the relational logic for the Instance API. The commits are identifiable by the label `instance:` prepended to them. This is the complete list: bafce01b0 , 6fe7257ab , e27bc9c34 , 8133ede73 , fde667953 , a3e1135ed , ee1a6f9c1 # Additional Context - Closes #10444 --------- Co-authored-by: Elio Bischof <[email protected]> Co-authored-by: Lebogang Phoshoko <[email protected]> Co-authored-by: Wim Van Laer <[email protected]> Co-authored-by: Max Peintner <[email protected]> Co-authored-by: Gayathri Vijayan <[email protected]>
This commit is contained in:
co-authored by
Elio Bischof
Lebogang Phoshoko
Wim Van Laer
Max Peintner
Gayathri Vijayan
parent
d79bfe6eba
commit
b339a3e696
@@ -9,9 +9,99 @@ import (
|
||||
"google.golang.org/protobuf/types/known/timestamppb"
|
||||
|
||||
"github.com/zitadel/zitadel/backend/v3/domain"
|
||||
instance "github.com/zitadel/zitadel/pkg/grpc/instance/v2beta"
|
||||
filter_v2 "github.com/zitadel/zitadel/pkg/grpc/filter/v2"
|
||||
filter_v2beta "github.com/zitadel/zitadel/pkg/grpc/filter/v2beta"
|
||||
instance_v2 "github.com/zitadel/zitadel/pkg/grpc/instance/v2"
|
||||
instance_v2beta "github.com/zitadel/zitadel/pkg/grpc/instance/v2beta"
|
||||
)
|
||||
|
||||
func TestDomainInstanceModelToGRPCBetaResponse(t *testing.T) {
|
||||
// Given
|
||||
t.Parallel()
|
||||
|
||||
now := time.Now().UTC()
|
||||
yesterday := now.AddDate(0, 0, -1)
|
||||
|
||||
inputInstance := &domain.Instance{
|
||||
ID: "instance-1",
|
||||
Name: "Instance One",
|
||||
CreatedAt: yesterday,
|
||||
UpdatedAt: now,
|
||||
Domains: []*domain.InstanceDomain{
|
||||
{
|
||||
InstanceID: "instance-1",
|
||||
Domain: "d1.example.com",
|
||||
IsPrimary: gu.Ptr(true),
|
||||
CreatedAt: yesterday,
|
||||
},
|
||||
{
|
||||
InstanceID: "instance-1",
|
||||
Domain: "d2.example.com",
|
||||
IsGenerated: gu.Ptr(true),
|
||||
CreatedAt: yesterday,
|
||||
},
|
||||
{
|
||||
InstanceID: "instance-1",
|
||||
Domain: "d3.example.com",
|
||||
IsPrimary: gu.Ptr(true),
|
||||
IsGenerated: gu.Ptr(false),
|
||||
CreatedAt: yesterday,
|
||||
},
|
||||
{
|
||||
InstanceID: "instance-1",
|
||||
Domain: "d4.example.com",
|
||||
IsPrimary: gu.Ptr(false),
|
||||
IsGenerated: gu.Ptr(true),
|
||||
CreatedAt: yesterday,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
expectedInstance := &instance_v2beta.Instance{
|
||||
Id: "instance-1",
|
||||
ChangeDate: timestamppb.New(now),
|
||||
CreationDate: timestamppb.New(yesterday),
|
||||
Name: "Instance One",
|
||||
Version: "",
|
||||
Domains: []*instance_v2beta.Domain{
|
||||
{
|
||||
InstanceId: "instance-1",
|
||||
CreationDate: timestamppb.New(yesterday),
|
||||
Domain: "d1.example.com",
|
||||
Primary: true,
|
||||
Generated: false,
|
||||
},
|
||||
{
|
||||
InstanceId: "instance-1",
|
||||
CreationDate: timestamppb.New(yesterday),
|
||||
Domain: "d2.example.com",
|
||||
Primary: false,
|
||||
Generated: true,
|
||||
},
|
||||
{
|
||||
InstanceId: "instance-1",
|
||||
CreationDate: timestamppb.New(yesterday),
|
||||
Domain: "d3.example.com",
|
||||
Primary: true,
|
||||
Generated: false,
|
||||
},
|
||||
{
|
||||
InstanceId: "instance-1",
|
||||
CreationDate: timestamppb.New(yesterday),
|
||||
Domain: "d4.example.com",
|
||||
Primary: false,
|
||||
Generated: true,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
// Test
|
||||
res := DomainInstanceModelToGRPCBetaResponse(inputInstance)
|
||||
|
||||
// Verify
|
||||
assert.Equal(t, expectedInstance, res)
|
||||
}
|
||||
|
||||
func TestDomainInstanceModelToGRPCResponse(t *testing.T) {
|
||||
// Given
|
||||
t.Parallel()
|
||||
@@ -54,14 +144,14 @@ func TestDomainInstanceModelToGRPCResponse(t *testing.T) {
|
||||
},
|
||||
}
|
||||
|
||||
expectedInstance := &instance.Instance{
|
||||
expectedInstance := &instance_v2.Instance{
|
||||
Id: "instance-1",
|
||||
ChangeDate: timestamppb.New(now),
|
||||
CreationDate: timestamppb.New(yesterday),
|
||||
State: instance.State_STATE_RUNNING,
|
||||
State: instance_v2.State_STATE_RUNNING,
|
||||
Name: "Instance One",
|
||||
Version: "",
|
||||
Domains: []*instance.Domain{
|
||||
CustomDomains: []*instance_v2.CustomDomain{
|
||||
{
|
||||
InstanceId: "instance-1",
|
||||
CreationDate: timestamppb.New(yesterday),
|
||||
@@ -100,19 +190,19 @@ func TestDomainInstanceModelToGRPCResponse(t *testing.T) {
|
||||
assert.Equal(t, expectedInstance, res)
|
||||
}
|
||||
|
||||
func TestDomainInstanceListModelToGRPCResponse(t *testing.T) {
|
||||
func TestDomainInstanceListModelToGRPCBetaResponse(t *testing.T) {
|
||||
t.Parallel()
|
||||
now := time.Now()
|
||||
|
||||
tt := []struct {
|
||||
testName string
|
||||
inputResult []*domain.Instance
|
||||
expectedResult []*instance.Instance
|
||||
expectedResult []*instance_v2beta.Instance
|
||||
}{
|
||||
{
|
||||
testName: "empty result",
|
||||
inputResult: []*domain.Instance{},
|
||||
expectedResult: []*instance.Instance{},
|
||||
expectedResult: []*instance_v2beta.Instance{},
|
||||
},
|
||||
{
|
||||
testName: "single instance without domains",
|
||||
@@ -125,14 +215,13 @@ func TestDomainInstanceListModelToGRPCResponse(t *testing.T) {
|
||||
Domains: nil,
|
||||
},
|
||||
},
|
||||
expectedResult: []*instance.Instance{
|
||||
expectedResult: []*instance_v2beta.Instance{
|
||||
{
|
||||
Id: "instance1",
|
||||
Name: "test-instance",
|
||||
CreationDate: timestamppb.New(now),
|
||||
ChangeDate: timestamppb.New(now),
|
||||
State: instance.State_STATE_RUNNING,
|
||||
Domains: []*instance.Domain{},
|
||||
Domains: []*instance_v2beta.Domain{},
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -162,14 +251,13 @@ func TestDomainInstanceListModelToGRPCResponse(t *testing.T) {
|
||||
Domains: nil,
|
||||
},
|
||||
},
|
||||
expectedResult: []*instance.Instance{
|
||||
expectedResult: []*instance_v2beta.Instance{
|
||||
{
|
||||
Id: "instance1",
|
||||
Name: "test-instance-1",
|
||||
CreationDate: timestamppb.New(now),
|
||||
ChangeDate: timestamppb.New(now),
|
||||
State: instance.State_STATE_RUNNING,
|
||||
Domains: []*instance.Domain{
|
||||
Domains: []*instance_v2beta.Domain{
|
||||
{
|
||||
InstanceId: "instance1",
|
||||
Domain: "domain1.com",
|
||||
@@ -184,8 +272,110 @@ func TestDomainInstanceListModelToGRPCResponse(t *testing.T) {
|
||||
Name: "test-instance-2",
|
||||
CreationDate: timestamppb.New(now),
|
||||
ChangeDate: timestamppb.New(now),
|
||||
State: instance.State_STATE_RUNNING,
|
||||
Domains: []*instance.Domain{},
|
||||
Domains: []*instance_v2beta.Domain{},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range tt {
|
||||
t.Run(tc.testName, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
// Test
|
||||
result := DomainInstanceListModelToGRPCBetaResponse(tc.inputResult)
|
||||
|
||||
// Verify
|
||||
assert.Equal(t, tc.expectedResult, result)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestDomainInstanceListModelToGRPCResponse(t *testing.T) {
|
||||
t.Parallel()
|
||||
now := time.Now()
|
||||
|
||||
tt := []struct {
|
||||
testName string
|
||||
inputResult []*domain.Instance
|
||||
expectedResult []*instance_v2.Instance
|
||||
}{
|
||||
{
|
||||
testName: "empty result",
|
||||
inputResult: []*domain.Instance{},
|
||||
expectedResult: []*instance_v2.Instance{},
|
||||
},
|
||||
{
|
||||
testName: "single instance without domains",
|
||||
inputResult: []*domain.Instance{
|
||||
{
|
||||
ID: "instance1",
|
||||
Name: "test-instance",
|
||||
CreatedAt: now,
|
||||
UpdatedAt: now,
|
||||
Domains: nil,
|
||||
},
|
||||
},
|
||||
expectedResult: []*instance_v2.Instance{
|
||||
{
|
||||
Id: "instance1",
|
||||
Name: "test-instance",
|
||||
CreationDate: timestamppb.New(now),
|
||||
ChangeDate: timestamppb.New(now),
|
||||
State: instance_v2.State_STATE_RUNNING,
|
||||
CustomDomains: []*instance_v2.CustomDomain{},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
testName: "multiple instances with domains",
|
||||
inputResult: []*domain.Instance{
|
||||
{
|
||||
ID: "instance1",
|
||||
Name: "test-instance-1",
|
||||
CreatedAt: now,
|
||||
UpdatedAt: now,
|
||||
Domains: []*domain.InstanceDomain{
|
||||
{
|
||||
InstanceID: "instance1",
|
||||
Domain: "domain1.com",
|
||||
CreatedAt: now,
|
||||
IsPrimary: gu.Ptr(true),
|
||||
IsGenerated: gu.Ptr(false),
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
ID: "instance2",
|
||||
Name: "test-instance-2",
|
||||
CreatedAt: now,
|
||||
UpdatedAt: now,
|
||||
Domains: nil,
|
||||
},
|
||||
},
|
||||
expectedResult: []*instance_v2.Instance{
|
||||
{
|
||||
Id: "instance1",
|
||||
Name: "test-instance-1",
|
||||
CreationDate: timestamppb.New(now),
|
||||
ChangeDate: timestamppb.New(now),
|
||||
State: instance_v2.State_STATE_RUNNING,
|
||||
CustomDomains: []*instance_v2.CustomDomain{
|
||||
{
|
||||
InstanceId: "instance1",
|
||||
Domain: "domain1.com",
|
||||
CreationDate: timestamppb.New(now),
|
||||
Primary: true,
|
||||
Generated: false,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Id: "instance2",
|
||||
Name: "test-instance-2",
|
||||
CreationDate: timestamppb.New(now),
|
||||
ChangeDate: timestamppb.New(now),
|
||||
State: instance_v2.State_STATE_RUNNING,
|
||||
CustomDomains: []*instance_v2.CustomDomain{},
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -202,3 +392,140 @@ func TestDomainInstanceListModelToGRPCResponse(t *testing.T) {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestListInstancesBetaRequestToV2Request(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
tt := []struct {
|
||||
name string
|
||||
request *instance_v2beta.ListInstancesRequest
|
||||
want *instance_v2.ListInstancesRequest
|
||||
}{
|
||||
{
|
||||
name: "empty request",
|
||||
request: &instance_v2beta.ListInstancesRequest{
|
||||
Pagination: &filter_v2beta.PaginationRequest{},
|
||||
},
|
||||
want: &instance_v2.ListInstancesRequest{
|
||||
Pagination: &filter_v2.PaginationRequest{},
|
||||
SortingColumn: instance_v2.FieldName_FIELD_NAME_UNSPECIFIED,
|
||||
Filters: []*instance_v2.Filter{},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "request with all fields",
|
||||
request: &instance_v2beta.ListInstancesRequest{
|
||||
Pagination: &filter_v2beta.PaginationRequest{
|
||||
Offset: 10,
|
||||
Limit: 20,
|
||||
Asc: true,
|
||||
},
|
||||
SortingColumn: gu.Ptr(instance_v2beta.FieldName_FIELD_NAME_NAME),
|
||||
Queries: []*instance_v2beta.Query{
|
||||
{
|
||||
Query: &instance_v2beta.Query_DomainQuery{
|
||||
DomainQuery: &instance_v2beta.DomainsQuery{
|
||||
Domains: []string{"domain1.com", "domain2.com"},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Query: &instance_v2beta.Query_IdQuery{
|
||||
IdQuery: &instance_v2beta.IdsQuery{
|
||||
Ids: []string{"id1", "id2"},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
want: &instance_v2.ListInstancesRequest{
|
||||
Pagination: &filter_v2.PaginationRequest{
|
||||
Offset: 10,
|
||||
Limit: 20,
|
||||
Asc: true,
|
||||
},
|
||||
SortingColumn: instance_v2.FieldName_FIELD_NAME_NAME,
|
||||
Filters: []*instance_v2.Filter{
|
||||
{
|
||||
Filter: &instance_v2.Filter_CustomDomainsFilter{
|
||||
CustomDomainsFilter: &instance_v2.CustomDomainsFilter{
|
||||
Domains: []string{"domain1.com", "domain2.com"},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Filter: &instance_v2.Filter_InIdsFilter{
|
||||
InIdsFilter: &filter_v2.InIDsFilter{
|
||||
Ids: []string{"id1", "id2"},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "request with different sorting field",
|
||||
request: &instance_v2beta.ListInstancesRequest{
|
||||
Pagination: &filter_v2beta.PaginationRequest{},
|
||||
SortingColumn: gu.Ptr(instance_v2beta.FieldName_FIELD_NAME_CREATION_DATE),
|
||||
},
|
||||
want: &instance_v2.ListInstancesRequest{
|
||||
Pagination: &filter_v2.PaginationRequest{},
|
||||
SortingColumn: instance_v2.FieldName_FIELD_NAME_CREATION_DATE,
|
||||
Filters: []*instance_v2.Filter{},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range tt {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
got := ListInstancesBetaRequestToV2Request(tc.request)
|
||||
assert.Equal(t, tc.want, got)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestListInstancesBetaSortingColToV2Request(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
fieldName *instance_v2beta.FieldName
|
||||
want instance_v2.FieldName
|
||||
}{
|
||||
{
|
||||
name: "nil field name",
|
||||
fieldName: nil,
|
||||
want: instance_v2.FieldName_FIELD_NAME_UNSPECIFIED,
|
||||
},
|
||||
{
|
||||
name: "creation date field",
|
||||
fieldName: gu.Ptr(instance_v2beta.FieldName_FIELD_NAME_CREATION_DATE),
|
||||
want: instance_v2.FieldName_FIELD_NAME_CREATION_DATE,
|
||||
},
|
||||
{
|
||||
name: "id field",
|
||||
fieldName: gu.Ptr(instance_v2beta.FieldName_FIELD_NAME_ID),
|
||||
want: instance_v2.FieldName_FIELD_NAME_ID,
|
||||
},
|
||||
{
|
||||
name: "name field",
|
||||
fieldName: gu.Ptr(instance_v2beta.FieldName_FIELD_NAME_NAME),
|
||||
want: instance_v2.FieldName_FIELD_NAME_NAME,
|
||||
},
|
||||
{
|
||||
name: "unspecified field",
|
||||
fieldName: gu.Ptr(instance_v2beta.FieldName_FIELD_NAME_UNSPECIFIED),
|
||||
want: instance_v2.FieldName_FIELD_NAME_UNSPECIFIED,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
got := listInstancesBetaSortingColToV2Request(tt.fieldName)
|
||||
assert.Equal(t, tt.want, got)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user