Commit 306ef6ba authored by Ali Juma's avatar Ali Juma Committed by Chromium LUCI CQ

[iOS] Remove EarlGrey dependencies from CWTChromeDriver

EarlGrey is not compatible with ASan, so in order to adapt
CWTChromeDriver for fuzzing, all dependencies on EarlGrey need to
be removed.

CWTChromeDriver doesn't do any actual EarlGrey UI testing.
Instead, it only used EarlGrey as a convenient way of setting up
a test process and app process, with EDO communication between
processes.

This CL removes the EarlGrey dependencies, instead using XCUITest
and EDO directly.

Bug: 1158540
Change-Id: Iec0534d668413e0630010c7d470bac4e98db43bb
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2622239Reviewed-by: default avatarJustin Cohen <justincohen@chromium.org>
Commit-Queue: Ali Juma <ajuma@chromium.org>
Cr-Commit-Position: refs/heads/master@{#843008}
parent 9f4f84b5
......@@ -2,9 +2,11 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
import("//build/apple/tweak_info_plist.gni")
import("//build/config/ios/ios_sdk.gni")
import("//build/config/ios/rules.gni")
import("//ios/chrome/test/earl_grey2/chrome_ios_eg2_test.gni")
import("//ios/build/chrome_build.gni")
import("//ios/public/provider/chrome/browser/build_config.gni")
group("all_tests") {
testonly = true
......@@ -14,15 +16,50 @@ group("all_tests") {
]
}
chrome_ios_eg2_test_app_host("ios_cwt_chromedriver_tests") {
deps = [ ":eg_app_support+eg2" ]
tweak_info_plist("chrome_app_plist") {
info_plists = [
"//ios/chrome/app/resources/Info.plist",
"//ios/chrome/app/resources/ChromeAddition+Info.plist",
"//ios/chrome/app/resources/MultiWindowEnabled+Info.plist",
]
}
ios_app_bundle("ios_cwt_chromedriver_tests") {
testonly = true
deps = [
":app_support",
"//ios/chrome/app:main",
]
bundle_deps = [
"//ios/chrome/app/resources",
"//ios/third_party/gtx:gtx+bundle",
ios_application_icons_target,
]
info_plist_target = ":chrome_app_plist"
extra_substitutions = [
"CHROMIUM_HANDOFF_ID=$chromium_handoff_id",
"CHROMIUM_SHORT_NAME=$target_name",
"CHROMIUM_URL_CHANNEL_SCHEME=$url_channel_scheme",
"CHROMIUM_URL_SCHEME_1=$url_unsecure_scheme",
"CHROMIUM_URL_SCHEME_2=$url_secure_scheme",
"CHROMIUM_URL_SCHEME_3=$url_x_callback_scheme",
"CHROMIUM_BUNDLE_ID=gtest.$target_name",
"CONTENT_WIDGET_EXTENSION_BUNDLE_ID=$chromium_bundle_id.ContentTodayExtension",
"IOS_MOVE_TAB_ACTIVITY_TYPE=$ios_move_tab_activity_type",
"SSOAUTH_URL_SCHEME=$url_ssoauth_scheme",
]
}
chrome_ios_eg2_test("ios_cwt_chromedriver_tests_module") {
ios_xcuitest_test("ios_cwt_chromedriver_tests_module") {
xcode_test_application_name = "ios_cwt_chromedriver_tests"
deps = [ ":cwt_chromedriver_tests" ]
data_deps = [ ":ios_cwt_chromedriver_tests" ]
bundle_deps = [
"//ios/chrome/app/resources",
"//ios/third_party/gtx:gtx+bundle",
"//third_party/icu:icudata",
]
}
source_set("shared_helper_headers") {
......@@ -30,25 +67,36 @@ source_set("shared_helper_headers") {
sources = [ "cwt_webdriver_app_interface.h" ]
}
source_set("eg_app_support+eg2") {
defines = [ "CHROME_EARL_GREY_2" ]
source_set("cwt_constants") {
testonly = true
sources = [
"cwt_constants.cc",
"cwt_constants.h",
]
}
source_set("app_support") {
testonly = true
configs += [ "//build/config/compiler:enable_arc" ]
sources = [ "cwt_webdriver_app_interface.mm" ]
sources = [
"cwt_tests_hook.mm",
"cwt_webdriver_app_interface.mm",
]
deps = [
":cwt_constants",
"//base",
"//base/test:test_support",
"//ios/chrome/app:app_internal",
"//ios/chrome/app:tests_hook",
"//ios/chrome/browser/main:public",
"//ios/chrome/browser/tabs:tabs",
"//ios/chrome/browser/web:tab_id_tab_helper",
"//ios/chrome/browser/web_state_list",
"//ios/chrome/test/app:test_support",
"//ios/testing:nserror_support",
"//ios/testing/earl_grey:eg_app_support+eg2",
"//ios/third_party/earl_grey2:app_framework+link",
"//ios/third_party/edo",
"//ios/web/public/test",
"//ui/gfx",
]
......@@ -57,7 +105,6 @@ source_set("eg_app_support+eg2") {
}
source_set("cwt_chromedriver_tests") {
defines = [ "CHROME_EARL_GREY_2" ]
testonly = true
configs += [
"//build/config/compiler:enable_arc",
......@@ -71,10 +118,10 @@ source_set("cwt_chromedriver_tests") {
]
deps = [
":cwt_constants",
":shared_helper_headers",
"//components/version_info:version_info",
"//ios/testing/earl_grey:eg_test_support+eg2",
"//ios/third_party/earl_grey2:test_lib",
"//ios/third_party/edo",
"//net:test_support",
]
......
......@@ -2,14 +2,12 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#import <TestLib/EarlGreyImpl/EarlGrey.h>
#import <UIKit/UIKit.h>
#import <XCTest/XCTest.h>
#include "base/logging.h"
#include "base/strings/sys_string_conversions.h"
#import "ios/chrome/test/wpt/cwt_request_handler.h"
#import "ios/testing/earl_grey/base_earl_grey_test_case.h"
#include "net/base/port_util.h"
#include "net/test/embedded_test_server/embedded_test_server.h"
#include "url/url_constants.h"
......@@ -28,17 +26,20 @@ const int kDefaultPort = 8123;
// Dummy test case that hosts CWTChromeDriver. CWTChromeDriver implements a
// minimal subset of the WebDriver protocol needed to run most Web Platform
// Tests. CWTChromeDriverTestCase launches a test server that listens for
// WebDriver commands, and then uses EarlGrey2's eDistantObject protocol to pass
// on corresponding messages to the app process. Each CWTChromeDriver launches a
// single instance of Chrome, but mulitple instances of CWTChromeDriver can be
// WebDriver commands, and then uses the eDistantObject protocol to pass on
// corresponding messages to the app process. Each CWTChromeDriver launches a
// single instance of Chrome, but multiple instances of CWTChromeDriver can be
// run in parallel in order to use multiple instances of Chrome.
@interface CWTChromeDriverTestCase : BaseEarlGreyTestCase
@interface CWTChromeDriverTestCase : XCTestCase
@end
@implementation CWTChromeDriverTestCase
// Dummy test that keeps the test app alive.
- (void)testRunCWTChromeDriver {
XCUIApplication* application = [[XCUIApplication alloc] init];
[application launch];
int port = kDefaultPort;
NSArray* arguments = NSProcessInfo.processInfo.arguments;
......
// Copyright 2021 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#import "ios/chrome/test/wpt/cwt_constants.h"
extern const int kCwtEdoPortNumber = 56800;
// Copyright 2021 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef IOS_CHROME_TEST_WPT_CWT_CONSTANTS_H_
#define IOS_CHROME_TEST_WPT_CWT_CONSTANTS_H_
// The port that the app process listens on for EDO communication with the
// the test process.
extern const int kCwtEdoPortNumber;
#endif // IOS_CHROME_TEST_WPT_CWT_CONSTANTS_H_
......@@ -10,15 +10,16 @@
#include "base/json/json_writer.h"
#include "base/strings/sys_string_conversions.h"
#include "components/version_info/version_info.h"
#import "ios/chrome/test/wpt/cwt_constants.h"
#import "ios/chrome/test/wpt/cwt_webdriver_app_interface.h"
#import "ios/testing/earl_grey/earl_grey_test.h"
#import "ios/third_party/edo/src/Service/Sources/EDOClientService.h"
#include "net/http/http_status_code.h"
#if !defined(__has_feature) || !__has_feature(objc_arc)
#error "This file requires ARC support."
#endif
GREY_STUB_CLASS_IN_APP_BACKGROUND_QUEUE(CWTWebDriverAppInterface)
EDO_STUB_CLASS(CWTWebDriverAppInterface, kCwtEdoPortNumber)
using net::test_server::HttpRequest;
using net::test_server::HttpResponse;
......
// Copyright 2021 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#import "ios/chrome/app/tests_hook.h"
#import "ios/chrome/test/wpt/cwt_constants.h"
#import "ios/chrome/test/wpt/cwt_webdriver_app_interface.h"
#import "ios/third_party/edo/src/Service/Sources/EDOHostService.h"
#if !defined(__has_feature) || !__has_feature(objc_arc)
#error "This file requires ARC support."
#endif
namespace tests_hook {
bool DisableAppGroupAccess() {
return true;
}
bool DisableContentSuggestions() {
return true;
}
bool DisableFirstRun() {
return true;
}
bool DisableGeolocation() {
return true;
}
bool DisableSigninRecallPromo() {
return true;
}
bool DisableUpdateService() {
return true;
}
bool DisableMainThreadFreezeDetection() {
return true;
}
policy::ConfigurationPolicyProvider* GetOverriddenPlatformPolicyProvider() {
return nullptr;
}
void SetUpTestsIfPresent() {
CWTWebDriverAppInterface* appInterface =
[[CWTWebDriverAppInterface alloc] init];
[EDOHostService serviceWithPort:kCwtEdoPortNumber
rootObject:appInterface
queue:[appInterface executingQueue]];
}
void RunTestsIfPresent() {}
} // namespace tests_hook
......@@ -13,6 +13,9 @@
// avoid deadlock while waiting for actions to complete on the main thread.
@interface CWTWebDriverAppInterface : NSObject
// The background thread where this class' methods are run.
@property(nonatomic, readonly) dispatch_queue_t executingQueue;
// Loads the given URL in the tab identified by |tabID|. Returns an error if the
// page fails to load within |timeout| seconds or if no such tab exists.
+ (NSError*)loadURL:(NSString*)URL
......
......@@ -17,7 +17,6 @@
#import "ios/chrome/test/app/chrome_test_util.h"
#import "ios/chrome/test/app/settings_test_util.h"
#import "ios/chrome/test/app/tab_test_util.h"
#import "ios/testing/earl_grey/earl_grey_app.h"
#import "ios/testing/nserror_util.h"
#import "ios/web/public/test/navigation_test_util.h"
#import "ios/web/public/ui/crw_web_view_proxy.h"
......@@ -59,15 +58,40 @@ int GetIndexOfWebStateWithId(NSString* tab_id) {
return web_state_list->GetIndexOfWebState(GetWebStateWithId(tab_id));
}
void DispatchSyncOnMainThread(void (^block)(void)) {
if ([NSThread isMainThread]) {
block();
} else {
dispatch_semaphore_t waitForBlock = dispatch_semaphore_create(0);
CFRunLoopPerformBlock(CFRunLoopGetMain(), kCFRunLoopDefaultMode, ^{
block();
dispatch_semaphore_signal(waitForBlock);
});
// CFRunLoopPerformBlock does not wake up the main queue.
CFRunLoopWakeUp(CFRunLoopGetMain());
// Waits until block is executed and semaphore is signalled.
dispatch_semaphore_wait(waitForBlock, DISPATCH_TIME_FOREVER);
}
}
} // namespace
@implementation CWTWebDriverAppInterface
- (instancetype)init {
self = [super init];
if (self) {
_executingQueue = dispatch_queue_create("com.google.chrome.cwt.background",
DISPATCH_QUEUE_SERIAL);
}
return self;
}
+ (NSError*)loadURL:(NSString*)URL
inTab:(NSString*)tabID
timeoutInSeconds:(NSTimeInterval)timeout {
__block web::WebState* webState = nullptr;
grey_dispatch_sync_on_main_thread(^{
DispatchSyncOnMainThread(^{
webState = GetWebStateWithId(tabID);
if (webState)
web::test::LoadUrl(webState, GURL(base::SysNSStringToUTF8(URL)));
......@@ -78,7 +102,7 @@ int GetIndexOfWebStateWithId(NSString* tab_id) {
bool success = WaitUntilConditionOrTimeout(timeout, ^bool {
__block BOOL isLoading = NO;
grey_dispatch_sync_on_main_thread(^{
DispatchSyncOnMainThread(^{
isLoading = webState->IsLoading();
});
return !isLoading;
......@@ -92,7 +116,7 @@ int GetIndexOfWebStateWithId(NSString* tab_id) {
+ (NSString*)currentTabID {
__block NSString* tabID = nil;
grey_dispatch_sync_on_main_thread(^{
DispatchSyncOnMainThread(^{
web::WebState* webState = chrome_test_util::GetCurrentWebState();
if (webState)
tabID = GetIdForWebState(webState);
......@@ -103,7 +127,7 @@ int GetIndexOfWebStateWithId(NSString* tab_id) {
+ (NSArray*)tabIDs {
__block NSMutableArray* tabIDs;
grey_dispatch_sync_on_main_thread(^{
DispatchSyncOnMainThread(^{
DCHECK(!chrome_test_util::IsIncognitoMode());
WebStateList* webStateList = GetCurrentWebStateList();
tabIDs = [NSMutableArray arrayWithCapacity:webStateList->count()];
......@@ -119,7 +143,7 @@ int GetIndexOfWebStateWithId(NSString* tab_id) {
+ (NSError*)closeTabWithID:(NSString*)ID {
__block NSError* error = nil;
grey_dispatch_sync_on_main_thread(^{
DispatchSyncOnMainThread(^{
int webStateIndex = GetIndexOfWebStateWithId(ID);
if (webStateIndex != WebStateList::kInvalidIndex) {
WebStateList* webStateList = GetCurrentWebStateList();
......@@ -135,7 +159,7 @@ int GetIndexOfWebStateWithId(NSString* tab_id) {
+ (NSError*)switchToTabWithID:(NSString*)ID {
__block NSError* error = nil;
grey_dispatch_sync_on_main_thread(^{
DispatchSyncOnMainThread(^{
DCHECK(!chrome_test_util::IsIncognitoMode());
int webStateIndex = GetIndexOfWebStateWithId(ID);
if (webStateIndex != WebStateList::kInvalidIndex) {
......@@ -193,7 +217,7 @@ int GetIndexOfWebStateWithId(NSString* tab_id) {
__block BOOL webStateFound = NO;
__block base::CallbackListSubscription subscription;
grey_dispatch_sync_on_main_thread(^{
DispatchSyncOnMainThread(^{
web::WebState* webState = GetWebStateWithId(tabID);
if (!webState)
return;
......@@ -208,7 +232,7 @@ int GetIndexOfWebStateWithId(NSString* tab_id) {
bool success = WaitUntilConditionOrTimeout(timeout, ^bool {
__block BOOL scriptExecutionComplete = NO;
grey_dispatch_sync_on_main_thread(^{
DispatchSyncOnMainThread(^{
scriptExecutionComplete = messageValue.has_value();
});
return scriptExecutionComplete;
......@@ -223,14 +247,14 @@ int GetIndexOfWebStateWithId(NSString* tab_id) {
}
+ (void)enablePopups {
grey_dispatch_sync_on_main_thread(^{
DispatchSyncOnMainThread(^{
chrome_test_util::SetContentSettingsBlockPopups(CONTENT_SETTING_ALLOW);
});
}
+ (NSString*)takeSnapshotOfTabWithID:(NSString*)ID {
__block web::WebState* webState;
grey_dispatch_sync_on_main_thread(^{
DispatchSyncOnMainThread(^{
webState = GetWebStateWithId(ID);
});
......@@ -238,7 +262,7 @@ int GetIndexOfWebStateWithId(NSString* tab_id) {
return nil;
__block UIImage* snapshot = nil;
grey_dispatch_sync_on_main_thread(^{
DispatchSyncOnMainThread(^{
CGRect bounds = webState->GetWebViewProxy().bounds;
UIEdgeInsets insets = webState->GetWebViewProxy().contentInset;
CGRect adjustedBounds = UIEdgeInsetsInsetRect(bounds, insets);
......@@ -252,7 +276,7 @@ int GetIndexOfWebStateWithId(NSString* tab_id) {
const NSTimeInterval kSnapshotTimeoutSeconds = 100;
bool success = WaitUntilConditionOrTimeout(kSnapshotTimeoutSeconds, ^bool {
__block BOOL snapshotComplete = NO;
grey_dispatch_sync_on_main_thread(^{
DispatchSyncOnMainThread(^{
if (snapshot != nil)
snapshotComplete = YES;
});
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment