1 /*
2  * Copyright (C) 2021 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.car.debuggingrestrictioncontroller;
18 
19 import static androidx.test.core.app.ApplicationProvider.getApplicationContext;
20 import static androidx.test.espresso.Espresso.onView;
21 import static androidx.test.espresso.action.ViewActions.click;
22 import static androidx.test.espresso.action.ViewActions.typeText;
23 import static androidx.test.espresso.assertion.ViewAssertions.matches;
24 import static androidx.test.espresso.intent.Intents.intended;
25 import static androidx.test.espresso.intent.Intents.intending;
26 import static androidx.test.espresso.intent.matcher.IntentMatchers.hasComponent;
27 import static androidx.test.espresso.intent.matcher.IntentMatchers.toPackage;
28 import static androidx.test.espresso.matcher.ViewMatchers.hasErrorText;
29 import static androidx.test.espresso.matcher.ViewMatchers.isDisplayed;
30 import static androidx.test.espresso.matcher.ViewMatchers.isEnabled;
31 import static androidx.test.espresso.matcher.ViewMatchers.withId;
32 import static androidx.test.espresso.matcher.ViewMatchers.withText;
33 import static org.hamcrest.Matchers.allOf;
34 import static org.hamcrest.Matchers.not;
35 
36 import android.app.Activity;
37 import android.app.Instrumentation.ActivityResult;
38 import android.content.Context;
39 import android.content.Intent;
40 import androidx.test.espresso.IdlingRegistry;
41 import androidx.test.espresso.action.ViewActions;
42 import androidx.test.espresso.idling.CountingIdlingResource;
43 import androidx.test.espresso.intent.Intents;
44 import androidx.test.ext.junit.rules.ActivityScenarioRule;
45 import androidx.test.ext.junit.runners.AndroidJUnit4;
46 import com.android.car.debuggingrestrictioncontroller.ui.login.LoginActivity;
47 import com.android.car.debuggingrestrictioncontroller.ui.token.TokenActivity;
48 import com.google.firebase.auth.FirebaseAuth;
49 import org.junit.After;
50 import org.junit.Before;
51 import org.junit.Rule;
52 import org.junit.Test;
53 import org.junit.runner.RunWith;
54 
55 @RunWith(AndroidJUnit4.class)
56 public class LoginTest {
57 
58   private static final String TEST_EMAIL = BuildConfig.DRC_TEST_EMAIL;
59   private static final String TEST_PASSWORD = BuildConfig.DRC_TEST_PASSWORD;
60   private static final String INVALID_EMAIL = "invalid_email@";
61   private static final String SHORT_PASSWORD = "word";
62   private static final String WRONG_PASSWORD = "wrong_password";
63   private final FirebaseAuth firebaseAuth = FirebaseAuth.getInstance();
64 
65   @Rule
66   public ActivityScenarioRule<LoginActivity> activityScenarioRule =
67       new ActivityScenarioRule<LoginActivity>(LoginActivity.class);
68 
69   private CountingIdlingResource idlingResource;
70 
71   @Before
setUp()72   public void setUp() {
73     activityScenarioRule
74         .getScenario()
75         .onActivity(
76             activity -> {
77               idlingResource = activity.getIdlingResource();
78             });
79     IdlingRegistry.getInstance().register(idlingResource);
80     Intents.init();
81     firebaseAuth.signOut();
82   }
83 
84   @After
tearDown()85   public void tearDown() {
86     IdlingRegistry.getInstance().unregister(idlingResource);
87     Intents.release();
88     firebaseAuth.signOut();
89   }
90 
91   @Test
invalidEmail()92   public void invalidEmail() {
93     Context ctx = getApplicationContext();
94     onView(withId(R.id.username)).perform(typeText(INVALID_EMAIL), ViewActions.closeSoftKeyboard());
95     onView(withId(R.id.username))
96         .check(matches(hasErrorText(ctx.getString(R.string.invalid_username))));
97     onView(withId(R.id.login)).check(matches(not(isEnabled())));
98   }
99 
100   @Test
invalidPassword()101   public void invalidPassword() {
102     Context ctx = getApplicationContext();
103     onView(withId(R.id.username)).perform(typeText(TEST_EMAIL), ViewActions.closeSoftKeyboard());
104     onView(withId(R.id.password))
105         .perform(typeText(SHORT_PASSWORD), ViewActions.closeSoftKeyboard());
106     onView(withId(R.id.password))
107         .check(matches(hasErrorText(ctx.getString(R.string.invalid_password))));
108     onView(withId(R.id.login)).check(matches(not(isEnabled())));
109   }
110 
111   @Test
initialButtonStates()112   public void initialButtonStates() {
113     onView(withId(R.id.login)).check(matches(isDisplayed()));
114     onView(withId(R.id.login)).check(matches(not(isEnabled())));
115     onView(withId(R.id.next)).check(matches(isDisplayed()));
116     onView(withId(R.id.next)).check(matches(not(isEnabled())));
117   }
118 
119   @Test
wrongPassword()120   public void wrongPassword() {
121     onView(withId(R.id.username)).perform(typeText(TEST_EMAIL), ViewActions.closeSoftKeyboard());
122     onView(withId(R.id.password))
123         .perform(typeText(WRONG_PASSWORD), ViewActions.pressImeActionButton());
124     onView(withId(R.id.next)).check(matches(not(isEnabled())));
125     firebaseAuth.signOut();
126   }
127 
128   @Test
userLogout()129   public void userLogout() {
130     onView(withId(R.id.username)).perform(typeText(TEST_EMAIL), ViewActions.closeSoftKeyboard());
131     onView(withId(R.id.password)).perform(typeText(TEST_PASSWORD), ViewActions.closeSoftKeyboard());
132 
133     onView(withId(R.id.login)).check(matches(isEnabled()));
134     onView(withId(R.id.login)).check(matches(withText(R.string.button_sign_in)));
135     onView(withId(R.id.login)).perform(click());
136     onView(withId(R.id.login)).check(matches(isEnabled()));
137     onView(withId(R.id.login)).check(matches(withText(R.string.button_sign_out)));
138     onView(withId(R.id.login)).perform(click());
139     onView(withId(R.id.login)).check(matches(isEnabled()));
140     onView(withId(R.id.login)).check(matches(withText(R.string.button_sign_in)));
141     firebaseAuth.signOut();
142   }
143 
144   @Test
startTokenActivity()145   public void startTokenActivity() {
146     onView(withId(R.id.username)).perform(typeText(TEST_EMAIL), ViewActions.closeSoftKeyboard());
147     onView(withId(R.id.password)).perform(typeText(TEST_PASSWORD), ViewActions.closeSoftKeyboard());
148 
149     onView(withId(R.id.login)).check(matches(isEnabled()));
150     onView(withId(R.id.login)).perform(click());
151     onView(withId(R.id.next)).check(matches(isEnabled()));
152     onView(withId(R.id.next)).perform(click());
153 
154     intended(
155         allOf(
156             toPackage(getApplicationContext().getPackageName()),
157             hasComponent(TokenActivity.class.getName())));
158     onView(withId(R.id.agreement)).check(matches(isDisplayed()));
159     onView(withId(R.id.agree)).check(matches(isDisplayed()));
160     onView(withId(R.id.disagree)).check(matches(isDisplayed()));
161     firebaseAuth.signOut();
162   }
163 
164   @Test
returnedFromTokenActivityOK()165   public void returnedFromTokenActivityOK() {
166     Intent intent = new Intent(getApplicationContext(), TokenActivity.class);
167     ActivityResult result = new ActivityResult(Activity.RESULT_OK, intent);
168     intending(
169             allOf(
170                 toPackage(getApplicationContext().getPackageName()),
171                 hasComponent(TokenActivity.class.getName())))
172         .respondWith(result);
173 
174     onView(withId(R.id.username)).perform(typeText(TEST_EMAIL), ViewActions.closeSoftKeyboard());
175     onView(withId(R.id.password)).perform(typeText(TEST_PASSWORD), ViewActions.closeSoftKeyboard());
176 
177     onView(withId(R.id.login)).check(matches(isEnabled()));
178     onView(withId(R.id.login)).perform(click());
179     onView(withId(R.id.next)).check(matches(isEnabled()));
180     onView(withId(R.id.next)).perform(click());
181 
182     onView(withId(com.google.android.material.R.id.snackbar_text))
183         .check(matches(withText(R.string.token_authorized)));
184     firebaseAuth.signOut();
185   }
186 
187   @Test
returnedFromTokenActivityCancelled()188   public void returnedFromTokenActivityCancelled() {
189     Intent intent = new Intent(getApplicationContext(), TokenActivity.class);
190     ActivityResult result = new ActivityResult(Activity.RESULT_CANCELED, intent);
191     intending(
192             allOf(
193                 toPackage(getApplicationContext().getPackageName()),
194                 hasComponent(TokenActivity.class.getName())))
195         .respondWith(result);
196 
197     onView(withId(R.id.username)).perform(typeText(TEST_EMAIL), ViewActions.closeSoftKeyboard());
198     onView(withId(R.id.password)).perform(typeText(TEST_PASSWORD), ViewActions.closeSoftKeyboard());
199 
200     onView(withId(R.id.login)).check(matches(isEnabled()));
201     onView(withId(R.id.login)).perform(click());
202     onView(withId(R.id.next)).check(matches(isEnabled()));
203     onView(withId(R.id.next)).perform(click());
204 
205     onView(withId(com.google.android.material.R.id.snackbar_text))
206         .check(matches(withText(R.string.token_unauthorized)));
207     firebaseAuth.signOut();
208   }
209 }
210