1 package net.pterodactylus.sone.core
3 import com.google.common.eventbus.*
4 import freenet.client.*
6 import freenet.support.io.*
7 import net.pterodactylus.sone.core.FreenetInterface.*
8 import net.pterodactylus.sone.core.event.*
9 import net.pterodactylus.sone.main.*
10 import net.pterodactylus.sone.test.*
11 import net.pterodactylus.util.version.Version
12 import org.hamcrest.MatcherAssert.*
13 import org.hamcrest.Matchers.equalTo
14 import org.hamcrest.Matchers.instanceOf
16 import org.mockito.ArgumentCaptor.*
17 import org.mockito.ArgumentMatchers.any
18 import org.mockito.Mockito.never
19 import org.mockito.Mockito.times
20 import org.mockito.Mockito.verify
21 import org.mockito.hamcrest.MockitoHamcrest.*
23 import kotlin.Long.Companion.MAX_VALUE
26 * Unit test for [UpdateChecker].
28 class UpdateCheckerTest {
30 private val eventBus = mock<EventBus>()
31 private val freenetInterface = mock<FreenetInterface>()
32 private val currentVersion = Version(1, 0, 0)
33 private val pluginHomepage = PluginHomepage("KSK@homepage")
34 private val updateChecker = UpdateChecker(eventBus, freenetInterface, currentVersion, pluginHomepage)
37 fun startUpdateChecker() {
42 fun `new update checker does not have a latest version`() {
43 assertThat(updateChecker.hasLatestVersion(), equalTo(false))
44 assertThat(updateChecker.latestVersion, equalTo(currentVersion))
48 fun `starting an update checker register a usk`() {
49 verify(freenetInterface).registerUsk(any(FreenetURI::class.java), any(Callback::class.java))
53 fun `stopping an update checker unregisters a usk`() {
55 verify(freenetInterface).unregisterUsk(any(FreenetURI::class.java))
59 fun `callback does not download if new edition is not found`() {
60 setupCallbackWithEdition(MAX_VALUE, false)
61 verify(freenetInterface, never()).fetchUri(any(FreenetURI::class.java))
62 verify(eventBus, never()).post(argThat(instanceOf(UpdateFoundEvent::class.java)))
65 private fun setupCallbackWithEdition(edition: Long, newKnownGood: Boolean, newSlot: Boolean = false) {
66 val uri = forClass(FreenetURI::class.java)
67 val callback = forClass(Callback::class.java)
68 verify(freenetInterface).registerUsk(uri.capture(), callback.capture())
69 callback.value.editionFound(uri.value, edition, newKnownGood, newSlot)
73 fun `callback starts if new edition is found`() {
74 setupFetchResult(createFutureFetchResult())
75 setupCallbackWithEdition(MAX_VALUE, true)
76 verifyAFreenetUriIsFetched()
77 verifyEventIsFired(Version(99, 0, 0), 11865368297000L, false)
78 verifyThatUpdateCheckerKnowsLatestVersion(Version(99, 0, 0), 11865368297000L)
81 private fun createFutureFetchResult(): FetchResult {
82 val clientMetadata = ClientMetadata("application/xml")
83 val fetched = ArrayBucket(("# MapConfigurationBackendVersion=1\n" +
84 "CurrentVersion/Version: 99.0.0\n" +
85 "CurrentVersion/ReleaseTime: 11865368297000\n" +
86 "DisruptiveVersion/0.1.2: true").toByteArray())
87 return FetchResult(clientMetadata, fetched)
90 private fun verifyEventIsFired(version: Version, releaseTime: Long, disruptive: Boolean) {
91 val updateFoundEvent = forClass(UpdateFoundEvent::class.java)
92 verify(eventBus, times(1)).post(updateFoundEvent.capture())
93 assertThat(updateFoundEvent.value.version, equalTo(version))
94 assertThat(updateFoundEvent.value.releaseTime, equalTo(releaseTime))
95 assertThat(updateFoundEvent.value.isDisruptive, equalTo(disruptive))
98 private fun verifyThatUpdateCheckerKnowsLatestVersion(version: Version, releaseTime: Long) {
99 assertThat(updateChecker.latestVersion, equalTo(version))
100 assertThat(updateChecker.latestVersionDate, equalTo(releaseTime))
101 assertThat(updateChecker.hasLatestVersion(), equalTo(true))
105 fun `callback does not start if no new edition is found`() {
106 setupFetchResult(createPastFetchResult())
107 setupCallbackWithEdition(updateChecker.latestEdition, true)
108 verifyAFreenetUriIsFetched()
109 verifyNoUpdateFoundEventIsFired()
112 private fun setupFetchResult(pastFetchResult: FetchResult) {
113 whenever(freenetInterface.fetchUri(any(FreenetURI::class.java))).thenAnswer { invocation ->
114 val freenetUri = invocation.arguments[0] as FreenetURI
115 Fetched(freenetUri, pastFetchResult)
119 private fun createPastFetchResult(): FetchResult {
120 val clientMetadata = ClientMetadata("application/xml")
121 val fetched = ArrayBucket(("# MapConfigurationBackendVersion=1\n" +
122 "CurrentVersion/Version: 0.2\n" +
123 "CurrentVersion/ReleaseTime: 1289417883000").toByteArray())
124 return FetchResult(clientMetadata, fetched)
128 fun `invalid update file does not start callback`() {
129 setupFetchResult(createInvalidFetchResult())
130 setupCallbackWithEdition(MAX_VALUE, true)
131 verifyAFreenetUriIsFetched()
132 verifyNoUpdateFoundEventIsFired()
135 private fun createInvalidFetchResult(): FetchResult {
136 val clientMetadata = ClientMetadata("text/plain")
137 val fetched = ArrayBucket("Some other data.".toByteArray())
138 return FetchResult(clientMetadata, fetched)
142 fun `non existing properties will not cause update to be found`() {
143 setupCallbackWithEdition(MAX_VALUE, true)
144 verifyAFreenetUriIsFetched()
145 verifyNoUpdateFoundEventIsFired()
148 private fun verifyNoUpdateFoundEventIsFired() {
149 verify(eventBus, never()).post(any(UpdateFoundEvent::class.java))
152 private fun verifyAFreenetUriIsFetched() {
153 verify(freenetInterface).fetchUri(any(FreenetURI::class.java))
157 fun `broken bucket does not cause update to be found`() {
158 setupFetchResult(createBrokenBucketFetchResult())
159 setupCallbackWithEdition(MAX_VALUE, true)
160 verifyAFreenetUriIsFetched()
161 verifyNoUpdateFoundEventIsFired()
164 private fun createBrokenBucketFetchResult(): FetchResult {
165 val clientMetadata = ClientMetadata("text/plain")
166 val fetched = object : ArrayBucket("Some other data.".toByteArray()) {
167 override fun getInputStream() =
168 whenever(mock<InputStream>().read()).thenThrow(IOException()).getMock<InputStream>()
170 return FetchResult(clientMetadata, fetched)
174 fun `invalid time does not cause an update to be found`() {
175 setupFetchResult(createInvalidTimeFetchResult())
176 setupCallbackWithEdition(MAX_VALUE, true)
177 verifyAFreenetUriIsFetched()
178 verifyNoUpdateFoundEventIsFired()
181 private fun createInvalidTimeFetchResult(): FetchResult {
182 val clientMetadata = ClientMetadata("application/xml")
183 val fetched = ArrayBucket(("# MapConfigurationBackendVersion=1\n" +
184 "CurrentVersion/Version: 0.2\n" +
185 "CurrentVersion/ReleaseTime: invalid").toByteArray())
186 return FetchResult(clientMetadata, fetched)
190 fun `invalid properties does not cause an update to be found`() {
191 setupFetchResult(createMissingTimeFetchResult())
192 setupCallbackWithEdition(MAX_VALUE, true)
193 verifyAFreenetUriIsFetched()
194 verifyNoUpdateFoundEventIsFired()
197 private fun createMissingTimeFetchResult(): FetchResult {
198 val clientMetadata = ClientMetadata("application/xml")
199 val fetched = ArrayBucket(("# MapConfigurationBackendVersion=1\nCurrentVersion/Version: 0.2\n").toByteArray())
200 return FetchResult(clientMetadata, fetched)
204 fun `invalid version does not cause an update to be found`() {
205 setupFetchResult(createInvalidVersionFetchResult())
206 setupCallbackWithEdition(MAX_VALUE, true)
207 verifyAFreenetUriIsFetched()
208 verifyNoUpdateFoundEventIsFired()
211 private fun createInvalidVersionFetchResult(): FetchResult {
212 val clientMetadata = ClientMetadata("application/xml")
213 val fetched = ArrayBucket(("# MapConfigurationBackendVersion=1\n" +
214 "CurrentVersion/Version: foo\n" +
215 "CurrentVersion/ReleaseTime: 1289417883000").toByteArray())
216 return FetchResult(clientMetadata, fetched)
220 fun `disruptive version gets notification`() {
221 setupFetchResult(createDisruptiveVersionFetchResult())
222 setupCallbackWithEdition(MAX_VALUE, true)
223 verifyAFreenetUriIsFetched()
224 verifyEventIsFired(Version(1, 2, 3), 1289417883000L, true)
225 verifyThatUpdateCheckerKnowsLatestVersion(Version(1, 2, 3), 1289417883000L)
228 private fun createDisruptiveVersionFetchResult(): FetchResult {
229 val clientMetadata = ClientMetadata("application/xml")
230 val fetched = ArrayBucket(("# MapConfigurationBackendVersion=1\n" +
231 "CurrentVersion/Version: 1.2.3\n" +
232 "CurrentVersion/ReleaseTime: 1289417883000\n" +
233 "DisruptiveVersion/1.2.3: true").toByteArray())
234 return FetchResult(clientMetadata, fetched)