Enhance screenshot handling

Signed-off-by: tobiasKaminsky <tobias@kaminsky.me>
This commit is contained in:
tobiasKaminsky 2021-07-15 09:00:38 +02:00
parent 545197d68c
commit a57f8eb989
No known key found for this signature in database
GPG key ID: 0E00D4D47D0C5AF7
26 changed files with 233 additions and 35 deletions

View file

@ -214,3 +214,57 @@ trigger:
event: event:
- push - push
- pull_request - pull_request
---
kind: pipeline
type: docker
name: allScreenshots
steps:
- name: runAllScreenshots
image: nextcloudci/android8:android-61
privileged: true
environment:
GIT_USERNAME:
from_secret: GIT_USERNAME
GIT_TOKEN:
from_secret: GIT_TOKEN
LOG_USERNAME:
from_secret: LOG_USERNAME
LOG_PASSWORD:
from_secret: LOG_PASSWORD
commands:
- emulator -avd android -no-snapshot -gpu swiftshader_indirect -no-window -no-audio -skin 500x833 &
- sed -i s'#<bool name="is_beta">false</bool>#<bool name="is_beta">true</bool>#'g src/main/res/values/setup.xml
- sed -i s'#showOnlyFailingTestsInReports = ciBuild#showOnlyFailingTestsInReports = false#' build.gradle
- scripts/wait_for_emulator.sh
- scripts/runAllScreenshotCombinations noCI false
- scripts/screenshotSummary.sh
- name: notify
image: drillster/drone-email
settings:
port: 587
from: nextcloud-drone@kaminsky.me
recipients_only: true
username:
from_secret: EMAIL_USERNAME
password:
from_secret: EMAIL_PASSWORD
recipients:
from_secret: EMAIL_RECIPIENTS
host:
from_secret: EMAIL_HOST
when:
event:
- push
status:
- failure
branch:
- master
- stable-*
trigger:
branch:
- master
event:
- cron
cron:
- nightly

View file

@ -10,8 +10,8 @@ jobs:
strategy: strategy:
fail-fast: false fail-fast: false
matrix: matrix:
scheme: [ Dark, Light ] scheme: [ Light ]
color: [ blue, white, black ] color: [ blue ]
steps: steps:
- uses: actions/checkout@v2 - uses: actions/checkout@v2
- name: set up JDK 1.8 - name: set up JDK 1.8

Binary file not shown.

Before

Width:  |  Height:  |  Size: 20 KiB

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.5 KiB

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 35 KiB

After

Width:  |  Height:  |  Size: 35 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 29 KiB

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.9 KiB

After

Width:  |  Height:  |  Size: 5.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.2 KiB

After

Width:  |  Height:  |  Size: 8.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.6 KiB

After

Width:  |  Height:  |  Size: 5.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.6 KiB

After

Width:  |  Height:  |  Size: 6.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.3 KiB

After

Width:  |  Height:  |  Size: 9.3 KiB

View file

