🔀 Merge “release/v81” into “master”
[Sone.git] / src / test / kotlin / net / pterodactylus / sone / core / SoneParserTest.kt
1 package net.pterodactylus.sone.core
2
3 import com.codahale.metrics.*
4 import com.google.common.base.Optional.*
5 import freenet.crypt.*
6 import freenet.keys.InsertableClientSSK.*
7 import net.pterodactylus.sone.data.*
8 import net.pterodactylus.sone.database.memory.*
9 import net.pterodactylus.sone.freenet.wot.*
10 import net.pterodactylus.sone.test.*
11 import net.pterodactylus.util.config.*
12 import org.hamcrest.MatcherAssert.*
13 import org.hamcrest.Matchers.*
14 import org.mockito.Mockito.*
15 import java.lang.System.*
16 import java.util.concurrent.TimeUnit.*
17 import kotlin.test.*
18
19 /**
20  * Unit test for [SoneParser].
21  */
22 class SoneParserTest {
23
24         private val database = MemoryDatabase(Configuration(MapConfigurationBackend()))
25         private val metricRegistry = MetricRegistry()
26         private val soneParser = SoneParser(database, metricRegistry)
27         private val sone = mock<Sone>()
28
29         @BeforeTest
30         fun setupSone() {
31                 setupSone(this.sone, Identity::class.java)
32                 database.storeSone(sone)
33         }
34
35         private fun setupSone(sone: Sone, identityClass: Class<out Identity>) {
36                 val identity = mock(identityClass)
37                 val clientSSK = createRandom(DummyRandomSource(), "WoT")
38                 whenever(identity.requestUri).thenReturn(clientSSK.uri.toString())
39                 whenever(identity.id).thenReturn("identity")
40                 whenever(sone.id).thenReturn("identity")
41                 whenever(sone.identity).thenReturn(identity)
42                 whenever(sone.requestUri).thenAnswer { clientSSK.uri.setKeyType("USK").setDocName("Sone") }
43                 whenever(sone.time).thenReturn(currentTimeMillis() - DAYS.toMillis(1))
44         }
45
46         @Test
47         fun `parsing a sone fails when document is not xml`() {
48                 val inputStream = javaClass.getResourceAsStream("sone-parser-not-xml.xml")
49                 assertThat(soneParser.parseSone(sone, inputStream), nullValue())
50         }
51
52         @Test
53         fun `parsing a sone fails when document has negative protocol version`() {
54                 val inputStream = javaClass.getResourceAsStream("sone-parser-negative-protocol-version.xml")
55                 assertThat(soneParser.parseSone(sone, inputStream), nullValue())
56         }
57
58         @Test
59         fun `parsing a sone fails when protocol version is too large`() {
60                 val inputStream = javaClass.getResourceAsStream("sone-parser-too-large-protocol-version.xml")
61                 assertThat(soneParser.parseSone(sone, inputStream), nullValue())
62         }
63
64         @Test
65         fun `parsing a sone fails when there is no time`() {
66                 val inputStream = javaClass.getResourceAsStream("sone-parser-no-time.xml")
67                 assertThat(soneParser.parseSone(sone, inputStream), nullValue())
68         }
69
70         @Test
71         fun `parsing a sone fails when time is not numeric`() {
72                 val inputStream = javaClass.getResourceAsStream("sone-parser-time-not-numeric.xml")
73                 assertThat(soneParser.parseSone(sone, inputStream), nullValue())
74         }
75
76         @Test
77         fun `parsing a sone fails when profile is missing`() {
78                 val inputStream = javaClass.getResourceAsStream("sone-parser-no-profile.xml")
79                 assertThat(soneParser.parseSone(sone, inputStream), nullValue())
80         }
81
82         @Test
83         fun `parsing a sone fails when profile field is missing afield name`() {
84                 val inputStream = javaClass.getResourceAsStream("sone-parser-profile-missing-field-name.xml")
85                 assertThat(soneParser.parseSone(sone, inputStream), nullValue())
86         }
87
88         @Test
89         fun `parsing a sone fails when profile field name is empty`() {
90                 val inputStream = javaClass.getResourceAsStream("sone-parser-profile-empty-field-name.xml")
91                 assertThat(soneParser.parseSone(sone, inputStream), nullValue())
92         }
93
94         @Test
95         fun `parsing a sone fails when profile field name is not unique`() {
96                 val inputStream = javaClass.getResourceAsStream("sone-parser-profile-duplicate-field-name.xml")
97                 assertThat(soneParser.parseSone(sone, inputStream), nullValue())
98         }
99
100         @Test
101         fun `parsing a sone succeeds without payload`() {
102                 val inputStream = javaClass.getResourceAsStream("sone-parser-no-payload.xml")
103                 assertThat(soneParser.parseSone(sone, inputStream)!!.time, equalTo(1407197508000L))
104         }
105
106         @Test
107         fun `parsing a local sone succeeds without payload`() {
108                 val inputStream = javaClass.getResourceAsStream("sone-parser-no-payload.xml")
109                 val localSone = mock<Sone>()
110                 setupSone(localSone, OwnIdentity::class.java)
111                 whenever(localSone.isLocal).thenReturn(true)
112                 val parsedSone = soneParser.parseSone(localSone, inputStream)
113                 assertThat(parsedSone!!.time, equalTo(1407197508000L))
114                 assertThat(parsedSone.isLocal, equalTo(true))
115         }
116
117         @Test
118         fun `parsing a sone succeeds without protocol version`() {
119                 val inputStream = javaClass.getResourceAsStream("sone-parser-missing-protocol-version.xml")
120                 assertThat(soneParser.parseSone(sone, inputStream), notNullValue())
121         }
122
123         @Test
124         fun `parsing a sone fails with missing client name`() {
125                 val inputStream = javaClass.getResourceAsStream("sone-parser-missing-client-name.xml")
126                 assertThat(soneParser.parseSone(sone, inputStream), nullValue())
127         }
128
129         @Test
130         fun `parsing a sone fails with missing client version`() {
131                 val inputStream = javaClass.getResourceAsStream("sone-parser-missing-client-version.xml")
132                 assertThat(soneParser.parseSone(sone, inputStream), nullValue())
133         }
134
135         @Test
136         fun `parsing a sone succeeds with client info`() {
137                 val inputStream = javaClass.getResourceAsStream("sone-parser-with-client-info.xml")
138                 assertThat(soneParser.parseSone(sone, inputStream)!!.client, equalTo(Client("some-client", "some-version")))
139         }
140
141         @Test
142         fun `parsing a sone succeeds with profile`() {
143                 val inputStream = javaClass.getResourceAsStream("sone-parser-with-profile.xml")
144                 val profile = soneParser.parseSone(sone, inputStream)!!.profile
145                 assertThat(profile.firstName, equalTo("first"))
146                 assertThat(profile.middleName, equalTo("middle"))
147                 assertThat(profile.lastName, equalTo("last"))
148                 assertThat(profile.birthDay, equalTo(18))
149                 assertThat(profile.birthMonth, equalTo(12))
150                 assertThat(profile.birthYear, equalTo(1976))
151         }
152
153         @Test
154         fun `parsing a sone succeeds without profile fields`() {
155                 val inputStream = javaClass.getResourceAsStream("sone-parser-without-fields.xml")
156                 assertThat(soneParser.parseSone(sone, inputStream), notNullValue())
157         }
158
159         @Test
160         fun `parsing a sone fails without post id`() {
161                 val inputStream = javaClass.getResourceAsStream("sone-parser-without-post-id.xml")
162                 assertThat(soneParser.parseSone(sone, inputStream), nullValue())
163         }
164
165         @Test
166         fun `parsing a sone fails without post time`() {
167                 val inputStream = javaClass.getResourceAsStream("sone-parser-without-post-time.xml")
168                 assertThat(soneParser.parseSone(sone, inputStream), nullValue())
169         }
170
171         @Test
172         fun `parsing a sone fails without post text`() {
173                 val inputStream = javaClass.getResourceAsStream("sone-parser-without-post-text.xml")
174                 assertThat(soneParser.parseSone(sone, inputStream), nullValue())
175         }
176
177         @Test
178         fun `parsing a sone fails with invalid post time`() {
179                 val inputStream = javaClass.getResourceAsStream("sone-parser-with-invalid-post-time.xml")
180                 assertThat(soneParser.parseSone(sone, inputStream), nullValue())
181         }
182
183         @Test
184         fun `parsing a sone succeeds with valid post time`() {
185                 val inputStream = javaClass.getResourceAsStream("sone-parser-with-valid-post-time.xml")
186                 val posts = soneParser.parseSone(sone, inputStream)!!.posts
187                 assertThat(posts, hasSize(1))
188                 assertThat(posts[0].sone.id, equalTo(sone.id))
189                 assertThat(posts[0].id, equalTo("3de12680-afef-11e9-a124-e713cf8912fe"))
190                 assertThat(posts[0].time, equalTo(1407197508000L))
191                 assertThat(posts[0].recipientId, equalTo(absent()))
192                 assertThat(posts[0].text, equalTo("text"))
193         }
194
195         @Test
196         fun `parsing a sone succeeds with recipient`() {
197                 val inputStream = javaClass.getResourceAsStream("sone-parser-with-recipient.xml")
198                 val posts = soneParser.parseSone(sone, inputStream)!!.posts
199                 assertThat(posts, hasSize(1))
200                 assertThat(posts[0].sone.id, equalTo(sone.id))
201                 assertThat(posts[0].id, equalTo("3de12680-afef-11e9-a124-e713cf8912fe"))
202                 assertThat(posts[0].time, equalTo(1407197508000L))
203                 assertThat(posts[0].recipientId, equalTo(of("1234567890123456789012345678901234567890123")))
204                 assertThat(posts[0].text, equalTo("text"))
205         }
206
207         @Test
208         fun `parsing a sone succeeds with invalid recipient`() {
209                 val inputStream = javaClass.getResourceAsStream("sone-parser-with-invalid-recipient.xml")
210                 val posts = soneParser.parseSone(sone, inputStream)!!.posts
211                 assertThat(posts, hasSize(1))
212                 assertThat(posts[0].sone.id, equalTo(sone.id))
213                 assertThat(posts[0].id, equalTo("3de12680-afef-11e9-a124-e713cf8912fe"))
214                 assertThat(posts[0].time, equalTo(1407197508000L))
215                 assertThat(posts[0].recipientId, equalTo(absent()))
216                 assertThat(posts[0].text, equalTo("text"))
217         }
218
219         @Test
220         fun `parsing a sone fails without post reply id`() {
221                 val inputStream = javaClass.getResourceAsStream("sone-parser-without-post-reply-id.xml")
222                 assertThat(soneParser.parseSone(sone, inputStream), nullValue())
223         }
224
225         @Test
226         fun `parsing a sone fails without post reply post id`() {
227                 val inputStream = javaClass.getResourceAsStream("sone-parser-without-post-reply-post-id.xml")
228                 assertThat(soneParser.parseSone(sone, inputStream), nullValue())
229         }
230
231         @Test
232         fun `parsing a sone fails without post reply time`() {
233                 val inputStream = javaClass.getResourceAsStream("sone-parser-without-post-reply-time.xml")
234                 assertThat(soneParser.parseSone(sone, inputStream), nullValue())
235         }
236
237         @Test
238         fun `parsing a sone fails without post reply text`() {
239                 val inputStream = javaClass.getResourceAsStream("sone-parser-without-post-reply-text.xml")
240                 assertThat(soneParser.parseSone(sone, inputStream), nullValue())
241         }
242
243         @Test
244         fun `parsing a sone fails with invalid post reply time`() {
245                 val inputStream = javaClass.getResourceAsStream("sone-parser-with-invalid-post-reply-time.xml")
246                 assertThat(soneParser.parseSone(sone, inputStream), nullValue())
247         }
248
249         @Test
250         fun `parsing a sone succeeds with valid post reply time`() {
251                 val inputStream = javaClass.getResourceAsStream("sone-parser-with-valid-post-reply-time.xml")
252                 val postReplies = soneParser.parseSone(sone, inputStream)!!.replies
253                 assertThat(postReplies, hasSize(1))
254                 val postReply = postReplies.first()
255                 assertThat(postReply.id, equalTo("5ccba7f4-aff0-11e9-b176-a7b9db60ce98"))
256                 assertThat(postReply.postId, equalTo("3de12680-afef-11e9-a124-e713cf8912fe"))
257                 assertThat(postReply.sone.id, equalTo("identity"))
258                 assertThat(postReply.time, equalTo(1407197508000L))
259                 assertThat(postReply.text, equalTo("reply-text"))
260         }
261
262         @Test
263         fun `parsing a sone succeeds without liked post ids`() {
264                 val inputStream = javaClass.getResourceAsStream("sone-parser-without-liked-post-ids.xml")
265                 assertThat(soneParser.parseSone(sone, inputStream), notNullValue())
266         }
267
268         @Test
269         fun `parsing a sone succeeds with liked post ids`() {
270                 val inputStream = javaClass.getResourceAsStream("sone-parser-with-liked-post-ids.xml")
271                 assertThat(soneParser.parseSone(sone, inputStream)!!.likedPostIds, equalTo(setOf("liked-post-id")))
272         }
273
274         @Test
275         fun `parsing a sone succeeds without liked post reply ids`() {
276                 val inputStream = javaClass.getResourceAsStream("sone-parser-without-liked-post-reply-ids.xml")
277                 assertThat(soneParser.parseSone(sone, inputStream), notNullValue())
278         }
279
280         @Test
281         fun `parsing a sone succeeds with liked post reply ids`() {
282                 val inputStream = javaClass.getResourceAsStream("sone-parser-with-liked-post-reply-ids.xml")
283                 assertThat(soneParser.parseSone(sone, inputStream)!!.likedReplyIds, equalTo(setOf("liked-post-reply-id")))
284         }
285
286         @Test
287         fun `parsing a sone succeeds without albums`() {
288                 val inputStream = javaClass.getResourceAsStream("sone-parser-without-albums.xml")
289                 assertThat(soneParser.parseSone(sone, inputStream), notNullValue())
290         }
291
292         @Test
293         fun `parsing a sone fails without album id`() {
294                 val inputStream = javaClass.getResourceAsStream("sone-parser-without-album-id.xml")
295                 assertThat(soneParser.parseSone(sone, inputStream), nullValue())
296         }
297
298         @Test
299         fun `parsing a sone fails without album title`() {
300                 val inputStream = javaClass.getResourceAsStream("sone-parser-without-album-title.xml")
301                 assertThat(soneParser.parseSone(sone, inputStream), nullValue())
302         }
303
304         @Test
305         fun `parsing a sone succeeds with nested albums`() {
306                 val inputStream = javaClass.getResourceAsStream("sone-parser-with-multiple-albums.xml")
307                 val parsedSone = soneParser.parseSone(sone, inputStream)
308                 assertThat(parsedSone, notNullValue())
309                 assertThat(parsedSone!!.rootAlbum.albums, hasSize(1))
310                 val album = parsedSone.rootAlbum.albums[0]
311                 assertThat(album.id, equalTo("album-id-1"))
312                 assertThat(album.title, equalTo("album-title"))
313                 assertThat(album.description, equalTo("album-description"))
314                 assertThat(album.albums, hasSize(1))
315                 val nestedAlbum = album.albums[0]
316                 assertThat(nestedAlbum.id, equalTo("album-id-2"))
317                 assertThat(nestedAlbum.title, equalTo("album-title-2"))
318                 assertThat(nestedAlbum.description, equalTo("album-description-2"))
319                 assertThat(nestedAlbum.albums, hasSize(0))
320         }
321
322         @Test
323         fun `parsing a sone fails with invalid parent album id`() {
324                 val inputStream = javaClass.getResourceAsStream("sone-parser-with-invalid-parent-album-id.xml")
325                 assertThat(soneParser.parseSone(sone, inputStream), nullValue())
326         }
327
328         @Test
329         fun `parsing a sone succeeds without images`() {
330                 val inputStream = javaClass.getResourceAsStream("sone-parser-without-images.xml")
331                 assertThat(soneParser.parseSone(sone, inputStream), notNullValue())
332         }
333
334         @Test
335         fun `parsing a sone fails without image id`() {
336                 val inputStream = javaClass.getResourceAsStream("sone-parser-without-image-id.xml")
337                 assertThat(soneParser.parseSone(sone, inputStream), nullValue())
338         }
339
340         @Test
341         fun `parsing a sone fails without image time`() {
342                 val inputStream = javaClass.getResourceAsStream("sone-parser-without-image-time.xml")
343                 assertThat(soneParser.parseSone(sone, inputStream), nullValue())
344         }
345
346         @Test
347         fun `parsing a sone fails without image key`() {
348                 val inputStream = javaClass.getResourceAsStream("sone-parser-without-image-key.xml")
349                 assertThat(soneParser.parseSone(sone, inputStream), nullValue())
350         }
351
352         @Test
353         fun `parsing a sone fails without image title`() {
354                 val inputStream = javaClass.getResourceAsStream("sone-parser-without-image-title.xml")
355                 assertThat(soneParser.parseSone(sone, inputStream), nullValue())
356         }
357
358         @Test
359         fun `parsing a sone fails without image width`() {
360                 val inputStream = javaClass.getResourceAsStream("sone-parser-without-image-width.xml")
361                 assertThat(soneParser.parseSone(sone, inputStream), nullValue())
362         }
363
364         @Test
365         fun `parsing a sone fails without image height`() {
366                 val inputStream = javaClass.getResourceAsStream("sone-parser-without-image-height.xml")
367                 assertThat(soneParser.parseSone(sone, inputStream), nullValue())
368         }
369
370         @Test
371         fun `parsing a sone fails with invalid image width`() {
372                 val inputStream = javaClass.getResourceAsStream("sone-parser-with-invalid-image-width.xml")
373                 assertThat(soneParser.parseSone(sone, inputStream), nullValue())
374         }
375
376         @Test
377         fun `parsing a sone fails with invalid image height`() {
378                 val inputStream = javaClass.getResourceAsStream("sone-parser-with-invalid-image-height.xml")
379                 assertThat(soneParser.parseSone(sone, inputStream), nullValue())
380         }
381
382         @Test
383         fun `parsing a sone succeeds with image`() {
384                 val inputStream = javaClass.getResourceAsStream("sone-parser-with-image.xml")
385                 val sone = soneParser.parseSone(this.sone, inputStream)
386                 assertThat(sone, notNullValue())
387                 assertThat(sone!!.rootAlbum.albums, hasSize(1))
388                 assertThat(sone.rootAlbum.albums[0].images, hasSize(1))
389                 val image = sone.rootAlbum.albums[0].images[0]
390                 assertThat(image.id, equalTo("image-id"))
391                 assertThat(image.creationTime, equalTo(1407197508000L))
392                 assertThat(image.key, equalTo("KSK@GPLv3.txt"))
393                 assertThat(image.title, equalTo("image-title"))
394                 assertThat(image.description, equalTo("image-description"))
395                 assertThat(image.width, equalTo(1920))
396                 assertThat(image.height, equalTo(1080))
397                 assertThat(sone.profile.avatar, equalTo("image-id"))
398         }
399
400         @Test
401         fun `unsuccessful parsing does not add a histogram entry`() {
402                 val inputStream = javaClass.getResourceAsStream("sone-parser-with-invalid-image-height.xml")
403                 assertThat(soneParser.parseSone(sone, inputStream), nullValue())
404                 val histogram = metricRegistry.histogram("sone.parse.duration")
405                 assertThat(histogram.count, equalTo(0L))
406         }
407
408         @Test
409         fun `successful parsing adds histogram entry`() {
410                 val inputStream = javaClass.getResourceAsStream("sone-parser-without-images.xml")
411                 assertThat(soneParser.parseSone(sone, inputStream), notNullValue())
412                 val histogram = metricRegistry.histogram("sone.parse.duration")
413                 assertThat(histogram.count, equalTo(1L))
414         }
415
416 }