2 * Copyright (C) 2015-2016 Apple Inc. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
14 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
15 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
17 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
19 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
22 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
23 * THE POSSIBILITY OF SUCH DAMAGE.
27 #import "TestController.h"
29 #import "CrashReporterInfo.h"
30 #import "PlatformWebView.h"
31 #import "StringFunctions.h"
32 #import "TestInvocation.h"
33 #import "TestRunnerWKWebView.h"
34 #import <Foundation/Foundation.h>
35 #import <WebKit/WKContextConfigurationRef.h>
36 #import <WebKit/WKCookieManager.h>
37 #import <WebKit/WKPreferencesRefPrivate.h>
38 #import <WebKit/WKProcessPoolPrivate.h>
39 #import <WebKit/WKStringCF.h>
40 #import <WebKit/WKUserContentControllerPrivate.h>
41 #import <WebKit/WKWebView.h>
42 #import <WebKit/WKWebViewConfiguration.h>
43 #import <WebKit/WKWebViewConfigurationPrivate.h>
44 #import <WebKit/WKWebViewPrivate.h>
45 #import <WebKit/WKWebsiteDataRecordPrivate.h>
46 #import <WebKit/WKWebsiteDataStorePrivate.h>
47 #import <WebKit/WKWebsiteDataStoreRef.h>
48 #import <WebKit/_WKProcessPoolConfiguration.h>
49 #import <WebKit/_WKUserContentExtensionStore.h>
50 #import <WebKit/_WKUserContentExtensionStorePrivate.h>
51 #import <wtf/MainThread.h>
56 static NSString* toNSString(WKStringRef string)
58 return [NSString stringWithCString:toWTFString(string).utf8().data()];
62 static WKWebViewConfiguration *globalWebViewConfiguration;
64 void initializeWebViewConfiguration(const char* libraryPath, WKStringRef injectedBundlePath, WKContextRef context, WKContextConfigurationRef contextConfiguration)
67 [globalWebViewConfiguration release];
68 globalWebViewConfiguration = [[WKWebViewConfiguration alloc] init];
70 globalWebViewConfiguration.processPool = (WKProcessPool *)context;
71 globalWebViewConfiguration.websiteDataStore = (WKWebsiteDataStore *)WKContextGetWebsiteDataStore(context);
72 globalWebViewConfiguration._allowUniversalAccessFromFileURLs = YES;
74 #if (PLATFORM(MAC) && __MAC_OS_X_VERSION_MIN_REQUIRED >= 101200) || PLATFORM(IOS)
75 globalWebViewConfiguration._applePayEnabled = YES;
78 #if (PLATFORM(MAC) && __MAC_OS_X_VERSION_MIN_REQUIRED >= 101300) || PLATFORM(IOS)
79 WKCookieManagerSetCookieStoragePartitioningEnabled(WKContextGetCookieManager(context), true);
82 WKWebsiteDataStore* poolWebsiteDataStore = (WKWebsiteDataStore *)WKContextGetWebsiteDataStore((WKContextRef)globalWebViewConfiguration.processPool);
83 [poolWebsiteDataStore _setCacheStoragePerOriginQuota: 400 * 1024];
85 String cacheStorageDirectory = String(libraryPath) + '/' + "CacheStorage";
86 [poolWebsiteDataStore _setCacheStorageDirectory: cacheStorageDirectory];
89 [globalWebViewConfiguration.websiteDataStore _setResourceLoadStatisticsEnabled:YES];
90 [globalWebViewConfiguration.websiteDataStore _resourceLoadStatisticsSetShouldSubmitTelemetry:NO];
93 globalWebViewConfiguration.allowsInlineMediaPlayback = YES;
94 globalWebViewConfiguration._inlineMediaPlaybackRequiresPlaysInlineAttribute = NO;
95 globalWebViewConfiguration._invisibleAutoplayNotPermitted = NO;
96 globalWebViewConfiguration._mediaDataLoadsAutomatically = YES;
97 globalWebViewConfiguration.requiresUserActionForMediaPlayback = NO;
99 globalWebViewConfiguration.mediaTypesRequiringUserActionForPlayback = WKAudiovisualMediaTypeNone;
103 void TestController::cocoaPlatformInitialize()
105 const char* dumpRenderTreeTemp = libraryPathForTesting();
106 if (!dumpRenderTreeTemp)
109 String resourceLoadStatisticsFolder = String(dumpRenderTreeTemp) + '/' + "ResourceLoadStatistics";
110 [[NSFileManager defaultManager] createDirectoryAtPath:resourceLoadStatisticsFolder withIntermediateDirectories:YES attributes:nil error: nil];
111 String fullBrowsingSessionResourceLog = resourceLoadStatisticsFolder + '/' + "full_browsing_session_resourceLog.plist";
112 NSDictionary *resourceLogPlist = [[NSDictionary alloc] initWithObjectsAndKeys: [NSNumber numberWithInt:1], @"version", nil];
113 if (![resourceLogPlist writeToFile:fullBrowsingSessionResourceLog atomically:YES])
115 [resourceLogPlist release];
118 WKContextRef TestController::platformContext()
121 return (WKContextRef)globalWebViewConfiguration.processPool;
127 WKPreferencesRef TestController::platformPreferences()
130 return (WKPreferencesRef)globalWebViewConfiguration.preferences;
136 void TestController::platformCreateWebView(WKPageConfigurationRef, const TestOptions& options)
139 RetainPtr<WKWebViewConfiguration> copiedConfiguration = adoptNS([globalWebViewConfiguration copy]);
142 if (options.useDataDetection)
143 [copiedConfiguration setDataDetectorTypes:WKDataDetectorTypeAll];
144 if (options.ignoresViewportScaleLimits)
145 [copiedConfiguration setIgnoresViewportScaleLimits:YES];
146 if (options.useCharacterSelectionGranularity)
147 [copiedConfiguration setSelectionGranularity:WKSelectionGranularityCharacter];
148 if (options.useCharacterSelectionGranularity)
149 [copiedConfiguration setSelectionGranularity:WKSelectionGranularityCharacter];
152 if (options.enableAttachmentElement)
153 [copiedConfiguration _setAttachmentElementEnabled: YES];
155 m_mainWebView = std::make_unique<PlatformWebView>(copiedConfiguration.get(), options);
157 m_mainWebView = std::make_unique<PlatformWebView>(globalWebViewConfiguration, options);
161 PlatformWebView* TestController::platformCreateOtherPage(PlatformWebView* parentView, WKPageConfigurationRef, const TestOptions& options)
164 WKWebViewConfiguration *newConfiguration = [[globalWebViewConfiguration copy] autorelease];
165 newConfiguration._relatedWebView = static_cast<WKWebView*>(parentView->platformView());
166 return new PlatformWebView(newConfiguration, options);
172 WKContextRef TestController::platformAdjustContext(WKContextRef context, WKContextConfigurationRef contextConfiguration)
175 initializeWebViewConfiguration(libraryPathForTesting(), injectedBundlePath(), context, contextConfiguration);
176 return (WKContextRef)globalWebViewConfiguration.processPool;
182 void TestController::platformRunUntil(bool& done, double timeout)
184 NSDate *endDate = (timeout > 0) ? [NSDate dateWithTimeIntervalSinceNow:timeout] : [NSDate distantFuture];
186 while (!done && [endDate compare:[NSDate date]] == NSOrderedDescending)
187 [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:endDate];
190 void TestController::cocoaResetStateToConsistentValues()
193 __block bool doneRemoving = false;
194 [[_WKUserContentExtensionStore defaultStore] removeContentExtensionForIdentifier:@"TestContentExtensions" completionHandler:^(NSError *error) {
197 platformRunUntil(doneRemoving, 0);
198 [[_WKUserContentExtensionStore defaultStore] _removeAllContentExtensions];
200 if (PlatformWebView* webView = mainWebView())
201 [webView->platformView().configuration.userContentController _removeAllUserContentFilters];
205 void TestController::platformWillRunTest(const TestInvocation& testInvocation)
207 setCrashReportApplicationSpecificInformationToURL(testInvocation.url());
210 static NSString * const WebArchivePboardType = @"Apple Web Archive pasteboard type";
211 static NSString * const WebSubresourcesKey = @"WebSubresources";
212 static NSString * const WebSubframeArchivesKey = @"WebResourceMIMEType like 'image*'";
214 unsigned TestController::imageCountInGeneralPasteboard() const
217 NSData *data = [[NSPasteboard generalPasteboard] dataForType:WebArchivePboardType];
219 NSData *data = [[UIPasteboard generalPasteboard] valueForPasteboardType:WebArchivePboardType];
224 NSError *error = nil;
225 id webArchive = [NSPropertyListSerialization propertyListWithData:data options:NSPropertyListImmutable format:NULL error:&error];
227 NSLog(@"Encountered error while serializing Web Archive pasteboard data: %@", error);
231 NSArray *subItems = [NSArray arrayWithArray:[webArchive objectForKey:WebSubresourcesKey]];
232 NSPredicate *predicate = [NSPredicate predicateWithFormat:WebSubframeArchivesKey];
233 NSArray *imagesArray = [subItems filteredArrayUsingPredicate:predicate];
238 return imagesArray.count;
241 void TestController::removeAllSessionCredentials()
244 auto types = adoptNS([[NSSet alloc] initWithObjects:_WKWebsiteDataTypeCredentials, nil]);
245 [globalWebViewConfiguration.websiteDataStore removeDataOfTypes:types.get() modifiedSince:[NSDate distantPast] completionHandler:^() {
246 m_currentInvocation->didRemoveAllSessionCredentials();
252 void TestController::setStatisticsLastSeen(WKStringRef hostName, double seconds)
254 [globalWebViewConfiguration.websiteDataStore _resourceLoadStatisticsSetLastSeen:seconds forHost:toNSString(hostName)];
257 void TestController::setStatisticsPrevalentResource(WKStringRef hostName, bool value)
259 [globalWebViewConfiguration.websiteDataStore _resourceLoadStatisticsSetIsPrevalentResource:value forHost:toNSString(hostName)];
262 bool TestController::isStatisticsPrevalentResource(WKStringRef hostName)
264 __block bool isDataReady = false;
265 __block bool isPrevalentResource = false;
266 [globalWebViewConfiguration.websiteDataStore _resourceLoadStatisticsIsPrevalentResource:toNSString(hostName) completionHandler:^(BOOL _isPrevalentResource) {
267 isPrevalentResource = _isPrevalentResource;
270 platformRunUntil(isDataReady, 0);
272 return isPrevalentResource;
275 bool TestController::isStatisticsRegisteredAsSubFrameUnder(WKStringRef subFrameHost, WKStringRef topFrameHost)
277 __block bool isDataReady = false;
278 __block bool isRegisteredAsSubFrameUnder = false;
279 [globalWebViewConfiguration.websiteDataStore _resourceLoadStatisticsIsRegisteredAsSubFrameUnder:toNSString(subFrameHost) topFrameHost:toNSString(topFrameHost) completionHandler:^(BOOL _isRegisteredAsSubFrameUnder) {
280 isRegisteredAsSubFrameUnder = _isRegisteredAsSubFrameUnder;
283 platformRunUntil(isDataReady, 0);
285 return isRegisteredAsSubFrameUnder;
288 bool TestController::isStatisticsRegisteredAsRedirectingTo(WKStringRef hostRedirectedFrom, WKStringRef hostRedirectedTo)
290 __block bool isDataReady = false;
291 __block bool isRegisteredAsRedirectingTo = false;
292 [globalWebViewConfiguration.websiteDataStore _resourceLoadStatisticsIsRegisteredAsRedirectingTo:toNSString(hostRedirectedFrom) hostRedirectedTo:toNSString(hostRedirectedTo) completionHandler:^(BOOL _isRegisteredAsRedirectingTo) {
293 isRegisteredAsRedirectingTo = _isRegisteredAsRedirectingTo;
296 platformRunUntil(isDataReady, 0);
298 return isRegisteredAsRedirectingTo;
301 void TestController::setStatisticsHasHadUserInteraction(WKStringRef hostName, bool value)
303 [globalWebViewConfiguration.websiteDataStore _resourceLoadStatisticsSetHadUserInteraction:value forHost:toNSString(hostName)];
306 bool TestController::isStatisticsHasHadUserInteraction(WKStringRef hostName)
308 __block bool isDataReady = false;
309 __block bool hasHadUserInteraction = false;
310 [globalWebViewConfiguration.websiteDataStore _resourceLoadStatisticsHadUserInteraction:toNSString(hostName) completionHandler:^(BOOL _hasHadUserInteraction) {
311 hasHadUserInteraction = _hasHadUserInteraction;
314 platformRunUntil(isDataReady, 0);
316 return hasHadUserInteraction;
319 void TestController::setStatisticsGrandfathered(WKStringRef hostName, bool value)
321 [globalWebViewConfiguration.websiteDataStore _resourceLoadStatisticsSetIsGrandfathered:value forHost:toNSString(hostName)];
324 bool TestController::isStatisticsGrandfathered(WKStringRef hostName)
326 __block bool isDataReady = false;
327 __block bool isGrandfathered = false;
328 [globalWebViewConfiguration.websiteDataStore _resourceLoadStatisticsIsGrandfathered:toNSString(hostName) completionHandler:^(BOOL _isGrandfathered) {
329 isGrandfathered = _isGrandfathered;
332 platformRunUntil(isDataReady, 0);
334 return isGrandfathered;
337 void TestController::setStatisticsSubframeUnderTopFrameOrigin(WKStringRef hostName, WKStringRef topFrameHostName)
339 [globalWebViewConfiguration.websiteDataStore _resourceLoadStatisticsSetSubframeUnderTopFrameOrigin:toNSString(topFrameHostName) forHost:toNSString(hostName)];
342 void TestController::setStatisticsSubresourceUnderTopFrameOrigin(WKStringRef hostName, WKStringRef topFrameHostName)
344 [globalWebViewConfiguration.websiteDataStore _resourceLoadStatisticsSetSubresourceUnderTopFrameOrigin:toNSString(topFrameHostName) forHost:toNSString(hostName)];
347 void TestController::setStatisticsSubresourceUniqueRedirectTo(WKStringRef hostName, WKStringRef hostNameRedirectedTo)
349 [globalWebViewConfiguration.websiteDataStore _resourceLoadStatisticsSetSubresourceUniqueRedirectTo:toNSString(hostNameRedirectedTo) forHost:toNSString(hostName)];
352 void TestController::setStatisticsTimeToLiveUserInteraction(double seconds)
354 [globalWebViewConfiguration.websiteDataStore _resourceLoadStatisticsSetTimeToLiveUserInteraction:seconds];
357 void TestController::setStatisticsTimeToLiveCookiePartitionFree(double seconds)
359 [globalWebViewConfiguration.websiteDataStore _resourceLoadStatisticsSetTimeToLiveCookiePartitionFree:seconds];
362 void TestController::statisticsProcessStatisticsAndDataRecords()
364 [globalWebViewConfiguration.websiteDataStore _resourceLoadStatisticsProcessStatisticsAndDataRecords];
367 void TestController::statisticsUpdateCookiePartitioning()
369 [globalWebViewConfiguration.websiteDataStore _resourceLoadStatisticsUpdateCookiePartitioning];
372 void TestController::statisticsSetShouldPartitionCookiesForHost(WKStringRef hostName, bool value)
374 [globalWebViewConfiguration.websiteDataStore _resourceLoadStatisticsSetShouldPartitionCookies:value forHost:toNSString(hostName)];
377 void TestController::statisticsSubmitTelemetry()
379 [globalWebViewConfiguration.websiteDataStore _resourceLoadStatisticsSubmitTelemetry];
382 void TestController::setStatisticsNotifyPagesWhenDataRecordsWereScanned(bool value)
384 [globalWebViewConfiguration.websiteDataStore _resourceLoadStatisticsSetNotifyPagesWhenDataRecordsWereScanned:value];
387 void TestController::setStatisticsShouldClassifyResourcesBeforeDataRecordsRemoval(bool value)
389 [globalWebViewConfiguration.websiteDataStore _resourceLoadStatisticsSetShouldClassifyResourcesBeforeDataRecordsRemoval:value];
392 void TestController::setStatisticsNotifyPagesWhenTelemetryWasCaptured(bool value)
394 [globalWebViewConfiguration.websiteDataStore _resourceLoadStatisticsSetNotifyPagesWhenTelemetryWasCaptured:value];
397 void TestController::setStatisticsMinimumTimeBetweenDataRecordsRemoval(double seconds)
399 [globalWebViewConfiguration.websiteDataStore _resourceLoadStatisticsSetMinimumTimeBetweenDataRecordsRemoval:seconds];
402 void TestController::setStatisticsGrandfatheringTime(double seconds)
404 [globalWebViewConfiguration.websiteDataStore _resourceLoadStatisticsSetGrandfatheringTime:seconds];
407 void TestController::setStatisticsMaxStatisticsEntries(unsigned entries)
409 [globalWebViewConfiguration.websiteDataStore _resourceLoadStatisticsSetMaxStatisticsEntries:entries];
412 void TestController::setStatisticsPruneEntriesDownTo(unsigned entries)
414 [globalWebViewConfiguration.websiteDataStore _resourceLoadStatisticsSetPruneEntriesDownTo:entries];
417 void TestController::statisticsClearInMemoryAndPersistentStore()
419 [globalWebViewConfiguration.websiteDataStore _resourceLoadStatisticsClearInMemoryAndPersistentStore];
422 void TestController::statisticsClearInMemoryAndPersistentStoreModifiedSinceHours(unsigned hours)
424 [globalWebViewConfiguration.websiteDataStore _resourceLoadStatisticsClearInMemoryAndPersistentStoreModifiedSinceHours:hours];
427 void TestController::statisticsClearThroughWebsiteDataRemoval()
430 auto types = adoptNS([[NSSet alloc] initWithObjects:_WKWebsiteDataTypeResourceLoadStatistics, nil]);
431 [globalWebViewConfiguration.websiteDataStore removeDataOfTypes:types.get() modifiedSince:[NSDate distantPast] completionHandler:^() {
432 m_currentInvocation->didClearStatisticsThroughWebsiteDataRemoval();
437 void TestController::statisticsResetToConsistentState()
439 [globalWebViewConfiguration.websiteDataStore _resourceLoadStatisticsResetToConsistentState];
441 #endif // WK_API_ENABLED