Merge "LOCAL_COMPATIBILITY_SUPPORT_FILES relative to $(TOP)." into nyc-dev
diff --git a/hostsidetests/devicepolicy/app/ManagedProfile/src/com/android/cts/managedprofile/ContactsTest.java b/hostsidetests/devicepolicy/app/ManagedProfile/src/com/android/cts/managedprofile/ContactsTest.java
index 3d64d47..0c4e74c 100644
--- a/hostsidetests/devicepolicy/app/ManagedProfile/src/com/android/cts/managedprofile/ContactsTest.java
+++ b/hostsidetests/devicepolicy/app/ManagedProfile/src/com/android/cts/managedprofile/ContactsTest.java
@@ -259,9 +259,7 @@
assertManagedLocalContact(contactInfo);
contactInfo.assertPhotoUrisReadable();
assertFalse(contactInfo.hasPhotoId());
-
- // Quirk: the _id column from the SIP lookup is actually of the data id, not the contact id.
- // assertTrue(isEnterpriseContactId(contactInfo.contactId));
+ assertTrue(isEnterpriseContactId(contactInfo.contactId));
}
public void testPrimaryProfileEnterpriseEmailLookup_canAccessEnterpriseContact()
@@ -1093,12 +1091,32 @@
contactInfo.assertPhotoUri(R.raw.managed_photo);
}
+ private void assertContactInfoEquals(ContactInfo lhs, ContactInfo rhs) {
+ if (lhs == null) {
+ assertNull(rhs);
+ } else {
+ assertNotNull(rhs);
+ assertEquals(lhs.contactId, rhs.contactId);
+ assertEquals(lhs.displayName, rhs.displayName);
+ assertEquals(lhs.photoId, rhs.photoId);
+ assertEquals(lhs.photoThumbnailUri, rhs.photoThumbnailUri);
+ assertEquals(lhs.photoUri, rhs.photoUri);
+ }
+ }
+
private ContactInfo getContactInfoFromPhoneLookupUri(boolean isEnterprise, String phoneNumber) {
Uri baseUri = (isEnterprise) ? PhoneLookup.ENTERPRISE_CONTENT_FILTER_URI
: PhoneLookup.CONTENT_FILTER_URI;
Uri uri = baseUri.buildUpon().appendPath(phoneNumber).build();
- return getContactInfoFromUri(uri, PhoneLookup._ID, PhoneLookup.DISPLAY_NAME,
+ ContactInfo contactInfo = getContactInfoFromUri(uri, PhoneLookup._ID,
+ PhoneLookup.DISPLAY_NAME,
PhoneLookup.PHOTO_URI, PhoneLookup.PHOTO_THUMBNAIL_URI, PhoneLookup.PHOTO_ID);
+
+ ContactInfo contactInfo2 = getContactInfoFromUri(uri, PhoneLookup.CONTACT_ID,
+ PhoneLookup.DISPLAY_NAME,
+ PhoneLookup.PHOTO_URI, PhoneLookup.PHOTO_THUMBNAIL_URI, PhoneLookup.PHOTO_ID);
+ assertContactInfoEquals(contactInfo, contactInfo2);
+ return contactInfo;
}
private ContactInfo getContactInfoFromEnterprisePhoneLookupUriWithSipAddress(
@@ -1107,7 +1125,7 @@
: PhoneLookup.CONTENT_FILTER_URI;
Uri uri = baseUri.buildUpon().appendPath(sipAddress)
.appendQueryParameter(PhoneLookup.QUERY_PARAMETER_SIP_ADDRESS, "1").build();
- return getContactInfoFromUri(uri, PhoneLookup._ID, PhoneLookup.DISPLAY_NAME,
+ return getContactInfoFromUri(uri, PhoneLookup.CONTACT_ID, PhoneLookup.DISPLAY_NAME,
PhoneLookup.PHOTO_URI, PhoneLookup.PHOTO_THUMBNAIL_URI, PhoneLookup.PHOTO_ID);
}
diff --git a/tests/accessibilityservice/AndroidManifest.xml b/tests/accessibilityservice/AndroidManifest.xml
index 41e13ee..43a7baf 100644
--- a/tests/accessibilityservice/AndroidManifest.xml
+++ b/tests/accessibilityservice/AndroidManifest.xml
@@ -44,23 +44,38 @@
<activity android:label="Full screen activity for gesture dispatch testing"
android:name=".AccessibilityGestureDispatchTest$GestureDispatchActivity"/>
- <service
- android:name="android.accessibilityservice.cts.StubGestureAccessibilityService"
- android:permission="android.permission.BIND_ACCESSIBILITY_SERVICE" >
- <intent-filter>
- <action android:name="android.accessibilityservice.AccessibilityService" />
+ <service
+ android:name="android.accessibilityservice.cts.StubGestureAccessibilityService"
+ android:permission="android.permission.BIND_ACCESSIBILITY_SERVICE" >
+ <intent-filter>
+ <action android:name="android.accessibilityservice.AccessibilityService" />
- <category android:name="android.accessibilityservice.category.FEEDBACK_GENERIC" />
- </intent-filter>
+ <category android:name="android.accessibilityservice.category.FEEDBACK_GENERIC" />
+ </intent-filter>
- <meta-data
- android:name="android.accessibilityservice"
- android:resource="@xml/stub_gesture_a11y_service" />
- </service>
+ <meta-data
+ android:name="android.accessibilityservice"
+ android:resource="@xml/stub_gesture_a11y_service" />
+ </service>
+
+ <activity android:label="@string/accessibility_soft_keyboard_modes_activity"
+ android:name=".AccessibilitySoftKeyboardModesTest$SoftKeyboardModesActivity"
+ android:windowSoftInputMode="stateAlwaysVisible" />
+
+ <service android:name=".StubSoftKeyboardModesAccessibilityService"
+ android:label="@string/title_soft_keyboard_modes_accessibility_service"
+ android:permission="android.permission.BIND_ACCESSIBILITY_SERVICE">
+ <intent-filter>
+ <action android:name="android.accessibilityservice.AccessibilityService"/>
+ <category android:name="android.accessibilityservice.category.FEEDBACK_GENERIC" />
+ </intent-filter>
+ <meta-data android:name="android.accessibilityservice"
+ android:resource="@xml/stub_soft_keyboard_modes_accessibility_service" />
+ </service>
</application>
- <instrumentation android:name="android.support.test.runner.AndroidJUnitRunner"
+ <instrumentation android:name="android.support.test.runner.AndroidJUnitRunner"
android:targetPackage="android.accessibilityservice.cts"
android:label="Tests for the accessibility APIs.">
<meta-data android:name="listener"
diff --git a/tests/accessibilityservice/AndroidTest.xml b/tests/accessibilityservice/AndroidTest.xml
index db2707d..1287524 100644
--- a/tests/accessibilityservice/AndroidTest.xml
+++ b/tests/accessibilityservice/AndroidTest.xml
@@ -21,4 +21,4 @@
<test class="com.android.tradefed.testtype.AndroidJUnitTest" >
<option name="package" value="android.accessibilityservice.cts" />
</test>
-</configuration>
\ No newline at end of file
+</configuration>
diff --git a/tests/accessibilityservice/res/layout/accessibility_soft_keyboard_modes_test.xml b/tests/accessibilityservice/res/layout/accessibility_soft_keyboard_modes_test.xml
new file mode 100644
index 0000000..577a204
--- /dev/null
+++ b/tests/accessibilityservice/res/layout/accessibility_soft_keyboard_modes_test.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2016 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<EditText xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/edit_text"
+ android:orientation="vertical"
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent" />
diff --git a/tests/accessibilityservice/res/values/strings.xml b/tests/accessibilityservice/res/values/strings.xml
index 89ce1df..1c34c2c 100644
--- a/tests/accessibilityservice/res/values/strings.xml
+++ b/tests/accessibilityservice/res/values/strings.xml
@@ -145,5 +145,16 @@
unveiling\n\n</string>
<string name="full_screen_text_view">Full Screen Text View</string>
+ <!-- Soft Keyboard Modes tests -->
+
+ <!-- String title for the accessibility service -->
+ <string name="accessibility_soft_keyboard_modes_activity">
+ Soft Keyboard Modes Activity</string>
+
+ <string name="title_soft_keyboard_modes_accessibility_service">
+ Stub Soft Keyboard Modes Accessibility Service</string>
+
+ <!-- Description of the accessibility service -->
+ <string name="soft_keyboard_modes_accessibility_service_description">This Accessibility Service was installed for testing purposes. It can be uninstalled by going to Settings > Apps > android.view.accessibilityservice.services and selecting \"Uninstall\".</string>
</resources>
diff --git a/tests/accessibilityservice/res/xml/stub_soft_keyboard_modes_accessibility_service.xml b/tests/accessibilityservice/res/xml/stub_soft_keyboard_modes_accessibility_service.xml
new file mode 100644
index 0000000..b5f9ede
--- /dev/null
+++ b/tests/accessibilityservice/res/xml/stub_soft_keyboard_modes_accessibility_service.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<!-- Copyright (C) 2016 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<accessibility-service xmlns:android="http://schemas.android.com/apk/res/android"
+ android:accessibilityEventTypes="typeAllMask"
+ android:accessibilityFeedbackType="feedbackGeneric"
+ android:accessibilityFlags="flagDefault|flagRetrieveInteractiveWindows"
+ android:canRetrieveWindowContent="true"
+ android:description="@string/soft_keyboard_modes_accessibility_service_description" />
diff --git a/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilitySoftKeyboardModesTest.java b/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilitySoftKeyboardModesTest.java
new file mode 100644
index 0000000..649df16
--- /dev/null
+++ b/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilitySoftKeyboardModesTest.java
@@ -0,0 +1,362 @@
+/**
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
+ * in compliance with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the
+ * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
+ * express or implied. See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.accessibilityservice.cts;
+
+import android.accessibilityservice.AccessibilityService;
+import android.accessibilityservice.AccessibilityServiceInfo;
+import android.accessibilityservice.AccessibilityService.SoftKeyboardController;
+import android.app.UiAutomation;
+import android.content.ContentResolver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.os.Bundle;
+import android.os.ParcelFileDescriptor;
+import android.os.SystemClock;
+import android.provider.Settings;
+import android.test.ActivityInstrumentationTestCase2;
+import android.test.suitebuilder.annotation.MediumTest;
+import android.text.Selection;
+import android.text.TextUtils;
+import android.view.View;
+import android.view.accessibility.AccessibilityEvent;
+import android.view.accessibility.AccessibilityManager;
+import android.view.accessibility.AccessibilityNodeInfo;
+import android.view.WindowManager;
+import android.widget.EditText;
+import android.widget.TextView;
+
+import android.accessibilityservice.cts.R;
+
+import java.io.BufferedReader;
+import java.io.FileInputStream;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.nio.charset.StandardCharsets;
+import java.util.List;
+import java.util.concurrent.TimeoutException;
+
+/**
+ * Test cases for testing the accessibility APIs for interacting with the soft keyboard show mode.
+ */
+public class AccessibilitySoftKeyboardModesTest extends ActivityInstrumentationTestCase2
+ <AccessibilitySoftKeyboardModesTest.SoftKeyboardModesActivity> {
+
+ /**
+ * Timeout in which we are waiting for the system to start the mock
+ * accessibility services.
+ */
+ private static final long TIMEOUT_SERVICE_TOGGLE_MS = 10000;
+
+ private static final long TIMEOUT_PROPAGATE_SETTING = 5000;
+
+ private static final int SHOW_MODE_AUTO = 0;
+ private static final int SHOW_MODE_HIDDEN = 1;
+
+ private int mCallbackCount;
+ private int mLastCallbackValue;
+
+ private Context mContext;
+ private StubSoftKeyboardModesAccessibilityService mService;
+ private SoftKeyboardController mKeyboardController;
+
+ private Object mLock = new Object();
+
+ public AccessibilitySoftKeyboardModesTest() {
+ super(SoftKeyboardModesActivity.class);
+ }
+
+ @Override
+ public void setUp() throws Exception {
+ super.setUp();
+
+ // If we don't call getActivity(), we get an empty list when requesting the number of
+ // windows on screen.
+ getActivity();
+
+ mContext = getInstrumentation().getContext();
+ UiAutomation uiAutomation;
+ try {
+ uiAutomation = getUiAutomation();
+ } catch (RuntimeException e) {
+ // Clean up UI Automation after other tests as we cannot request UI Automation with
+ // different flags if one already exists.
+ uiAutomation = getInstrumentation().getUiAutomation();
+ uiAutomation.destroy();
+
+ // Try to get UI Automation again.
+ uiAutomation = getUiAutomation();
+ }
+ String command = "pm grant " + mContext.getPackageName()
+ + "android.permission.WRITE_SECURE_SETTINGS";
+ executeShellCommand(uiAutomation, command);
+ uiAutomation.destroy();
+
+ disableAllServices();
+ enableTestService();
+
+ }
+
+ @Override
+ public void tearDown() throws Exception {
+ disableAllServices();
+ }
+
+ public void testApiReturnValues_shouldChangeValueOnRequestAndSendCallback() throws Exception {
+ mLastCallbackValue = -1;
+
+ final SoftKeyboardController.OnShowModeChangedListener listener =
+ new SoftKeyboardController.OnShowModeChangedListener() {
+ @Override
+ public void onShowModeChanged(SoftKeyboardController controller, int showMode) {
+ synchronized (mLock) {
+ mLastCallbackValue = showMode;
+ mLock.notifyAll();
+ }
+ }
+ };
+ mKeyboardController.addOnShowModeChangedListener(listener);
+
+ // The soft keyboard should be in its' default mode.
+ assertEquals(SHOW_MODE_AUTO, mKeyboardController.getShowMode());
+
+ // Set the show mode to SHOW_MODE_HIDDEN.
+ assertTrue(mKeyboardController.setShowMode(SHOW_MODE_HIDDEN));
+
+ // Make sure the mode was changed.
+ assertEquals(SHOW_MODE_HIDDEN, mKeyboardController.getShowMode());
+
+ // Make sure we're getting the callback with the proper value.
+ waitForCallbackValueWithLock(SHOW_MODE_HIDDEN);
+
+ // Make sure we can set the value back to the default.
+ assertTrue(mKeyboardController.setShowMode(SHOW_MODE_AUTO));
+ assertEquals(SHOW_MODE_AUTO, mKeyboardController.getShowMode());
+ waitForCallbackValueWithLock(SHOW_MODE_AUTO);
+
+ // Make sure we can remove our listener.
+ assertTrue(mKeyboardController.removeOnShowModeChangedListener(listener));
+ }
+
+ public void testHideSoftKeyboard_shouldHideAndShowKeyboardOnRequest() throws Exception {
+ // The soft keyboard should be in its' default mode.
+ assertEquals(SHOW_MODE_AUTO, mKeyboardController.getShowMode());
+
+ // Note: This Activity always has a visible keyboard (due to windowSoftInputMode being set
+ // to stateAlwaysVisible).
+ int numWindowsWithIme = mService.getTestWindowsListSize();
+
+ // Request the keyboard be hidden.
+ assertTrue(mKeyboardController.setShowMode(SHOW_MODE_HIDDEN));
+ waitForWindowStateChanged();
+
+ // Make sure the keyboard is hidden.
+ assertEquals(numWindowsWithIme - 1, mService.getTestWindowsListSize());
+
+ // Request the default keyboard mode.
+ assertTrue(mKeyboardController.setShowMode(SHOW_MODE_AUTO));
+ waitForWindowStateChanged();
+
+ // Make sure the keyboard is visible.
+ assertEquals(numWindowsWithIme, mService.getTestWindowsListSize());
+ }
+
+
+ public void testHideSoftKeyboard_shouldHideKeyboardUntilAllServicesDisabled() throws Exception {
+ // The soft keyboard should be in its' default mode.
+ assertEquals(SHOW_MODE_AUTO, mKeyboardController.getShowMode());
+
+ // Note: This Activity always has a visible keyboard (due to windowSoftInputMode being set
+ // to stateAlwaysVisible).
+ int numWindowsWithIme = mService.getTestWindowsListSize();
+
+ // Set the show mode to SHOW_MODE_HIDDEN.
+ assertTrue(mKeyboardController.setShowMode(SHOW_MODE_HIDDEN));
+ waitForWindowStateChanged();
+
+ // Make sure the keyboard is hidden.
+ assertEquals(numWindowsWithIme - 1, mService.getTestWindowsListSize());
+
+ // Make sure we can see the soft keyboard once all Accessibility Services are disabled.
+ disableAllServices();
+ waitForWindowStateChanged();
+
+ // Enable our test service,.
+ enableTestService();
+
+ // See how many windows are present.
+ assertEquals(numWindowsWithIme, mService.getTestWindowsListSize());
+ }
+
+ private synchronized UiAutomation getUiAutomation() {
+ return getInstrumentation()
+ .getUiAutomation(UiAutomation.FLAG_DONT_SUPPRESS_ACCESSIBILITY_SERVICES);
+ }
+
+ private void executeShellCommand(UiAutomation uiAutomation, String command) throws Exception {
+ ParcelFileDescriptor fd = uiAutomation.executeShellCommand(command);
+ BufferedReader reader = null;
+ try (InputStream inputStream = new FileInputStream(fd.getFileDescriptor())) {
+ reader = new BufferedReader(new InputStreamReader(inputStream, StandardCharsets.UTF_8));
+ while (reader.readLine() != null) {
+ // Keep reading.
+ }
+ } finally {
+ if (reader != null) {
+ reader.close();
+ }
+ fd.close();
+ }
+ }
+
+ private void waitForCallbackValueWithLock(int expectedValue) throws Exception {
+ long timeoutTimeMillis = SystemClock.uptimeMillis() + TIMEOUT_PROPAGATE_SETTING;
+
+ while (SystemClock.uptimeMillis() < timeoutTimeMillis) {
+ synchronized(mLock) {
+ if (mLastCallbackValue == expectedValue) {
+ return;
+ }
+ try {
+ mLock.wait(timeoutTimeMillis - SystemClock.uptimeMillis());
+ } catch (InterruptedException e) {
+ // Wait until timeout.
+ }
+ }
+ }
+
+ throw new IllegalStateException("last callback value <" + mLastCallbackValue
+ + "> does not match expected value < " + expectedValue + ">");
+ }
+
+ private void waitForWindowStateChanged() throws Exception {
+ UiAutomation uiAutomation = getUiAutomation();
+ try {
+ uiAutomation.executeAndWaitForEvent(new Runnable() {
+ @Override
+ public void run() {
+ // Do nothing.
+ }
+ },
+ new UiAutomation.AccessibilityEventFilter() {
+ @Override
+ public boolean accept (AccessibilityEvent event) {
+ return event.getEventType() == AccessibilityEvent.TYPE_WINDOWS_CHANGED;
+ }
+ },
+ TIMEOUT_PROPAGATE_SETTING);
+ } catch (TimeoutException ignored) {
+ // Ignore since the event could have occured before this method was called. There should // be a check after this method returns to catch incorrect values.
+ } finally {
+ uiAutomation.destroy();
+ }
+ }
+
+ private void disableAllServices() throws Exception {
+ final Object waitLockForA11yOff = new Object();
+ AccessibilityManager manager =
+ (AccessibilityManager) mContext.getSystemService(Context.ACCESSIBILITY_SERVICE);
+ manager.addAccessibilityStateChangeListener(
+ new AccessibilityManager.AccessibilityStateChangeListener() {
+ @Override
+ public void onAccessibilityStateChanged(boolean b) {
+ synchronized (waitLockForA11yOff) {
+ waitLockForA11yOff.notifyAll();
+ }
+ }
+ });
+ ContentResolver cr = mContext.getContentResolver();
+ UiAutomation uiAutomation = getUiAutomation();
+ executeShellCommand(uiAutomation, "settings put secure "
+ + Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES + " null");
+ uiAutomation.destroy();
+ StubSoftKeyboardModesAccessibilityService.sInstance = null;
+ long timeoutTimeMillis = SystemClock.uptimeMillis() + TIMEOUT_SERVICE_TOGGLE_MS;
+ while (SystemClock.uptimeMillis() < timeoutTimeMillis) {
+ synchronized (waitLockForA11yOff) {
+ if (!manager.isEnabled()) {
+ return;
+ }
+ try {
+ waitLockForA11yOff.wait(timeoutTimeMillis - SystemClock.uptimeMillis());
+ } catch (InterruptedException e) {
+ // Ignored; loop again
+ }
+ }
+ }
+ throw new RuntimeException("Unable to turn accessibility off");
+ }
+
+ private void enableTestService() throws Exception {
+ Context context = getInstrumentation().getContext();
+ AccessibilityManager manager =
+ (AccessibilityManager) context.getSystemService(Context.ACCESSIBILITY_SERVICE);
+ List<AccessibilityServiceInfo> serviceInfos =
+ manager.getInstalledAccessibilityServiceList();
+ for (int i = 0; i < serviceInfos.size(); i++) {
+ AccessibilityServiceInfo serviceInfo = serviceInfos.get(i);
+ if (context.getString(R.string.soft_keyboard_modes_accessibility_service_description)
+ .equals(serviceInfo.getDescription())) {
+ ContentResolver cr = context.getContentResolver();
+ UiAutomation uiAutomation = getUiAutomation();
+ String command = "settings put secure "
+ + Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES + " "
+ + serviceInfo.getId();
+ executeShellCommand(uiAutomation, command);
+ executeShellCommand(uiAutomation, "settings put secure "
+ + Settings.Secure.ACCESSIBILITY_ENABLED + " 1");
+ uiAutomation.destroy();
+
+ // We have enabled the services of interest and need to wait until they
+ // are instantiated and started (if needed) and the system binds to them.
+ long timeoutTimeMillis = SystemClock.uptimeMillis() + TIMEOUT_SERVICE_TOGGLE_MS;
+ while (SystemClock.uptimeMillis() < timeoutTimeMillis) {
+ synchronized(
+ StubSoftKeyboardModesAccessibilityService.sWaitObjectForConnecting) {
+ if (StubSoftKeyboardModesAccessibilityService.sInstance != null) {
+ mService = StubSoftKeyboardModesAccessibilityService.sInstance;
+ mKeyboardController = mService.getTestSoftKeyboardController();
+ return;
+ }
+ try {
+ StubSoftKeyboardModesAccessibilityService.sWaitObjectForConnecting.wait(
+ timeoutTimeMillis - SystemClock.uptimeMillis());
+ } catch (InterruptedException e) {
+ // Ignored; loop again
+ }
+ }
+ }
+ throw new IllegalStateException("Stub accessibility service not started");
+ }
+ }
+ throw new IllegalStateException("Stub accessiblity service not found");
+ }
+
+ /**
+ * Activity for testing the AccessibilityService API for hiding and showring the soft keyboard.
+ */
+ public static class SoftKeyboardModesActivity extends AccessibilityTestActivity {
+ public SoftKeyboardModesActivity() {
+ super();
+ }
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.accessibility_soft_keyboard_modes_test);
+ }
+ }
+}
diff --git a/tests/accessibilityservice/src/android/accessibilityservice/cts/StubSoftKeyboardModesAccessibilityService.java b/tests/accessibilityservice/src/android/accessibilityservice/cts/StubSoftKeyboardModesAccessibilityService.java
new file mode 100644
index 0000000..27d51d9
--- /dev/null
+++ b/tests/accessibilityservice/src/android/accessibilityservice/cts/StubSoftKeyboardModesAccessibilityService.java
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.accessibilityservice.cts;
+
+import android.accessibilityservice.AccessibilityService;
+import android.content.Intent;
+import android.view.accessibility.AccessibilityEvent;
+import android.view.accessibility.AccessibilityWindowInfo;
+
+/**
+ * Stub accessibility service for testing APIs to show/hide Soft Keyboard.
+ */
+public class StubSoftKeyboardModesAccessibilityService extends AccessibilityService {
+
+ public static Object sWaitObjectForConnecting = new Object();
+
+ public static StubSoftKeyboardModesAccessibilityService sInstance = null;
+
+ @Override
+ protected void onServiceConnected() {
+ synchronized (sWaitObjectForConnecting) {
+ sInstance = this;
+ sWaitObjectForConnecting.notifyAll();
+ }
+ }
+
+ @Override
+ public void onDestroy() {
+ sInstance = null;
+ super.onDestroy();
+ }
+
+ @Override
+ public void onAccessibilityEvent(AccessibilityEvent event) {
+ /* do nothing */
+ }
+
+ @Override
+ public void onInterrupt() {
+ /* do nothing */
+ }
+
+ public SoftKeyboardController getTestSoftKeyboardController() {
+ return sInstance.getSoftKeyboardController();
+ }
+
+ public int getTestWindowsListSize() {
+ return sInstance.getWindows().size();
+ }
+}
diff --git a/tests/tests/graphics/src/android/graphics/cts/RegionTest.java b/tests/tests/graphics/src/android/graphics/cts/RegionTest.java
index 803f3e9..10e277b 100644
--- a/tests/tests/graphics/src/android/graphics/cts/RegionTest.java
+++ b/tests/tests/graphics/src/android/graphics/cts/RegionTest.java
@@ -1497,21 +1497,42 @@
Rect oriRect = new Rect(0, 0, 10, 10);
mRegion = new Region();
+ // test reading/writing an empty parcel
Parcel p = Parcel.obtain();
mRegion.writeToParcel(p, flags);
- assertEquals(8, p.dataSize());
-
- p = Parcel.obtain();
- mRegion.set(oriRect);
- mRegion.writeToParcel(p, flags);
- assertEquals(24, p.dataSize());
p.setDataPosition(0);
Region dst = Region.CREATOR.createFromParcel(p);
+ assertTrue(dst.isEmpty());
+
+ // test reading/writing a single rect parcel
+ p = Parcel.obtain();
+ mRegion.set(oriRect);
+ mRegion.writeToParcel(p, flags);
+
+ p.setDataPosition(0);
+ dst = Region.CREATOR.createFromParcel(p);
assertEquals(oriRect.top, dst.getBounds().top);
assertEquals(oriRect.left, dst.getBounds().left);
assertEquals(oriRect.bottom, dst.getBounds().bottom);
assertEquals(oriRect.right, dst.getBounds().right);
+
+ // test reading/writing a multiple rect parcel
+ p = Parcel.obtain();
+ mRegion.op(5, 5, 15, 15, Region.Op.UNION);
+ mRegion.writeToParcel(p, flags);
+
+ p.setDataPosition(0);
+ dst = Region.CREATOR.createFromParcel(p);
+ assertTrue(dst.contains(2,2));
+ assertTrue(dst.contains(7,7));
+ assertTrue(dst.contains(12,12));
+ assertFalse(dst.contains(2,12));
+ assertFalse(dst.contains(12,2));
+ assertEquals(0, dst.getBounds().top);
+ assertEquals(0, dst.getBounds().left);
+ assertEquals(15, dst.getBounds().bottom);
+ assertEquals(15, dst.getBounds().right);
}
public void testDescribeContents() {
diff --git a/tests/tests/provider/src/android/provider/cts/ContactsContract_PhoneLookup.java b/tests/tests/provider/src/android/provider/cts/ContactsContract_PhoneLookup.java
index 434ac20..556fb2d 100644
--- a/tests/tests/provider/src/android/provider/cts/ContactsContract_PhoneLookup.java
+++ b/tests/tests/provider/src/android/provider/cts/ContactsContract_PhoneLookup.java
@@ -23,6 +23,7 @@
import android.provider.ContactsContract;
import android.provider.ContactsContract.CommonDataKinds.Email;
import android.provider.ContactsContract.CommonDataKinds.Phone;
+import android.provider.ContactsContract.CommonDataKinds.SipAddress;
import android.provider.ContactsContract.CommonDataKinds.StructuredName;
import android.provider.ContactsContract.Contacts;
import android.provider.ContactsContract.PhoneLookup;
@@ -60,7 +61,17 @@
mBuilder.cleanup();
}
- private long[] setupTestData() throws Exception {
+ static class Id {
+ public long contactId;
+ public long dataId;
+
+ public Id (long contactId, long dataId) {
+ this.contactId = contactId;
+ this.dataId = dataId;
+ }
+ }
+
+ private Id[] setupTestData() throws Exception {
TestRawContact rawContact = mBuilder.newRawContact()
.with(RawContacts.ACCOUNT_TYPE, "test_account")
.with(RawContacts.ACCOUNT_NAME, "test_name")
@@ -68,7 +79,7 @@
rawContact.newDataRow(StructuredName.CONTENT_ITEM_TYPE)
.with(StructuredName.DISPLAY_NAME, "Hot Tamale")
.insert();
- rawContact.newDataRow(Phone.CONTENT_ITEM_TYPE)
+ long dataId = rawContact.newDataRow(Phone.CONTENT_ITEM_TYPE)
.with(Phone.DATA, "1111222333444")
.with(Email.TYPE, Phone.TYPE_HOME)
.insert().load().getId();
@@ -82,24 +93,41 @@
rawContact2.newDataRow(StructuredName.CONTENT_ITEM_TYPE)
.with(StructuredName.DISPLAY_NAME, "Cold Tamago")
.insert();
- rawContact2.newDataRow(Phone.CONTENT_ITEM_TYPE)
+ long dataId2 = rawContact2.newDataRow(Phone.CONTENT_ITEM_TYPE)
.with(Phone.DATA, "2111222333444")
.with(Phone.TYPE, Phone.TYPE_OTHER)
- .insert().load();
-
+ .insert().load().getId();
rawContact2.load();
TestContact contact2 = rawContact2.getContact().load();
- return new long[] {
- contact.getId(), contact2.getId()
+ // Contact with SIP address
+ TestRawContact rawContact3 = mBuilder.newRawContact()
+ .with(RawContacts.ACCOUNT_TYPE, "test_account")
+ .with(RawContacts.ACCOUNT_NAME, "test_name")
+ .insert();
+ rawContact3.newDataRow(StructuredName.CONTENT_ITEM_TYPE)
+ .with(StructuredName.DISPLAY_NAME, "Warm Tempura")
+ .insert();
+ long dataId3 = rawContact2.newDataRow(SipAddress.CONTENT_ITEM_TYPE)
+ .with(SipAddress.SIP_ADDRESS, "777@sip.org")
+ .with(SipAddress.TYPE, SipAddress.TYPE_WORK)
+ .insert().load().getId();
+ rawContact3.load();
+ TestContact contact3 = rawContact2.getContact().load();
+
+ return new Id[] {
+ new Id(contact.getId(), dataId),
+ new Id(contact2.getId(), dataId2),
+ new Id(contact3.getId(), dataId3)
};
+
}
/**
* Test for {@link android.provider.ContactsContract.PhoneLookup#CONTENT_FILTER_URI}.
*/
public void testPhoneLookup_nomatch() throws Exception {
- long[] ids = setupTestData();
+ Id[] ids = setupTestData();
final Uri uri = PhoneLookup.CONTENT_FILTER_URI.buildUpon()
.appendPath("no-such-phone-number").build();
@@ -110,12 +138,14 @@
* Test for {@link android.provider.ContactsContract.PhoneLookup#CONTENT_FILTER_URI}.
*/
public void testPhoneLookup_found1() throws Exception {
- long[] ids = setupTestData();
+ Id[] ids = setupTestData();
final Uri uri = PhoneLookup.CONTENT_FILTER_URI.buildUpon()
.appendPath("1111222333444").build();
final ContentValues expected = new ContentValues();
- expected.put(PhoneLookup._ID, ids[0]);
+ expected.put(PhoneLookup._ID, ids[0].contactId);
+ expected.put(PhoneLookup.CONTACT_ID, ids[0].contactId);
+ expected.put(PhoneLookup.DATA_ID, ids[0].dataId);
expected.put(PhoneLookup.NUMBER, "1111222333444");
assertCursorStoredValuesWithContactsFilter(uri, ids, expected);
@@ -125,22 +155,39 @@
* Test for {@link android.provider.ContactsContract.PhoneLookup#CONTENT_FILTER_URI}.
*/
public void testPhoneLookup_found2() throws Exception {
- long[] ids = setupTestData();
+ Id[] ids = setupTestData();
final Uri uri = PhoneLookup.CONTENT_FILTER_URI.buildUpon()
.appendPath("2111222333444").build();
final ContentValues expected = new ContentValues();
- expected.put(PhoneLookup._ID, ids[1]);
+ expected.put(PhoneLookup._ID, ids[1].contactId);
+ expected.put(PhoneLookup.CONTACT_ID, ids[1].contactId);
+ expected.put(PhoneLookup.DATA_ID, ids[1].dataId);
expected.put(PhoneLookup.NUMBER, "2111222333444");
assertCursorStoredValuesWithContactsFilter(uri, ids, expected);
}
+ public void testPhoneLookup_sip_found() throws Exception {
+ Id[] ids = setupTestData();
+ final Uri uri = PhoneLookup.CONTENT_FILTER_URI.buildUpon()
+ .appendPath("777@sip.org")
+ .appendQueryParameter(PhoneLookup.QUERY_PARAMETER_SIP_ADDRESS, "1")
+ .build();
+
+ final ContentValues expected = new ContentValues();
+ expected.put(PhoneLookup.CONTACT_ID, ids[2].contactId);
+ expected.put(PhoneLookup.DATA_ID, ids[2].dataId);
+ expected.put(SipAddress.SIP_ADDRESS, "777@sip.org");
+
+ assertCursorStoredValuesWithContactsFilter(uri, ids, expected);
+ }
+
/**
* Test for {@link android.provider.ContactsContract.PhoneLookup#ENTERPRISE_CONTENT_FILTER_URI}.
*/
public void testPhoneLookupEnterprise_nomatch() throws Exception {
- long[] ids = setupTestData();
+ Id[] ids = setupTestData();
final Uri uri = PhoneLookup.ENTERPRISE_CONTENT_FILTER_URI.buildUpon()
.appendPath("no-such-phone-number").build();
@@ -151,12 +198,14 @@
* Test for {@link android.provider.ContactsContract.PhoneLookup#ENTERPRISE_CONTENT_FILTER_URI}.
*/
public void testPhoneLookupEnterprise_found1() throws Exception {
- long[] ids = setupTestData();
+ Id[] ids = setupTestData();
final Uri uri = PhoneLookup.ENTERPRISE_CONTENT_FILTER_URI.buildUpon()
.appendPath("1111222333444").build();
final ContentValues expected = new ContentValues();
- expected.put(PhoneLookup._ID, ids[0]);
+ expected.put(PhoneLookup._ID, ids[0].contactId);
+ expected.put(PhoneLookup.CONTACT_ID, ids[0].contactId);
+ expected.put(PhoneLookup.DATA_ID, ids[0].dataId);
expected.put(PhoneLookup.NUMBER, "1111222333444");
assertCursorStoredValuesWithContactsFilter(uri, ids, expected);
@@ -166,27 +215,45 @@
* Test for {@link android.provider.ContactsContract.PhoneLookup#ENTERPRISE_CONTENT_FILTER_URI}.
*/
public void testPhoneLookupEnterprise_found2() throws Exception {
- long[] ids = setupTestData();
+ Id[] ids = setupTestData();
final Uri uri = PhoneLookup.ENTERPRISE_CONTENT_FILTER_URI.buildUpon()
.appendPath("2111222333444").build();
final ContentValues expected = new ContentValues();
- expected.put(PhoneLookup._ID, ids[1]);
+ expected.put(PhoneLookup._ID, ids[1].contactId);
+ expected.put(PhoneLookup.CONTACT_ID, ids[1].contactId);
+ expected.put(PhoneLookup.DATA_ID, ids[1].dataId);
expected.put(PhoneLookup.NUMBER, "2111222333444");
assertCursorStoredValuesWithContactsFilter(uri, ids, expected);
}
- private void assertCursorStoredValuesWithContactsFilter(Uri uri, long[] contactsId,
+ public void testPhoneLookupEnterprise_sip_found() throws Exception {
+ Id[] ids = setupTestData();
+ final Uri uri = PhoneLookup.ENTERPRISE_CONTENT_FILTER_URI.buildUpon()
+ .appendPath("777@sip.org")
+ .appendQueryParameter(PhoneLookup.QUERY_PARAMETER_SIP_ADDRESS, "1")
+ .build();
+
+ final ContentValues expected = new ContentValues();
+ expected.put(PhoneLookup._ID, ids[2].dataId);
+ expected.put(PhoneLookup.CONTACT_ID, ids[2].contactId);
+ expected.put(PhoneLookup.DATA_ID, ids[2].dataId);
+ expected.put(SipAddress.SIP_ADDRESS, "777@sip.org");
+
+ assertCursorStoredValuesWithContactsFilter(uri, ids, expected);
+ }
+
+ private void assertCursorStoredValuesWithContactsFilter(Uri uri, Id[] ids,
ContentValues... expected) {
// We need this helper function to add a filter for specific contacts because
// otherwise tests will fail if performed on a device with existing contacts data
StringBuilder sb = new StringBuilder();
sb.append(Contacts._ID + " in ");
sb.append("(");
- for (int i = 0; i < contactsId.length; i++) {
+ for (int i = 0; i < ids.length; i++) {
if (i != 0) sb.append(",");
- sb.append(contactsId[i]);
+ sb.append(ids[i].contactId);
}
sb.append(")");
DatabaseAsserts.assertStoredValuesInUriMatchExactly(mResolver, uri, null,
diff --git a/tests/tests/tv/src/android/media/tv/cts/TvContractTest.java b/tests/tests/tv/src/android/media/tv/cts/TvContractTest.java
index 916cf6d..596f5fa 100644
--- a/tests/tests/tv/src/android/media/tv/cts/TvContractTest.java
+++ b/tests/tests/tv/src/android/media/tv/cts/TvContractTest.java
@@ -845,6 +845,9 @@
}
public void testBroadcastGenreEncodeDecode() {
+ if (!Utils.hasTvInputFramework(getContext())) {
+ return;
+ }
String[] broadcastGenre = new String[] {"Animation", "Classic, opera"};
insertProgramWithBroadcastGenre(broadcastGenre);
try (Cursor c = mContentResolver.query(TvContract.Programs.CONTENT_URI,
@@ -857,6 +860,9 @@
}
public void testBroadcastGenreQueryChannel() {
+ if (!Utils.hasTvInputFramework(getContext())) {
+ return;
+ }
// "Animation" is mapped to Genres.MOVIES
// "Classic, opera" is mapped to Genres.MUSIC
insertProgramWithBroadcastGenre(new String[]{"Animation"});
diff --git a/tests/tests/view/src/android/view/cts/FrameMetricsListenerTest.java b/tests/tests/view/src/android/view/cts/FrameMetricsListenerTest.java
new file mode 100644
index 0000000..860c394
--- /dev/null
+++ b/tests/tests/view/src/android/view/cts/FrameMetricsListenerTest.java
@@ -0,0 +1,243 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.view.cts;
+
+import android.view.cts.R;
+
+import android.app.Activity;
+import android.app.Instrumentation;
+import android.cts.util.PollingCheck;
+import android.os.Looper;
+import android.os.Handler;
+import android.os.HandlerThread;
+import android.os.SystemClock;
+import android.test.ActivityInstrumentationTestCase2;
+import android.util.Log;
+import android.view.FrameMetrics;
+import android.view.View;
+import android.view.Window;
+import android.widget.ScrollView;
+
+import java.lang.Thread;
+import java.lang.Exception;
+import java.lang.System;
+import java.util.ArrayList;
+import java.util.concurrent.atomic.AtomicInteger;
+
+public class FrameMetricsListenerTest extends ActivityInstrumentationTestCase2<MockActivity> {
+
+ private Instrumentation mInstrumentation;
+ private Window.FrameMetricsListener mFrameMetricsListener;
+ private Activity mActivity;
+
+ public FrameMetricsListenerTest() {
+ super(MockActivity.class);
+ }
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+ mActivity = getActivity();
+ mInstrumentation = getInstrumentation();
+ }
+
+ private void layout(final int layoutId) {
+ mInstrumentation.runOnMainSync(new Runnable() {
+ @Override
+ public void run() {
+ mActivity.setContentView(layoutId);
+ }
+ });
+ mInstrumentation.waitForIdleSync();
+ }
+
+ public void testReceiveData() throws Throwable {
+ layout(R.layout.scrollview_layout);
+ final ScrollView scrollView = (ScrollView) mActivity.findViewById(R.id.scroll_view);
+ final ArrayList<FrameMetrics> data = new ArrayList<>();
+ final Handler handler = new Handler(Looper.getMainLooper());
+ final Window myWindow = mActivity.getWindow();
+ final Window.FrameMetricsListener listener =
+ new Window.FrameMetricsListener() {
+ @Override
+ public void onMetricsAvailable(Window window, FrameMetrics frameMetrics, int dropCount) {
+ assertEquals(myWindow, window);
+ assertEquals(0, dropCount);
+ data.add(new FrameMetrics(frameMetrics));
+ }
+ };
+ runTestOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ mActivity.getWindow().addFrameMetricsListener(listener, handler);
+ }
+ });
+
+ mInstrumentation.waitForIdleSync();
+
+ runTestOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ scrollView.fling(-100);
+ }
+ });
+
+ mInstrumentation.waitForIdleSync();
+ new PollingCheck() {
+ @Override
+ protected boolean check() {
+ return data.size() != 0;
+ }
+ }.run();
+
+ runTestOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ mActivity.getWindow().removeFrameMetricsListener(listener);
+ data.clear();
+ }
+ });
+
+ mInstrumentation.waitForIdleSync();
+
+ runTestOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ scrollView.fling(100);
+ assertEquals(0, data.size());
+ }
+ });
+
+ mInstrumentation.waitForIdleSync();
+ }
+
+ public void testMultipleListeners() throws Throwable {
+ layout(R.layout.scrollview_layout);
+ final ScrollView scrollView = (ScrollView) mActivity.findViewById(R.id.scroll_view);
+ final ArrayList<FrameMetrics> data1 = new ArrayList<>();
+ final Handler handler = new Handler(Looper.getMainLooper());
+ final Window myWindow = mActivity.getWindow();
+
+ final Window.FrameMetricsListener frameMetricsListener1 =
+ new Window.FrameMetricsListener() {
+ @Override
+ public void onMetricsAvailable(Window window, FrameMetrics frameMetrics, int dropCount) {
+ assertEquals(myWindow, window);
+ assertEquals(0, dropCount);
+ data1.add(new FrameMetrics(frameMetrics));
+ }
+ };
+ final ArrayList<FrameMetrics> data2 = new ArrayList<>();
+ final Window.FrameMetricsListener frameMetricsListener2 =
+ new Window.FrameMetricsListener() {
+ @Override
+ public void onMetricsAvailable(Window window, FrameMetrics frameMetrics, int dropCount) {
+ assertEquals(myWindow, window);
+ assertEquals(0, dropCount);
+ data2.add(new FrameMetrics(frameMetrics));
+ }
+ };
+ runTestOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ mActivity.getWindow().addFrameMetricsListener(frameMetricsListener1, handler);
+ mActivity.getWindow().addFrameMetricsListener(frameMetricsListener2, handler);
+ }
+ });
+
+ mInstrumentation.waitForIdleSync();
+
+ runTestOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ scrollView.fling(-100);
+ }
+ });
+
+ mInstrumentation.waitForIdleSync();
+ new PollingCheck() {
+ @Override
+ protected boolean check() {
+ return data1.size() != 0 && data1.size() == data2.size();
+ }
+ }.run();
+
+ runTestOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ mActivity.getWindow().removeFrameMetricsListener(frameMetricsListener1);
+ mActivity.getWindow().removeFrameMetricsListener(frameMetricsListener2);
+ }
+ });
+ }
+
+ public void testDropCount() throws Throwable {
+ layout(R.layout.scrollview_layout);
+ final ScrollView scrollView = (ScrollView) mActivity.findViewById(R.id.scroll_view);
+
+ final Window window = mActivity.getWindow();
+ final AtomicInteger framesDropped = new AtomicInteger();
+ final AtomicInteger frameCount = new AtomicInteger();
+
+ final HandlerThread thread = new HandlerThread("Listener");
+ thread.start();
+ final Handler handler = new Handler(thread.getLooper());
+ final Window.FrameMetricsListener frameMetricsListener =
+ new Window.FrameMetricsListener() {
+ @Override
+ public void onMetricsAvailable(Window window, FrameMetrics frameMetrics, int dropCount) {
+ try {
+ Thread.sleep(100);
+ framesDropped.addAndGet(dropCount);
+ } catch (Exception e) { }
+ }
+ };
+
+ runTestOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ mActivity.getWindow().addFrameMetricsListener(frameMetricsListener, handler);
+ }
+ });
+
+ mInstrumentation.waitForIdleSync();
+
+ runTestOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ scrollView.fling(-100);
+ }
+ });
+
+ mInstrumentation.waitForIdleSync();
+ new PollingCheck() {
+ @Override
+ protected boolean check() {
+ return framesDropped.get() > 0;
+ }
+ }.run();
+
+ runTestOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ mActivity.getWindow().removeFrameMetricsListener(frameMetricsListener);
+ }
+ });
+ }
+}
+
+
diff --git a/tools/tradefed-host/src/com/android/cts/tradefed/testtype/DeqpTestRunner.java b/tools/tradefed-host/src/com/android/cts/tradefed/testtype/DeqpTestRunner.java
index 66fcd44..7bde54e 100644
--- a/tools/tradefed-host/src/com/android/cts/tradefed/testtype/DeqpTestRunner.java
+++ b/tools/tradefed-host/src/com/android/cts/tradefed/testtype/DeqpTestRunner.java
@@ -311,6 +311,8 @@
final Map<String, String> emptyMap = Collections.emptyMap();
mSink.testEnded(testId, emptyMap);
+ } else {
+ CLog.w("Finalization for non-pending case %s", testId);
}
}
@@ -372,6 +374,8 @@
public void abortTest(TestIdentifier testId, String errorMessage) {
final PendingResult result = mPendingResults.get(testId);
+ CLog.i("Test %s aborted with message %s", testId, errorMessage);
+
// Mark as executed
result.allInstancesPassed = false;
result.errorMessages.put(mRunConfig, errorMessage);
@@ -390,37 +394,57 @@
/**
* Handles beginning of dEQP session.
*/
- private void handleBeginSession(Map<String, String> values) {
+ private boolean handleBeginSession(Map<String, String> values) {
// ignore
+ return true;
+ }
+
+ /**
+ * Handle session info
+ */
+ private boolean handleSessionInfo(Map<String, String> values) {
+ // ignore
+ return true;
}
/**
* Handles end of dEQP session.
*/
- private void handleEndSession(Map<String, String> values) {
+ private boolean handleEndSession(Map<String, String> values) {
// ignore
+ return true;
}
/**
* Handles beginning of dEQP testcase.
*/
- private void handleBeginTestCase(Map<String, String> values) {
- mCurrentTestId = pathToIdentifier(values.get("dEQP-BeginTestCase-TestCasePath"));
+ private boolean handleBeginTestCase(Map<String, String> values) {
+ String casePath = values.get("dEQP-BeginTestCase-TestCasePath");
+
mCurrentTestLog = "";
mGotTestResult = false;
+ if (casePath == null) {
+ CLog.w("Got null case path for test case begin event. Current test ID: %s", mCurrentTestId);
+ mCurrentTestId = null;
+ return false;
+ }
+
+ mCurrentTestId = pathToIdentifier(casePath);
+
// mark instance as started
if (mPendingResults.get(mCurrentTestId) != null) {
mPendingResults.get(mCurrentTestId).remainingConfigs.remove(mRunConfig);
} else {
CLog.w("Got unexpected start of %s", mCurrentTestId);
}
+ return true;
}
/**
* Handles end of dEQP testcase.
*/
- private void handleEndTestCase(Map<String, String> values) {
+ private boolean handleEndTestCase(Map<String, String> values) {
final PendingResult result = mPendingResults.get(mCurrentTestId);
if (result != null) {
@@ -442,19 +466,24 @@
CLog.w("Got unexpected end of %s", mCurrentTestId);
}
mCurrentTestId = null;
+ return true;
}
/**
* Handles dEQP testcase result.
*/
- private void handleTestCaseResult(Map<String, String> values) {
+ private boolean handleTestCaseResult(Map<String, String> values) {
String code = values.get("dEQP-TestCaseResult-Code");
+ if (code == null) {
+ return false;
+ }
+
String details = values.get("dEQP-TestCaseResult-Details");
if (mPendingResults.get(mCurrentTestId) == null) {
CLog.w("Got unexpected result for %s", mCurrentTestId);
mGotTestResult = true;
- return;
+ return true;
}
if (code.compareTo("Pass") == 0) {
@@ -480,12 +509,13 @@
mGotTestResult = true;
CLog.e("Got invalid result code '%s' for test %s", code, mCurrentTestId);
}
+ return true;
}
/**
* Handles terminated dEQP testcase.
*/
- private void handleTestCaseTerminate(Map<String, String> values) {
+ private boolean handleTestCaseTerminate(Map<String, String> values) {
final PendingResult result = mPendingResults.get(mCurrentTestId);
if (result != null) {
@@ -504,40 +534,52 @@
mCurrentTestId = null;
mGotTestResult = true;
+ return true;
}
/**
* Handles dEQP testlog data.
*/
- private void handleTestLogData(Map<String, String> values) {
- mCurrentTestLog = mCurrentTestLog + values.get("dEQP-TestLogData-Log");
+ private boolean handleTestLogData(Map<String, String> values) {
+ String newLog = values.get("dEQP-TestLogData-Log");
+ if (newLog == null) {
+ return false;
+ }
+ mCurrentTestLog = mCurrentTestLog + newLog;
+ return true;
}
/**
* Handles new instrumentation status message.
+ * @return true if handled correctly, false if missing values.
*/
- public void handleStatus(Map<String, String> values) {
+ public boolean handleStatus(Map<String, String> values) {
String eventType = values.get("dEQP-EventType");
if (eventType == null) {
- return;
+ // Not an event, but some other line
+ return true;
}
if (eventType.compareTo("BeginSession") == 0) {
- handleBeginSession(values);
+ return handleBeginSession(values);
+ } else if (eventType.compareTo("SessionInfo") == 0) {
+ return handleSessionInfo(values);
} else if (eventType.compareTo("EndSession") == 0) {
- handleEndSession(values);
+ return handleEndSession(values);
} else if (eventType.compareTo("BeginTestCase") == 0) {
- handleBeginTestCase(values);
+ return handleBeginTestCase(values);
} else if (eventType.compareTo("EndTestCase") == 0) {
- handleEndTestCase(values);
+ return handleEndTestCase(values);
} else if (eventType.compareTo("TestCaseResult") == 0) {
- handleTestCaseResult(values);
+ return handleTestCaseResult(values);
} else if (eventType.compareTo("TerminateTestCase") == 0) {
- handleTestCaseTerminate(values);
+ return handleTestCaseTerminate(values);
} else if (eventType.compareTo("TestLogData") == 0) {
- handleTestLogData(values);
+ return handleTestLogData(values);
}
+ CLog.e("Unknown event type (%s)", eventType);
+ return false;
}
/**
@@ -548,6 +590,7 @@
if (mCurrentTestId != null) {
// Current instance was removed from remainingConfigs when case
// started. Mark current instance as pending.
+ CLog.i("Batch ended with test '%s' current", mCurrentTestId);
if (mPendingResults.get(mCurrentTestId) != null) {
mPendingResults.get(mCurrentTestId).remainingConfigs.add(mRunConfig);
} else {
@@ -569,6 +612,7 @@
private String mCurrentValue;
private int mResultCode;
private boolean mGotExitValue = false;
+ private boolean mParseSuccessful = true;
public InstrumentationParser(TestInstanceResultListener listener) {
@@ -591,7 +635,7 @@
mCurrentValue = null;
}
- mListener.handleStatus(mValues);
+ mParseSuccessful &= mListener.handleStatus(mValues);
mValues = null;
} else if (line.startsWith("INSTRUMENTATION_STATUS: dEQP-")) {
if (mCurrentName != null) {
@@ -604,16 +648,25 @@
String prefix = "INSTRUMENTATION_STATUS: ";
int nameBegin = prefix.length();
int nameEnd = line.indexOf('=');
- int valueBegin = nameEnd + 1;
-
- mCurrentName = line.substring(nameBegin, nameEnd);
- mCurrentValue = line.substring(valueBegin);
+ if (nameEnd < 0) {
+ CLog.e("Line does not contain value. Logcat interrupted? (%s)", line);
+ mCurrentValue = null;
+ mCurrentName = null;
+ mParseSuccessful = false;
+ return;
+ } else {
+ int valueBegin = nameEnd + 1;
+ mCurrentName = line.substring(nameBegin, nameEnd);
+ mCurrentValue = line.substring(valueBegin);
+ }
} else if (line.startsWith("INSTRUMENTATION_CODE: ")) {
try {
mResultCode = Integer.parseInt(line.substring(22));
mGotExitValue = true;
} catch (NumberFormatException ex) {
- CLog.w("Instrumentation code format unexpected");
+ CLog.e("Instrumentation code format unexpected");
+ mParseSuccessful = false;
+ return;
}
} else if (mCurrentValue != null) {
mCurrentValue = mCurrentValue + line;
@@ -634,7 +687,7 @@
}
if (mValues != null) {
- mListener.handleStatus(mValues);
+ mParseSuccessful &= mListener.handleStatus(mValues);
mValues = null;
}
}
@@ -651,7 +704,7 @@
* Returns whether target instrumentation exited normally.
*/
public boolean wasSuccessful() {
- return mGotExitValue;
+ return mGotExitValue && mParseSuccessful;
}
/**
@@ -1452,11 +1505,12 @@
Throwable interruptingError = null;
try {
+ CLog.d("Running command '%s'", command);
executeShellCommandAndReadOutput(command, parser);
- } catch (Throwable ex) {
- interruptingError = ex;
- } finally {
parser.flush();
+ } catch (Throwable ex) {
+ CLog.w("Instrumented call threw '%s'", ex.getMessage());
+ interruptingError = ex;
}
final boolean progressedSinceLastCall = mInstanceListerner.getCurrentTestId() != null ||
diff --git a/tools/tradefed-host/tests/src/com/android/cts/tradefed/testtype/DeqpTestRunnerTest.java b/tools/tradefed-host/tests/src/com/android/cts/tradefed/testtype/DeqpTestRunnerTest.java
index 2c8a816..2ba6b42 100644
--- a/tools/tradefed-host/tests/src/com/android/cts/tradefed/testtype/DeqpTestRunnerTest.java
+++ b/tools/tradefed-host/tests/src/com/android/cts/tradefed/testtype/DeqpTestRunnerTest.java
@@ -1162,6 +1162,735 @@
EasyMock.verify(mockDevice);
}
+ public void testRun_sessionInfoValueMissing() throws Exception {
+ final String instrumentationAnswerOk =
+ "INSTRUMENTATION_STATUS: dEQP-SessionInfo-Name=releaseName\r\n"
+ + "INSTRUMENTATION_STATUS: dEQP-EventType=SessionInfo\r\n"
+ + "INSTRUMENTATION_STATUS: dEQP-SessionInfo-Value=2014.x\r\n"
+ + "INSTRUMENTATION_STATUS_CODE: 0\r\n"
+ + "INSTRUMENTATION_STATUS: dEQP-SessionInfo-Name=releaseId\r\n"
+ + "INSTRUMENTATION_STATUS: dEQP-EventType=SessionInfo\r\n"
+ + "INSTRUMENTATION_STATUS: dEQP-SessionInfo-Value=0xcafebabe\r\n"
+ + "INSTRUMENTATION_STATUS_CODE: 0\r\n"
+ + "INSTRUMENTATION_STATUS: dEQP-SessionInfo-Name=targetName\r\n"
+ + "INSTRUMENTATION_STATUS: dEQP-EventType=SessionInfo\r\n"
+ + "INSTRUMENTATION_STATUS: dEQP-SessionInfo-Value=android\r\n"
+ + "INSTRUMENTATION_STATUS_CODE: 0\r\n"
+ + "INSTRUMENTATION_STATUS: dEQP-EventType=BeginSession\r\n"
+ + "INSTRUMENTATION_STATUS_CODE: 0\r\n"
+ + "INSTRUMENTATION_STATUS: dEQP-EventType=BeginTestCase\r\n"
+ + "INSTRUMENTATION_STATUS: dEQP-BeginTestCase-TestCasePath=dEQP-GLES3.instances.test1\r\n"
+ + "INSTRUMENTATION_STATUS_CODE: 0\r\n"
+ + "INSTRUMENTATION_STATUS: dEQP-TestCaseResult-Code=Pass\r\n"
+ + "INSTRUMENTATION_STATUS: dEQP-TestCaseResult-Details=Pass\r\n"
+ + "INSTRUMENTATION_STATUS: dEQP-EventType=TestCaseResult\r\n"
+ + "INSTRUMENTATION_STATUS_CODE: 0\r\n"
+ + "INSTRUMENTATION_STATUS: dEQP-EventType=EndTestCase\r\n"
+ + "INSTRUMENTATION_STATUS_CODE: 0\r\n"
+ + "INSTRUMENTATION_STATUS: dEQP-EventType=EndSession\r\n"
+ + "INSTRUMENTATION_STATUS_CODE: 0\r\n"
+ + "INSTRUMENTATION_CODE: 0\r\n";
+
+ final String instrumentationAnswerBroken =
+ "INSTRUMENTATION_STATUS: dEQP-SessionInfo-Name=releaseName\r\n"
+ + "INSTRUMENTATION_STATUS: dEQP-EventType=SessionInfo\r\n"
+ + "INSTRUMENTATION_STATUS: dEQP-SessionInfo-Value=2014.x\r\n"
+ + "INSTRUMENTATION_STATUS_CODE: 0\r\n"
+ + "INSTRUMENTATION_STATUS: dEQP-SessionInfo-Name=releaseId\r\n"
+ + "INSTRUMENTATION_STATUS: dEQP-EventType=SessionInfo\r\n";
+
+ final TestIdentifier[] testIds = {
+ new TestIdentifier("dEQP-GLES3.instances", "test1"),
+ };
+
+ final String[] testPaths = {
+ "dEQP-GLES3.instances.test1",
+ };
+
+ Map<String,String> config = new HashMap<>();
+ config.put("glconfig", "rgba8888d24s8");
+ config.put("rotation", "unspecified");
+ config.put("surfacetype", "window");
+
+ Map<TestIdentifier, List<Map<String, String>>> instances = new HashMap<>();
+
+ instances.put(testIds[0], new ArrayList<Map<String,String>>());
+ instances.get(testIds[0]).add(config);
+
+ Collection<TestIdentifier> tests = new ArrayList<TestIdentifier>();
+ for (TestIdentifier id : testIds) {
+ tests.add(id);
+ }
+
+ ITestInvocationListener mockListener
+ = EasyMock.createStrictMock(ITestInvocationListener.class);
+ IMocksControl orderedControl = EasyMock.createStrictControl();
+ ITestDevice mockDevice = orderedControl.createMock(ITestDevice.class);
+ IDevice mockIDevice = orderedControl.createMock(IDevice.class);
+
+ DeqpTestRunner.IRecovery mockRecovery = EasyMock.createMock(DeqpTestRunner.IRecovery.class);
+
+ DeqpTestRunner deqpTest = new DeqpTestRunner(NAME, NAME, tests, instances);
+ deqpTest.setAbi(UnitTests.ABI);
+ deqpTest.setDevice(mockDevice);
+ deqpTest.setBuildHelper(new StubCtsBuildHelper());
+ deqpTest.setRecovery(mockRecovery);
+
+ int version = 3 << 16;
+ EasyMock.expect(mockDevice.getProperty("ro.opengles.version"))
+ .andReturn(Integer.toString(version)).atLeastOnce();
+
+ mockRecovery.onExecutionProgressed();
+ EasyMock.expectLastCall().atLeastOnce();
+
+ mockRecovery.setDevice(mockDevice);
+ EasyMock.expectLastCall().atLeastOnce();
+
+ EasyMock.expect(mockDevice.uninstallPackage(EasyMock.eq(DEQP_ONDEVICE_PKG))).
+ andReturn("").once();
+
+ EasyMock.expect(mockDevice.installPackage(EasyMock.<File>anyObject(),
+ EasyMock.eq(true),
+ EasyMock.eq(AbiUtils.createAbiFlag(UnitTests.ABI.getName())))).andReturn(null)
+ .once();
+
+ // query config
+ expectRenderConfigQueryAndReturn(mockDevice,
+ "--deqp-gl-config-name=rgba8888d24s8 "
+ + "--deqp-screen-rotation=unspecified "
+ + "--deqp-surface-type=window "
+ + "--deqp-gl-major-version=3 "
+ + "--deqp-gl-minor-version=0", "Yes");
+
+ // run config and fail
+ runInstrumentationLineAndAnswer(mockDevice, mockIDevice,
+ "{dEQP-GLES3{instances{test1}}}",
+ "--deqp-caselist-file=" + CASE_LIST_FILE_NAME
+ + " --deqp-gl-config-name=rgba8888d24s8 "
+ + "--deqp-screen-rotation=unspecified "
+ + "--deqp-surface-type=window "
+ + "--deqp-log-images=disable "
+ + "--deqp-watchdog=enable", instrumentationAnswerBroken);
+
+ mockRecovery.recoverComLinkKilled();
+ EasyMock.expectLastCall().once();
+
+ // Re-try
+ runInstrumentationLineAndAnswer(mockDevice, mockIDevice,
+ "{dEQP-GLES3{instances{test1}}}",
+ "--deqp-caselist-file=" + CASE_LIST_FILE_NAME
+ + " --deqp-gl-config-name=rgba8888d24s8 "
+ + "--deqp-screen-rotation=unspecified "
+ + "--deqp-surface-type=window "
+ + "--deqp-log-images=disable "
+ + "--deqp-watchdog=enable", instrumentationAnswerOk);
+
+ EasyMock.expect(mockDevice.uninstallPackage(EasyMock.eq(DEQP_ONDEVICE_PKG)))
+ .andReturn("").once();
+
+ mockListener.testRunStarted(ID, 1);
+ EasyMock.expectLastCall().once();
+
+ // test1
+ mockListener.testStarted(EasyMock.eq(testIds[0]));
+ EasyMock.expectLastCall().once();
+
+ mockListener.testEnded(EasyMock.eq(testIds[0]), EasyMock.<Map<String, String>>notNull());
+ EasyMock.expectLastCall().once();
+
+ mockListener.testRunEnded(EasyMock.anyLong(), EasyMock.<Map<String, String>>notNull());
+ EasyMock.expectLastCall().once();
+
+ orderedControl.replay();
+ EasyMock.replay(mockListener);
+ EasyMock.replay(mockRecovery);
+ deqpTest.run(mockListener);
+
+ EasyMock.verify(mockListener);
+ orderedControl.verify();
+ EasyMock.verify(mockRecovery);
+ }
+
+ public void testRun_resultEventTypeMissing() throws Exception {
+ final String instrumentationAnswerOk =
+ "INSTRUMENTATION_STATUS: dEQP-SessionInfo-Name=releaseName\r\n"
+ + "INSTRUMENTATION_STATUS: dEQP-EventType=SessionInfo\r\n"
+ + "INSTRUMENTATION_STATUS: dEQP-SessionInfo-Value=2014.x\r\n"
+ + "INSTRUMENTATION_STATUS_CODE: 0\r\n"
+ + "INSTRUMENTATION_STATUS: dEQP-SessionInfo-Name=releaseId\r\n"
+ + "INSTRUMENTATION_STATUS: dEQP-EventType=SessionInfo\r\n"
+ + "INSTRUMENTATION_STATUS: dEQP-SessionInfo-Value=0xcafebabe\r\n"
+ + "INSTRUMENTATION_STATUS_CODE: 0\r\n"
+ + "INSTRUMENTATION_STATUS: dEQP-SessionInfo-Name=targetName\r\n"
+ + "INSTRUMENTATION_STATUS: dEQP-EventType=SessionInfo\r\n"
+ + "INSTRUMENTATION_STATUS: dEQP-SessionInfo-Value=android\r\n"
+ + "INSTRUMENTATION_STATUS_CODE: 0\r\n"
+ + "INSTRUMENTATION_STATUS: dEQP-EventType=BeginSession\r\n"
+ + "INSTRUMENTATION_STATUS_CODE: 0\r\n"
+ + "INSTRUMENTATION_STATUS: dEQP-EventType=BeginTestCase\r\n"
+ + "INSTRUMENTATION_STATUS: dEQP-BeginTestCase-TestCasePath=dEQP-GLES3.instances.test1\r\n"
+ + "INSTRUMENTATION_STATUS_CODE: 0\r\n"
+ + "INSTRUMENTATION_STATUS: dEQP-TestCaseResult-Code=Pass\r\n"
+ + "INSTRUMENTATION_STATUS: dEQP-TestCaseResult-Details=Pass\r\n"
+ + "INSTRUMENTATION_STATUS: dEQP-EventType=TestCaseResult\r\n"
+ + "INSTRUMENTATION_STATUS_CODE: 0\r\n"
+ + "INSTRUMENTATION_STATUS: dEQP-EventType=EndTestCase\r\n"
+ + "INSTRUMENTATION_STATUS_CODE: 0\r\n"
+ + "INSTRUMENTATION_STATUS: dEQP-EventType=EndSession\r\n"
+ + "INSTRUMENTATION_STATUS_CODE: 0\r\n"
+ + "INSTRUMENTATION_CODE: 0\r\n";
+
+ final String instrumentationAnswerBroken =
+ "INSTRUMENTATION_STATUS: dEQP-SessionInfo-Name=releaseName\r\n"
+ + "INSTRUMENTATION_STATUS: dEQP-EventType=SessionInfo\r\n"
+ + "INSTRUMENTATION_STATUS: dEQP-SessionInfo-Value=2014.x\r\n"
+ + "INSTRUMENTATION_STATUS_CODE: 0\r\n"
+ + "INSTRUMENTATION_STATUS: dEQP-SessionInfo-Name=releaseId\r\n"
+ + "INSTRUMENTATION_STATUS: dEQP-EventType=SessionInfo\r\n"
+ + "INSTRUMENTATION_STATUS: dEQP-SessionInfo-Value=0xcafebabe\r\n"
+ + "INSTRUMENTATION_STATUS_CODE: 0\r\n"
+ + "INSTRUMENTATION_STATUS: dEQP-SessionInfo-Name=targetName\r\n"
+ + "INSTRUMENTATION_STATUS: dEQP-EventType=SessionInfo\r\n"
+ + "INSTRUMENTATION_STATUS: dEQP-SessionInfo-Value=android\r\n"
+ + "INSTRUMENTATION_STATUS_CODE: 0\r\n"
+ + "INSTRUMENTATION_STATUS: dEQP-EventType=BeginSession\r\n"
+ + "INSTRUMENTATION_STATUS_CODE: 0\r\n"
+ + "INSTRUMENTATION_STATUS: dEQP-EventType=BeginTestCase\r\n"
+ + "INSTRUMENTATION_STATUS: dEQP-BeginTestCase-TestCasePath=dEQP-GLES3.instances.test1\r\n"
+ + "INSTRUMENTATION_STATUS_CODE: 0\r\n"
+ + "INSTRUMENTATION_STATUS: dEQP-TestCaseResult-Code=Pass\r\n"
+ + "INSTRUMENTATION_STATUS: dEQP-TestCaseResult-Details=Pass\r\n";
+
+ final TestIdentifier[] testIds = {
+ new TestIdentifier("dEQP-GLES3.instances", "test1"),
+ };
+
+ final String[] testPaths = {
+ "dEQP-GLES3.instances.test1",
+ };
+
+ Map<String,String> config = new HashMap<>();
+ config.put("glconfig", "rgba8888d24s8");
+ config.put("rotation", "unspecified");
+ config.put("surfacetype", "window");
+
+ Map<TestIdentifier, List<Map<String, String>>> instances = new HashMap<>();
+
+ instances.put(testIds[0], new ArrayList<Map<String,String>>());
+ instances.get(testIds[0]).add(config);
+
+ Collection<TestIdentifier> tests = new ArrayList<TestIdentifier>();
+ for (TestIdentifier id : testIds) {
+ tests.add(id);
+ }
+
+ ITestInvocationListener mockListener
+ = EasyMock.createStrictMock(ITestInvocationListener.class);
+ IMocksControl orderedControl = EasyMock.createStrictControl();
+ ITestDevice mockDevice = orderedControl.createMock(ITestDevice.class);
+ IDevice mockIDevice = orderedControl.createMock(IDevice.class);
+
+ DeqpTestRunner.IRecovery mockRecovery = EasyMock.createMock(DeqpTestRunner.IRecovery.class);
+
+ DeqpTestRunner deqpTest = new DeqpTestRunner(NAME, NAME, tests, instances);
+ deqpTest.setAbi(UnitTests.ABI);
+ deqpTest.setDevice(mockDevice);
+ deqpTest.setBuildHelper(new StubCtsBuildHelper());
+ deqpTest.setRecovery(mockRecovery);
+
+ int version = 3 << 16;
+ EasyMock.expect(mockDevice.getProperty("ro.opengles.version"))
+ .andReturn(Integer.toString(version)).atLeastOnce();
+
+ mockRecovery.onExecutionProgressed();
+ EasyMock.expectLastCall().atLeastOnce();
+
+ mockRecovery.setDevice(mockDevice);
+ EasyMock.expectLastCall().atLeastOnce();
+
+ EasyMock.expect(mockDevice.uninstallPackage(EasyMock.eq(DEQP_ONDEVICE_PKG))).
+ andReturn("").once();
+
+ EasyMock.expect(mockDevice.installPackage(EasyMock.<File>anyObject(),
+ EasyMock.eq(true),
+ EasyMock.eq(AbiUtils.createAbiFlag(UnitTests.ABI.getName())))).andReturn(null)
+ .once();
+
+ // query config
+ expectRenderConfigQueryAndReturn(mockDevice,
+ "--deqp-gl-config-name=rgba8888d24s8 "
+ + "--deqp-screen-rotation=unspecified "
+ + "--deqp-surface-type=window "
+ + "--deqp-gl-major-version=3 "
+ + "--deqp-gl-minor-version=0", "Yes");
+
+ // run config and fail
+ runInstrumentationLineAndAnswer(mockDevice, mockIDevice,
+ "{dEQP-GLES3{instances{test1}}}",
+ "--deqp-caselist-file=" + CASE_LIST_FILE_NAME
+ + " --deqp-gl-config-name=rgba8888d24s8 "
+ + "--deqp-screen-rotation=unspecified "
+ + "--deqp-surface-type=window "
+ + "--deqp-log-images=disable "
+ + "--deqp-watchdog=enable", instrumentationAnswerBroken);
+
+ mockRecovery.recoverComLinkKilled();
+ EasyMock.expectLastCall().once();
+
+ // Re-try
+ runInstrumentationLineAndAnswer(mockDevice, mockIDevice,
+ "{dEQP-GLES3{instances{test1}}}",
+ "--deqp-caselist-file=" + CASE_LIST_FILE_NAME
+ + " --deqp-gl-config-name=rgba8888d24s8 "
+ + "--deqp-screen-rotation=unspecified "
+ + "--deqp-surface-type=window "
+ + "--deqp-log-images=disable "
+ + "--deqp-watchdog=enable", instrumentationAnswerOk);
+
+ EasyMock.expect(mockDevice.uninstallPackage(EasyMock.eq(DEQP_ONDEVICE_PKG)))
+ .andReturn("").once();
+
+ mockListener.testRunStarted(ID, 1);
+ EasyMock.expectLastCall().once();
+
+ // test1
+ mockListener.testStarted(EasyMock.eq(testIds[0]));
+ EasyMock.expectLastCall().once();
+
+ mockListener.testEnded(EasyMock.eq(testIds[0]), EasyMock.<Map<String, String>>notNull());
+ EasyMock.expectLastCall().once();
+
+ mockListener.testRunEnded(EasyMock.anyLong(), EasyMock.<Map<String, String>>notNull());
+ EasyMock.expectLastCall().once();
+
+ orderedControl.replay();
+ EasyMock.replay(mockListener);
+ EasyMock.replay(mockRecovery);
+ deqpTest.run(mockListener);
+
+ EasyMock.verify(mockListener);
+ orderedControl.verify();
+ EasyMock.verify(mockRecovery);
+ }
+
+ /**
+ * Test handling of interrupted line in the instrumentation output
+ * and recovery from the error.
+ */
+ public void testRun_testCasePathInterrupted() throws Exception {
+ final String instrumentationAnswerOk1 =
+ "INSTRUMENTATION_STATUS: dEQP-SessionInfo-Name=releaseName\r\n"
+ + "INSTRUMENTATION_STATUS: dEQP-EventType=SessionInfo\r\n"
+ + "INSTRUMENTATION_STATUS: dEQP-SessionInfo-Value=2014.x\r\n"
+ + "INSTRUMENTATION_STATUS_CODE: 0\r\n"
+ + "INSTRUMENTATION_STATUS: dEQP-SessionInfo-Name=releaseId\r\n"
+ + "INSTRUMENTATION_STATUS: dEQP-EventType=SessionInfo\r\n"
+ + "INSTRUMENTATION_STATUS: dEQP-SessionInfo-Value=0xcafebabe\r\n"
+ + "INSTRUMENTATION_STATUS_CODE: 0\r\n"
+ + "INSTRUMENTATION_STATUS: dEQP-SessionInfo-Name=targetName\r\n"
+ + "INSTRUMENTATION_STATUS: dEQP-EventType=SessionInfo\r\n"
+ + "INSTRUMENTATION_STATUS: dEQP-SessionInfo-Value=android\r\n"
+ + "INSTRUMENTATION_STATUS_CODE: 0\r\n"
+ + "INSTRUMENTATION_STATUS: dEQP-EventType=BeginSession\r\n"
+ + "INSTRUMENTATION_STATUS_CODE: 0\r\n"
+ + "INSTRUMENTATION_STATUS: dEQP-EventType=BeginTestCase\r\n"
+ + "INSTRUMENTATION_STATUS: dEQP-BeginTestCase-TestCasePath=dEQP-GLES3.instances.test1\r\n"
+ + "INSTRUMENTATION_STATUS_CODE: 0\r\n"
+ + "INSTRUMENTATION_STATUS: dEQP-TestCaseResult-Code=Pass\r\n"
+ + "INSTRUMENTATION_STATUS: dEQP-TestCaseResult-Details=Pass\r\n"
+ + "INSTRUMENTATION_STATUS: dEQP-EventType=TestCaseResult\r\n"
+ + "INSTRUMENTATION_STATUS_CODE: 0\r\n"
+ + "INSTRUMENTATION_STATUS: dEQP-EventType=EndTestCase\r\n"
+ + "INSTRUMENTATION_STATUS_CODE: 0\r\n"
+ + "INSTRUMENTATION_STATUS: dEQP-EventType=EndSession\r\n"
+ + "INSTRUMENTATION_STATUS_CODE: 0\r\n"
+ + "INSTRUMENTATION_CODE: 0\r\n";
+ final String instrumentationAnswerOk2 =
+ "INSTRUMENTATION_STATUS: dEQP-SessionInfo-Name=releaseName\r\n"
+ + "INSTRUMENTATION_STATUS: dEQP-EventType=SessionInfo\r\n"
+ + "INSTRUMENTATION_STATUS: dEQP-SessionInfo-Value=2014.x\r\n"
+ + "INSTRUMENTATION_STATUS_CODE: 0\r\n"
+ + "INSTRUMENTATION_STATUS: dEQP-SessionInfo-Name=releaseId\r\n"
+ + "INSTRUMENTATION_STATUS: dEQP-EventType=SessionInfo\r\n"
+ + "INSTRUMENTATION_STATUS: dEQP-SessionInfo-Value=0xcafebabe\r\n"
+ + "INSTRUMENTATION_STATUS_CODE: 0\r\n"
+ + "INSTRUMENTATION_STATUS: dEQP-SessionInfo-Name=targetName\r\n"
+ + "INSTRUMENTATION_STATUS: dEQP-EventType=SessionInfo\r\n"
+ + "INSTRUMENTATION_STATUS: dEQP-SessionInfo-Value=android\r\n"
+ + "INSTRUMENTATION_STATUS_CODE: 0\r\n"
+ + "INSTRUMENTATION_STATUS: dEQP-EventType=BeginSession\r\n"
+ + "INSTRUMENTATION_STATUS_CODE: 0\r\n"
+ + "INSTRUMENTATION_STATUS: dEQP-EventType=BeginTestCase\r\n"
+ + "INSTRUMENTATION_STATUS: dEQP-BeginTestCase-TestCasePath=dEQP-GLES3.instances.test2\r\n"
+ + "INSTRUMENTATION_STATUS_CODE: 0\r\n"
+ + "INSTRUMENTATION_STATUS: dEQP-TestCaseResult-Code=Pass\r\n"
+ + "INSTRUMENTATION_STATUS: dEQP-TestCaseResult-Details=Pass\r\n"
+ + "INSTRUMENTATION_STATUS: dEQP-EventType=TestCaseResult\r\n"
+ + "INSTRUMENTATION_STATUS_CODE: 0\r\n"
+ + "INSTRUMENTATION_STATUS: dEQP-EventType=EndTestCase\r\n"
+ + "INSTRUMENTATION_STATUS_CODE: 0\r\n"
+ + "INSTRUMENTATION_STATUS: dEQP-EventType=EndSession\r\n"
+ + "INSTRUMENTATION_STATUS_CODE: 0\r\n"
+ + "INSTRUMENTATION_CODE: 0\r\n";
+ final String instrumentationAnswerBroken =
+ "INSTRUMENTATION_STATUS: dEQP-SessionInfo-Name=releaseName\r\n"
+ + "INSTRUMENTATION_STATUS: dEQP-EventType=SessionInfo\r\n"
+ + "INSTRUMENTATION_STATUS: dEQP-SessionInfo-Value=2014.x\r\n"
+ + "INSTRUMENTATION_STATUS_CODE: 0\r\n"
+ + "INSTRUMENTATION_STATUS: dEQP-SessionInfo-Name=releaseId\r\n"
+ + "INSTRUMENTATION_STATUS: dEQP-EventType=SessionInfo\r\n"
+ + "INSTRUMENTATION_STATUS: dEQP-SessionInfo-Value=0xcafebabe\r\n"
+ + "INSTRUMENTATION_STATUS_CODE: 0\r\n"
+ + "INSTRUMENTATION_STATUS: dEQP-SessionInfo-Name=targetName\r\n"
+ + "INSTRUMENTATION_STATUS: dEQP-EventType=SessionInfo\r\n"
+ + "INSTRUMENTATION_STATUS: dEQP-SessionInfo-Value=android\r\n"
+ + "INSTRUMENTATION_STATUS_CODE: 0\r\n"
+ + "INSTRUMENTATION_STATUS: dEQP-EventType=BeginSession\r\n"
+ + "INSTRUMENTATION_STATUS_CODE: 0\r\n"
+ + "INSTRUMENTATION_STATUS: dEQP-EventType=BeginTestCase\r\n"
+ + "INSTRUMENTATION_STATUS: dEQP-BeginTestCase-TestCasePat";
+
+ final TestIdentifier[] testIds = {
+ new TestIdentifier("dEQP-GLES3.instances", "test1"),
+ new TestIdentifier("dEQP-GLES3.instances", "test2"),
+ };
+
+ final String[] testPaths = {
+ "dEQP-GLES3.instances.test1",
+ "dEQP-GLES3.instances.test2",
+ };
+
+ Map<String,String> config = new HashMap<>();
+ config.put("glconfig", "rgba8888d24s8");
+ config.put("rotation", "unspecified");
+ config.put("surfacetype", "window");
+
+ Map<TestIdentifier, List<Map<String, String>>> instances = new HashMap<>();
+
+ instances.put(testIds[0], new ArrayList<Map<String,String>>());
+ instances.get(testIds[0]).add(config);
+ instances.put(testIds[1], new ArrayList<Map<String,String>>());
+ instances.get(testIds[1]).add(config);
+
+ Collection<TestIdentifier> tests = new ArrayList<TestIdentifier>();
+ for (TestIdentifier id : testIds) {
+ tests.add(id);
+ }
+
+ ITestInvocationListener mockListener
+ = EasyMock.createStrictMock(ITestInvocationListener.class);
+ IMocksControl orderedControl = EasyMock.createStrictControl();
+ ITestDevice mockDevice = orderedControl.createMock(ITestDevice.class);
+ IDevice mockIDevice = orderedControl.createMock(IDevice.class);
+
+ DeqpTestRunner.IRecovery mockRecovery = EasyMock.createMock(DeqpTestRunner.IRecovery.class);
+
+ DeqpTestRunner deqpTest = new DeqpTestRunner(NAME, NAME, tests, instances);
+ deqpTest.setAbi(UnitTests.ABI);
+ deqpTest.setDevice(mockDevice);
+ deqpTest.setBuildHelper(new StubCtsBuildHelper());
+ deqpTest.setRecovery(mockRecovery);
+
+ int version = 3 << 16;
+ EasyMock.expect(mockDevice.getProperty("ro.opengles.version"))
+ .andReturn(Integer.toString(version)).atLeastOnce();
+
+ mockRecovery.onExecutionProgressed();
+ EasyMock.expectLastCall().atLeastOnce();
+
+ mockRecovery.setDevice(mockDevice);
+ EasyMock.expectLastCall().atLeastOnce();
+
+ EasyMock.expect(mockDevice.uninstallPackage(EasyMock.eq(DEQP_ONDEVICE_PKG))).
+ andReturn("").once();
+
+ EasyMock.expect(mockDevice.installPackage(EasyMock.<File>anyObject(),
+ EasyMock.eq(true),
+ EasyMock.eq(AbiUtils.createAbiFlag(UnitTests.ABI.getName())))).andReturn(null)
+ .once();
+
+ // query config
+ expectRenderConfigQueryAndReturn(mockDevice,
+ "--deqp-gl-config-name=rgba8888d24s8 "
+ + "--deqp-screen-rotation=unspecified "
+ + "--deqp-surface-type=window "
+ + "--deqp-gl-major-version=3 "
+ + "--deqp-gl-minor-version=0", "Yes");
+
+ // run config and fail
+ runInstrumentationLineAndAnswer(mockDevice, mockIDevice,
+ "{dEQP-GLES3{instances{test1,test2}}}",
+ "--deqp-caselist-file=" + CASE_LIST_FILE_NAME
+ + " --deqp-gl-config-name=rgba8888d24s8 "
+ + "--deqp-screen-rotation=unspecified "
+ + "--deqp-surface-type=window "
+ + "--deqp-log-images=disable "
+ + "--deqp-watchdog=enable", instrumentationAnswerBroken);
+
+ mockRecovery.recoverComLinkKilled();
+ EasyMock.expectLastCall().once();
+
+ // Re-try
+ runInstrumentationLineAndAnswer(mockDevice, mockIDevice,
+ "{dEQP-GLES3{instances{test1}}}",
+ "--deqp-caselist-file=" + CASE_LIST_FILE_NAME
+ + " --deqp-gl-config-name=rgba8888d24s8 "
+ + "--deqp-screen-rotation=unspecified "
+ + "--deqp-surface-type=window "
+ + "--deqp-log-images=disable "
+ + "--deqp-watchdog=enable", instrumentationAnswerOk1);
+
+ runInstrumentationLineAndAnswer(mockDevice, mockIDevice,
+ "{dEQP-GLES3{instances{test2}}}",
+ "--deqp-caselist-file=" + CASE_LIST_FILE_NAME
+ + " --deqp-gl-config-name=rgba8888d24s8 "
+ + "--deqp-screen-rotation=unspecified "
+ + "--deqp-surface-type=window "
+ + "--deqp-log-images=disable "
+ + "--deqp-watchdog=enable", instrumentationAnswerOk2);
+
+ EasyMock.expect(mockDevice.uninstallPackage(EasyMock.eq(DEQP_ONDEVICE_PKG)))
+ .andReturn("").once();
+
+ mockListener.testRunStarted(ID, 2);
+ EasyMock.expectLastCall().once();
+
+ // test1
+ mockListener.testStarted(EasyMock.eq(testIds[0]));
+ EasyMock.expectLastCall().once();
+
+ mockListener.testEnded(EasyMock.eq(testIds[0]), EasyMock.<Map<String, String>>notNull());
+ EasyMock.expectLastCall().once();
+
+ // test2
+ mockListener.testStarted(EasyMock.eq(testIds[1]));
+ EasyMock.expectLastCall().once();
+
+ mockListener.testEnded(EasyMock.eq(testIds[1]), EasyMock.<Map<String, String>>notNull());
+ EasyMock.expectLastCall().once();
+
+ mockListener.testRunEnded(EasyMock.anyLong(), EasyMock.<Map<String, String>>notNull());
+ EasyMock.expectLastCall().once();
+
+ orderedControl.replay();
+ EasyMock.replay(mockListener);
+ EasyMock.replay(mockRecovery);
+ deqpTest.run(mockListener);
+
+ EasyMock.verify(mockListener);
+ orderedControl.verify();
+ EasyMock.verify(mockRecovery);
+ }
+
+ /**
+ * Test handling of interrupted line in the instrumentation output
+ * and recovery from the error.
+ */
+ public void testRun_testCasePathMissing() throws Exception {
+ final String instrumentationAnswerOk1 =
+ "INSTRUMENTATION_STATUS: dEQP-SessionInfo-Name=releaseName\r\n"
+ + "INSTRUMENTATION_STATUS: dEQP-EventType=SessionInfo\r\n"
+ + "INSTRUMENTATION_STATUS: dEQP-SessionInfo-Value=2014.x\r\n"
+ + "INSTRUMENTATION_STATUS_CODE: 0\r\n"
+ + "INSTRUMENTATION_STATUS: dEQP-SessionInfo-Name=releaseId\r\n"
+ + "INSTRUMENTATION_STATUS: dEQP-EventType=SessionInfo\r\n"
+ + "INSTRUMENTATION_STATUS: dEQP-SessionInfo-Value=0xcafebabe\r\n"
+ + "INSTRUMENTATION_STATUS_CODE: 0\r\n"
+ + "INSTRUMENTATION_STATUS: dEQP-SessionInfo-Name=targetName\r\n"
+ + "INSTRUMENTATION_STATUS: dEQP-EventType=SessionInfo\r\n"
+ + "INSTRUMENTATION_STATUS: dEQP-SessionInfo-Value=android\r\n"
+ + "INSTRUMENTATION_STATUS_CODE: 0\r\n"
+ + "INSTRUMENTATION_STATUS: dEQP-EventType=BeginSession\r\n"
+ + "INSTRUMENTATION_STATUS_CODE: 0\r\n"
+ + "INSTRUMENTATION_STATUS: dEQP-EventType=BeginTestCase\r\n"
+ + "INSTRUMENTATION_STATUS: dEQP-BeginTestCase-TestCasePath=dEQP-GLES3.instances.test1\r\n"
+ + "INSTRUMENTATION_STATUS_CODE: 0\r\n"
+ + "INSTRUMENTATION_STATUS: dEQP-TestCaseResult-Code=Pass\r\n"
+ + "INSTRUMENTATION_STATUS: dEQP-TestCaseResult-Details=Pass\r\n"
+ + "INSTRUMENTATION_STATUS: dEQP-EventType=TestCaseResult\r\n"
+ + "INSTRUMENTATION_STATUS_CODE: 0\r\n"
+ + "INSTRUMENTATION_STATUS: dEQP-EventType=EndTestCase\r\n"
+ + "INSTRUMENTATION_STATUS_CODE: 0\r\n"
+ + "INSTRUMENTATION_STATUS: dEQP-EventType=EndSession\r\n"
+ + "INSTRUMENTATION_STATUS_CODE: 0\r\n"
+ + "INSTRUMENTATION_CODE: 0\r\n";
+ final String instrumentationAnswerOk2 =
+ "INSTRUMENTATION_STATUS: dEQP-SessionInfo-Name=releaseName\r\n"
+ + "INSTRUMENTATION_STATUS: dEQP-EventType=SessionInfo\r\n"
+ + "INSTRUMENTATION_STATUS: dEQP-SessionInfo-Value=2014.x\r\n"
+ + "INSTRUMENTATION_STATUS_CODE: 0\r\n"
+ + "INSTRUMENTATION_STATUS: dEQP-SessionInfo-Name=releaseId\r\n"
+ + "INSTRUMENTATION_STATUS: dEQP-EventType=SessionInfo\r\n"
+ + "INSTRUMENTATION_STATUS: dEQP-SessionInfo-Value=0xcafebabe\r\n"
+ + "INSTRUMENTATION_STATUS_CODE: 0\r\n"
+ + "INSTRUMENTATION_STATUS: dEQP-SessionInfo-Name=targetName\r\n"
+ + "INSTRUMENTATION_STATUS: dEQP-EventType=SessionInfo\r\n"
+ + "INSTRUMENTATION_STATUS: dEQP-SessionInfo-Value=android\r\n"
+ + "INSTRUMENTATION_STATUS_CODE: 0\r\n"
+ + "INSTRUMENTATION_STATUS: dEQP-EventType=BeginSession\r\n"
+ + "INSTRUMENTATION_STATUS_CODE: 0\r\n"
+ + "INSTRUMENTATION_STATUS: dEQP-EventType=BeginTestCase\r\n"
+ + "INSTRUMENTATION_STATUS: dEQP-BeginTestCase-TestCasePath=dEQP-GLES3.instances.test2\r\n"
+ + "INSTRUMENTATION_STATUS_CODE: 0\r\n"
+ + "INSTRUMENTATION_STATUS: dEQP-TestCaseResult-Code=Pass\r\n"
+ + "INSTRUMENTATION_STATUS: dEQP-TestCaseResult-Details=Pass\r\n"
+ + "INSTRUMENTATION_STATUS: dEQP-EventType=TestCaseResult\r\n"
+ + "INSTRUMENTATION_STATUS_CODE: 0\r\n"
+ + "INSTRUMENTATION_STATUS: dEQP-EventType=EndTestCase\r\n"
+ + "INSTRUMENTATION_STATUS_CODE: 0\r\n"
+ + "INSTRUMENTATION_STATUS: dEQP-EventType=EndSession\r\n"
+ + "INSTRUMENTATION_STATUS_CODE: 0\r\n"
+ + "INSTRUMENTATION_CODE: 0\r\n";
+ final String instrumentationAnswerBroken =
+ "INSTRUMENTATION_STATUS: dEQP-SessionInfo-Name=releaseName\r\n"
+ + "INSTRUMENTATION_STATUS: dEQP-EventType=SessionInfo\r\n"
+ + "INSTRUMENTATION_STATUS: dEQP-SessionInfo-Value=2014.x\r\n"
+ + "INSTRUMENTATION_STATUS_CODE: 0\r\n"
+ + "INSTRUMENTATION_STATUS: dEQP-SessionInfo-Name=releaseId\r\n"
+ + "INSTRUMENTATION_STATUS: dEQP-EventType=SessionInfo\r\n"
+ + "INSTRUMENTATION_STATUS: dEQP-SessionInfo-Value=0xcafebabe\r\n"
+ + "INSTRUMENTATION_STATUS_CODE: 0\r\n"
+ + "INSTRUMENTATION_STATUS: dEQP-SessionInfo-Name=targetName\r\n"
+ + "INSTRUMENTATION_STATUS: dEQP-EventType=SessionInfo\r\n"
+ + "INSTRUMENTATION_STATUS: dEQP-SessionInfo-Value=android\r\n"
+ + "INSTRUMENTATION_STATUS_CODE: 0\r\n"
+ + "INSTRUMENTATION_STATUS: dEQP-EventType=BeginSession\r\n"
+ + "INSTRUMENTATION_STATUS_CODE: 0\r\n"
+ + "INSTRUMENTATION_STATUS: dEQP-EventType=BeginTestCase\r\n";
+
+
+ final TestIdentifier[] testIds = {
+ new TestIdentifier("dEQP-GLES3.instances", "test1"),
+ new TestIdentifier("dEQP-GLES3.instances", "test2"),
+ };
+
+ final String[] testPaths = {
+ "dEQP-GLES3.instances.test1",
+ "dEQP-GLES3.instances.test2",
+ };
+
+ Map<String,String> config = new HashMap<>();
+ config.put("glconfig", "rgba8888d24s8");
+ config.put("rotation", "unspecified");
+ config.put("surfacetype", "window");
+
+ Map<TestIdentifier, List<Map<String, String>>> instances = new HashMap<>();
+
+ instances.put(testIds[0], new ArrayList<Map<String,String>>());
+ instances.get(testIds[0]).add(config);
+ instances.put(testIds[1], new ArrayList<Map<String,String>>());
+ instances.get(testIds[1]).add(config);
+
+ Collection<TestIdentifier> tests = new ArrayList<TestIdentifier>();
+ for (TestIdentifier id : testIds) {
+ tests.add(id);
+ }
+
+ ITestInvocationListener mockListener
+ = EasyMock.createStrictMock(ITestInvocationListener.class);
+ IMocksControl orderedControl = EasyMock.createStrictControl();
+ ITestDevice mockDevice = orderedControl.createMock(ITestDevice.class);
+ IDevice mockIDevice = orderedControl.createMock(IDevice.class);
+
+ DeqpTestRunner.IRecovery mockRecovery = EasyMock.createMock(DeqpTestRunner.IRecovery.class);
+
+ DeqpTestRunner deqpTest = new DeqpTestRunner(NAME, NAME, tests, instances);
+ deqpTest.setAbi(UnitTests.ABI);
+ deqpTest.setDevice(mockDevice);
+ deqpTest.setBuildHelper(new StubCtsBuildHelper());
+ deqpTest.setRecovery(mockRecovery);
+
+ int version = 3 << 16;
+ EasyMock.expect(mockDevice.getProperty("ro.opengles.version"))
+ .andReturn(Integer.toString(version)).atLeastOnce();
+
+ mockRecovery.onExecutionProgressed();
+ EasyMock.expectLastCall().atLeastOnce();
+
+ mockRecovery.setDevice(mockDevice);
+ EasyMock.expectLastCall().atLeastOnce();
+
+ EasyMock.expect(mockDevice.uninstallPackage(EasyMock.eq(DEQP_ONDEVICE_PKG))).
+ andReturn("").once();
+
+ EasyMock.expect(mockDevice.installPackage(EasyMock.<File>anyObject(),
+ EasyMock.eq(true),
+ EasyMock.eq(AbiUtils.createAbiFlag(UnitTests.ABI.getName())))).andReturn(null)
+ .once();
+
+ // query config
+ expectRenderConfigQueryAndReturn(mockDevice,
+ "--deqp-gl-config-name=rgba8888d24s8 "
+ + "--deqp-screen-rotation=unspecified "
+ + "--deqp-surface-type=window "
+ + "--deqp-gl-major-version=3 "
+ + "--deqp-gl-minor-version=0", "Yes");
+
+ // run config and fail
+ runInstrumentationLineAndAnswer(mockDevice, mockIDevice,
+ "{dEQP-GLES3{instances{test1,test2}}}",
+ "--deqp-caselist-file=" + CASE_LIST_FILE_NAME
+ + " --deqp-gl-config-name=rgba8888d24s8 "
+ + "--deqp-screen-rotation=unspecified "
+ + "--deqp-surface-type=window "
+ + "--deqp-log-images=disable "
+ + "--deqp-watchdog=enable", instrumentationAnswerBroken);
+
+ mockRecovery.recoverComLinkKilled();
+ EasyMock.expectLastCall().once();
+
+ // Re-try
+ runInstrumentationLineAndAnswer(mockDevice, mockIDevice,
+ "{dEQP-GLES3{instances{test1}}}",
+ "--deqp-caselist-file=" + CASE_LIST_FILE_NAME
+ + " --deqp-gl-config-name=rgba8888d24s8 "
+ + "--deqp-screen-rotation=unspecified "
+ + "--deqp-surface-type=window "
+ + "--deqp-log-images=disable "
+ + "--deqp-watchdog=enable", instrumentationAnswerOk1);
+
+ runInstrumentationLineAndAnswer(mockDevice, mockIDevice,
+ "{dEQP-GLES3{instances{test2}}}",
+ "--deqp-caselist-file=" + CASE_LIST_FILE_NAME
+ + " --deqp-gl-config-name=rgba8888d24s8 "
+ + "--deqp-screen-rotation=unspecified "
+ + "--deqp-surface-type=window "
+ + "--deqp-log-images=disable "
+ + "--deqp-watchdog=enable", instrumentationAnswerOk2);
+
+ EasyMock.expect(mockDevice.uninstallPackage(EasyMock.eq(DEQP_ONDEVICE_PKG)))
+ .andReturn("").once();
+
+ mockListener.testRunStarted(ID, 2);
+ EasyMock.expectLastCall().once();
+
+ // test1
+ mockListener.testStarted(EasyMock.eq(testIds[0]));
+ EasyMock.expectLastCall().once();
+
+ mockListener.testEnded(EasyMock.eq(testIds[0]), EasyMock.<Map<String, String>>notNull());
+ EasyMock.expectLastCall().once();
+
+ // test2
+ mockListener.testStarted(EasyMock.eq(testIds[1]));
+ EasyMock.expectLastCall().once();
+
+ mockListener.testEnded(EasyMock.eq(testIds[1]), EasyMock.<Map<String, String>>notNull());
+ EasyMock.expectLastCall().once();
+
+ mockListener.testRunEnded(EasyMock.anyLong(), EasyMock.<Map<String, String>>notNull());
+ EasyMock.expectLastCall().once();
+
+ orderedControl.replay();
+ EasyMock.replay(mockListener);
+ EasyMock.replay(mockRecovery);
+ deqpTest.run(mockListener);
+
+ EasyMock.verify(mockListener);
+ orderedControl.verify();
+ EasyMock.verify(mockRecovery);
+ }
+
/**
* Test dEQP with multiple instances
*/