Add configuration for automatic process pre-warming
[WebKit-https.git] / Tools / TestWebKitAPI / Tests / WebKitCocoa / ProcessSwapOnNavigation.mm
1 /*
2  * Copyright (C) 2017 Apple Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
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.
12  *
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.
24  */
25
26 #import "config.h"
27
28 #import "PlatformUtilities.h"
29 #import "Test.h"
30 #import <WebKit/WKInspector.h>
31 #import <WebKit/WKNavigationDelegatePrivate.h>
32 #import <WebKit/WKNavigationPrivate.h>
33 #import <WebKit/WKPreferencesPrivate.h>
34 #import <WebKit/WKProcessPoolPrivate.h>
35 #import <WebKit/WKUIDelegatePrivate.h>
36 #import <WebKit/WKURLSchemeHandler.h>
37 #import <WebKit/WKURLSchemeTaskPrivate.h>
38 #import <WebKit/WKWebViewConfigurationPrivate.h>
39 #import <WebKit/WKWebViewPrivate.h>
40 #import <WebKit/WKWebsiteDataStorePrivate.h>
41 #import <WebKit/WKWebsiteDataStoreRef.h>
42 #import <WebKit/WebKit.h>
43 #import <WebKit/_WKExperimentalFeature.h>
44 #import <WebKit/_WKProcessPoolConfiguration.h>
45 #import <WebKit/_WKWebsiteDataStoreConfiguration.h>
46 #import <WebKit/_WKWebsitePolicies.h>
47 #import <wtf/Deque.h>
48 #import <wtf/HashMap.h>
49 #import <wtf/HashSet.h>
50 #import <wtf/RetainPtr.h>
51 #import <wtf/Vector.h>
52 #import <wtf/text/StringHash.h>
53 #import <wtf/text/WTFString.h>
54
55 #if WK_API_ENABLED
56
57 @interface WKProcessPool ()
58 - (WKContextRef)_contextForTesting;
59 @end
60
61 static bool done;
62 static bool failed;
63 static bool didCreateWebView;
64 static int numberOfDecidePolicyCalls;
65
66 static RetainPtr<NSMutableArray> receivedMessages = adoptNS([@[] mutableCopy]);
67 bool didReceiveAlert;
68 static bool receivedMessage;
69 static bool serverRedirected;
70 static HashSet<pid_t> seenPIDs;
71 @interface PSONMessageHandler : NSObject <WKScriptMessageHandler>
72 @end
73
74 @implementation PSONMessageHandler
75 - (void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message
76 {
77     if ([message body])
78         [receivedMessages addObject:[message body]];
79     else
80         [receivedMessages addObject:@""];
81
82     receivedMessage = true;
83     if ([message.webView _webProcessIdentifier])
84         seenPIDs.add([message.webView _webProcessIdentifier]);
85 }
86 @end
87
88 @interface PSONNavigationDelegate : NSObject <WKNavigationDelegate> {
89     @public WKNavigationActionPolicy navigationActionPolicyToUse;
90 }
91 @end
92
93 @implementation PSONNavigationDelegate
94
95 - (instancetype) init
96 {
97     self = [super init];
98     navigationActionPolicyToUse = WKNavigationActionPolicyAllow;
99     return self;
100 }
101
102 - (void)webView:(WKWebView *)webView didFailProvisionalNavigation:(WKNavigation *)navigation withError:(NSError *)error
103 {
104     seenPIDs.add([webView _webProcessIdentifier]);
105     failed = true;
106 }
107
108 - (void)webView:(WKWebView *)webView didFinishNavigation:(WKNavigation *)navigation
109 {
110     seenPIDs.add([webView _webProcessIdentifier]);
111     done = true;
112 }
113
114 - (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler
115 {
116     ++numberOfDecidePolicyCalls;
117     seenPIDs.add([webView _webProcessIdentifier]);
118     decisionHandler(navigationActionPolicyToUse);
119 }
120
121 - (void)webView:(WKWebView *)webView didReceiveServerRedirectForProvisionalNavigation:(WKNavigation *)navigation
122 {
123     seenPIDs.add([webView _webProcessIdentifier]);
124     serverRedirected = true;
125 }
126
127 @end
128
129 static RetainPtr<WKWebView> createdWebView;
130
131 @interface PSONUIDelegate : NSObject <WKUIDelegatePrivate>
132 - (instancetype)initWithNavigationDelegate:(PSONNavigationDelegate *)navigationDelegate;
133 @end
134
135 @implementation PSONUIDelegate {
136     RetainPtr<PSONNavigationDelegate> _navigationDelegate;
137 }
138
139 - (instancetype)initWithNavigationDelegate:(PSONNavigationDelegate *)navigationDelegate
140 {
141     if (!(self = [super init]))
142         return nil;
143
144     _navigationDelegate = navigationDelegate;
145     return self;
146 }
147
148 - (nullable WKWebView *)webView:(WKWebView *)webView createWebViewWithConfiguration:(WKWebViewConfiguration *)configuration forNavigationAction:(WKNavigationAction *)navigationAction windowFeatures:(WKWindowFeatures *)windowFeatures
149 {
150     createdWebView = adoptNS([[WKWebView alloc] initWithFrame:CGRectMake(0, 0, 800, 600) configuration:configuration]);
151     [createdWebView setNavigationDelegate:_navigationDelegate.get()];
152     didCreateWebView = true;
153     return createdWebView.get();
154 }
155
156 - (void)webView:(WKWebView *)webView runJavaScriptAlertPanelWithMessage:(NSString *)message initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)())completionHandler
157 {
158     didReceiveAlert = true;
159     completionHandler();
160 }
161
162 @end
163
164 @interface PSONScheme : NSObject <WKURLSchemeHandler> {
165     const char* _bytes;
166     HashMap<String, String> _redirects;
167     HashMap<String, RetainPtr<NSData *>> _dataMappings;
168 }
169 - (instancetype)initWithBytes:(const char*)bytes;
170 - (void)addRedirectFromURLString:(NSString *)sourceURLString toURLString:(NSString *)destinationURLString;
171 - (void)addMappingFromURLString:(NSString *)urlString toData:(const char*)data;
172 @end
173
174 @implementation PSONScheme
175
176 - (instancetype)initWithBytes:(const char*)bytes
177 {
178     self = [super init];
179     _bytes = bytes;
180     return self;
181 }
182
183 - (void)addRedirectFromURLString:(NSString *)sourceURLString toURLString:(NSString *)destinationURLString
184 {
185     _redirects.set(sourceURLString, destinationURLString);
186 }
187
188 - (void)addMappingFromURLString:(NSString *)urlString toData:(const char*)data
189 {
190     _dataMappings.set(urlString, [NSData dataWithBytesNoCopy:(void*)data length:strlen(data) freeWhenDone:NO]);
191 }
192
193 - (void)webView:(WKWebView *)webView startURLSchemeTask:(id <WKURLSchemeTask>)task
194 {
195     NSURL *finalURL = task.request.URL;
196     auto target = _redirects.get(task.request.URL.absoluteString);
197     if (!target.isEmpty()) {
198         auto redirectResponse = adoptNS([[NSURLResponse alloc] initWithURL:task.request.URL MIMEType:nil expectedContentLength:0 textEncodingName:nil]);
199
200         finalURL = [NSURL URLWithString:(NSString *)target];
201         auto request = adoptNS([[NSURLRequest alloc] initWithURL:finalURL]);
202
203         [(id<WKURLSchemeTaskPrivate>)task _didPerformRedirection:redirectResponse.get() newRequest:request.get()];
204     }
205
206     RetainPtr<NSURLResponse> response = adoptNS([[NSURLResponse alloc] initWithURL:finalURL MIMEType:@"text/html" expectedContentLength:1 textEncodingName:nil]);
207     [task didReceiveResponse:response.get()];
208
209     if (auto data = _dataMappings.get([finalURL absoluteString]))
210         [task didReceiveData:data.get()];
211     else if (_bytes) {
212         RetainPtr<NSData> data = adoptNS([[NSData alloc] initWithBytesNoCopy:(void *)_bytes length:strlen(_bytes) freeWhenDone:NO]);
213         [task didReceiveData:data.get()];
214     } else
215         [task didReceiveData:[@"Hello" dataUsingEncoding:NSUTF8StringEncoding]];
216
217     [task didFinish];
218 }
219
220 - (void)webView:(WKWebView *)webView stopURLSchemeTask:(id <WKURLSchemeTask>)task
221 {
222 }
223
224 @end
225
226 static const char* testBytes = R"PSONRESOURCE(
227 <head>
228 <script>
229
230 function log(msg)
231 {
232     window.webkit.messageHandlers.pson.postMessage(msg);
233 }
234
235 window.onload = function(evt) {
236     if (window.history.state != "onloadCalled")
237         setTimeout('window.history.replaceState("onloadCalled", "");', 0);
238 }
239
240 window.onpageshow = function(evt) {
241     log("PageShow called. Persisted: " + evt.persisted + ", and window.history.state is: " + window.history.state);
242 }
243
244 </script>
245 </head>
246 )PSONRESOURCE";
247
248 #if PLATFORM(MAC)
249
250 static const char* windowOpenCrossOriginNoOpenerTestBytes = R"PSONRESOURCE(
251 <script>
252 window.onload = function() {
253     window.open("pson2://host/main2.html", "_blank", "noopener");
254 }
255 </script>
256 )PSONRESOURCE";
257
258 static const char* windowOpenCrossOriginWithOpenerTestBytes = R"PSONRESOURCE(
259 <script>
260 window.onload = function() {
261     window.open("pson2://host/main2.html");
262 }
263 </script>
264 )PSONRESOURCE";
265
266 static const char* windowOpenSameOriginNoOpenerTestBytes = R"PSONRESOURCE(
267 <script>
268 window.onload = function() {
269     if (!opener)
270         window.open("pson1://host/main2.html", "_blank", "noopener");
271 }
272 </script>
273 )PSONRESOURCE";
274
275 static const char* dummyBytes = R"PSONRESOURCE(
276 <body>TEST</body>
277 )PSONRESOURCE";
278
279 #endif // PLATFORM(MAC)
280
281 TEST(ProcessSwap, Basic)
282 {
283     auto processPoolConfiguration = adoptNS([[_WKProcessPoolConfiguration alloc] init]);
284     processPoolConfiguration.get().processSwapsOnNavigation = YES;
285     processPoolConfiguration.get().maximumPrewarmedProcessCount = 1;
286     auto processPool = adoptNS([[WKProcessPool alloc] _initWithConfiguration:processPoolConfiguration.get()]);
287
288     auto webViewConfiguration = adoptNS([[WKWebViewConfiguration alloc] init]);
289     [webViewConfiguration setProcessPool:processPool.get()];
290     RetainPtr<PSONScheme> handler = adoptNS([[PSONScheme alloc] init]);
291     [webViewConfiguration setURLSchemeHandler:handler.get() forURLScheme:@"PSON1"];
292     [webViewConfiguration setURLSchemeHandler:handler.get() forURLScheme:@"PSON2"];
293
294     auto webView = adoptNS([[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:webViewConfiguration.get()]);
295     auto delegate = adoptNS([[PSONNavigationDelegate alloc] init]);
296     [webView setNavigationDelegate:delegate.get()];
297
298     NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson1://host/main1.html"]];
299     [webView loadRequest:request];
300
301     TestWebKitAPI::Util::run(&done);
302     done = false;
303
304     auto pid1 = [webView _webProcessIdentifier];
305
306     request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson1://host/main2.html"]];
307     [webView loadRequest:request];
308
309     TestWebKitAPI::Util::run(&done);
310     done = false;
311
312     auto pid2 = [webView _webProcessIdentifier];
313
314     request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson2://host/main2.html"]];
315     [webView loadRequest:request];
316
317     TestWebKitAPI::Util::run(&done);
318     done = false;
319
320     auto pid3 = [webView _webProcessIdentifier];
321
322     EXPECT_EQ(pid1, pid2);
323     EXPECT_FALSE(pid2 == pid3);
324
325     // 3 loads, 3 decidePolicy calls (e.g. the load that did perform a process swap should not have generated an additional decidePolicy call)
326     EXPECT_EQ(numberOfDecidePolicyCalls, 3);
327 }
328
329 TEST(ProcessSwap, Back)
330 {
331     auto processPoolConfiguration = adoptNS([[_WKProcessPoolConfiguration alloc] init]);
332     processPoolConfiguration.get().processSwapsOnNavigation = YES;
333     auto processPool = adoptNS([[WKProcessPool alloc] _initWithConfiguration:processPoolConfiguration.get()]);
334
335     auto webViewConfiguration = adoptNS([[WKWebViewConfiguration alloc] init]);
336     [webViewConfiguration setProcessPool:processPool.get()];
337     RetainPtr<PSONScheme> handler1 = adoptNS([[PSONScheme alloc] initWithBytes:testBytes]);
338     RetainPtr<PSONScheme> handler2 = adoptNS([[PSONScheme alloc] init]);
339     [webViewConfiguration setURLSchemeHandler:handler1.get() forURLScheme:@"PSON1"];
340     [webViewConfiguration setURLSchemeHandler:handler2.get() forURLScheme:@"PSON2"];
341
342     RetainPtr<PSONMessageHandler> messageHandler = adoptNS([[PSONMessageHandler alloc] init]);
343     [[webViewConfiguration userContentController] addScriptMessageHandler:messageHandler.get() name:@"pson"];
344
345     auto webView = adoptNS([[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:webViewConfiguration.get()]);
346     auto delegate = adoptNS([[PSONNavigationDelegate alloc] init]);
347     [webView setNavigationDelegate:delegate.get()];
348
349     NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson1://host/main1.html"]];
350     [webView loadRequest:request];
351
352     TestWebKitAPI::Util::run(&receivedMessage);
353     receivedMessage = false;
354     TestWebKitAPI::Util::run(&done);
355     done = false;
356
357     auto pid1 = [webView _webProcessIdentifier];
358
359     request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson2://host/main2.html"]];
360     [webView loadRequest:request];
361
362     TestWebKitAPI::Util::run(&done);
363     done = false;
364
365     auto pid2 = [webView _webProcessIdentifier];
366
367     [webView goBack];
368
369     TestWebKitAPI::Util::run(&receivedMessage);
370     receivedMessage = false;
371     TestWebKitAPI::Util::run(&done);
372     done = false;
373
374     auto pid3 = [webView _webProcessIdentifier];
375
376     // 3 loads, 3 decidePolicy calls (e.g. any load that performs a process swap should not have generated an
377     // additional decidePolicy call as a result of the process swap)
378     EXPECT_EQ(numberOfDecidePolicyCalls, 3);
379
380     EXPECT_EQ([receivedMessages count], 2u);
381     EXPECT_TRUE([receivedMessages.get()[0] isEqualToString:@"PageShow called. Persisted: false, and window.history.state is: null"]);
382     EXPECT_TRUE([receivedMessages.get()[1] isEqualToString:@"PageShow called. Persisted: true, and window.history.state is: onloadCalled"]);
383
384     EXPECT_EQ(2u, seenPIDs.size());
385
386     EXPECT_FALSE(pid1 == pid2);
387     EXPECT_FALSE(pid2 == pid3);
388     EXPECT_TRUE(pid1 == pid3);
389 }
390
391 #if PLATFORM(MAC)
392
393 TEST(ProcessSwap, CrossOriginWindowOpenNoOpener)
394 {
395     auto processPoolConfiguration = adoptNS([[_WKProcessPoolConfiguration alloc] init]);
396     processPoolConfiguration.get().processSwapsOnNavigation = YES;
397     auto processPool = adoptNS([[WKProcessPool alloc] _initWithConfiguration:processPoolConfiguration.get()]);
398
399     auto webViewConfiguration = adoptNS([[WKWebViewConfiguration alloc] init]);
400     [webViewConfiguration setProcessPool:processPool.get()];
401     RetainPtr<PSONScheme> handler1 = adoptNS([[PSONScheme alloc] initWithBytes:windowOpenCrossOriginNoOpenerTestBytes]);
402     RetainPtr<PSONScheme> handler2 = adoptNS([[PSONScheme alloc] initWithBytes:dummyBytes]);
403     [webViewConfiguration setURLSchemeHandler:handler1.get() forURLScheme:@"PSON1"];
404     [webViewConfiguration setURLSchemeHandler:handler2.get() forURLScheme:@"PSON2"];
405
406     auto webView = adoptNS([[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:webViewConfiguration.get()]);
407     auto navigationDelegate = adoptNS([[PSONNavigationDelegate alloc] init]);
408     [webView setNavigationDelegate:navigationDelegate.get()];
409     auto uiDelegate = adoptNS([[PSONUIDelegate alloc] initWithNavigationDelegate:navigationDelegate.get()]);
410     [webView setUIDelegate:uiDelegate.get()];
411
412     numberOfDecidePolicyCalls = 0;
413     NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson1://host/main1.html"]];
414     [webView loadRequest:request];
415
416     TestWebKitAPI::Util::run(&done);
417     done = false;
418
419     TestWebKitAPI::Util::run(&didCreateWebView);
420     didCreateWebView = false;
421
422     TestWebKitAPI::Util::run(&done);
423
424     EXPECT_EQ(2, numberOfDecidePolicyCalls);
425
426     auto pid1 = [webView _webProcessIdentifier];
427     EXPECT_TRUE(!!pid1);
428     auto pid2 = [createdWebView _webProcessIdentifier];
429     EXPECT_TRUE(!!pid2);
430
431     EXPECT_NE(pid1, pid2);
432 }
433
434 TEST(ProcessSwap, CrossOriginWindowOpenWithOpener)
435 {
436     auto processPoolConfiguration = adoptNS([[_WKProcessPoolConfiguration alloc] init]);
437     processPoolConfiguration.get().processSwapsOnNavigation = YES;
438     processPoolConfiguration.get().processSwapsOnWindowOpenWithOpener = YES;
439     auto processPool = adoptNS([[WKProcessPool alloc] _initWithConfiguration:processPoolConfiguration.get()]);
440
441     auto webViewConfiguration = adoptNS([[WKWebViewConfiguration alloc] init]);
442     [webViewConfiguration setProcessPool:processPool.get()];
443     RetainPtr<PSONScheme> handler1 = adoptNS([[PSONScheme alloc] initWithBytes:windowOpenCrossOriginWithOpenerTestBytes]);
444     RetainPtr<PSONScheme> handler2 = adoptNS([[PSONScheme alloc] initWithBytes:dummyBytes]);
445     [webViewConfiguration setURLSchemeHandler:handler1.get() forURLScheme:@"PSON1"];
446     [webViewConfiguration setURLSchemeHandler:handler2.get() forURLScheme:@"PSON2"];
447
448     auto webView = adoptNS([[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:webViewConfiguration.get()]);
449     auto navigationDelegate = adoptNS([[PSONNavigationDelegate alloc] init]);
450     [webView setNavigationDelegate:navigationDelegate.get()];
451     auto uiDelegate = adoptNS([[PSONUIDelegate alloc] initWithNavigationDelegate:navigationDelegate.get()]);
452     [webView setUIDelegate:uiDelegate.get()];
453
454     numberOfDecidePolicyCalls = 0;
455     NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson1://host/main1.html"]];
456     [webView loadRequest:request];
457
458     TestWebKitAPI::Util::run(&done);
459     done = false;
460
461     TestWebKitAPI::Util::run(&didCreateWebView);
462     didCreateWebView = false;
463
464     TestWebKitAPI::Util::run(&done);
465
466     EXPECT_EQ(2, numberOfDecidePolicyCalls);
467
468     auto pid1 = [webView _webProcessIdentifier];
469     EXPECT_TRUE(!!pid1);
470     auto pid2 = [createdWebView _webProcessIdentifier];
471     EXPECT_TRUE(!!pid2);
472
473     EXPECT_NE(pid1, pid2);
474 }
475
476 TEST(ProcessSwap, SameOriginWindowOpenNoOpener)
477 {
478     auto processPoolConfiguration = adoptNS([[_WKProcessPoolConfiguration alloc] init]);
479     processPoolConfiguration.get().processSwapsOnNavigation = YES;
480     auto processPool = adoptNS([[WKProcessPool alloc] _initWithConfiguration:processPoolConfiguration.get()]);
481
482     auto webViewConfiguration = adoptNS([[WKWebViewConfiguration alloc] init]);
483     [webViewConfiguration setProcessPool:processPool.get()];
484     RetainPtr<PSONScheme> handler = adoptNS([[PSONScheme alloc] initWithBytes:windowOpenSameOriginNoOpenerTestBytes]);
485     [webViewConfiguration setURLSchemeHandler:handler.get() forURLScheme:@"PSON1"];
486
487     auto webView = adoptNS([[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:webViewConfiguration.get()]);
488     auto navigationDelegate = adoptNS([[PSONNavigationDelegate alloc] init]);
489     [webView setNavigationDelegate:navigationDelegate.get()];
490     auto uiDelegate = adoptNS([[PSONUIDelegate alloc] initWithNavigationDelegate:navigationDelegate.get()]);
491     [webView setUIDelegate:uiDelegate.get()];
492
493     numberOfDecidePolicyCalls = 0;
494     NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson1://host/main1.html"]];
495     [webView loadRequest:request];
496
497     TestWebKitAPI::Util::run(&done);
498     done = false;
499
500     TestWebKitAPI::Util::run(&didCreateWebView);
501     didCreateWebView = false;
502
503     TestWebKitAPI::Util::run(&done);
504
505     EXPECT_EQ(2, numberOfDecidePolicyCalls);
506
507     auto pid1 = [webView _webProcessIdentifier];
508     EXPECT_TRUE(!!pid1);
509     auto pid2 = [createdWebView _webProcessIdentifier];
510     EXPECT_TRUE(!!pid2);
511
512     EXPECT_EQ(pid1, pid2);
513 }
514
515 #endif // PLATFORM(MAC)
516
517 TEST(ProcessSwap, ServerRedirectFromNewWebView)
518 {
519     auto processPoolConfiguration = adoptNS([[_WKProcessPoolConfiguration alloc] init]);
520     processPoolConfiguration.get().processSwapsOnNavigation = YES;
521     auto processPool = adoptNS([[WKProcessPool alloc] _initWithConfiguration:processPoolConfiguration.get()]);
522
523     auto webViewConfiguration = adoptNS([[WKWebViewConfiguration alloc] init]);
524     [webViewConfiguration setProcessPool:processPool.get()];
525     RetainPtr<PSONScheme> handler = adoptNS([[PSONScheme alloc] init]);
526     [handler addRedirectFromURLString:@"pson://host/main1.html" toURLString:@"psonredirected://host/main1.html"];
527     [webViewConfiguration setURLSchemeHandler:handler.get() forURLScheme:@"pson"];
528
529     auto webView = adoptNS([[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:webViewConfiguration.get()]);
530     auto delegate = adoptNS([[PSONNavigationDelegate alloc] init]);
531     [webView setNavigationDelegate:delegate.get()];
532
533     NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://host/main1.html"]];
534     [webView loadRequest:request];
535
536     TestWebKitAPI::Util::run(&serverRedirected);
537     serverRedirected = false;
538
539     seenPIDs.add([webView _webProcessIdentifier]);
540
541     TestWebKitAPI::Util::run(&done);
542     done = false;
543
544     seenPIDs.add([webView _webProcessIdentifier]);
545
546     EXPECT_FALSE(serverRedirected);
547     EXPECT_EQ(2, numberOfDecidePolicyCalls);
548     EXPECT_EQ(1u, seenPIDs.size());
549 }
550
551 TEST(ProcessSwap, ServerRedirect)
552 {
553     auto processPoolConfiguration = adoptNS([[_WKProcessPoolConfiguration alloc] init]);
554     processPoolConfiguration.get().processSwapsOnNavigation = YES;
555     auto processPool = adoptNS([[WKProcessPool alloc] _initWithConfiguration:processPoolConfiguration.get()]);
556
557     auto webViewConfiguration = adoptNS([[WKWebViewConfiguration alloc] init]);
558     [webViewConfiguration setProcessPool:processPool.get()];
559     RetainPtr<PSONScheme> handler1 = adoptNS([[PSONScheme alloc] init]);
560     [handler1 addRedirectFromURLString:@"pson://host/main1.html" toURLString:@"psonredirected://host/main1.html"];
561     [webViewConfiguration setURLSchemeHandler:handler1.get() forURLScheme:@"pson"];
562     RetainPtr<PSONScheme> handler2 = adoptNS([[PSONScheme alloc] init]);
563     [webViewConfiguration setURLSchemeHandler:handler2.get() forURLScheme:@"originalload"];
564
565     auto webView = adoptNS([[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:webViewConfiguration.get()]);
566     auto delegate = adoptNS([[PSONNavigationDelegate alloc] init]);
567     [webView setNavigationDelegate:delegate.get()];
568
569     NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"originalload://host/main1.html"]];
570     [webView loadRequest:request];
571
572     TestWebKitAPI::Util::run(&done);
573     done = false;
574
575     auto pidAfterFirstLoad = [webView _webProcessIdentifier];
576
577     EXPECT_EQ(1, numberOfDecidePolicyCalls);
578     EXPECT_EQ(1u, seenPIDs.size());
579     EXPECT_TRUE(*seenPIDs.begin() == pidAfterFirstLoad);
580
581     request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://host/main1.html"]];
582     [webView loadRequest:request];
583
584     TestWebKitAPI::Util::run(&serverRedirected);
585     serverRedirected = false;
586
587     seenPIDs.add([webView _webProcessIdentifier]);
588
589     TestWebKitAPI::Util::run(&done);
590     done = false;
591
592     seenPIDs.add([webView _webProcessIdentifier]);
593
594     EXPECT_FALSE(serverRedirected);
595     EXPECT_EQ(3, numberOfDecidePolicyCalls);
596     EXPECT_EQ(2u, seenPIDs.size());
597 }
598
599 TEST(ProcessSwap, ServerRedirect2)
600 {
601     // This tests a load that *starts out* to the same origin as the previous load, but then redirects to a new origin.
602     auto processPoolConfiguration = adoptNS([[_WKProcessPoolConfiguration alloc] init]);
603     processPoolConfiguration.get().processSwapsOnNavigation = YES;
604     auto processPool = adoptNS([[WKProcessPool alloc] _initWithConfiguration:processPoolConfiguration.get()]);
605
606     auto webViewConfiguration = adoptNS([[WKWebViewConfiguration alloc] init]);
607     [webViewConfiguration setProcessPool:processPool.get()];
608     RetainPtr<PSONScheme> handler1 = adoptNS([[PSONScheme alloc] init]);
609     [handler1 addRedirectFromURLString:@"pson://host/main2.html" toURLString:@"psonredirected://host/main1.html"];
610     [webViewConfiguration setURLSchemeHandler:handler1.get() forURLScheme:@"pson"];
611     RetainPtr<PSONScheme> handler2 = adoptNS([[PSONScheme alloc] init]);
612     [webViewConfiguration setURLSchemeHandler:handler2.get() forURLScheme:@"psonredirected"];
613
614     auto webView = adoptNS([[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:webViewConfiguration.get()]);
615     auto delegate = adoptNS([[PSONNavigationDelegate alloc] init]);
616     [webView setNavigationDelegate:delegate.get()];
617
618     NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://host/main1.html"]];
619     [webView loadRequest:request];
620
621     TestWebKitAPI::Util::run(&done);
622     done = false;
623
624     auto pidAfterFirstLoad = [webView _webProcessIdentifier];
625
626     EXPECT_FALSE(serverRedirected);
627     EXPECT_EQ(1, numberOfDecidePolicyCalls);
628     EXPECT_EQ(1u, seenPIDs.size());
629     EXPECT_TRUE(*seenPIDs.begin() == pidAfterFirstLoad);
630
631     request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://host/main2.html"]];
632     [webView loadRequest:request];
633
634     TestWebKitAPI::Util::run(&serverRedirected);
635     serverRedirected = false;
636
637     seenPIDs.add([webView _webProcessIdentifier]);
638
639     TestWebKitAPI::Util::run(&done);
640     done = false;
641
642     seenPIDs.add([webView _webProcessIdentifier]);
643
644     EXPECT_FALSE(serverRedirected);
645     EXPECT_EQ(3, numberOfDecidePolicyCalls);
646     EXPECT_EQ(2u, seenPIDs.size());
647 }
648
649 static const char* sessionStorageTestBytes = R"PSONRESOURCE(
650 <head>
651 <script>
652
653 function log(msg)
654 {
655     window.webkit.messageHandlers.pson.postMessage(msg);
656 }
657
658 window.onload = function(evt) {
659     log(sessionStorage.psonKey);
660     sessionStorage.psonKey = "I exist!";
661 }
662
663 </script>
664 </head>
665 )PSONRESOURCE";
666
667 TEST(ProcessSwap, SessionStorage)
668 {
669     auto processPoolConfiguration = adoptNS([[_WKProcessPoolConfiguration alloc] init]);
670     [processPoolConfiguration setProcessSwapsOnNavigation:YES];
671     auto processPool = adoptNS([[WKProcessPool alloc] _initWithConfiguration:processPoolConfiguration.get()]);
672
673     auto webViewConfiguration = adoptNS([[WKWebViewConfiguration alloc] init]);
674     [webViewConfiguration setProcessPool:processPool.get()];
675     auto handler1 = adoptNS([[PSONScheme alloc] initWithBytes:sessionStorageTestBytes]);
676     auto handler2 = adoptNS([[PSONScheme alloc] init]);
677     [webViewConfiguration setURLSchemeHandler:handler1.get() forURLScheme:@"PSON1"];
678     [webViewConfiguration setURLSchemeHandler:handler2.get() forURLScheme:@"PSON2"];
679
680     auto messageHandler = adoptNS([[PSONMessageHandler alloc] init]);
681     [[webViewConfiguration userContentController] addScriptMessageHandler:messageHandler.get() name:@"pson"];
682
683     auto webView = adoptNS([[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:webViewConfiguration.get()]);
684     auto delegate = adoptNS([[PSONNavigationDelegate alloc] init]);
685     [webView setNavigationDelegate:delegate.get()];
686
687     NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson1://host/main.html"]];
688     [webView loadRequest:request];
689
690     TestWebKitAPI::Util::run(&receivedMessage);
691     receivedMessage = false;
692     TestWebKitAPI::Util::run(&done);
693     done = false;
694
695     auto pid1 = [webView _webProcessIdentifier];
696
697     request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson2://host/main.html"]];
698     [webView loadRequest:request];
699
700     TestWebKitAPI::Util::run(&done);
701     done = false;
702
703     auto pid2 = [webView _webProcessIdentifier];
704
705     request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson1://host/main.html"]];
706     [webView loadRequest:request];
707
708     TestWebKitAPI::Util::run(&receivedMessage);
709     receivedMessage = false;
710     TestWebKitAPI::Util::run(&done);
711     done = false;
712
713     auto pid3 = [webView _webProcessIdentifier];
714
715     // Verify the web pages are in different processes
716     EXPECT_NE(pid1, pid2);
717     EXPECT_NE(pid1, pid3);
718     EXPECT_NE(pid2, pid3);
719
720     // Verify the sessionStorage values were as expected
721     EXPECT_EQ([receivedMessages count], 2u);
722     EXPECT_TRUE([receivedMessages.get()[0] isEqualToString:@""]);
723     EXPECT_TRUE([receivedMessages.get()[1] isEqualToString:@"I exist!"]);
724 }
725
726 static const char* mainFramesOnlyMainFrame = R"PSONRESOURCE(
727 <script>
728 function loaded() {
729     setTimeout('window.frames[0].location.href = "pson2://host2/main.html"', 0);
730 }
731 </script>
732 <body onload="loaded();">
733 Some text
734 <iframe src="pson1://host/iframe.html"></iframe>
735 </body>
736 )PSONRESOURCE";
737
738 static const char* mainFramesOnlySubframe = R"PSONRESOURCE(
739 Some content
740 )PSONRESOURCE";
741
742
743 static const char* mainFramesOnlySubframe2 = R"PSONRESOURCE(
744 <script>
745     window.webkit.messageHandlers.pson.postMessage("Done");
746 </script>
747 )PSONRESOURCE";
748
749 TEST(ProcessSwap, MainFramesOnly)
750 {
751     auto processPoolConfiguration = adoptNS([[_WKProcessPoolConfiguration alloc] init]);
752     [processPoolConfiguration setProcessSwapsOnNavigation:YES];
753     auto processPool = adoptNS([[WKProcessPool alloc] _initWithConfiguration:processPoolConfiguration.get()]);
754
755     auto webViewConfiguration = adoptNS([[WKWebViewConfiguration alloc] init]);
756     [webViewConfiguration setProcessPool:processPool.get()];
757     auto handler = adoptNS([[PSONScheme alloc] init]);
758     [handler addMappingFromURLString:@"pson1://host/main.html" toData:mainFramesOnlyMainFrame];
759     [handler addMappingFromURLString:@"pson1://host/iframe" toData:mainFramesOnlySubframe];
760     [handler addMappingFromURLString:@"pson2://host2/main.html" toData:mainFramesOnlySubframe2];
761     [webViewConfiguration setURLSchemeHandler:handler.get() forURLScheme:@"PSON1"];
762     [webViewConfiguration setURLSchemeHandler:handler.get() forURLScheme:@"PSON2"];
763
764     auto messageHandler = adoptNS([[PSONMessageHandler alloc] init]);
765     [[webViewConfiguration userContentController] addScriptMessageHandler:messageHandler.get() name:@"pson"];
766
767     auto webView = adoptNS([[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:webViewConfiguration.get()]);
768     auto delegate = adoptNS([[PSONNavigationDelegate alloc] init]);
769     [webView setNavigationDelegate:delegate.get()];
770
771     NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson1://host/main.html"]];
772     [webView loadRequest:request];
773
774     TestWebKitAPI::Util::run(&receivedMessage);
775     receivedMessage = false;
776
777     EXPECT_EQ(1u, seenPIDs.size());
778 }
779
780 TEST(ProcessSwap, OnePreviousProcessRemains)
781 {
782     auto processPoolConfiguration = adoptNS([[_WKProcessPoolConfiguration alloc] init]);
783     [processPoolConfiguration setProcessSwapsOnNavigation:YES];
784     auto processPool = adoptNS([[WKProcessPool alloc] _initWithConfiguration:processPoolConfiguration.get()]);
785
786     auto webViewConfiguration = adoptNS([[WKWebViewConfiguration alloc] init]);
787     [webViewConfiguration setProcessPool:processPool.get()];
788     auto handler = adoptNS([[PSONScheme alloc] init]);
789     [webViewConfiguration setURLSchemeHandler:handler.get() forURLScheme:@"PSON"];
790
791     auto webView = adoptNS([[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:webViewConfiguration.get()]);
792     auto delegate = adoptNS([[PSONNavigationDelegate alloc] init]);
793     [webView setNavigationDelegate:delegate.get()];
794
795     NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://host1/main.html"]];
796     [webView loadRequest:request];
797
798     TestWebKitAPI::Util::run(&done);
799     done = false;
800
801     request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://host2/main.html"]];
802     [webView loadRequest:request];
803
804     TestWebKitAPI::Util::run(&done);
805     done = false;
806
807     request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://host3/main.html"]];
808     [webView loadRequest:request];
809
810     TestWebKitAPI::Util::run(&done);
811     done = false;
812
813     // Navigations to 3 different domains, we expect to have seen 3 different PIDs
814     EXPECT_EQ(3u, seenPIDs.size());
815
816     // But only 2 of those processes should still be alive
817     EXPECT_EQ(2u, [processPool _webProcessCountIgnoringPrewarmed]);
818 }
819
820 static const char* pageCache1Bytes = R"PSONRESOURCE(
821 <script>
822 window.addEventListener('pageshow', function(event) {
823     if (event.persisted)
824         window.webkit.messageHandlers.pson.postMessage("Was persisted");
825 });
826 </script>
827 )PSONRESOURCE";
828
829 TEST(ProcessSwap, PageCache1)
830 {
831     auto processPoolConfiguration = adoptNS([[_WKProcessPoolConfiguration alloc] init]);
832     [processPoolConfiguration setProcessSwapsOnNavigation:YES];
833     auto processPool = adoptNS([[WKProcessPool alloc] _initWithConfiguration:processPoolConfiguration.get()]);
834
835     auto webViewConfiguration = adoptNS([[WKWebViewConfiguration alloc] init]);
836     [webViewConfiguration setProcessPool:processPool.get()];
837     auto handler = adoptNS([[PSONScheme alloc] init]);
838     [handler addMappingFromURLString:@"pson1://host/main.html" toData:pageCache1Bytes];
839     [handler addMappingFromURLString:@"pson2://host/main.html" toData:pageCache1Bytes];
840     [webViewConfiguration setURLSchemeHandler:handler.get() forURLScheme:@"PSON1"];
841     [webViewConfiguration setURLSchemeHandler:handler.get() forURLScheme:@"PSON2"];
842
843     auto messageHandler = adoptNS([[PSONMessageHandler alloc] init]);
844     [[webViewConfiguration userContentController] addScriptMessageHandler:messageHandler.get() name:@"pson"];
845
846     auto webView = adoptNS([[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:webViewConfiguration.get()]);
847     auto delegate = adoptNS([[PSONNavigationDelegate alloc] init]);
848     [webView setNavigationDelegate:delegate.get()];
849
850     NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson1://host/main.html"]];
851
852     [webView loadRequest:request];
853     TestWebKitAPI::Util::run(&done);
854     done = false;
855
856     auto pidAfterLoad1 = [webView _webProcessIdentifier];
857
858     EXPECT_EQ(1u, [processPool _webProcessCountIgnoringPrewarmed]);
859
860     request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson2://host/main.html"]];
861
862     [webView loadRequest:request];
863     TestWebKitAPI::Util::run(&done);
864     done = false;
865
866     auto pidAfterLoad2 = [webView _webProcessIdentifier];
867
868     EXPECT_EQ(2u, [processPool _webProcessCountIgnoringPrewarmed]);
869     EXPECT_NE(pidAfterLoad1, pidAfterLoad2);
870
871     [webView goBack];
872     TestWebKitAPI::Util::run(&receivedMessage);
873     receivedMessage = false;
874     TestWebKitAPI::Util::run(&done);
875     done = false;
876
877     auto pidAfterLoad3 = [webView _webProcessIdentifier];
878
879     EXPECT_EQ(2u, [processPool _webProcessCountIgnoringPrewarmed]);
880     EXPECT_EQ(pidAfterLoad1, pidAfterLoad3);
881     EXPECT_EQ(1u, [receivedMessages count]);
882     EXPECT_TRUE([receivedMessages.get()[0] isEqualToString:@"Was persisted" ]);
883     EXPECT_EQ(2u, seenPIDs.size());
884
885     [webView goForward];
886     TestWebKitAPI::Util::run(&receivedMessage);
887     receivedMessage = false;
888     TestWebKitAPI::Util::run(&done);
889     done = false;
890
891     auto pidAfterLoad4 = [webView _webProcessIdentifier];
892
893     EXPECT_EQ(2u, [processPool _webProcessCountIgnoringPrewarmed]);
894     EXPECT_EQ(pidAfterLoad2, pidAfterLoad4);
895     EXPECT_EQ(2u, [receivedMessages count]);
896     EXPECT_TRUE([receivedMessages.get()[1] isEqualToString:@"Was persisted" ]);
897     EXPECT_EQ(2u, seenPIDs.size());
898 }
899
900 TEST(ProcessSwap, NumberOfPrewarmedProcesses)
901 {
902     auto processPoolConfiguration = adoptNS([[_WKProcessPoolConfiguration alloc] init]);
903     [processPoolConfiguration setProcessSwapsOnNavigation:YES];
904     [processPoolConfiguration setMaximumPrewarmedProcessCount:1];
905     auto processPool = adoptNS([[WKProcessPool alloc] _initWithConfiguration:processPoolConfiguration.get()]);
906
907     auto webViewConfiguration = adoptNS([[WKWebViewConfiguration alloc] init]);
908     [webViewConfiguration setProcessPool:processPool.get()];
909     auto handler = adoptNS([[PSONScheme alloc] init]);
910     [webViewConfiguration setURLSchemeHandler:handler.get() forURLScheme:@"PSON"];
911
912     auto webView = adoptNS([[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:webViewConfiguration.get()]);
913     auto delegate = adoptNS([[PSONNavigationDelegate alloc] init]);
914     [webView setNavigationDelegate:delegate.get()];
915
916     NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://host1/main.html"]];
917     [webView loadRequest:request];
918     TestWebKitAPI::Util::run(&done);
919     done = false;
920
921     EXPECT_EQ(2u, [processPool _webProcessCount]);
922     EXPECT_EQ(1u, [processPool _webProcessCountIgnoringPrewarmed]);
923     EXPECT_EQ(1u, [processPool _prewarmedWebProcessCount]);
924
925     request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://host3/main.html"]];
926     [webView loadRequest:request];
927     TestWebKitAPI::Util::run(&done);
928     done = false;
929
930     EXPECT_EQ(3u, [processPool _webProcessCount]);
931     EXPECT_EQ(2u, [processPool _webProcessCountIgnoringPrewarmed]);
932     EXPECT_EQ(1u, [processPool _prewarmedWebProcessCount]);
933 }
934
935 static const char* visibilityBytes = R"PSONRESOURCE(
936 <script>
937 window.addEventListener('pageshow', function(event) {
938     var msg = window.location.href + " - pageshow ";
939     msg += event.persisted ? "persisted" : "NOT persisted";
940     window.webkit.messageHandlers.pson.postMessage(msg);
941 });
942
943 window.addEventListener('pagehide', function(event) {
944     var msg = window.location.href + " - pagehide ";
945     msg += event.persisted ? "persisted" : "NOT persisted";
946     window.webkit.messageHandlers.pson.postMessage(msg);
947 });
948 </script>
949 )PSONRESOURCE";
950
951 TEST(ProcessSwap, PageShowHide)
952 {
953     auto processPoolConfiguration = adoptNS([[_WKProcessPoolConfiguration alloc] init]);
954     [processPoolConfiguration setProcessSwapsOnNavigation:YES];
955     auto processPool = adoptNS([[WKProcessPool alloc] _initWithConfiguration:processPoolConfiguration.get()]);
956
957     auto webViewConfiguration = adoptNS([[WKWebViewConfiguration alloc] init]);
958     [webViewConfiguration setProcessPool:processPool.get()];
959     auto handler = adoptNS([[PSONScheme alloc] init]);
960     [handler addMappingFromURLString:@"pson1://host/main.html" toData:visibilityBytes];
961     [handler addMappingFromURLString:@"pson2://host/main.html" toData:visibilityBytes];
962     [webViewConfiguration setURLSchemeHandler:handler.get() forURLScheme:@"PSON1"];
963     [webViewConfiguration setURLSchemeHandler:handler.get() forURLScheme:@"PSON2"];
964
965     auto messageHandler = adoptNS([[PSONMessageHandler alloc] init]);
966     [[webViewConfiguration userContentController] addScriptMessageHandler:messageHandler.get() name:@"pson"];
967
968     auto webView = adoptNS([[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:webViewConfiguration.get()]);
969     auto delegate = adoptNS([[PSONNavigationDelegate alloc] init]);
970     [webView setNavigationDelegate:delegate.get()];
971
972     NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson1://host/main.html"]];
973
974     [webView loadRequest:request];
975     TestWebKitAPI::Util::run(&receivedMessage);
976     receivedMessage = false;
977     TestWebKitAPI::Util::run(&done);
978     done = false;
979
980     request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson2://host/main.html"]];
981
982     [webView loadRequest:request];
983     TestWebKitAPI::Util::run(&receivedMessage);
984     receivedMessage = false;
985     TestWebKitAPI::Util::run(&done);
986     done = false;
987
988     [webView goBack];
989     TestWebKitAPI::Util::run(&receivedMessage);
990     receivedMessage = false;
991     TestWebKitAPI::Util::run(&done);
992     done = false;
993
994     [webView goForward];
995     TestWebKitAPI::Util::run(&receivedMessage);
996     receivedMessage = false;
997     TestWebKitAPI::Util::run(&done);
998     done = false;
999
1000     EXPECT_EQ(7u, [receivedMessages count]);
1001     EXPECT_TRUE([receivedMessages.get()[0] isEqualToString:@"pson1://host/main.html - pageshow NOT persisted" ]);
1002     EXPECT_TRUE([receivedMessages.get()[1] isEqualToString:@"pson1://host/main.html - pagehide persisted" ]);
1003     EXPECT_TRUE([receivedMessages.get()[2] isEqualToString:@"pson2://host/main.html - pageshow NOT persisted" ]);
1004     EXPECT_TRUE([receivedMessages.get()[3] isEqualToString:@"pson2://host/main.html - pagehide persisted" ]);
1005     EXPECT_TRUE([receivedMessages.get()[4] isEqualToString:@"pson1://host/main.html - pageshow persisted" ]);
1006     EXPECT_TRUE([receivedMessages.get()[5] isEqualToString:@"pson1://host/main.html - pagehide persisted" ]);
1007     EXPECT_TRUE([receivedMessages.get()[6] isEqualToString:@"pson2://host/main.html - pageshow persisted" ]);
1008 }
1009
1010 // Disabling the page cache explicitly is (for some reason) not available on iOS.
1011 #if !TARGET_OS_IPHONE
1012 static const char* loadUnloadBytes = R"PSONRESOURCE(
1013 <script>
1014 window.addEventListener('unload', function(event) {
1015     var msg = window.location.href + " - unload";
1016     window.webkit.messageHandlers.pson.postMessage(msg);
1017 });
1018
1019 window.addEventListener('load', function(event) {
1020     var msg = window.location.href + " - load";
1021     window.webkit.messageHandlers.pson.postMessage(msg);
1022 });
1023 </script>
1024 )PSONRESOURCE";
1025
1026 TEST(ProcessSwap, LoadUnload)
1027 {
1028     auto processPoolConfiguration = adoptNS([[_WKProcessPoolConfiguration alloc] init]);
1029     [processPoolConfiguration setProcessSwapsOnNavigation:YES];
1030     auto processPool = adoptNS([[WKProcessPool alloc] _initWithConfiguration:processPoolConfiguration.get()]);
1031
1032     auto webViewConfiguration = adoptNS([[WKWebViewConfiguration alloc] init]);
1033     [webViewConfiguration setProcessPool:processPool.get()];
1034     auto handler = adoptNS([[PSONScheme alloc] init]);
1035     [handler addMappingFromURLString:@"pson1://host/main.html" toData:loadUnloadBytes];
1036     [handler addMappingFromURLString:@"pson2://host/main.html" toData:loadUnloadBytes];
1037     [webViewConfiguration setURLSchemeHandler:handler.get() forURLScheme:@"PSON1"];
1038     [webViewConfiguration setURLSchemeHandler:handler.get() forURLScheme:@"PSON2"];
1039
1040     auto messageHandler = adoptNS([[PSONMessageHandler alloc] init]);
1041     [[webViewConfiguration userContentController] addScriptMessageHandler:messageHandler.get() name:@"pson"];
1042     [[webViewConfiguration preferences] _setUsesPageCache:NO];
1043
1044     auto webView = adoptNS([[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:webViewConfiguration.get()]);
1045     auto delegate = adoptNS([[PSONNavigationDelegate alloc] init]);
1046     [webView setNavigationDelegate:delegate.get()];
1047
1048     NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson1://host/main.html"]];
1049
1050     [webView loadRequest:request];
1051     TestWebKitAPI::Util::run(&receivedMessage);
1052     receivedMessage = false;
1053     TestWebKitAPI::Util::run(&done);
1054     done = false;
1055
1056     request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson2://host/main.html"]];
1057
1058     [webView loadRequest:request];
1059     TestWebKitAPI::Util::run(&receivedMessage);
1060     receivedMessage = false;
1061     TestWebKitAPI::Util::run(&done);
1062     done = false;
1063
1064     [webView goBack];
1065     TestWebKitAPI::Util::run(&receivedMessage);
1066     receivedMessage = false;
1067     TestWebKitAPI::Util::run(&done);
1068     done = false;
1069
1070     [webView goForward];
1071     TestWebKitAPI::Util::run(&receivedMessage);
1072     receivedMessage = false;
1073     TestWebKitAPI::Util::run(&done);
1074     done = false;
1075
1076     EXPECT_EQ(7u, [receivedMessages count]);
1077     EXPECT_TRUE([receivedMessages.get()[0] isEqualToString:@"pson1://host/main.html - load" ]);
1078     EXPECT_TRUE([receivedMessages.get()[1] isEqualToString:@"pson1://host/main.html - unload" ]);
1079     EXPECT_TRUE([receivedMessages.get()[2] isEqualToString:@"pson2://host/main.html - load" ]);
1080     EXPECT_TRUE([receivedMessages.get()[3] isEqualToString:@"pson2://host/main.html - unload" ]);
1081     EXPECT_TRUE([receivedMessages.get()[4] isEqualToString:@"pson1://host/main.html - load" ]);
1082     EXPECT_TRUE([receivedMessages.get()[5] isEqualToString:@"pson1://host/main.html - unload" ]);
1083     EXPECT_TRUE([receivedMessages.get()[6] isEqualToString:@"pson2://host/main.html - load" ]);
1084 }
1085
1086 TEST(ProcessSwap, DisableForInspector)
1087 {
1088     auto processPoolConfiguration = adoptNS([[_WKProcessPoolConfiguration alloc] init]);
1089     processPoolConfiguration.get().processSwapsOnNavigation = YES;
1090     auto processPool = adoptNS([[WKProcessPool alloc] _initWithConfiguration:processPoolConfiguration.get()]);
1091
1092     auto webViewConfiguration = adoptNS([[WKWebViewConfiguration alloc] init]);
1093     [webViewConfiguration setProcessPool:processPool.get()];
1094     webViewConfiguration.get().preferences._developerExtrasEnabled = YES;
1095
1096     RetainPtr<PSONScheme> handler = adoptNS([[PSONScheme alloc] init]);
1097     [webViewConfiguration setURLSchemeHandler:handler.get() forURLScheme:@"PSON1"];
1098     [webViewConfiguration setURLSchemeHandler:handler.get() forURLScheme:@"PSON2"];
1099
1100     auto webView = adoptNS([[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:webViewConfiguration.get()]);
1101     auto delegate = adoptNS([[PSONNavigationDelegate alloc] init]);
1102     [webView setNavigationDelegate:delegate.get()];
1103
1104     NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson1://host/main1.html"]];
1105     [webView loadRequest:request];
1106
1107     TestWebKitAPI::Util::run(&done);
1108     done = false;
1109
1110     auto pid1 = [webView _webProcessIdentifier];
1111
1112     // FIXME: use ObjC equivalent for WKInspectorRef when available.
1113     WKInspectorShow(WKPageGetInspector([webView _pageRefForTransitionToWKWebView]));
1114
1115     request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson2://host/main2.html"]];
1116     [webView loadRequest:request];
1117
1118     TestWebKitAPI::Util::run(&done);
1119     done = false;
1120
1121     auto pid2 = [webView _webProcessIdentifier];
1122
1123     WKInspectorClose(WKPageGetInspector([webView _pageRefForTransitionToWKWebView]));
1124
1125     request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson1://host/main2.html"]];
1126     [webView loadRequest:request];
1127
1128     TestWebKitAPI::Util::run(&done);
1129     done = false;
1130
1131     auto pid3 = [webView _webProcessIdentifier];
1132
1133     EXPECT_EQ(pid1, pid2);
1134     EXPECT_FALSE(pid2 == pid3);
1135     EXPECT_EQ(numberOfDecidePolicyCalls, 3);
1136 }
1137
1138 #endif // !TARGET_OS_IPHONE
1139
1140 static const char* sameOriginBlobNavigationTestBytes = R"PSONRESOURCE(
1141 <!DOCTYPE html>
1142 <html>
1143 <body>
1144 <p><a id="link">Click here</a></p>
1145 <script>
1146 const blob = new Blob(['<!DOCTYPE html><html><p>PASS</p></html>'], {type: 'text/html'});
1147 link.href = URL.createObjectURL(blob);
1148 </script>
1149 )PSONRESOURCE";
1150
1151 TEST(ProcessSwap, SameOriginBlobNavigation)
1152 {
1153     auto processPoolConfiguration = adoptNS([[_WKProcessPoolConfiguration alloc] init]);
1154     processPoolConfiguration.get().processSwapsOnNavigation = YES;
1155     auto processPool = adoptNS([[WKProcessPool alloc] _initWithConfiguration:processPoolConfiguration.get()]);
1156
1157     auto webViewConfiguration = adoptNS([[WKWebViewConfiguration alloc] init]);
1158     [webViewConfiguration setProcessPool:processPool.get()];
1159     RetainPtr<PSONScheme> handler = adoptNS([[PSONScheme alloc] initWithBytes:sameOriginBlobNavigationTestBytes]);
1160     [webViewConfiguration setURLSchemeHandler:handler.get() forURLScheme:@"PSON"];
1161
1162     auto webView = adoptNS([[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:webViewConfiguration.get()]);
1163     auto navigationDelegate = adoptNS([[PSONNavigationDelegate alloc] init]);
1164     [webView setNavigationDelegate:navigationDelegate.get()];
1165     auto uiDelegate = adoptNS([[PSONUIDelegate alloc] initWithNavigationDelegate:navigationDelegate.get()]);
1166     [webView setUIDelegate:uiDelegate.get()];
1167
1168     numberOfDecidePolicyCalls = 0;
1169     [webView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://host/main1.html"]]];
1170
1171     TestWebKitAPI::Util::run(&done);
1172     done = false;
1173     auto pid1 = [webView _webProcessIdentifier];
1174     EXPECT_TRUE(!!pid1);
1175
1176     [webView _evaluateJavaScriptWithoutUserGesture:@"document.getElementById('link').click()" completionHandler: nil];
1177
1178     TestWebKitAPI::Util::run(&done);
1179     done = false;
1180     auto pid2 = [webView _webProcessIdentifier];
1181     EXPECT_TRUE(!!pid2);
1182     EXPECT_EQ(2, numberOfDecidePolicyCalls);
1183     EXPECT_EQ(pid1, pid2);
1184 }
1185
1186 TEST(ProcessSwap, CrossOriginBlobNavigation)
1187 {
1188     auto processPoolConfiguration = adoptNS([[_WKProcessPoolConfiguration alloc] init]);
1189     processPoolConfiguration.get().processSwapsOnNavigation = YES;
1190     auto processPool = adoptNS([[WKProcessPool alloc] _initWithConfiguration:processPoolConfiguration.get()]);
1191
1192     auto webViewConfiguration = adoptNS([[WKWebViewConfiguration alloc] init]);
1193     [webViewConfiguration setProcessPool:processPool.get()];
1194     RetainPtr<PSONScheme> handler = adoptNS([[PSONScheme alloc] initWithBytes:sameOriginBlobNavigationTestBytes]);
1195     [webViewConfiguration setURLSchemeHandler:handler.get() forURLScheme:@"PSON1"];
1196     [webViewConfiguration setURLSchemeHandler:handler.get() forURLScheme:@"PSON2"];
1197
1198     auto webView = adoptNS([[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:webViewConfiguration.get()]);
1199     auto navigationDelegate = adoptNS([[PSONNavigationDelegate alloc] init]);
1200     [webView setNavigationDelegate:navigationDelegate.get()];
1201     auto uiDelegate = adoptNS([[PSONUIDelegate alloc] initWithNavigationDelegate:navigationDelegate.get()]);
1202     [webView setUIDelegate:uiDelegate.get()];
1203
1204     numberOfDecidePolicyCalls = 0;
1205     [webView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:@"pson1://host/main1.html"]]];
1206     TestWebKitAPI::Util::run(&done);
1207     done = false;
1208     auto pid1 = [webView _webProcessIdentifier];
1209     EXPECT_TRUE(!!pid1);
1210
1211     bool finishedRunningScript = false;
1212     String blobURL;
1213     [webView _evaluateJavaScriptWithoutUserGesture:@"document.getElementById('link').href" completionHandler: [&] (id result, NSError *error) {
1214         blobURL = String([NSString stringWithFormat:@"%@", result]);
1215         finishedRunningScript = true;
1216     }];
1217     TestWebKitAPI::Util::run(&finishedRunningScript);
1218
1219     [webView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:@"pson2://host/main1.html"]]];
1220     TestWebKitAPI::Util::run(&done);
1221     done = false;
1222     auto pid2 = [webView _webProcessIdentifier];
1223     EXPECT_TRUE(!!pid2);
1224
1225     finishedRunningScript = false;
1226     String script = "document.getElementById('link').href = '" + blobURL + "'";
1227     [webView _evaluateJavaScriptWithoutUserGesture:(NSString *)script completionHandler: [&] (id result, NSError *error) {
1228         finishedRunningScript = true;
1229     }];
1230     TestWebKitAPI::Util::run(&finishedRunningScript);
1231
1232     // This navigation will fail.
1233     [webView _evaluateJavaScriptWithoutUserGesture:@"document.getElementById('link').click()" completionHandler: [&] (id result, NSError *error) {
1234         done = true;
1235     }];
1236     TestWebKitAPI::Util::run(&done);
1237     done = false;
1238     auto pid3 = [webView _webProcessIdentifier];
1239     EXPECT_TRUE(!!pid3);
1240
1241     EXPECT_EQ(2, numberOfDecidePolicyCalls);
1242     EXPECT_NE(pid1, pid2);
1243     EXPECT_EQ(pid2, pid3);
1244 }
1245
1246 TEST(ProcessSwap, NavigateToAboutBlank)
1247 {
1248     auto processPoolConfiguration = adoptNS([[_WKProcessPoolConfiguration alloc] init]);
1249     processPoolConfiguration.get().processSwapsOnNavigation = YES;
1250     auto processPool = adoptNS([[WKProcessPool alloc] _initWithConfiguration:processPoolConfiguration.get()]);
1251
1252     auto webViewConfiguration = adoptNS([[WKWebViewConfiguration alloc] init]);
1253     [webViewConfiguration setProcessPool:processPool.get()];
1254     RetainPtr<PSONScheme> handler = adoptNS([[PSONScheme alloc] initWithBytes:sameOriginBlobNavigationTestBytes]);
1255     [webViewConfiguration setURLSchemeHandler:handler.get() forURLScheme:@"PSON"];
1256
1257     auto webView = adoptNS([[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:webViewConfiguration.get()]);
1258     auto navigationDelegate = adoptNS([[PSONNavigationDelegate alloc] init]);
1259     [webView setNavigationDelegate:navigationDelegate.get()];
1260     auto uiDelegate = adoptNS([[PSONUIDelegate alloc] initWithNavigationDelegate:navigationDelegate.get()]);
1261     [webView setUIDelegate:uiDelegate.get()];
1262
1263     numberOfDecidePolicyCalls = 0;
1264     [webView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://host/main1.html"]]];
1265     TestWebKitAPI::Util::run(&done);
1266     done = false;
1267     auto pid1 = [webView _webProcessIdentifier];
1268     EXPECT_TRUE(!!pid1);
1269
1270     [webView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:@"about:blank"]]];
1271     TestWebKitAPI::Util::run(&done);
1272     done = false;
1273     auto pid2 = [webView _webProcessIdentifier];
1274     EXPECT_TRUE(!!pid2);
1275
1276     EXPECT_EQ(2, numberOfDecidePolicyCalls);
1277     EXPECT_EQ(pid1, pid2);
1278 }
1279
1280 TEST(ProcessSwap, NavigateToDataURL)
1281 {
1282     auto processPoolConfiguration = adoptNS([[_WKProcessPoolConfiguration alloc] init]);
1283     processPoolConfiguration.get().processSwapsOnNavigation = YES;
1284     auto processPool = adoptNS([[WKProcessPool alloc] _initWithConfiguration:processPoolConfiguration.get()]);
1285
1286     auto webViewConfiguration = adoptNS([[WKWebViewConfiguration alloc] init]);
1287     [webViewConfiguration setProcessPool:processPool.get()];
1288     RetainPtr<PSONScheme> handler = adoptNS([[PSONScheme alloc] initWithBytes:sameOriginBlobNavigationTestBytes]);
1289     [webViewConfiguration setURLSchemeHandler:handler.get() forURLScheme:@"PSON"];
1290
1291     auto webView = adoptNS([[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:webViewConfiguration.get()]);
1292     auto navigationDelegate = adoptNS([[PSONNavigationDelegate alloc] init]);
1293     [webView setNavigationDelegate:navigationDelegate.get()];
1294     auto uiDelegate = adoptNS([[PSONUIDelegate alloc] initWithNavigationDelegate:navigationDelegate.get()]);
1295     [webView setUIDelegate:uiDelegate.get()];
1296
1297     numberOfDecidePolicyCalls = 0;
1298     [webView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://host/main1.html"]]];
1299     TestWebKitAPI::Util::run(&done);
1300     done = false;
1301     auto pid1 = [webView _webProcessIdentifier];
1302     EXPECT_TRUE(!!pid1);
1303
1304     [webView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:@"data:text/plain,PASS"]]];
1305     TestWebKitAPI::Util::run(&done);
1306     done = false;
1307     auto pid2 = [webView _webProcessIdentifier];
1308     EXPECT_TRUE(!!pid2);
1309
1310     EXPECT_EQ(2, numberOfDecidePolicyCalls);
1311     EXPECT_EQ(pid1, pid2);
1312 }
1313
1314 TEST(ProcessSwap, ProcessReuse)
1315 {
1316     auto processPoolConfiguration = adoptNS([[_WKProcessPoolConfiguration alloc] init]);
1317     [processPoolConfiguration setProcessSwapsOnNavigation:YES];
1318     [processPoolConfiguration setAlwaysKeepAndReuseSwappedProcesses:YES];
1319     auto processPool = adoptNS([[WKProcessPool alloc] _initWithConfiguration:processPoolConfiguration.get()]);
1320
1321     auto webViewConfiguration = adoptNS([[WKWebViewConfiguration alloc] init]);
1322     [webViewConfiguration setProcessPool:processPool.get()];
1323     auto handler = adoptNS([[PSONScheme alloc] init]);
1324     [webViewConfiguration setURLSchemeHandler:handler.get() forURLScheme:@"PSON"];
1325
1326     auto webView = adoptNS([[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:webViewConfiguration.get()]);
1327     auto delegate = adoptNS([[PSONNavigationDelegate alloc] init]);
1328     [webView setNavigationDelegate:delegate.get()];
1329
1330     NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://host1/main.html"]];
1331     [webView loadRequest:request];
1332
1333     TestWebKitAPI::Util::run(&done);
1334     done = false;
1335
1336     auto pid1 = [webView _webProcessIdentifier];
1337
1338     request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://host2/main.html"]];
1339     [webView loadRequest:request];
1340
1341     TestWebKitAPI::Util::run(&done);
1342     done = false;
1343
1344     auto pid2 = [webView _webProcessIdentifier];
1345
1346     request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://host1/main2.html"]];
1347     [webView loadRequest:request];
1348
1349     TestWebKitAPI::Util::run(&done);
1350     done = false;
1351
1352     auto pid3 = [webView _webProcessIdentifier];
1353
1354     // Two process swaps have occurred, but we should only have ever seen 2 pids.
1355     EXPECT_EQ(2u, seenPIDs.size());
1356     EXPECT_NE(pid1, pid2);
1357     EXPECT_NE(pid2, pid3);
1358     EXPECT_EQ(pid1, pid3);
1359 }
1360
1361 static const char* navigateToInvalidURLTestBytes = R"PSONRESOURCE(
1362 <!DOCTYPE html>
1363 <html>
1364 <body onload="setTimeout(() => alert('DONE'), 0); location.href = 'http://A=a%B=b'">
1365 )PSONRESOURCE";
1366
1367 TEST(ProcessSwap, NavigateToInvalidURL)
1368 {
1369     auto processPoolConfiguration = adoptNS([[_WKProcessPoolConfiguration alloc] init]);
1370     processPoolConfiguration.get().processSwapsOnNavigation = YES;
1371     auto processPool = adoptNS([[WKProcessPool alloc] _initWithConfiguration:processPoolConfiguration.get()]);
1372
1373     auto webViewConfiguration = adoptNS([[WKWebViewConfiguration alloc] init]);
1374     [webViewConfiguration setProcessPool:processPool.get()];
1375     RetainPtr<PSONScheme> handler = adoptNS([[PSONScheme alloc] initWithBytes:navigateToInvalidURLTestBytes]);
1376     [webViewConfiguration setURLSchemeHandler:handler.get() forURLScheme:@"PSON"];
1377
1378     auto webView = adoptNS([[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:webViewConfiguration.get()]);
1379     auto navigationDelegate = adoptNS([[PSONNavigationDelegate alloc] init]);
1380     [webView setNavigationDelegate:navigationDelegate.get()];
1381     auto uiDelegate = adoptNS([[PSONUIDelegate alloc] initWithNavigationDelegate:navigationDelegate.get()]);
1382     [webView setUIDelegate:uiDelegate.get()];
1383
1384     numberOfDecidePolicyCalls = 0;
1385     [webView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://host/main1.html"]]];
1386     TestWebKitAPI::Util::run(&done);
1387     done = false;
1388     auto pid1 = [webView _webProcessIdentifier];
1389     EXPECT_TRUE(!!pid1);
1390
1391     TestWebKitAPI::Util::run(&didReceiveAlert);
1392     didReceiveAlert = false;
1393     auto pid2 = [webView _webProcessIdentifier];
1394     EXPECT_TRUE(!!pid2);
1395
1396     EXPECT_EQ(2, numberOfDecidePolicyCalls);
1397     EXPECT_EQ(pid1, pid2);
1398 }
1399
1400 static const char* navigateToDataURLThenBackBytes = R"PSONRESOURCE(
1401 <script>
1402 onpageshow = function(event) {
1403     // Location changes need to happen outside the onload handler to generate history entries.
1404     setTimeout(function() {
1405       window.location.href = "data:text/html,<body onload='history.back()'></body>";
1406     }, 0);
1407 }
1408
1409 </script>
1410 )PSONRESOURCE";
1411
1412 TEST(ProcessSwap, NavigateToDataURLThenBack)
1413 {
1414     auto processPoolConfiguration = adoptNS([[_WKProcessPoolConfiguration alloc] init]);
1415     processPoolConfiguration.get().processSwapsOnNavigation = YES;
1416     processPoolConfiguration.get().pageCacheEnabled = NO;
1417     auto processPool = adoptNS([[WKProcessPool alloc] _initWithConfiguration:processPoolConfiguration.get()]);
1418
1419     auto webViewConfiguration = adoptNS([[WKWebViewConfiguration alloc] init]);
1420     [webViewConfiguration setProcessPool:processPool.get()];
1421     RetainPtr<PSONScheme> handler = adoptNS([[PSONScheme alloc] initWithBytes:navigateToDataURLThenBackBytes]);
1422     [webViewConfiguration setURLSchemeHandler:handler.get() forURLScheme:@"PSON"];
1423
1424     auto webView = adoptNS([[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:webViewConfiguration.get()]);
1425     auto navigationDelegate = adoptNS([[PSONNavigationDelegate alloc] init]);
1426     [webView setNavigationDelegate:navigationDelegate.get()];
1427
1428     numberOfDecidePolicyCalls = 0;
1429     [webView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://host/main1.html"]]];
1430     TestWebKitAPI::Util::run(&done);
1431     done = false;
1432     auto pid1 = [webView _webProcessIdentifier];
1433
1434     TestWebKitAPI::Util::run(&done);
1435     done = false;
1436     auto pid2 = [webView _webProcessIdentifier];
1437
1438     TestWebKitAPI::Util::run(&done);
1439     done = false;
1440     auto pid3 = [webView _webProcessIdentifier];
1441
1442     EXPECT_EQ(3, numberOfDecidePolicyCalls);
1443     EXPECT_EQ(1u, seenPIDs.size());
1444     EXPECT_EQ(pid1, pid2);
1445     EXPECT_EQ(pid2, pid3);
1446 }
1447
1448 TEST(ProcessSwap, APIControlledProcessSwapping)
1449 {
1450     auto webViewConfiguration = adoptNS([[WKWebViewConfiguration alloc] init]);
1451     RetainPtr<PSONScheme> handler = adoptNS([[PSONScheme alloc] initWithBytes:"Hello World!"]);
1452     [webViewConfiguration setURLSchemeHandler:handler.get() forURLScheme:@"PSON"];
1453
1454     auto webView = adoptNS([[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:webViewConfiguration.get()]);
1455     auto navigationDelegate = adoptNS([[PSONNavigationDelegate alloc] init]);
1456     [webView setNavigationDelegate:navigationDelegate.get()];
1457
1458     numberOfDecidePolicyCalls = 0;
1459     [webView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://host/1"]]];
1460     TestWebKitAPI::Util::run(&done);
1461     done = false;
1462     auto pid1 = [webView _webProcessIdentifier];
1463
1464     // Navigating from the above URL to this URL normally should not process swap.
1465     [webView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://host/2"]]];
1466     TestWebKitAPI::Util::run(&done);
1467     done = false;
1468     auto pid2 = [webView _webProcessIdentifier];
1469
1470     EXPECT_EQ(1u, seenPIDs.size());
1471     EXPECT_EQ(pid1, pid2);
1472
1473     // Navigating from the above URL to this URL normally should not process swap,
1474     // but we'll explicitly ask for a swap.
1475     navigationDelegate->navigationActionPolicyToUse = _WKNavigationActionPolicyAllowInNewProcess;
1476     [webView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://host/3"]]];
1477     TestWebKitAPI::Util::run(&done);
1478     done = false;
1479     auto pid3 = [webView _webProcessIdentifier];
1480
1481     EXPECT_EQ(3, numberOfDecidePolicyCalls);
1482     EXPECT_EQ(2u, seenPIDs.size());
1483     EXPECT_NE(pid1, pid3);
1484 }
1485
1486 #endif // WK_API_ENABLED