Skip to content
This repository has been archived by the owner on Jul 4, 2024. It is now read-only.

Add created and updated timestamps to certificate subject mappings #3859

Merged
merged 9 commits into from
May 10, 2024
Merged
4 changes: 2 additions & 2 deletions chart/compass/values.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -175,7 +175,7 @@ global:
name: compass-pairing-adapter
director:
dir: dev/incubator/
version: "PR-3849"
version: "PR-3859"
name: compass-director
hydrator:
dir: dev/incubator/
Expand Down Expand Up @@ -211,7 +211,7 @@ global:
name: compass-ord-service
schema_migrator:
dir: dev/incubator/
version: "PR-3857"
version: "PR-3859"
name: compass-schema-migrator
system_broker:
dir: dev/incubator/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,8 @@ func (c *converter) ToGraphQL(in *model.CertSubjectMapping) *graphql.Certificate
ConsumerType: in.ConsumerType,
InternalConsumerID: in.InternalConsumerID,
TenantAccessLevels: in.TenantAccessLevels,
CreatedAt: graphql.Timestamp(in.CreatedAt),
UpdatedAt: graphql.TimePtrToGraphqlTimestampPtr(in.UpdatedAt),
}
}

Expand Down Expand Up @@ -96,5 +98,7 @@ func (c *converter) FromEntity(e *Entity) (*model.CertSubjectMapping, error) {
ConsumerType: e.ConsumerType,
InternalConsumerID: e.InternalConsumerID,
TenantAccessLevels: unmarshalledTntAccessLevels,
CreatedAt: e.CreatedAt,
UpdatedAt: e.UpdatedAt,
}, nil
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package certsubjectmapping_test

