fix: log url for waitFor* methods (#1047)

This commit is contained in:
Yury Semikhatsky 2022-09-07 15:10:38 -07:00 committed by GitHub
parent 398c979378
commit 4a0ff6ef5c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 146 additions and 74 deletions

View File

@ -170,7 +170,7 @@ class BrowserContextImpl extends ChannelOwner implements BrowserContext {
@Override
public Page waitForPage(WaitForPageOptions options, Runnable code) {
return withWaitLogging("BrowserContext.close", () -> waitForPageImpl(options, code));
return withWaitLogging("BrowserContext.close", logger -> waitForPageImpl(options, code));
}
private Page waitForPageImpl(WaitForPageOptions options, Runnable code) {

View File

@ -22,6 +22,8 @@ import com.google.gson.JsonObject;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
import java.util.function.BinaryOperator;
import java.util.function.Function;
import java.util.function.Supplier;
class ChannelOwner extends LoggingSupport {
@ -74,7 +76,7 @@ class ChannelOwner extends LoggingSupport {
child.parent = this;
}
<T> T withWaitLogging(String apiName, Supplier<T> code) {
<T> T withWaitLogging(String apiName, Function<Logger, T> code) {
return new WaitForEventLogger<>(this, apiName, code).get();
}

View File

@ -811,17 +811,17 @@ public class FrameImpl extends ChannelOwner implements Frame {
@Override
public void waitForLoadState(LoadState state, WaitForLoadStateOptions options) {
withWaitLogging("Frame.waitForLoadState", () -> {
waitForLoadStateImpl(state, options);
withWaitLogging("Frame.waitForLoadState", logger -> {
waitForLoadStateImpl(state, options, logger);
return null;
});
}
void waitForLoadStateImpl(LoadState state, WaitForLoadStateOptions options) {
waitForLoadStateImpl(convertType(state, WaitUntilState.class), options);
void waitForLoadStateImpl(LoadState state, WaitForLoadStateOptions options, Logger logger) {
waitForLoadStateImpl(convertType(state, WaitUntilState.class), options, logger);
}
private void waitForLoadStateImpl(WaitUntilState state, WaitForLoadStateOptions options) {
private void waitForLoadStateImpl(WaitUntilState state, WaitForLoadStateOptions options, Logger logger) {
if (options == null) {
options = new WaitForLoadStateOptions();
}
@ -830,7 +830,7 @@ public class FrameImpl extends ChannelOwner implements Frame {
}
List<Waitable<Void>> waitables = new ArrayList<>();
waitables.add(new WaitForLoadStateHelper(state));
waitables.add(new WaitForLoadStateHelper(state, logger));
waitables.add(page.createWaitForCloseHelper());
waitables.add(page.createWaitableTimeout(options.timeout));
runUntil(() -> {}, new WaitableRace<>(waitables));
@ -838,10 +838,12 @@ public class FrameImpl extends ChannelOwner implements Frame {
private class WaitForLoadStateHelper implements Waitable<Void>, Consumer<WaitUntilState> {
private final WaitUntilState expectedState;
private final Logger logger;
private boolean isDone;
WaitForLoadStateHelper(WaitUntilState state) {
WaitForLoadStateHelper(WaitUntilState state, Logger logger) {
expectedState = state;
this.logger = logger;
isDone = loadStates.contains(state);
if (!isDone) {
internalListeners.add(InternalEventType.LOADSTATE, this);
@ -850,6 +852,7 @@ public class FrameImpl extends ChannelOwner implements Frame {
@Override
public void accept(WaitUntilState state) {
logger.log(" load state changed to " + state);
if (expectedState.equals(state)) {
isDone = true;
dispose();
@ -873,20 +876,24 @@ public class FrameImpl extends ChannelOwner implements Frame {
private class WaitForNavigationHelper implements Waitable<Response>, Consumer<JsonObject> {
private final UrlMatcher matcher;
private final WaitUntilState expectedLoadState;
private final Logger logger;
private WaitForLoadStateHelper loadStateHelper;
private RequestImpl request;
private RuntimeException exception;
WaitForNavigationHelper(UrlMatcher matcher, WaitUntilState expectedLoadState) {
WaitForNavigationHelper(UrlMatcher matcher, WaitUntilState expectedLoadState, Logger logger) {
this.matcher = matcher;
this.expectedLoadState = expectedLoadState;
this.logger = logger;
internalListeners.add(InternalEventType.NAVIGATED, this);
}
@Override
public void accept(JsonObject params) {
if (!matcher.test(params.get("url").getAsString())) {
String url = params.get("url").getAsString();
logger.log(" navigated to " + url);
if (!matcher.test(url)) {
return;
}
if (params.has("error")) {
@ -898,7 +905,7 @@ public class FrameImpl extends ChannelOwner implements Frame {
request = connection.getExistingObject(jsonReq.get("guid").getAsString());
}
}
loadStateHelper = new WaitForLoadStateHelper(expectedLoadState);
loadStateHelper = new WaitForLoadStateHelper(expectedLoadState, logger);
}
internalListeners.remove(InternalEventType.NAVIGATED, this);
}
@ -937,14 +944,14 @@ public class FrameImpl extends ChannelOwner implements Frame {
@Override
public Response waitForNavigation(WaitForNavigationOptions options, Runnable code) {
return withLogging("Frame.waitForNavigation", () -> waitForNavigationImpl(code, options, null));
return withWaitLogging("Frame.waitForNavigation", logger -> waitForNavigationImpl(logger, code, options, null));
}
Response waitForNavigationImpl(Runnable code, WaitForNavigationOptions options) {
return waitForNavigationImpl(code, options, null);
Response waitForNavigationImpl(Logger logger, Runnable code, WaitForNavigationOptions options) {
return waitForNavigationImpl(logger, code, options, null);
}
private Response waitForNavigationImpl(Runnable code, WaitForNavigationOptions options, UrlMatcher matcher) {
private Response waitForNavigationImpl(Logger logger, Runnable code, WaitForNavigationOptions options, UrlMatcher matcher) {
if (options == null) {
options = new WaitForNavigationOptions();
}
@ -956,7 +963,8 @@ public class FrameImpl extends ChannelOwner implements Frame {
if (matcher == null) {
matcher = UrlMatcher.forOneOf(page.context().baseUrl, options.url);
}
waitables.add(new WaitForNavigationHelper(matcher, options.waitUntil));
logger.log("waiting for navigation " + matcher);
waitables.add(new WaitForNavigationHelper(matcher, options.waitUntil, logger));
waitables.add(page.createWaitForCloseHelper());
waitables.add(page.createWaitableFrameDetach(this));
waitables.add(page.createWaitableNavigationTimeout(options.timeout));
@ -1014,18 +1022,22 @@ public class FrameImpl extends ChannelOwner implements Frame {
}
private void waitForURL(UrlMatcher matcher, WaitForURLOptions options) {
withLogging("Frame.waitForURL", () -> waitForURLImpl(matcher, options));
withWaitLogging("Frame.waitForURL", logger -> {
waitForURLImpl(logger, matcher, options);
return null;
});
}
void waitForURLImpl(UrlMatcher matcher, WaitForURLOptions options) {
void waitForURLImpl(Logger logger, UrlMatcher matcher, WaitForURLOptions options) {
logger.log("waiting for url " + matcher);
if (options == null) {
options = new WaitForURLOptions();
}
if (matcher.test(url())) {
waitForLoadStateImpl(options.waitUntil, convertType(options, WaitForLoadStateOptions.class));
waitForLoadStateImpl(options.waitUntil, convertType(options, WaitForLoadStateOptions.class), logger);
return;
}
waitForNavigationImpl(() -> {}, convertType(options, WaitForNavigationOptions.class), matcher);
waitForNavigationImpl(logger, () -> {}, convertType(options, WaitForNavigationOptions.class), matcher);
}
int queryCount(String selector) {

View File

@ -26,8 +26,7 @@ import java.nio.file.Path;
import java.util.Base64;
import java.util.Map;
import static com.microsoft.playwright.impl.LoggingSupport.isApiLoggingEnabled;
import static com.microsoft.playwright.impl.LoggingSupport.logApi;
import static com.microsoft.playwright.impl.LoggingSupport.*;
import static com.microsoft.playwright.impl.Serialization.fromNameValues;
import static com.microsoft.playwright.impl.Serialization.gson;
@ -67,9 +66,7 @@ public class HARRouter {
String action = response.get("action").getAsString();
if ("redirect".equals(action)) {
String redirectURL = response.get("redirectURL").getAsString();
if (isApiLoggingEnabled()) {
logApi("HAR: " + route.request().url() + " redirected to " + redirectURL);
}
logApiIfEnabled("HAR: " + route.request().url() + " redirected to " + redirectURL);
((RouteImpl) route).redirectNavigationRequest(redirectURL);
return;
}
@ -86,9 +83,7 @@ public class HARRouter {
}
if ("error".equals(action)) {
if (isApiLoggingEnabled()) {
logApi("HAR: " + response.get("message").getAsString());
}
logApiIfEnabled("HAR: " + response.get("message").getAsString());
// Report the error, but fall through to the default handler.
}

View File

@ -0,0 +1,21 @@
/*
* Copyright (c) Microsoft Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.microsoft.playwright.impl;
interface Logger {
void log(String message);
}

View File

@ -60,8 +60,10 @@ class LoggingSupport {
System.err.println(timestamp + " " + message);
}
static boolean isApiLoggingEnabled() {
return isEnabled;
static void logApiIfEnabled(String message) {
if (isEnabled) {
logApi(message);
}
}
static void logApi(String message) {

View File

@ -443,7 +443,7 @@ public class PageImpl extends ChannelOwner implements Page {
@Override
public Page waitForClose(WaitForCloseOptions options, Runnable code) {
return withWaitLogging("Page.waitForClose", () -> waitForCloseImpl(options, code));
return withWaitLogging("Page.waitForClose", logger -> waitForCloseImpl(options, code));
}
private Page waitForCloseImpl(WaitForCloseOptions options, Runnable code) {
@ -455,7 +455,7 @@ public class PageImpl extends ChannelOwner implements Page {
@Override
public ConsoleMessage waitForConsoleMessage(WaitForConsoleMessageOptions options, Runnable code) {
return withWaitLogging("Page.waitForConsoleMessage", () -> waitForConsoleMessageImpl(options, code));
return withWaitLogging("Page.waitForConsoleMessage", logger -> waitForConsoleMessageImpl(options, code));
}
private ConsoleMessage waitForConsoleMessageImpl(WaitForConsoleMessageOptions options, Runnable code) {
@ -467,7 +467,7 @@ public class PageImpl extends ChannelOwner implements Page {
@Override
public Download waitForDownload(WaitForDownloadOptions options, Runnable code) {
return withWaitLogging("Page.waitForDownload", () -> waitForDownloadImpl(options, code));
return withWaitLogging("Page.waitForDownload", logger -> waitForDownloadImpl(options, code));
}
private Download waitForDownloadImpl(WaitForDownloadOptions options, Runnable code) {
@ -479,7 +479,7 @@ public class PageImpl extends ChannelOwner implements Page {
@Override
public FileChooser waitForFileChooser(WaitForFileChooserOptions options, Runnable code) {
return withWaitLogging("Page.waitForFileChooser", () -> waitForFileChooserImpl(options, code));
return withWaitLogging("Page.waitForFileChooser", logger -> waitForFileChooserImpl(options, code));
}
private FileChooser waitForFileChooserImpl(WaitForFileChooserOptions options, Runnable code) {
@ -492,7 +492,7 @@ public class PageImpl extends ChannelOwner implements Page {
@Override
public Page waitForPopup(WaitForPopupOptions options, Runnable code) {
return withWaitLogging("Page.waitForPopup", () -> waitForPopupImpl(options, code));
return withWaitLogging("Page.waitForPopup", logger -> waitForPopupImpl(options, code));
}
private Page waitForPopupImpl(WaitForPopupOptions options, Runnable code) {
@ -504,7 +504,7 @@ public class PageImpl extends ChannelOwner implements Page {
@Override
public WebSocket waitForWebSocket(WaitForWebSocketOptions options, Runnable code) {
return withWaitLogging("Page.waitForWebSocket", () -> waitForWebSocketImpl(options, code));
return withWaitLogging("Page.waitForWebSocket", logger -> waitForWebSocketImpl(options, code));
}
private WebSocket waitForWebSocketImpl(WaitForWebSocketOptions options, Runnable code) {
@ -516,7 +516,7 @@ public class PageImpl extends ChannelOwner implements Page {
@Override
public Worker waitForWorker(WaitForWorkerOptions options, Runnable code) {
return withWaitLogging("Page.waitForWorker", () -> waitForWorkerImpl(options, code));
return withWaitLogging("Page.waitForWorker", logger -> waitForWorkerImpl(options, code));
}
private Worker waitForWorkerImpl(WaitForWorkerOptions options, Runnable code) {
@ -1268,25 +1268,25 @@ public class PageImpl extends ChannelOwner implements Page {
@Override
public void waitForLoadState(LoadState state, WaitForLoadStateOptions options) {
withWaitLogging("Page.waitForLoadState", () -> {
mainFrame.waitForLoadStateImpl(state, convertType(options, Frame.WaitForLoadStateOptions.class));
withWaitLogging("Page.waitForLoadState", logger -> {
mainFrame.waitForLoadStateImpl(state, convertType(options, Frame.WaitForLoadStateOptions.class), logger);
return null;
});
}
@Override
public Response waitForNavigation(WaitForNavigationOptions options, Runnable code) {
return withLogging("Page.waitForNavigation", () -> waitForNavigationImpl(code, options));
return withWaitLogging("Page.waitForNavigation", logger -> waitForNavigationImpl(logger, code, options));
}
Response waitForNavigationImpl(Runnable code, WaitForNavigationOptions options) {
private Response waitForNavigationImpl(Logger logger, Runnable code, WaitForNavigationOptions options) {
Frame.WaitForNavigationOptions frameOptions = new Frame.WaitForNavigationOptions();
if (options != null) {
frameOptions.timeout = options.timeout;
frameOptions.waitUntil = options.waitUntil;
frameOptions.url = options.url;
}
return mainFrame.waitForNavigationImpl(code, frameOptions);
return mainFrame.waitForNavigationImpl(logger, code, frameOptions);
}
void frameNavigated(FrameImpl frame) {
@ -1338,21 +1338,28 @@ public class PageImpl extends ChannelOwner implements Page {
@Override
public Request waitForRequest(String urlGlob, WaitForRequestOptions options, Runnable code) {
return waitForRequest(toRequestPredicate(new UrlMatcher(browserContext.baseUrl, urlGlob)), options, code);
return waitForRequest(new UrlMatcher(browserContext.baseUrl, urlGlob), null, options, code);
}
@Override
public Request waitForRequest(Pattern urlPattern, WaitForRequestOptions options, Runnable code) {
return waitForRequest(toRequestPredicate(new UrlMatcher(urlPattern)), options, code);
return waitForRequest(new UrlMatcher(urlPattern), null, options, code);
}
@Override
public Request waitForRequest(Predicate<Request> predicate, WaitForRequestOptions options, Runnable code) {
return withWaitLogging("Page.waitForRequest", () -> waitForRequestImpl(predicate, options, code));
return waitForRequest(null, predicate, options, code);
}
private static Predicate<Request> toRequestPredicate(UrlMatcher matcher) {
return request -> matcher.test(request.url());
private Request waitForRequest(UrlMatcher urlMatcher, Predicate<Request> predicate, WaitForRequestOptions options, Runnable code) {
return withWaitLogging("Page.waitForRequest", logger -> {
logger.log("waiting for request " + ((urlMatcher == null) ? "matching predicate" : urlMatcher.toString()));
Predicate<Request> requestPredicate = predicate;
if (requestPredicate == null) {
requestPredicate = request -> urlMatcher.test(request.url());;
}
return waitForRequestImpl(requestPredicate, options, code);
});
}
private Request waitForRequestImpl(Predicate<Request> predicate, WaitForRequestOptions options, Runnable code) {
@ -1364,7 +1371,7 @@ public class PageImpl extends ChannelOwner implements Page {
@Override
public Request waitForRequestFinished(WaitForRequestFinishedOptions options, Runnable code) {
return withWaitLogging("Page.waitForRequestFinished", () -> waitForRequestFinishedImpl(options, code));
return withWaitLogging("Page.waitForRequestFinished", logger -> waitForRequestFinishedImpl(options, code));
}
private Request waitForRequestFinishedImpl(WaitForRequestFinishedOptions options, Runnable code) {
@ -1376,21 +1383,28 @@ public class PageImpl extends ChannelOwner implements Page {
@Override
public Response waitForResponse(String urlGlob, WaitForResponseOptions options, Runnable code) {
return waitForResponse(toResponsePredicate(new UrlMatcher(browserContext.baseUrl, urlGlob)), options, code);
return waitForResponse(new UrlMatcher(browserContext.baseUrl, urlGlob), null, options, code);
}
@Override
public Response waitForResponse(Pattern urlPattern, WaitForResponseOptions options, Runnable code) {
return waitForResponse(toResponsePredicate(new UrlMatcher(urlPattern)), options, code);
return waitForResponse(new UrlMatcher(urlPattern), null, options, code);
}
@Override
public Response waitForResponse(Predicate<Response> predicate, WaitForResponseOptions options, Runnable code) {
return withLogging("Page.waitForResponse", () -> waitForResponseImpl(predicate, options, code));
return waitForResponse(null, predicate, options, code);
}
private static Predicate<Response> toResponsePredicate(UrlMatcher matcher) {
return response -> matcher.test(response.url());
private Response waitForResponse(UrlMatcher urlMatcher, Predicate<Response> predicate, WaitForResponseOptions options, Runnable code) {
return withWaitLogging("Page.waitForResponse", logger -> {
logger.log("waiting for response " + ((urlMatcher == null) ? "matching predicate" : urlMatcher.toString()));
Predicate<Response> responsePredicate = predicate;
if (responsePredicate == null) {
responsePredicate = response -> urlMatcher.test(response.url());;
}
return waitForResponseImpl(responsePredicate, options, code);
});
}
private Response waitForResponseImpl(Predicate<Response> predicate, WaitForResponseOptions options, Runnable code) {
@ -1427,7 +1441,10 @@ public class PageImpl extends ChannelOwner implements Page {
}
private void waitForURL(UrlMatcher matcher, WaitForURLOptions options) {
withLogging("Page.waitForURL", () -> mainFrame.waitForURLImpl(matcher, convertType(options, Frame.WaitForURLOptions.class)));
withWaitLogging("Page.waitForURL", logger -> {
mainFrame.waitForURLImpl(logger, matcher, convertType(options, Frame.WaitForURLOptions.class));
return null;
});
}
@Override

View File

@ -97,4 +97,13 @@ class UrlMatcher {
public int hashCode() {
return Objects.hash(rawSource);
}
@Override
public String toString() {
if (rawSource == null)
return "<any>";
if (rawSource instanceof Predicate)
return "matching predicate";
return rawSource.toString();
}
}

View File

@ -18,38 +18,52 @@ package com.microsoft.playwright.impl;
import com.google.gson.JsonObject;
import java.util.function.Function;
import java.util.function.Supplier;
import static com.microsoft.playwright.impl.Utils.createGuid;
public class WaitForEventLogger<T> implements Supplier<T> {
private final Supplier<T> supplier;
public class WaitForEventLogger<T> implements Supplier<T>, Logger {
private final Function<Logger, T> supplier;
private final ChannelOwner channel;
private final String waitId;
private final String apiName;
WaitForEventLogger(ChannelOwner channelOwner, String apiName, Supplier<T> supplier) {
WaitForEventLogger(ChannelOwner channelOwner, String apiName, Function<Logger, T> supplier) {
this.supplier = supplier;
this.channel = channelOwner;
this.apiName = apiName;
this.waitId = createGuid();
JsonObject info = new JsonObject();
info.addProperty("phase", "before");
sendWaitForEventInfo(info);
}
@Override
public T get() {
return channel.withLogging(apiName, () -> {
{
JsonObject info = new JsonObject();
info.addProperty("phase", "before");
sendWaitForEventInfo(info);
}
JsonObject info = new JsonObject();
info.addProperty("phase", "after");
try {
return supplier.apply(this);
} catch (RuntimeException e) {
info.addProperty("error", e.getMessage());
throw e;
} finally {
sendWaitForEventInfo(info);
}
});
}
@Override
public void log(String message) {
LoggingSupport.logApiIfEnabled(message);
JsonObject info = new JsonObject();
info.addProperty("phase", "after");
try {
return supplier.get();
} catch (RuntimeException e) {
info.addProperty("error", e.getMessage());
throw e;
} finally {
sendWaitForEventInfo(info);
}
info.addProperty("phase", "log");
info.addProperty("message", message);
sendWaitForEventInfo(info);
}
private void sendWaitForEventInfo(JsonObject info) {
@ -57,6 +71,6 @@ public class WaitForEventLogger<T> implements Supplier<T> {
info.addProperty("waitId", waitId);
JsonObject params = new JsonObject();
params.add("info", info);
channel.withLogging(apiName, () -> channel.sendMessageAsync("waitForEventInfo", params));
channel.sendMessageAsync("waitForEventInfo", params);
}
}

View File

@ -87,7 +87,7 @@ class WebSocketImpl extends ChannelOwner implements WebSocket {
@Override
public WebSocketFrame waitForFrameReceived(WaitForFrameReceivedOptions options, Runnable code) {
return withWaitLogging("WebSocket.waitForFrameReceived", () -> waitForFrameReceivedImpl(options, code));
return withWaitLogging("WebSocket.waitForFrameReceived", logger -> waitForFrameReceivedImpl(options, code));
}
private WebSocketFrame waitForFrameReceivedImpl(WaitForFrameReceivedOptions options, Runnable code) {
@ -99,7 +99,7 @@ class WebSocketImpl extends ChannelOwner implements WebSocket {
@Override
public WebSocketFrame waitForFrameSent(WaitForFrameSentOptions options, Runnable code) {
return withWaitLogging("WebSocket.waitForFrameSent", () -> waitForFrameSentImpl(options, code));
return withWaitLogging("WebSocket.waitForFrameSent", logger -> waitForFrameSentImpl(options, code));
}
private WebSocketFrame waitForFrameSentImpl(WaitForFrameSentOptions options, Runnable code) {

View File

@ -59,7 +59,7 @@ class WorkerImpl extends ChannelOwner implements Worker {
@Override
public Worker waitForClose(WaitForCloseOptions options, Runnable code) {
return withWaitLogging("Worker.waitForClose", () -> waitForCloseImpl(options, code));
return withWaitLogging("Worker.waitForClose", logger -> waitForCloseImpl(options, code));
}
private Worker waitForCloseImpl(WaitForCloseOptions options, Runnable code) {