import 'package:test/test.dart'; import 'package:mockito/annotations.dart'; import 'package:mockito/mockito.dart'; import 'package:angel3_container/angel3_container.dart'; import 'package:angel3_event_bus/event_bus.dart'; import 'package:angel3_mq/mq.dart'; import 'package:angel3_queue/src/queue.dart'; import 'package:angel3_queue/src/job_queueing_event.dart'; import 'package:angel3_queue/src/job_queued_event.dart'; import 'package:angel3_queue/src/should_queue_after_commit.dart'; //import 'package:angel3_queue/src/invalid_payload_exception.dart'; import 'queue_test.mocks.dart'; @GenerateMocks([Container, EventBus, MQClient, TransactionManager]) void main() { late MockContainer container; late MockEventBus eventBus; late MockMQClient mq; late TestQueue queue; setUpAll(() { provideDummy(MockEventBus()); }); setUp(() { container = MockContainer(); eventBus = MockEventBus(); mq = MockMQClient(); queue = TestQueue(container, eventBus, mq); // Inject the other mocks into the queue // queue.container = container; // queue.mq = mq; when(container.has()).thenReturn(true); when(container.has()).thenReturn(false); when(container.make()).thenReturn(eventBus); // Setup for EventBus mock when(eventBus.fire(any)).thenAnswer((_) => Future.value()); // Setup for MQClient mock when(mq.sendMessage( message: anyNamed('message'), exchangeName: anyNamed('exchangeName'), routingKey: anyNamed('routingKey'), )).thenAnswer((_) { print("Debug: Mock sendMessage called"); // Notice we're not returning anything here }); }); test('pushOn calls push with correct arguments', () async { final result = await queue.pushOn('test_queue', 'test_job', 'test_data'); expect(result, equals('pushed')); }); test('laterOn calls later with correct arguments', () async { final result = await queue.laterOn( 'test_queue', Duration(minutes: 5), 'test_job', 'test_data'); expect(result, equals('pushed later')); }); test('bulk pushes multiple jobs', () async { await queue.bulk(['job1', 'job2', 'job3'], 'test_data', 'test_queue'); expect(queue.pushedJobs.length, equals(3)); expect(queue.pushedJobs, containsAll(['job1', 'job2', 'job3'])); }); test('createPayload throws InvalidPayloadException for invalid job', () { expect(() => queue.createPayload({}, 'test_queue'), throwsA(isA())); }); test('shouldDispatchAfterCommit returns correct value', () { expect( queue.shouldDispatchAfterCommit(MockShouldQueueAfterCommit()), isTrue); expect(queue.shouldDispatchAfterCommit({}), isFalse); queue.dispatchAfterCommit = true; expect(queue.shouldDispatchAfterCommit({}), isTrue); }); test('enqueueUsing publishes message and fires events', () async { when(container.has()).thenReturn(false); print("Debug: Before enqueueUsing"); await queue.enqueueUsing( 'test_job', 'test_payload', 'test_queue', null, (payload, queue, delay) async => 'job_id', ); print("Debug: After enqueueUsing"); // Verify all method calls in order verifyInOrder([ eventBus.fire(argThat(isA())), eventBus.fire(argThat(isA())), mq.sendMessage( message: anyNamed('message'), exchangeName: anyNamed('exchangeName'), routingKey: anyNamed('routingKey'), ), ]); // Print captured arguments for sendMessage final sendMessageCall = verify(mq.sendMessage( message: captureAnyNamed('message'), exchangeName: captureAnyNamed('exchangeName'), routingKey: captureAnyNamed('routingKey'), )); if (sendMessageCall.captured.isNotEmpty) { print("sendMessage was called with:"); print("message: ${sendMessageCall.captured[0]}"); print("exchangeName: ${sendMessageCall.captured[1]}"); print("routingKey: ${sendMessageCall.captured[2]}"); } else { print("sendMessage was not called"); } // Additional verifications verify(eventBus.fire(any)).called(2); verify(mq.sendMessage( message: anyNamed('message'), exchangeName: anyNamed('exchangeName'), routingKey: anyNamed('routingKey'), )).called(1); }); } class TestQueue extends Queue { List pushedJobs = []; TestQueue(Container container, EventBus eventBus, MQClient mq) : super(container, eventBus, mq); @override Future push(dynamic job, [dynamic data = '', String? queue]) async { pushedJobs.add(job); return 'pushed'; } @override Future later(Duration delay, dynamic job, [dynamic data = '', String? queue]) async { return 'pushed later'; } @override Future createPayload(dynamic job, String queue, [dynamic data = '']) async { if (job is Map && job.isEmpty) { throw InvalidPayloadException('Invalid job: empty map'); } return 'valid payload'; } @override bool shouldDispatchAfterCommit(dynamic job) { if (job is ShouldQueueAfterCommit) { return true; } return dispatchAfterCommit; } @override Future enqueueUsing( dynamic job, String payload, String? queue, Duration? delay, Future Function(String, String?, Duration?) callback, ) async { eventBus.fire(JobQueueingEvent(connectionName, queue, job, payload, delay)); final result = await callback(payload, queue, delay); eventBus.fire( JobQueuedEvent(connectionName, queue, result, job, payload, delay)); print("Attempting to send message..."); // Debug print mq.sendMessage( message: Message( id: 'test-id', headers: {}, payload: payload, timestamp: DateTime.now().toIso8601String(), ), exchangeName: '', routingKey: queue ?? 'default', ); print("Message sent."); // Debug print return result; } } // class DummyEventBus implements EventBus { // List firedEvents = []; // @override // Future fire(AppEvent event) async { // firedEvents.add(event); // } // @override // dynamic noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation); // } class InvalidPayloadException implements Exception { final String message; InvalidPayloadException(this.message); @override String toString() => 'InvalidPayloadException: $message'; } class MockShouldQueueAfterCommit implements ShouldQueueAfterCommit {}