How to use getExtraOptions method of org.openqa.selenium.firefox.FirefoxBinary class

Best Selenium code snippet using org.openqa.selenium.firefox.FirefoxBinary.getExtraOptions

Run Selenium automation tests on LambdaTest cloud grid

Perform automation testing on 3000+ real desktop and mobile devices online.

copy
1// Licensed to the Software Freedom Conservancy (SFC) under one
2// or more contributor license agreements.  See the NOTICE file
3// distributed with this work for additional information
4// regarding copyright ownership.  The SFC licenses this file
5// to you under the Apache License, Version 2.0 (the
6// "License"); you may not use this file except in compliance
7// with the License.  You may obtain a copy of the License at
8//
9//   http://www.apache.org/licenses/LICENSE-2.0
10//
11// Unless required by applicable law or agreed to in writing,
12// software distributed under the License is distributed on an
13// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14// KIND, either express or implied.  See the License for the
15// specific language governing permissions and limitations
16// under the License.
17
18package org.openqa.selenium.firefox.xpi;
19
20import static java.util.concurrent.TimeUnit.SECONDS;
21import static org.openqa.selenium.firefox.FirefoxOptions.FIREFOX_OPTIONS;
22import static org.openqa.selenium.firefox.FirefoxProfile.PORT_PREFERENCE;
23
24import com.google.auto.service.AutoService;
25import com.google.common.base.Preconditions;
26import com.google.common.collect.ImmutableList;
27import com.google.common.collect.ImmutableMap;
28import com.google.common.collect.Iterables;
29import com.google.common.io.ByteStreams;
30
31import org.openqa.selenium.Capabilities;
32import org.openqa.selenium.Platform;
33import org.openqa.selenium.WebDriverException;
34import org.openqa.selenium.firefox.ClasspathExtension;
35import org.openqa.selenium.firefox.Extension;
36import org.openqa.selenium.firefox.FileExtension;
37import org.openqa.selenium.firefox.FirefoxBinary;
38import org.openqa.selenium.firefox.FirefoxDriver;
39import org.openqa.selenium.firefox.FirefoxDriverService;
40import org.openqa.selenium.firefox.FirefoxOptions;
41import org.openqa.selenium.firefox.FirefoxProfile;
42import org.openqa.selenium.io.FileHandler;
43import org.openqa.selenium.net.UrlChecker;
44import org.openqa.selenium.os.CommandLine;
45import org.openqa.selenium.remote.service.DriverService;
46
47import java.io.File;
48import java.io.FileOutputStream;
49import java.io.IOException;
50import java.net.MalformedURLException;
51import java.net.URL;
52import java.util.ArrayList;
53import java.util.HashSet;
54import java.util.List;
55import java.util.Map;
56import java.util.Objects;
57import java.util.Optional;
58import java.util.Set;
59import java.util.concurrent.locks.Lock;
60import java.util.concurrent.locks.ReentrantLock;
61import java.util.function.Supplier;
62import java.util.stream.Stream;
63
64public class XpiDriverService extends FirefoxDriverService {
65
66  private static final String NO_FOCUS_LIBRARY_NAME = "x_ignore_nofocus.so";
67  private static final String PATH_PREFIX =
68      "/" + XpiDriverService.class.getPackage().getName().replace(".", "/") + "/";
69
70  private final Lock lock = new ReentrantLock();
71
72  private final int port;
73  private final FirefoxBinary binary;
74  private final FirefoxProfile profile;
75  private File profileDir;
76
77  private XpiDriverService(
78      File executable,
79      int port,
80      ImmutableList<String> args,
81      ImmutableMap<String, String> environment,
82      FirefoxBinary binary,
83      FirefoxProfile profile,
84      File logFile)
85      throws IOException {
86    super(executable, port, args, environment);
87
88    Preconditions.checkState(port > 0, "Port must be set");
89
90    this.port = port;
91    this.binary = binary;
92    this.profile = profile;
93
94    String firefoxLogFile = System.getProperty(FirefoxDriver.SystemProperty.BROWSER_LOGFILE);
95    if (firefoxLogFile != null) { // System property has higher precedence
96      if ("/dev/stdout".equals(firefoxLogFile)) {
97        sendOutputTo(System.out);
98      } else if ("/dev/stderr".equals(firefoxLogFile)) {
99        sendOutputTo(System.err);
100      } else if ("/dev/null".equals(firefoxLogFile)) {
101        sendOutputTo(ByteStreams.nullOutputStream());
102      } else {
103        sendOutputTo(new FileOutputStream(firefoxLogFile));
104      }
105    } else {
106      if (logFile != null) {
107        // TODO: This stream is leaked.
108        sendOutputTo(new FileOutputStream(logFile));
109      } else {
110        sendOutputTo(ByteStreams.nullOutputStream());
111      }
112    }
113  }
114
115  @Override
116  protected URL getUrl(int port) throws MalformedURLException {
117    return new URL("http", "localhost", port, "/hub");
118  }
119
120  @Override
121  public void start() throws IOException {
122    lock.lock();
123    try {
124      profile.setPreference(PORT_PREFERENCE, port);
125      addWebDriverExtension(profile);
126      profileDir = profile.layoutOnDisk();
127
128      ImmutableMap.Builder<String, String> envBuilder = new ImmutableMap.Builder<String, String>()
129          .putAll(getEnvironment())
130          .put("XRE_PROFILE_PATH", profileDir.getAbsolutePath())
131          .put("MOZ_NO_REMOTE", "1")
132          .put("MOZ_CRASHREPORTER_DISABLE", "1") // Disable Breakpad
133          .put("NO_EM_RESTART", "1"); // Prevent the binary from detaching from the console
134
135      if (Platform.getCurrent().is(Platform.LINUX) && profile.shouldLoadNoFocusLib()) {
136        modifyLinkLibraryPath(envBuilder, profileDir);
137      }
138      Map<String, String> env = envBuilder.build();
139
140      List<String> cmdArray = new ArrayList<>(getArgs());
141      cmdArray.addAll(binary.getExtraOptions());
142      cmdArray.add("-foreground");
143      process = new CommandLine(binary.getPath(), Iterables.toArray(cmdArray, String.class));
144      process.setEnvironmentVariables(env);
145      process.updateDynamicLibraryPath(env.get(CommandLine.getLibraryPathPropertyName()));
146      // On Snow Leopard, beware of problems the sqlite library
147      if (! (Platform.getCurrent().is(Platform.MAC) && Platform.getCurrent().getMinorVersion() > 5)) {
148        String firefoxLibraryPath = System.getProperty(
149            FirefoxDriver.SystemProperty.BROWSER_LIBRARY_PATH,
150            binary.getFile().getAbsoluteFile().getParentFile().getAbsolutePath());
151        process.updateDynamicLibraryPath(firefoxLibraryPath);
152      }
153
154      process.copyOutputTo(getOutputStream());
155
156      process.executeAsync();
157
158      waitUntilAvailable();
159    } finally {
160      lock.unlock();
161    }
162  }
163
164  private void modifyLinkLibraryPath(ImmutableMap.Builder<String, String> envBuilder, File profileDir) {
165    // Extract x_ignore_nofocus.so from x86, amd64 directories inside
166    // the jar into a real place in the filesystem and change LD_LIBRARY_PATH
167    // to reflect that.
168
169    String existingLdLibPath = System.getenv("LD_LIBRARY_PATH");
170    // The returned new ld lib path is terminated with ':'
171    String newLdLibPath =
172        extractAndCheck(profileDir, NO_FOCUS_LIBRARY_NAME, PATH_PREFIX + "x86", PATH_PREFIX +
173                                                                                "amd64");
174    if (existingLdLibPath != null && !existingLdLibPath.equals("")) {
175      newLdLibPath += existingLdLibPath;
176    }
177
178    envBuilder.put("LD_LIBRARY_PATH", newLdLibPath);
179    // Set LD_PRELOAD to x_ignore_nofocus.so - this will be taken automagically
180    // from the LD_LIBRARY_PATH
181    envBuilder.put("LD_PRELOAD", NO_FOCUS_LIBRARY_NAME);
182  }
183
184  private String extractAndCheck(File profileDir, String noFocusSoName,
185                                   String jarPath32Bit, String jarPath64Bit) {
186
187    // 1. Extract x86/x_ignore_nofocus.so to profile.getLibsDir32bit
188    // 2. Extract amd64/x_ignore_nofocus.so to profile.getLibsDir64bit
189    // 3. Create a new LD_LIB_PATH string to contain:
190    // profile.getLibsDir32bit + ":" + profile.getLibsDir64bit
191
192    Set<String> pathsSet = new HashSet<>();
193    pathsSet.add(jarPath32Bit);
194    pathsSet.add(jarPath64Bit);
195
196    StringBuilder builtPath = new StringBuilder();
197
198    for (String path : pathsSet) {
199      try {
200
201        FileHandler.copyResource(profileDir, getClass(), path + File.separator + noFocusSoName);
202
203      } catch (IOException e) {
204        if (Boolean.getBoolean("webdriver.development")) {
205          System.err.println(
206              "Exception unpacking required library, but in development mode. Continuing");
207        } else {
208          throw new WebDriverException(e);
209        }
210      } // End catch.
211
212      String outSoPath = profileDir.getAbsolutePath() + File.separator + path;
213
214      File file = new File(outSoPath, noFocusSoName);
215      if (!file.exists()) {
216        throw new WebDriverException("Could not locate " + path + ": "
217                                     + "native events will not work.");
218      }
219
220      builtPath.append(outSoPath).append(":");
221    }
222
223    return builtPath.toString();
224  }
225
226  @Override
227  protected void waitUntilAvailable() throws MalformedURLException {
228    try {
229      // Use a longer timeout, because 45 seconds was the default timeout in the predecessor to
230      // XpiDriverService. This has to wait for Firefox to start, not just a service, and some users
231      // may be running tests on really slow machines.
232      URL status = new URL(getUrl(port).toString() + "/status");
233      new UrlChecker().waitUntilAvailable(45, SECONDS, status);
234    } catch (UrlChecker.TimeoutException e) {
235      throw new WebDriverException("Timed out waiting 45 seconds for Firefox to start.", e);
236    }
237  }
238
239  @Override
240  public void stop() {
241    super.stop();
242    profile.cleanTemporaryModel();
243    profile.clean(profileDir);
244  }
245
246  private void addWebDriverExtension(FirefoxProfile profile) {
247    if (profile.containsWebDriverExtension()) {
248      return;
249    }
250    profile.addExtension("webdriver", loadCustomExtension().orElse(loadDefaultExtension()));
251  }
252
253  private Optional<Extension> loadCustomExtension() {
254    String xpiProperty = System.getProperty(FirefoxDriver.SystemProperty.DRIVER_XPI_PROPERTY);
255    if (xpiProperty != null) {
256      File xpi = new File(xpiProperty);
257      return Optional.of(new FileExtension(xpi));
258    }
259    return Optional.empty();
260  }
261
262  private static Extension loadDefaultExtension() {
263    return new ClasspathExtension(
264        FirefoxProfile.class,
265        "/" + XpiDriverService.class.getPackage().getName().replace(".", "/") + "/webdriver.xpi");
266  }
267
268  /**
269   * Configures and returns a new {@link XpiDriverService} using the default configuration. In
270   * this configuration, the service will use the firefox executable identified by the
271   * {@link FirefoxDriver.SystemProperty#BROWSER_BINARY} system property on a free port.
272   *
273   * @return A new XpiDriverService using the default configuration.
274   */
275  public static XpiDriverService createDefaultService() {
276    try {
277      return new Builder().build();
278    } catch (WebDriverException e) {
279      throw new IllegalStateException(e.getMessage(), e.getCause());
280    }
281  }
282
283  @SuppressWarnings("unchecked")
284  static XpiDriverService createDefaultService(Capabilities caps) {
285    Builder builder = new Builder().usingAnyFreePort();
286
287    Stream.<Supplier<FirefoxProfile>>of(
288        () -> (FirefoxProfile) caps.getCapability(FirefoxDriver.PROFILE),
289        () -> { try {
290          return FirefoxProfile.fromJson((String) caps.getCapability(FirefoxDriver.PROFILE));
291        } catch (IOException ex) {
292          throw new RuntimeException(ex);
293        }},
294        // Don't believe IDEA, this lambda can't be replaced with a method reference!
295        () -> ((FirefoxOptions) caps).getProfile(),
296        () -> (FirefoxProfile) ((Map<String, Object>) caps.getCapability(FIREFOX_OPTIONS)).get("profile"),
297        () -> { try {
298          return FirefoxProfile.fromJson(
299              (String) ((Map<String, Object>) caps.getCapability(FIREFOX_OPTIONS)).get("profile"));
300        } catch (IOException ex) {
301          throw new RuntimeException(ex);
302        }},
303        () -> {
304          Map<String, Object> options = (Map<String, Object>) caps.getCapability(FIREFOX_OPTIONS);
305          FirefoxProfile toReturn = new FirefoxProfile();
306          ((Map<String, Object>) options.get("prefs")).forEach((key, value) -> {
307            if (value instanceof Boolean) { toReturn.setPreference(key, (Boolean) value); }
308            if (value instanceof Integer) { toReturn.setPreference(key, (Integer) value); }
309            if (value instanceof String) { toReturn.setPreference(key, (String) value); }
310          });
311          return toReturn;
312        })
313        .map(supplier -> {
314          try {
315            return supplier.get();
316          } catch (Exception e) {
317            return null;
318          }
319        })
320        .filter(Objects::nonNull)
321        .findFirst()
322        .ifPresent(builder::withProfile);
323
324    Object binary = caps.getCapability(FirefoxDriver.BINARY);
325    if (binary != null) {
326      FirefoxBinary actualBinary;
327      if (binary instanceof FirefoxBinary) {
328        actualBinary = (FirefoxBinary) binary;
329      } else if (binary instanceof String) {
330        actualBinary = new FirefoxBinary(new File(String.valueOf(binary)));
331      } else {
332        throw new IllegalArgumentException(
333            "Expected binary to be a string or a binary: " + binary);
334      }
335
336      builder.withBinary(actualBinary);
337    }
338
339    return builder.build();
340
341  }
342
343  public static Builder builder() {
344    return new Builder();
345  }
346
347  @AutoService(DriverService.Builder.class)
348  public static class Builder extends FirefoxDriverService.Builder<XpiDriverService, XpiDriverService.Builder> {
349
350    private FirefoxBinary binary = null;
351    private FirefoxProfile profile = null;
352
353    @Override
354    protected boolean isLegacy() {
355      return true;
356    }
357
358    @Override
359    public int score(Capabilities capabilities) {
360      if (capabilities.is(FirefoxDriver.MARIONETTE)) {
361        return 0;
362      }
363
364      int score = 0;
365
366      if (capabilities.getCapability(FirefoxDriver.BINARY) != null) {
367        score++;
368      }
369
370      if (capabilities.getCapability(FirefoxDriver.PROFILE) != null) {
371        score++;
372      }
373
374      return score;
375    }
376
377    public Builder withBinary(FirefoxBinary binary) {
378      this.binary = Preconditions.checkNotNull(binary);
379      return this;
380    }
381
382    public Builder withProfile(FirefoxProfile profile) {
383      this.profile = Preconditions.checkNotNull(profile);
384      return this;
385    }
386
387    @Override
388    protected FirefoxDriverService.Builder withOptions(FirefoxOptions options) {
389      FirefoxProfile profile = options.getProfile();
390      if (profile == null) {
391        profile = new FirefoxProfile();
392        options.setCapability(FirefoxDriver.PROFILE, profile);
393      }
394      withBinary(options.getBinary());
395      withProfile(profile);
396      return this;
397    }
398
399    @Override
400    protected File findDefaultExecutable() {
401      if (binary == null) {
402        return new FirefoxBinary().getFile();
403      }
404      return binary.getFile();
405    }
406
407    @Override
408    protected ImmutableList<String> createArgs() {
409      return ImmutableList.of("-foreground");
410    }
411
412    @Override
413    protected XpiDriverService createDriverService(
414        File exe,
415        int port,
416        ImmutableList<String> args,
417        ImmutableMap<String, String> environment) {
418      try {
419        return new XpiDriverService(
420            exe,
421            port,
422            args,
423            environment,
424            binary == null ? new FirefoxBinary() : binary,
425            profile == null ? new FirefoxProfile() : profile,
426            getLogFile());
427      } catch (IOException e) {
428        throw new WebDriverException(e);
429      }
430    }
431  }
432}
433
Full Screen

Accelerate Your Automation Test Cycles With LambdaTest

Leverage LambdaTest’s cloud-based platform to execute your automation tests in parallel and trim down your test execution time significantly. Your first 100 automation testing minutes are on us.

Try LambdaTest

Trigger getExtraOptions code on LambdaTest Cloud Grid

Execute automation tests with getExtraOptions on a cloud-based Grid of 3000+ real browsers and operating systems for both web and mobile applications.

Test now for Free
LambdaTestX

We use cookies to give you the best experience. Cookies help to provide a more personalized experience and relevant advertising for you, and web analytics for us. Learn More in our Cookies policy, Privacy & Terms of service

Allow Cookie