Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
189 changes: 189 additions & 0 deletions pkg/test/integration_wrapper.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,189 @@
package test

import (
"context"
"net"
"os"
"testing"

connectorV2 "github.com/conductorone/baton-sdk/pb/c1/connector/v2"
"github.com/conductorone/baton-sdk/pkg/connectorbuilder"
"github.com/conductorone/baton-sdk/pkg/dotc1z"
"github.com/conductorone/baton-sdk/pkg/dotc1z/manager"
"github.com/conductorone/baton-sdk/pkg/sync"
"github.com/conductorone/baton-sdk/pkg/types"
"github.com/conductorone/baton-sdk/pkg/ugrpc"
"github.com/stretchr/testify/require"
"go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc"
"go.opentelemetry.io/otel/propagation"
"google.golang.org/grpc"
"google.golang.org/grpc/credentials/insecure"
"google.golang.org/grpc/test/bufconn"
)

const bufSize = 1024 * 1024 // 1MB buffer size for the in-memory connection

type inMemoryConnectorClient struct {
connectorV2.ResourceTypesServiceClient
connectorV2.ResourcesServiceClient
connectorV2.ResourceGetterServiceClient
connectorV2.EntitlementsServiceClient
connectorV2.GrantsServiceClient
connectorV2.ConnectorServiceClient
connectorV2.AssetServiceClient
connectorV2.GrantManagerServiceClient
connectorV2.ResourceManagerServiceClient
connectorV2.ResourceDeleterServiceClient
connectorV2.AccountManagerServiceClient
connectorV2.CredentialManagerServiceClient
connectorV2.EventServiceClient
connectorV2.TicketsServiceClient
connectorV2.ActionServiceClient
}

type IntegrationTestWrapper struct {
Client types.ConnectorClient
// Does not expose the underlying syncer directly, but provides a method to perform synchronization.
// sync.Syncer handle c1z file internally, will override the previous one when call Sync then Close
syncer sync.Syncer
c1zPath string
manager manager.Manager
}