@ -0,0 +1,85 @@
#!/bin/bash
#
# Nextcloud Android client application
#
# @author Tobias Kaminsky
# Copyright (C) 2021 Tobias Kaminsky
# Copyright (C) 2021 Nextcloud GmbH
#
# 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 <https://www.gnu.org/licenses/>.
#
error=0
total=0
cp scripts/screenshotCombinations scripts/screenshotCombinations_
grep -v "#" scripts/screenshotCombinations_ > scripts/screenshotCombinations
rm scripts/screenshotCombinations_
echo '<!DOCTYPE html>
<html lang="de">
<head>
<meta charset="utf-8"/>
</head>'
echo "<table>"
echo "<tr><td style='width:150px'>Original</td>"
while read line; do
echo "<td style='width:150px'>$line</td>"
done < scripts/screenshotCombinations
echo "</tr>"
#for image in ./build/reports/shot/verification/images/*.png ; do
for image in $(/bin/ls -1 ./screenshots/gplay/debug/*.png | grep -v _dark_ | grep -v _light_) ; do
cp $image build/screenshotSummary/images/
echo "<tr style='height:200px'>"
echo "<td><a target='_blank' href=\"images/$(basename $image)\"><img width=100px src=\"images/$(basename $image)\"/></a></td>"
while read line; do
echo "<td>"
mode=$(echo $line | cut -d" " -f1)
color=$(echo $line | cut -d" " -f2)
total=$((total + 1))
if [ $mode = "light" -a $color = "blue" ]; then
name=$(basename $image)
else
name=$(basename $image| sed s"/\.png/_${mode}_$color\.png/")
fi
# if image does not exist
if [ ! -e ./build/reports/shot/verification/images/$name ]; then
echo "<span style='color: red'>✘</span>"
error=$((error + 1))
elif [ -e ./build/reports/shot/verification/images/diff_$name ]; then
# file with "diff_" prefix
cp ./build/reports/shot/verification/images/diff_$name build/screenshotSummary/images/
echo "<a target='_blank' href=\"images/diff_$name\"><img width=100px src=\"images/diff_$name\"/></a>"
error=$((error + 1))
else
echo "✔"
fi
echo "</td>"
done < scripts/screenshotCombinations
echo "</tr>"
done
echo "</table>"
echo "ERROR: $error / $total"
echo "</html>"

View file

@ -16,12 +16,12 @@ fi
classMethod=$3 classMethod=$3
resultCode=0 resultCode=0
while read line grep -v "#" scripts/screenshotCombinations | while read line
do do
darkMode=$(echo "$line" | cut -d" " -f1) darkMode=$(echo "$line" | cut -d" " -f1)
color=$(echo "$line" | cut -d" " -f2) color=$(echo "$line" | cut -d" " -f2)
echo "Run $color on $darkMode mode" echo -n "Run $color on $darkMode mode"
if [[ $1 = "noCI" ]]; then if [[ $1 = "noCI" ]]; then
./gradlew --console plain gplayDebugExecuteScreenshotTests \ ./gradlew --console plain gplayDebugExecuteScreenshotTests \
@ -32,7 +32,9 @@ do
-Pandroid.testInstrumentationRunnerArguments.DARKMODE="$darkMode" \ -Pandroid.testInstrumentationRunnerArguments.DARKMODE="$darkMode" \
$classMethod </dev/null > /dev/null $classMethod </dev/null > /dev/null
if [[ $? -ne 0 ]]; then if [[ $? -ne 0 ]]; then
exit echo " failed!"
else
echo
fi fi
else else
./gradlew --console plain gplayDebugExecuteScreenshotTests \ ./gradlew --console plain gplayDebugExecuteScreenshotTests \
@ -45,7 +47,7 @@ do
|| resultCode=1 && scripts/uploadReport.sh "$LOG_USERNAME" "$LOG_PASSWORD" "$4" \ || resultCode=1 && scripts/uploadReport.sh "$LOG_USERNAME" "$LOG_PASSWORD" "$4" \
"$1-$darkMode-$color" "Screenshot" "$4" "$GIT_TOKEN" "$1-$darkMode-$color" "Screenshot" "$4" "$GIT_TOKEN"
fi fi
done < scripts/screenshotCombinations done
sed -i s'#<bool name="is_beta">true</bool>#<bool name="is_beta">false</bool>#'g src/main/res/values/setup.xml sed -i s'#<bool name="is_beta">true</bool>#<bool name="is_beta">false</bool>#'g src/main/res/values/setup.xml

View file

@ -1,4 +1,10 @@
light blue light blue
dark blue #dark blue
light white #light white
dark white #dark white
#light black
#dark black
#light red
#dark red
#light lightgreen
dark lightgreen

30
scripts/screenshotSummary.sh Executable file
View file

@ -0,0 +1,30 @@
#!/bin/bash
#
# Nextcloud Android client application
#
# @author Tobias Kaminsky
# Copyright (C) 2021 Tobias Kaminsky
# Copyright (C) 2021 Nextcloud GmbH
#
# 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 <https://www.gnu.org/licenses/>.
#
mkdir -p build/screenshotSummary/images
scripts/generateScreenshotOverview.sh > build/screenshotSummary/summary.html
error=$?
scripts/uploadScreenshotSummary.sh $LOG_USERNAME $LOG_PASSWORD
exit $error

View file

@ -0,0 +1,17 @@
#!/bin/bash -x
#1: LOG_USERNAME
#2: LOG_PASSWORD
DAV_URL=https://nextcloud.kaminsky.me/remote.php/webdav/android-screenshot-summary/
PUBLIC_URL=https://www.kaminsky.me/nc-dev/android-screenshot-summary
USER=$1
PASS=$2
date=$(date +%F)
echo "Uploaded screenshot summary to $PUBLIC_URL/$date/summary.html"
cd build/screenshotSummary
find . -type d -exec curl > /dev/null 2>&1 -u $USER:$PASS -X MKCOL $DAV_URL/$date/$(echo {} | sed s#\./##) \;
find . -type f -exec curl > /dev/null 2>&1 -u $USER:$PASS -X PUT $DAV_URL/$date/$(echo {} | sed s#\./##) --upload-file {} \;

View file

@ -27,6 +27,7 @@ import android.Manifest;
import com.owncloud.android.AbstractIT; import com.owncloud.android.AbstractIT;
import com.owncloud.android.R; import com.owncloud.android.R;
import com.owncloud.android.ui.activity.FileDisplayActivity; import com.owncloud.android.ui.activity.FileDisplayActivity;
import com.owncloud.android.ui.fragment.OCFileListFragment;
import com.owncloud.android.utils.ScreenshotTest; import com.owncloud.android.utils.ScreenshotTest;
import org.junit.Rule; import org.junit.Rule;
@ -39,6 +40,7 @@ import androidx.test.rule.GrantPermissionRule;
import static androidx.test.espresso.Espresso.onView; import static androidx.test.espresso.Espresso.onView;
import static androidx.test.espresso.matcher.ViewMatchers.withId; import static androidx.test.espresso.matcher.ViewMatchers.withId;
import static org.junit.Assert.assertNotNull;
public class FileDisplayActivityScreenshotIT extends AbstractIT { public class FileDisplayActivityScreenshotIT extends AbstractIT {
@Rule public IntentsTestRule<FileDisplayActivity> activityRule = new IntentsTestRule<>(FileDisplayActivity.class, @Rule public IntentsTestRule<FileDisplayActivity> activityRule = new IntentsTestRule<>(FileDisplayActivity.class,
@ -64,14 +66,16 @@ public class FileDisplayActivityScreenshotIT extends AbstractIT {
screenshot(sut); screenshot(sut);
} }
@Test //@Test
@ScreenshotTest //@ScreenshotTest
public void showMediaThenAllFiles() { public void showMediaThenAllFiles() {
FileDisplayActivity sut = activityRule.launchActivity(null); FileDisplayActivity fileDisplayActivity = activityRule.launchActivity(null);
OCFileListFragment sut = fileDisplayActivity.getListOfFilesFragment();
assertNotNull(sut);
sut.getListOfFilesFragment().setFabEnabled(false); sut.setFabEnabled(false);
sut.getListOfFilesFragment().setEmptyListLoadingMessage(); sut.setEmptyListLoadingMessage();
sut.getListOfFilesFragment().setLoading(false); sut.setLoading(false);
// open drawer // open drawer
onView(withId(R.id.drawer_layout)).perform(DrawerActions.open()); onView(withId(R.id.drawer_layout)).perform(DrawerActions.open());
@ -89,11 +93,11 @@ public class FileDisplayActivityScreenshotIT extends AbstractIT {
// then compare screenshot // then compare screenshot
shortSleep(); shortSleep();
sut.getListOfFilesFragment().setFabEnabled(false); sut.setFabEnabled(false);
sut.getListOfFilesFragment().setEmptyListLoadingMessage(); sut.setEmptyListLoadingMessage();
sut.getListOfFilesFragment().setLoading(false); sut.setLoading(false);
shortSleep(); shortSleep();
screenshot(sut); screenshot(fileDisplayActivity);
} }
@Test @Test

View file

@ -25,11 +25,9 @@ package com.nextcloud.client.etm
import android.app.Activity import android.app.Activity
import androidx.test.espresso.intent.rule.IntentsTestRule import androidx.test.espresso.intent.rule.IntentsTestRule
import androidx.test.internal.runner.junit4.statement.UiThreadStatement import androidx.test.internal.runner.junit4.statement.UiThreadStatement
import com.nextcloud.client.preferences.AppPreferencesImpl
import com.owncloud.android.AbstractIT import com.owncloud.android.AbstractIT
import com.owncloud.android.lib.resources.status.OwnCloudVersion
import com.owncloud.android.utils.ScreenshotTest import com.owncloud.android.utils.ScreenshotTest
import org.junit.Assume
import org.junit.Before
import org.junit.Rule import org.junit.Rule
import org.junit.Test import org.junit.Test
@ -37,16 +35,6 @@ class EtmActivityTest : AbstractIT() {
@get:Rule @get:Rule
var activityRule = IntentsTestRule(EtmActivity::class.java, true, false) var activityRule = IntentsTestRule(EtmActivity::class.java, true, false)
@Before
fun before() {
// tests only on NC 18
Assume.assumeTrue(
storageManager
.getCapability(account.name)
.version.compareTo(OwnCloudVersion.nextcloud_18) == 0
)
}
@Test @Test
@ScreenshotTest @ScreenshotTest
fun overview() { fun overview() {
@ -62,7 +50,11 @@ class EtmActivityTest : AbstractIT() {
fun preferences() { fun preferences() {
val sut: EtmActivity = activityRule.launchActivity(null) val sut: EtmActivity = activityRule.launchActivity(null)
UiThreadStatement.runOnUiThread { sut.vm.onPageSelected(0) } UiThreadStatement.runOnUiThread {
val preferences = AppPreferencesImpl.fromContext(targetContext)
preferences.pushToken = "Push token"
sut.vm.onPageSelected(0)
}
screenshot(sut) screenshot(sut)
} }

View file

@ -156,6 +156,10 @@ public abstract class AbstractIT {
colorHex = "#000000"; colorHex = "#000000";
break; break;
case "lightgreen":
colorHex = "#aaff00";
break;
default: default:
break; break;
} }

View file

@ -40,6 +40,10 @@ class NotificationsActivityIT : AbstractIT() {
fun loading() { fun loading() {
val sut: NotificationsActivity = activityRule.launchActivity(null) val sut: NotificationsActivity = activityRule.launchActivity(null)
waitForIdleSync()
sut.runOnUiThread { sut.setLoadingMessageEmpty() }
screenshot(sut) screenshot(sut)
} }

View file

@ -290,7 +290,7 @@ public class RefreshFolderOperation extends RemoteOperation {
} else { } else {
Log_OC.i(TAG, "Got display name: " + result.getResultData()); Log_OC.i(TAG, "Got display name: " + result.getResultData());
} }
} catch (AccountUtils.AccountNotFoundException e) { } catch (AccountUtils.AccountNotFoundException | NullPointerException e) {
Log_OC.e(this, "Error updating profile", e); Log_OC.e(this, "Error updating profile", e);
} }
} }

View file

@ -61,7 +61,7 @@ public class RetrieveStatusAsyncTask extends AsyncTask<Void, Void, Status> {
} else { } else {
return new com.owncloud.android.lib.resources.users.Status(StatusType.OFFLINE, "", "", -1); return new com.owncloud.android.lib.resources.users.Status(StatusType.OFFLINE, "", "", -1);
} }
} catch (ClientFactory.CreationException e) { } catch (ClientFactory.CreationException | NullPointerException e) {
return new com.owncloud.android.lib.resources.users.Status(StatusType.OFFLINE, "", "", -1); return new com.owncloud.android.lib.resources.users.Status(StatusType.OFFLINE, "", "", -1);
} }
} }