#1175 automate code coverage

This commit is contained in:
Sean Mac Gillicuddy 2019-05-23 13:02:25 +01:00
parent aa01598e27
commit 6e8b1ffbb2
10 changed files with 192 additions and 129 deletions

View File

@ -4,9 +4,16 @@ jdk: oraclejdk8
sudo: required
env:
global:
- ANDROID_TARGET=android-22
- ANDROID_ABI=arm64-v8a
install:
- pip install --user 'requests[security]'
- wget -r -nH -nd -np -R index.html* robots.txt* http://download.kiwix.org/dev/android/api/licenses/ -e robots=off -P $ANDROID_HOME/licenses || true
- wget -r -nH -nd -np -R index.html* robots.txt* http://download.kiwix.org/dev/android/api/licenses/
-e robots=off -P $ANDROID_HOME/licenses || true
before_cache:
- rm -f $HOME/.gradle/caches/modules-2/modules-2.lock
@ -14,9 +21,9 @@ before_cache:
cache:
directories:
- $HOME/.gradle/caches/
- $HOME/.gradle/wrapper/
- $HOME/.android/build-cache
- "$HOME/.gradle/caches/"
- "$HOME/.gradle/wrapper/"
- "$HOME/.android/build-cache"
android:
components:
@ -25,8 +32,23 @@ android:
- tools
- build-tools-27.0.3
- android-27
- extra-android-m2repository
- $ANDROID_TARGET
- sys-img-${ANDROID_ABI}-${ANDROID_TARGET}
licenses:
- '.+'
- ".+"
script: ./gradlew assembleKiwixRelease testdroidUploadKiwix && ./testdroid.py
script:
- ./gradlew assembleKiwixDebug jacocoTestKiwixDebugUnitTestReport
- echo no | android create avd --force -n test -t $ANDROID_TARGET --abi $ANDROID_ABI
- emulator -avd test -no-skin -no-audio -no-window &
- android-wait-for-emulator
- adb shell setprop dalvik.vm.dexopt-flags v=n,o=v
- ./gradlew createKiwixDebugCoverageReport
- if [ "$TRAVIS_BRANCH" == "release" ];
then ./gradlew publishKiwixRelease; fi
after_success:
- bash <(curl -s https://codecov.io/bash)
- ./gradlew testdroidUploadKiwixDebug

View File

@ -1,3 +1,4 @@
import com.android.build.OutputFile
import groovy.json.JsonSlurper
buildscript {
@ -13,13 +14,18 @@ buildscript {
}
}
apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'
apply plugin: 'kotlin-android-extensions'
apply plugin: 'kotlin-kapt'
apply plugin: 'checkstyle'
plugins {
id 'com.android.application'
id 'kotlin-android'
id 'kotlin-android-extensions'
id 'kotlin-kapt'
id 'checkstyle'
id 'io.objectbox'
id 'com.github.triplet.play' version '2.2.1'
}
apply plugin: 'testdroid'
apply plugin: 'io.objectbox'
apply plugin: 'jacoco-android'
repositories {
mavenCentral()
@ -30,7 +36,7 @@ repositories {
google()
}
String[] archs = ['arm64-v8a', 'armeabi', 'mips', 'mips64', 'x86', 'x86_64']
String[] archs = ['arm64-v8a', 'armeabi-v7a', 'x86', 'x86_64']
dependencies {
// Get kiwixlib online if it is not populated locally
@ -67,7 +73,7 @@ dependencies {
exclude group: 'com.android.support', module: 'recyclerview-v7'
}
androidTestCompile('com.schibsted.spain:barista:2.4.0') {
androidTestImplementation('com.schibsted.spain:barista:2.4.0') {
exclude group: 'com.android.support'
}
@ -118,19 +124,10 @@ dependencies {
androidTestImplementation "org.mockito:mockito-android:2.24.5"
// Leak canary
implementation 'com.squareup.leakcanary:leakcanary-android-no-op:1.6.3'
// Only enable leak canary in debug builds
configurations.all { config ->
if (config.name.contains('debug') || config.name.contains("Debug")) {
config.resolutionStrategy.eachDependency { details ->
if (details.requested.group == 'com.squareup.leakcanary' &&
details.requested.name == 'leakcanary-android-no-op') {
details.useTarget(group: details.requested.group, name: 'leakcanary-android',
version: details.requested.version)
}
}
}
}
debugImplementation 'com.squareup.leakcanary:leakcanary-android:1.6.3'
androidTestImplementation 'com.squareup.leakcanary:leakcanary-android-no-op:1.6.3'
releaseImplementation 'com.squareup.leakcanary:leakcanary-android-no-op:1.6.3'
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
implementation 'com.android.support.constraint:constraint-layout:1.1.3'
implementation "android.arch.lifecycle:extensions:1.1.1"
@ -146,17 +143,28 @@ if (project.hasProperty('customDir')) {
}
// Set up flavours for each custom app in the directory
if(custom.listFiles()) {
if (custom.listFiles()) {
custom.eachFile() { file ->
def fileName = file.getName()
if (fileName.startsWith(".") || fileName.contains("test") || fileName == "main" || fileName.contains("Test")) {
if (fileName.startsWith(".") ||
fileName.contains("test") ||
fileName == "main" ||
fileName.contains("Test")) {
return
}
map.put(fileName, file.getAbsolutePath())
}
}
jacoco {
toolVersion = "0.8.3"
}
tasks.withType(Test) {
jacoco.includeNoLocationClasses = true
}
android {
compileSdkVersion 27
@ -197,8 +205,7 @@ android {
debug {
buildConfigField "String", "KIWIX_DOWNLOAD_URL", "\"http://download.kiwix.org/\""
buildConfigField "boolean", "KIWIX_ERROR_ACTIVITY", "false"
// True breaks local variables being shown in breakpoints
testCoverageEnabled false
testCoverageEnabled true
}
mock_network {
@ -213,19 +220,11 @@ android {
matchingFallbacks = ['debug', 'release']
}
// Used to assess code coverage
coverage {
initWith debug
testCoverageEnabled true
matchingFallbacks = ['debug', 'release']
}
// Release Type
release {
buildConfigField "String", "KIWIX_DOWNLOAD_URL", "\"http://download.kiwix.org/\""
buildConfigField "boolean", "KIWIX_ERROR_ACTIVITY", "false"
}
}
productFlavors {
@ -253,6 +252,7 @@ android {
versionName "2.5"
}
}
// Custom apps built from a json file, zim file and icon set
map.each { name, directory ->
"$name" {
@ -274,15 +274,15 @@ android {
sourceFile = file(directory + "/" + parsedJson.zim_file)
}
if (parsedJson.embed_zim) {
// Place content in each lib directory for embeded zims
// Place content in each lib directory for embeded zims
for (String archName : archs) {
copy {
from sourceFile
into file(directory + "/jniLibs/" + archName)
rename { String filename -> "libcontent.so" }
}
}
parsedJson.zim_file = "libcontent.so"
copy {
from sourceFile
into file(directory + "/jniLibs/" + archName)
rename { String filename -> "libcontent.so" }
}
}
parsedJson.zim_file = "libcontent.so"
}
// Set custom config from json
applicationId "$parsedJson.package"
@ -318,7 +318,7 @@ android {
buildConfigField "int", "CONTENT_VERSION_CODE", "$content_version_code"
} else if (parsedJson.content_version_code != null) {
buildConfigField "int", "CONTENT_VERSION_CODE", "$parsedJson.content_version_code"
} else if (project.hasProperty('version_code')) {
} else if (project.hasProperty('version_code')) {
def version_code = project.property('version_code')
buildConfigField "int", "CONTENT_VERSION_CODE", "$version_code"
} else if (parsedJson.version_code != null) {

View File

@ -17,18 +17,17 @@
*/
package org.kiwix.kiwixmobile.di.components;
import android.content.Context;
import dagger.BindsInstance;
import dagger.Component;
import javax.inject.Singleton;
import org.kiwix.kiwixmobile.di.modules.ApplicationModule;
import org.kiwix.kiwixmobile.di.modules.JNIModule;
import org.kiwix.kiwixmobile.di.modules.TestJNIModule;
import org.kiwix.kiwixmobile.di.modules.TestNetworkModule;
import org.kiwix.kiwixmobile.tests.NetworkTest;
import org.kiwix.kiwixmobile.tests.ZimTest;
import org.kiwix.kiwixmobile.utils.TestNetworkInterceptor;
import javax.inject.Singleton;
import dagger.Component;
/**
* Created by mhutti1 on 13/04/17.
*/
@ -41,6 +40,14 @@ import dagger.Component;
})
public interface TestComponent extends ApplicationComponent {
@Component.Builder
interface Builder {
@BindsInstance TestComponent.Builder context(Context context);
TestComponent build();
}
void inject(ZimTest zimTest);
void inject(NetworkTest networkTest);

View File

@ -17,7 +17,6 @@
*/
package org.kiwix.kiwixmobile.di.modules;
import org.apache.commons.io.IOUtils;
import org.kiwix.kiwixlib.JNIKiwix;
import org.kiwix.kiwixlib.JNIKiwixString;
import org.mockito.Mockito;

View File

@ -18,48 +18,44 @@
package org.kiwix.kiwixmobile.tests;
import android.Manifest;
import android.support.test.espresso.Espresso;
import android.support.test.espresso.IdlingPolicies;
import android.support.test.espresso.ViewInteraction;
import android.support.test.rule.ActivityTestRule;
import android.support.test.rule.GrantPermissionRule;
import android.support.test.runner.AndroidJUnit4;
import android.test.suitebuilder.annotation.LargeTest;
import android.util.Log;
import com.schibsted.spain.barista.interaction.BaristaSleepInteractions;
import java.util.concurrent.TimeUnit;
import org.junit.After;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Ignore;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.kiwix.kiwixmobile.R;
import org.kiwix.kiwixmobile.utils.KiwixIdlingResource;
import org.kiwix.kiwixmobile.utils.SplashActivity;
import android.Manifest;
import android.support.test.espresso.Espresso;
import android.support.test.espresso.IdlingPolicies;
import android.support.test.espresso.ViewInteraction;
import android.support.test.rule.ActivityTestRule;
import android.support.test.runner.AndroidJUnit4;
import android.support.test.rule.GrantPermissionRule;
import android.test.suitebuilder.annotation.LargeTest;
import android.util.Log;
import com.schibsted.spain.barista.interaction.BaristaSleepInteractions;
import org.junit.After;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.kiwix.kiwixmobile.R;
import org.kiwix.kiwixmobile.utils.KiwixIdlingResource;
import org.kiwix.kiwixmobile.utils.SplashActivity;
import java.util.concurrent.TimeUnit;
import static android.support.test.espresso.Espresso.onData;
import static android.support.test.espresso.Espresso.onView;
import static android.support.test.espresso.action.ViewActions.click;
import static android.support.test.espresso.matcher.ViewMatchers.isDisplayed;
import static android.support.test.espresso.matcher.ViewMatchers.withId;
import static android.support.test.espresso.matcher.ViewMatchers.withParent;
import static com.schibsted.spain.barista.assertion.BaristaVisibilityAssertions.assertDisplayed;
import static com.schibsted.spain.barista.interaction.BaristaClickInteractions.clickOn;
import static com.schibsted.spain.barista.interaction.BaristaSwipeRefreshInteractions.refresh;
import static junit.framework.Assert.fail;
import static org.hamcrest.Matchers.allOf;
import static org.kiwix.kiwixmobile.testutils.TestUtils.TEST_PAUSE_MS;
import static org.kiwix.kiwixmobile.testutils.TestUtils.allowPermissionsIfNeeded;
import static org.kiwix.kiwixmobile.testutils.TestUtils.captureAndSaveScreenshot;
import static org.kiwix.kiwixmobile.testutils.TestUtils.withContent;
import static org.kiwix.kiwixmobile.utils.StandardActions.deleteZimIfExists;
import static org.kiwix.kiwixmobile.utils.StandardActions.enterHelp;
import static android.support.test.espresso.Espresso.onData;
import static android.support.test.espresso.Espresso.onView;
import static android.support.test.espresso.matcher.ViewMatchers.isDisplayed;
import static android.support.test.espresso.matcher.ViewMatchers.withId;
import static android.support.test.espresso.matcher.ViewMatchers.withParent;
import static com.schibsted.spain.barista.assertion.BaristaVisibilityAssertions.assertDisplayed;
import static com.schibsted.spain.barista.interaction.BaristaClickInteractions.clickOn;
import static com.schibsted.spain.barista.interaction.BaristaSwipeRefreshInteractions.refresh;
import static junit.framework.Assert.fail;
import static org.hamcrest.Matchers.allOf;
import static org.kiwix.kiwixmobile.testutils.TestUtils.TEST_PAUSE_MS;
import static org.kiwix.kiwixmobile.testutils.TestUtils.allowPermissionsIfNeeded;
import static org.kiwix.kiwixmobile.testutils.TestUtils.captureAndSaveScreenshot;
import static org.kiwix.kiwixmobile.testutils.TestUtils.withContent;
import static org.kiwix.kiwixmobile.utils.StandardActions.deleteZimIfExists;
import static org.kiwix.kiwixmobile.utils.StandardActions.enterHelp;
@LargeTest
@RunWith(AndroidJUnit4.class)
@ -85,6 +81,7 @@ public class DownloadTest {
}
@Test
@Ignore("Broken in 2.5")//TODO: Fix in 3.0
public void downloadTest() {
enterHelp();
clickOn(R.string.menu_zim_manager);
@ -97,12 +94,6 @@ public class DownloadTest {
clickOn(R.string.remote_zims);
try {
clickOn(R.id.network_permission_button);
} catch (RuntimeException e) {
Log.d(KIWIX_DOWNLOAD_TEST, "Failed to click Network Permission Button", e);
}
captureAndSaveScreenshot("Before-checking-for-ZimManager-Main-Activity");
ViewInteraction viewPager2 = onView(
allOf(withId(R.id.manageViewPager),

View File

@ -24,11 +24,19 @@ import android.support.test.espresso.IdlingPolicies;
import android.support.test.rule.ActivityTestRule;
import android.support.test.rule.GrantPermissionRule;
import android.util.Log;
import org.apache.commons.io.IOUtils;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.concurrent.TimeUnit;
import javax.inject.Inject;
import okhttp3.mockwebserver.MockResponse;
import okhttp3.mockwebserver.MockWebServer;
import okio.Buffer;
import org.junit.After;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Ignore;
import org.junit.Rule;
import org.junit.Test;
import org.kiwix.kiwixmobile.KiwixApplication;
@ -37,20 +45,10 @@ import org.kiwix.kiwixmobile.R;
import org.kiwix.kiwixmobile.ZimContentProvider;
import org.kiwix.kiwixmobile.di.components.DaggerTestComponent;
import org.kiwix.kiwixmobile.di.components.TestComponent;
import org.kiwix.kiwixmobile.di.modules.ApplicationModule;
import org.kiwix.kiwixmobile.testutils.TestUtils;
import org.kiwix.kiwixmobile.utils.IOUtils;
import org.kiwix.kiwixmobile.utils.KiwixIdlingResource;
import java.io.IOException;
import java.io.InputStream;
import java.util.concurrent.TimeUnit;
import javax.inject.Inject;
import okhttp3.mockwebserver.MockResponse;
import okhttp3.mockwebserver.MockWebServer;
import okio.Buffer;
import static android.support.test.InstrumentationRegistry.getInstrumentation;
import static android.support.test.espresso.Espresso.onData;
import static android.support.test.espresso.Espresso.onView;
@ -93,9 +91,8 @@ public class NetworkTest {
@Before
public void setUp() {
TestComponent component = DaggerTestComponent.builder().applicationModule
(new ApplicationModule(
(KiwixApplication) getInstrumentation().getTargetContext().getApplicationContext())).build();
TestComponent component = DaggerTestComponent.builder().context(
getInstrumentation().getTargetContext().getApplicationContext()).build();
((KiwixApplication) getInstrumentation().getTargetContext().getApplicationContext()).setApplicationComponent(component);
@ -121,6 +118,7 @@ public class NetworkTest {
@Test
@Ignore("Broken in 2.5")//TODO: Fix in 3.0
public void networkTest() {
mActivityTestRule.launchActivity(null);
@ -130,13 +128,6 @@ public class NetworkTest {
TestUtils.allowPermissionsIfNeeded();
try {
onView(withId(R.id.network_permission_button)).perform(click());
} catch (RuntimeException e) {
Log.i(NETWORK_TEST_TAG,
"Permission dialog was not shown, we probably already have required permissions");
}
onData(withContent("wikipedia_ab_all_2017-03")).inAdapterView(withId(R.id.libraryList)).perform(click());
try {

View File

@ -0,0 +1,57 @@
package org.kiwix.kiwixmobile.utils;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
/*
* Kiwix Android
* Copyright (C) 2018 Kiwix <android.kiwix.org>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
public class IOUtils {
private IOUtils() {
//utility class
}
private static final int DEFAULT_BUFFER_SIZE = 1024 * 4;
private static final int EOF = -1;
public static byte[] toByteArray(final InputStream input) throws IOException {
try (final ByteArrayOutputStream output = new ByteArrayOutputStream()) {
copy(input, output);
return output.toByteArray();
}
}
private static int copy(final InputStream input, final OutputStream output) throws IOException {
final long count = copyLarge(input, output);
if (count > Integer.MAX_VALUE) {
return -1;
}
return (int) count;
}
private static long copyLarge(final InputStream input, final OutputStream output) throws IOException {
final byte[] buffer = new byte[DEFAULT_BUFFER_SIZE];
long count = 0;
int n;
while (EOF != (n = input.read(buffer))) {
output.write(buffer, 0, n);
count += n;
}
return count;
}
}

View File

@ -176,8 +176,6 @@
</receiver>
<service android:name=".downloader.DownloadService" />
<activity
android:name=".KiwixErrorActivity"
android:process=":error_activity" />

View File

@ -26,7 +26,6 @@ import org.kiwix.kiwixmobile.ZimContentProvider;
import org.kiwix.kiwixmobile.di.modules.ApplicationModule;
import org.kiwix.kiwixmobile.di.modules.JNIModule;
import org.kiwix.kiwixmobile.di.modules.NetworkModule;
import org.kiwix.kiwixmobile.downloader.DownloadService;
import org.kiwix.kiwixmobile.settings.KiwixSettingsActivity;
import org.kiwix.kiwixmobile.views.AutoCompleteAdapter;
import org.kiwix.kiwixmobile.views.web.KiwixWebView;
@ -52,8 +51,6 @@ public interface ApplicationComponent {
void inject(KiwixApplication application);
void inject(DownloadService service);
void inject(ZimContentProvider zimContentProvider);
void inject(KiwixWebView kiwixWebView);

View File

@ -9,6 +9,7 @@ buildscript {
classpath 'com.android.tools.build:gradle:3.4.1'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
classpath "io.objectbox:objectbox-gradle-plugin:$objectboxVersion"
classpath 'com.dicedmelon.gradle:jacoco-android:0.1.4'
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files