123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262 |
- /*
- * Nextcloud Android client application
- *
- * @author Chris Narkiewicz
- * Copyright (C) 2019 Chris Narkiewicz <hello@ezaquarii.com>
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
- package com.nextcloud.client.network
- import android.net.ConnectivityManager
- import android.net.NetworkInfo
- import com.nextcloud.client.account.Server
- import com.nextcloud.client.account.User
- import com.nextcloud.client.account.UserAccountManager
- import com.nextcloud.client.logger.Logger
- import com.nhaarman.mockitokotlin2.any
- import com.nhaarman.mockitokotlin2.mock
- import com.nhaarman.mockitokotlin2.never
- import com.nhaarman.mockitokotlin2.verify
- import com.nhaarman.mockitokotlin2.whenever
- import com.owncloud.android.lib.resources.status.OwnCloudVersion
- import org.apache.commons.httpclient.HttpClient
- import org.apache.commons.httpclient.HttpStatus
- import org.apache.commons.httpclient.methods.GetMethod
- import org.junit.Assert.assertFalse
- import org.junit.Assert.assertTrue
- import org.junit.Before
- import org.junit.Test
- import org.junit.runner.RunWith
- import org.junit.runners.Suite
- import org.mockito.ArgumentCaptor
- import org.mockito.Mock
- import org.mockito.MockitoAnnotations
- import java.net.URI
- @RunWith(Suite::class)
- @Suite.SuiteClasses(
- ConnectivityServiceTest.IsConnected::class,
- ConnectivityServiceTest.WifiConnectionWalledStatusOnLegacyServer::class,
- ConnectivityServiceTest.WifiConnectionWalledStatus::class
- )
- class ConnectivityServiceTest {
- internal abstract class Base {
- companion object {
- fun mockNetworkInfo(connected: Boolean, connecting: Boolean, type: Int): NetworkInfo {
- val networkInfo = mock<NetworkInfo>()
- whenever(networkInfo.isConnectedOrConnecting).thenReturn(connected or connecting)
- whenever(networkInfo.isConnected).thenReturn(connected)
- whenever(networkInfo.type).thenReturn(type)
- return networkInfo
- }
- const val SERVER_BASE_URL = "https://test.server.com"
- }
- @Mock
- lateinit var platformConnectivityManager: ConnectivityManager
- @Mock
- lateinit var networkInfo: NetworkInfo
- @Mock
- lateinit var accountManager: UserAccountManager
- @Mock
- lateinit var clientFactory: ClientFactory
- @Mock
- lateinit var client: HttpClient
- @Mock
- lateinit var getRequest: GetMethod
- @Mock
- lateinit var requestBuilder: ConnectivityServiceImpl.GetRequestBuilder
- @Mock
- lateinit var logger: Logger
- val baseServerUri = URI.create(SERVER_BASE_URL)
- val newServer = Server(baseServerUri, OwnCloudVersion.nextcloud_14)
- val legacyServer = Server(baseServerUri, OwnCloudVersion.nextcloud_13)
- @Mock
- lateinit var user: User
- lateinit var connectivityService: ConnectivityServiceImpl
- @Before
- fun setUpMocks() {
- MockitoAnnotations.initMocks(this)
- connectivityService = ConnectivityServiceImpl(
- platformConnectivityManager,
- accountManager,
- clientFactory,
- requestBuilder,
- logger
- )
- whenever(platformConnectivityManager.activeNetworkInfo).thenReturn(networkInfo)
- whenever(requestBuilder.invoke(any())).thenReturn(getRequest)
- whenever(clientFactory.createPlainClient()).thenReturn(client)
- whenever(user.server).thenReturn(newServer)
- whenever(accountManager.user).thenReturn(user)
- }
- }
- internal class IsConnected : Base() {
- @Test
- fun `connected to wifi`() {
- whenever(networkInfo.isConnectedOrConnecting).thenReturn(true)
- whenever(networkInfo.type).thenReturn(ConnectivityManager.TYPE_WIFI)
- assertTrue(connectivityService.isOnlineWithWifi)
- }
- @Test
- fun `connected to wifi and vpn`() {
- whenever(networkInfo.isConnectedOrConnecting).thenReturn(true)
- whenever(networkInfo.type).thenReturn(ConnectivityManager.TYPE_VPN)
- val wifiNetworkInfoList = arrayOf(
- mockNetworkInfo(
- connected = true,
- connecting = true,
- type = ConnectivityManager.TYPE_VPN
- ),
- mockNetworkInfo(
- connected = true,
- connecting = true,
- type = ConnectivityManager.TYPE_WIFI
- )
- )
- whenever(platformConnectivityManager.allNetworkInfo).thenReturn(wifiNetworkInfoList)
- assertTrue(connectivityService.isOnlineWithWifi)
- }
- @Test
- fun `connected to mobile network`() {
- whenever(networkInfo.isConnectedOrConnecting).thenReturn(true)
- whenever(networkInfo.type).thenReturn(ConnectivityManager.TYPE_MOBILE)
- assertFalse(connectivityService.isOnlineWithWifi)
- }
- }
- internal class WifiConnectionWalledStatusOnLegacyServer : Base() {
- @Before
- fun setUp() {
- whenever(networkInfo.isConnectedOrConnecting).thenReturn(true)
- whenever(networkInfo.type).thenReturn(ConnectivityManager.TYPE_WIFI)
- whenever(user.server).thenReturn(legacyServer)
- assertTrue("Precondition failed", connectivityService.isOnlineWithWifi)
- }
- fun mockResponse(maintenance: Boolean = true, httpStatus: Int = HttpStatus.SC_OK) {
- whenever(client.executeMethod(getRequest)).thenReturn(httpStatus)
- val body = """{"maintenance":$maintenance}"""
- whenever(getRequest.responseContentLength).thenReturn(body.length.toLong())
- whenever(getRequest.responseBodyAsString).thenReturn(body)
- }
- @Test
- fun `false maintenance status flag is used`() {
- mockResponse(maintenance = false, httpStatus = HttpStatus.SC_OK)
- assertFalse(connectivityService.isInternetWalled)
- }
- @Test
- fun `true maintenance status flag is used`() {
- mockResponse(maintenance = true, httpStatus = HttpStatus.SC_OK)
- assertTrue(connectivityService.isInternetWalled)
- }
- @Test
- fun `maintenance flag is ignored when non-200 HTTP code is returned`() {
- mockResponse(maintenance = false, httpStatus = HttpStatus.SC_NO_CONTENT)
- assertTrue(connectivityService.isInternetWalled)
- }
- @Test
- fun `status endpoint is used to determine internet state`() {
- mockResponse()
- connectivityService.isInternetWalled
- val urlCaptor = ArgumentCaptor.forClass(String::class.java)
- verify(requestBuilder).invoke(urlCaptor.capture())
- assertTrue("Invalid URL used to check status", urlCaptor.value.endsWith("/status.php"))
- }
- }
- internal class WifiConnectionWalledStatus : Base() {
- @Before
- fun setUp() {
- whenever(networkInfo.isConnectedOrConnecting).thenReturn(true)
- whenever(networkInfo.type).thenReturn(ConnectivityManager.TYPE_WIFI)
- whenever(accountManager.getServerVersion(any())).thenReturn(OwnCloudVersion.nextcloud_14)
- assertTrue("Precondition failed", connectivityService.isOnlineWithWifi)
- }
- @Test
- fun `check request is not sent when server uri is not set`() {
- // GIVEN
- // network connectivity is present
- // user has no server URI (empty)
- val serverWithoutUri = Server(URI(""), OwnCloudVersion.nextcloud_14)
- whenever(user.server).thenReturn(serverWithoutUri)
- // WHEN
- // connectivity is checked
- val result = connectivityService.isInternetWalled
- // THEN
- // connection is walled
- // request is not sent
- assertTrue("Server should not be accessible", result)
- verify(requestBuilder, never()).invoke(any())
- verify(client, never()).executeMethod(any())
- verify(client, never()).executeMethod(any(), any())
- verify(client, never()).executeMethod(any(), any(), any())
- }
- fun mockResponse(contentLength: Long = 0, status: Int = HttpStatus.SC_OK) {
- whenever(client.executeMethod(any())).thenReturn(status)
- whenever(getRequest.statusCode).thenReturn(status)
- whenever(getRequest.responseContentLength).thenReturn(contentLength)
- }
- @Test
- fun `status 204 means internet is not walled`() {
- mockResponse(contentLength = 0, status = HttpStatus.SC_NO_CONTENT)
- assertFalse(connectivityService.isInternetWalled)
- }
- @Test
- fun `other status than 204 means internet is walled`() {
- mockResponse(contentLength = 0, status = HttpStatus.SC_GONE)
- assertTrue(connectivityService.isInternetWalled)
- }
- @Test
- fun `index endpoint is used to determine internet state`() {
- mockResponse()
- connectivityService.isInternetWalled
- val urlCaptor = ArgumentCaptor.forClass(String::class.java)
- verify(requestBuilder).invoke(urlCaptor.capture())
- assertTrue("Invalid URL used to check status", urlCaptor.value.endsWith("/index.php/204"))
- }
- }
- }
|