]> nmode's Git Repositories - signal-cli/blob - lib/src/test/java/org/asamk/signal/manager/storage/recipients/MergeRecipientHelperTest.java
0931b008f9ecedd374a233db55b403f980354be6
[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.ACI;
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 ACI ACI_A = ACI.from(UUID.randomUUID());
21 static final ACI ACI_B = 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(ACI_A, PNI_A, NUMBER_A, USERNAME_A);
30 static final PartialAddresses ADDR_B = new PartialAddresses(ACI_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)), ADDR_A.ACI_NUM, Set.of(rec(1, ADDR_A.FULL))),
57 new T(Set.of(rec(1, ADDR_A.ACI_PNI)), ADDR_A.ACI_NUM, Set.of(rec(1, ADDR_A.FULL))),
58
59 new T(Set.of(rec(1, ADDR_A.FULL)), ADDR_A.PNI_NUM, Set.of(rec(1, ADDR_A.FULL))),
60 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))),
61 new T(Set.of(rec(1, ADDR_A.PNI)), ADDR_A.PNI_NUM, Set.of(rec(1, ADDR_A.PNI_NUM))),
62 new T(Set.of(rec(1, ADDR_A.NUM)), ADDR_A.PNI_NUM, Set.of(rec(1, ADDR_A.PNI_NUM))),
63 new T(Set.of(rec(1, ADDR_A.ACI_NUM)),
64 ADDR_A.PNI_NUM,
65 Set.of(rec(1, ADDR_A.ACI), rec(1000000, ADDR_A.PNI_NUM))),
66 new T(Set.of(rec(1, ADDR_A.PNI_NUM)), ADDR_A.PNI_NUM, Set.of(rec(1, ADDR_A.PNI_NUM))),
67 new T(Set.of(rec(1, ADDR_A.ACI_PNI)), ADDR_A.PNI_NUM, Set.of(rec(1, ADDR_A.FULL))),
68
69 new T(Set.of(rec(1, ADDR_A.FULL)), ADDR_A.ACI_PNI, Set.of(rec(1, ADDR_A.FULL))),
70 new T(Set.of(rec(1, ADDR_A.ACI)), ADDR_A.ACI_PNI, Set.of(rec(1, ADDR_A.ACI_PNI))),
71 new T(Set.of(rec(1, ADDR_A.PNI)), ADDR_A.ACI_PNI, Set.of(rec(1, ADDR_A.ACI_PNI))),
72 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))),
73 new T(Set.of(rec(1, ADDR_A.ACI_NUM)), ADDR_A.ACI_PNI, Set.of(rec(1, ADDR_A.FULL))),
74 new T(Set.of(rec(1, ADDR_A.PNI_NUM)), ADDR_A.ACI_PNI, Set.of(rec(1, ADDR_A.FULL))),
75 new T(Set.of(rec(1, ADDR_A.ACI_PNI)), ADDR_A.ACI_PNI, Set.of(rec(1, ADDR_A.ACI_PNI))),
76
77 new T(Set.of(rec(1, ADDR_A.FULL)), ADDR_B.FULL, Set.of(rec(1, ADDR_A.FULL), rec(1000000, ADDR_B.FULL))),
78
79 new T(Set.of(rec(1, ADDR_A.FULL)), ADDR_A.ACI_USERNAME, Set.of(rec(1, ADDR_A.FULL_USERNAME))),
80 new T(Set.of(rec(1, ADDR_A.ACI)), ADDR_A.ACI_USERNAME, Set.of(rec(1, ADDR_A.ACI_USERNAME))),
81 new T(Set.of(rec(1, ADDR_A.ACI_NUM)), ADDR_A.ACI_USERNAME, Set.of(rec(1, ADDR_A.ACI_NUM_USERNAME))),
82 };
83
84 static final T[] testInstancesTwo = new T[]{
85 new T(Set.of(rec(1, ADDR_A.ACI), rec(2, ADDR_A.PNI)), ADDR_A.FULL, Set.of(rec(1, ADDR_A.FULL))),
86 new T(Set.of(rec(1, ADDR_A.ACI), rec(2, ADDR_A.NUM)), ADDR_A.FULL, Set.of(rec(1, ADDR_A.FULL))),
87 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))),
88 new T(Set.of(rec(1, ADDR_A.PNI), rec(2, ADDR_A.NUM)), ADDR_A.FULL, Set.of(rec(1, ADDR_A.FULL))),
89 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))),
90 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))),
91
92 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))),
93 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))),
94 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))),
95
96 new T(Set.of(rec(1, ADDR_A.ACI), rec(2, ADDR_A.PNI_NUM)),
97 ADDR_A.PNI_NUM,
98 Set.of(rec(1, ADDR_A.ACI), rec(2, ADDR_A.PNI_NUM))),
99 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))),
100 new T(Set.of(rec(1, ADDR_A.PNI), rec(2, ADDR_A.ACI_NUM)),
101 ADDR_A.PNI_NUM,
102 Set.of(rec(1, ADDR_A.PNI_NUM), rec(2, ADDR_A.ACI))),
103 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))),
104
105 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))),
106 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))),
107 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))),
108 };
109
110 static final T[] testInstancesThree = new T[]{
111 new T(Set.of(rec(1, ADDR_A.ACI), rec(2, ADDR_A.PNI), rec(3, ADDR_A.NUM)),
112 ADDR_A.FULL,
113 Set.of(rec(1, ADDR_A.FULL))),
114 new T(Set.of(rec(1, ADDR_A.ACI.withIdentifiersFrom(ADDR_B.PNI)), rec(2, ADDR_A.PNI), rec(3, ADDR_A.NUM)),
115 ADDR_A.FULL,
116 Set.of(rec(1, ADDR_A.FULL))),
117 new T(Set.of(rec(1, ADDR_A.ACI.withIdentifiersFrom(ADDR_B.NUM)), rec(2, ADDR_A.PNI), rec(3, ADDR_A.NUM)),
118 ADDR_A.FULL,
119 Set.of(rec(1, ADDR_A.FULL))),
120 new T(Set.of(rec(1, ADDR_A.ACI), rec(2, ADDR_A.PNI), rec(3, ADDR_A.NUM.withIdentifiersFrom(ADDR_B.ACI))),
121 ADDR_A.FULL,
122 Set.of(rec(1, ADDR_A.FULL), rec(3, ADDR_B.ACI))),
123 new T(Set.of(rec(1, ADDR_A.ACI), rec(2, ADDR_A.PNI.withIdentifiersFrom(ADDR_B.ACI)), rec(3, ADDR_A.NUM)),
124 ADDR_A.FULL,
125 Set.of(rec(1, ADDR_A.FULL), rec(2, ADDR_B.ACI))),
126 };
127
128 @ParameterizedTest
129 @MethodSource
130 void resolveRecipientTrustedLocked_NoneExisting(T test) throws Exception {
131 final var testStore = new TestStore(test.input);
132 MergeRecipientHelper.resolveRecipientTrustedLocked(testStore, test.request);
133 assertEquals(test.output, testStore.getRecipients());
134 }
135
136 private static Stream<Arguments> resolveRecipientTrustedLocked_NoneExisting() {
137 return Arrays.stream(testInstancesNone).map(Arguments::of);
138 }
139
140 @ParameterizedTest
141 @MethodSource
142 void resolveRecipientTrustedLocked_SingleExisting(T test) throws Exception {
143 final var testStore = new TestStore(test.input);
144 MergeRecipientHelper.resolveRecipientTrustedLocked(testStore, test.request);
145 assertEquals(test.output, testStore.getRecipients());
146 }
147
148 private static Stream<Arguments> resolveRecipientTrustedLocked_SingleExisting() {
149 return Arrays.stream(testInstancesSingle).map(Arguments::of);
150 }
151
152 @ParameterizedTest
153 @MethodSource
154 void resolveRecipientTrustedLocked_TwoExisting(T test) throws Exception {
155 final var testStore = new TestStore(test.input);
156 MergeRecipientHelper.resolveRecipientTrustedLocked(testStore, test.request);
157 assertEquals(test.output, testStore.getRecipients());
158 }
159
160 private static Stream<Arguments> resolveRecipientTrustedLocked_TwoExisting() {
161 return Arrays.stream(testInstancesTwo).map(Arguments::of);
162 }
163
164 @ParameterizedTest
165 @MethodSource
166 void resolveRecipientTrustedLocked_ThreeExisting(T test) throws Exception {
167 final var testStore = new TestStore(test.input);
168 MergeRecipientHelper.resolveRecipientTrustedLocked(testStore, test.request);
169 assertEquals(test.output, testStore.getRecipients());
170 }
171
172 private static Stream<Arguments> resolveRecipientTrustedLocked_ThreeExisting() {
173 return Arrays.stream(testInstancesThree).map(Arguments::of);
174 }
175
176 private static RecipientWithAddress rec(long recipientId, RecipientAddress address) {
177 return new RecipientWithAddress(new RecipientId(recipientId, null), address);
178 }
179
180 record T(
181 Set<RecipientWithAddress> input, RecipientAddress request, Set<RecipientWithAddress> output
182 ) {
183
184 @Override
185 public String toString() {
186 return "T{#input=%s, request=%s_%s_%s, #output=%s}".formatted(input.size(),
187 request.aci().isPresent() ? "ACI" : "",
188 request.pni().isPresent() ? "PNI" : "",
189 request.number().isPresent() ? "NUM" : "",
190 output.size());
191 }
192 }
193
194 static class TestStore implements MergeRecipientHelper.Store {
195
196 final Set<RecipientWithAddress> recipients;
197 long nextRecipientId = 1000000;
198
199 TestStore(final Set<RecipientWithAddress> recipients) {
200 this.recipients = new HashSet<>(recipients);
201 }
202
203 public Set<RecipientWithAddress> getRecipients() {
204 return recipients;
205 }
206
207 @Override
208 public Set<RecipientWithAddress> findAllByAddress(final RecipientAddress address) {
209 return recipients.stream().filter(r -> r.address().matches(address)).collect(Collectors.toSet());
210 }
211
212 @Override
213 public RecipientId addNewRecipient(final RecipientAddress address) {
214 final var recipientId = new RecipientId(nextRecipientId++, null);
215 recipients.add(new RecipientWithAddress(recipientId, address));
216 return recipientId;
217 }
218
219 @Override
220 public void updateRecipientAddress(final RecipientId recipientId, final RecipientAddress address) {
221 recipients.removeIf(r -> r.id().equals(recipientId));
222 recipients.add(new RecipientWithAddress(recipientId, address));
223 }
224
225 @Override
226 public void removeRecipientAddress(final RecipientId recipientId) {
227 recipients.removeIf(r -> r.id().equals(recipientId));
228 }
229 }
230
231 private record PartialAddresses(
232 RecipientAddress FULL,
233 RecipientAddress FULL_USERNAME,
234 RecipientAddress ACI,
235 RecipientAddress PNI,
236 RecipientAddress NUM,
237 RecipientAddress ACI_NUM,
238 RecipientAddress ACI_NUM_USERNAME,
239 RecipientAddress PNI_NUM,
240 RecipientAddress ACI_PNI,
241 RecipientAddress ACI_USERNAME
242 ) {
243
244 PartialAddresses(ACI aci, PNI pni, String number, String username) {
245 this(new RecipientAddress(aci, pni, number),
246 new RecipientAddress(aci, pni, number, username),
247 new RecipientAddress(aci, null, null),
248 new RecipientAddress(null, pni, null),
249 new RecipientAddress(null, null, number),
250 new RecipientAddress(aci, null, number),
251 new RecipientAddress(aci, null, number, username),
252 new RecipientAddress(null, pni, number),
253 new RecipientAddress(aci, pni, null),
254 new RecipientAddress(aci, null, null, username));
255 }
256 }
257 }