func NewIntegrationTestWrapper(ctx context.Context, t *testing.T, connector interface{}) *IntegrationTestWrapper {
srv, err := connectorbuilder.NewConnector(ctx, connector)
require.NoError(t, err)

tempPath, err := os.CreateTemp("", "baton-integration-test-*.c1z")
require.NoError(t, err)

err = tempPath.Close()
require.NoError(t, err)

t.Cleanup(func() {
err := os.Remove(tempPath.Name())
require.NoError(t, err)
})

lis := bufconn.Listen(bufSize)
s := grpc.NewServer(
grpc.Creds(insecure.NewCredentials()),
grpc.ChainUnaryInterceptor(ugrpc.UnaryServerInterceptor(ctx)...),
grpc.ChainStreamInterceptor(ugrpc.StreamServerInterceptors(ctx)...),
grpc.StatsHandler(
otelgrpc.NewServerHandler(
otelgrpc.WithPropagators(
propagation.NewCompositeTextMapPropagator(
propagation.TraceContext{},
propagation.Baggage{},
),
),
),
),
)

connectorV2.RegisterConnectorServiceServer(s, srv)
connectorV2.RegisterGrantsServiceServer(s, srv)
connectorV2.RegisterEntitlementsServiceServer(s, srv)
connectorV2.RegisterResourcesServiceServer(s, srv)
connectorV2.RegisterResourceTypesServiceServer(s, srv)
connectorV2.RegisterAssetServiceServer(s, srv)
connectorV2.RegisterEventServiceServer(s, srv)
connectorV2.RegisterResourceGetterServiceServer(s, srv)
connectorV2.RegisterGrantManagerServiceServer(s, srv)
connectorV2.RegisterResourceManagerServiceServer(s, srv)
connectorV2.RegisterResourceDeleterServiceServer(s, srv)
connectorV2.RegisterAccountManagerServiceServer(s, srv)
connectorV2.RegisterCredentialManagerServiceServer(s, srv)
Comment on lines +85 to +97
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Add missing server registrations for complete service coverage.

The server setup is missing registrations for TicketsServiceServer and ActionServiceServer, but the client includes TicketsServiceClient and ActionServiceClient. This mismatch will cause runtime errors when these services are called.

Add the missing server registrations:

 	connectorV2.RegisterAccountManagerServiceServer(s, srv)
 	connectorV2.RegisterCredentialManagerServiceServer(s, srv)
+	connectorV2.RegisterTicketsServiceServer(s, srv)
+	connectorV2.RegisterActionServiceServer(s, srv)
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
connectorV2.RegisterConnectorServiceServer(s, srv)
connectorV2.RegisterGrantsServiceServer(s, srv)
connectorV2.RegisterEntitlementsServiceServer(s, srv)
connectorV2.RegisterResourcesServiceServer(s, srv)
connectorV2.RegisterResourceTypesServiceServer(s, srv)
connectorV2.RegisterAssetServiceServer(s, srv)
connectorV2.RegisterEventServiceServer(s, srv)
connectorV2.RegisterResourceGetterServiceServer(s, srv)
connectorV2.RegisterGrantManagerServiceServer(s, srv)
connectorV2.RegisterResourceManagerServiceServer(s, srv)
connectorV2.RegisterResourceDeleterServiceServer(s, srv)
connectorV2.RegisterAccountManagerServiceServer(s, srv)
connectorV2.RegisterCredentialManagerServiceServer(s, srv)
connectorV2.RegisterConnectorServiceServer(s, srv)
connectorV2.RegisterGrantsServiceServer(s, srv)
connectorV2.RegisterEntitlementsServiceServer(s, srv)
connectorV2.RegisterResourcesServiceServer(s, srv)
connectorV2.RegisterResourceTypesServiceServer(s, srv)
connectorV2.RegisterAssetServiceServer(s, srv)
connectorV2.RegisterEventServiceServer(s, srv)
connectorV2.RegisterResourceGetterServiceServer(s, srv)
connectorV2.RegisterGrantManagerServiceServer(s, srv)
connectorV2.RegisterResourceManagerServiceServer(s, srv)
connectorV2.RegisterResourceDeleterServiceServer(s, srv)
connectorV2.RegisterAccountManagerServiceServer(s, srv)
connectorV2.RegisterCredentialManagerServiceServer(s, srv)
+ connectorV2.RegisterTicketsServiceServer(s, srv)
+ connectorV2.RegisterActionServiceServer(s, srv)
🤖 Prompt for AI Agents
In pkg/test/integration_wrapper.go around lines 85 to 97, the server setup is
missing registrations for TicketsServiceServer and ActionServiceServer, causing
a mismatch with the client that includes TicketsServiceClient and
ActionServiceClient. To fix this, add the missing server registration calls for
TicketsServiceServer and ActionServiceServer to the server setup to ensure
complete service coverage and prevent runtime errors.


go func() {
if err := s.Serve(lis); err != nil {
t.Errorf("Server exited with error: %v", err)
}
}()

t.Cleanup(func() {
s.Stop()
})

bufDialer := func(ctx context.Context, s string) (net.Conn, error) {
return lis.DialContext(ctx)
}

cc, err := grpc.NewClient(
"passthrough://bufnet",
grpc.WithContextDialer(bufDialer),
grpc.WithTransportCredentials(insecure.NewCredentials()),
)
require.NoError(t, err)

client := &inMemoryConnectorClient{
ResourceTypesServiceClient: connectorV2.NewResourceTypesServiceClient(cc),
ResourcesServiceClient: connectorV2.NewResourcesServiceClient(cc),
EntitlementsServiceClient: connectorV2.NewEntitlementsServiceClient(cc),
GrantsServiceClient: connectorV2.NewGrantsServiceClient(cc),
ConnectorServiceClient: connectorV2.NewConnectorServiceClient(cc),
AssetServiceClient: connectorV2.NewAssetServiceClient(cc),
GrantManagerServiceClient: connectorV2.NewGrantManagerServiceClient(cc),
ResourceManagerServiceClient: connectorV2.NewResourceManagerServiceClient(cc),
ResourceDeleterServiceClient: connectorV2.NewResourceDeleterServiceClient(cc),
AccountManagerServiceClient: connectorV2.NewAccountManagerServiceClient(cc),
CredentialManagerServiceClient: connectorV2.NewCredentialManagerServiceClient(cc),
EventServiceClient: connectorV2.NewEventServiceClient(cc),
TicketsServiceClient: connectorV2.NewTicketsServiceClient(cc),
ActionServiceClient: connectorV2.NewActionServiceClient(cc),
ResourceGetterServiceClient: connectorV2.NewResourceGetterServiceClient(cc),
}

syncer, err := sync.NewSyncer(
ctx,
client,
sync.WithC1ZPath(tempPath.Name()),
sync.WithProgressHandler(func(s *sync.Progress) {
t.Logf("Progress: %v", s)
}),
)
require.NoError(t, err)

m, err := manager.New(ctx, tempPath.Name())
require.NoError(t, err)

t.Cleanup(func() {
err := m.Close(ctx)
require.NoError(t, err)
})

return &IntegrationTestWrapper{
Client: client,
syncer: syncer,
manager: m,
c1zPath: tempPath.Name(),
}
}

