Diff
Modified: trunk/Source/WebCore/ChangeLog (231703 => 231704)
--- trunk/Source/WebCore/ChangeLog 2018-05-11 16:08:42 UTC (rev 231703)
+++ trunk/Source/WebCore/ChangeLog 2018-05-11 16:12:11 UTC (rev 231704)
@@ -1,3 +1,29 @@
+2018-05-11 Brady Eidson <[email protected]>
+
+ Make sure history navigations reuse the existing process when necessary.
+ <rdar://problem/39746516> and https://bugs.webkit.org/show_bug.cgi?id=185532
+
+ Reviewed by Ryosuke Niwa.
+
+ Covered by new API tests.
+
+ In WebCore-land, make sure *all* NavigationActions to a back/forward item are tagged with
+ the item identifier.
+
+ * history/HistoryItem.cpp:
+ (WebCore::HistoryItem::HistoryItem):
+ (WebCore::HistoryItem::logString const):
+ * history/HistoryItem.h:
+
+ * loader/FrameLoader.cpp:
+ (WebCore::FrameLoader::loadDifferentDocumentItem):
+
+ * loader/NavigationAction.cpp:
+ (WebCore::NavigationAction::setTargetBackForwardItem):
+
+ * loader/NavigationAction.h:
+ (WebCore::NavigationAction::targetBackForwardItemIdentifier const):
+
2018-05-11 Yacine Bandou <[email protected]>
[EME][GStreamer] Handle the protection event in MediaPlayerPrivate
Modified: trunk/Source/WebCore/history/HistoryItem.cpp (231703 => 231704)
--- trunk/Source/WebCore/history/HistoryItem.cpp 2018-05-11 16:08:42 UTC (rev 231703)
+++ trunk/Source/WebCore/history/HistoryItem.cpp 2018-05-11 16:12:11 UTC (rev 231704)
@@ -35,6 +35,7 @@
#include "SharedBuffer.h"
#include <stdio.h>
#include <wtf/DateMath.h>
+#include <wtf/DebugUtilities.h>
#include <wtf/WallTime.h>
#include <wtf/text/CString.h>
@@ -105,6 +106,7 @@
, m_scale(item.m_scale)
, m_scaleIsInitial(item.m_scaleIsInitial)
#endif
+ , m_identifier(item.m_identifier)
{
if (item.m_formData)
m_formData = item.m_formData->copy();
@@ -489,7 +491,14 @@
}
#endif
-
+
+#if !LOG_DISABLED
+const char* HistoryItem::logString() const
+{
+ return debugString("HistoryItem current URL ", urlString(), ", identifier ", m_identifier.logString());
+}
+#endif
+
} // namespace WebCore
#ifndef NDEBUG
Modified: trunk/Source/WebCore/history/HistoryItem.h (231703 => 231704)
--- trunk/Source/WebCore/history/HistoryItem.h 2018-05-11 16:08:42 UTC (rev 231703)
+++ trunk/Source/WebCore/history/HistoryItem.h 2018-05-11 16:12:11 UTC (rev 231704)
@@ -215,6 +215,10 @@
void setWasRestoredFromSession(bool wasRestoredFromSession) { m_wasRestoredFromSession = wasRestoredFromSession; }
bool wasRestoredFromSession() const { return m_wasRestoredFromSession; }
+#if !LOG_DISABLED
+ const char* logString() const;
+#endif
+
private:
WEBCORE_EXPORT HistoryItem();
WEBCORE_EXPORT HistoryItem(const String& urlString, const String& title);
Modified: trunk/Source/WebCore/loader/FrameLoader.cpp (231703 => 231704)
--- trunk/Source/WebCore/loader/FrameLoader.cpp 2018-05-11 16:08:42 UTC (rev 231703)
+++ trunk/Source/WebCore/loader/FrameLoader.cpp 2018-05-11 16:12:11 UTC (rev 231704)
@@ -3528,7 +3528,11 @@
if (CachedPage* cachedPage = PageCache::singleton().get(item, m_frame.page())) {
auto documentLoader = cachedPage->documentLoader();
m_client.updateCachedDocumentLoader(*documentLoader);
- documentLoader->setTriggeringAction({ *m_frame.document(), documentLoader->request(), initiatedByMainFrame, loadType, false });
+
+ auto action = "" { *m_frame.document(), documentLoader->request(), initiatedByMainFrame, loadType, false };
+ action.setTargetBackForwardItem(item);
+ documentLoader->setTriggeringAction(WTFMove(action));
+
documentLoader->setLastCheckedRequest(ResourceRequest());
loadWithDocumentLoader(documentLoader, loadType, 0, AllowNavigationToInvalidURL::Yes, navigationPolicyCheck, [] { });
return;
@@ -3616,6 +3620,8 @@
action = { *m_frame.document(), requestForOriginalURL, initiatedByMainFrame, loadType, isFormSubmission, event, shouldOpenExternalURLsPolicy };
}
+ action.setTargetBackForwardItem(item);
+
loadWithNavigationAction(request, action, LockHistory::No, loadType, 0, AllowNavigationToInvalidURL::Yes, [] { });
}
Modified: trunk/Source/WebCore/loader/NavigationAction.cpp (231703 => 231704)
--- trunk/Source/WebCore/loader/NavigationAction.cpp 2018-05-11 16:08:42 UTC (rev 231703)
+++ trunk/Source/WebCore/loader/NavigationAction.cpp 2018-05-11 16:12:11 UTC (rev 231704)
@@ -32,6 +32,7 @@
#include "Document.h"
#include "Event.h"
#include "FrameLoader.h"
+#include "HistoryItem.h"
namespace WebCore {
@@ -95,4 +96,9 @@
return result;
}
+void NavigationAction::setTargetBackForwardItem(HistoryItem& item)
+{
+ m_targetBackForwardItemIdentifier = item.identifier();
}
+
+}
Modified: trunk/Source/WebCore/loader/NavigationAction.h (231703 => 231704)
--- trunk/Source/WebCore/loader/NavigationAction.h 2018-05-11 16:08:42 UTC (rev 231703)
+++ trunk/Source/WebCore/loader/NavigationAction.h 2018-05-11 16:12:11 UTC (rev 231704)
@@ -28,6 +28,7 @@
#pragma once
+#include "BackForwardItemIdentifier.h"
#include "FrameLoaderTypes.h"
#include "ResourceRequest.h"
#include "UserGestureIndicator.h"
@@ -37,6 +38,7 @@
class Document;
class Event;
+class HistoryItem;
class NavigationAction {
public:
@@ -80,6 +82,9 @@
void setOpener(std::optional<std::pair<uint64_t, uint64_t>>&& opener) { m_opener = WTFMove(opener); }
const std::optional<std::pair<uint64_t, uint64_t>>& opener() const { return m_opener; }
+ void setTargetBackForwardItem(HistoryItem&);
+ const std::optional<BackForwardItemIdentifier>& targetBackForwardItemIdentifier() const { return m_targetBackForwardItemIdentifier; }
+
private:
RefPtr<Document> m_sourceDocument;
ResourceRequest m_resourceRequest;
@@ -92,6 +97,7 @@
bool m_treatAsSameOriginNavigation;
bool m_isCrossOriginWindowOpenNavigation { false };
std::optional<std::pair<uint64_t /* pageID */, uint64_t /* frameID */>> m_opener;
+ std::optional<BackForwardItemIdentifier> m_targetBackForwardItemIdentifier;
};
} // namespace WebCore
Modified: trunk/Source/WebKit/ChangeLog (231703 => 231704)
--- trunk/Source/WebKit/ChangeLog 2018-05-11 16:08:42 UTC (rev 231703)
+++ trunk/Source/WebKit/ChangeLog 2018-05-11 16:12:11 UTC (rev 231704)
@@ -1,3 +1,38 @@
+2018-05-11 Brady Eidson <[email protected]>
+
+ Make sure history navigations reuse the existing process when necessary.
+ <rdar://problem/39746516> and https://bugs.webkit.org/show_bug.cgi?id=185532
+
+ Reviewed by Ryosuke Niwa.
+
+ If a view navigates to either a data: or blob: URL, it reuses the existing process.
+
+ In such cases we need to also ensure that history navigations back will also reuse the existing process.
+
+ * Shared/NavigationActionData.cpp:
+ (WebKit::NavigationActionData::encode const):
+ (WebKit::NavigationActionData::decode):
+ * Shared/NavigationActionData.h:
+
+ * UIProcess/API/APINavigation.h:
+ (API::Navigation::setTargetItem):
+
+ * UIProcess/API/Cocoa/_WKProcessPoolConfiguration.h:
+ * UIProcess/API/Cocoa/_WKProcessPoolConfiguration.mm:
+ (-[_WKProcessPoolConfiguration pageCacheEnabled]):
+ (-[_WKProcessPoolConfiguration setPageCacheEnabled:]):
+
+ * UIProcess/WebPageProxy.cpp:
+ (WebKit::WebPageProxy::receivedPolicyDecision):
+ (WebKit::WebPageProxy::decidePolicyForNavigationAction):
+
+ * UIProcess/WebProcessPool.cpp:
+ (WebKit::WebProcessPool::processForNavigationInternal): If the current and target back/forward items both
+ came from the same process, then reuse the existing process.
+
+ * WebProcess/WebCoreSupport/WebFrameLoaderClient.cpp:
+ (WebKit::WebFrameLoaderClient::dispatchDecidePolicyForNavigationAction):
+
2018-05-10 Brent Fulgham <[email protected]>
REGRESSION(r231057): Encrypted media content playback failures
Modified: trunk/Source/WebKit/Shared/NavigationActionData.cpp (231703 => 231704)
--- trunk/Source/WebKit/Shared/NavigationActionData.cpp 2018-05-11 16:08:42 UTC (rev 231703)
+++ trunk/Source/WebKit/Shared/NavigationActionData.cpp 2018-05-11 16:12:11 UTC (rev 231704)
@@ -50,6 +50,7 @@
encoder << treatAsSameOriginNavigation;
encoder << isCrossOriginWindowOpenNavigation;
encoder << opener;
+ encoder << targetBackForwardItemIdentifier;
}
std::optional<NavigationActionData> NavigationActionData::decode(IPC::Decoder& decoder)
@@ -113,9 +114,14 @@
if (!opener)
return std::nullopt;
+ std::optional<std::optional<BackForwardItemIdentifier>> targetBackForwardItemIdentifier;
+ decoder >> targetBackForwardItemIdentifier;
+ if (!targetBackForwardItemIdentifier)
+ return std::nullopt;
+
return {{ WTFMove(navigationType), WTFMove(modifiers), WTFMove(mouseButton), WTFMove(syntheticClickType), WTFMove(*userGestureTokenIdentifier),
WTFMove(*canHandleRequest), WTFMove(shouldOpenExternalURLsPolicy), WTFMove(*downloadAttribute), WTFMove(clickLocationInRootViewCoordinates),
- WTFMove(*isRedirect), *treatAsSameOriginNavigation, *isCrossOriginWindowOpenNavigation, WTFMove(*opener) }};
+ WTFMove(*isRedirect), *treatAsSameOriginNavigation, *isCrossOriginWindowOpenNavigation, WTFMove(*opener), WTFMove(*targetBackForwardItemIdentifier) }};
}
} // namespace WebKit
Modified: trunk/Source/WebKit/Shared/NavigationActionData.h (231703 => 231704)
--- trunk/Source/WebKit/Shared/NavigationActionData.h 2018-05-11 16:08:42 UTC (rev 231703)
+++ trunk/Source/WebKit/Shared/NavigationActionData.h 2018-05-11 16:12:11 UTC (rev 231704)
@@ -26,6 +26,7 @@
#pragma once
#include "WebEvent.h"
+#include <WebCore/BackForwardItemIdentifier.h>
#include <WebCore/FloatPoint.h>
#include <WebCore/FrameLoaderTypes.h>
@@ -53,6 +54,7 @@
bool treatAsSameOriginNavigation { false };
bool isCrossOriginWindowOpenNavigation { false };
std::optional<std::pair<uint64_t, uint64_t>> opener;
+ std::optional<WebCore::BackForwardItemIdentifier> targetBackForwardItemIdentifier;
};
}
Modified: trunk/Source/WebKit/UIProcess/API/APINavigation.h (231703 => 231704)
--- trunk/Source/WebKit/UIProcess/API/APINavigation.h 2018-05-11 16:08:42 UTC (rev 231703)
+++ trunk/Source/WebKit/UIProcess/API/APINavigation.h 2018-05-11 16:12:11 UTC (rev 231704)
@@ -26,6 +26,7 @@
#pragma once
#include "APIObject.h"
+#include "WebBackForwardListItem.h"
#include <WebCore/Process.h>
#include <WebCore/ResourceRequest.h>
#include <wtf/Ref.h>
@@ -35,7 +36,6 @@
}
namespace WebKit {
-class WebBackForwardListItem;
class WebNavigationState;
}
@@ -71,6 +71,7 @@
void setCurrentRequestIsRedirect(bool isRedirect) { m_isRedirect = isRedirect; }
bool currentRequestIsRedirect() const { return m_isRedirect; }
+ void setTargetItem(WebKit::WebBackForwardListItem& item) { m_targetItem = &item; }
WebKit::WebBackForwardListItem* targetItem() const { return m_targetItem.get(); }
WebKit::WebBackForwardListItem* fromItem() const { return m_fromItem.get(); }
std::optional<WebCore::FrameLoadType> backForwardFrameLoadType() const { return m_backForwardFrameLoadType; }
Modified: trunk/Source/WebKit/UIProcess/API/Cocoa/_WKProcessPoolConfiguration.h (231703 => 231704)
--- trunk/Source/WebKit/UIProcess/API/Cocoa/_WKProcessPoolConfiguration.h 2018-05-11 16:08:42 UTC (rev 231703)
+++ trunk/Source/WebKit/UIProcess/API/Cocoa/_WKProcessPoolConfiguration.h 2018-05-11 16:12:11 UTC (rev 231704)
@@ -61,6 +61,7 @@
@property (nonatomic) BOOL alwaysKeepAndReuseSwappedProcesses WK_API_AVAILABLE(macosx(WK_MAC_TBA), ios(WK_IOS_TBA));
@property (nonatomic) BOOL processSwapsOnWindowOpenWithOpener WK_API_AVAILABLE(macosx(WK_MAC_TBA), ios(WK_IOS_TBA));
@property (nonatomic) BOOL trackNetworkActivity WK_API_AVAILABLE(macosx(WK_MAC_TBA), ios(WK_IOS_TBA));
+@property (nonatomic) BOOL pageCacheEnabled WK_API_AVAILABLE(macosx(WK_MAC_TBA), ios(WK_IOS_TBA));
@end
Modified: trunk/Source/WebKit/UIProcess/API/Cocoa/_WKProcessPoolConfiguration.mm (231703 => 231704)
--- trunk/Source/WebKit/UIProcess/API/Cocoa/_WKProcessPoolConfiguration.mm 2018-05-11 16:08:42 UTC (rev 231703)
+++ trunk/Source/WebKit/UIProcess/API/Cocoa/_WKProcessPoolConfiguration.mm 2018-05-11 16:12:11 UTC (rev 231704)
@@ -267,6 +267,19 @@
_processPoolConfiguration->setTrackNetworkActivity(track);
}
+- (BOOL)pageCacheEnabled
+{
+ return _processPoolConfiguration->cacheModel() != WebKit::CacheModelDocumentViewer;
+}
+
+- (void)setPageCacheEnabled:(BOOL)enabled
+{
+ if (!enabled)
+ _processPoolConfiguration->setCacheModel(WebKit::CacheModelDocumentViewer);
+ else if (![self pageCacheEnabled])
+ _processPoolConfiguration->setCacheModel(WebKit::CacheModelPrimaryWebBrowser);
+}
+
#if PLATFORM(IOS)
- (NSString *)CTDataConnectionServiceType
{
Modified: trunk/Source/WebKit/UIProcess/WebPageProxy.cpp (231703 => 231704)
--- trunk/Source/WebKit/UIProcess/WebPageProxy.cpp 2018-05-11 16:08:42 UTC (rev 231703)
+++ trunk/Source/WebKit/UIProcess/WebPageProxy.cpp 2018-05-11 16:12:11 UTC (rev 231704)
@@ -2423,7 +2423,7 @@
auto proposedProcess = process().processPool().processForNavigation(*this, *navigation, action);
if (proposedProcess.ptr() != &process()) {
- LOG(ProcessSwapping, "Switching from process %i to new process for navigation %" PRIu64 " '%s'", processIdentifier(), navigation->navigationID(), navigation->loggingString());
+ LOG(ProcessSwapping, "(ProcessSwapping) Switching from process %i to new process (%i) for navigation %" PRIu64 " '%s'", processIdentifier(), proposedProcess->processIdentifier(), navigation->navigationID(), navigation->loggingString());
RunLoop::main().dispatch([this, protectedThis = makeRef(*this), navigation = makeRef(*navigation), proposedProcess = WTFMove(proposedProcess)]() mutable {
continueNavigationInNewProcess(navigation.get(), WTFMove(proposedProcess));
@@ -3964,9 +3964,23 @@
MESSAGE_CHECK(frame);
MESSAGE_CHECK_URL(request.url());
MESSAGE_CHECK_URL(originalRequest.url());
-
- Ref<API::Navigation> navigation = navigationID ? makeRef(m_navigationState->navigation(navigationID)) : m_navigationState->createLoadRequestNavigation(ResourceRequest(request), m_backForwardList->currentItem());
+ RefPtr<API::Navigation> navigation;
+ if (navigationID)
+ navigation = makeRef(m_navigationState->navigation(navigationID));
+
+ if (auto targetBackForwardItemIdentifier = navigationActionData.targetBackForwardItemIdentifier) {
+ if (auto* item = m_backForwardList->itemForID(*navigationActionData.targetBackForwardItemIdentifier)) {
+ if (!navigation)
+ navigation = m_navigationState->createBackForwardNavigation(*item, m_backForwardList->currentItem(), FrameLoadType::IndexedBackForward);
+ else
+ navigation->setTargetItem(*item);
+ }
+ }
+
+ if (!navigation)
+ navigation = m_navigationState->createLoadRequestNavigation(ResourceRequest(request), m_backForwardList->currentItem());
+
uint64_t newNavigationID = navigation->navigationID();
navigation->setWasUserInitiated(!!navigationActionData.userGestureTokenIdentifier);
navigation->setShouldForceDownload(!navigationActionData.downloadAttribute.isNull() || request.isSystemPreview());
@@ -3977,7 +3991,7 @@
navigation->setOpener(navigationActionData.opener);
auto listener = makeRef(frame->setUpPolicyListenerProxy(listenerID, PolicyListenerType::NavigationAction));
- listener->setNavigation(WTFMove(navigation));
+ listener->setNavigation(navigation.releaseNonNull());
#if ENABLE(CONTENT_FILTERING)
if (frame->didHandleContentFilterUnblockNavigation(request))
Modified: trunk/Source/WebKit/UIProcess/WebProcessPool.cpp (231703 => 231704)
--- trunk/Source/WebKit/UIProcess/WebProcessPool.cpp 2018-05-11 16:08:42 UTC (rev 231703)
+++ trunk/Source/WebKit/UIProcess/WebProcessPool.cpp 2018-05-11 16:12:11 UTC (rev 231704)
@@ -59,6 +59,8 @@
#include "UIGamepadProvider.h"
#include "WKContextPrivate.h"
#include "WebAutomationSession.h"
+#include "WebBackForwardList.h"
+#include "WebBackForwardListItem.h"
#include "WebCertificateInfo.h"
#include "WebContextSupplement.h"
#include "WebCookieManagerProxy.h"
@@ -2106,6 +2108,15 @@
action = ""
return *suspendedPage->process();
}
+
+ // If the target back/forward item and the current back/forward item originated
+ // in the same WebProcess then we should reuse the current WebProcess.
+ if (auto* currentItem = page.backForwardList().currentItem()) {
+ if (currentItem->itemID().processIdentifier == backForwardListItem->itemID().processIdentifier) {
+ action = ""
+ return page.process();
+ }
+ }
}
if (navigation.treatAsSameOriginNavigation())
Modified: trunk/Source/WebKit/WebProcess/WebCoreSupport/WebFrameLoaderClient.cpp (231703 => 231704)
--- trunk/Source/WebKit/WebProcess/WebCoreSupport/WebFrameLoaderClient.cpp 2018-05-11 16:08:42 UTC (rev 231703)
+++ trunk/Source/WebKit/WebProcess/WebCoreSupport/WebFrameLoaderClient.cpp 2018-05-11 16:12:11 UTC (rev 231704)
@@ -867,6 +867,7 @@
navigationActionData.treatAsSameOriginNavigation = navigationAction.treatAsSameOriginNavigation();
navigationActionData.isCrossOriginWindowOpenNavigation = navigationAction.isCrossOriginWindowOpenNavigation();
navigationActionData.opener = navigationAction.opener();
+ navigationActionData.targetBackForwardItemIdentifier = navigationAction.targetBackForwardItemIdentifier();
WebCore::Frame* coreFrame = m_frame->coreFrame();
if (!coreFrame)
Modified: trunk/Tools/ChangeLog (231703 => 231704)
--- trunk/Tools/ChangeLog 2018-05-11 16:08:42 UTC (rev 231703)
+++ trunk/Tools/ChangeLog 2018-05-11 16:12:11 UTC (rev 231704)
@@ -1,3 +1,12 @@
+2018-05-11 Brady Eidson <[email protected]>
+
+ Make sure history navigations reuse the existing process when necessary.
+ <rdar://problem/39746516> and https://bugs.webkit.org/show_bug.cgi?id=185532
+
+ Reviewed by Ryosuke Niwa.
+
+ * TestWebKitAPI/Tests/WebKitCocoa/ProcessSwapOnNavigation.mm:
+
2018-05-10 Carlos Garcia Campos <[email protected]>
[JSC][GLIB] Add introspectable alternatives to functions using vargars
Modified: trunk/Tools/TestWebKitAPI/Tests/WebKitCocoa/ProcessSwapOnNavigation.mm (231703 => 231704)
--- trunk/Tools/TestWebKitAPI/Tests/WebKitCocoa/ProcessSwapOnNavigation.mm 2018-05-11 16:08:42 UTC (rev 231703)
+++ trunk/Tools/TestWebKitAPI/Tests/WebKitCocoa/ProcessSwapOnNavigation.mm 2018-05-11 16:12:11 UTC (rev 231704)
@@ -54,6 +54,10 @@
#if WK_API_ENABLED
+@interface WKProcessPool ()
+- (WKContextRef)_contextForTesting;
+@end
+
static bool done;
static bool failed;
static bool didCreateWebView;
@@ -1382,4 +1386,52 @@
EXPECT_EQ(pid1, pid2);
}
+static const char* navigateToDataURLThenBackBytes = R"PSONRESOURCE(
+<script>
+_onpageshow_ = function(event) {
+ // Location changes need to happen outside the onload handler to generate history entries.
+ setTimeout(function() {
+ window.location.href = "" _onload_='history.back()'></body>";
+ }, 0);
+}
+
+</script>
+)PSONRESOURCE";
+
+TEST(ProcessSwap, NavigateToDataURLThenBack)
+{
+ auto processPoolConfiguration = adoptNS([[_WKProcessPoolConfiguration alloc] init]);
+ processPoolConfiguration.get().processSwapsOnNavigation = YES;
+ processPoolConfiguration.get().pageCacheEnabled = NO;
+ auto processPool = adoptNS([[WKProcessPool alloc] _initWithConfiguration:processPoolConfiguration.get()]);
+
+ auto webViewConfiguration = adoptNS([[WKWebViewConfiguration alloc] init]);
+ [webViewConfiguration setProcessPool:processPool.get()];
+ RetainPtr<PSONScheme> handler = adoptNS([[PSONScheme alloc] initWithBytes:navigateToDataURLThenBackBytes]);
+ [webViewConfiguration setURLSchemeHandler:handler.get() forURLScheme:@"PSON"];
+
+ auto webView = adoptNS([[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:webViewConfiguration.get()]);
+ auto navigationDelegate = adoptNS([[PSONNavigationDelegate alloc] init]);
+ [webView setNavigationDelegate:navigationDelegate.get()];
+
+ numberOfDecidePolicyCalls = 0;
+ [webView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://host/main1.html"]]];
+ TestWebKitAPI::Util::run(&done);
+ done = false;
+ auto pid1 = [webView _webProcessIdentifier];
+
+ TestWebKitAPI::Util::run(&done);
+ done = false;
+ auto pid2 = [webView _webProcessIdentifier];
+
+ TestWebKitAPI::Util::run(&done);
+ done = false;
+ auto pid3 = [webView _webProcessIdentifier];
+
+ EXPECT_EQ(3, numberOfDecidePolicyCalls);
+ EXPECT_EQ(1u, seenPIDs.size());
+ EXPECT_EQ(pid1, pid2);
+ EXPECT_EQ(pid2, pid3);
+}
+
#endif // WK_API_ENABLED