From 823dfc53fbc98949ed5080606a509f5b7d962968 Mon Sep 17 00:00:00 2001 From: Yury Semikhatsky Date: Wed, 9 Jun 2021 14:54:45 -0700 Subject: [PATCH 1/2] feat: accept driver env in Playwright.create() --- .../microsoft/playwright/impl/DriverJar.java | 10 ++- .../com/microsoft/playwright/TestInstall.java | 3 +- .../com/microsoft/playwright/impl/Driver.java | 12 ++- .../java/com/microsoft/playwright/CLI.java | 3 +- .../com/microsoft/playwright/Playwright.java | 18 ++++- .../playwright/impl/PlaywrightImpl.java | 12 ++- .../com/microsoft/playwright/TestBase.java | 1 - .../playwright/TestBrowserTypeConnect.java | 6 +- .../playwright/TestPlaywrightCreate.java | 73 +++++++++++++++++++ .../playwright/tools/ApiGenerator.java | 17 ++--- 10 files changed, 130 insertions(+), 25 deletions(-) create mode 100644 playwright/src/test/java/com/microsoft/playwright/TestPlaywrightCreate.java diff --git a/driver-bundle/src/main/java/com/microsoft/playwright/impl/DriverJar.java b/driver-bundle/src/main/java/com/microsoft/playwright/impl/DriverJar.java index 0f35f9ccd..7e2f8b821 100644 --- a/driver-bundle/src/main/java/com/microsoft/playwright/impl/DriverJar.java +++ b/driver-bundle/src/main/java/com/microsoft/playwright/impl/DriverJar.java @@ -21,6 +21,7 @@ import java.net.URISyntaxException; import java.nio.file.*; import java.util.Collections; +import java.util.Map; import java.util.concurrent.TimeUnit; public class DriverJar extends Driver { @@ -29,17 +30,22 @@ public class DriverJar extends Driver { DriverJar() throws IOException, URISyntaxException, InterruptedException { driverTempDir = Files.createTempDirectory("playwright-java-"); driverTempDir.toFile().deleteOnExit(); + } + + @Override + protected void initialize(Map env) throws Exception { extractDriverToTempDir(); - installBrowsers(); + installBrowsers(env); } - private void installBrowsers() throws IOException, InterruptedException { + private void installBrowsers(Map env) throws IOException, InterruptedException { String cliFileName = super.cliFileName(); Path driver = driverTempDir.resolve(cliFileName); if (!Files.exists(driver)) { throw new RuntimeException("Failed to find " + cliFileName + " at " + driver); } ProcessBuilder pb = new ProcessBuilder(driver.toString(), "install"); + pb.environment().putAll(env); pb.redirectError(ProcessBuilder.Redirect.INHERIT); pb.redirectOutput(ProcessBuilder.Redirect.INHERIT); Process p = pb.start(); diff --git a/driver-bundle/src/test/java/com/microsoft/playwright/TestInstall.java b/driver-bundle/src/test/java/com/microsoft/playwright/TestInstall.java index 8a453e8ce..43d76d7e6 100644 --- a/driver-bundle/src/test/java/com/microsoft/playwright/TestInstall.java +++ b/driver-bundle/src/test/java/com/microsoft/playwright/TestInstall.java @@ -21,6 +21,7 @@ import java.nio.file.Files; import java.nio.file.Path; +import java.util.Collections; import java.util.concurrent.TimeUnit; import static org.junit.jupiter.api.Assertions.assertNull; @@ -31,7 +32,7 @@ public class TestInstall { void playwrightCliInstalled() throws Exception { // Clear system property to ensure that the driver is loaded from jar. System.clearProperty("playwright.cli.dir"); - Path cli = Driver.ensureDriverInstalled(); + Path cli = Driver.ensureDriverInstalled(Collections.emptyMap()); assertTrue(Files.exists(cli)); ProcessBuilder pb = new ProcessBuilder(cli.toString(), "install"); diff --git a/driver/src/main/java/com/microsoft/playwright/impl/Driver.java b/driver/src/main/java/com/microsoft/playwright/impl/Driver.java index 223b7f1b7..df0077fee 100644 --- a/driver/src/main/java/com/microsoft/playwright/impl/Driver.java +++ b/driver/src/main/java/com/microsoft/playwright/impl/Driver.java @@ -18,6 +18,7 @@ import java.nio.file.Path; import java.nio.file.Paths; +import java.util.Map; /** * This class provides access to playwright-cli. It can be either preinstalled @@ -32,16 +33,23 @@ private static class PreinstalledDriver extends Driver { PreinstalledDriver(Path driverDir) { this.driverDir = driverDir; } + + @Override + protected void initialize(Map env) { + // no-op + } + @Override Path driverDir() { return driverDir; } } - public static synchronized Path ensureDriverInstalled() { + public static synchronized Path ensureDriverInstalled(Map env) { if (instance == null) { try { instance = createDriver(); + instance.initialize(env); } catch (Exception exception) { throw new RuntimeException("Failed to create driver", exception); } @@ -50,6 +58,8 @@ public static synchronized Path ensureDriverInstalled() { return instance.driverDir().resolve(name); } + protected abstract void initialize(Map env) throws Exception; + protected String cliFileName() { return System.getProperty("os.name").toLowerCase().contains("windows") ? "playwright.cmd" : "playwright.sh"; diff --git a/playwright/src/main/java/com/microsoft/playwright/CLI.java b/playwright/src/main/java/com/microsoft/playwright/CLI.java index 56fc6ed23..3a8be8cbf 100644 --- a/playwright/src/main/java/com/microsoft/playwright/CLI.java +++ b/playwright/src/main/java/com/microsoft/playwright/CLI.java @@ -20,6 +20,7 @@ import java.io.IOException; import java.nio.file.Path; +import java.util.Collections; import static java.util.Arrays.asList; @@ -28,7 +29,7 @@ */ public class CLI { public static void main(String[] args) throws IOException, InterruptedException { - Path driver = Driver.ensureDriverInstalled(); + Path driver = Driver.ensureDriverInstalled(Collections.emptyMap()); ProcessBuilder pb = new ProcessBuilder(driver.toString()); pb.command().addAll(asList(args)); if (!pb.environment().containsKey("PW_CLI_TARGET_LANG")) { diff --git a/playwright/src/main/java/com/microsoft/playwright/Playwright.java b/playwright/src/main/java/com/microsoft/playwright/Playwright.java index a6622c2a5..3a3e61670 100644 --- a/playwright/src/main/java/com/microsoft/playwright/Playwright.java +++ b/playwright/src/main/java/com/microsoft/playwright/Playwright.java @@ -40,6 +40,18 @@ * } */ public interface Playwright extends AutoCloseable { + class CreateOptions { + /** + * Specify environment variables that will be passed to the driver process. By default driver process inherits environment + * variables of the Playwright process. + */ + public Map env; + + public CreateOptions setEnv(Map env) { + this.env = env; + return this; + } + } /** * This object can be used to launch or connect to Chromium, returning instances of {@code Browser}. */ @@ -72,8 +84,12 @@ public interface Playwright extends AutoCloseable { * playwright.close(); * } */ + static Playwright create(CreateOptions options) { + return PlaywrightImpl.create(options); + } + static Playwright create() { - return PlaywrightImpl.create(); + return create(null); } } diff --git a/playwright/src/main/java/com/microsoft/playwright/impl/PlaywrightImpl.java b/playwright/src/main/java/com/microsoft/playwright/impl/PlaywrightImpl.java index ecb19da56..ac5e5d714 100644 --- a/playwright/src/main/java/com/microsoft/playwright/impl/PlaywrightImpl.java +++ b/playwright/src/main/java/com/microsoft/playwright/impl/PlaywrightImpl.java @@ -23,17 +23,23 @@ import java.io.IOException; import java.nio.file.Path; +import java.util.Collections; +import java.util.Map; import java.util.concurrent.TimeUnit; public class PlaywrightImpl extends ChannelOwner implements Playwright { private Process driverProcess; - public static PlaywrightImpl create() { + public static PlaywrightImpl create(CreateOptions options) { try { - Path driver = Driver.ensureDriverInstalled(); + Map env = Collections.emptyMap(); + if (options != null && options.env != null) { + env = options.env; + } + Path driver = Driver.ensureDriverInstalled(env); ProcessBuilder pb = new ProcessBuilder(driver.toString(), "run-driver"); pb.redirectError(ProcessBuilder.Redirect.INHERIT); -// pb.environment().put("DEBUG", "pw:pro*"); + pb.environment().putAll(env); Process p = pb.start(); Connection connection = new Connection(new PipeTransport(p.getInputStream(), p.getOutputStream())); PlaywrightImpl result = (PlaywrightImpl) connection.waitForObjectWithKnownName("Playwright"); diff --git a/playwright/src/test/java/com/microsoft/playwright/TestBase.java b/playwright/src/test/java/com/microsoft/playwright/TestBase.java index f6ca80c6b..a9a1a8e5f 100644 --- a/playwright/src/test/java/com/microsoft/playwright/TestBase.java +++ b/playwright/src/test/java/com/microsoft/playwright/TestBase.java @@ -16,7 +16,6 @@ package com.microsoft.playwright; -import com.microsoft.playwright.options.BrowserChannel; import org.junit.jupiter.api.*; import java.io.IOException; diff --git a/playwright/src/test/java/com/microsoft/playwright/TestBrowserTypeConnect.java b/playwright/src/test/java/com/microsoft/playwright/TestBrowserTypeConnect.java index 48dd8c9ba..fab49e3d1 100644 --- a/playwright/src/test/java/com/microsoft/playwright/TestBrowserTypeConnect.java +++ b/playwright/src/test/java/com/microsoft/playwright/TestBrowserTypeConnect.java @@ -31,9 +31,7 @@ import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; +import java.util.*; import static com.microsoft.playwright.Utils.mapOf; import static org.junit.jupiter.api.Assertions.*; @@ -60,7 +58,7 @@ void kill() throws InterruptedException { private static BrowserServer launchBrowserServer(BrowserType browserType) { try { - Path driver = Driver.ensureDriverInstalled(); + Path driver = Driver.ensureDriverInstalled(Collections.emptyMap()); Path dir = driver.getParent(); String node = dir.resolve(isWindows ? "node.exe" : "node").toString(); String cliJs = dir.resolve("package/lib/cli/cli.js").toString(); diff --git a/playwright/src/test/java/com/microsoft/playwright/TestPlaywrightCreate.java b/playwright/src/test/java/com/microsoft/playwright/TestPlaywrightCreate.java new file mode 100644 index 000000000..cdeb2ab09 --- /dev/null +++ b/playwright/src/test/java/com/microsoft/playwright/TestPlaywrightCreate.java @@ -0,0 +1,73 @@ +/* + * 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; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.io.TempDir; + +import java.io.IOException; +import java.nio.file.DirectoryStream; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.Map; + +import static com.microsoft.playwright.Utils.getBrowserTypeFromEnv; +import static com.microsoft.playwright.Utils.mapOf; +import static org.junit.jupiter.api.Assertions.*; + +public class TestPlaywrightCreate { + @Test + void shouldSupportEnvSkipBrowserDownload(@TempDir Path browsersDir) throws IOException { + Map env = mapOf("PLAYWRIGHT_BROWSERS_PATH", browsersDir.toString(), + "PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD", "1"); + Playwright.CreateOptions options = new Playwright.CreateOptions().setEnv(env); + + try (Playwright playwright = Playwright.create(options)) { + try { + getBrowserTypeFromEnv(playwright).launch(); + fail("Did not throw"); + } catch (PlaywrightException e) { + assertTrue(e.getMessage().contains("executable doesn't exist"), e.getMessage()); + assertTrue(e.getMessage().contains(browsersDir.toString()), e.getMessage()); + } + + try (DirectoryStream ds = Files.newDirectoryStream(browsersDir)) { + for (Path child : ds) { + fail("Unexpected file: " + child.toString()); + } + } + } + } + + // This test is too slow, so we don't run it. + void shouldSupportEnvBrowsersPath(@TempDir Path browsersDir) throws IOException { + Map env = mapOf("PLAYWRIGHT_BROWSERS_PATH", browsersDir.toString()); + Playwright.CreateOptions options = new Playwright.CreateOptions().setEnv(env); + + try (Playwright playwright = Playwright.create(options)) { + try (Browser browser = playwright.chromium().launch()) { + assertNotNull(browser); + } + + try (DirectoryStream ds = Files.newDirectoryStream(browsersDir)) { + for (Path child : ds) { + assertTrue(Files.isDirectory(child)); + } + } + } + } +} diff --git a/tools/api-generator/src/main/java/com/microsoft/playwright/tools/ApiGenerator.java b/tools/api-generator/src/main/java/com/microsoft/playwright/tools/ApiGenerator.java index 55433dfdb..e66c63064 100644 --- a/tools/api-generator/src/main/java/com/microsoft/playwright/tools/ApiGenerator.java +++ b/tools/api-generator/src/main/java/com/microsoft/playwright/tools/ApiGenerator.java @@ -587,15 +587,6 @@ class Method extends Element { final TypeRef returnType; final List params = new ArrayList<>(); - private static Map customSignature = new HashMap<>(); - static { - customSignature.put("Playwright.create", new String[]{ - "static Playwright create() {", - " return PlaywrightImpl.create();", - "}" - }); - } - Method(TypeDefinition parent, JsonObject jsonElement) { super(parent, jsonElement); returnType = new TypeRef(this, jsonElement.get("type")); @@ -614,8 +605,12 @@ class Method extends Element { void writeTo(List output, String offset) { if ("Playwright.create".equals(jsonPath)) { writeJavadoc(params, output, offset); + output.add(offset + "static Playwright create(CreateOptions options) {"); + output.add(offset + " return PlaywrightImpl.create(options);"); + output.add(offset + "}"); + output.add(""); output.add(offset + "static Playwright create() {"); - output.add(offset + " return PlaywrightImpl.create();"); + output.add(offset + " return create(null);"); output.add(offset + "}"); return; } @@ -1170,7 +1165,7 @@ private static boolean isSupported(JsonElement json) { public static void main(String[] args) throws IOException { File cwd = FileSystems.getDefault().getPath(".").toFile(); System.out.println(cwd.getCanonicalPath()); - File file = new File(cwd, "tools/api-generator/src/main/resources/api.json"); + File file = new File("/home/yurys/playwright/api.json"); System.out.println("Reading from: " + file.getCanonicalPath()); new ApiGenerator(new FileReader(file)); } From 25dfb5281ee903bb3cbfca12f058e54c5df7a21d Mon Sep 17 00:00:00 2001 From: Yury Semikhatsky Date: Wed, 9 Jun 2021 16:08:45 -0700 Subject: [PATCH 2/2] Revert local path --- .../main/java/com/microsoft/playwright/tools/ApiGenerator.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/api-generator/src/main/java/com/microsoft/playwright/tools/ApiGenerator.java b/tools/api-generator/src/main/java/com/microsoft/playwright/tools/ApiGenerator.java index e66c63064..23df6b9f3 100644 --- a/tools/api-generator/src/main/java/com/microsoft/playwright/tools/ApiGenerator.java +++ b/tools/api-generator/src/main/java/com/microsoft/playwright/tools/ApiGenerator.java @@ -1165,7 +1165,7 @@ private static boolean isSupported(JsonElement json) { public static void main(String[] args) throws IOException { File cwd = FileSystems.getDefault().getPath(".").toFile(); System.out.println(cwd.getCanonicalPath()); - File file = new File("/home/yurys/playwright/api.json"); + File file = new File(cwd, "tools/api-generator/src/main/resources/api.json"); System.out.println("Reading from: " + file.getCanonicalPath()); new ApiGenerator(new FileReader(file)); }