Skip to content

Commit

Permalink
Merge pull request #1263 from atsign-foundation/add_unit_tests
Browse files Browse the repository at this point in the history
fix: Add unit test related to sshnpd
  • Loading branch information
sitaram-kalluri authored Aug 19, 2024
2 parents bf6591e + 9dd1928 commit 5eaaaff
Show file tree
Hide file tree
Showing 2 changed files with 123 additions and 25 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import 'dart:async';

import 'package:at_client/at_client.dart';
import 'package:dartssh2/dartssh2.dart';
import 'package:meta/meta.dart';
import 'package:noports_core/src/sshnp/impl/notification_request_message.dart';
import 'package:noports_core/sshnp_foundation.dart';

Expand Down Expand Up @@ -64,31 +65,7 @@ class SshnpDartPureImpl extends SshnpCore
sendProgress(msg);

/// Send an ssh request to sshnpd
await notify(
AtKey()
..key = 'ssh_request'
..namespace = namespace
..sharedBy = params.clientAtSign
..sharedWith = params.sshnpdAtSign
..metadata = (Metadata()..ttl = 10000),
signAndWrapAndJsonEncode(
atClient,
SshnpSessionRequest(
direct: true,
sessionId: sessionId,
host: srvdChannel.rvdHost,
port: srvdChannel.daemonPort,
authenticateToRvd: params.authenticateDeviceToRvd,
clientNonce: srvdChannel.clientNonce,
rvdNonce: srvdChannel.rvdNonce,
encryptRvdTraffic: params.encryptRvdTraffic,
clientEphemeralPK: params.sessionKP.atPublicKey.publicKey,
clientEphemeralPKType: params.sessionKPType.name,
).toJson()),
checkForFinalDeliveryStatus: false,
waitForFinalDeliveryStatus: false,
ttln: Duration(minutes: 1),
);
await sendSshRequestToSshnpd();

/// Wait for a response from sshnpd
sendProgress('Waiting for response from the device daemon');
Expand Down Expand Up @@ -162,6 +139,35 @@ class SshnpDartPureImpl extends SshnpCore
);
}

@visibleForTesting
Future<void> sendSshRequestToSshnpd() async {
await notify(
AtKey()
..key = 'ssh_request'
..namespace = namespace
..sharedBy = params.clientAtSign
..sharedWith = params.sshnpdAtSign
..metadata = (Metadata()..ttl = 10000),
signAndWrapAndJsonEncode(
atClient,
SshnpSessionRequest(
direct: true,
sessionId: sessionId,
host: srvdChannel.rvdHost,
port: srvdChannel.daemonPort,
authenticateToRvd: params.authenticateDeviceToRvd,
clientNonce: srvdChannel.clientNonce,
rvdNonce: srvdChannel.rvdNonce,
encryptRvdTraffic: params.encryptRvdTraffic,
clientEphemeralPK: params.sessionKP.atPublicKey.publicKey,
clientEphemeralPKType: params.sessionKPType.name,
).toJson()),
checkForFinalDeliveryStatus: false,
waitForFinalDeliveryStatus: false,
ttln: Duration(minutes: 1),
);
}

@override
bool get canRunShell => true;

Expand Down
92 changes: 92 additions & 0 deletions packages/dart/noports_core/test/sshnp/sshnp_core_test.dart
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
import 'dart:async';
import 'dart:convert';

import 'package:at_chops/at_chops.dart';
import 'package:at_client/at_client.dart';
import 'package:at_commons/at_builders.dart';
import 'package:at_utils/at_logger.dart';
import 'package:logging/logging.dart';
import 'package:mocktail/mocktail.dart';
import 'package:noports_core/src/common/features.dart';
import 'package:noports_core/srvd.dart';
import 'package:noports_core/sshnp_foundation.dart';
import 'package:test/test.dart';

Expand Down Expand Up @@ -304,6 +307,95 @@ void main() {
expect(sshnpDeviceList.activeDevices, ['active']);
expect(sshnpDeviceList.inactiveDevices, ['inactive']);
});

