From 65f6141df3e076d20c2cd3a747d28988217e52a6 Mon Sep 17 00:00:00 2001 From: purnimavenkatasubbu Date: Mon, 18 Nov 2024 22:01:54 +0530 Subject: [PATCH] removed useWebSocket flag and added unit tests --- .../at_lookup/lib/src/at_lookup_impl.dart | 9 +- packages/at_lookup/test/at_lookup_test.dart | 1049 +++++++++++------ .../at_lookup/test/at_lookup_test_utils.dart | 22 + .../test/at_lookup_test.dart | 10 +- 4 files changed, 725 insertions(+), 365 deletions(-) diff --git a/packages/at_lookup/lib/src/at_lookup_impl.dart b/packages/at_lookup/lib/src/at_lookup_impl.dart index 95697c3d..c8c635d5 100644 --- a/packages/at_lookup/lib/src/at_lookup_impl.dart +++ b/packages/at_lookup/lib/src/at_lookup_impl.dart @@ -16,7 +16,6 @@ import 'package:crypto/crypto.dart'; import 'package:crypton/crypton.dart'; import 'package:mutex/mutex.dart'; - class AtLookupImpl implements AtLookUp { final logger = AtSignLogger('AtLookup'); @@ -63,12 +62,10 @@ class AtLookupImpl implements AtLookUp { SecondaryAddressFinder? secondaryAddressFinder, SecureSocketConfig? secureSocketConfig, Map? clientConfig, - bool useWebSocket = false}) // Add a flag for WebSocket or SecureSocket + AtLookupOutboundConnectionFactory? atSocketFactory}) { - // Determine the factory type based on the useWebSocket flag - atSocketFactory = useWebSocket - ? AtLookupWebSocketFactory() - : AtLookupSecureSocketFactory() as AtLookupOutboundConnectionFactory; + // Default to secure socket factory + this.atSocketFactory = atSocketFactory ?? AtLookupSecureSocketFactory(); _currentAtSign = atSign; _rootDomain = rootDomain; _rootPort = rootPort; diff --git a/packages/at_lookup/test/at_lookup_test.dart b/packages/at_lookup/test/at_lookup_test.dart index 38015029..24abad81 100644 --- a/packages/at_lookup/test/at_lookup_test.dart +++ b/packages/at_lookup/test/at_lookup_test.dart @@ -18,408 +18,749 @@ class FakeAtSigningInput extends Fake implements AtSigningInput {} void main() { AtSignLogger.root_level = 'finest'; late OutboundConnection mockOutBoundConnection; + late OutboundWebSocketConnection mockOutboundWebsocketConnection; late SecondaryAddressFinder mockSecondaryAddressFinder; late OutboundMessageListener mockOutboundListener; late AtLookupOutboundConnectionFactory mockAtConnectionFactory; late AtChops mockAtChops; late SecureSocket mockSecureSocket; + late WebSocket mockWebSocket; String atServerHost = '127.0.0.1'; int atServerPort = 12345; - setUp(() { - mockOutBoundConnection = MockOutboundConnectionImpl(); - mockSecondaryAddressFinder = MockSecondaryAddressFinder(); - mockOutboundListener = MockOutboundMessageListener(); - mockAtConnectionFactory = MockAtLookupOutboundConnectionFactory(); - mockAtChops = MockAtChops(); - registerFallbackValue(SecureSocketConfig()); - mockSecureSocket = createMockAtServerSocket(atServerHost, atServerPort); - - when(() => mockSecondaryAddressFinder.findSecondary('@alice')) - .thenAnswer((_) async { - return SecondaryAddress(atServerHost, atServerPort); - }); + group('A group of websocket tests', () { + setUp(() { + mockOutBoundConnection = MockOutboundConnectionImpl(); + mockSecondaryAddressFinder = MockSecondaryAddressFinder(); + mockOutboundListener = MockOutboundMessageListener(); + mockAtConnectionFactory = MockAtLookupOutboundConnectionFactory(); + mockAtChops = MockAtChops(); + registerFallbackValue(SecureSocketConfig()); + mockSecureSocket = createMockAtServerSocket(atServerHost, atServerPort); + + when(() => mockSecondaryAddressFinder.findSecondary('@alice')) + .thenAnswer((_) async { + return SecondaryAddress(atServerHost, atServerPort); + }); - when(() => mockAtConnectionFactory.createUnderlying( - atServerHost, '12345', any())).thenAnswer((_) { - return Future.value(mockSecureSocket); - }); + when(() => mockAtConnectionFactory.createUnderlying( + atServerHost, '12345', any())).thenAnswer((_) { + return Future.value(mockSecureSocket); + }); - when(() => - mockAtConnectionFactory.outBoundConnectionFactory(mockSecureSocket)) - .thenAnswer((_) => mockOutBoundConnection); + when(() => mockAtConnectionFactory.outBoundConnectionFactory( + mockSecureSocket)).thenAnswer((_) => mockOutBoundConnection); - when(() => mockOutBoundConnection.write(any())) - .thenAnswer((_) => Future.value()); + when(() => mockOutBoundConnection.write(any())) + .thenAnswer((_) => Future.value()); - when(() => mockAtConnectionFactory.atLookupSocketListenerFactory( - mockOutBoundConnection)).thenAnswer((_) => mockOutboundListener); - }); + when(() => mockAtConnectionFactory.atLookupSocketListenerFactory( + mockOutBoundConnection)).thenAnswer((_) => mockOutboundListener); + }); - group('A group of tests to verify atlookup pkam authentication', () { - test('pkam auth without enrollmentId - auth success', () async { - final pkamSignature = - 'MbNbIwCSxsHxm4CHyakSE2yLqjjtnmzpSLPcGG7h+4M/GQAiJkklQfd/x9z58CSJfuSW8baIms26SrnmuYePZURfp5oCqtwRpvt+l07Gnz8aYpXH0k5qBkSR34SBk4nb+hdAjsXXgfWWC56gROPMwpOEbuDS6esU7oku+a7Rdr10xrFlk1Tf2eRwPOMWyuKwOvLwSgyq/INAFRYav5RmLFiecQhPME6ssc1jW92wztylKBtuZT4rk8787b6Z9StxT4dPZzWjfV1+oYDLaqu2PcQS2ZthH+Wj8NgoogDxSP+R7BE1FOVJKnavpuQWeOqNWeUbKkSVP0B0DN6WopAdsg=='; - - AtSigningResult mockSigningResult = AtSigningResult() - ..result = 'mock_signing_result'; - registerFallbackValue(FakeAtSigningInput()); - when(() => mockAtChops.sign(any())).thenAnswer((_) => mockSigningResult); - - when(() => mockAtChops.sign(any())) - .thenReturn(AtSigningResult()..result = pkamSignature); - when(() => mockOutboundListener.read()) - .thenAnswer((_) => Future.value('data:success')); - - when(() => mockOutBoundConnection.getMetaData()) - .thenReturn(OutboundConnectionMetadata()..isAuthenticated = false); - when(() => mockOutBoundConnection.isInValid()).thenReturn(false); - - when(() => mockOutBoundConnection.write( - 'pkam:signingAlgo:rsa2048:hashingAlgo:sha256:$pkamSignature\n')) - .thenAnswer((invocation) { - mockSecureSocket.write( - 'pkam:signingAlgo:rsa2048:hashingAlgo:sha256:$pkamSignature\n'); - return Future.value(); + group('A group of tests to verify atlookup pkam authentication', () { + test('pkam auth without enrollmentId - auth success', () async { + final pkamSignature = + 'MbNbIwCSxsHxm4CHyakSE2yLqjjtnmzpSLPcGG7h+4M/GQAiJkklQfd/x9z58CSJfuSW8baIms26SrnmuYePZURfp5oCqtwRpvt+l07Gnz8aYpXH0k5qBkSR34SBk4nb+hdAjsXXgfWWC56gROPMwpOEbuDS6esU7oku+a7Rdr10xrFlk1Tf2eRwPOMWyuKwOvLwSgyq/INAFRYav5RmLFiecQhPME6ssc1jW92wztylKBtuZT4rk8787b6Z9StxT4dPZzWjfV1+oYDLaqu2PcQS2ZthH+Wj8NgoogDxSP+R7BE1FOVJKnavpuQWeOqNWeUbKkSVP0B0DN6WopAdsg=='; + + AtSigningResult mockSigningResult = AtSigningResult() + ..result = 'mock_signing_result'; + registerFallbackValue(FakeAtSigningInput()); + when(() => mockAtChops.sign(any())) + .thenAnswer((_) => mockSigningResult); + + when(() => mockAtChops.sign(any())) + .thenReturn(AtSigningResult()..result = pkamSignature); + when(() => mockOutboundListener.read()) + .thenAnswer((_) => Future.value('data:success')); + + when(() => mockOutBoundConnection.getMetaData()) + .thenReturn(OutboundConnectionMetadata()..isAuthenticated = false); + when(() => mockOutBoundConnection.isInValid()).thenReturn(false); + + when(() => mockOutBoundConnection.write( + 'pkam:signingAlgo:rsa2048:hashingAlgo:sha256:$pkamSignature\n')) + .thenAnswer((invocation) { + mockSecureSocket.write( + 'pkam:signingAlgo:rsa2048:hashingAlgo:sha256:$pkamSignature\n'); + return Future.value(); + }); + + final atLookup = AtLookupImpl( + '@alice', + atServerHost, + 64, + secondaryAddressFinder: mockSecondaryAddressFinder); + // Override atConnectionFactory with mock in AtLookupImpl + atLookup.atSocketFactory = mockAtConnectionFactory; + atLookup.atChops = mockAtChops; + var result = await atLookup.pkamAuthenticate(); + expect(result, true); }); - final atLookup = AtLookupImpl( - '@alice', - atServerHost, - 64, - secondaryAddressFinder: mockSecondaryAddressFinder, - ); - // Override atConnectionFactory with mock in AtLookupImpl - atLookup.atSocketFactory = mockAtConnectionFactory; - atLookup.atChops = mockAtChops; - var result = await atLookup.pkamAuthenticate(); - expect(result, true); - }); + test('pkam auth without enrollmentId - auth failed', () async { + final pkamSignature = + 'MbNbIwCSxsHxm4CHyakSE2yLqjjtnmzpSLPcGG7h+4M/GQAiJkklQfd/x9z58CSJfuSW8baIms26SrnmuYePZURfp5oCqtwRpvt+l07Gnz8aYpXH0k5qBkSR34SBk4nb+hdAjsXXgfWWC56gROPMwpOEbuDS6esU7oku+a7Rdr10xrFlk1Tf2eRwPOMWyuKwOvLwSgyq/INAFRYav5RmLFiecQhPME6ssc1jW92wztylKBtuZT4rk8787b6Z9StxT4dPZzWjfV1+oYDLaqu2PcQS2ZthH+Wj8NgoogDxSP+R7BE1FOVJKnavpuQWeOqNWeUbKkSVP0B0DN6WopAdsg=='; + + AtSigningResult mockSigningResult = AtSigningResult() + ..result = 'mock_signing_result'; + registerFallbackValue(FakeAtSigningInput()); + when(() => mockAtChops.sign(any())) + .thenAnswer((_) => mockSigningResult); + + when(() => mockAtChops.sign(any())) + .thenReturn(AtSigningResult()..result = pkamSignature); + when(() => mockOutboundListener.read()).thenAnswer((_) => + Future.value('error:AT0401-Exception: pkam authentication failed')); + + when(() => mockOutBoundConnection.getMetaData()) + .thenReturn(OutboundConnectionMetadata()..isAuthenticated = false); + when(() => mockOutBoundConnection.isInValid()).thenReturn(false); + + when(() => mockOutBoundConnection.write( + 'pkam:signingAlgo:rsa2048:hashingAlgo:sha256:$pkamSignature\n')) + .thenAnswer((invocation) { + mockSecureSocket.write( + 'pkam:signingAlgo:rsa2048:hashingAlgo:sha256:$pkamSignature\n'); + return Future.value(); + }); + + final atLookup = AtLookupImpl('@alice', atServerHost, 64, + secondaryAddressFinder: mockSecondaryAddressFinder); + // Override atConnectionFactory with mock in AtLookupImpl + atLookup.atSocketFactory = mockAtConnectionFactory; + atLookup.atChops = mockAtChops; + expect(() async => await atLookup.pkamAuthenticate(), + throwsA(predicate((e) => e is UnAuthenticatedException))); + }); - test('pkam auth without enrollmentId - auth failed', () async { - final pkamSignature = - 'MbNbIwCSxsHxm4CHyakSE2yLqjjtnmzpSLPcGG7h+4M/GQAiJkklQfd/x9z58CSJfuSW8baIms26SrnmuYePZURfp5oCqtwRpvt+l07Gnz8aYpXH0k5qBkSR34SBk4nb+hdAjsXXgfWWC56gROPMwpOEbuDS6esU7oku+a7Rdr10xrFlk1Tf2eRwPOMWyuKwOvLwSgyq/INAFRYav5RmLFiecQhPME6ssc1jW92wztylKBtuZT4rk8787b6Z9StxT4dPZzWjfV1+oYDLaqu2PcQS2ZthH+Wj8NgoogDxSP+R7BE1FOVJKnavpuQWeOqNWeUbKkSVP0B0DN6WopAdsg=='; - - AtSigningResult mockSigningResult = AtSigningResult() - ..result = 'mock_signing_result'; - registerFallbackValue(FakeAtSigningInput()); - when(() => mockAtChops.sign(any())).thenAnswer((_) => mockSigningResult); - - when(() => mockAtChops.sign(any())) - .thenReturn(AtSigningResult()..result = pkamSignature); - when(() => mockOutboundListener.read()).thenAnswer((_) => - Future.value('error:AT0401-Exception: pkam authentication failed')); - - when(() => mockOutBoundConnection.getMetaData()) - .thenReturn(OutboundConnectionMetadata()..isAuthenticated = false); - when(() => mockOutBoundConnection.isInValid()).thenReturn(false); - - when(() => mockOutBoundConnection.write( - 'pkam:signingAlgo:rsa2048:hashingAlgo:sha256:$pkamSignature\n')) - .thenAnswer((invocation) { - mockSecureSocket.write( - 'pkam:signingAlgo:rsa2048:hashingAlgo:sha256:$pkamSignature\n'); - return Future.value(); + test('pkam auth with enrollmentId - auth success', () async { + final pkamSignature = + 'MbNbIwCSxsHxm4CHyakSE2yLqjjtnmzpSLPcGG7h+4M/GQAiJkklQfd/x9z58CSJfuSW8baIms26SrnmuYePZURfp5oCqtwRpvt+l07Gnz8aYpXH0k5qBkSR34SBk4nb+hdAjsXXgfWWC56gROPMwpOEbuDS6esU7oku+a7Rdr10xrFlk1Tf2eRwPOMWyuKwOvLwSgyq/INAFRYav5RmLFiecQhPME6ssc1jW92wztylKBtuZT4rk8787b6Z9StxT4dPZzWjfV1+oYDLaqu2PcQS2ZthH+Wj8NgoogDxSP+R7BE1FOVJKnavpuQWeOqNWeUbKkSVP0B0DN6WopAdsg=='; + final enrollmentIdFromServer = '5a21feb4-dc04-4603-829c-15f523789170'; + AtSigningResult mockSigningResult = AtSigningResult() + ..result = 'mock_signing_result'; + registerFallbackValue(FakeAtSigningInput()); + when(() => mockAtChops.sign(any())) + .thenAnswer((_) => mockSigningResult); + + when(() => mockAtChops.sign(any())) + .thenReturn(AtSigningResult()..result = pkamSignature); + when(() => mockOutboundListener.read()) + .thenAnswer((_) => Future.value('data:success')); + + when(() => mockOutBoundConnection.getMetaData()) + .thenReturn(OutboundConnectionMetadata()..isAuthenticated = false); + when(() => mockOutBoundConnection.isInValid()).thenReturn(false); + + when(() => mockOutBoundConnection.write( + 'pkam:signingAlgo:rsa2048:hashingAlgo:sha256:enrollmentId:$enrollmentIdFromServer:$pkamSignature\n')) + .thenAnswer((invocation) { + mockSecureSocket.write( + 'pkam:signingAlgo:rsa2048:hashingAlgo:sha256:enrollmentId:$enrollmentIdFromServer:$pkamSignature\n'); + return Future.value(); + }); + + final atLookup = AtLookupImpl('@alice', atServerHost, 64, + secondaryAddressFinder: mockSecondaryAddressFinder); + atLookup.atSocketFactory = mockAtConnectionFactory; + atLookup.atChops = mockAtChops; + var result = await atLookup.pkamAuthenticate( + enrollmentId: enrollmentIdFromServer); + expect(result, true); }); - final atLookup = AtLookupImpl('@alice', atServerHost, 64, - secondaryAddressFinder: mockSecondaryAddressFinder); - // Override atConnectionFactory with mock in AtLookupImpl - atLookup.atSocketFactory = mockAtConnectionFactory; - atLookup.atChops = mockAtChops; - expect(() async => await atLookup.pkamAuthenticate(), - throwsA(predicate((e) => e is UnAuthenticatedException))); + test('pkam auth with enrollmentId - auth failed', () async { + final pkamSignature = + 'MbNbIwCSxsHxm4CHyakSE2yLqjjtnmzpSLPcGG7h+4M/GQAiJkklQfd/x9z58CSJfuSW8baIms26SrnmuYePZURfp5oCqtwRpvt+l07Gnz8aYpXH0k5qBkSR34SBk4nb+hdAjsXXgfWWC56gROPMwpOEbuDS6esU7oku+a7Rdr10xrFlk1Tf2eRwPOMWyuKwOvLwSgyq/INAFRYav5RmLFiecQhPME6ssc1jW92wztylKBtuZT4rk8787b6Z9StxT4dPZzWjfV1+oYDLaqu2PcQS2ZthH+Wj8NgoogDxSP+R7BE1FOVJKnavpuQWeOqNWeUbKkSVP0B0DN6WopAdsg=='; + final enrollmentIdFromServer = '5a21feb4-dc04-4603-829c-15f523789170'; + AtSigningResult mockSigningResult = AtSigningResult() + ..result = 'mock_signing_result'; + registerFallbackValue(FakeAtSigningInput()); + when(() => mockAtChops.sign(any())) + .thenAnswer((_) => mockSigningResult); + + when(() => mockAtChops.sign(any())) + .thenReturn(AtSigningResult()..result = pkamSignature); + when(() => mockOutboundListener.read()).thenAnswer((_) => + Future.value('error:AT0401-Exception: pkam authentication failed')); + + when(() => mockOutBoundConnection.getMetaData()) + .thenReturn(OutboundConnectionMetadata()..isAuthenticated = false); + when(() => mockOutBoundConnection.isInValid()).thenReturn(false); + when(() => mockOutBoundConnection.write( + 'pkam:signingAlgo:rsa2048:hashingAlgo:sha256:enrollmentId:$enrollmentIdFromServer:$pkamSignature\n')) + .thenAnswer((invocation) { + mockSecureSocket.write( + 'pkam:signingAlgo:rsa2048:hashingAlgo:sha256:enrollmentId:$enrollmentIdFromServer:$pkamSignature\n'); + return Future.value(); + }); + + final atLookup = AtLookupImpl('@alice', atServerHost, 64, + secondaryAddressFinder: mockSecondaryAddressFinder); + atLookup.atSocketFactory = mockAtConnectionFactory; + atLookup.atChops = mockAtChops; + expect( + () async => await atLookup.pkamAuthenticate( + enrollmentId: enrollmentIdFromServer), + throwsA(predicate((e) => + e is UnAuthenticatedException && + e.message.contains('AT0401')))); + }); }); - test('pkam auth with enrollmentId - auth success', () async { - final pkamSignature = - 'MbNbIwCSxsHxm4CHyakSE2yLqjjtnmzpSLPcGG7h+4M/GQAiJkklQfd/x9z58CSJfuSW8baIms26SrnmuYePZURfp5oCqtwRpvt+l07Gnz8aYpXH0k5qBkSR34SBk4nb+hdAjsXXgfWWC56gROPMwpOEbuDS6esU7oku+a7Rdr10xrFlk1Tf2eRwPOMWyuKwOvLwSgyq/INAFRYav5RmLFiecQhPME6ssc1jW92wztylKBtuZT4rk8787b6Z9StxT4dPZzWjfV1+oYDLaqu2PcQS2ZthH+Wj8NgoogDxSP+R7BE1FOVJKnavpuQWeOqNWeUbKkSVP0B0DN6WopAdsg=='; - final enrollmentIdFromServer = '5a21feb4-dc04-4603-829c-15f523789170'; - AtSigningResult mockSigningResult = AtSigningResult() - ..result = 'mock_signing_result'; - registerFallbackValue(FakeAtSigningInput()); - when(() => mockAtChops.sign(any())).thenAnswer((_) => mockSigningResult); - - when(() => mockAtChops.sign(any())) - .thenReturn(AtSigningResult()..result = pkamSignature); - when(() => mockOutboundListener.read()) - .thenAnswer((_) => Future.value('data:success')); - - when(() => mockOutBoundConnection.getMetaData()) - .thenReturn(OutboundConnectionMetadata()..isAuthenticated = false); - when(() => mockOutBoundConnection.isInValid()).thenReturn(false); - - when(() => mockOutBoundConnection.write( - 'pkam:signingAlgo:rsa2048:hashingAlgo:sha256:enrollmentId:$enrollmentIdFromServer:$pkamSignature\n')) - .thenAnswer((invocation) { - mockSecureSocket.write( - 'pkam:signingAlgo:rsa2048:hashingAlgo:sha256:enrollmentId:$enrollmentIdFromServer:$pkamSignature\n'); - return Future.value(); + group('A group of tests to verify executeCommand method', () { + test('executeCommand - from verb - auth false', () async { + final atLookup = AtLookupImpl('@alice', atServerHost, 64, + secondaryAddressFinder: mockSecondaryAddressFinder); + atLookup.atSocketFactory = mockAtConnectionFactory; + final fromResponse = + 'data:_03fe0ff2-ac50-4c80-8f43-88480beba888@alice:c3d345fc-5691-4f90-bc34-17cba31f060f'; + when(() => mockOutboundListener.read()) + .thenAnswer((_) => Future.value(fromResponse)); + var result = await atLookup.executeCommand('from:@alice\n'); + expect(result, fromResponse); + }, timeout: Timeout(Duration(minutes: 5))); + + test('executeCommand -llookup verb - auth true - auth key not set', + () async { + final atLookup = AtLookupImpl('@alice', atServerHost, 64, + secondaryAddressFinder: mockSecondaryAddressFinder); + final fromResponse = 'data:1234'; + when(() => mockOutboundListener.read()) + .thenAnswer((_) => Future.value(fromResponse)); + expect( + () async => await atLookup.executeCommand('llookup:phone@alice\n', + auth: true), + throwsA(predicate((e) => e is UnAuthenticatedException))); }); - final atLookup = AtLookupImpl('@alice', atServerHost, 64, - secondaryAddressFinder: mockSecondaryAddressFinder); - atLookup.atSocketFactory = mockAtConnectionFactory; - atLookup.atChops = mockAtChops; - var result = - await atLookup.pkamAuthenticate(enrollmentId: enrollmentIdFromServer); - expect(result, true); - }); + test('executeCommand -llookup verb - auth true - at_chops set', () async { + final atLookup = AtLookupImpl('@alice', atServerHost, 64, + secondaryAddressFinder: mockSecondaryAddressFinder); + atLookup.atSocketFactory = mockAtConnectionFactory; + atLookup.atChops = mockAtChops; + final llookupCommand = 'llookup:phone@alice\n'; + final llookupResponse = 'data:1234'; + when(() => mockOutBoundConnection.write(llookupCommand)) + .thenAnswer((invocation) { + mockSecureSocket.write(llookupCommand); + return Future.value(); + }); + when(() => mockOutboundListener.read()) + .thenAnswer((_) => Future.value(llookupResponse)); + var result = await atLookup.executeCommand(llookupCommand); + expect(result, llookupResponse); + }); - test('pkam auth with enrollmentId - auth failed', () async { - final pkamSignature = - 'MbNbIwCSxsHxm4CHyakSE2yLqjjtnmzpSLPcGG7h+4M/GQAiJkklQfd/x9z58CSJfuSW8baIms26SrnmuYePZURfp5oCqtwRpvt+l07Gnz8aYpXH0k5qBkSR34SBk4nb+hdAjsXXgfWWC56gROPMwpOEbuDS6esU7oku+a7Rdr10xrFlk1Tf2eRwPOMWyuKwOvLwSgyq/INAFRYav5RmLFiecQhPME6ssc1jW92wztylKBtuZT4rk8787b6Z9StxT4dPZzWjfV1+oYDLaqu2PcQS2ZthH+Wj8NgoogDxSP+R7BE1FOVJKnavpuQWeOqNWeUbKkSVP0B0DN6WopAdsg=='; - final enrollmentIdFromServer = '5a21feb4-dc04-4603-829c-15f523789170'; - AtSigningResult mockSigningResult = AtSigningResult() - ..result = 'mock_signing_result'; - registerFallbackValue(FakeAtSigningInput()); - when(() => mockAtChops.sign(any())).thenAnswer((_) => mockSigningResult); - - when(() => mockAtChops.sign(any())) - .thenReturn(AtSigningResult()..result = pkamSignature); - when(() => mockOutboundListener.read()).thenAnswer((_) => - Future.value('error:AT0401-Exception: pkam authentication failed')); - - when(() => mockOutBoundConnection.getMetaData()) - .thenReturn(OutboundConnectionMetadata()..isAuthenticated = false); - when(() => mockOutBoundConnection.isInValid()).thenReturn(false); - when(() => mockOutBoundConnection.write( - 'pkam:signingAlgo:rsa2048:hashingAlgo:sha256:enrollmentId:$enrollmentIdFromServer:$pkamSignature\n')) - .thenAnswer((invocation) { - mockSecureSocket.write( - 'pkam:signingAlgo:rsa2048:hashingAlgo:sha256:enrollmentId:$enrollmentIdFromServer:$pkamSignature\n'); - return Future.value(); + test('executeCommand - test non json error handling', () async { + final atLookup = AtLookupImpl('@alice', atServerHost, 64, + secondaryAddressFinder: mockSecondaryAddressFinder); + atLookup.atSocketFactory = mockAtConnectionFactory; + atLookup.atChops = mockAtChops; + final llookupCommand = 'llookup:phone@alice\n'; + final llookupResponse = 'error:AT0015-Exception: fubar'; + when(() => mockOutBoundConnection.write(llookupCommand)) + .thenAnswer((invocation) { + mockSecureSocket.write(llookupCommand); + return Future.value(); + }); + when(() => mockOutboundListener.read()) + .thenAnswer((_) => Future.value(llookupResponse)); + await expectLater( + atLookup.executeCommand(llookupCommand), + throwsA(predicate((e) => + e is AtLookUpException && + e.errorMessage == 'Exception: fubar'))); }); - final atLookup = AtLookupImpl('@alice', atServerHost, 64, - secondaryAddressFinder: mockSecondaryAddressFinder); - atLookup.atSocketFactory = mockAtConnectionFactory; - atLookup.atChops = mockAtChops; - expect( - () async => await atLookup.pkamAuthenticate( - enrollmentId: enrollmentIdFromServer), - throwsA(predicate((e) => - e is UnAuthenticatedException && e.message.contains('AT0401')))); + test('executeCommand - test json error handling', () async { + final atLookup = AtLookupImpl('@alice', atServerHost, 64, + secondaryAddressFinder: mockSecondaryAddressFinder); + atLookup.atSocketFactory = mockAtConnectionFactory; + atLookup.atChops = mockAtChops; + final llookupCommand = 'llookup:phone@alice\n'; + final llookupResponse = + 'error:{"errorCode":"AT0015","errorDescription":"Exception: fubar"}'; + when(() => mockOutBoundConnection.write(llookupCommand)) + .thenAnswer((invocation) { + mockSecureSocket.write(llookupCommand); + return Future.value(); + }); + when(() => mockOutboundListener.read()) + .thenAnswer((_) => Future.value(llookupResponse)); + await expectLater( + atLookup.executeCommand(llookupCommand), + throwsA(predicate((e) => + e is AtLookUpException && + e.errorMessage == 'Exception: fubar'))); + }); }); - }); - group('A group of tests to verify executeCommand method', () { - test('executeCommand - from verb - auth false', () async { - final atLookup = AtLookupImpl('@alice', atServerHost, 64, - secondaryAddressFinder: mockSecondaryAddressFinder); - atLookup.atSocketFactory = mockAtConnectionFactory; - final fromResponse = - 'data:_03fe0ff2-ac50-4c80-8f43-88480beba888@alice:c3d345fc-5691-4f90-bc34-17cba31f060f'; - when(() => mockOutboundListener.read()) - .thenAnswer((_) => Future.value(fromResponse)); - var result = await atLookup.executeCommand('from:@alice\n'); - expect(result, fromResponse); - }, timeout: Timeout(Duration(minutes: 5))); - - test('executeCommand -llookup verb - auth true - auth key not set', - () async { - final atLookup = AtLookupImpl('@alice', atServerHost, 64, - secondaryAddressFinder: mockSecondaryAddressFinder); - final fromResponse = 'data:1234'; - when(() => mockOutboundListener.read()) - .thenAnswer((_) => Future.value(fromResponse)); - expect( - () async => await atLookup.executeCommand('llookup:phone@alice\n', - auth: true), - throwsA(predicate((e) => e is UnAuthenticatedException))); - }); + group('Validate executeVerb() behaviour', () { + test('validate EnrollVerbHandler behaviour - request', () async { + final atLookup = AtLookupImpl('@alice', atServerHost, 64, + secondaryAddressFinder: mockSecondaryAddressFinder); + atLookup.atSocketFactory = mockAtConnectionFactory; + String appName = 'unit_test_1'; + String deviceName = 'test_device'; + String otp = 'ABCDEF'; + + EnrollVerbBuilder enrollVerbBuilder = EnrollVerbBuilder() + ..operation = EnrollOperationEnum.request + ..appName = appName + ..deviceName = deviceName + ..otp = otp; + String enrollCommand = + 'enroll:request:{"appName":"$appName","deviceName":"$deviceName","otp":"$otp"}\n'; + final enrollResponse = + 'data:{"enrollmentId":"1234567890","status":"pending"}'; + + when(() => mockOutBoundConnection.write(enrollCommand)) + .thenAnswer((invocation) { + mockSecureSocket.write(enrollCommand); + return Future.value(); + }); + when(() => mockOutboundListener.read()) + .thenAnswer((_) => Future.value(enrollResponse)); + AtConnectionMetaData? atConnectionMetaData = + OutboundConnectionMetadata()..isAuthenticated = false; + when(() => mockOutBoundConnection.getMetaData()) + .thenReturn(atConnectionMetaData); + when(() => mockOutBoundConnection.isInValid()).thenReturn(false); + + var result = await atLookup.executeVerb(enrollVerbBuilder); + expect(result, enrollResponse); + }); - test('executeCommand -llookup verb - auth true - at_chops set', () async { - final atLookup = AtLookupImpl('@alice', atServerHost, 64, - secondaryAddressFinder: mockSecondaryAddressFinder); - atLookup.atSocketFactory = mockAtConnectionFactory; - atLookup.atChops = mockAtChops; - final llookupCommand = 'llookup:phone@alice\n'; - final llookupResponse = 'data:1234'; - when(() => mockOutBoundConnection.write(llookupCommand)) - .thenAnswer((invocation) { - mockSecureSocket.write(llookupCommand); - return Future.value(); + test('validate behaviour with EnrollVerbHandler - approve', () async { + final atLookup = AtLookupImpl('@alice', atServerHost, 64, + secondaryAddressFinder: mockSecondaryAddressFinder); + atLookup.atChops = mockAtChops; + atLookup.atSocketFactory = mockAtConnectionFactory; + String appName = 'unit_test_2'; + String deviceName = 'test_device'; + String enrollmentId = '1357913579'; + + EnrollVerbBuilder enrollVerbBuilder = EnrollVerbBuilder() + ..operation = EnrollOperationEnum.approve + ..enrollmentId = '1357913579' + ..appName = appName + ..deviceName = deviceName; + String enrollCommand = + 'enroll:approve:{"enrollmentId":"$enrollmentId","appName":"$appName","deviceName":"$deviceName"}\n'; + final enrollResponse = + 'data:{"enrollmentId":"1357913579","status":"approved"}'; + + when(() => mockOutBoundConnection.write(enrollCommand)) + .thenAnswer((invocation) { + mockSecureSocket.write(enrollCommand); + return Future.value(); + }); + when(() => mockOutboundListener.read()) + .thenAnswer((_) => Future.value(enrollResponse)); + AtConnectionMetaData? atConnectionMetaData = + OutboundConnectionMetadata()..isAuthenticated = true; + when(() => mockOutBoundConnection.getMetaData()) + .thenReturn(atConnectionMetaData); + when(() => mockOutBoundConnection.isInValid()).thenReturn(false); + + expect(await atLookup.executeVerb(enrollVerbBuilder), enrollResponse); }); - when(() => mockOutboundListener.read()) - .thenAnswer((_) => Future.value(llookupResponse)); - var result = await atLookup.executeCommand(llookupCommand); - expect(result, llookupResponse); - }); - test('executeCommand - test non json error handling', () async { - final atLookup = AtLookupImpl('@alice', atServerHost, 64, - secondaryAddressFinder: mockSecondaryAddressFinder); - atLookup.atSocketFactory = mockAtConnectionFactory; - atLookup.atChops = mockAtChops; - final llookupCommand = 'llookup:phone@alice\n'; - final llookupResponse = 'error:AT0015-Exception: fubar'; - when(() => mockOutBoundConnection.write(llookupCommand)) - .thenAnswer((invocation) { - mockSecureSocket.write(llookupCommand); - return Future.value(); + test('validate behaviour with EnrollVerbHandler - revoke', () async { + final atLookup = AtLookupImpl('@alice', atServerHost, 64, + secondaryAddressFinder: mockSecondaryAddressFinder); + atLookup.atChops = mockAtChops; + atLookup.atSocketFactory = mockAtConnectionFactory; + String enrollmentId = '89213647826348'; + + EnrollVerbBuilder enrollVerbBuilder = EnrollVerbBuilder() + ..operation = EnrollOperationEnum.revoke + ..enrollmentId = enrollmentId; + String enrollCommand = + 'enroll:revoke:{"enrollmentId":"$enrollmentId"}\n'; + String enrollResponse = + 'data:{"enrollmentId":"$enrollmentId","status":"revoked"}'; + + when(() => mockOutBoundConnection.write(enrollCommand)) + .thenAnswer((invocation) { + mockSecureSocket.write(enrollCommand); + return Future.value(); + }); + when(() => mockOutboundListener.read()) + .thenAnswer((_) => Future.value(enrollResponse)); + AtConnectionMetaData? atConnectionMetaData = + OutboundConnectionMetadata()..isAuthenticated = true; + when(() => mockOutBoundConnection.getMetaData()) + .thenReturn(atConnectionMetaData); + when(() => mockOutBoundConnection.isInValid()).thenReturn(false); + + expect(await atLookup.executeVerb(enrollVerbBuilder), enrollResponse); }); - when(() => mockOutboundListener.read()) - .thenAnswer((_) => Future.value(llookupResponse)); - await expectLater( - atLookup.executeCommand(llookupCommand), - throwsA(predicate((e) => - e is AtLookUpException && e.errorMessage == 'Exception: fubar'))); - }); - test('executeCommand - test json error handling', () async { - final atLookup = AtLookupImpl('@alice', atServerHost, 64, - secondaryAddressFinder: mockSecondaryAddressFinder); - atLookup.atSocketFactory = mockAtConnectionFactory; - atLookup.atChops = mockAtChops; - final llookupCommand = 'llookup:phone@alice\n'; - final llookupResponse = - 'error:{"errorCode":"AT0015","errorDescription":"Exception: fubar"}'; - when(() => mockOutBoundConnection.write(llookupCommand)) - .thenAnswer((invocation) { - mockSecureSocket.write(llookupCommand); - return Future.value(); + test('validate behaviour with EnrollVerbHandler - deny', () async { + final atLookup = AtLookupImpl('@alice', atServerHost, 64, + secondaryAddressFinder: mockSecondaryAddressFinder); + atLookup.atSocketFactory = mockAtConnectionFactory; + atLookup.atChops = mockAtChops; + String enrollmentId = '5754765754'; + + EnrollVerbBuilder enrollVerbBuilder = EnrollVerbBuilder() + ..operation = EnrollOperationEnum.deny + ..enrollmentId = enrollmentId; + String enrollCommand = 'enroll:deny:{"enrollmentId":"$enrollmentId"}\n'; + String enrollResponse = + 'data:{"enrollmentId":"$enrollmentId","status":"denied"}'; + + when(() => mockOutBoundConnection.write(enrollCommand)) + .thenAnswer((invocation) { + mockSecureSocket.write(enrollCommand); + return Future.value(); + }); + when(() => mockOutboundListener.read()) + .thenAnswer((_) => Future.value(enrollResponse)); + AtConnectionMetaData? atConnectionMetaData = + OutboundConnectionMetadata()..isAuthenticated = true; + when(() => mockOutBoundConnection.getMetaData()) + .thenReturn(atConnectionMetaData); + when(() => mockOutBoundConnection.isInValid()).thenReturn(false); + + expect(await atLookup.executeVerb(enrollVerbBuilder), enrollResponse); }); - when(() => mockOutboundListener.read()) - .thenAnswer((_) => Future.value(llookupResponse)); - await expectLater( - atLookup.executeCommand(llookupCommand), - throwsA(predicate((e) => - e is AtLookUpException && e.errorMessage == 'Exception: fubar'))); }); }); - group('Validate executeVerb() behaviour', () { - test('validate EnrollVerbHandler behaviour - request', () async { - final atLookup = AtLookupImpl('@alice', atServerHost, 64, - secondaryAddressFinder: mockSecondaryAddressFinder); - atLookup.atSocketFactory = mockAtConnectionFactory; - String appName = 'unit_test_1'; - String deviceName = 'test_device'; - String otp = 'ABCDEF'; - - EnrollVerbBuilder enrollVerbBuilder = EnrollVerbBuilder() - ..operation = EnrollOperationEnum.request - ..appName = appName - ..deviceName = deviceName - ..otp = otp; - String enrollCommand = - 'enroll:request:{"appName":"$appName","deviceName":"$deviceName","otp":"$otp"}\n'; - final enrollResponse = - 'data:{"enrollmentId":"1234567890","status":"pending"}'; - - when(() => mockOutBoundConnection.write(enrollCommand)) - .thenAnswer((invocation) { - mockSecureSocket.write(enrollCommand); - return Future.value(); + group('A group of web socket tests', () { + setUp(() { + mockOutboundWebsocketConnection = MockOutboundWebsocketConnectionImpl(); + mockSecondaryAddressFinder = MockSecondaryAddressFinder(); + mockOutboundListener = MockOutboundMessageListener(); + mockAtConnectionFactory = MockAtLookupOutboundConnectionFactory(); + mockAtChops = MockAtChops(); + registerFallbackValue(SecureSocketConfig()); + mockWebSocket = createMockWebSocket(atServerHost, atServerPort); + + when(() => mockSecondaryAddressFinder.findSecondary('@alice')) + .thenAnswer((_) async { + return SecondaryAddress(atServerHost, atServerPort); }); - when(() => mockOutboundListener.read()) - .thenAnswer((_) => Future.value(enrollResponse)); - AtConnectionMetaData? atConnectionMetaData = OutboundConnectionMetadata() - ..isAuthenticated = false; - when(() => mockOutBoundConnection.getMetaData()) - .thenReturn(atConnectionMetaData); - when(() => mockOutBoundConnection.isInValid()).thenReturn(false); - - var result = await atLookup.executeVerb(enrollVerbBuilder); - expect(result, enrollResponse); + + when(() => mockAtConnectionFactory.createUnderlying( + atServerHost, '12345', any())).thenAnswer((_) { + return Future.value(mockWebSocket); + }); + + when(() => + mockAtConnectionFactory.outBoundConnectionFactory(mockWebSocket)) + .thenAnswer((_) => mockOutboundWebsocketConnection); + + when(() => mockOutboundWebsocketConnection.write(any())) + .thenAnswer((_) => Future.value()); + + when(() => mockAtConnectionFactory + .atLookupSocketListenerFactory(mockOutboundWebsocketConnection)) + .thenAnswer((_) => mockOutboundListener); }); - test('validate behaviour with EnrollVerbHandler - approve', () async { - final atLookup = AtLookupImpl('@alice', atServerHost, 64, - secondaryAddressFinder: mockSecondaryAddressFinder); - atLookup.atChops = mockAtChops; - atLookup.atSocketFactory = mockAtConnectionFactory; - String appName = 'unit_test_2'; - String deviceName = 'test_device'; - String enrollmentId = '1357913579'; - - EnrollVerbBuilder enrollVerbBuilder = EnrollVerbBuilder() - ..operation = EnrollOperationEnum.approve - ..enrollmentId = '1357913579' - ..appName = appName - ..deviceName = deviceName; - String enrollCommand = - 'enroll:approve:{"enrollmentId":"$enrollmentId","appName":"$appName","deviceName":"$deviceName"}\n'; - final enrollResponse = - 'data:{"enrollmentId":"1357913579","status":"approved"}'; - - when(() => mockOutBoundConnection.write(enrollCommand)) - .thenAnswer((invocation) { - mockSecureSocket.write(enrollCommand); - return Future.value(); + group('A group of tests to verify atlookup pkam authentication', () { + test('pkam auth using websocket without enrollmentId - auth success', + () async { + final pkamSignature = + 'MbNbIwCSxsHxm4CHyakSE2yLqjjtnmzpSLPcGG7h+4M/GQAiJkklQfd/x9z58CSJfuSW8baIms26SrnmuYePZURfp5oCqtwRpvt+l07Gnz8aYpXH0k5qBkSR34SBk4nb+hdAjsXXgfWWC56gROPMwpOEbuDS6esU7oku+a7Rdr10xrFlk1Tf2eRwPOMWyuKwOvLwSgyq/INAFRYav5RmLFiecQhPME6ssc1jW92wztylKBtuZT4rk8787b6Z9StxT4dPZzWjfV1+oYDLaqu2PcQS2ZthH+Wj8NgoogDxSP+R7BE1FOVJKnavpuQWeOqNWeUbKkSVP0B0DN6WopAdsg=='; + + AtSigningResult mockSigningResult = AtSigningResult() + ..result = 'mock_signing_result'; + registerFallbackValue(FakeAtSigningInput()); + when(() => mockAtChops.sign(any())) + .thenAnswer((_) => mockSigningResult); + + when(() => mockAtChops.sign(any())) + .thenReturn(AtSigningResult()..result = pkamSignature); + when(() => mockOutboundListener.read()) + .thenAnswer((_) => Future.value('data:success')); + + when(() => mockOutboundWebsocketConnection.getMetaData()) + .thenReturn(OutboundConnectionMetadata()..isAuthenticated = false); + when(() => mockOutboundWebsocketConnection.isInValid()) + .thenReturn(false); + + when(() => mockOutboundWebsocketConnection.write( + 'pkam:signingAlgo:rsa2048:hashingAlgo:sha256:$pkamSignature\n')) + .thenAnswer((invocation) { + mockWebSocket.add( + 'pkam:signingAlgo:rsa2048:hashingAlgo:sha256:$pkamSignature\n'); + return Future.value(); + }); + + final atLookup = AtLookupImpl('@alice', atServerHost, 64, + secondaryAddressFinder: mockSecondaryAddressFinder, + atSocketFactory: AtLookupWebSocketFactory()); + // Override atConnectionFactory with mock in AtLookupImpl + atLookup.atSocketFactory = mockAtConnectionFactory; + atLookup.atChops = mockAtChops; + var result = await atLookup.pkamAuthenticate(); + expect(result, true); + }, timeout: Timeout(Duration(minutes: 2))); + + test('pkam auth using a websocket without enrollmentId - auth failed', + () async { + final pkamSignature = + 'MbNbIwCSxsHxm4CHyakSE2yLqjjtnmzpSLPcGG7h+4M/GQAiJkklQfd/x9z58CSJfuSW8baIms26SrnmuYePZURfp5oCqtwRpvt+l07Gnz8aYpXH0k5qBkSR34SBk4nb+hdAjsXXgfWWC56gROPMwpOEbuDS6esU7oku+a7Rdr10xrFlk1Tf2eRwPOMWyuKwOvLwSgyq/INAFRYav5RmLFiecQhPME6ssc1jW92wztylKBtuZT4rk8787b6Z9StxT4dPZzWjfV1+oYDLaqu2PcQS2ZthH+Wj8NgoogDxSP+R7BE1FOVJKnavpuQWeOqNWeUbKkSVP0B0DN6WopAdsg=='; + + AtSigningResult mockSigningResult = AtSigningResult() + ..result = 'mock_signing_result'; + registerFallbackValue(FakeAtSigningInput()); + when(() => mockAtChops.sign(any())) + .thenAnswer((_) => mockSigningResult); + + when(() => mockAtChops.sign(any())) + .thenReturn(AtSigningResult()..result = pkamSignature); + when(() => mockOutboundListener.read()).thenAnswer((_) => + Future.value('error:AT0401-Exception: pkam authentication failed')); + + when(() => mockOutboundWebsocketConnection.getMetaData()) + .thenReturn(OutboundConnectionMetadata()..isAuthenticated = false); + when(() => mockOutboundWebsocketConnection.isInValid()) + .thenReturn(false); + + when(() => mockOutboundWebsocketConnection.write( + 'pkam:signingAlgo:rsa2048:hashingAlgo:sha256:$pkamSignature\n')) + .thenAnswer((invocation) { + mockWebSocket.add( + 'pkam:signingAlgo:rsa2048:hashingAlgo:sha256:$pkamSignature\n'); + return Future.value(); + }); + + final atLookup = AtLookupImpl('@alice', atServerHost, 64, + secondaryAddressFinder: mockSecondaryAddressFinder, + atSocketFactory: AtLookupWebSocketFactory()); + // Override atConnectionFactory with mock in AtLookupImpl + atLookup.atSocketFactory = mockAtConnectionFactory; + atLookup.atChops = mockAtChops; + expect(() async => await atLookup.pkamAuthenticate(), + throwsA(predicate((e) => e is UnAuthenticatedException))); + }); + + test('pkam auth using a websocket with enrollmentId - auth success', + () async { + final pkamSignature = + 'MbNbIwCSxsHxm4CHyakSE2yLqjjtnmzpSLPcGG7h+4M/GQAiJkklQfd/x9z58CSJfuSW8baIms26SrnmuYePZURfp5oCqtwRpvt+l07Gnz8aYpXH0k5qBkSR34SBk4nb+hdAjsXXgfWWC56gROPMwpOEbuDS6esU7oku+a7Rdr10xrFlk1Tf2eRwPOMWyuKwOvLwSgyq/INAFRYav5RmLFiecQhPME6ssc1jW92wztylKBtuZT4rk8787b6Z9StxT4dPZzWjfV1+oYDLaqu2PcQS2ZthH+Wj8NgoogDxSP+R7BE1FOVJKnavpuQWeOqNWeUbKkSVP0B0DN6WopAdsg=='; + final enrollmentIdFromServer = '5a21feb4-dc04-4603-829c-15f523789170'; + AtSigningResult mockSigningResult = AtSigningResult() + ..result = 'mock_signing_result'; + registerFallbackValue(FakeAtSigningInput()); + when(() => mockAtChops.sign(any())) + .thenAnswer((_) => mockSigningResult); + + when(() => mockAtChops.sign(any())) + .thenReturn(AtSigningResult()..result = pkamSignature); + when(() => mockOutboundListener.read()) + .thenAnswer((_) => Future.value('data:success')); + + when(() => mockOutboundWebsocketConnection.getMetaData()) + .thenReturn(OutboundConnectionMetadata()..isAuthenticated = false); + when(() => mockOutboundWebsocketConnection.isInValid()) + .thenReturn(false); + + when(() => mockOutboundWebsocketConnection.write( + 'pkam:signingAlgo:rsa2048:hashingAlgo:sha256:enrollmentId:$enrollmentIdFromServer:$pkamSignature\n')) + .thenAnswer((invocation) { + mockWebSocket.add( + 'pkam:signingAlgo:rsa2048:hashingAlgo:sha256:enrollmentId:$enrollmentIdFromServer:$pkamSignature\n'); + return Future.value(); + }); + + final atLookup = AtLookupImpl('@alice', atServerHost, 64, + secondaryAddressFinder: mockSecondaryAddressFinder, + atSocketFactory: AtLookupWebSocketFactory()); + atLookup.atSocketFactory = mockAtConnectionFactory; + atLookup.atChops = mockAtChops; + var result = await atLookup.pkamAuthenticate( + enrollmentId: enrollmentIdFromServer); + expect(result, true); }); - when(() => mockOutboundListener.read()) - .thenAnswer((_) => Future.value(enrollResponse)); - AtConnectionMetaData? atConnectionMetaData = OutboundConnectionMetadata() - ..isAuthenticated = true; - when(() => mockOutBoundConnection.getMetaData()) - .thenReturn(atConnectionMetaData); - when(() => mockOutBoundConnection.isInValid()).thenReturn(false); - - expect(await atLookup.executeVerb(enrollVerbBuilder), enrollResponse); }); - test('validate behaviour with EnrollVerbHandler - revoke', () async { - final atLookup = AtLookupImpl('@alice', atServerHost, 64, - secondaryAddressFinder: mockSecondaryAddressFinder); - atLookup.atChops = mockAtChops; - atLookup.atSocketFactory = mockAtConnectionFactory; - String enrollmentId = '89213647826348'; - - EnrollVerbBuilder enrollVerbBuilder = EnrollVerbBuilder() - ..operation = EnrollOperationEnum.revoke - ..enrollmentId = enrollmentId; - String enrollCommand = 'enroll:revoke:{"enrollmentId":"$enrollmentId"}\n'; - String enrollResponse = - 'data:{"enrollmentId":"$enrollmentId","status":"revoked"}'; - - when(() => mockOutBoundConnection.write(enrollCommand)) - .thenAnswer((invocation) { - mockSecureSocket.write(enrollCommand); - return Future.value(); + group('A group of tests to verify executeCommand method', () { + test('executeCommand using websocket- from verb - auth false', () async { + final atLookup = AtLookupImpl('@alice', atServerHost, 64, + secondaryAddressFinder: mockSecondaryAddressFinder, + atSocketFactory: AtLookupWebSocketFactory()); + atLookup.atSocketFactory = mockAtConnectionFactory; + final fromResponse = + 'data:_03fe0ff2-ac50-4c80-8f43-88480beba888@alice:c3d345fc-5691-4f90-bc34-17cba31f060f'; + when(() => mockOutboundListener.read()) + .thenAnswer((_) => Future.value(fromResponse)); + var result = await atLookup.executeCommand('from:@alice\n'); + expect(result, fromResponse); + }, timeout: Timeout(Duration(minutes: 5))); + + test( + 'executeCommand using websocket-llookup verb - auth true - auth key not set', + () async { + final atLookup = AtLookupImpl('@alice', atServerHost, 64, + secondaryAddressFinder: mockSecondaryAddressFinder, + atSocketFactory: AtLookupWebSocketFactory()); + final fromResponse = 'data:1234'; + when(() => mockOutboundListener.read()) + .thenAnswer((_) => Future.value(fromResponse)); + expect( + () async => await atLookup.executeCommand('llookup:phone@alice\n', + auth: true), + throwsA(predicate((e) => e is UnAuthenticatedException))); }); - when(() => mockOutboundListener.read()) - .thenAnswer((_) => Future.value(enrollResponse)); - AtConnectionMetaData? atConnectionMetaData = OutboundConnectionMetadata() - ..isAuthenticated = true; - when(() => mockOutBoundConnection.getMetaData()) - .thenReturn(atConnectionMetaData); - when(() => mockOutBoundConnection.isInValid()).thenReturn(false); - - expect(await atLookup.executeVerb(enrollVerbBuilder), enrollResponse); }); - test('validate behaviour with EnrollVerbHandler - deny', () async { - final atLookup = AtLookupImpl('@alice', atServerHost, 64, - secondaryAddressFinder: mockSecondaryAddressFinder); - atLookup.atSocketFactory = mockAtConnectionFactory; - atLookup.atChops = mockAtChops; - String enrollmentId = '5754765754'; - - EnrollVerbBuilder enrollVerbBuilder = EnrollVerbBuilder() - ..operation = EnrollOperationEnum.deny - ..enrollmentId = enrollmentId; - String enrollCommand = 'enroll:deny:{"enrollmentId":"$enrollmentId"}\n'; - String enrollResponse = - 'data:{"enrollmentId":"$enrollmentId","status":"denied"}'; - - when(() => mockOutBoundConnection.write(enrollCommand)) - .thenAnswer((invocation) { - mockSecureSocket.write(enrollCommand); - return Future.value(); + group('Validate executeVerb() behaviour', () { + test( + 'validate EnrollVerbHandler behaviour using a websocket connection- request', + () async { + final atLookup = AtLookupImpl('@alice', atServerHost, 64, + secondaryAddressFinder: mockSecondaryAddressFinder, + atSocketFactory: AtLookupWebSocketFactory()); + atLookup.atSocketFactory = mockAtConnectionFactory; + String appName = 'unit_test_1'; + String deviceName = 'test_device'; + String otp = 'ABCDEF'; + + EnrollVerbBuilder enrollVerbBuilder = EnrollVerbBuilder() + ..operation = EnrollOperationEnum.request + ..appName = appName + ..deviceName = deviceName + ..otp = otp; + String enrollCommand = + 'enroll:request:{"appName":"$appName","deviceName":"$deviceName","otp":"$otp"}\n'; + final enrollResponse = + 'data:{"enrollmentId":"1234567890","status":"pending"}'; + + when(() => mockOutboundWebsocketConnection.write(enrollCommand)) + .thenAnswer((invocation) { + mockWebSocket.add(enrollCommand); + return Future.value(); + }); + when(() => mockOutboundListener.read()) + .thenAnswer((_) => Future.value(enrollResponse)); + AtConnectionMetaData? atConnectionMetaData = + OutboundConnectionMetadata()..isAuthenticated = false; + when(() => mockOutboundWebsocketConnection.getMetaData()) + .thenReturn(atConnectionMetaData); + when(() => mockOutboundWebsocketConnection.isInValid()) + .thenReturn(false); + + var result = await atLookup.executeVerb(enrollVerbBuilder); + expect(result, enrollResponse); + }); + + test( + 'validate behaviour with EnrollVerbHandler using a websocket connection- approve', + () async { + final atLookup = AtLookupImpl('@alice', atServerHost, 64, + secondaryAddressFinder: mockSecondaryAddressFinder, + atSocketFactory: AtLookupWebSocketFactory()); + atLookup.atChops = mockAtChops; + atLookup.atSocketFactory = mockAtConnectionFactory; + String appName = 'unit_test_2'; + String deviceName = 'test_device'; + String enrollmentId = '1357913579'; + + EnrollVerbBuilder enrollVerbBuilder = EnrollVerbBuilder() + ..operation = EnrollOperationEnum.approve + ..enrollmentId = '1357913579' + ..appName = appName + ..deviceName = deviceName; + String enrollCommand = + 'enroll:approve:{"enrollmentId":"$enrollmentId","appName":"$appName","deviceName":"$deviceName"}\n'; + final enrollResponse = + 'data:{"enrollmentId":"1357913579","status":"approved"}'; + + when(() => mockOutboundWebsocketConnection.write(enrollCommand)) + .thenAnswer((invocation) { + mockWebSocket.add(enrollCommand); + return Future.value(); + }); + when(() => mockOutboundListener.read()) + .thenAnswer((_) => Future.value(enrollResponse)); + AtConnectionMetaData? atConnectionMetaData = + OutboundConnectionMetadata()..isAuthenticated = true; + when(() => mockOutboundWebsocketConnection.getMetaData()) + .thenReturn(atConnectionMetaData); + when(() => mockOutboundWebsocketConnection.isInValid()) + .thenReturn(false); + + expect(await atLookup.executeVerb(enrollVerbBuilder), enrollResponse); + }); + + test( + 'validate behaviour with EnrollVerbHandler using a websocket connection - revoke', + () async { + final atLookup = AtLookupImpl('@alice', atServerHost, 64, + secondaryAddressFinder: mockSecondaryAddressFinder, + atSocketFactory: AtLookupWebSocketFactory()); + atLookup.atChops = mockAtChops; + atLookup.atSocketFactory = mockAtConnectionFactory; + String enrollmentId = '89213647826348'; + + EnrollVerbBuilder enrollVerbBuilder = EnrollVerbBuilder() + ..operation = EnrollOperationEnum.revoke + ..enrollmentId = enrollmentId; + String enrollCommand = + 'enroll:revoke:{"enrollmentId":"$enrollmentId"}\n'; + String enrollResponse = + 'data:{"enrollmentId":"$enrollmentId","status":"revoked"}'; + + when(() => mockOutboundWebsocketConnection.write(enrollCommand)) + .thenAnswer((invocation) { + mockWebSocket.add(enrollCommand); + return Future.value(); + }); + when(() => mockOutboundListener.read()) + .thenAnswer((_) => Future.value(enrollResponse)); + AtConnectionMetaData? atConnectionMetaData = + OutboundConnectionMetadata()..isAuthenticated = true; + when(() => mockOutboundWebsocketConnection.getMetaData()) + .thenReturn(atConnectionMetaData); + when(() => mockOutboundWebsocketConnection.isInValid()) + .thenReturn(false); + + expect(await atLookup.executeVerb(enrollVerbBuilder), enrollResponse); + }); + + test( + 'validate behaviour with EnrollVerbHandler using a websocket connection - deny', + () async { + final atLookup = AtLookupImpl('@alice', atServerHost, 64, + secondaryAddressFinder: mockSecondaryAddressFinder, + atSocketFactory: AtLookupWebSocketFactory()); + atLookup.atSocketFactory = mockAtConnectionFactory; + atLookup.atChops = mockAtChops; + String enrollmentId = '5754765754'; + + EnrollVerbBuilder enrollVerbBuilder = EnrollVerbBuilder() + ..operation = EnrollOperationEnum.deny + ..enrollmentId = enrollmentId; + String enrollCommand = 'enroll:deny:{"enrollmentId":"$enrollmentId"}\n'; + String enrollResponse = + 'data:{"enrollmentId":"$enrollmentId","status":"denied"}'; + + when(() => mockOutboundWebsocketConnection.write(enrollCommand)) + .thenAnswer((invocation) { + mockWebSocket.add(enrollCommand); + return Future.value(); + }); + when(() => mockOutboundListener.read()) + .thenAnswer((_) => Future.value(enrollResponse)); + AtConnectionMetaData? atConnectionMetaData = + OutboundConnectionMetadata()..isAuthenticated = true; + when(() => mockOutboundWebsocketConnection.getMetaData()) + .thenReturn(atConnectionMetaData); + when(() => mockOutboundWebsocketConnection.isInValid()) + .thenReturn(false); + + expect(await atLookup.executeVerb(enrollVerbBuilder), enrollResponse); }); - when(() => mockOutboundListener.read()) - .thenAnswer((_) => Future.value(enrollResponse)); - AtConnectionMetaData? atConnectionMetaData = OutboundConnectionMetadata() - ..isAuthenticated = true; - when(() => mockOutBoundConnection.getMetaData()) - .thenReturn(atConnectionMetaData); - when(() => mockOutBoundConnection.isInValid()).thenReturn(false); - - expect(await atLookup.executeVerb(enrollVerbBuilder), enrollResponse); }); }); } diff --git a/packages/at_lookup/test/at_lookup_test_utils.dart b/packages/at_lookup/test/at_lookup_test_utils.dart index 3ed78fcd..c9a4b648 100644 --- a/packages/at_lookup/test/at_lookup_test_utils.dart +++ b/packages/at_lookup/test/at_lookup_test_utils.dart @@ -23,6 +23,11 @@ class MockSecureSocket extends Mock implements SecureSocket { int mockNumber = mockSocketNumber++; } +class MockWebSocket extends Mock implements WebSocket { + bool destroyed = false; + int mockNumber = mockSocketNumber++; +} + class MockOutboundMessageListener extends Mock implements OutboundMessageListener {} @@ -31,6 +36,9 @@ class MockAtChops extends Mock implements AtChopsImpl {} class MockOutboundConnectionImpl extends Mock implements OutboundConnectionImpl {} +class MockOutboundWebsocketConnectionImpl extends Mock + implements OutboundWebsocketConnectionImpl {} + SecureSocket createMockAtServerSocket(String address, int port) { SecureSocket mss = MockSecureSocket(); when(() => mss.destroy()).thenAnswer((invocation) { @@ -44,3 +52,17 @@ SecureSocket createMockAtServerSocket(String address, int port) { onDone: any(named: "onDone"))).thenReturn(MockStreamSubscription()); return mss; } + +WebSocket createMockWebSocket(String address, int port) { + var mockWebSocket = MockWebSocket(); + when(() => mockWebSocket.close(any(), any())).thenAnswer((_) async { + (mockWebSocket).destroyed = true; + }); + when(() => mockWebSocket.add(any())).thenReturn(null); + when(() => mockWebSocket.listen(any(), + onError: any(named: "onError"), + onDone: any(named: "onDone"), + cancelOnError: any(named: "cancelOnError"))) + .thenReturn(MockStreamSubscription()); + return mockWebSocket; +} diff --git a/tests/at_onboarding_cli_functional_tests/test/at_lookup_test.dart b/tests/at_onboarding_cli_functional_tests/test/at_lookup_test.dart index 4991997f..26ff2266 100644 --- a/tests/at_onboarding_cli_functional_tests/test/at_lookup_test.dart +++ b/tests/at_onboarding_cli_functional_tests/test/at_lookup_test.dart @@ -15,7 +15,7 @@ void main() { 'A test to verify a websocket connection and do a cram authenticate and scan', () async { var atLookup = - AtLookupImpl(atSign, 'vip.ve.atsign.zone', 64, useWebSocket: true); + AtLookupImpl(atSign, 'vip.ve.atsign.zone', 64, atSocketFactory: AtLookupWebSocketFactory()); await atLookup.cramAuthenticate(at_demos.cramKeyMap[atSign]!); var command = 'scan\n'; var response = await atLookup.executeCommand(command, auth: true); @@ -26,7 +26,7 @@ void main() { 'A test to verify a socket connection by passing useWebSocket to false and do a cram authenticate and scan', () async { var atLookup = - AtLookupImpl(atSign, 'vip.ve.atsign.zone', 64, useWebSocket: true); + AtLookupImpl(atSign, 'vip.ve.atsign.zone', 64, atSocketFactory: AtLookupWebSocketFactory()); await atLookup.cramAuthenticate(at_demos.cramKeyMap[atSign]!); var command = 'scan\n'; var response = await atLookup.executeCommand(command, auth: true); @@ -37,7 +37,7 @@ void main() { 'A test to verify a websocket connection and do a cram authenticate and update', () async { var atLookup = - AtLookupImpl(atSign, 'vip.ve.atsign.zone', 64, useWebSocket: true); + AtLookupImpl(atSign, 'vip.ve.atsign.zone', 64, atSocketFactory: AtLookupWebSocketFactory()); await atLookup.cramAuthenticate(at_demos.cramKeyMap[atSign]!); // update public and private keys manually var command = @@ -56,7 +56,7 @@ void main() { 'A test to verify a websocket connection and do a pkam authenticate and executeCommand', () async { var atLookup = - AtLookupImpl(atSign, 'vip.ve.atsign.zone', 64, useWebSocket: true); + AtLookupImpl(atSign, 'vip.ve.atsign.zone', 64, atSocketFactory: AtLookupWebSocketFactory()); atLookup.atChops = atChopsKeys; await atLookup.pkamAuthenticate(); var command = 'update:public:username$atSign bob123\n'; @@ -69,7 +69,7 @@ void main() { 'A test to verify a websocket connection and do a pkam authenticate and execute verb', () async { var atLookup = - AtLookupImpl(atSign, 'vip.ve.atsign.zone', 64, useWebSocket: true); + AtLookupImpl(atSign, 'vip.ve.atsign.zone', 64, atSocketFactory: AtLookupWebSocketFactory()); atLookup.atChops = atChopsKeys; await atLookup.pkamAuthenticate(); var atKey = 'key1';