Merge pull request #1739 from nextcloud/test/login-flow

Add test for login flow
This commit is contained in:
Marcel Hibbe 2021-12-21 15:24:11 +01:00 committed by GitHub
commit 53df2451f1
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
8 changed files with 197 additions and 34 deletions

View file

@ -47,28 +47,24 @@ steps:
- scripts/wait_for_emulator.sh - scripts/wait_for_emulator.sh
- ./gradlew --console=plain testGplayDebugUnitTest connectedGplayDebugAndroidTest - ./gradlew --console=plain testGplayDebugUnitTest connectedGplayDebugAndroidTest
#services: services:
# - name: server - name: server
# image: nextcloudci/server:server-17 # also change in updateScreenshots.sh image: nextcloudci/server:server-17
# environment: environment:
# EVAL: true EVAL: "true"
# commands: commands:
# - BRANCH='stable22' /usr/local/bin/initnc.sh - BRANCH='stable23' /usr/local/bin/initnc.sh
# - echo 127.0.0.1 server >> /etc/hosts - echo 127.0.0.1 server >> /etc/hosts
# - su www-data -c "OC_PASS=user1 php /var/www/html/occ user:add --password-from-env --display-name='User One' user1" - su www-data -c "OC_PASS=user1 php /var/www/html/occ user:add --password-from-env --display-name='User One' user1"
# - su www-data -c "OC_PASS=user2 php /var/www/html/occ user:add --password-from-env --display-name='User Two' user2" - su www-data -c "OC_PASS=user2 php /var/www/html/occ user:add --password-from-env --display-name='User Two' user2"
# - su www-data -c "OC_PASS=user3 php /var/www/html/occ user:add --password-from-env --display-name='User Three' user3" - su www-data -c "OC_PASS=user3 php /var/www/html/occ user:add --password-from-env --display-name='User Three' user3"
# - su www-data -c "php /var/www/html/occ user:setting user2 files quota 1G" - su www-data -c "php /var/www/html/occ user:setting user2 files quota 1G"
# - su www-data -c "php /var/www/html/occ group:add users" - su www-data -c "php /var/www/html/occ group:add users"
# - su www-data -c "php /var/www/html/occ group:adduser users user1" - su www-data -c "php /var/www/html/occ group:adduser users user1"
# - su www-data -c "php /var/www/html/occ group:adduser users user2" - su www-data -c "php /var/www/html/occ group:adduser users user2"
# - su www-data -c "git clone -b stable22 https://github.com/nextcloud/activity.git /var/www/html/apps/activity/" - su www-data -c "git clone -b stable23 https://github.com/nextcloud/spreed.git /var/www/html/apps/spreed/"
# - su www-data -c "php /var/www/html/occ app:enable activity" - su www-data -c "php /var/www/html/occ app:enable spreed"
# - su www-data -c "git clone -b stable22 https://github.com/nextcloud/text.git /var/www/html/apps/text/" - /usr/local/bin/run.sh
# - su www-data -c "php /var/www/html/occ app:enable text"
# - su www-data -c "git clone -b stable22 https://github.com/nextcloud/end_to_end_encryption.git /var/www/html/apps/end_to_end_encryption/"
# - su www-data -c "php /var/www/html/occ app:enable end_to_end_encryption"
# - /usr/local/bin/run.sh
trigger: trigger:
branch: branch:

View file

