basic nostr actors
This commit is contained in:
parent
c14de9c3e9
commit
f1e54f2722
13 changed files with 1081 additions and 2 deletions
150
test/nostr_publish_actor_test.dart
Normal file
150
test/nostr_publish_actor_test.dart
Normal file
|
|
@ -0,0 +1,150 @@
|
|||
import 'dart:convert';
|
||||
import 'package:swarm/swarm.dart';
|
||||
import 'package:test/test.dart';
|
||||
import 'fake_relay_connection.dart';
|
||||
|
||||
const _event = '{'
|
||||
'"id":"abc123",'
|
||||
'"pubkey":"pub",'
|
||||
'"created_at":1,'
|
||||
'"kind":1,'
|
||||
'"tags":[],'
|
||||
'"content":"hi",'
|
||||
'"sig":"sig"'
|
||||
'}';
|
||||
|
||||
void main() {
|
||||
group('NostrPublishActor', () {
|
||||
tearDown(() async {});
|
||||
|
||||
test('sends correct EVENT format', () async {
|
||||
final fake = FakeRelayConnection();
|
||||
addTearDown(fake.dispose);
|
||||
|
||||
final actor = NostrPublishActor(
|
||||
relayUrls: ['ws://relay1'],
|
||||
retryConfig: const RetryConfig(maxAttempts: 1),
|
||||
connectionFactory: (_) => fake,
|
||||
);
|
||||
|
||||
await actor.handle(const PublishBatch([_event]));
|
||||
|
||||
final eventMsgs = fake.sentMessages
|
||||
.where((m) => (jsonDecode(m) as List)[0] == 'EVENT')
|
||||
.toList();
|
||||
expect(eventMsgs, hasLength(1));
|
||||
final decoded = jsonDecode(eventMsgs[0]) as List;
|
||||
expect(decoded[0], equals('EVENT'));
|
||||
expect(decoded[1], isA<Map>());
|
||||
expect((decoded[1] as Map)['id'], equals('abc123'));
|
||||
});
|
||||
|
||||
test('returns RelayConfirmed on success', () async {
|
||||
final fake = FakeRelayConnection();
|
||||
addTearDown(fake.dispose);
|
||||
|
||||
final actor = NostrPublishActor(
|
||||
relayUrls: ['ws://relay1'],
|
||||
retryConfig: const RetryConfig(maxAttempts: 1),
|
||||
connectionFactory: (_) => fake,
|
||||
);
|
||||
|
||||
final result = await actor.handle(const PublishBatch([_event]));
|
||||
|
||||
expect(result, isA<BatchPublished>());
|
||||
final outcomes = (result as BatchPublished).outcomes;
|
||||
expect(outcomes['ws://relay1'], isA<RelayConfirmed>());
|
||||
});
|
||||
|
||||
test('returns RelayRejected with no retry', () async {
|
||||
final fake = FakeRelayConnection()..autoRespond = false;
|
||||
addTearDown(fake.dispose);
|
||||
fake.queuedResponses.add(jsonEncode(['OK', 'abc123', false, 'spam']));
|
||||
|
||||
final actor = NostrPublishActor(
|
||||
relayUrls: ['ws://relay1'],
|
||||
retryConfig: const RetryConfig(maxAttempts: 1),
|
||||
connectionFactory: (_) => fake,
|
||||
);
|
||||
|
||||
final result = await actor.handle(const PublishBatch([_event]));
|
||||
|
||||
expect(result, isA<BatchPublished>());
|
||||
final outcomes = (result as BatchPublished).outcomes;
|
||||
expect(outcomes['ws://relay1'], isA<RelayRejected>());
|
||||
expect((outcomes['ws://relay1'] as RelayRejected).reason, equals('spam'));
|
||||
|
||||
final eventMsgs = fake.sentMessages
|
||||
.where((m) => (jsonDecode(m) as List)[0] == 'EVENT')
|
||||
.toList();
|
||||
expect(eventMsgs, hasLength(1));
|
||||
});
|
||||
|
||||
test('returns RelayFailed on timeout and retries', () async {
|
||||
final fake = FakeRelayConnection()..autoRespond = false;
|
||||
addTearDown(fake.dispose);
|
||||
|
||||
final actor = NostrPublishActor(
|
||||
relayUrls: ['ws://relay1'],
|
||||
retryConfig: const RetryConfig(
|
||||
maxAttempts: 2,
|
||||
baseDelay: Duration(milliseconds: 1),
|
||||
jitter: false,
|
||||
),
|
||||
batchTimeout: const Duration(milliseconds: 50),
|
||||
connectionFactory: (_) => fake,
|
||||
);
|
||||
|
||||
final result = await actor.handle(const PublishBatch([_event]));
|
||||
|
||||
expect(result, isA<BatchPublished>());
|
||||
final outcomes = (result as BatchPublished).outcomes;
|
||||
expect(outcomes['ws://relay1'], isA<RelayFailed>());
|
||||
|
||||
final eventMsgs = fake.sentMessages
|
||||
.where((m) => (jsonDecode(m) as List)[0] == 'EVENT')
|
||||
.toList();
|
||||
expect(eventMsgs, hasLength(2));
|
||||
});
|
||||
|
||||
test('returns RelayFailed on connection error', () async {
|
||||
final fake = FakeRelayConnection()..throwOnConnect = true;
|
||||
addTearDown(fake.dispose);
|
||||
|
||||
final actor = NostrPublishActor(
|
||||
relayUrls: ['ws://relay1'],
|
||||
retryConfig: const RetryConfig(maxAttempts: 1),
|
||||
connectionFactory: (_) => fake,
|
||||
);
|
||||
|
||||
final result = await actor.handle(const PublishBatch([_event]));
|
||||
|
||||
expect(result, isA<BatchPublished>());
|
||||
final outcomes = (result as BatchPublished).outcomes;
|
||||
expect(outcomes['ws://relay1'], isA<RelayFailed>());
|
||||
});
|
||||
|
||||
test('fans out to multiple relays', () async {
|
||||
final fake1 = FakeRelayConnection();
|
||||
final fake2 = FakeRelayConnection();
|
||||
addTearDown(fake1.dispose);
|
||||
addTearDown(fake2.dispose);
|
||||
|
||||
final fakes = {'ws://relay1': fake1, 'ws://relay2': fake2};
|
||||
|
||||
final actor = NostrPublishActor(
|
||||
relayUrls: ['ws://relay1', 'ws://relay2'],
|
||||
retryConfig: const RetryConfig(maxAttempts: 1),
|
||||
connectionFactory: (url) => fakes[url]!,
|
||||
);
|
||||
|
||||
final result = await actor.handle(const PublishBatch([_event]));
|
||||
|
||||
expect(result, isA<BatchPublished>());
|
||||
final outcomes = (result as BatchPublished).outcomes;
|
||||
expect(outcomes.keys, containsAll(['ws://relay1', 'ws://relay2']));
|
||||
expect(outcomes['ws://relay1'], isA<RelayConfirmed>());
|
||||
expect(outcomes['ws://relay2'], isA<RelayConfirmed>());
|
||||
});
|
||||
});
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue