Skip to content

Commit

Permalink
Add a test to demonstrate that Proxy works
Browse files Browse the repository at this point in the history
The current state of using a Proxy is both well-defined and variously
implemented.

* Chrome and ChromeDriver uses just the HTTP field with a host:port.

* Firefox via GeckoDriver directly requires that the host be provided in
  the HTTP field and the port be provided in the HTTPPort field.

* Firefox via Selenium 2 uses just the HTTP field, with the caveat that
  connections to localhost are not proxied, by default. An additional
  preference is needed to unset this.

* Firefox via Selenium 3 and GeckoDriver fails because Selenium adds a
  whole bunch of "nulls" for unset values in the Proxy object, which
  Marionette does not like. mozilla/geckodriver#490

Fixes #41.
  • Loading branch information
minusnine committed Feb 27, 2017
1 parent 9d1dd83 commit 3302dc6
Show file tree
Hide file tree
Showing 4 changed files with 106 additions and 5 deletions.
3 changes: 3 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,9 @@ one.
implement this support](https://github.com/mozilla/geckodriver/issues/159).
Then, [Selenium 3 doesn't implement this support for
Firefox](https://github.com/SeleniumHQ/selenium/issues/2285).
5. [The Proxy object is
misinterpreted](https://github.com/mozilla/geckodriver/issues/490) by
Geckodriver when passed through by Selenium 3.

The Geckodriver team recommends using the newest available Firefox version, as
the integration is actively being developed.
Expand Down
86 changes: 85 additions & 1 deletion remote_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,12 @@ import (
"net"
"net/http"
"net/http/httptest"
"net/url"
"os"
"os/exec"
"path/filepath"
"reflect"
"strconv"
"strings"
"testing"
"time"
Expand Down Expand Up @@ -485,6 +487,7 @@ func runTests(t *testing.T, c config) {
t.Run("ResizeWindow", runTest(testResizeWindow, c))
t.Run("KeyDownUp", runTest(testKeyDownUp, c))
t.Run("CSSProperty", runTest(testCSSProperty, c))
t.Run("Proxy", runTest(testProxy, c))
}

func testStatus(t *testing.T, c config) {
Expand Down Expand Up @@ -750,7 +753,7 @@ func testFindElement(t *testing.T, c config) {

we, ok := elem.(*remoteWE)
if !ok {
t.Errorf("wd.FindElement(%q, %q) = %T, want a *remoteWE", tc.by, tc.query)
t.Errorf("wd.FindElement(%q, %q) = %T, want a *remoteWE", tc.by, tc.query, elem)
continue
}

Expand Down Expand Up @@ -1363,6 +1366,87 @@ func testCSSProperty(t *testing.T, c config) {
t.Fatalf(`e.CSSProperty("color") = %q, want one of %q`, color, wantColors)
}

func testProxy(t *testing.T, c config) {
const pageContents = "You are viewing a proxied page"
s := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
fmt.Fprintf(w, pageContents)
}))
defer s.Close()

u, err := url.Parse(s.URL)
if err != nil {
t.Fatalf("url.Parse(%q) returned error: %v", s.URL, err)
}

caps := newTestCapabilities(t, c)
proxy := Proxy{Type: Manual}
switch c.browser {
case "firefox":
switch c.seleniumVersion.Major {
case 0: // Geckodriver.
host, port, err := net.SplitHostPort(u.Host)
if err != nil {
t.Fatalf("net.SplitHostPort(%q) returned error: %v", u.Host, err)
}
p, err := strconv.Atoi(port)
if err != nil {
t.Fatalf("strconv.Atoi(%q) returned error: %v", port, err)
}
proxy.HTTP = host
proxy.HTTPPort = p
case 2:
proxy.HTTP = u.Host
case 3:
// When the Proxy object is passed through Selenium 3 to GeckoDriver, it
// adds a whole bunch of "null" values for empty entities. GeckoDriver
// does not interpret this well.
// https://github.com/mozilla/geckodriver/issues/490
t.Skip("Skipping test due to https://github.com/mozilla/geckodriver/issues/490")
}
// By default, Firefox explicitly does not use a proxy for connection to
// localhost and 127.0.0.1. Clear this preference to reach our test proxy.
ff, ok := caps[firefox.CapabilitiesKey].(firefox.Capabilities)
if ok { // Selenium 3.0.1 does not support Firefox capabilities.
if ff.Prefs == nil {
ff.Prefs = make(map[string]interface{})
}
ff.Prefs["network.proxy.no_proxies_on"] = ""
caps[firefox.CapabilitiesKey] = ff
}
case "chrome":
proxy.HTTP = u.Host
}
caps.AddProxy(proxy)

wd := &remoteWD{
capabilities: caps,
urlPrefix: c.addr,
}
defer func() {
if err := wd.Quit(); err != nil {
t.Fatalf("wd.Quit() returned error: %v", err)
}
}()
if _, err := wd.NewSession(); err != nil {
t.Fatalf("wd.NewSession() returned error: %v", err)
}

if err := wd.Get(serverURL); err != nil {
t.Fatalf("wd.Get(%q) returned error: %v", serverURL, err)
}
source, err := wd.PageSource()
if err != nil {
t.Fatalf("wd.PageSource() returned error: %v", err)
}

if !strings.Contains(source, pageContents) {
if strings.Contains(source, "Go Selenium Test Suite") {
t.Fatal("Got non-proxied page.")
}
t.Fatalf("Got page: %s\n\nExpected: %q", source, pageContents)
}
}

var homePage = `
<html>
<head>
Expand Down
18 changes: 16 additions & 2 deletions selenium.go
Original file line number Diff line number Diff line change
Expand Up @@ -104,16 +104,25 @@ func (c Capabilities) AddFirefox(f firefox.Capabilities) {
c[firefox.CapabilitiesKey] = f
}

// AddProxy adds proxy configuration to the capabilities.
func (c Capabilities) AddProxy(p Proxy) {
c["proxy"] = p
}

// Proxy specifies configuration for proxies in the browser. Set the key
// "proxy" in Capabilities to an instance of this type.
type Proxy struct {
// Type is the type of proxy to use. This is required to be populated.
Type ProxyType `json:"proxyType"`

// AutoconfigURL is the URL to be used for proxy auto configuration. This is
// required if Type is set to PAC.
AutoconfigURL string `json:"proxyAutoconfigUrl,omitempty"`

// The following are used when Type is set to Manual.
//
// Note that in Firefox, connections to localhost are not proxied by default,
// even if a proxy is set. This can be overrided via a preference setting.
FTP string `json:"ftpProxy,omitempty"`
HTTP string `json:"httpProxy,omitempty"`
SSL string `json:"sslProxy,omitempty"`
Expand All @@ -122,8 +131,13 @@ type Proxy struct {
SOCKSPassword string `json:"socksPassword,omitempty"`
NoProxy string `json:"noProxy,omitempty"`

// TODO(minusnine): The W3C draft spec includes port fields as well. Should
// they be added here?
// The W3C draft spec includes port fields as well. According to the
// specification, ports can also be included in the above addresses. However,
// in the Geckodriver implementation, the ports must be specified by these
// additional fields.
HTTPPort int `json:"httpProxyPort,omitempty"`
SSLPort int `json:"sslProxyPort,omitempty"`
SocksPort int `json:"socksProxyPort,omitempty"`
}

// ProxyType is an enumeration of the types of proxies available.
Expand Down
4 changes: 2 additions & 2 deletions vendor/init.go
Original file line number Diff line number Diff line change
Expand Up @@ -64,9 +64,9 @@ var files = []file{
},
{
// This is a recent nightly. Update this path periodically.
url: "https://archive.mozilla.org/pub/firefox/nightly/2017/02/2017-02-14-11-02-12-mozilla-central/firefox-54.0a1.en-US.linux-x86_64.tar.bz2",
url: "https://archive.mozilla.org/pub/firefox/nightly/2017/02/2017-02-15-11-01-51-mozilla-central/firefox-54.0a1.en-US.linux-x86_64.tar.bz2",
name: "firefox-54.0a1.en-US.linux-x86_64.tar.bz2",
hash: "df3dcecbb630ca662851160b4d619a11c3ab52a8ceb238eb00e522248a3890ee",
hash: "1d2a066308b9c31adc8fe6f9ce92e6cb503e004141b4ca8b7a50f74632ae7aed",
browser: true,
rename: []string{"firefox", "firefox-nightly"},
},
Expand Down

0 comments on commit 3302dc6

Please sign in to comment.