@ -87,6 +87,10 @@ android {
] ]
} }
} }
testInstrumentationRunnerArgument "TEST_SERVER_URL", "${NC_TEST_SERVER_BASEURL}"
testInstrumentationRunnerArgument "TEST_SERVER_USERNAME", "${NC_TEST_SERVER_USERNAME}"
testInstrumentationRunnerArgument "TEST_SERVER_PASSWORD", "${NC_TEST_SERVER_PASSWORD}"
} }
dexOptions { dexOptions {
@ -111,7 +115,7 @@ android {
android.applicationVariants.all { variant -> android.applicationVariants.all { variant ->
String variantName = variant.name String variantName = variant.name
String capVariantName = variantName.substring(0, 1).toUpperCase() + variantName.substring(1) String capVariantName = variantName.substring(0, 1).toUpperCase(Locale.ROOT) + variantName.substring(1)
tasks.register("spotbugs${capVariantName}Report", SpotBugsTask) { tasks.register("spotbugs${capVariantName}Report", SpotBugsTask) {
ignoreFailures = true // should continue checking ignoreFailures = true // should continue checking
effort = "max" effort = "max"
@ -297,16 +301,19 @@ dependencies {
testImplementation "org.powermock:powermock-module-junit4:${powermockVersion}" testImplementation "org.powermock:powermock-module-junit4:${powermockVersion}"
testImplementation "org.powermock:powermock-api-mockito2:${powermockVersion}" testImplementation "org.powermock:powermock-api-mockito2:${powermockVersion}"
androidTestImplementation "androidx.test:core:1.4.0"
// Espresso core // Espresso core
androidTestImplementation "androidx.test.espresso:espresso-core:$espressoVersion" androidTestImplementation ("androidx.test.espresso:espresso-core:$espressoVersion", {
exclude group: 'com.android.support', module: 'support-annotations'
})
androidTestImplementation "androidx.test.espresso:espresso-contrib:$espressoVersion" androidTestImplementation "androidx.test.espresso:espresso-contrib:$espressoVersion"
androidTestImplementation "androidx.test.espresso:espresso-web:$espressoVersion" androidTestImplementation "androidx.test.espresso:espresso-web:$espressoVersion"
androidTestImplementation "androidx.test.espresso:espresso-accessibility:$espressoVersion" androidTestImplementation "androidx.test.espresso:espresso-accessibility:$espressoVersion"
androidTestImplementation('com.android.support.test.espresso:espresso-intents:3.0.2') androidTestImplementation('com.android.support.test.espresso:espresso-intents:3.0.2')
androidTestImplementation ('androidx.test.espresso:espresso-core:3.4.0', {
exclude group: 'com.android.support', module: 'support-annotations'
})
spotbugsPlugins 'com.h3xstream.findsecbugs:findsecbugs-plugin:1.11.0' spotbugsPlugins 'com.h3xstream.findsecbugs:findsecbugs-plugin:1.11.0'
spotbugsPlugins 'com.mebigfatguy.fb-contrib:fb-contrib:7.4.7' spotbugsPlugins 'com.mebigfatguy.fb-contrib:fb-contrib:7.4.7'

View file

@ -5,7 +5,7 @@ import androidx.test.espresso.intent.rule.IntentsTestRule
import com.nextcloud.talk.models.database.UserEntity import com.nextcloud.talk.models.database.UserEntity
import io.reactivex.android.schedulers.AndroidSchedulers import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.schedulers.Schedulers import io.reactivex.schedulers.Schedulers
import junit.framework.Assert.assertTrue import org.junit.Assert.assertTrue
import org.junit.Rule import org.junit.Rule
import org.junit.Test import org.junit.Test
@ -23,7 +23,7 @@ class MainActivityTest {
sut.userUtils.createOrUpdateUser( sut.userUtils.createOrUpdateUser(
"test", "test",
"test", "test",
"http://10.0.2.2/nc", "http://server/nc",
"test", "test",
null, null,
true, true,
@ -49,7 +49,7 @@ class MainActivityTest {
sut.runOnUiThread { sut.resetConversationsList() } sut.runOnUiThread { sut.resetConversationsList() }
assertTrue(sut.userUtils.getIfUserWithUsernameAndServer("test", "http://10.0.2.2/nc")) assertTrue(sut.userUtils.getIfUserWithUsernameAndServer("test", "http://server/nc"))
try { try {
} catch (e: InterruptedException) { } catch (e: InterruptedException) {

View file

@ -0,0 +1,152 @@
/*
* Nextcloud Talk application
*
* @author Tobias Kaminsky
* @author Tim Krüger
* Copyright (C) 2021 Tim Krüger
* Copyright (C) 2020 Tobias Kaminsky
* Copyright (C) 2020 Nextcloud GmbH
*
* 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/>.
*/
package com.nextcloud.talk.ui;
import android.os.Bundle;
import com.nextcloud.talk.R;
import com.nextcloud.talk.activities.MainActivity;
import junit.framework.AssertionFailedError;
import org.junit.Test;
import java.util.Objects;
import androidx.test.core.app.ActivityScenario;
import androidx.test.espresso.NoMatchingViewException;
import androidx.test.espresso.web.webdriver.DriverAtoms;
import androidx.test.espresso.web.webdriver.Locator;
import androidx.test.filters.LargeTest;
import static androidx.test.espresso.Espresso.onView;
import static androidx.test.espresso.action.ViewActions.click;
import static androidx.test.espresso.action.ViewActions.typeText;
import static androidx.test.espresso.assertion.ViewAssertions.matches;
import static androidx.test.espresso.matcher.ViewMatchers.isDisplayed;
import static androidx.test.espresso.matcher.ViewMatchers.withContentDescription;
import static androidx.test.espresso.matcher.ViewMatchers.withId;
import static androidx.test.espresso.matcher.ViewMatchers.withText;
import static androidx.test.espresso.web.sugar.Web.onWebView;
import static androidx.test.espresso.web.webdriver.DriverAtoms.findElement;
import static androidx.test.espresso.web.webdriver.DriverAtoms.webClick;
import static org.hamcrest.Matchers.not;
import static org.junit.Assert.assertEquals;
@LargeTest
public class LoginIT {
@Test
public void login() throws InterruptedException {
ActivityScenario<MainActivity> activityScenario = ActivityScenario.launch(MainActivity.class);
Bundle arguments = androidx.test.platform.app.InstrumentationRegistry.getArguments();
String baseUrl = arguments.getString("TEST_SERVER_URL");
String loginName = arguments.getString("TEST_SERVER_USERNAME");
String password = arguments.getString("TEST_SERVER_PASSWORD");
Thread.sleep(2000);
try {
onView(withId(R.id.serverEntryTextInputEditText)).check(matches(isDisplayed()));
} catch (NoMatchingViewException e) {
try {
// can happen that an invalid account from previous tests is existing
onView(withText(R.string.nc_settings_remove_account)).perform(click());
Thread.sleep(2000);
} catch (NoMatchingViewException ie) {
// is OK if the dialog is not shown
}
try {
// Delete account if exists
onView(withId(R.id.switch_account_button)).perform(click());
onView(withId(R.id.manage_settings)).perform(click());
onView(withId(R.id.settings_remove_account)).perform(click());
onView(withText(R.string.nc_settings_remove)).perform(click());
// The remove button must be clicked two times
onView(withId(R.id.settings_remove_account)).perform(click());
// And yes: The button must be clicked two times
onView(withText(R.string.nc_settings_remove)).perform(click());
onView(withText(R.string.nc_settings_remove)).perform(click());
} catch (Exception ie2) {
// ignore
} finally {
Thread.sleep(2000);
}
}
onView(withId(R.id.serverEntryTextInputEditText)).perform(typeText(baseUrl));
// Click on EditText's drawable right
onView(withContentDescription(R.string.nc_server_connect)).perform(click());
Thread.sleep(4000);
onWebView().forceJavascriptEnabled();
// click on login
onWebView()
.withElement(findElement(Locator.XPATH, "//p[@id='redirect-link']/a"))
.perform(webClick());
// username
onWebView()
.withElement(findElement(Locator.XPATH, "//input[@id='user']"))
.perform(DriverAtoms.webKeys(loginName));
// password
onWebView()
.withElement(findElement(Locator.XPATH, "//input[@id='password']"))
.perform(DriverAtoms.webKeys(password));
// click login
onWebView()
.withElement(findElement(Locator.XPATH, "//input[@id='submit-form']"))
.perform(webClick());
Thread.sleep(2000);
// grant access
onWebView()
.withElement(findElement(Locator.XPATH, "//input[@type='submit']"))
.perform(webClick());
Thread.sleep(5 * 1000);
onView(withId(R.id.switch_account_button)).perform(click());
onView(withId(R.id.user_name)).check(matches(withText("User One")));
activityScenario.onActivity(activity -> {
assertEquals(loginName, Objects.requireNonNull(activity.userUtils.getCurrentUser()).getUserId());
});
}
}

View file

@ -80,6 +80,7 @@ import java.util.Collections;
import java.util.HashMap; import java.util.HashMap;
import java.util.HashSet; import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Locale;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
@ -540,7 +541,8 @@ public class ContactsController extends BaseController implements SearchView.OnQ
} else if (participant.getActorType() == Participant.ActorType.CIRCLES) { } else if (participant.getActorType() == Participant.ActorType.CIRCLES) {
headerTitle = getResources().getString(R.string.nc_circles); headerTitle = getResources().getString(R.string.nc_circles);
} else { } else {
headerTitle = participant.getDisplayName().substring(0, 1).toUpperCase(); headerTitle =
participant.getDisplayName().substring(0, 1).toUpperCase(Locale.getDefault());
} }
GenericTextHeaderItem genericTextHeaderItem; GenericTextHeaderItem genericTextHeaderItem;

View file

@ -92,8 +92,8 @@ public class MagicWebRTCUtils {
public static boolean shouldEnableVideoHardwareAcceleration() { public static boolean shouldEnableVideoHardwareAcceleration() {
return (!HARDWARE_ACCELERATION_VENDOR_BLACKLIST.contains(Build.MANUFACTURER.toLowerCase()) return (!HARDWARE_ACCELERATION_VENDOR_BLACKLIST.contains(Build.MANUFACTURER.toLowerCase(Locale.ROOT))
&& !HARDWARE_ACCELERATION_DEVICE_BLACKLIST.contains(Build.MODEL.toUpperCase())); && !HARDWARE_ACCELERATION_DEVICE_BLACKLIST.contains(Build.MODEL.toUpperCase(Locale.ROOT)));
} }
public static String preferCodec(String sdpDescription, String codec, boolean isAudio) { public static String preferCodec(String sdpDescription, String codec, boolean isAudio) {

View file

@ -2,6 +2,8 @@
# Nextcloud Talk application # Nextcloud Talk application
# #
# @author Mario Danic # @author Mario Danic
# @author Tim Krüger
# Copyright (C) 2021 Tim Krüger <t@timkrueger.me>
# Copyright (C) 2017-2019 Mario Danic <mario@lovelyhq.com> # Copyright (C) 2017-2019 Mario Danic <mario@lovelyhq.com>
# #
# This program is free software: you can redistribute it and/or modify # This program is free software: you can redistribute it and/or modify
@ -39,3 +41,7 @@ org.gradle.daemon=true
org.gradle.configureondemand=true org.gradle.configureondemand=true
org.gradle.caching=true org.gradle.caching=true
org.gradle.parallel=true org.gradle.parallel=true
NC_TEST_SERVER_BASEURL=http://server
NC_TEST_SERVER_USERNAME=user1
NC_TEST_SERVER_PASSWORD=user1

View file

@ -1,2 +1,2 @@
DO NOT TOUCH; GENERATED BY DRONE DO NOT TOUCH; GENERATED BY DRONE
<span class="mdl-layout-title">Lint Report: 1 error and 224 warnings</span> <span class="mdl-layout-title">Lint Report: 1 error and 222 warnings</span>