test('A test to verify notifying ssh request to sshnpd', () async {
registerFallbackValue(FakeNotificationParams());
AtEncryptionKeyPair atEncryptionKeyPair =
AtChopsUtil.generateAtEncryptionKeyPair();

MockAtClient mockAtClient = MockAtClient();
MockNotificationService mockNotificationService =
MockNotificationService();

when(() => mockAtClient.atChops).thenAnswer(
(_) => AtChopsImpl(AtChopsKeys.create(atEncryptionKeyPair, null)));

when(() => mockAtClient.notificationService)
.thenAnswer((_) => mockNotificationService);

when(() =>
mockNotificationService.notify(any(),
checkForFinalDeliveryStatus:
any(named: 'checkForFinalDeliveryStatus'),
waitForFinalDeliveryStatus:
any(named: 'waitForFinalDeliveryStatus'),
onSuccess: any(named: 'onSuccess'),
onError: any(named: 'onError'),
onSentToSecondary: any(named: 'onSentToSecondary')))
.thenAnswer(expectAsync1((Invocation invocation) async {
// Assert when the notification response belongs to "ssh_request"
if (invocation.positionalArguments[0].atKey.key
.contains('ssh_request')) {
expect(invocation.positionalArguments[0].atKey.toString(),
'@alice_device:ssh_request.default.sshnp@alice');
print(invocation.positionalArguments[0].value);
Map sshRequestResponse =
jsonDecode(invocation.positionalArguments[0].value);
expect(sshRequestResponse['payload']['direct'], true);
expect(
sshRequestResponse['payload']['sessionId'].toString().isNotEmpty,
true);
expect(sshRequestResponse['payload']['host'], '127.0.0.1');
expect(sshRequestResponse['payload']['port'], 98879);
expect(sshRequestResponse['payload']['authenticateToRvd'], true);
expect(sshRequestResponse['payload']['rvdNonce'], 'rvd_dummy_nonce');
expect(sshRequestResponse['payload']['encryptRvdTraffic'], true);
expect(sshRequestResponse['payload']['clientEphemeralPK'].isNotEmpty,
true);
expect(sshRequestResponse['signature'].isNotEmpty, true);
expect(sshRequestResponse['hashingAlgo'].isNotEmpty, true);
expect(sshRequestResponse['signingAlgo'].isNotEmpty, true);
}

return Future.value(NotificationResult()
..notificationStatusEnum = NotificationStatusEnum.delivered);
}, count: 2));

// Create a stream controller to simulate the notification received from the srvd
// which contains the host and port numbers.
final streamController = StreamController<AtNotification>();
streamController.add(AtNotification(
'123',
'local.request_ports.${Srvd.namespace}',
'@alice',
'@bob',
123,
'key',
true)
..value = '127.0.0.1,98878,98879,rvd_dummy_nonce');
when(() => mockNotificationService.subscribe(
regex: any(named: 'regex'),
shouldDecrypt: any(named: 'shouldDecrypt')))
.thenAnswer((_) => streamController.stream);

SshnpParams sshnpParams = SshnpParams(
clientAtSign: '@alice',
sshnpdAtSign: '@alice_device',
srvdAtSign: '@srvd');
AtSshKeyPair atSshKeyPair =
await DartSshKeyUtil().generateKeyPair(identifier: 'my-test');
StreamController<String> testStreamController = StreamController();
SshnpDartPureImpl sshnp = SshnpDartPureImpl(
atClient: mockAtClient,
params: sshnpParams,
identityKeyPair: atSshKeyPair,
logStream: testStreamController.stream);

// Initialize srvd, to fetch the host and port from the srvd -
// Here returning a mocked response from a stream controller.
await sshnp.srvdChannel.initialize();
await sshnp.sendSshRequestToSshnpd();
});
});
}

Expand Down

0 comments on commit 5eaaaff

Please sign in to comment.