|
17 | 17 | */ |
18 | 18 | package org.kiwix.kiwixmobile |
19 | 19 |
|
20 | | -import android.Manifest |
21 | | -import androidx.test.core.app.ActivityScenario |
22 | | -import androidx.test.espresso.Espresso |
23 | | -import androidx.test.espresso.IdlingPolicies |
24 | | -import androidx.test.espresso.IdlingRegistry |
25 | | -import androidx.test.espresso.action.ViewActions |
26 | | -import androidx.test.espresso.matcher.ViewMatchers |
27 | 20 | import androidx.test.ext.junit.runners.AndroidJUnit4 |
28 | | -import androidx.test.platform.app.InstrumentationRegistry |
29 | | -import androidx.test.rule.GrantPermissionRule |
30 | | -import com.adevinta.android.barista.interaction.BaristaClickInteractions.clickOn |
31 | | -import com.adevinta.android.barista.interaction.BaristaMenuClickInteractions.clickMenu |
32 | | -import com.adevinta.android.barista.interaction.BaristaSleepInteractions |
| 21 | +import androidx.test.filters.SmallTest |
| 22 | +import kotlinx.coroutines.runBlocking |
| 23 | +import kotlinx.coroutines.test.runTest |
| 24 | +import kotlinx.coroutines.withTimeout |
| 25 | +import okhttp3.OkHttpClient |
| 26 | +import okhttp3.logging.HttpLoggingInterceptor |
| 27 | +import okhttp3.logging.HttpLoggingInterceptor.Level.BASIC |
| 28 | +import okhttp3.mockwebserver.MockResponse |
| 29 | +import okhttp3.mockwebserver.MockWebServer |
| 30 | +import okhttp3.mockwebserver.SocketPolicy |
33 | 31 | import org.junit.After |
| 32 | +import org.junit.Assert.assertEquals |
| 33 | +import org.junit.Assert.assertFalse |
| 34 | +import org.junit.Assert.assertNotNull |
| 35 | +import org.junit.Assert.assertNull |
| 36 | +import org.junit.Assert.assertTrue |
34 | 37 | import org.junit.Before |
35 | | -import org.junit.BeforeClass |
36 | | -import org.junit.Ignore |
37 | 38 | import org.junit.Rule |
38 | 39 | import org.junit.Test |
39 | 40 | import org.junit.runner.RunWith |
40 | | -import org.kiwix.kiwixmobile.core.CoreApp.Companion.coreComponent |
41 | | -import org.kiwix.kiwixmobile.core.R.string |
42 | | -import org.kiwix.kiwixmobile.core.di.components.DaggerTestComponent |
| 41 | +import org.kiwix.kiwixmobile.core.data.remote.KiwixService |
43 | 42 | import org.kiwix.kiwixmobile.core.utils.files.Log |
44 | | -import org.kiwix.kiwixmobile.main.KiwixMainActivity |
45 | | -import org.kiwix.kiwixmobile.testutils.TestUtils |
46 | | -import org.kiwix.kiwixmobile.utils.KiwixIdlingResource.Companion.getInstance |
47 | | -import java.util.concurrent.TimeUnit |
| 43 | +import org.kiwix.kiwixmobile.testutils.RetryRule |
| 44 | +import org.kiwix.sharedFunctions.TEST_PORT |
| 45 | +import java.net.InetAddress |
| 46 | +import java.util.concurrent.TimeUnit.SECONDS |
48 | 47 |
|
49 | 48 | /** |
50 | 49 | * Created by mhutti1 on 14/04/17. |
51 | 50 | */ |
| 51 | +@SmallTest |
52 | 52 | @RunWith(AndroidJUnit4::class) |
53 | 53 | class NetworkTest { |
54 | | - // @Inject |
55 | | - // MockWebServer mockWebServer |
| 54 | + @Rule |
| 55 | + @JvmField |
| 56 | + val retryRule = RetryRule() |
| 57 | + |
| 58 | + private lateinit var mockWebServer: MockWebServer |
| 59 | + private lateinit var kiwixService: KiwixService |
56 | 60 |
|
57 | | - private val permissions = |
58 | | - arrayOf( |
59 | | - Manifest.permission.READ_EXTERNAL_STORAGE, |
60 | | - Manifest.permission.WRITE_EXTERNAL_STORAGE |
| 61 | + @Before |
| 62 | + fun setUp() { |
| 63 | + mockWebServer = MockWebServer() |
| 64 | + mockWebServer.start(InetAddress.getByName("127.0.0.1"), TEST_PORT) |
| 65 | + kiwixService = KiwixService.ServiceCreator.newHackListService( |
| 66 | + OkHttpClient().newBuilder() |
| 67 | + .connectTimeout(TEST_TIMEOUT, SECONDS) |
| 68 | + .readTimeout(TEST_TIMEOUT, SECONDS) |
| 69 | + .callTimeout(TEST_TIMEOUT, SECONDS) |
| 70 | + .addNetworkInterceptor(HttpLoggingInterceptor().apply { level = BASIC }) |
| 71 | + .build(), |
| 72 | + mockWebServer.url("/").toString() |
61 | 73 | ) |
| 74 | + Log.d(TAG, "MockWebServer started on port $TEST_PORT") |
| 75 | + } |
62 | 76 |
|
63 | | - @Rule |
64 | | - @JvmField |
65 | | - var permissionRules: GrantPermissionRule = |
66 | | - GrantPermissionRule.grant(*permissions) |
67 | | - |
68 | | - @Before fun setUp() { |
69 | | - val component = |
70 | | - DaggerTestComponent.builder().context( |
71 | | - InstrumentationRegistry.getInstrumentation().targetContext.applicationContext |
72 | | - ).build() |
73 | | - coreComponent = component |
74 | | - component.inject(this) |
75 | | - val library = NetworkTest::class.java.classLoader.getResourceAsStream("library.xml") |
76 | | - val metalinks = NetworkTest::class.java.classLoader.getResourceAsStream("test.zim.meta4") |
77 | | - val testzim = NetworkTest::class.java.classLoader.getResourceAsStream("testzim.zim") |
78 | | - // try { |
79 | | - // byte[] libraryBytes = IOUtils.toByteArray(library); |
80 | | - // mockWebServer.enqueue(new MockResponse().setBody(new String(libraryBytes))); |
81 | | - // byte[] metalinkBytes = IOUtils.toByteArray(metalinks); |
82 | | - // mockWebServer.enqueue(new MockResponse().setBody(new String(metalinkBytes))); |
83 | | - // mockWebServer.enqueue(new MockResponse().setHeader("Content-Length", 357269)); |
84 | | - // Buffer buffer = new Buffer(); |
85 | | - // buffer.write(IOUtils.toByteArray(testzim)); |
86 | | - // buffer.close(); |
87 | | - // mockWebServer.enqueue(new MockResponse().setBody(buffer)); |
88 | | - // } catch (IOException e) { |
89 | | - // e.printStackTrace(); |
90 | | - // } |
| 77 | + @After |
| 78 | + fun tearDown() { |
| 79 | + mockWebServer.shutdown() |
| 80 | + Log.d(TAG, "MockWebServer shut down") |
91 | 81 | } |
92 | 82 |
|
| 83 | + private fun getResourceAsString(name: String): String = |
| 84 | + javaClass.classLoader!!.getResourceAsStream(name)!!.bufferedReader().readText() |
| 85 | + |
93 | 86 | @Test |
94 | | - @Ignore("Broken in 2.5") // TODO Fix in 3.0 |
95 | | - fun networkTest() { |
96 | | - ActivityScenario.launch(KiwixMainActivity::class.java) |
97 | | - BaristaSleepInteractions.sleep(TestUtils.TEST_PAUSE_MS.toLong()) |
98 | | - clickMenu(TestUtils.getResourceString(string.library)) |
99 | | - TestUtils.allowStoragePermissionsIfNeeded() |
100 | | - // Espresso.onData(TestUtils.withContent("wikipedia_ab_all_2017-03")) |
101 | | - // .inAdapterView(ViewMatchers.withId(R.id.libraryList)) |
102 | | - // .perform(ViewActions.click()) |
103 | | - try { |
104 | | - Espresso.onView(ViewMatchers.withId(android.R.id.button1)).perform(ViewActions.click()) |
105 | | - } catch (e: RuntimeException) { |
106 | | - Log.w(NETWORK_TEST_TAG, "failed to perform click action on the view : ${e.localizedMessage} ") |
107 | | - } |
108 | | - clickOn(string.local_zims) |
109 | | - try { |
110 | | - // Espresso.onData(CoreMatchers.allOf(ViewMatchers.withId(R.id.zim_swiperefresh))) |
111 | | - // refresh(R.id.zim_swiperefresh) |
112 | | - Thread.sleep(500) |
113 | | - } catch (e: InterruptedException) { |
114 | | - e.printStackTrace() |
115 | | - } |
| 87 | + fun testNetworkSuccess() = runTest { |
| 88 | + val libraryXml = getResourceAsString("library.xml") |
| 89 | + mockWebServer.enqueue( |
| 90 | + MockResponse() |
| 91 | + .setResponseCode(200) |
| 92 | + .setBody(libraryXml) |
| 93 | + ) |
| 94 | + |
| 95 | + val response = kiwixService.getLibraryPage(mockWebServer.url("/v2/entries").toString()) |
| 96 | + val recordedRequest = mockWebServer.takeRequest() |
| 97 | + Log.d(TAG, "testNetworkSuccess: code=${response.code()} bodyLength=${response.body()?.length}") |
| 98 | + Log.d(TAG, "testNetworkSuccess: method=${recordedRequest.method} path=${recordedRequest.path}") |
| 99 | + Log.d( |
| 100 | + TAG, |
| 101 | + "testNetworkSuccess: code=${response.code()} bodyLength=${response.body()?.length} bodyPreview=${ |
| 102 | + response.body()?.take(100) |
| 103 | + }" |
| 104 | + ) |
116 | 105 |
|
117 | | - // Commented out the following which assumes only 1 match - not always safe to assume as there may |
118 | | - // already be a similar file on the device. |
119 | | - // onData(withContent("wikipedia_ab_all_2017-03")).inAdapterView(withId(R.id.zimfilelist)).perform(click()); |
120 | | - |
121 | | - // Find matching zim files on the device |
122 | | - // try { |
123 | | - // val dataInteraction = |
124 | | - // Espresso.onData(TestUtils.withContent("wikipedia_ab_all_2017-03")) |
125 | | - // .inAdapterView(ViewMatchers.withId(R.id.zimfilelist)) |
126 | | - // // TODO how can we get a count of the items matching the dataInteraction? |
127 | | - // dataInteraction.atPosition(0).perform(ViewActions.click()) |
128 | | - // clickMenu(string.library) |
129 | | - // val dataInteraction1 = |
130 | | - // Espresso.onData(TestUtils.withContent("wikipedia_ab_all_2017-03")) |
131 | | - // .inAdapterView(ViewMatchers.withId(R.id.zimfilelist)) |
132 | | - // dataInteraction1.atPosition(0).perform(ViewActions.longClick()) // to delete the zim file |
133 | | - // BaristaDialogInteractions.clickDialogPositiveButton() |
134 | | - // } catch (e: Exception) { |
135 | | - // Log.w(NETWORK_TEST_TAG, "failed to interact with local ZIM file: " + e.localizedMessage) |
136 | | - // } |
| 106 | + assertEquals("GET", recordedRequest.method) |
| 107 | + assertTrue(recordedRequest.path!!.startsWith("/v2/entries")) |
| 108 | + assertTrue(response.isSuccessful) |
| 109 | + assertEquals(200, response.code()) |
| 110 | + assertEquals(libraryXml, response.body()) |
137 | 111 | } |
138 | 112 |
|
139 | | - @After fun finish() { |
140 | | - IdlingRegistry.getInstance().unregister(getInstance()) |
| 113 | + @Test |
| 114 | + fun testNetworkError() = runTest { |
| 115 | + mockWebServer.enqueue(MockResponse().setResponseCode(500)) |
| 116 | + |
| 117 | + val response = kiwixService.getLibraryPage(mockWebServer.url("/v2/entries").toString()) |
| 118 | + Log.d(TAG, "testNetworkError: code=${response.code()} body=${response.body()}") |
| 119 | + |
| 120 | + assertFalse(response.isSuccessful) |
| 121 | + assertEquals(500, response.code()) |
| 122 | + assertNull(response.body()) |
| 123 | + assertNotNull(response.errorBody()) |
141 | 124 | } |
142 | 125 |
|
143 | | - companion object { |
144 | | - private const val NETWORK_TEST_TAG = "KiwixNetworkTest" |
| 126 | + @Test |
| 127 | + fun testNetworkNotFound() = runTest { |
| 128 | + mockWebServer.enqueue(MockResponse().setResponseCode(404)) |
| 129 | + |
| 130 | + val response = kiwixService.getLibraryPage(mockWebServer.url("/v2/entries").toString()) |
| 131 | + Log.d(TAG, "testNetworkNotFound: code=${response.code()} body=${response.body()}") |
| 132 | + |
| 133 | + assertFalse(response.isSuccessful) |
| 134 | + assertEquals(404, response.code()) |
| 135 | + assertNull(response.body()) |
| 136 | + assertNotNull(response.errorBody()) |
| 137 | + } |
| 138 | + |
| 139 | + @Test |
| 140 | + fun testNetworkEmptyResponse() = runTest { |
| 141 | + mockWebServer.enqueue( |
| 142 | + MockResponse() |
| 143 | + .setResponseCode(200) |
| 144 | + .setBody("") |
| 145 | + ) |
| 146 | + |
| 147 | + val response = kiwixService.getLibraryPage(mockWebServer.url("/v2/entries").toString()) |
| 148 | + Log.d(TAG, "testNetworkEmptyResponse: code=${response.code()} body='${response.body()}'") |
| 149 | + |
| 150 | + assertTrue(response.isSuccessful) |
| 151 | + assertEquals(200, response.code()) |
| 152 | + assertEquals("", response.body()) |
| 153 | + } |
145 | 154 |
|
146 | | - @BeforeClass fun beforeClass() { |
147 | | - IdlingPolicies.setMasterPolicyTimeout(180, TimeUnit.SECONDS) |
148 | | - IdlingPolicies.setIdlingResourceTimeout(180, TimeUnit.SECONDS) |
149 | | - IdlingRegistry.getInstance().register(getInstance()) |
| 155 | + @Test |
| 156 | + fun testNetworkTimeout() { |
| 157 | + mockWebServer.enqueue( |
| 158 | + MockResponse().apply { socketPolicy = SocketPolicy.NO_RESPONSE } |
| 159 | + ) |
| 160 | + |
| 161 | + var exceptionThrown = false |
| 162 | + try { |
| 163 | + runBlocking { |
| 164 | + withTimeout((TEST_TIMEOUT + 2L) * 1000L) { |
| 165 | + kiwixService.getLibraryPage(mockWebServer.url("/v2/entries").toString()) |
| 166 | + } |
| 167 | + } |
| 168 | + } catch (e: Exception) { |
| 169 | + Log.e(TAG, "testNetworkTimeout: caught expected ${e::class.java.simpleName}: ${e.message}") |
| 170 | + exceptionThrown = true |
150 | 171 | } |
| 172 | + |
| 173 | + assertTrue("Expected a timeout exception to be thrown", exceptionThrown) |
| 174 | + } |
| 175 | + |
| 176 | + companion object { |
| 177 | + private const val TAG = "NetworkTest" |
| 178 | + private const val TEST_TIMEOUT = 5L |
151 | 179 | } |
152 | 180 | } |
0 commit comments