import (
"testing"
"time"

"github.com/kyma-incubator/compass/components/director/internal/domain/certsubjectmapping"
"github.com/kyma-incubator/compass/components/director/internal/model"
Expand Down Expand Up @@ -42,6 +43,8 @@ func TestConverter_ToGraphQL(t *testing.T) {
}

func TestConverter_FromGraphql(t *testing.T) {
csmModel := fixCertSubjectMappingModel(TestID, TestSubject, TestConsumerType, TestInternalConsumerID, TestTenantAccessLevels, time.Time{})

testCases := []struct {
Name string
Input graphql.CertificateSubjectMappingInput
Expand All @@ -51,7 +54,7 @@ func TestConverter_FromGraphql(t *testing.T) {
{
Name: "Success",
Input: CertSubjectMappingGQLModelInput,
Expected: CertSubjectMappingModel,
Expected: csmModel,
},
}

Expand Down Expand Up @@ -102,6 +105,9 @@ func TestConverter_MultipleToGraphQL(t *testing.T) {
}

func TestConverter_ToEntity(t *testing.T) {
csmModel := fixCertSubjectMappingModel(TestID, TestSubject, TestConsumerType, TestInternalConsumerID, TestTenantAccessLevels, testTime)
csmEntity := fixCertSubjectMappingEntity(TestID, TestSubject, TestConsumerType, TestInternalConsumerID, TestTenantAccessLevelsAsString, time.Time{})

testCases := []struct {
Name string
Input *model.CertSubjectMapping
Expand All @@ -110,8 +116,8 @@ func TestConverter_ToEntity(t *testing.T) {
}{
{
Name: "Success",
Input: CertSubjectMappingModel,
Expected: CertSubjectMappingEntity,
Input: csmModel,
Expected: csmEntity,
},
{
Name: "Success when input is nil",
Expand Down Expand Up @@ -139,6 +145,9 @@ func TestConverter_ToEntity(t *testing.T) {
}

func TestConverter_FromEntity(t *testing.T) {
csmModel := fixCertSubjectMappingModel(TestID, TestSubject, TestConsumerType, TestInternalConsumerID, TestTenantAccessLevels, testTime)
csmEntity := fixCertSubjectMappingEntity(TestID, TestSubject, TestConsumerType, TestInternalConsumerID, TestTenantAccessLevelsAsString, testTime)

testCases := []struct {
Name string
Input *certsubjectmapping.Entity
Expand All @@ -147,8 +156,8 @@ func TestConverter_FromEntity(t *testing.T) {
}{
{
Name: "Success",
Input: CertSubjectMappingEntity,
Expected: CertSubjectMappingModel,
Input: csmEntity,
Expected: csmModel,
},
{
Name: "Success when input is nil",
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,16 @@
package certsubjectmapping

import "time"

// Entity is a representation of a certificate subject mapping in the DB
type Entity struct {
ID string `db:"id"`
Subject string `db:"subject"`
ConsumerType string `db:"consumer_type"`
InternalConsumerID *string `db:"internal_consumer_id"`
TenantAccessLevels string `db:"tenant_access_levels"`
ID string `db:"id"`
Subject string `db:"subject"`
ConsumerType string `db:"consumer_type"`
InternalConsumerID *string `db:"internal_consumer_id"`
TenantAccessLevels string `db:"tenant_access_levels"`
CreatedAt time.Time `db:"created_at"`
UpdatedAt *time.Time `db:"updated_at"`
}

// EntityCollection is a collection of certificate subject mapping entities.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package certsubjectmapping_test

import (
"time"

"github.com/kyma-incubator/compass/components/director/internal/domain/certsubjectmapping"
"github.com/kyma-incubator/compass/components/director/internal/domain/certsubjectmapping/automock"
"github.com/kyma-incubator/compass/components/director/internal/model"
Expand All @@ -24,21 +26,19 @@ var (
TestInvalidTenantAccessLevelsAsString = "[invalid"
TestTenantAccessLevels = []string{string(tenantEntity.Account), string(tenantEntity.Subaccount)}
nilModelEntity *model.CertSubjectMapping
testTime = time.Date(2024, 04, 24, 9, 9, 9, 9, time.Local)

CertSubjectMappingModel = &model.CertSubjectMapping{
ID: TestID,
Subject: TestSubject,
ConsumerType: TestConsumerType,
InternalConsumerID: &TestInternalConsumerID,
TenantAccessLevels: TestTenantAccessLevels,
}
CertSubjectMappingEntity = fixCertSubjectMappingEntity(TestID, TestSubject, TestConsumerType, TestInternalConsumerID, TestTenantAccessLevelsAsString, testTime)
CertSubjectMappingEntityInvalidTntAccessLevels = fixCertSubjectMappingEntity(TestID, TestSubject, TestConsumerType, TestInternalConsumerID, TestInvalidTenantAccessLevelsAsString, testTime)
CertSubjectMappingModel = fixCertSubjectMappingModel(TestID, TestSubject, TestConsumerType, TestInternalConsumerID, TestTenantAccessLevels, testTime)

CertSubjectMappingGQLModel = &graphql.CertificateSubjectMapping{
ID: TestID,
Subject: TestSubject,
ConsumerType: TestConsumerType,
InternalConsumerID: &TestInternalConsumerID,
TenantAccessLevels: TestTenantAccessLevels,
CreatedAt: graphql.Timestamp(testTime),
}

CertSubjectMappingGQLModelInput = graphql.CertificateSubjectMappingInput{
Expand All @@ -61,22 +61,6 @@ var (
TenantAccessLevels: TestTenantAccessLevels,
}

CertSubjectMappingEntity = &certsubjectmapping.Entity{
ID: TestID,
Subject: TestSubject,
ConsumerType: TestConsumerType,
InternalConsumerID: &TestInternalConsumerID,
TenantAccessLevels: TestTenantAccessLevelsAsString,
}

CertSubjectMappingEntityInvalidTntAccessLevels = &certsubjectmapping.Entity{
ID: TestID,
Subject: TestSubject,
ConsumerType: TestConsumerType,
InternalConsumerID: &TestInternalConsumerID,
TenantAccessLevels: TestInvalidTenantAccessLevelsAsString,
}

CertificateSubjectMappingModelPage = &model.CertSubjectMappingPage{
Data: []*model.CertSubjectMapping{CertSubjectMappingModel},
PageInfo: &pagination.Page{
Expand All @@ -100,8 +84,30 @@ var (
}
)

func fixCertSubjectMappingEntity(ID, subject, consumerType, internalConsumerID, tenantAccessLevels string, createdAt time.Time) *certsubjectmapping.Entity {
return &certsubjectmapping.Entity{
ID: ID,
Subject: subject,
ConsumerType: consumerType,
InternalConsumerID: &internalConsumerID,
TenantAccessLevels: tenantAccessLevels,
CreatedAt: createdAt,
}
}

func fixCertSubjectMappingModel(ID, subject, consumerType, internalConsumerID string, tenantAccessLevels []string, createdAt time.Time) *model.CertSubjectMapping {
return &model.CertSubjectMapping{
ID: ID,
Subject: subject,
ConsumerType: consumerType,
InternalConsumerID: &internalConsumerID,
TenantAccessLevels: tenantAccessLevels,
CreatedAt: createdAt,
}
}

func fixColumns() []string {
return []string{"id", "subject", "consumer_type", "internal_consumer_id", "tenant_access_levels"}
return []string{"id", "subject", "consumer_type", "internal_consumer_id", "tenant_access_levels", "created_at", "updated_at"}
}

func fixUnusedCertSubjectMappingRepository() *automock.CertMappingRepository {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package certsubjectmapping

import (
"context"
"time"

"github.com/kyma-incubator/compass/components/director/internal/model"
"github.com/kyma-incubator/compass/components/director/internal/repo"
Expand All @@ -17,11 +18,13 @@ const (
)

var (
idTableColumns = []string{"id"}
updatableTableColumns = []string{"subject", "consumer_type", "internal_consumer_id", "tenant_access_levels"}
tableColumns = append(idTableColumns, updatableTableColumns...)

idTableColumns = []string{"id"}
updatableTableColumns = []string{"subject", "consumer_type", "internal_consumer_id", "tenant_access_levels", "updated_at"}
tableColumns = []string{"id", "subject", "consumer_type", "internal_consumer_id", "tenant_access_levels", "created_at", "updated_at"}
internalConsumerIDColumn = "internal_consumer_id"

// Now is a function variable that returns the current time. It is used, so we could mock it in the tests.
Now = time.Now
)

// entityConverter converts between the internal model and entity
Expand Down Expand Up @@ -68,6 +71,7 @@ func (r *repository) Create(ctx context.Context, model *model.CertSubjectMapping
if err != nil {
return errors.Wrapf(err, "while converting certificate subject mapping with ID: %s", model.ID)
}
entity.CreatedAt = Now()

log.C(ctx).Debugf("Persisting certificate mapping with ID: %s and subject: %s to DB", model.ID, model.Subject)
return r.creator.Create(ctx, entity)
Expand Down Expand Up @@ -100,6 +104,8 @@ func (r *repository) Update(ctx context.Context, model *model.CertSubjectMapping
if err != nil {
return errors.Wrapf(err, "while converting certificate subject mapping with ID: %s", model.ID)
}
currentTime := Now()
entity.UpdatedAt = &currentTime

log.C(ctx).Debugf("Updating certificate mapping with ID: %s and subject: %s", model.ID, model.Subject)
return r.updaterGlobal.UpdateSingleGlobal(ctx, entity)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"database/sql/driver"
"regexp"
"testing"
"time"

"github.com/DATA-DOG/go-sqlmock"
"github.com/kyma-incubator/compass/components/director/internal/domain/certsubjectmapping"
Expand All @@ -14,13 +15,15 @@ import (
)

func TestRepository_Create(t *testing.T) {
certsubjectmapping.Now = func() time.Time { return testTime }

suite := testdb.RepoCreateTestSuite{
Name: "Create certificate subject mapping",
MethodName: "Create",
SQLQueryDetails: []testdb.SQLQueryDetails{
{
Query: `^INSERT INTO public.cert_subject_mapping \(.+\) VALUES \(.+\)$`,
Args: []driver.Value{CertSubjectMappingEntity.ID, CertSubjectMappingEntity.Subject, CertSubjectMappingEntity.ConsumerType, CertSubjectMappingEntity.InternalConsumerID, CertSubjectMappingEntity.TenantAccessLevels},
Args: []driver.Value{CertSubjectMappingEntity.ID, CertSubjectMappingEntity.Subject, CertSubjectMappingEntity.ConsumerType, CertSubjectMappingEntity.InternalConsumerID, CertSubjectMappingEntity.TenantAccessLevels, testTime, nil},
ValidResult: sqlmock.NewResult(-1, 1),
},
},
Expand All @@ -44,11 +47,11 @@ func TestRepository_Get(t *testing.T) {
MethodName: "Get",
SQLQueryDetails: []testdb.SQLQueryDetails{
{
Query: regexp.QuoteMeta(`SELECT id, subject, consumer_type, internal_consumer_id, tenant_access_levels FROM public.cert_subject_mapping WHERE id = $1`),
Query: regexp.QuoteMeta(`SELECT id, subject, consumer_type, internal_consumer_id, tenant_access_levels, created_at, updated_at FROM public.cert_subject_mapping WHERE id = $1`),
Args: []driver.Value{TestID},
IsSelect: true,
ValidRowsProvider: func() []*sqlmock.Rows {
return []*sqlmock.Rows{sqlmock.NewRows(fixColumns()).AddRow(CertSubjectMappingEntity.ID, CertSubjectMappingEntity.Subject, CertSubjectMappingEntity.ConsumerType, CertSubjectMappingEntity.InternalConsumerID, CertSubjectMappingEntity.TenantAccessLevels)}
return []*sqlmock.Rows{sqlmock.NewRows(fixColumns()).AddRow(CertSubjectMappingEntity.ID, CertSubjectMappingEntity.Subject, CertSubjectMappingEntity.ConsumerType, CertSubjectMappingEntity.InternalConsumerID, CertSubjectMappingEntity.TenantAccessLevels, testTime, nil)}
},
InvalidRowsProvider: func() []*sqlmock.Rows {
return []*sqlmock.Rows{sqlmock.NewRows(fixColumns())}
Expand All @@ -69,13 +72,17 @@ func TestRepository_Get(t *testing.T) {
}

func TestRepository_Update(t *testing.T) {
updateStmt := regexp.QuoteMeta(`UPDATE public.cert_subject_mapping SET subject = ?, consumer_type = ?, internal_consumer_id = ?, tenant_access_levels = ? WHERE id = ?`)
certsubjectmapping.Now = func() time.Time { return testTime }
csmModel := fixCertSubjectMappingModel(TestID, TestSubject, TestConsumerType, TestInternalConsumerID, TestTenantAccessLevels, testTime)
csmEntity := fixCertSubjectMappingEntity(TestID, TestSubject, TestConsumerType, TestInternalConsumerID, TestTenantAccessLevelsAsString, testTime)

updateStmt := regexp.QuoteMeta(`UPDATE public.cert_subject_mapping SET subject = ?, consumer_type = ?, internal_consumer_id = ?, tenant_access_levels = ?, updated_at = ? WHERE id = ?`)
suite := testdb.RepoUpdateTestSuite{
Name: "Update certificate subject mapping by ID",
SQLQueryDetails: []testdb.SQLQueryDetails{
{
Query: updateStmt,
Args: []driver.Value{CertSubjectMappingEntity.Subject, CertSubjectMappingEntity.ConsumerType, CertSubjectMappingEntity.InternalConsumerID, CertSubjectMappingEntity.TenantAccessLevels, CertSubjectMappingEntity.ID},
Args: []driver.Value{csmEntity.Subject, csmEntity.ConsumerType, csmEntity.InternalConsumerID, csmEntity.TenantAccessLevels, testTime, csmEntity.ID},
ValidResult: sqlmock.NewResult(-1, 1),
InvalidResult: sqlmock.NewResult(-1, 0),
},
Expand All @@ -84,8 +91,8 @@ func TestRepository_Update(t *testing.T) {
ConverterMockProvider: func() testdb.Mock {
return &automock.EntityConverter{}
},
ModelEntity: CertSubjectMappingModel,
DBEntity: CertSubjectMappingEntity,
ModelEntity: csmModel,
DBEntity: csmEntity,
NilModelEntity: nilModelEntity,
IsGlobal: true,
}
Expand Down Expand Up @@ -150,10 +157,10 @@ func TestRepository_List(t *testing.T) {
MethodName: "List",
SQLQueryDetails: []testdb.SQLQueryDetails{
{
Query: regexp.QuoteMeta(`SELECT id, subject, consumer_type, internal_consumer_id, tenant_access_levels FROM public.cert_subject_mapping ORDER BY id LIMIT 3 OFFSET 0`),
Query: regexp.QuoteMeta(`SELECT id, subject, consumer_type, internal_consumer_id, tenant_access_levels, created_at, updated_at FROM public.cert_subject_mapping ORDER BY id LIMIT 3 OFFSET 0`),
IsSelect: true,
ValidRowsProvider: func() []*sqlmock.Rows {
return []*sqlmock.Rows{sqlmock.NewRows(fixColumns()).AddRow(CertSubjectMappingEntity.ID, CertSubjectMappingEntity.Subject, CertSubjectMappingEntity.ConsumerType, CertSubjectMappingEntity.InternalConsumerID, CertSubjectMappingEntity.TenantAccessLevels)}
return []*sqlmock.Rows{sqlmock.NewRows(fixColumns()).AddRow(CertSubjectMappingEntity.ID, CertSubjectMappingEntity.Subject, CertSubjectMappingEntity.ConsumerType, CertSubjectMappingEntity.InternalConsumerID, CertSubjectMappingEntity.TenantAccessLevels, testTime, nil)}
},
InvalidRowsProvider: func() []*sqlmock.Rows {
return []*sqlmock.Rows{sqlmock.NewRows(fixColumns())}
Expand Down Expand Up @@ -199,10 +206,10 @@ func TestRepository_ListAll(t *testing.T) {
MethodName: "ListAll",
SQLQueryDetails: []testdb.SQLQueryDetails{
{
Query: regexp.QuoteMeta(`SELECT id, subject, consumer_type, internal_consumer_id, tenant_access_levels FROM public.cert_subject_mapping`),
Query: regexp.QuoteMeta(`SELECT id, subject, consumer_type, internal_consumer_id, tenant_access_levels, created_at, updated_at FROM public.cert_subject_mapping`),
IsSelect: true,
ValidRowsProvider: func() []*sqlmock.Rows {
return []*sqlmock.Rows{sqlmock.NewRows(fixColumns()).AddRow(CertSubjectMappingEntity.ID, CertSubjectMappingEntity.Subject, CertSubjectMappingEntity.ConsumerType, CertSubjectMappingEntity.InternalConsumerID, CertSubjectMappingEntity.TenantAccessLevels)}
return []*sqlmock.Rows{sqlmock.NewRows(fixColumns()).AddRow(CertSubjectMappingEntity.ID, CertSubjectMappingEntity.Subject, CertSubjectMappingEntity.ConsumerType, CertSubjectMappingEntity.InternalConsumerID, CertSubjectMappingEntity.TenantAccessLevels, testTime, nil)}
},
InvalidRowsProvider: func() []*sqlmock.Rows {
return []*sqlmock.Rows{sqlmock.NewRows(fixColumns())}
Expand All @@ -229,11 +236,11 @@ func TestRepository_ListByConsumerID(t *testing.T) {
MethodName: "ListByConsumerID",
SQLQueryDetails: []testdb.SQLQueryDetails{
{
Query: regexp.QuoteMeta(`SELECT id, subject, consumer_type, internal_consumer_id, tenant_access_levels FROM public.cert_subject_mapping WHERE internal_consumer_id = $1`),
Query: regexp.QuoteMeta(`SELECT id, subject, consumer_type, internal_consumer_id, tenant_access_levels, created_at, updated_at FROM public.cert_subject_mapping WHERE internal_consumer_id = $1`),
Args: []driver.Value{consumerID},
IsSelect: true,
ValidRowsProvider: func() []*sqlmock.Rows {
return []*sqlmock.Rows{sqlmock.NewRows(fixColumns()).AddRow(CertSubjectMappingEntity.ID, CertSubjectMappingEntity.Subject, CertSubjectMappingEntity.ConsumerType, CertSubjectMappingEntity.InternalConsumerID, CertSubjectMappingEntity.TenantAccessLevels)}
return []*sqlmock.Rows{sqlmock.NewRows(fixColumns()).AddRow(CertSubjectMappingEntity.ID, CertSubjectMappingEntity.Subject, CertSubjectMappingEntity.ConsumerType, CertSubjectMappingEntity.InternalConsumerID, CertSubjectMappingEntity.TenantAccessLevels, testTime, nil)}
},
InvalidRowsProvider: func() []*sqlmock.Rows {
return []*sqlmock.Rows{sqlmock.NewRows(fixColumns())}
Expand Down
18 changes: 12 additions & 6 deletions components/director/internal/model/cert_subject_mapping.go
Original file line number Diff line number Diff line change
@@ -1,15 +1,21 @@
package model

import "github.com/kyma-incubator/compass/components/director/pkg/pagination"
import (
"time"

"github.com/kyma-incubator/compass/components/director/pkg/pagination"
)

// CertSubjectMapping is a structure that represents a certificate subject
// mapped to internal consumer with given tenant access levels
type CertSubjectMapping struct {
ID string `json:"id"`
Subject string `json:"subject"`
ConsumerType string `json:"consumer_type"`
InternalConsumerID *string `json:"internal_consumer_id"`
TenantAccessLevels []string `json:"tenant_access_levels"`
ID string `json:"id"`
Subject string `json:"subject"`
ConsumerType string `json:"consumer_type"`
InternalConsumerID *string `json:"internal_consumer_id"`
TenantAccessLevels []string `json:"tenant_access_levels"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt *time.Time `json:"updated_at"`
}

// CertSubjectMappingInput is an input for creating a new CertSubjectMapping
Expand Down
Loading