-
Notifications
You must be signed in to change notification settings - Fork 11
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
define the structure of autogcd
- Loading branch information
Showing
8 changed files
with
663 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,137 @@ | ||
package autogcd | ||
|
||
import ( | ||
"github.com/wirepair/gcd" | ||
"sync" | ||
) | ||
|
||
type AutoGcd struct { | ||
debugger *gcd.Gcd | ||
settings *Settings | ||
tabLock *sync.RWMutex | ||
tabs map[string]*Tab | ||
} | ||
|
||
func NewAutoGcd(settings *Settings) *AutoGcd { | ||
auto := &AutoGcd{settings: settings} | ||
auto.tabLock = &sync.RWMutex{} | ||
auto.tabs = make(map[string]*Tab) | ||
auto.debugger = gcd.NewChromeDebugger() | ||
|
||
if len(settings.extensions) > 0 { | ||
auto.debugger.AddFlags(settings.extensions) | ||
} | ||
|
||
if len(settings.flags) > 0 { | ||
auto.debugger.AddFlags(settings.flags) | ||
} | ||
|
||
if settings.timeout > 0 { | ||
auto.debugger.SetTimeout(settings.timeout) | ||
} | ||
|
||
if settings.chromeHost != "" { | ||
auto.debugger.SetHost(settings.chromeHost) | ||
} | ||
|
||
return auto | ||
} | ||
|
||
func (auto *AutoGcd) Start() error { | ||
var tabs []*gcd.ChromeTarget | ||
var err error | ||
auto.debugger.StartProcess(auto.settings.chromePath, auto.settings.userDir, auto.settings.chromePort) | ||
|
||
tabs, err = auto.debugger.GetTargets() | ||
if err != nil { | ||
return err | ||
} | ||
|
||
auto.tabLock.Lock() | ||
for _, tab := range tabs { | ||
auto.tabs[tab.Target.Id] = NewTab(tab) | ||
} | ||
auto.tabLock.Unlock() | ||
return nil | ||
} | ||
|
||
// Returns the first "visual" tab. | ||
func (auto *AutoGcd) GetTab() (*Tab, error) { | ||
auto.tabLock.RLock() | ||
defer auto.tabLock.RUnlock() | ||
for _, tab := range auto.tabs { | ||
if tab.Target.Type == "page" { | ||
return tab, nil | ||
} | ||
} | ||
return nil, &InvalidTabErr{Message: "no Page tab types found"} | ||
} | ||
|
||
// Returns a safe copy of tabs | ||
func (auto *AutoGcd) GetAllTabs() map[string]*Tab { | ||
auto.tabLock.RLock() | ||
defer auto.tabLock.RUnlock() | ||
tabs := make(map[string]*Tab) | ||
for id, tab := range auto.tabs { | ||
tabs[id] = tab | ||
} | ||
return tabs | ||
} | ||
|
||
// Activate the tab in the chrome UI | ||
func (auto *AutoGcd) ActivateTab(tab *Tab) error { | ||
return auto.debugger.ActivateTab(tab.ChromeTarget) | ||
} | ||
|
||
// Activate the tab in the chrome UI, by tab id | ||
func (auto *AutoGcd) ActivateTabById(id string) error { | ||
tab, err := auto.tabById(id) | ||
if err != nil { | ||
return err | ||
} | ||
return auto.ActivateTab(tab) | ||
} | ||
|
||
// Creates a new tab | ||
func (auto *AutoGcd) NewTab() (*Tab, error) { | ||
target, err := auto.debugger.NewTab() | ||
if err != nil { | ||
return nil, &InvalidTabErr{Message: "unable to create tab: " + err.Error()} | ||
} | ||
auto.tabLock.Lock() | ||
defer auto.tabLock.Unlock() | ||
|
||
tab := NewTab(target) | ||
auto.tabs[target.Target.Id] = tab | ||
return tab, nil | ||
} | ||
|
||
func (auto *AutoGcd) CloseTab(tab *Tab) error { | ||
if err := auto.debugger.CloseTab(tab.ChromeTarget); err != nil { | ||
return err | ||
} | ||
auto.tabLock.Lock() | ||
defer auto.tabLock.Unlock() | ||
|
||
delete(auto.tabs, tab.Target.Id) | ||
return nil | ||
} | ||
|
||
func (auto *AutoGcd) CloseTabById(id string) error { | ||
tab, err := auto.tabById(id) | ||
if err != nil { | ||
return err | ||
} | ||
auto.CloseTab(tab) | ||
return nil | ||
} | ||
|
||
func (auto *AutoGcd) tabById(id string) (*Tab, error) { | ||
auto.tabLock.RLock() | ||
tab := auto.tabs[id] | ||
auto.tabLock.RUnlock() | ||
if tab == nil { | ||
return nil, &InvalidTabErr{"unknown tab id " + id} | ||
} | ||
return tab, nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,109 @@ | ||
package autogcd | ||
|
||
import ( | ||
"flag" | ||
"os" | ||
"testing" | ||
) | ||
|
||
var ( | ||
testPath string | ||
testDir string | ||
testPort string | ||
) | ||
|
||
func init() { | ||
flag.StringVar(&testPath, "chrome", "C:\\Program Files (x86)\\Google\\Chrome\\Application\\chrome.exe", "path to Xvfb") | ||
flag.StringVar(&testDir, "dir", "C:\\temp\\", "user directory") | ||
flag.StringVar(&testPort, "port", "9222", "Debugger port") | ||
} | ||
|
||
func TestMain(m *testing.M) { | ||
flag.Parse() | ||
ret := m.Run() | ||
testCleanUp() | ||
os.Exit(ret) | ||
} | ||
|
||
func testCleanUp() { | ||
|
||
} | ||
|
||
func TestStart(t *testing.T) { | ||
s := NewSettings(testPath, testDir, testPort) | ||
s.SetStartTimeout(15) | ||
s.SetChromeHost("localhost") | ||
auto := NewAutoGcd(s) | ||
if err := auto.Start(); err != nil { | ||
t.Fatalf("failed to start chrome: %s\n", err) | ||
} | ||
auto.debugger.ExitProcess() | ||
} | ||
|
||
func TestGetTab(t *testing.T) { | ||
var err error | ||
var tab *Tab | ||
auto := testDefaultStartup(t) | ||
tab, err = auto.GetTab() | ||
if err != nil { | ||
t.Fatalf("Error getting tab: %s\n", err) | ||
} | ||
|
||
if tab.Target.Type != "page" { | ||
t.Fatalf("Got tab but wasn't of type Page") | ||
} | ||
auto.debugger.ExitProcess() | ||
} | ||
|
||
func TestNewTab(t *testing.T) { | ||
var err error | ||
//var newTab *Tab | ||
auto := testDefaultStartup(t) | ||
tabLen := len(auto.tabs) | ||
_, err = auto.NewTab() | ||
if err != nil { | ||
t.Fatalf("error creating new tab: %s\n", err) | ||
} | ||
|
||
if tabLen+1 != len(auto.tabs) { | ||
t.Fatalf("error created new tab but not reflected in our map") | ||
} | ||
|
||
auto.debugger.ExitProcess() | ||
} | ||
|
||
func TestCloseTab(t *testing.T) { | ||
var err error | ||
var newTab *Tab | ||
auto := testDefaultStartup(t) | ||
tabLen := len(auto.tabs) | ||
|
||
newTab, err = auto.NewTab() | ||
if err != nil { | ||
t.Fatalf("error creating new tab: %s\n", err) | ||
} | ||
|
||
if tabLen+1 != len(auto.tabs) { | ||
t.Fatalf("error created new tab but not reflected in our map") | ||
} | ||
|
||
err = auto.CloseTab(newTab) | ||
if err != nil { | ||
t.Fatalf("error closing tab") | ||
} | ||
|
||
if _, err := auto.tabById(newTab.Target.Id); err == nil { | ||
t.Fatalf("error closed tab still in our map") | ||
} | ||
|
||
auto.debugger.ExitProcess() | ||
} | ||
|
||
func testDefaultStartup(t *testing.T) *AutoGcd { | ||
s := NewSettings(testPath, testDir, testPort) | ||
auto := NewAutoGcd(s) | ||
if err := auto.Start(); err != nil { | ||
t.Fatalf("failed to start chrome: %s\n", err) | ||
} | ||
return auto | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,69 @@ | ||
package autogcd | ||
|
||
import ( | ||
"github.com/wirepair/gcd/gcdprotogen/types" | ||
) | ||
|
||
type InvalidDimensionsErr struct { | ||
Message string | ||
} | ||
|
||
func (e *InvalidDimensionsErr) Error() string { | ||
return "invalid dimensions " + e.Message | ||
} | ||
|
||
type Element struct { | ||
tab *Tab // reference to the containing tab | ||
id *types.ChromeDOMNodeId // nodeId in chrome | ||
} | ||
|
||
func newElement(tab *Tab, id int) *Element { | ||
nodeId := types.ChromeDOMNodeId(id) | ||
e := &Element{} | ||
e.tab = tab | ||
e.id = &nodeId | ||
return e | ||
} | ||
|
||
func (e *Element) Click() error { | ||
var x int | ||
var y int | ||
|
||
points, err := e.Dimensions() | ||
if err != nil { | ||
return err | ||
} | ||
|
||
x, y, err = centroid(points) | ||
if err != nil { | ||
return err | ||
} | ||
// click the centroid of the element. | ||
return e.tab.Click(x, y) | ||
} | ||
|
||
func (e *Element) Dimensions() ([]float64, error) { | ||
var points []float64 | ||
box, err := e.tab.DOM().GetBoxModel(e.id) | ||
if err != nil { | ||
return nil, err | ||
} | ||
points = *box.Content | ||
return points, nil | ||
} | ||
|
||
// finds the centroid of an arbitrary number of points. | ||
// Assumes points[i] = x, points[i+1] = y. | ||
func centroid(points []float64) (int, int, error) { | ||
pointLen := len(points) | ||
if pointLen%2 != 0 { | ||
return -1, -1, &InvalidDimensionsErr{"number of points are not divisible by two"} | ||
} | ||
x := 0 | ||
y := 0 | ||
for i := 0; i < pointLen; i = i + 2 { | ||
x += int(points[i]) | ||
y += int(points[i+1]) | ||
} | ||
return x / pointLen, y / pointLen, nil | ||
} |
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
package autogcd | ||
|
||
import ( | ||
"fmt" | ||
"time" | ||
) | ||
|
||
type Settings struct { | ||
timeout time.Duration | ||
chromePath string | ||
chromeHost string | ||
chromePort string | ||
userDir string | ||
extensions []string | ||
flags []string | ||
} | ||
|
||
func NewSettings(chromePath, userDir, chromePort string) *Settings { | ||
s := &Settings{} | ||
s.chromePath = chromePath | ||
s.chromePort = chromePort | ||
s.userDir = userDir | ||
s.extensions = make([]string, 0) | ||
s.flags = make([]string, 0) | ||
return s | ||
} | ||
|
||
func (s *Settings) SetChromeHost(host string) { | ||
s.chromeHost = host | ||
} | ||
|
||
func (s *Settings) SetStartTimeout(timeout time.Duration) { | ||
s.timeout = timeout | ||
} | ||
|
||
func (s *Settings) AddStartupFlags(flags []string) { | ||
s.flags = append(s.flags, flags...) | ||
} | ||
|
||
func (s *Settings) AddExtension(path string) { | ||
s.extensions = append(s.extensions, fmt.Sprintf("--load-extension=%s", path)) | ||
} |
Oops, something went wrong.