Skip to content
This repository has been archived by the owner on Aug 14, 2019. It is now read-only.

Commit

Permalink
Merge pull request #5 from schwartzmx/integrationtest
Browse files Browse the repository at this point in the history
set up some integration tests with gremlin docker
  • Loading branch information
schwartzmx committed Jun 8, 2019
2 parents a89dc0c + ab8ce18 commit 2e6f3cd
Show file tree
Hide file tree
Showing 16 changed files with 321 additions and 13 deletions.
5 changes: 4 additions & 1 deletion .gitignore
@@ -1,4 +1,7 @@
vendor/


gremgo-neptune
gremgo-neptune


debug.test
13 changes: 12 additions & 1 deletion .travis.yml
Expand Up @@ -4,10 +4,21 @@ go:
- 1.11.x
- master

services:
- docker

before_install:
- docker build -t gremgo-neptune/gremlin-server -f ./Dockerfile.gremlin .
- docker run -d -p 8182:8182 -t gremgo-neptune/gremlin-server
- docker ps -a

before_script:
- go vet ./...

env:
- GO111MODULE=on

install: true
install: true

notifications:
email: false
1 change: 1 addition & 0 deletions Dockerfile.gremlin
@@ -0,0 +1 @@
FROM tinkerpop/gremlin-server
21 changes: 21 additions & 0 deletions Makefile
@@ -0,0 +1,21 @@
.DEFAULT_GOAL:= all

.PHONY: all
all: vet test

.PHONY: vet
vet:
@go vet -v

.PHONY: test
test:
@go test -v

.PHONY: test-bench
test-bench:
@go test -bench=. -race

