From eec524ec6c77db42a882e2ae7fda2564650dc3eb Mon Sep 17 00:00:00 2001 From: David Luhmer Date: Fri, 5 Apr 2019 17:04:36 -0300 Subject: [PATCH] update unit tests --- News-Android-App/build.gradle | 3 +- News-Android-App/proguard-rules.pro | 11 ++- .../android/sso/api/NewFeedTests.java | 12 +-- .../owncloudnewsreader/di/TestApiModule.java | 51 +---------- .../di/TestApiProvider.java | 89 +++++++++++++++++++ .../owncloudnewsreader/di/ApiProvider.java | 8 +- 6 files changed, 112 insertions(+), 62 deletions(-) create mode 100644 News-Android-App/src/androidTest/java/de/luhmer/owncloudnewsreader/di/TestApiProvider.java diff --git a/News-Android-App/build.gradle b/News-Android-App/build.gradle index be806a44..57ded969 100644 --- a/News-Android-App/build.gradle +++ b/News-Android-App/build.gradle @@ -114,7 +114,8 @@ dependencies { // implementation 'com.google.android.gms:play-services:4.2.42' //implementation project(':Android-SingleSignOn') //implementation project(path: ':MaterialShowcaseView:library', configuration: 'default') - implementation 'com.github.nextcloud:Android-SingleSignOn:e781a33e01' + //implementation 'com.github.nextcloud:Android-SingleSignOn:e781a33e01' + implementation 'com.github.nextcloud:Android-SingleSignOn:unit-testing-SNAPSHOT' implementation 'com.github.David-Development:MaterialShowcaseView:bf6afa225d' // https://mvnrepository.com/artifact/androidx.legacy/legacy-support-v4 diff --git a/News-Android-App/proguard-rules.pro b/News-Android-App/proguard-rules.pro index ed594186..234e583d 100644 --- a/News-Android-App/proguard-rules.pro +++ b/News-Android-App/proguard-rules.pro @@ -29,8 +29,6 @@ -dontwarn org.mockito.** - - -keepnames class * implements java.io.Serializable -keepclassmembers class * implements java.io.Serializable { @@ -160,4 +158,11 @@ -dontwarn okhttp3.internal.platform.ConscryptPlatform -keep interface org.conscrypt.Conscrypt { *; } --keep class org.conscrypt.Conscrypt { *; } \ No newline at end of file +-keep class org.conscrypt.Conscrypt { *; } + + + +# https://stackoverflow.com/a/39777485 +# Also, note that this rule should be added to the regular proguard file(the one of listed in proguardFiles) and not the test one(declared as testProguardFile) +# java.lang.NoSuchMethodError: No virtual method getParameter +-keepclasseswithmembers public class com.nextcloud.android.sso.aidl.NextcloudRequest { *; } \ No newline at end of file diff --git a/News-Android-App/src/androidTest/java/com/nextcloud/android/sso/api/NewFeedTests.java b/News-Android-App/src/androidTest/java/com/nextcloud/android/sso/api/NewFeedTests.java index 7a8a2b09..3a2353c5 100644 --- a/News-Android-App/src/androidTest/java/com/nextcloud/android/sso/api/NewFeedTests.java +++ b/News-Android-App/src/androidTest/java/com/nextcloud/android/sso/api/NewFeedTests.java @@ -59,8 +59,8 @@ public class NewFeedTests { onView(withId(R.id.btn_addFeed)).perform(click()); try { - API api = mApi.getAPI(); - verify(api, timeout(2000)).createFeed(feed, 0L); + //API api = mApi.getAPI(); + //verify(api, timeout(2000)).createFeed(feed, 0L); //onView(withId(R.id.et_feed_url)).check(matches(hasErrorText(nullValue(String.class)))); @@ -81,8 +81,8 @@ public class NewFeedTests { onView(withId(R.id.btn_addFeed)).perform(click()); try { - API api = mApi.getAPI(); - verify(api, timeout(2000)).createFeed(feed, 0L); + //API api = mApi.getAPI(); + //verify(api, timeout(2000)).createFeed(feed, 0L); // Check Activity still open Thread.sleep(1000); @@ -103,8 +103,8 @@ public class NewFeedTests { onView(withId(R.id.btn_addFeed)).perform(click()); try { - API api = mApi.getAPI(); - verify(api, timeout(2000)).createFeed(feed, 0L); + //API api = mApi.getAPI(); + //verify(api, timeout(2000)).createFeed(feed, 0L); // Check Activity still open Thread.sleep(1000); diff --git a/News-Android-App/src/androidTest/java/de/luhmer/owncloudnewsreader/di/TestApiModule.java b/News-Android-App/src/androidTest/java/de/luhmer/owncloudnewsreader/di/TestApiModule.java index 74450c74..4e00a7a9 100644 --- a/News-Android-App/src/androidTest/java/de/luhmer/owncloudnewsreader/di/TestApiModule.java +++ b/News-Android-App/src/androidTest/java/de/luhmer/owncloudnewsreader/di/TestApiModule.java @@ -5,6 +5,7 @@ import android.content.Context; import android.content.SharedPreferences; import com.nextcloud.android.sso.AccountImporter; +import com.nextcloud.android.sso.api.NextcloudAPI; import com.nextcloud.android.sso.helper.SingleAccountHelper; import com.nextcloud.android.sso.model.SingleSignOnAccount; @@ -16,6 +17,7 @@ import java.util.List; import de.luhmer.owncloudnewsreader.SettingsActivity; import de.luhmer.owncloudnewsreader.database.model.Feed; +import de.luhmer.owncloudnewsreader.helper.GsonConfig; import de.luhmer.owncloudnewsreader.reader.nextcloud.API; import de.luhmer.owncloudnewsreader.ssl.MemorizingTrustManager; import okhttp3.ResponseBody; @@ -79,60 +81,13 @@ public class TestApiModule extends ApiModule { return sharedPrefs; } - private final String NEW_FEED_SUCCESS = "http://test.de/new"; - private final String NEW_FEED_EXISTING = "http://test.de/existing"; - private final String NEW_FEED_FAIL = "http://test.de/fail"; - private final String NEW_FEED_EXISTING_ERROR_MESSAGE = "{\"message\":\"Feed konnte nicht hinzugef\\u00fcgt werden: Existiert bereits\"}"; - private final String NEW_FEED_FAIL_ERROR_MESSAGE = "{\"message\":\"FeedIo\\\\Adapter\\\\NotFoundException: Client error: `GET http:\\/\\/feeds2.feedburner.com\\/stadt-bremerhaven\\/dqXM222` resulted in a `404 Feed not found error: FeedBurner cannot locate this feed URI.` response:\\n\\u003Chtml\\u003E\\n\\u003Chead\\u003E\\n\\u003Cstyle type=\\\"text\\/css\\\"\\u003E\\na:link, a:visited {\\n color: #000099;\\n text-decoration: underline;\\n}\\n\\na:hover {\\n (truncated...)\\n in \\/apps2\\/news\\/lib\\/Fetcher\\/Client\\/FeedIoClient.php:57\\nStack trace:\\n#0 \\/apps2\\/news\\/vendor\\/debril\\/feed-io\\/src\\/FeedIo\\/Reader.php(116): OCA\\\\News\\\\Fetcher\\\\Client\\\\FeedIoClient-\\u003EgetResponse('http:\\/\\/feeds2.f...', Object(DateTime))\\n#1 \\/apps2\\/news\\/vendor\\/debril\\/feed-io\\/src\\/FeedIo\\/FeedIo.php(286): FeedIo\\\\Reader-\\u003Eread('http:\\/\\/feeds2.f...', Object(FeedIo\\\\Feed), Object(DateTime))\\n#2 \\/apps2\\/news\\/lib\\/Fetcher\\/FeedFetcher.php(77): FeedIo\\\\FeedIo-\\u003Eread('http:\\/\\/feeds2.f...')\\n#3 \\/apps2\\/news\\/lib\\/Fetcher\\/Fetcher.php(68): OCA\\\\News\\\\Fetcher\\\\FeedFetcher-\\u003Efetch('http:\\/\\/feeds2.f...', true, NULL, NULL, NULL)\\n#4 \\/apps2\\/news\\/lib\\/Service\\/FeedService.php(116): OCA\\\\News\\\\Fetcher\\\\Fetcher-\\u003Efetch('http:\\/\\/feeds2.f...', true, NULL, NULL, NULL)\\n#5 \\/apps2\\/news\\/lib\\/Controller\\/FeedApiController.php(96): OCA\\\\News\\\\Service\\\\FeedService-\\u003Ecreate('http:\\/\\/feeds2.f...', 0, 'david')\\n#6 \\/nextcloud\\/lib\\/private\\/AppFramework\\/Http\\/Dispatcher.php(166): OCA\\\\News\\\\Controller\\\\FeedApiController-\\u003Ecreate('http:\\/\\/feeds2.f...', 0)\\n#7 \\/nextcloud\\/lib\\/private\\/AppFramework\\/Http\\/Dispatcher.php(99): OC\\\\AppFramework\\\\Http\\\\Dispatcher-\\u003EexecuteController(Object(OCA\\\\News\\\\Controller\\\\FeedApiController), 'create')\\n#8 \\/nextcloud\\/lib\\/private\\/AppFramework\\/App.php(118): OC\\\\AppFramework\\\\Http\\\\Dispatcher-\\u003Edispatch(Object(OCA\\\\News\\\\Controller\\\\FeedApiController), 'create')\\n#9 \\/nextcloud\\/lib\\/private\\/AppFramework\\/Routing\\/RouteActionHandler.php(47): OC\\\\AppFramework\\\\App::main('OCA\\\\\\\\News\\\\\\\\Contro...', 'create', Object(OC\\\\AppFramework\\\\DependencyInjection\\\\DIContainer), Array)\\n#10 [internal function]: OC\\\\AppFramework\\\\Routing\\\\RouteActionHandler-\\u003E__invoke(Array)\\n#11 \\/nextcloud\\/lib\\/private\\/Route\\/Router.php(297): call_user_func(Object(OC\\\\AppFramework\\\\Routing\\\\RouteActionHandler), Array)\\n#12 \\/nextcloud\\/lib\\/base.php(987): OC\\\\Route\\\\Router-\\u003Ematch('\\/apps\\/news\\/api\\/...')\\n#13 \\/nextcloud\\/index.php(42): OC::handleRequest()\\n#14 {main}\"}"; - - @Override ApiProvider provideAPI(MemorizingTrustManager mtm, SharedPreferences sp) { - ApiProvider apiProvider = Mockito.mock(ApiProvider.class); - API api = Mockito.mock(API.class); - when(apiProvider.getAPI()).thenReturn(api); - - Call> mockCallSuccess = mockCreateFeed(NEW_FEED_SUCCESS); - Call> mockCallExisting = mockCreateFeed(NEW_FEED_EXISTING); - Call> mockCallFail = mockCreateFeed(NEW_FEED_FAIL); - - when(api.createFeed(eq(NEW_FEED_SUCCESS), any())).thenReturn(mockCallSuccess); - when(api.createFeed(eq(NEW_FEED_EXISTING), any())).thenReturn(mockCallExisting); - when(api.createFeed(eq(NEW_FEED_FAIL), any())).thenReturn(mockCallFail); - + ApiProvider apiProvider = new TestApiProvider(mtm, sp, application); return apiProvider; } - // https://github.com/nextcloud/news/blob/master/docs/externalapi/Legacy.md#create-a-feed - private Call> mockCreateFeed(String url) { - Call> mockCall = Mockito.mock(Call.class); - doAnswer((Answer) invocation -> { - Object[] args = invocation.getArguments(); - Callback callback = (Callback) args[0]; - final Thread thr = new Thread() { - @Override - public void run() { - switch(url) { - case NEW_FEED_SUCCESS: - callback.onResponse(mockCall, Response.success("")); - break; - case NEW_FEED_EXISTING: - callback.onResponse(mockCall, Response.error(409, ResponseBody.create(null, NEW_FEED_EXISTING_ERROR_MESSAGE))); - break; - case NEW_FEED_FAIL: - callback.onResponse(mockCall,Response.error(422 , ResponseBody.create(null, NEW_FEED_FAIL_ERROR_MESSAGE))); - break; - default: - throw new RuntimeException("URL NOT KNOWN FOR TEST!"); - } - } - }; - thr.start(); - return null; - }).when(mockCall).enqueue(any()); - return mockCall; - } } diff --git a/News-Android-App/src/androidTest/java/de/luhmer/owncloudnewsreader/di/TestApiProvider.java b/News-Android-App/src/androidTest/java/de/luhmer/owncloudnewsreader/di/TestApiProvider.java new file mode 100644 index 00000000..cda8f54e --- /dev/null +++ b/News-Android-App/src/androidTest/java/de/luhmer/owncloudnewsreader/di/TestApiProvider.java @@ -0,0 +1,89 @@ +package de.luhmer.owncloudnewsreader.di; + +import android.content.Context; +import android.content.SharedPreferences; +import android.os.Looper; +import android.os.NetworkOnMainThreadException; +import android.util.Log; + +import com.nextcloud.android.sso.aidl.NextcloudRequest; +import com.nextcloud.android.sso.api.NetworkRequest; +import com.nextcloud.android.sso.api.NextcloudAPI; +import com.nextcloud.android.sso.exceptions.NextcloudHttpRequestFailedException; +import com.nextcloud.android.sso.model.SingleSignOnAccount; + +import java.io.ByteArrayInputStream; +import java.io.InputStream; +import java.lang.reflect.Field; +import java.nio.charset.Charset; +import java.util.function.BiConsumer; + +import de.luhmer.owncloudnewsreader.helper.GsonConfig; +import de.luhmer.owncloudnewsreader.reader.nextcloud.API; +import de.luhmer.owncloudnewsreader.ssl.MemorizingTrustManager; +import retrofit2.NextcloudRetrofitApiBuilder; + +public class TestApiProvider extends ApiProvider { + + + private static final String TAG = TestApiProvider.class.getCanonicalName(); + + TestApiProvider(MemorizingTrustManager mtm, SharedPreferences sp, Context context) { + super(mtm, sp, context); + } + + @Override + protected void initSsoApi(final NextcloudAPI.ApiConnectedListener callback) { + NextcloudAPI nextcloudAPI = new NextcloudAPI(GsonConfig.GetGson(), new NewsTestNetworkRequest(callback)); + mApi = new NextcloudRetrofitApiBuilder(nextcloudAPI, API.mApiEndpoint).create(API.class); + } + + + class NewsTestNetworkRequest extends NetworkRequest { + + NewsTestNetworkRequest(NextcloudAPI.ApiConnectedListener callback) { + super(null, null, callback); + } + + @Override + protected InputStream performNetworkRequest(NextcloudRequest request, InputStream requestBodyInputStream) throws Exception { + if(Looper.myLooper() == Looper.getMainLooper()) { + throw new NetworkOnMainThreadException(); + } + + Log.e(TAG, "Requested URL: " + request.getUrl()); + InputStream inputStream = null; + switch (request.getUrl()) { + case "/index.php/apps/news/api/v1-2/feeds": + inputStream = handleCreateFeed(request); + break; + + } + return inputStream; + } + + + private final String NEW_FEED_SUCCESS = "http://test.de/new"; + private final String NEW_FEED_EXISTING = "http://test.de/existing"; + private final String NEW_FEED_FAIL = "http://test.de/fail"; + private final String NEW_FEED_EXISTING_ERROR_MESSAGE = "{\"message\":\"Feed konnte nicht hinzugef\\u00fcgt werden: Existiert bereits\"}"; + private final String NEW_FEED_FAIL_ERROR_MESSAGE = "{\"message\":\"FeedIo\\\\Adapter\\\\NotFoundException: Client error: `GET http:\\/\\/feeds2.feedburner.com\\/stadt-bremerhaven\\/dqXM222` resulted in a `404 Feed not found error: FeedBurner cannot locate this feed URI.` response:\\n\\u003Chtml\\u003E\\n\\u003Chead\\u003E\\n\\u003Cstyle type=\\\"text\\/css\\\"\\u003E\\na:link, a:visited {\\n color: #000099;\\n text-decoration: underline;\\n}\\n\\na:hover {\\n (truncated...)\\n in \\/apps2\\/news\\/lib\\/Fetcher\\/Client\\/FeedIoClient.php:57\\nStack trace:\\n#0 \\/apps2\\/news\\/vendor\\/debril\\/feed-io\\/src\\/FeedIo\\/Reader.php(116): OCA\\\\News\\\\Fetcher\\\\Client\\\\FeedIoClient-\\u003EgetResponse('http:\\/\\/feeds2.f...', Object(DateTime))\\n#1 \\/apps2\\/news\\/vendor\\/debril\\/feed-io\\/src\\/FeedIo\\/FeedIo.php(286): FeedIo\\\\Reader-\\u003Eread('http:\\/\\/feeds2.f...', Object(FeedIo\\\\Feed), Object(DateTime))\\n#2 \\/apps2\\/news\\/lib\\/Fetcher\\/FeedFetcher.php(77): FeedIo\\\\FeedIo-\\u003Eread('http:\\/\\/feeds2.f...')\\n#3 \\/apps2\\/news\\/lib\\/Fetcher\\/Fetcher.php(68): OCA\\\\News\\\\Fetcher\\\\FeedFetcher-\\u003Efetch('http:\\/\\/feeds2.f...', true, NULL, NULL, NULL)\\n#4 \\/apps2\\/news\\/lib\\/Service\\/FeedService.php(116): OCA\\\\News\\\\Fetcher\\\\Fetcher-\\u003Efetch('http:\\/\\/feeds2.f...', true, NULL, NULL, NULL)\\n#5 \\/apps2\\/news\\/lib\\/Controller\\/FeedApiController.php(96): OCA\\\\News\\\\Service\\\\FeedService-\\u003Ecreate('http:\\/\\/feeds2.f...', 0, 'david')\\n#6 \\/nextcloud\\/lib\\/private\\/AppFramework\\/Http\\/Dispatcher.php(166): OCA\\\\News\\\\Controller\\\\FeedApiController-\\u003Ecreate('http:\\/\\/feeds2.f...', 0)\\n#7 \\/nextcloud\\/lib\\/private\\/AppFramework\\/Http\\/Dispatcher.php(99): OC\\\\AppFramework\\\\Http\\\\Dispatcher-\\u003EexecuteController(Object(OCA\\\\News\\\\Controller\\\\FeedApiController), 'create')\\n#8 \\/nextcloud\\/lib\\/private\\/AppFramework\\/App.php(118): OC\\\\AppFramework\\\\Http\\\\Dispatcher-\\u003Edispatch(Object(OCA\\\\News\\\\Controller\\\\FeedApiController), 'create')\\n#9 \\/nextcloud\\/lib\\/private\\/AppFramework\\/Routing\\/RouteActionHandler.php(47): OC\\\\AppFramework\\\\App::main('OCA\\\\\\\\News\\\\\\\\Contro...', 'create', Object(OC\\\\AppFramework\\\\DependencyInjection\\\\DIContainer), Array)\\n#10 [internal function]: OC\\\\AppFramework\\\\Routing\\\\RouteActionHandler-\\u003E__invoke(Array)\\n#11 \\/nextcloud\\/lib\\/private\\/Route\\/Router.php(297): call_user_func(Object(OC\\\\AppFramework\\\\Routing\\\\RouteActionHandler), Array)\\n#12 \\/nextcloud\\/lib\\/base.php(987): OC\\\\Route\\\\Router-\\u003Ematch('\\/apps\\/news\\/api\\/...')\\n#13 \\/nextcloud\\/index.php(42): OC::handleRequest()\\n#14 {main}\"}"; + + // https://github.com/nextcloud/news/blob/master/docs/externalapi/Legacy.md#create-a-feed + private InputStream handleCreateFeed(NextcloudRequest request) throws NextcloudHttpRequestFailedException { + switch (request.getParameter().get("url")) { + case NEW_FEED_SUCCESS: + return stringToInputStream(""); + case NEW_FEED_EXISTING: + throw new NextcloudHttpRequestFailedException(409, new Throwable(NEW_FEED_EXISTING_ERROR_MESSAGE)); + case NEW_FEED_FAIL: + throw new NextcloudHttpRequestFailedException(422, new Throwable(NEW_FEED_FAIL_ERROR_MESSAGE)); + } + return null; + } + + private InputStream stringToInputStream(String data) { + return new ByteArrayInputStream(data.getBytes(Charset.forName("UTF-8"))); + } + } +} diff --git a/News-Android-App/src/main/java/de/luhmer/owncloudnewsreader/di/ApiProvider.java b/News-Android-App/src/main/java/de/luhmer/owncloudnewsreader/di/ApiProvider.java index ca41b6cd..9870cfd9 100644 --- a/News-Android-App/src/main/java/de/luhmer/owncloudnewsreader/di/ApiProvider.java +++ b/News-Android-App/src/main/java/de/luhmer/owncloudnewsreader/di/ApiProvider.java @@ -36,9 +36,9 @@ public class ApiProvider { private static final String TAG = ApiProvider.class.getCanonicalName(); private final MemorizingTrustManager mMemorizingTrustManager; - private final SharedPreferences mPrefs; - private API mApi; - private Context context; + protected final SharedPreferences mPrefs; + protected Context context; + protected API mApi; public ApiProvider(MemorizingTrustManager mtm, SharedPreferences sp, Context context) { @@ -90,7 +90,7 @@ public class ApiProvider { mApi = retrofit.create(API.class); } - private void initSsoApi(final NextcloudAPI.ApiConnectedListener callback) { + protected void initSsoApi(final NextcloudAPI.ApiConnectedListener callback) { try { SingleSignOnAccount ssoAccount = SingleAccountHelper.getCurrentSingleSignOnAccount(context); NextcloudAPI nextcloudAPI = new NextcloudAPI(context, ssoAccount, GsonConfig.GetGson(), callback);