]> nmode's Git Repositories - signal-cli/blob - lib/src/test/java/org/asamk/signal/manager/storage/recipients/MergeRecipientHelperTest.java
eae8958f21915205e7041283c935a416bdc29642
[signal-cli] / lib / src / test / java / org / asamk / signal / manager / storage / recipients / MergeRecipientHelperTest.java
1 package org.asamk.signal.manager.storage.recipients;
2
3 import org.junit.jupiter.params.ParameterizedTest;
4 import org.junit.jupiter.params.provider.Arguments;
5 import org.junit.jupiter.params.provider.MethodSource;
6 import org.whispersystems.signalservice.api.push.ServiceId;
7 import org.whispersystems.signalservice.api.push.ServiceId.PNI;
8
9 import java.util.Arrays;
10 import java.util.HashSet;
11 import java.util.Set;
12 import java.util.UUID;
13 import java.util.stream.Collectors;
14 import java.util.stream.Stream;
15
16 import static org.junit.jupiter.api.Assertions.assertEquals;
17
18 class MergeRecipientHelperTest {
19
20 static final ServiceId SERVICE_ID_A = ServiceId.ACI.from(UUID.randomUUID());
21 static final ServiceId SERVICE_ID_B = ServiceId.ACI.from(UUID.randomUUID());
22 static final PNI PNI_A = PNI.from(UUID.randomUUID());
23 static final PNI PNI_B = PNI.from(UUID.randomUUID());
24 static final String NUMBER_A = "+AAA";
25 static final String NUMBER_B = "+BBB";
26 static final String USERNAME_A = "USER.1";
27 static final String USERNAME_B = "USER.2";
28
29 static final PartialAddresses ADDR_A = new PartialAddresses(SERVICE_ID_A, PNI_A, NUMBER_A, USERNAME_A);
30 static final PartialAddresses ADDR_B = new PartialAddresses(SERVICE_ID_B, PNI_B, NUMBER_B, USERNAME_B);
31
32 static final T[] testInstancesNone = new T[]{
33 new T(Set.of(), ADDR_A.FULL, Set.of(rec(1000000, ADDR_A.FULL))),
34 new T(Set.of(), ADDR_A.ACI_NUM, Set.of(rec(1000000, ADDR_A.ACI_NUM))),
35 new T(Set.of(), ADDR_A.ACI_PNI, Set.of(rec(1000000, ADDR_A.ACI_PNI))),
36 new T(Set.of(), ADDR_A.PNI_NUM, Set.of(rec(1000000, ADDR_A.PNI_NUM))),
37 new T(Set.of(), ADDR_A.ACI_USERNAME, Set.of(rec(1000000, ADDR_A.ACI_USERNAME))),
38 new T(Set.of(), ADDR_A.FULL_USERNAME, Set.of(rec(1000000, ADDR_A.FULL_USERNAME))),
39 };
40
41 static final T[] testInstancesSingle = new T[]{
42 new T(Set.of(rec(1, ADDR_A.FULL)), ADDR_A.FULL, Set.of(rec(1, ADDR_A.FULL))),
43 new T(Set.of(rec(1, ADDR_A.FULL_USERNAME)), ADDR_A.FULL, Set.of(rec(1, ADDR_A.FULL_USERNAME))),
44 new T(Set.of(rec(1, ADDR_A.ACI)), ADDR_A.FULL, Set.of(rec(1, ADDR_A.FULL))),
45 new T(Set.of(rec(1, ADDR_A.PNI)), ADDR_A.FULL, Set.of(rec(1, ADDR_A.FULL))),
46 new T(Set.of(rec(1, ADDR_A.NUM)), ADDR_A.FULL, Set.of(rec(1, ADDR_A.FULL))),
47 new T(Set.of(rec(1, ADDR_A.ACI_NUM)), ADDR_A.FULL, Set.of(rec(1, ADDR_A.FULL))),
48 new T(Set.of(rec(1, ADDR_A.PNI_NUM)), ADDR_A.FULL, Set.of(rec(1, ADDR_A.FULL))),
49 new T(Set.of(rec(1, ADDR_A.ACI_PNI)), ADDR_A.FULL, Set.of(rec(1, ADDR_A.FULL))),
50
51 new T(Set.of(rec(1, ADDR_A.FULL)), ADDR_A.ACI_NUM, Set.of(rec(1, ADDR_A.FULL))),
52 new T(Set.of(rec(1, ADDR_A.ACI)), ADDR_A.ACI_NUM, Set.of(rec(1, ADDR_A.ACI_NUM))),
53 new T(Set.of(rec(1, ADDR_A.PNI)), ADDR_A.ACI_NUM, Set.of(rec(1, ADDR_A.PNI), rec(1000000, ADDR_A.ACI_NUM))),
54 new T(Set.of(rec(1, ADDR_A.NUM)), ADDR_A.ACI_NUM, Set.of(rec(1, ADDR_A.ACI_NUM))),
55 new T(Set.of(rec(1, ADDR_A.ACI_NUM)), ADDR_A.ACI_NUM, Set.of(rec(1, ADDR_A.ACI_NUM))),
56 new T(Set.of(rec(1, ADDR_A.PNI_NUM)),
57 ADDR_A.ACI_NUM,
58 Set.of(rec(1, ADDR_A.PNI), rec(1000000, ADDR_A.ACI_NUM))),
59 new T(Set.of(rec(1, ADDR_A.ACI_PNI)), ADDR_A.ACI_NUM, Set.of(rec(1, ADDR_A.FULL))),
60
61 new T(Set.of(rec(1, ADDR_A.FULL)), ADDR_A.PNI_NUM, Set.of(rec(1, ADDR_A.FULL))),
62 new T(Set.of(rec(1, ADDR_A.ACI)), ADDR_A.PNI_NUM, Set.of(rec(1, ADDR_A.ACI), rec(1000000, ADDR_A.PNI_NUM))),
63 new T(Set.of(rec(1, ADDR_A.PNI)), ADDR_A.PNI_NUM, Set.of(rec(1, ADDR_A.PNI_NUM))),
64 new T(Set.of(rec(1, ADDR_A.NUM)), ADDR_A.PNI_NUM, Set.of(rec(1, ADDR_A.PNI_NUM))),
65 new T(Set.of(rec(1, ADDR_A.ACI_NUM)),
66 ADDR_A.PNI_NUM,
67 Set.of(rec(1, ADDR_A.ACI), rec(1000000, ADDR_A.PNI_NUM))),
68 new T(Set.of(rec(1, ADDR_A.PNI_NUM)), ADDR_A.PNI_NUM, Set.of(rec(1, ADDR_A.PNI_NUM))),
69 new T(Set.of(rec(1, ADDR_A.ACI_PNI)), ADDR_A.PNI_NUM, Set.of(rec(1, ADDR_A.FULL))),
70
71 new T(Set.of(rec(1, ADDR_A.FULL)), ADDR_A.ACI_PNI, Set.of(rec(1, ADDR_A.FULL))),
72 new T(Set.of(rec(1, ADDR_A.ACI)), ADDR_A.ACI_PNI, Set.of(rec(1, ADDR_A.ACI_PNI))),
73 new T(Set.of(rec(1, ADDR_A.PNI)), ADDR_A.ACI_PNI, Set.of(rec(1, ADDR_A.ACI_PNI))),
74 new T(Set.of(rec(1, ADDR_A.NUM)), ADDR_A.ACI_PNI, Set.of(rec(1, ADDR_A.NUM), rec(1000000, ADDR_A.ACI_PNI))),
75 new T(Set.of(rec(1, ADDR_A.ACI_NUM)), ADDR_A.ACI_PNI, Set.of(rec(1, ADDR_A.FULL))),
76 new T(Set.of(rec(1, ADDR_A.PNI_NUM)), ADDR_A.ACI_PNI, Set.of(rec(1, ADDR_A.FULL))),
77 new T(Set.of(rec(1, ADDR_A.ACI_PNI)), ADDR_A.ACI_PNI, Set.of(rec(1, ADDR_A.ACI_PNI))),
78
79 new T(Set.of(rec(1, ADDR_A.FULL)), ADDR_B.FULL, Set.of(rec(1, ADDR_A.FULL), rec(1000000, ADDR_B.FULL))),
80
81 new T(Set.of(rec(1, ADDR_A.FULL)), ADDR_A.ACI_USERNAME, Set.of(rec(1, ADDR_A.FULL_USERNAME))),
82 new T(Set.of(rec(1, ADDR_A.ACI)), ADDR_A.ACI_USERNAME, Set.of(rec(1, ADDR_A.ACI_USERNAME))),
83 new T(Set.of(rec(1, ADDR_A.ACI_NUM)), ADDR_A.ACI_USERNAME, Set.of(rec(1, ADDR_A.ACI_NUM_USERNAME))),
84 };
85
86 static final T[] testInstancesTwo = new T[]{
87 new T(Set.of(rec(1, ADDR_A.ACI), rec(2, ADDR_A.PNI)), ADDR_A.FULL, Set.of(rec(1, ADDR_A.FULL))),
88 new T(Set.of(rec(1, ADDR_A.ACI), rec(2, ADDR_A.NUM)), ADDR_A.FULL, Set.of(rec(1, ADDR_A.FULL))),
89 new T(Set.of(rec(1, ADDR_A.ACI), rec(2, ADDR_A.PNI_NUM)), ADDR_A.FULL, Set.of(rec(1, ADDR_A.FULL))),
90 new T(Set.of(rec(1, ADDR_A.PNI), rec(2, ADDR_A.NUM)), ADDR_A.FULL, Set.of(rec(1, ADDR_A.FULL))),
91 new T(Set.of(rec(1, ADDR_A.PNI), rec(2, ADDR_A.ACI_NUM)), ADDR_A.FULL, Set.of(rec(2, ADDR_A.FULL))),
92 new T(Set.of(rec(1, ADDR_A.NUM), rec(2, ADDR_A.ACI_PNI)), ADDR_A.FULL, Set.of(rec(2, ADDR_A.FULL))),
93
94 new T(Set.of(rec(1, ADDR_A.ACI), rec(2, ADDR_A.NUM)), ADDR_A.ACI_NUM, Set.of(rec(1, ADDR_A.ACI_NUM))),
95 new T(Set.of(rec(1, ADDR_A.ACI), rec(2, ADDR_A.PNI_NUM)), ADDR_A.ACI_NUM, Set.of(rec(1, ADDR_A.FULL))),
96 new T(Set.of(rec(1, ADDR_A.NUM), rec(2, ADDR_A.ACI_PNI)), ADDR_A.ACI_NUM, Set.of(rec(2, ADDR_A.FULL))),
97
98 new T(Set.of(rec(1, ADDR_A.ACI), rec(2, ADDR_A.PNI_NUM)),
99 ADDR_A.PNI_NUM,
100 Set.of(rec(1, ADDR_A.ACI), rec(2, ADDR_A.PNI_NUM))),
101 new T(Set.of(rec(1, ADDR_A.PNI), rec(2, ADDR_A.NUM)), ADDR_A.PNI_NUM, Set.of(rec(1, ADDR_A.PNI_NUM))),
102 new T(Set.of(rec(1, ADDR_A.PNI), rec(2, ADDR_A.ACI_NUM)),
103 ADDR_A.PNI_NUM,
104 Set.of(rec(1, ADDR_A.PNI_NUM), rec(2, ADDR_A.ACI))),
105 new T(Set.of(rec(1, ADDR_A.NUM), rec(2, ADDR_A.ACI_PNI)), ADDR_A.PNI_NUM, Set.of(rec(2, ADDR_A.FULL))),
106
107 new T(Set.of(rec(1, ADDR_A.ACI), rec(2, ADDR_A.PNI)), ADDR_A.ACI_PNI, Set.of(rec(1, ADDR_A.ACI_PNI))),
108 new T(Set.of(rec(1, ADDR_A.ACI), rec(2, ADDR_A.PNI_NUM)), ADDR_A.ACI_PNI, Set.of(rec(1, ADDR_A.FULL))),
109 new T(Set.of(rec(1, ADDR_A.PNI), rec(2, ADDR_A.ACI_NUM)), ADDR_A.ACI_PNI, Set.of(rec(2, ADDR_A.FULL))),
110 };
111
112 static final T[] testInstancesThree = new T[]{
113 new T(Set.of(rec(1, ADDR_A.ACI), rec(2, ADDR_A.PNI), rec(3, ADDR_A.NUM)),
114 ADDR_A.FULL,
115 Set.of(rec(1, ADDR_A.FULL))),
116 new T(Set.of(rec(1, ADDR_A.ACI.withIdentifiersFrom(ADDR_B.PNI)), rec(2, ADDR_A.PNI), rec(3, ADDR_A.NUM)),
117 ADDR_A.FULL,
118 Set.of(rec(1, ADDR_A.FULL))),
119 new T(Set.of(rec(1, ADDR_A.ACI.withIdentifiersFrom(ADDR_B.NUM)), rec(2, ADDR_A.PNI), rec(3, ADDR_A.NUM)),
120 ADDR_A.FULL,
121 Set.of(rec(1, ADDR_A.FULL))),
122 new T(Set.of(rec(1, ADDR_A.ACI), rec(2, ADDR_A.PNI), rec(3, ADDR_A.NUM.withIdentifiersFrom(ADDR_B.ACI))),
123 ADDR_A.FULL,
124 Set.of(rec(1, ADDR_A.FULL), rec(3, ADDR_B.ACI))),
125 new T(Set.of(rec(1, ADDR_A.ACI), rec(2, ADDR_A.PNI.withIdentifiersFrom(ADDR_B.ACI)), rec(3, ADDR_A.NUM)),
126 ADDR_A.FULL,
127 Set.of(rec(1, ADDR_A.FULL), rec(2, ADDR_B.ACI))),
128 };
129
130 @ParameterizedTest
131 @MethodSource
132 void resolveRecipientTrustedLocked_NoneExisting(T test) throws Exception {
133 final var testStore = new TestStore(test.input);
134 MergeRecipientHelper.resolveRecipientTrustedLocked(testStore, test.request);
135 assertEquals(test.output, testStore.getRecipients());
136 }
137
138 private static Stream<Arguments> resolveRecipientTrustedLocked_NoneExisting() {
139 return Arrays.stream(testInstancesNone).map(Arguments::of);
140 }
141
142 @ParameterizedTest
143 @MethodSource
144 void resolveRecipientTrustedLocked_SingleExisting(T test) throws Exception {
145 final var testStore = new TestStore(test.input);
146 MergeRecipientHelper.resolveRecipientTrustedLocked(testStore, test.request);
147 assertEquals(test.output, testStore.getRecipients());
148 }
149
150 private static Stream<Arguments> resolveRecipientTrustedLocked_SingleExisting() {
151 return Arrays.stream(testInstancesSingle).map(Arguments::of);
152 }
153
154 @ParameterizedTest
155 @MethodSource
156 void resolveRecipientTrustedLocked_TwoExisting(T test) throws Exception {
157 final var testStore = new TestStore(test.input);
158 MergeRecipientHelper.resolveRecipientTrustedLocked(testStore, test.request);
159 assertEquals(test.output, testStore.getRecipients());
160 }
161
162 private static Stream<Arguments> resolveRecipientTrustedLocked_TwoExisting() {
163 return Arrays.stream(testInstancesTwo).map(Arguments::of);
164 }
165
166 @ParameterizedTest
167 @MethodSource
168 void resolveRecipientTrustedLocked_ThreeExisting(T test) throws Exception {
169 final var testStore = new TestStore(test.input);
170 MergeRecipientHelper.resolveRecipientTrustedLocked(testStore, test.request);
171 assertEquals(test.output, testStore.getRecipients());
172 }
173
174 private static Stream<Arguments> resolveRecipientTrustedLocked_ThreeExisting() {
175 return Arrays.stream(testInstancesThree).map(Arguments::of);
176 }
177
178 private static RecipientWithAddress rec(long recipientId, RecipientAddress address) {
179 return new RecipientWithAddress(new RecipientId(recipientId, null), address);
180 }
181
182 record T(
183 Set<RecipientWithAddress> input, RecipientAddress request, Set<RecipientWithAddress> output
184 ) {
185
186 @Override
187 public String toString() {
188 return "T{#input=%s, request=%s_%s_%s, #output=%s}".formatted(input.size(),
189 request.serviceId().isPresent() ? "SVI" : "",
190 request.pni().isPresent() ? "PNI" : "",
191 request.number().isPresent() ? "NUM" : "",
192 output.size());
193 }
194 }
195
196 static class TestStore implements MergeRecipientHelper.Store {
197
198 final Set<RecipientWithAddress> recipients;
199 long nextRecipientId = 1000000;
200
201 TestStore(final Set<RecipientWithAddress> recipients) {
202 this.recipients = new HashSet<>(recipients);
203 }
204
205 public Set<RecipientWithAddress> getRecipients() {
206 return recipients;
207 }
208
209 @Override
210 public Set<RecipientWithAddress> findAllByAddress(final RecipientAddress address) {
211 return recipients.stream().filter(r -> r.address().matches(address)).collect(Collectors.toSet());
212 }
213
214 @Override
215 public RecipientId addNewRecipient(final RecipientAddress address) {
216 final var recipientId = new RecipientId(nextRecipientId++, null);
217 recipients.add(new RecipientWithAddress(recipientId, address));
218 return recipientId;
219 }
220
221 @Override
222 public void updateRecipientAddress(
223 final RecipientId recipientId, final RecipientAddress address
224 ) {
225 recipients.removeIf(r -> r.id().equals(recipientId));
226 recipients.add(new RecipientWithAddress(recipientId, address));
227 }
228
229 @Override
230 public void removeRecipientAddress(final RecipientId recipientId) {
231 recipients.removeIf(r -> r.id().equals(recipientId));
232 }
233 }
234
235 private record PartialAddresses(
236 RecipientAddress FULL,
237 RecipientAddress FULL_USERNAME,
238 RecipientAddress ACI,
239 RecipientAddress PNI,
240 RecipientAddress NUM,
241 RecipientAddress ACI_NUM,
242 RecipientAddress ACI_NUM_USERNAME,
243 RecipientAddress PNI_NUM,
244 RecipientAddress ACI_PNI,
245 RecipientAddress ACI_USERNAME
246 ) {
247
248 PartialAddresses(ServiceId serviceId, PNI pni, String number, String username) {
249 this(new RecipientAddress(serviceId, pni, number),
250 new RecipientAddress(serviceId, pni, number, username),
251 new RecipientAddress(serviceId, null, null),
252 new RecipientAddress(null, pni, null),
253 new RecipientAddress(null, null, number),
254 new RecipientAddress(serviceId, null, number),
255 new RecipientAddress(serviceId, null, number, username),
256 new RecipientAddress(null, pni, number),
257 new RecipientAddress(serviceId, pni, null),
258 new RecipientAddress(serviceId, null, null, username));
259 }
260 }
261 }