func (w *IntegrationTestWrapper) Manager() manager.Manager {
return w.manager
}

func (w *IntegrationTestWrapper) LoadC1Z(ctx context.Context, t *testing.T) *dotc1z.C1File {
c1z, err := w.manager.LoadC1Z(ctx)
require.NoError(t, err)
require.NotNil(t, c1z)

return c1z
}

// Sync performs a synchronization operation using the provided syncer.
func (w *IntegrationTestWrapper) Sync(ctx context.Context) error {
err := w.syncer.Sync(ctx)
if err != nil {
return err
}

err = w.syncer.Close(ctx)
if err != nil {
return err
}

return nil
}
91 changes: 91 additions & 0 deletions pkg/test/integration_wrapper_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
package test

import (
"context"
"testing"

v2 "github.com/conductorone/baton-sdk/pb/c1/connector/v2"
"github.com/conductorone/baton-sdk/pkg/annotations"
"github.com/conductorone/baton-sdk/pkg/connectorbuilder"
"github.com/conductorone/baton-sdk/pkg/pagination"
"github.com/stretchr/testify/require"
)

var mockResourceType = &v2.ResourceType{
Id: "mock_resource_type",
Description: "mock resource type",
DisplayName: "mock resource type",
Traits: []v2.ResourceType_Trait{
v2.ResourceType_TRAIT_UNSPECIFIED,
},
}

type mockConnector struct{}

func (m mockConnector) Metadata(ctx context.Context) (*v2.ConnectorMetadata, error) {
return &v2.ConnectorMetadata{}, nil
}

func (m mockConnector) Validate(ctx context.Context) (annotations.Annotations, error) {
return annotations.Annotations{}, nil
}

func (m mockConnector) ResourceSyncers(ctx context.Context) []connectorbuilder.ResourceSyncer {
return []connectorbuilder.ResourceSyncer{
&mockResource{
resourceType: mockResourceType,
resources: []*v2.Resource{
{
Id: &v2.ResourceId{
Resource: "1",
ResourceType: mockResourceType.Id,
},
DisplayName: "Mock Resource 1",
},
},
},
}
}

type mockResource struct {
resourceType *v2.ResourceType
resources []*v2.Resource
}

func (m *mockResource) ResourceType(ctx context.Context) *v2.ResourceType {
return m.resourceType
}

func (m *mockResource) List(ctx context.Context, parentResourceID *v2.ResourceId, pToken *pagination.Token) ([]*v2.Resource, string, annotations.Annotations, error) {
return m.resources, "", nil, nil
}

func (m *mockResource) Entitlements(ctx context.Context, resource *v2.Resource, pToken *pagination.Token) ([]*v2.Entitlement, string, annotations.Annotations, error) {
return []*v2.Entitlement{}, "", nil, nil
}

func (m *mockResource) Grants(ctx context.Context, resource *v2.Resource, pToken *pagination.Token) ([]*v2.Grant, string, annotations.Annotations, error) {
return []*v2.Grant{}, "", nil, nil
}

func TestIntegrationTestWrapper_Sync(t *testing.T) {
ctx := context.Background()

wrapper := NewIntegrationTestWrapper(ctx, t, &mockConnector{})
require.NotNil(t, wrapper)

err := wrapper.Sync(ctx)
require.NoError(t, err)

z := wrapper.LoadC1Z(ctx, t)

t.Cleanup(func() {
err := z.Close()
require.NoError(t, err)
})

resources, err := z.ListResources(ctx, &v2.ResourcesServiceListResourcesRequest{})
require.NoError(t, err)

require.Len(t, resources.List, 1)
}
Loading
Loading