diff --git a/adapters/mock.go b/adapters/mock.go index 1b69fe2..4256036 100644 --- a/adapters/mock.go +++ b/adapters/mock.go @@ -14,13 +14,13 @@ import ( type MockAdapter struct { callbacks domain.Callbacks patchStrategy bool - resources map[string][]byte + Resources map[string][]byte shadowObjects map[string][]byte } func NewMockAdapter() *MockAdapter { return &MockAdapter{ - resources: map[string][]byte{}, + Resources: map[string][]byte{}, shadowObjects: map[string][]byte{}, } } @@ -28,12 +28,12 @@ func NewMockAdapter() *MockAdapter { var _ Adapter = (*MockAdapter)(nil) func (m *MockAdapter) DeleteObject(_ context.Context, id domain.KindName) error { - delete(m.resources, id.String()) + delete(m.Resources, id.String()) return nil } func (m *MockAdapter) GetObject(ctx context.Context, id domain.KindName, baseObject []byte) error { - object, ok := m.resources[id.String()] + object, ok := m.Resources[id.String()] if !ok { return fmt.Errorf("object not found") } @@ -72,7 +72,7 @@ func (m *MockAdapter) PatchObject(ctx context.Context, id domain.KindName, check } func (m *MockAdapter) patchObject(id domain.KindName, checksum string, patch []byte) ([]byte, error) { - object, ok := m.resources[id.String()] + object, ok := m.Resources[id.String()] if !ok { return nil, fmt.Errorf("object not found") } @@ -87,13 +87,13 @@ func (m *MockAdapter) patchObject(id domain.KindName, checksum string, patch []b if newChecksum != checksum { return object, fmt.Errorf("checksum mismatch: %s != %s", newChecksum, checksum) } - m.resources[id.String()] = modified + m.Resources[id.String()] = modified m.shadowObjects[id.String()] = modified return object, nil } func (m *MockAdapter) PutObject(_ context.Context, id domain.KindName, object []byte) error { - m.resources[id.String()] = object + m.Resources[id.String()] = object return nil } @@ -119,7 +119,7 @@ func (m *MockAdapter) VerifyObject(ctx context.Context, id domain.KindName, newC } func (m *MockAdapter) verifyObject(id domain.KindName, newChecksum string) ([]byte, error) { - object, ok := m.resources[id.String()] + object, ok := m.Resources[id.String()] if !ok { return nil, fmt.Errorf("object not found") } @@ -132,3 +132,33 @@ func (m *MockAdapter) verifyObject(id domain.KindName, newChecksum string) ([]by } return object, nil } + +func (m *MockAdapter) TestCallDeleteObject(ctx context.Context, id domain.KindName) error { + ctx = utils.ContextFromGeneric(ctx, domain.Generic{}) + err := m.callbacks.DeleteObject(ctx, id) + if err != nil { + return fmt.Errorf("send delete: %w", err) + } + if m.patchStrategy { + // remove from known resources + delete(m.shadowObjects, id.String()) + } + return nil +} + +// TestCallVerifyObject is used for testing purposes only, it is similar to incluster.client.callVerifyObject +func (m *MockAdapter) TestCallVerifyObject(ctx context.Context, id domain.KindName, object []byte) error { + // store object + m.Resources[id.String()] = object + // calculate checksum + checksum, err := utils.CanonicalHash(object) + if err != nil { + return fmt.Errorf("calculate checksum: %w", err) + } + ctx = utils.ContextFromGeneric(ctx, domain.Generic{}) + err = m.callbacks.VerifyObject(ctx, id, checksum) + if err != nil { + return fmt.Errorf("send checksum: %w", err) + } + return nil +} diff --git a/core/synchronizer_test.go b/core/synchronizer_test.go index d5ec0e5..9da3881 100644 --- a/core/synchronizer_test.go +++ b/core/synchronizer_test.go @@ -2,19 +2,87 @@ package core import ( "context" + "net" "testing" + "time" + "github.com/kubescape/go-logger" + "github.com/kubescape/go-logger/helpers" "github.com/kubescape/synchronizer/adapters" "github.com/kubescape/synchronizer/domain" "github.com/stretchr/testify/assert" ) -func TestSynchronizer_HandleSyncGetObject(t *testing.T) { - synchronizer := &Synchronizer{ - adapter: adapters.NewMockAdapter(), - outPool: nil, +func TestSynchronizer_ObjectAdded(t *testing.T) { + ctx := context.WithValue(context.TODO(), domain.ContextKeyClientIdentifier, domain.ClientIdentifier{ + Account: "11111111-2222-3333-4444-555555555555", + Cluster: "cluster", + }) + err := logger.L().SetLevel(helpers.DebugLevel.String()) + assert.NoError(t, err) + clientAdapter := adapters.NewMockAdapter() + serverAdapter := adapters.NewMockAdapter() + clientConn, serverConn := net.Pipe() + client := NewSynchronizerClient(ctx, clientAdapter, clientConn) + server := NewSynchronizerServer(ctx, serverAdapter, serverConn) + go func() { + _ = client.Start(ctx) + }() + go func() { + _ = server.Start(ctx) + }() + // add object + id := domain.KindName{ + Kind: domain.KindFromString("apps/v1/Deployment"), + Name: "name", + Namespace: "namespace", } + object := []byte(`{"kind":"kind","metadata":{"name":"name"}}`) + err = clientAdapter.TestCallVerifyObject(ctx, id, object) + assert.NoError(t, err) + time.Sleep(1 * time.Second) + // check object arrived + serverObj, ok := serverAdapter.Resources[id.String()] + assert.True(t, ok) + assert.Equal(t, object, serverObj) +} + +func TestSynchronizer_ObjectDeleted(t *testing.T) { + ctx := context.WithValue(context.TODO(), domain.ContextKeyClientIdentifier, domain.ClientIdentifier{ + Account: "11111111-2222-3333-4444-555555555555", + Cluster: "cluster", + }) + err := logger.L().SetLevel(helpers.DebugLevel.String()) + assert.NoError(t, err) + clientAdapter := adapters.NewMockAdapter() + serverAdapter := adapters.NewMockAdapter() + clientConn, serverConn := net.Pipe() + client := NewSynchronizerClient(ctx, clientAdapter, clientConn) + server := NewSynchronizerServer(ctx, serverAdapter, serverConn) + go func() { + _ = client.Start(ctx) + }() + go func() { + _ = server.Start(ctx) + }() + // pre: add object + id := domain.KindName{ + Kind: domain.KindFromString("apps/v1/Deployment"), + Name: "name", + Namespace: "namespace", + } + object := []byte(`{"kind":"kind","metadata":{"name":"name"}}`) + clientAdapter.Resources[id.String()] = object + serverAdapter.Resources[id.String()] = object + // delete object + err = clientAdapter.TestCallDeleteObject(ctx, id) + assert.NoError(t, err) + time.Sleep(1 * time.Second) + // check object deleted + _, ok := serverAdapter.Resources[id.String()] + assert.False(t, ok) +} - err := synchronizer.handleSyncGetObject(context.TODO(), domain.KindName{}, []byte("baseObject")) - assert.ErrorContains(t, err, "object not found") +func TestSynchronizer_ObjectModifiedWithPatch(t *testing.T) { + }