diff --git a/gremlin-go/Dockerfile b/gremlin-go/Dockerfile index 39622b256dd..d010366dc83 100644 --- a/gremlin-go/Dockerfile +++ b/gremlin-go/Dockerfile @@ -15,23 +15,34 @@ # specific language governing permissions and limitations # under the License. -ARG GREMLIN_SERVER_VERSION=${version:-3.5.4} -FROM tinkerpop/gremlin-server:${GREMLIN_SERVER_VERSION}-SNAPSHOT +ARG GREMLIN_SERVER_VERSION +FROM tinkerpop/gremlin-server:${GREMLIN_SERVER_VERSION:-3.5.4-SNAPSHOT} USER root RUN mkdir -p /opt WORKDIR /opt COPY gremlin-server/src/test /opt/test/ +COPY gremlin-go/docker/generate-all.groovy /opt/test/scripts/ COPY gremlin-go/docker/docker-entrypoint.sh gremlin-go/docker/*.yaml /opt/ RUN chmod 755 /opt/docker-entrypoint.sh -# Setting to 3.5.3 does gives error even when using outside of Docker. -ENV NEO4J_VERSION=${version:-3.5.2} +# Installing dos2unix to avoid errors in running the entrypoint script on Windows machines where their +# carriage return is \r\n instead of the \n needed for linux/unix containers +RUN apk update && apk add dos2unix +RUN dos2unix /opt/docker-entrypoint.sh && apk del dos2unix + +ARG NEO4J_VERSION # Installs Neo4j libraries to this image so that we can test variants with transactions, # but only only port 45940 is configured with the neo4j graph as the neo4j-empty.properties # is statically pointing at a temp directory and that space can only be accessed by one # graph at a time. -RUN /opt/gremlin-server/bin/gremlin-server.sh install org.apache.tinkerpop neo4j-gremlin $NEO4J_VERSION +RUN /opt/gremlin-server/bin/gremlin-server.sh install org.apache.tinkerpop neo4j-gremlin ${NEO4J_VERSION:-3.5.4} + +# Gremlin server and neo4j versions are set to 3.5.4 by default, to change their versions, add args under the +# docker-compose build step, e.g.: +# args: +# GREMLIN_SERVER_VERSION: 3.5.x-SNAPSHOT +# NEO4J_VERSION: 3.5.x EXPOSE 45940 45941 diff --git a/gremlin-go/docker-compose.yml b/gremlin-go/docker-compose.yml index 9c2a15d31c2..da379abb0e2 100644 --- a/gremlin-go/docker-compose.yml +++ b/gremlin-go/docker-compose.yml @@ -24,6 +24,8 @@ services: build: context: ../ dockerfile: gremlin-go/Dockerfile + args: + NEO4J_VERSION: 3.5.3 ports: - "45940:45940" - "45941:45941" @@ -45,6 +47,6 @@ services: working_dir: /go_app command: > bash -c "go install github.com/haveyoudebuggedit/gotestfmt/v2/cmd/gotestfmt@latest - && go test -p 1 -v -json ./... -race -covermode=atomic -coverprofile=\"coverage.out\" -coverpkg=./... | gotestfmt" + && go test -v -json ./... -race -covermode=atomic -coverprofile=\"coverage.out\" -coverpkg=./... | gotestfmt" depends_on: - gremlin-test-server diff --git a/gremlin-go/docker/generate-all.groovy b/gremlin-go/docker/generate-all.groovy new file mode 100644 index 00000000000..8383b3b639d --- /dev/null +++ b/gremlin-go/docker/generate-all.groovy @@ -0,0 +1,79 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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. + */ + +// An example of an initialization script that can be configured to run in Gremlin Server. +// Functions defined here will go into global cache and will not be removed from there +// unless there is a reset of the ScriptEngine. +def addItUp(x, y) { x + y } + +// an init script that returns a Map allows explicit setting of global bindings. +def globals = [:] + +// Generates the modern graph into an "empty" TinkerGraph via LifeCycleHook. +// Note that the name of the key in the "global" map is unimportant. +globals << [hook : [ + onStartUp: { ctx -> + // a wild bit of trickery here. the process tests use an INTEGER id manager when LoadGraphWith is used. this + // closure provides a way to to manually override the various id managers for TinkerGraph - the graph on which + // all of these remote tests are executed - so that the tests will pass nicely. an alternative might have been + // to have a special test TinkerGraph config for setting up the id manager properly, but based on how we do + // things now, that test config would have been mixed in with release artifacts and there would have been ugly + // exclusions to make packaging work properly. + allowSetOfIdManager = { graph, idManagerFieldName -> + java.lang.reflect.Field idManagerField = graph.class.getDeclaredField(idManagerFieldName) + idManagerField.setAccessible(true) + java.lang.reflect.Field modifiersField = java.lang.reflect.Field.class.getDeclaredField("modifiers") + modifiersField.setAccessible(true) + modifiersField.setInt(idManagerField, modifiersField.getModifiers() & ~java.lang.reflect.Modifier.FINAL) + + idManagerField.set(graph, TinkerGraph.DefaultIdManager.INTEGER) + } + + [classic, modern, crew, sink, grateful, test].each{ + allowSetOfIdManager(it, "vertexIdManager") + allowSetOfIdManager(it, "edgeIdManager") + allowSetOfIdManager(it, "vertexPropertyIdManager") + } + TinkerFactory.generateClassic(classic) + TinkerFactory.generateModern(modern) + TinkerFactory.generateTheCrew(crew) + TinkerFactory.generateGratefulDead(grateful) + TinkerFactory.generateKitchenSink(sink) + TinkerFactory.generateModern(test) + } +] as LifeCycleHook] + +// add default TraversalSource instances for each graph instance +globals << [gclassic : traversal().withEmbedded(classic).withStrategies(ReferenceElementStrategy)] +globals << [gmodern : traversal().withEmbedded(modern).withStrategies(ReferenceElementStrategy)] +globals << [gtest : traversal().withEmbedded(test).withStrategies(ReferenceElementStrategy)] +globals << [g : traversal().withEmbedded(graph).withStrategies(ReferenceElementStrategy)] +globals << [gcrew : traversal().withEmbedded(crew).withStrategies(ReferenceElementStrategy)] +globals << [ggraph : traversal().withEmbedded(graph).withStrategies(ReferenceElementStrategy)] +globals << [ggrateful : traversal().withEmbedded(grateful).withStrategies(ReferenceElementStrategy)] +globals << [gsink : traversal().withEmbedded(sink).withStrategies(ReferenceElementStrategy)] + +// dynamically detect existence of gtx as it may or may not be present depending on the -DincludeNeo4j +// and the configuration of the particular server instance. with docker/gremlin-server.sh the neo4j +// "tx" configuration is already present and will therefore be enabled. +def dynamicGtx = context.getBindings(javax.script.ScriptContext.GLOBAL_SCOPE)["tx"] +if (dynamicGtx != null) + globals << [gtx : traversal().withEmbedded(dynamicGtx).withStrategies(ReferenceElementStrategy)] + +globals diff --git a/gremlin-go/docker/gremlin-server-integration-secure.yaml b/gremlin-go/docker/gremlin-server-integration-secure.yaml index 15b1b3e6479..fb1d8abdbea 100644 --- a/gremlin-go/docker/gremlin-server-integration-secure.yaml +++ b/gremlin-go/docker/gremlin-server-integration-secure.yaml @@ -20,6 +20,7 @@ port: 45941 evaluationTimeout: 30000 graphs: { graph: conf/tinkergraph-empty.properties, + test: conf/tinkergraph-empty.properties, classic: conf/tinkergraph-empty.properties, modern: conf/tinkergraph-empty.properties, crew: conf/tinkergraph-empty.properties, diff --git a/gremlin-go/docker/gremlin-server-integration.yaml b/gremlin-go/docker/gremlin-server-integration.yaml index 00f614fbd6b..ff2626bd9db 100644 --- a/gremlin-go/docker/gremlin-server-integration.yaml +++ b/gremlin-go/docker/gremlin-server-integration.yaml @@ -20,6 +20,7 @@ port: 45940 evaluationTimeout: 30000 graphs: { graph: conf/tinkergraph-empty.properties, + test: conf/tinkergraph-empty.properties, classic: conf/tinkergraph-empty.properties, modern: conf/tinkergraph-empty.properties, crew: conf/tinkergraph-empty.properties, diff --git a/gremlin-go/driver/connection_test.go b/gremlin-go/driver/connection_test.go index 58802e2b1c4..2c76c94e89f 100644 --- a/gremlin-go/driver/connection_test.go +++ b/gremlin-go/driver/connection_test.go @@ -41,18 +41,16 @@ const integrationTestSuiteName = "integration" const basicAuthIntegrationTestSuite = "basic authentication integration" const validHostInvalidPortValidPath = "ws://localhost:12341253/gremlin" const invalidHostValidPortValidPath = "ws://invalidhost:8182/gremlin" -const validHostValidPortInvalidPath = "ws://localhost:8182/invalid" const testServerModernGraphAlias = "gmodern" +const testServerGraphAlias = "gtest" const manualTestSuiteName = "manual" const nonRoutableIPForConnectionTimeout = "ws://10.255.255.1/" // transaction is enabled on the same port as no auth url const noAuthUrl = "ws://localhost:45940/gremlin" -const basicAuthNoSsl = "ws://localhost:45941/gremlin" const basicAuthWithSsl = "wss://localhost:45941/gremlin" var testNames = []string{"Lyndon", "Yang", "Simon", "Rithin", "Alexey", "Valentyn"} -var mu sync.Mutex func newDefaultConnectionSettings() *connectionSettings { return &connectionSettings{ @@ -90,16 +88,23 @@ func addTestData(t *testing.T, g *GraphTraversalSource) { assert.Nil(t, <-promise) } -func initializeGraph(t *testing.T, url string, auth *AuthInfo, tls *tls.Config) *GraphTraversalSource { +func getTestGraph(t *testing.T, url string, auth *AuthInfo, tls *tls.Config) *GraphTraversalSource { remote, err := NewDriverRemoteConnection(url, func(settings *DriverRemoteConnectionSettings) { settings.TlsConfig = tls settings.AuthInfo = auth + settings.TraversalSource = testServerGraphAlias }) assert.Nil(t, err) assert.NotNil(t, remote) g := Traversal_().WithRemote(remote) + return g +} + +func initializeGraph(t *testing.T, url string, auth *AuthInfo, tls *tls.Config) *GraphTraversalSource { + g := getTestGraph(t, url, auth, tls) + // Drop the graph and check that it is empty. dropGraph(t, g) readCount(t, g, "", 0) @@ -325,9 +330,6 @@ func TestConnection(t *testing.T) { }) t.Run("Test DriverRemoteConnection GraphTraversal", func(t *testing.T) { - mu.Lock() - defer mu.Unlock() - skipTestsIfNotEnabled(t, integrationTestSuiteName, testNoAuthEnable) // Initialize graph @@ -628,9 +630,6 @@ func TestConnection(t *testing.T) { }) t.Run("Test DriverRemoteConnection GraphTraversal", func(t *testing.T) { - mu.Lock() - defer mu.Unlock() - skipTestsIfNotEnabled(t, integrationTestSuiteName, testNoAuthEnable) // Initialize graph @@ -642,16 +641,10 @@ func TestConnection(t *testing.T) { readTestDataValues(t, g) // Drop the graph and check that it is empty. - dropGraph(t, g) - readCount(t, g, "", 0) - readCount(t, g, testLabel, 0) - readCount(t, g, personLabel, 0) + resetGraph(t, g) }) t.Run("Test Traversal. Next and HasNext", func(t *testing.T) { - mu.Lock() - defer mu.Unlock() - skipTestsIfNotEnabled(t, integrationTestSuiteName, testNoAuthEnable) // Initialize graph @@ -663,13 +656,10 @@ func TestConnection(t *testing.T) { }) t.Run("Test DriverRemoteConnection GraphTraversal With Label", func(t *testing.T) { - mu.Lock() - defer mu.Unlock() - skipTestsIfNotEnabled(t, integrationTestSuiteName, testNoAuthEnable) // Initialize graph - g := initializeGraph(t, testNoAuthUrl, testNoAuthAuthInfo, testNoAuthTlsConfig) + g := getTestGraph(t, testNoAuthUrl, testNoAuthAuthInfo, testNoAuthTlsConfig) defer g.remoteConnection.Close() // Drop the graph. @@ -711,9 +701,6 @@ func TestConnection(t *testing.T) { }) t.Run("Test DriverRemoteConnection GraphTraversal P", func(t *testing.T) { - mu.Lock() - defer mu.Unlock() - skipTestsIfNotEnabled(t, integrationTestSuiteName, testNoAuthEnable) // Initialize graph @@ -730,9 +717,6 @@ func TestConnection(t *testing.T) { }) t.Run("Test DriverRemoteConnection Next and HasNext", func(t *testing.T) { - mu.Lock() - defer mu.Unlock() - skipTestsIfNotEnabled(t, integrationTestSuiteName, testNoAuthEnable) // Initialize graph @@ -759,9 +743,6 @@ func TestConnection(t *testing.T) { }) t.Run("Test anonymousTraversal", func(t *testing.T) { - mu.Lock() - defer mu.Unlock() - skipTestsIfNotEnabled(t, integrationTestSuiteName, testNoAuthEnable) // Initialize graph @@ -771,10 +752,7 @@ func TestConnection(t *testing.T) { readUsingAnonymousTraversal(t, g) // Drop the graph and check that it is empty. - dropGraph(t, g) - readCount(t, g, "", 0) - readCount(t, g, testLabel, 0) - readCount(t, g, personLabel, 0) + resetGraph(t, g) }) t.Run("Test Traversal.ToList fail", func(t *testing.T) { @@ -820,9 +798,6 @@ func TestConnection(t *testing.T) { }) t.Run("Test DriverRemoteConnection GraphTraversal WithSack", func(t *testing.T) { - mu.Lock() - defer mu.Unlock() - skipTestsIfNotEnabled(t, integrationTestSuiteName, testNoAuthEnable) // Initialize graph @@ -997,9 +972,6 @@ func TestConnection(t *testing.T) { }) t.Run("Test DriverRemoteConnection Invalid GraphTraversal", func(t *testing.T) { - mu.Lock() - defer mu.Unlock() - skipTestsIfNotEnabled(t, integrationTestSuiteName, testNoAuthEnable) // Initialize graph