.PHONY: gremlin
gremlin:
@docker build -t gremgo-neptune/gremlin-server -f ./Dockerfile.gremlin .
@docker run -p 8182:8182 -t gremgo-neptune/gremlin-server
4 changes: 2 additions & 2 deletions README.md
Expand Up @@ -45,7 +45,7 @@ func main() {
fmt.Println(err)
return
}
res, err := g.Execute( // Sends a query to Gremlin Server with bindings
res, err := g.Execute( // Sends a query to Gremlin Server
"g.V('1234')"
)
if err != nil {
Expand Down Expand Up @@ -90,7 +90,7 @@ func main() {
fmt.Println(err)
return
}
res, err := g.Execute( // Sends a query to Gremlin Server with bindings
res, err := g.Execute( // Sends a query to Gremlin Server
"g.V('1234')"
)
if err != nil {
Expand Down
23 changes: 19 additions & 4 deletions client.go
Expand Up @@ -16,8 +16,8 @@ type Client struct {
responses chan []byte
results *sync.Map
responseNotifier *sync.Map // responseNotifier notifies the requester that a response has arrived for the request
mu sync.RWMutex
Errored bool
sync.RWMutex
Errored bool
}

// NewDialer returns a WebSocket dialer to use when connecting to Gremlin Server
Expand Down Expand Up @@ -128,8 +128,8 @@ func (c *Client) Execute(query string) (resp []Response, err error) {
return
}

// ExecuteFile takes a file path to a Gremlin script, sends it to Gremlin Server, and returns the result.
func (c *Client) ExecuteFile(path string, bindings, rebindings map[string]string) (resp []Response, err error) {
// ExecuteFileWithBindings takes a file path to a Gremlin script, sends it to Gremlin Server with bindings, and returns the result.
func (c *Client) ExecuteFileWithBindings(path string, bindings, rebindings map[string]string) (resp []Response, err error) {
if c.conn.IsDisposed() {
return resp, errors.New("you cannot write on disposed connection")
}
Expand All @@ -143,6 +143,21 @@ func (c *Client) ExecuteFile(path string, bindings, rebindings map[string]string
return
}

// ExecuteFile takes a file path to a Gremlin script, sends it to Gremlin Server, and returns the result.
func (c *Client) ExecuteFile(path string) (resp []Response, err error) {
if c.conn.IsDisposed() {
return resp, errors.New("you cannot write on disposed connection")
}
d, err := ioutil.ReadFile(path) // Read script from file
if err != nil {
log.Println(err)
return
}
query := string(d)
resp, err = c.executeRequest(query, nil, nil)
return
}

// Close closes the underlying connection and marks the client as closed.
func (c *Client) Close() {
if c.conn != nil {
Expand Down
6 changes: 3 additions & 3 deletions connection.go
Expand Up @@ -136,15 +136,15 @@ func (c *Client) writeWorker(errs chan error, quit chan struct{}) { // writeWork
for {
select {
case msg := <-c.requests:
c.mu.Lock()
c.Lock()
err := c.conn.write(msg)
if err != nil {
errs <- err
c.Errored = true
c.mu.Unlock()
c.Unlock()
break
}
c.mu.Unlock()
c.Unlock()

case <-quit:
return
Expand Down
2 changes: 2 additions & 0 deletions go.mod
Expand Up @@ -2,6 +2,8 @@ module gremgo

require (
github.com/gorilla/websocket v1.2.0
github.com/kr/pretty v0.1.0 // indirect
github.com/pkg/errors v0.8.1
github.com/satori/go.uuid v1.2.0
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 // indirect
)
7 changes: 7 additions & 0 deletions go.sum
@@ -1,6 +1,13 @@
github.com/gorilla/websocket v1.2.0 h1:VJtLvh6VQym50czpZzx07z/kw9EgAxI3x1ZB8taTMQQ=
github.com/gorilla/websocket v1.2.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I=
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/satori/go.uuid v1.2.0 h1:0uYX9dsZ2yD7q2RtLRtPSdGDWzjeM3TbMJP9utgA0ww=
github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
31 changes: 31 additions & 0 deletions gremgo_neptune_benchmark_test.go
@@ -0,0 +1,31 @@
package gremgo

import (
"testing"
)

func init() {
InitGremlinClients()
t := testing.T{}
seedData(&t)

}

func benchmarkPoolExecute(i int, b *testing.B) {
for n := 0; n < i; n++ {
go func(p *Pool) {
_, err := p.Execute(`g.V('1234').label()`)
if err != nil {
b.Error(err)
}
}(gp)
}
}

func BenchmarkPoolExecute1(b *testing.B) { benchmarkPoolExecute(1, b) }
func BenchmarkPoolExecute5(b *testing.B) { benchmarkPoolExecute(5, b) }
func BenchmarkPoolExecute10(b *testing.B) { benchmarkPoolExecute(10, b) }
func BenchmarkPoolExecute20(b *testing.B) { benchmarkPoolExecute(20, b) }
func BenchmarkPoolExecute40(b *testing.B) { benchmarkPoolExecute(40, b) }
func BenchmarkPoolExecute80(b *testing.B) { benchmarkPoolExecute(80, b) }
func BenchmarkPoolExecute160(b *testing.B) { benchmarkPoolExecute(160, b) }
133 changes: 133 additions & 0 deletions gremgo_neptune_test.go
@@ -0,0 +1,133 @@
package gremgo

import (
"encoding/json"
"testing"
)

func init() {
InitGremlinClients()
}

func truncateData(t *testing.T) {
t.Logf("Removing all data from gremlin server")
r, err := g.Execute(`g.V().drop().iterate()`)
t.Logf("Removed all vertices, response: %v+ \n err: %s", r, err)
if err != nil {
t.Fatal(err)
}
}

func seedData(t *testing.T) {
truncateData(t)
t.Logf("Seeding data...")
r, err := g.Execute(`
g.addV('Phil').property(id, '1234').
property('timestamp', '2018-07-01T13:37:45-05:00').
property('source', 'tree').
as('x').
addV('Vincent').property(id, '2145').
property('timestamp', '2018-07-01T13:37:45-05:00').
property('source', 'tree').
as('y').
addE('brother').
from('x').
to('y')
`)
t.Logf("Added two vertices and one edge, response: %v+ \n err: %s", r, err)
if err != nil {
t.Fatal(err)
}
}

type nodeLabels struct {
Label []string `json:"@value"`
}

func TestExecute(t *testing.T) {
seedData(t)
r, err := g.Execute(`g.V('1234').label()`)
t.Logf("Execute get vertex, response: %s \n err: %s", r[0].Result.Data, err)
nl := new(nodeLabels)
err = json.Unmarshal(r[0].Result.Data, &nl)
if len(nl.Label) != 1 {
t.Errorf("There should only be 1 node label, got: %v+", nl)
}
expected := "Phil"
got := nl.Label[0]
if nl.Label[0] != expected {
t.Errorf("Unexpected label returned, expected: %s got: %s", expected, got)
}
}

func TestExecuteWithBindings(t *testing.T) {
seedData(t)
r, err := g.ExecuteWithBindings(
`g.V(x).label()`,
map[string]string{"x": "1234"},
map[string]string{},
)
t.Logf("Execute with bindings get vertex, response: %s \n err: %s", r[0].Result.Data, err)
nl := new(nodeLabels)
err = json.Unmarshal(r[0].Result.Data, &nl)
if len(nl.Label) != 1 {
t.Errorf("There should only be 1 node label, got: %v+", nl)
}
expected := "Phil"
got := nl.Label[0]
if nl.Label[0] != expected {
t.Errorf("Unexpected label returned, expected: %s got: %s", expected, got)
}
}

func TestExecuteFile(t *testing.T) {
seedData(t)
r, err := g.ExecuteFile("scripts/test.groovy")
t.Logf("ExecuteFile get vertex, response: %s \n err: %s", r[0].Result.Data, err)
nl := new(nodeLabels)
err = json.Unmarshal(r[0].Result.Data, &nl)
if len(nl.Label) != 1 {
t.Errorf("There should only be 1 node label, got: %v+", nl)
}
expected := "Vincent"
got := nl.Label[0]
if nl.Label[0] != expected {
t.Errorf("Unexpected label returned, expected: %s got: %s", expected, got)
}
}

func TestExecuteFileWithBindings(t *testing.T) {
seedData(t)
r, err := g.ExecuteFileWithBindings(
"scripts/test-wbindings.groovy",
map[string]string{"x": "2145"},
map[string]string{},
)
t.Logf("ExecuteFileWithBindings get vertex, response: %s \n err: %s", r[0].Result.Data, err)
nl := new(nodeLabels)
err = json.Unmarshal(r[0].Result.Data, &nl)
if len(nl.Label) != 1 {
t.Errorf("There should only be 1 node label, got: %v+", nl)
}
expected := "Vincent"
got := nl.Label[0]
if nl.Label[0] != expected {
t.Errorf("Unexpected label returned, expected: %s got: %s", expected, got)
}
}

func TestPoolExecute(t *testing.T) {
seedData(t)
r, err := gp.Execute(`g.V('1234').label()`)
t.Logf("PoolExecute get vertex, response: %s \n err: %s", r[0].Result.Data, err)
nl := new(nodeLabels)
err = json.Unmarshal(r[0].Result.Data, &nl)
if len(nl.Label) != 1 {
t.Errorf("There should only be 1 node label, got: %v+", nl)
}
expected := "Phil"
got := nl.Label[0]
if nl.Label[0] != expected {
t.Errorf("Unexpected label returned, expected: %s got: %s", expected, got)
}
}
59 changes: 59 additions & 0 deletions gremgo_neptune_test_util.go
@@ -0,0 +1,59 @@
package gremgo

import (
"fmt"
"log"
"time"
)

var g *Client
var errs = make(chan error)
var gp *Pool
var gperrs = make(chan error)

// InitGremlinClients intializes gremlin client and pool for use by tests
func InitGremlinClients() {
go func(chan error) {
err := <-errs
log.Fatal("Lost connection to the database: " + err.Error())
}(errs)
go func(chan error) {
err := <-gperrs
log.Fatal("Lost connection to the database: " + err.Error())
}(errs)
initClient()
initPool()
}

func initClient() {
if g != nil {
return
}
var err error
dialer := NewDialer("ws://127.0.0.1:8182")
r, err := Dial(dialer, errs)
if err != nil {
fmt.Println(err)
}
g = &r
}

func initPool() {
if gp != nil {
return
}
dialFn := func() (*Client, error) {
dialer := NewDialer("ws://127.0.0.1:8182")
c, err := Dial(dialer, gperrs)
if err != nil {
log.Fatal(err)
}
return &c, err
}
pool := Pool{
Dial: dialFn,
MaxActive: 10,
IdleTimeout: time.Duration(10 * time.Second),
}
gp = &pool
}

0 comments on commit 2e6f3cd

Please sign in to comment.