package adapter_test import ( "context" "errors" "testing" "time" "github.com/ThreeDotsLabs/watermill/message" "github.com/apache/pulsar-client-go/pulsar" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "go.yandata.net/iod/iod/trustlog-sdk/api/adapter" "go.yandata.net/iod/iod/trustlog-sdk/api/adapter/mocks" "go.yandata.net/iod/iod/trustlog-sdk/api/logger" ) // MockPulsarClientWithSubscribeError is a mock client that can return subscription errors. type MockPulsarClientWithSubscribeError struct { *mocks.MockPulsarClient subscribeError error } func NewMockPulsarClientWithSubscribeError() *MockPulsarClientWithSubscribeError { return &MockPulsarClientWithSubscribeError{ MockPulsarClient: mocks.NewMockPulsarClient(), } } func (m *MockPulsarClientWithSubscribeError) SetSubscribeError(err error) { m.subscribeError = err } func (m *MockPulsarClientWithSubscribeError) Subscribe(options pulsar.ConsumerOptions) (pulsar.Consumer, error) { if m.subscribeError != nil { return nil, m.subscribeError } return m.MockPulsarClient.Subscribe(options) } func TestSubscriber_Subscribe_SubscriptionError(t *testing.T) { t.Parallel() mockClient := NewMockPulsarClientWithSubscribeError() mockClient.SetSubscribeError(errors.New("subscription failed")) log := logger.NewNopLogger() config := adapter.SubscriberConfig{ SubscriberName: "test-sub", SubscriberType: pulsar.Shared, } sub, err := adapter.NewSubscriberWithPulsarClient(mockClient, config, log) require.NoError(t, err) defer sub.Close() ctx := context.Background() _, err = sub.Subscribe(ctx, "test-topic") require.Error(t, err) assert.Contains(t, err.Error(), "subscription failed") } func TestSubscriber_Subscribe_Timeout(t *testing.T) { t.Parallel() mockClient := mocks.NewMockPulsarClient() log := logger.NewNopLogger() config := adapter.SubscriberConfig{ SubscriberName: "test-sub", SubscriberType: pulsar.Shared, } sub, err := adapter.NewSubscriberWithPulsarClient(mockClient, config, log) require.NoError(t, err) defer sub.Close() // Use a very short timeout context that's already expired ctx, cancel := context.WithTimeout(context.Background(), time.Nanosecond) cancel() // Cancel immediately time.Sleep(time.Millisecond) _, err = sub.Subscribe(ctx, "test-topic") // Should timeout or fail due to cancelled context if err != nil { assert.Contains(t, err.Error(), "timeout") } } func TestSubscriber_Subscribe_WithCustomSubName(t *testing.T) { t.Parallel() mockClient := mocks.NewMockPulsarClient() log := logger.NewNopLogger() config := adapter.SubscriberConfig{ SubscriberName: "test-sub", SubscriberType: pulsar.Shared, } sub, err := adapter.NewSubscriberWithPulsarClient(mockClient, config, log) require.NoError(t, err) defer sub.Close() ctx := context.WithValue(context.Background(), adapter.SubNameKey, "custom-sub-name") msgChan, err := sub.Subscribe(ctx, "test-topic") require.NoError(t, err) assert.NotNil(t, msgChan) } func TestSubscriber_Subscribe_WithCustomIndex(t *testing.T) { t.Parallel() mockClient := mocks.NewMockPulsarClient() log := logger.NewNopLogger() config := adapter.SubscriberConfig{ SubscriberName: "test-sub", SubscriberType: pulsar.Shared, } sub, err := adapter.NewSubscriberWithPulsarClient(mockClient, config, log) require.NoError(t, err) defer sub.Close() ctx := context.WithValue(context.Background(), adapter.IndexKey, 5) msgChan, err := sub.Subscribe(ctx, "test-topic") require.NoError(t, err) assert.NotNil(t, msgChan) } func TestSubscriber_Subscribe_WithCustomReceiverQueueSize(t *testing.T) { t.Parallel() mockClient := mocks.NewMockPulsarClient() log := logger.NewNopLogger() config := adapter.SubscriberConfig{ SubscriberName: "test-sub", SubscriberType: pulsar.Shared, } sub, err := adapter.NewSubscriberWithPulsarClient(mockClient, config, log) require.NoError(t, err) defer sub.Close() ctx := context.WithValue(context.Background(), adapter.ReceiverQueueSizeKey, 2000) msgChan, err := sub.Subscribe(ctx, "test-topic") require.NoError(t, err) assert.NotNil(t, msgChan) } func TestPublisher_Publish_CreateProducerError(t *testing.T) { t.Parallel() mockClient := mocks.NewMockPulsarClient() log := logger.NewNopLogger() pub, err := adapter.NewPublisherWithPulsarClient(mockClient, log) require.NoError(t, err) defer pub.Close() // Close client before creating producer mockClient.Close() msg := message.NewMessage("test-uuid", []byte("test payload")) err = pub.Publish("new-topic", msg) // Should fail when creating producer if err != nil { assert.Contains(t, err.Error(), "closed") } } func TestPublisher_Publish_SendError(t *testing.T) { t.Parallel() mockClient := mocks.NewMockPulsarClient() log := logger.NewNopLogger() pub, err := adapter.NewPublisherWithPulsarClient(mockClient, log) require.NoError(t, err) defer pub.Close() // Create a producer first msg1 := message.NewMessage("test-uuid-1", []byte("test payload 1")) err = pub.Publish("test-topic", msg1) require.NoError(t, err) // Close the producer to cause send error producer := mockClient.GetProducer("test-topic") require.NotNil(t, producer) producer.Close() msg2 := message.NewMessage("test-uuid-2", []byte("test payload 2")) err = pub.Publish("test-topic", msg2) // May succeed or fail depending on implementation _ = err }