Build Reactive Signals for Bluesky's AT Protocol Firehose in Laravel
1<?php
2
3namespace SocialDept\AtpSignals\Tests\Unit;
4
5use Orchestra\Testbench\TestCase;
6use SocialDept\AtpSignals\Events\CommitEvent;
7use SocialDept\AtpSignals\Events\SignalEvent;
8use SocialDept\AtpSignals\Signals\Signal;
9
10class SignalTest extends TestCase
11{
12 /** @test */
13 public function it_can_create_a_signal()
14 {
15 $signal = new class () extends Signal {
16 public function eventTypes(): array
17 {
18 return ['commit'];
19 }
20
21 public function handle(SignalEvent $event): void
22 {
23 //
24 }
25 };
26
27 $this->assertInstanceOf(Signal::class, $signal);
28 $this->assertEquals(['commit'], $signal->eventTypes());
29 }
30
31 /** @test */
32 public function it_can_filter_by_exact_collection()
33 {
34 $signal = new class () extends Signal {
35 public function eventTypes(): array
36 {
37 return ['commit'];
38 }
39
40 public function collections(): ?array
41 {
42 return ['app.bsky.feed.post'];
43 }
44
45 public function handle(SignalEvent $event): void
46 {
47 //
48 }
49 };
50
51 $event = new SignalEvent(
52 did: 'did:plc:test',
53 timeUs: time() * 1000000,
54 kind: 'commit',
55 commit: new CommitEvent(
56 rev: 'test',
57 operation: 'create',
58 collection: 'app.bsky.feed.post',
59 rkey: 'test',
60 ),
61 );
62
63 $this->assertTrue($signal->shouldHandle($event));
64 }
65
66 /** @test */
67 public function it_can_filter_by_wildcard_collection()
68 {
69 $signalClass = new class () extends Signal {
70 public function eventTypes(): array
71 {
72 return ['commit'];
73 }
74
75 public function collections(): ?array
76 {
77 return ['app.bsky.feed.*'];
78 }
79
80 public function handle(SignalEvent $event): void
81 {
82 //
83 }
84 };
85
86 // Create registry and register the signal
87 $registry = new \SocialDept\AtpSignals\Services\SignalRegistry();
88 $registry->register($signalClass::class);
89
90 // Test that it matches app.bsky.feed.post
91 $postEvent = new SignalEvent(
92 did: 'did:plc:test',
93 timeUs: time() * 1000000,
94 kind: 'commit',
95 commit: new CommitEvent(
96 rev: 'test',
97 operation: 'create',
98 collection: 'app.bsky.feed.post',
99 rkey: 'test',
100 ),
101 );
102
103 $matchingSignals = $registry->getMatchingSignals($postEvent);
104 $this->assertCount(1, $matchingSignals);
105
106 // Test that it matches app.bsky.feed.like
107 $likeEvent = new SignalEvent(
108 did: 'did:plc:test',
109 timeUs: time() * 1000000,
110 kind: 'commit',
111 commit: new CommitEvent(
112 rev: 'test',
113 operation: 'create',
114 collection: 'app.bsky.feed.like',
115 rkey: 'test',
116 ),
117 );
118
119 $matchingSignals = $registry->getMatchingSignals($likeEvent);
120 $this->assertCount(1, $matchingSignals);
121
122 // Test that it does NOT match app.bsky.graph.follow
123 $followEvent = new SignalEvent(
124 did: 'did:plc:test',
125 timeUs: time() * 1000000,
126 kind: 'commit',
127 commit: new CommitEvent(
128 rev: 'test',
129 operation: 'create',
130 collection: 'app.bsky.graph.follow',
131 rkey: 'test',
132 ),
133 );
134
135 $matchingSignals = $registry->getMatchingSignals($followEvent);
136 $this->assertCount(0, $matchingSignals);
137 }
138}