This is an automated email from the ASF dual-hosted git repository. xiazcy pushed a commit to branch 3.5-dev in repository https://gitbox.apache.org/repos/asf/tinkerpop.git
The following commit(s) were added to refs/heads/3.5-dev by this push: new 361e903a52 Dev Environments: Dockerize Testing for Python and Gremlin Console (Python-based tests only) (#1797) 361e903a52 is described below commit 361e903a52bd38b7560d4788be5e4647d1f5128f Author: Yang Xia <55853655+xia...@users.noreply.github.com> AuthorDate: Wed Sep 14 13:18:40 2022 -0700 Dev Environments: Dockerize Testing for Python and Gremlin Console (Python-based tests only) (#1797) Dockerized gremlin-python build, testing, and packaging. Dockerized gremlin-console python-based integration tests. Python 3.8 is used for the Docker image. Co-authored-by: Valentyn Kahamlyk <vkagam...@users.noreply.github.com> Co-authored-by: Ken Hu <106191785+kenh...@users.noreply.github.com> --- .github/workflows/build-test.yml | 11 +- .gitignore | 1 + CHANGELOG.asciidoc | 1 + docker/gremlin-test-server/Dockerfile | 2 +- docker/gremlin-test-server/krb5.conf | 31 ++ .../dev/developer/development-environment.asciidoc | 75 ++++- gremlin-console/pom.xml | 94 +----- .../src/test/python/docker/Dockerfile | 17 +- gremlin-console/src/test/python/setup.cfg | 2 +- gremlin-go/driver/README.md | 2 +- gremlin-go/pom.xml | 2 +- gremlin-javascript/pom.xml | 2 +- gremlin-python/docker-compose.yml | 87 ++++++ gremlin-python/pom.xml | 315 +++------------------ gremlin-python/src/main/python/radish/terrain.py | 6 +- gremlin-python/src/main/python/setup.cfg | 2 +- gremlin-python/src/main/python/setup.py | 2 +- gremlin-python/src/main/python/tests/conftest.py | 9 +- .../src/main/python/tests/driver/test_client.py | 4 +- .../tests/driver/test_driver_remote_connection.py | 5 +- .../test_driver_remote_connection_threaded.py | 8 +- .../main/python/tests/process/test_traversal.py | 2 +- pom.xml | 1 + 23 files changed, 276 insertions(+), 405 deletions(-) diff --git a/.github/workflows/build-test.yml b/.github/workflows/build-test.yml index c05d9e9eab..4b37675f4a 100644 --- a/.github/workflows/build-test.yml +++ b/.github/workflows/build-test.yml @@ -173,6 +173,7 @@ jobs: distribution: 'temurin' - name: Build with Maven run: | + touch gremlin-python/.glv mvn clean install -pl -:gremlin-javascript,-:gremlin-python,-gremlin-dotnet,-:gremlin-dotnet-source,-:gremlin-dotnet-tests,-:gremlint -q -DskipTests -Dci mvn verify -pl :gremlin-console -DskipTests -DskipIntegrationTests=false javascript: @@ -212,13 +213,12 @@ jobs: run: docker load --input gremlin-server.tar - name: Build with Maven run: | - touch gremlin-javascript/.glv mvn clean install -pl -:gremlin-python,-gremlin-dotnet,-:gremlin-dotnet-source,-:gremlin-dotnet-tests -q -DskipTests -Dci mvn verify -pl :gremlin-javascript,:gremlint python: name: python timeout-minutes: 20 - needs: smoke + needs: cache-gremlin-server-docker-image runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 @@ -231,16 +231,11 @@ jobs: uses: actions/setup-python@v4 with: python-version: '3.8' - - name: Setup Python requirements - run: | - sudo apt install gcc libkrb5-dev - python3 -m pip install --upgrade pip - pip install virtualenv - name: Build with Maven run: | touch gremlin-python/.glv mvn clean install -pl -:gremlin-javascript,-gremlin-dotnet,-:gremlin-dotnet-source,-:gremlin-dotnet-tests,-:gremlint -q -DskipTests -Dci - mvn verify -pl gremlin-python -DincludeNeo4j + mvn verify -pl gremlin-python dotnet: name: .NET timeout-minutes: 20 diff --git a/.gitignore b/.gitignore index 0270d3ba27..802e0cf61d 100644 --- a/.gitignore +++ b/.gitignore @@ -44,3 +44,4 @@ docs/gremlint/ gremlint/ coverage.out .env +gremlinconsoletest.egg-info diff --git a/CHANGELOG.asciidoc b/CHANGELOG.asciidoc index 51b5c0ec72..78e578d810 100644 --- a/CHANGELOG.asciidoc +++ b/CHANGELOG.asciidoc @@ -30,6 +30,7 @@ image::https://raw.githubusercontent.com/apache/tinkerpop/master/docs/static/ima * Fixed bug where tasks that haven't started running yet time out due to `evaluationTimeout` and never send a response back to the client. * Set the exact exception in `initializationFailure` on the Java driver instead of the root cause. * Added `SparkIOUtil` utility to load graph into Spark RDD. +* Dockerized all test environment for .NET, JavaScript, Python, Go, and Python-based tests for Console, and added Docker as a build requirement. [[release-3-5-4]] === TinkerPop 3.5.4 (Release Date: July 18, 2022) diff --git a/docker/gremlin-test-server/Dockerfile b/docker/gremlin-test-server/Dockerfile index 85956cbead..4053a7246d 100644 --- a/docker/gremlin-test-server/Dockerfile +++ b/docker/gremlin-test-server/Dockerfile @@ -24,7 +24,7 @@ USER root RUN mkdir -p /opt WORKDIR /opt COPY gremlin-server/src/test /opt/test/ -COPY docker/gremlin-server/docker-entrypoint.sh docker/gremlin-server/*.yaml /opt/ +COPY docker/gremlin-server/docker-entrypoint.sh docker/gremlin-server/*.yaml docker/gremlin-server/*.conf /opt/ RUN chmod 755 /opt/docker-entrypoint.sh # Installing dos2unix to avoid errors in running the entrypoint script on Windows machines where their diff --git a/docker/gremlin-test-server/krb5.conf b/docker/gremlin-test-server/krb5.conf new file mode 100644 index 0000000000..af64f28cfd --- /dev/null +++ b/docker/gremlin-test-server/krb5.conf @@ -0,0 +1,31 @@ +# +# 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. +# + +[libdefaults] + kdc_realm = TEST.COM + default_realm = TEST.COM + udp_preference_limit = 4096 + kdc_tcp_port = 4588 + kdc_udp_port = 4588 + dns_canonicalize_hostname = false + qualify_shortname = "" + +[realms] + TEST.COM = { + kdc = gremlin-server-test:4588 + } diff --git a/docs/src/dev/developer/development-environment.asciidoc b/docs/src/dev/developer/development-environment.asciidoc index e26564dcbf..3ac74dbd4d 100644 --- a/docs/src/dev/developer/development-environment.asciidoc +++ b/docs/src/dev/developer/development-environment.asciidoc @@ -39,6 +39,12 @@ of the project and those will go untested. To gain the ability to execute all aspects of the TinkerPop build system, other environmental configurations must be established. Those prerequisites are defined in the following subsections. +As of TinkerPop 3.5.5, environment configuration for Gremlin Language Variants can be optional, as Docker becomes a +system requirement to build and test GLVs inside of Maven. Please make sure Docker is installed and running on your system. +You will need to install both link:https://docs.docker.com/engine/install/[Docker Engine] and +link:https://docs.docker.com/compose/install/[Docker Compose], which are included in +link:https://docs.docker.com/desktop/[Docker Desktop]. + IMPORTANT: Use Java 11 for documentation generation with `bin/process-docs.sh` and for other build features outside of the basic `mvn clean install` sort of function. @@ -181,6 +187,9 @@ therefore requires: [source,text] sudo apt install libkrb5-dev krb5-user +As of TinkerPop 3.5.5, `gremlin-python` uses Docker for all tests inside of Maven, and Python installation will not be required to +run `gremlin-python` through Maven. Please make sure Docker is installed and running on your system. + Once the Python environment is established, the full building and testing of `gremlin-python` may commence. It can be done manually from the command line with: @@ -191,10 +200,9 @@ which enables the "glv-python" Maven profile or in a more automated fashion simp `gremlin-python` module which will signify to Maven that the environment is Python-ready. The `.glv` file need not have any contents and is ignored by Git. A standard `mvn clean install` will then build `gremlin-python` in full. -The build also requires Python to execute `gremlin-console` integration tests. The integration test is configured by a -"console-integration-tests" Maven profile. This profile can be activated manually or can more simply piggy-back on -the `.glv` file in `gremlin-python`. Note that unlike `gremlin-python` the tests are actually integration tests and -therefore must be actively switched on with `-DskipIntegrationTests=false`: +The `.glv` file in `gremlin-python` also activates the "console-integration-tests" Maven profile to run gremlin-console +integration tests. Alternatively, this profile can be activated manually. Note that unlike `gremlin-python` the tests +are actually integration tests and therefore must be actively switched on with `-DskipIntegrationTests=false`: [source,text] mvn clean install -pl gremlin-console -DskipIntegrationTests=false @@ -213,6 +221,9 @@ The build optionally requires link:https://dotnet.microsoft.com/download[.NET SD `gremlin-dotnet` module. If .NET SDK is not installed, TinkerPop will still build with Maven, but .NET projects will be skipped. +As of TinkerPop 3.5.5, `gremlin-dotnet` uses Docker for running all test projects inside of Maven, and .NET SDK will not +be required to run `gremlin-dotnet` tests through Maven. Please make sure Docker is installed and running on your system. + `gremlin-dotnet` can be built and tested from the command line with: [source,text] @@ -248,6 +259,9 @@ have to be installed. When generating or publishing the TinkerPop website, the ` built. Consequently, the scripts `bin/generate-home.sh` and `bin/publish-home.sh` require that Node.js and npm are installed. Version 6.x or newer of npm is required. This is covered in more detail in the <<site,Site>> section. +As of TinkerPop 3.5.5, `gremlin-javascript` uses Docker for all tests inside of Maven. Please make sure Docker is +installed and running on your system. + IMPORTANT: Beware of unexpected or unwanted changes on `package-lock.json` files when committing and merging. TIP: For those who do not have a full Maven environment, please see <<docker-integration,this section>> for how Docker @@ -260,9 +274,16 @@ See the <<release-environment,Release Environment>> section for more information [[go-environment]] === Go Environment -The build optionally requires link:https://go.dev/dl/[Go] (>=1.17) to work with the `gremlin-go` module. If Go is not installed, TinkerPop will still build with Maven, but Go projects will be skipped. +The build optionally requires link:https://go.dev/dl/[Go] (>=1.17) to work with the `gremlin-go` module. Creating an +empty `.glv` file will enable running of tests inside of Maven. If `.glv` file does not exist, TinkerPop +will still build with Maven, but Go projects will be skipped. -`gremlin-go` can be built the command line with: +`gremlin-go` can be built and tested from the command line with: + +[source,text] +mvn clean install -pl gremlin-go + +Alternatively, after installing Go, `gremlin-go` can be built from the command line with: [source,text] go build @@ -287,6 +308,9 @@ mvn clean install -pl gremlin-server,gremlin-console -DdockerImages which enables the "docker-images" Maven profile. +As of TinkerPop 3.5.5, a docker image of the Gremlin Server will be built automatically with `mvn clean install`, which +is use for GLV tests inside of Docker. To skip building this image, append the `-DskipImageBuild` flag to Maven commands. + [[release-environment]] === Release Environment @@ -497,6 +521,45 @@ docker/gremlin-server.sh 3.4.2 To be a bit more clear, the version can not be a Docker tag like "latest" because there is no such TinkerPop artifact that has been published with that version number. +[[docker-testing]] +== Testing Sub-Modules with Docker + +Currently the modules gremlin-go, gremlin-javascript, gremlin-dotnet, gremlin-python and gremlin-console can be tested +through Docker. + +Please make sure Docker is installed and running on your system. You will need to install both +link:https://docs.docker.com/engine/install/[Docker Engine] and link:https://docs.docker.com/compose/install/[Docker Compose], +which are included in link:https://docs.docker.com/desktop/[Docker Desktop]. + +The following environment variables used by Docker Compose will automatically be set when running through Maven. + +The docker compose environment variable `GREMLIN_SERVER` specifies the Gremlin server docker image to use, i.e. an +image with the tag `tinkerpop/gremlin-server:$GREMLIN_SERVER`, and is a required environment variable. This also +requires the specified docker image to exist, either locally or in link:https://hub.docker.com/r/tinkerpop/gremlin-server[Docker Hub]. + +Running `mvn clean install -pl gremlin-server -DskipTests -DskipIntegrationTests=true -Dci -am` in the main `tinkerpop` +directory will automatically build a local SNAPSHOT Gremlin server image. If your OS Platform cannot build a local +SNAPSHOT Gremlin server through `maven`, it is recommended to use the latest released server version from +link:https://hub.docker.com/r/tinkerpop/gremlin-server[Docker Hub] (do not use `GREMLIN_SERVER=latest`, use actual +version number, e.g. `GREMLIN_SERVER=3.5.x` or `GREMLIN_SERVER=3.6.x`). + +The docker compose environment variable `HOME` specifies the user home directory for mounting volumes during test image +set up. This variable is set by default in Unix/Linux, but will need to be set for Windows, for example, run +`$env:HOME=$env:USERPROFILE` in PowerShell. + +There are different ways to launch the test suite and set the `GREMLIN_SERVER` environment variable depending on +your Platform: + +* Run Maven commands, e.g. `mvn clean install` inside of project folder e.g. `tinkerpop/gremlin-go`, or `mvn clean install -pl gremlin-go` +inside of `tinkerpop` (platform-agnostic - recommended) +* Add `GREMLIN_SERVER=<server-image-version>` and `HOME=<user-home-directory>` to an `.env` file inside project folder and run `docker-compose up --exit-code-from gremlin-go-integration-tests` (Platform-agnostic). +* Run `GREMLIN_SERVER=<server-image-version> docker-compose up --exit-code-from gremlin-go-integration-tests` in Unix/Linux. +* Run `$env:GREMLIN_SERVER="<server-image-version>";$env:HOME=$env:USERPROFILE;docker-compose up --exit-code-from gremlin-go-integration-tests` in Windows PowerShell. + +You should see exit code 0 upon successful completion of the test suites. Run `docker-compose down` to remove the +service containers (not needed if you executed Maven commands or `run.sh`), or `docker-compose down --rmi all` to +remove the service containers while deleting all used images. + [[intellij]] == Intellij Usage diff --git a/gremlin-console/pom.xml b/gremlin-console/pom.xml index 8d41bfc0d5..59f0ad1b7a 100644 --- a/gremlin-console/pom.xml +++ b/gremlin-console/pom.xml @@ -291,8 +291,8 @@ limitations under the License. </build> <profiles> - <!-- activates the building of python components and requires that python be installed on the system. use - the .glv file in gremlin-python as an indicator to activate --> + <!-- activates the building of python components through Docker. + use the .glv file in gremlin-python as an indicator to activate --> <profile> <id>console-integration-tests</id> <activation> @@ -308,84 +308,6 @@ limitations under the License. <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-antrun-plugin</artifactId> <executions> - <execution> - <id>create-python-reports-directory</id> - <phase>initialize</phase> - <goals> - <goal>run</goal> - </goals> - <configuration> - <skip>${skipIntegrationTests}</skip> - <target> - <mkdir dir="${project.build.directory}/python-reports"/> - <mkdir dir="${project.build.directory}/python/env"/> - </target> - </configuration> - </execution> - <!-- copy files in python directory to target/python and run virtual env to sandbox python. - there is no need to "activate" the virtualenv because all calls to python occur - directly from bin/ --> - <execution> - <id>setup-py-env</id> - <phase>process-resources</phase> - <goals> - <goal>run</goal> - </goals> - <configuration> - <skip>${skipIntegrationTests}</skip> - <tasks> - <copy todir="${project.build.directory}/python"> - <fileset dir="src/test/python"/> - </copy> - <exec dir="${project.build.directory}/python" executable="python3" - failonerror="true"> - <arg line="--version"/> - </exec> - <exec dir="${project.build.directory}/python" executable="virtualenv" - failonerror="true"> - <arg line="--version"/> - </exec> - <exec dir="${project.build.directory}/python" executable="virtualenv" - failonerror="true"> - <arg line="--python=python3 env"/> - </exec> - </tasks> - </configuration> - </execution> - <execution> - <id>native-python-build</id> - <phase>compile</phase> - <goals> - <goal>run</goal> - </goals> - <configuration> - <skip>${skipIntegrationTests}</skip> - <target> - <exec executable="env/bin/python" dir="${project.build.directory}/python" - failonerror="true"> - <env key="PYTHONPATH" value=""/> - <arg line="setup.py build --build-lib ${project.build.outputDirectory}/Lib"/> - </exec> - </target> - </configuration> - </execution> - - <execution> - <id>copy-gremlinsh</id> - <phase>pre-integration-test</phase> - <goals> - <goal>run</goal> - </goals> - <configuration> - <skip>${skipIntegrationTests}</skip> - <tasks> - <copy todir="${project.build.directory}/python/gremlin-console"> - <fileset dir="${project.build.directory}/apache-tinkerpop-gremlin-console-${project.version}-standalone"/> - </copy> - </tasks> - </configuration> - </execution> - <!-- use pytest to execute native python tests - output of xunit output is configured in setup.cfg. must run on integration tests because package phase has to execute to get the console binaries @@ -400,10 +322,14 @@ limitations under the License. <configuration> <skip>${skipIntegrationTests}</skip> <target> - <exec executable="env/bin/python" dir="${project.build.directory}/python" - failonerror="true"> - <env key="PYTHONPATH" value=""/> - <arg line="setup.py test"/> + <exec executable="docker" failonerror="true"> + <!-- This build command relies on Docker's caching mechanism to reduce the amount of times it is run. --> + <arg line="build -t gremlin-console-test:py3.8jre11 ./src/test/python/docker"/> + </exec> + <exec executable="docker" failonerror="true"> + <arg line="run --rm --mount type=bind,src=${project.basedir}/src/test/python,dst=/console_app + --mount type=bind,src=${project.basedir}/target/apache-tinkerpop-gremlin-console-${project.version}-standalone,dst=/console_app/gremlin-console + gremlin-console-test:py3.8jre11"/> </exec> </target> </configuration> diff --git a/gremlin-python/src/main/python/setup.cfg b/gremlin-console/src/test/python/docker/Dockerfile similarity index 64% copy from gremlin-python/src/main/python/setup.cfg copy to gremlin-console/src/test/python/docker/Dockerfile index b9e5f2207d..68cbb26071 100644 --- a/gremlin-python/src/main/python/setup.cfg +++ b/gremlin-console/src/test/python/docker/Dockerfile @@ -6,7 +6,7 @@ # "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 +# 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 @@ -14,12 +14,13 @@ # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. -[bdist_wheel] -universal=1 -[aliases] -test=pytest +# Image used for running integration tests for gremlin-console. +FROM python:3.8.12 -[tool:pytest] -addopts = --junitxml=../python-reports/TEST-native-python.xml -norecursedirs = '.*', 'build', 'dist', 'CVS', '_darcs', '{arch}', '*.egg' lib lib64 +LABEL maintainer="d...@tinkerpop.apache.org" + +RUN apt-get update && apt-get install -y --no-install-recommends openjdk-11-jre && apt-get install dos2unix + +WORKDIR /console_app +CMD bash -c "dos2unix ./gremlin-console/bin/gremlin.sh && python3 setup.py build && python3 setup.py test" diff --git a/gremlin-console/src/test/python/setup.cfg b/gremlin-console/src/test/python/setup.cfg index 4d693891f9..381374ed1c 100644 --- a/gremlin-console/src/test/python/setup.cfg +++ b/gremlin-console/src/test/python/setup.cfg @@ -18,5 +18,5 @@ test=pytest [tool:pytest] -addopts = --junitxml=../python-reports/TEST-native-python.xml +addopts = --junitxml=./python-reports/TEST-native-python.xml norecursedirs = '.*', 'build', 'dist', 'CVS', '_darcs', '{arch}', '*.egg' lib lib64 diff --git a/gremlin-go/driver/README.md b/gremlin-go/driver/README.md index 877eeee248..8cd106fb15 100644 --- a/gremlin-go/driver/README.md +++ b/gremlin-go/driver/README.md @@ -127,7 +127,7 @@ either locally or in [Docker Hub][dhub]. Running `mvn clean install -pl gremlin-server -DskipTests -DskipIntegrationTests=true -Dci -am` in the main `tinkerpop` directory will automatically build a local SNAPSHOT Gremlin server image. If your OS Platform cannot build a local SNAPSHOT Gremlin server through `maven`, it is recommended to use the latest released server version from [Docker Hub][dhub] (do not use `GREMLIN_SERVER=latest`, use actual version number, e.g. `GREMLIN_SERVER=3.5.x` or `GREMLIN_SERVER=3.6.x`). -The docker compose environment variable `HOME` specifies the user home directory for mounting volumes during test image set up. This varibale is set by default in Unix/Linux, but will need to be set for Windows, for example, run `$env:HOME=$env:USERPROFILE` in PowerShell. +The docker compose environment variable `HOME` specifies the user home directory for mounting volumes during test image set up. This variable is set by default in Unix/Linux, but will need to be set for Windows, for example, run `$env:HOME=$env:USERPROFILE` in PowerShell. There are different ways to launch the test suite and set the `GREMLIN_SERVER` environment variable depending on your Platform: - Run Maven commands, e.g. `mvn clean install` inside of `tinkerpop/gremlin-go`, or `mvn clean install -pl gremlin-go` inside of `tinkerpop` (platform-agnostic - recommended) diff --git a/gremlin-go/pom.xml b/gremlin-go/pom.xml index 35010f5688..046f003861 100644 --- a/gremlin-go/pom.xml +++ b/gremlin-go/pom.xml @@ -97,7 +97,7 @@ limitations under the License. <skip>${skipTests}</skip> <environmentVariables> <GREMLIN_SERVER>${project.version}</GREMLIN_SERVER> - <ABS_PROJECT_HOME>${project.basedir}</ABS_PROJECT_HOME> + <ABS_PROJECT_HOME>${project.basedir}/../</ABS_PROJECT_HOME> <!-- setting this env variable is needed to be cross-platform compatible --> <HOME>${user.home}</HOME> </environmentVariables> diff --git a/gremlin-javascript/pom.xml b/gremlin-javascript/pom.xml index 8b2e05e383..37035b163d 100644 --- a/gremlin-javascript/pom.xml +++ b/gremlin-javascript/pom.xml @@ -250,4 +250,4 @@ limitations under the License. </build> </profile> </profiles> -</project> +</project> \ No newline at end of file diff --git a/gremlin-python/docker-compose.yml b/gremlin-python/docker-compose.yml new file mode 100644 index 0000000000..a28657986a --- /dev/null +++ b/gremlin-python/docker-compose.yml @@ -0,0 +1,87 @@ +# 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. + +version: "3.8" + +services: + + gremlin-server-test-python: + container_name: gremlin-server-test-python + image: tinkerpop:gremlin-server-test-${GREMLIN_SERVER} + hostname: gremlin-server-test + build: + context: ../ + dockerfile: docker/gremlin-test-server/Dockerfile + args: + - GREMLIN_SERVER=${GREMLIN_SERVER} + ports: + - "45940:45940" + - "45941:45941" + - "45942:45942" + - "4588:4588" + volumes: + - ${HOME}/.groovy:/root/.groovy + - ${HOME}/.m2:/root/.m2 + - ${ABS_PROJECT_HOME}/gremlin-test/target:/opt/gremlin-test + healthcheck: + test: [ "CMD-SHELL", "apk add curl && curl -f http://localhost:45940?gremlin=100-1" ] + interval: 30s + timeout: 10s + retries: 30 + start_period: 30s + + gremlin-python-integration-tests: + container_name: gremlin-python-integration-tests + image: python:3.8 + volumes: + - ${BUILD_DIR:-./src/main/python}:/python_app + - ../gremlin-test/features:/python_app/gremlin-test/features + - ../docker/gremlin-test-server:/python_app/gremlin-test-server + environment: + - TEST_TRANSACTIONS=${TEST_TRANSACTIONS:-true} + - DEBIAN_FRONTEND=noninteractive + - KRB5_CONFIG=./gremlin-test-server/krb5.conf + - KRB5CCNAME=./test-tkt.cc + - GREMLIN_SERVER_URL=ws://gremlin-server-test-python:{}/gremlin + - GREMLIN_SERVER_BASIC_AUTH_URL=wss://gremlin-server-test-python:{}/gremlin + - KRB_HOSTNAME=${KRB_HOSTNAME:-gremlin-server-test} + - VERSION=${VERSION} + working_dir: /python_app + command: > + bash -c "apt-get update && apt-get -y install libkrb5-dev krb5-user + && echo 'password' | kinit stephen + && klist + && pip install wheel radish-bdd PyHamcrest aenum isodate kerberos six + && python3 ./setup.py build + && python3 ./setup.py test + && python3 ./setup.py install + && radish -f dots -e -t -b ./radish ./gremlin-test --user-data='serializer=application/vnd.gremlin-v3.0+json' + && radish -f dots -e -t -b ./radish ./gremlin-test --user-data='serializer=application/vnd.graphbinary-v1.0'" + depends_on: + gremlin-server-test-python: + condition: service_healthy + + gremlin-python-package: + container_name: gremlin-python-package + image: python:3.8 + volumes: + - ${PACKAGE_DIR:-./src/main/python}:/python_package + working_dir: /python_package + environment: + - VERSION=${VERSION} + command: > + bash -c "python3 setup.py sdist bdist_wheel" diff --git a/gremlin-python/pom.xml b/gremlin-python/pom.xml index a0707c7c22..942223d7b5 100644 --- a/gremlin-python/pom.xml +++ b/gremlin-python/pom.xml @@ -83,102 +83,33 @@ limitations under the License. </activation> <build> <plugins> - <!-- need to create python-reports directory at this point or else pytest can't write the report to it --> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-antrun-plugin</artifactId> <executions> + <!-- + copy source files in python directory to target/, to keep testing separate from packaging. + we use target/python3 for testing and target/python-packaged for distribution tasks. + --> <execution> - <id>create-python-reports-directory</id> - <phase>initialize</phase> - <goals> - <goal>run</goal> - </goals> - <configuration> - <target> - <mkdir dir="${project.build.directory}/python-reports"/> - <mkdir dir="${project.build.directory}/python-packaged/env"/> - </target> - </configuration> - </execution> - <!-- copy files in python directory to target/py and run virtual env to sandbox python. - there is no need to "activate" the virtualenv because all calls to python occur - directly from bin/ --> - <execution> - <id>setup-py-env</id> + <id>setup-env</id> <phase>process-resources</phase> <goals> <goal>run</goal> </goals> <configuration> - <tasks> - <!-- seems like we need a few different copies of the same source. all the - different python stuff doesn't seem to want to share. we use - /python3 for basic tests and stuff and /python-packaged for distribution - tasks. some of the problem seems to stem from the python lifecycle not - binding perfectly well to the maven lifecycle (integration tests seems to - cause troubles specifically). note that the commands to install wheel are - largely for safety in case someone is using an older version of virtualenv - (which doesn't install wheel by default) --> + <target> + <!-- pytest will create python-reports inside target/python3/python-reports + as docker compose cannot access outside its working directory --> <copy todir="${project.build.directory}/python3"> <fileset dir="src/main/python"/> </copy> - <exec dir="${project.build.directory}/python3" executable="python3" - failonerror="true"> - <arg line="--version"/> - </exec> - <exec dir="${project.build.directory}/python3" executable="virtualenv" - failonerror="true"> - <arg line="--version"/> - </exec> - <exec dir="${project.build.directory}/python3" executable="virtualenv" - failonerror="true"> - <arg line="--python=python3 env"/> - </exec> - <!-- pin setuptools before the breaking change at - https://github.com/pypa/setuptools/issues/2086 with removal of lib2to3. - not sure if this our code that is causing this problem though. the error - in travis shows as: - Setup script exited with error in radish-parse_type setup command: use_2to3 is invalid.--> - <exec dir="${project.build.directory}/python3" executable="env/bin/pip" - failonerror="true"> - <arg line="install setuptools<58.0.0"/> - </exec> - <exec dir="${project.build.directory}/python3" executable="env/bin/pip" - failonerror="true"> - <arg line="install wheel radish-bdd PyHamcrest aenum isodate kerberos six"/> - </exec> <copy todir="${project.build.directory}/python-packaged"> <fileset dir="src/main/python"/> </copy> - <exec dir="${project.build.directory}/python-packaged" executable="virtualenv" - failonerror="true"> - <arg line="--python=python3 env"/> - </exec> - <exec dir="${project.build.directory}/python-packaged" executable="env/bin/pip" - failonerror="true"> - <arg line="install wheel"/> - </exec> - </tasks> - </configuration> - </execution> - <execution> - <id>native-python3-build</id> - <phase>compile</phase> - <goals> - <goal>run</goal> - </goals> - <configuration> - <target> - <exec executable="env/bin/python" dir="${project.build.directory}/python3" - failonerror="true"> - <env key="PYTHONPATH" value=""/> - <arg line="setup.py build --build-lib ${project.build.outputDirectory}/Lib"/> - </exec> </target> </configuration> </execution> - <!-- build/package python source distribution and wheel archive. the version is bound to an environment variable that gets used in setup.py to dynamically construct a module @@ -192,23 +123,21 @@ limitations under the License. </goals> <configuration> <target> - <exec executable="env/bin/python" dir="${project.build.directory}/python-packaged" - failonerror="true"> + <exec executable="docker-compose" failonerror="true"> + <env key="PACKAGE_DIR" value="${project.build.directory}/python-packaged"/> <env key="VERSION" value="${project.version}"/> <env key="PYTHONPATH" value=""/> - <arg line="setup.py sdist bdist_wheel"/> + <arg line="up --build --abort-on-container-exit gremlin-python-package"/> </exec> </target> </configuration> </execution> <!-- - use pytest to execute native python tests - output of xunit output is configured in setup.cfg. - this has to be an integration-test because we need gremlin-server running and the standard - test phase doesn't have a pre/post event like integration-test does. + use docker-compose to run unit tests, radish, and integration tests. --> <execution> - <id>native-python3-test</id> + <id>python-tests</id> <phase>integration-test</phase> <goals> <goal>run</goal> @@ -216,36 +145,23 @@ limitations under the License. <configuration> <skip>${skipTests}</skip> <target> - <exec executable="env/bin/python" dir="${project.build.directory}/python3" - failonerror="true"> - <env key="TEST_TRANSACTIONS" value="${TEST_TRANSACTIONS}"/> - <env key="PYTHONPATH" value=""/> - <env key="KRB5_CONFIG" value="${project.build.directory}/kdc/krb5.conf"/> - <env key="KRB5CCNAME" value="${project.build.directory}/kdc/test-tkt.cc"/> - <arg line="setup.py test"/> - </exec> - <!-- radish seems to like all dependencies in place --> - <exec executable="env/bin/python" dir="${project.build.directory}/python3" - failonerror="true"> - <env key="TEST_TRANSACTIONS" value="${TEST_TRANSACTIONS}"/> + <exec executable="docker-compose" failonerror="true"> + <env key="VERSION" value="${project.version}"/> <env key="PYTHONPATH" value=""/> - <arg line="setup.py install"/> + <env key="GREMLIN_SERVER" value="${project.version}"/> + <env key="ABS_PROJECT_HOME" value="${project.basedir}/../"/> + <env key="BUILD_DIR" value="${project.build.directory}/python3"/> + <arg line="up --build --abort-on-container-exit gremlin-server-test-python gremlin-python-integration-tests"/> </exec> - <!-- run for graphson 3.0 --> - <exec executable="env/bin/radish" dir="${project.build.directory}/python3" - failonerror="true"> - <env key="TEST_TRANSACTIONS" value="${TEST_TRANSACTIONS}"/> + <exec executable="docker-compose" failonerror="true"> <env key="PYTHONPATH" value=""/> - <env key="PYTHONIOENCODING" value="utf-8:surrogateescape"/> - <arg line="-f dots -e -t -b ${project.build.directory}/python3/radish ${project.basedir}/../gremlin-test/features/ --user-data="serializer=application/vnd.gremlin-v3.0+json""/> <!-- -no-line-jump --> + <env key="BUILD_DIR" value="${project.build.directory}/python3"/> + <arg line="down"/> </exec> - <!-- run for graphbinary 1.0 --> - <exec executable="env/bin/radish" dir="${project.build.directory}/python3" - failonerror="true"> - <env key="TEST_TRANSACTIONS" value="${TEST_TRANSACTIONS}"/> + <exec executable="docker" failonerror="true"> <env key="PYTHONPATH" value=""/> - <env key="PYTHONIOENCODING" value="utf-8:surrogateescape"/> - <arg line="-f dots -e -t -b ${project.build.directory}/python3/radish ${project.basedir}/../gremlin-test/features/ --user-data="serializer=application/vnd.graphbinary-v1.0""/> <!-- -no-line-jump --> + <env key="BUILD_DIR" value="${project.build.directory}/python3"/> + <arg line="image prune --filter label=maintainer=d...@tinkerpop.apache.org -f"/> </exec> </target> </configuration> @@ -304,183 +220,11 @@ limitations under the License. </scripts> </configuration> </execution> - <execution> - <id>gremlin-server-start</id> - <phase>pre-integration-test</phase> - <goals> - <goal>execute</goal> - </goals> - <configuration> - <properties> - <property> - <name>skipTests</name> - <value>${skipTests}</value> - </property> - <property> - <name>gremlinServerDir</name> - <value>${gremlin.server.dir}</value> - </property> - <property> - <name>settingsFile</name> - <value>${gremlin.server.dir}/src/test/resources/org/apache/tinkerpop/gremlin/server/gremlin-server-integration.yaml</value> - </property> - <property> - <name>executionName</name> - <value>${project.name}</value> - </property> - <property> - <name>projectBaseDir</name> - <value>${project.basedir}</value> - </property> - <property> - <name>tinkerpopRootDir</name> - <value>${tinkerpop.root.dir}</value> - </property> - </properties> - <scripts> - <script>${gremlin.server.dir}/src/test/scripts/test-server-start.groovy</script> - </scripts> - </configuration> - </execution> - <execution> - <id>gremlin-server-stop</id> - <phase>post-integration-test</phase> - <goals> - <goal>execute</goal> - </goals> - <configuration> - <properties> - <property> - <name>skipTests</name> - <value>${skipTests}</value> - </property> - <property> - <name>executionName</name> - <value>${project.name}</value> - </property> - </properties> - <scripts> - <script>${gremlin.server.dir}/src/test/scripts/test-server-stop.groovy</script> - </scripts> - </configuration> - </execution> </executions> </plugin> </plugins> </build> </profile> - <!-- - This profile will include neo4j for purposes of transactional testing within Gremlin Server. - Tests that require neo4j specifically will be "ignored" if this profile is not turned on. - --> - <profile> - <id>include-neo4j</id> - <activation> - <activeByDefault>false</activeByDefault> - <property> - <name>includeNeo4j</name> - </property> - </activation> - <properties> - <TEST_TRANSACTIONS>true</TEST_TRANSACTIONS> - </properties> - <build> - <plugins> - <plugin> - <groupId>org.codehaus.gmavenplus</groupId> - <artifactId>gmavenplus-plugin</artifactId> - <dependencies> - <dependency> - <groupId>org.neo4j</groupId> - <artifactId>neo4j-tinkerpop-api-impl</artifactId> - <version>0.9-3.4.0</version> - <exclusions> - <exclusion> - <groupId>org.neo4j</groupId> - <artifactId>neo4j-kernel</artifactId> - </exclusion> - <exclusion> - <groupId>org.apache.commons</groupId> - <artifactId>commons-lang3</artifactId> - </exclusion> - <exclusion> - <groupId>org.apache.commons</groupId> - <artifactId>commons-text</artifactId> - </exclusion> - <exclusion> - <groupId>com.github.ben-manes.caffeine</groupId> - <artifactId>caffeine</artifactId> - </exclusion> - <exclusion> - <groupId>org.scala-lang</groupId> - <artifactId>scala-library</artifactId> - </exclusion> - <exclusion> - <groupId>org.scala-lang</groupId> - <artifactId>scala-reflect</artifactId> - </exclusion> - <exclusion> - <groupId>org.slf4j</groupId> - <artifactId>slf4j-api</artifactId> - </exclusion> - <exclusion> - <groupId>org.slf4j</groupId> - <artifactId>slf4j-nop</artifactId> - </exclusion> - <exclusion> - <groupId>org.apache.lucene</groupId> - <artifactId>lucene-core</artifactId> - </exclusion> - <exclusion> - <groupId>io.dropwizard.metrics</groupId> - <artifactId>metrics-core</artifactId> - </exclusion> - <exclusion> - <groupId>io.netty</groupId> - <artifactId>netty-all</artifactId> - </exclusion> - <exclusion> - <groupId>org.ow2.asm</groupId> - <artifactId>asm</artifactId> - </exclusion> - </exclusions> - </dependency> - <dependency> - <groupId>org.scala-lang</groupId> - <artifactId>scala-library</artifactId> - <version>2.11.8</version> - </dependency> - <dependency> - <groupId>org.scala-lang</groupId> - <artifactId>scala-reflect</artifactId> - <version>2.11.8</version> - </dependency> - <dependency> - <groupId>org.apache.lucene</groupId> - <artifactId>lucene-core</artifactId> - <version>5.5.0</version> - </dependency> - <dependency> - <groupId>io.dropwizard.metrics</groupId> - <artifactId>metrics-core</artifactId> - <version>4.2.11</version> - </dependency> - <dependency> - <groupId>org.neo4j</groupId> - <artifactId>neo4j-kernel</artifactId> - <version>3.4.11</version> - <exclusions> - <exclusion> - <groupId>io.netty</groupId> - <artifactId>netty-all</artifactId> - </exclusion> - </exclusions> - </dependency> - </dependencies> - </plugin> - </plugins> - </build> - </profile> <!-- Provides a way to deploy the gremlinpython GLV to pypi. This cannot be part of the standard maven execution because pypi does not have a staging environment like sonatype for releases. As soon as the release is @@ -510,6 +254,15 @@ limitations under the License. </goals> <configuration> <target> + <!-- + set up and run virtual env to sandbox python. there is no need to "activate" + the virtualenv because all calls to python occur directly from bin/ + --> + <mkdir dir="${project.build.directory}/python-packaged/env"/> + <exec dir="${project.build.directory}/python-packaged" executable="virtualenv" + failonerror="true"> + <arg line="--python=python3 env"/> + </exec> <!-- seems like https://github.com/pypa/twine/issues/338 is the reason to stay bound to this old version of twine. as long as keyring gets in the way and can't be diff --git a/gremlin-python/src/main/python/radish/terrain.py b/gremlin-python/src/main/python/radish/terrain.py index 24a102ced3..5dcaa3e0a1 100644 --- a/gremlin-python/src/main/python/radish/terrain.py +++ b/gremlin-python/src/main/python/radish/terrain.py @@ -16,6 +16,7 @@ # specific language governing permissions and limitations # under the License. # +import os from gremlin_python.process.anonymous_traversal import traversal from gremlin_python.process.graph_traversal import __ @@ -28,7 +29,8 @@ label = __.label inV = __.inV project = __.project tail = __.tail - +gremlin_server_url = os.environ.get('GREMLIN_SERVER_URL', 'ws://localhost:{}/gremlin') +test_no_auth_url = gremlin_server_url.format(45940) @before.all def prepare_static_traversal_source(features, marker): @@ -95,4 +97,4 @@ def __create_remote(server_graph_name): else: raise ValueError('serializer not found - ' + world.config.user_data["serializer"]) - return DriverRemoteConnection('ws://localhost:45940/gremlin', server_graph_name, message_serializer=s) + return DriverRemoteConnection(test_no_auth_url, server_graph_name, message_serializer=s) diff --git a/gremlin-python/src/main/python/setup.cfg b/gremlin-python/src/main/python/setup.cfg index b9e5f2207d..a4a55e0a1e 100644 --- a/gremlin-python/src/main/python/setup.cfg +++ b/gremlin-python/src/main/python/setup.cfg @@ -21,5 +21,5 @@ universal=1 test=pytest [tool:pytest] -addopts = --junitxml=../python-reports/TEST-native-python.xml +addopts = --junitxml=./python-reports/TEST-native-python.xml -sv norecursedirs = '.*', 'build', 'dist', 'CVS', '_darcs', '{arch}', '*.egg' lib lib64 diff --git a/gremlin-python/src/main/python/setup.py b/gremlin-python/src/main/python/setup.py index acfd8055ac..54fd2afb57 100644 --- a/gremlin-python/src/main/python/setup.py +++ b/gremlin-python/src/main/python/setup.py @@ -75,7 +75,7 @@ setup( tests_require=[ 'pytest>=4.6.4,<7.2.0', 'mock>=3.0.5,<4.0.0', - 'radish-bdd==0.8.6', + 'radish-bdd==0.13.4', 'PyHamcrest>=1.9.0,<2.0.0' ], install_requires=install_requires, diff --git a/gremlin-python/src/main/python/tests/conftest.py b/gremlin-python/src/main/python/tests/conftest.py index fc3ef8bd9b..3c89150176 100644 --- a/gremlin-python/src/main/python/tests/conftest.py +++ b/gremlin-python/src/main/python/tests/conftest.py @@ -18,6 +18,7 @@ # import concurrent.futures +import os import ssl import pytest import socket @@ -36,11 +37,13 @@ from gremlin_python.driver.serializer import ( GraphBinarySerializersV1) from gremlin_python.driver.aiohttp.transport import AiohttpTransport -gremlin_server_url = 'ws://localhost:{}/gremlin' +gremlin_server_url = os.environ.get('GREMLIN_SERVER_URL', 'ws://localhost:{}/gremlin') +gremlin_basic_auth_url = os.environ.get('GREMLIN_SERVER_BASIC_AUTH_URL', 'wss://localhost:{}/gremlin') +kerberos_hostname = os.environ.get('KRB_HOSTNAME', socket.gethostname()) anonymous_url = gremlin_server_url.format(45940) -basic_url = 'wss://localhost:{}/gremlin'.format(45941) +basic_url = gremlin_basic_auth_url.format(45941) kerberos_url = gremlin_server_url.format(45942) -kerberized_service = 'test-service@{}'.format(socket.gethostname()) +kerberized_service = 'test-service@{}'.format(kerberos_hostname) verbose_logging = False logging.basicConfig(format='%(asctime)s [%(levelname)8s] [%(filename)15s:%(lineno)d - %(funcName)10s()] - %(message)s', diff --git a/gremlin-python/src/main/python/tests/driver/test_client.py b/gremlin-python/src/main/python/tests/driver/test_client.py index 2fd251caa0..63ab354be8 100644 --- a/gremlin-python/src/main/python/tests/driver/test_client.py +++ b/gremlin-python/src/main/python/tests/driver/test_client.py @@ -17,6 +17,7 @@ # under the License. # import asyncio +import os import threading import uuid @@ -32,7 +33,8 @@ from asyncio import TimeoutError __author__ = 'David M. Brown (davebs...@gmail.com)' -test_no_auth_url = 'ws://localhost:45940/gremlin' +gremlin_server_url = os.environ.get('GREMLIN_SERVER_URL', 'ws://localhost:{}/gremlin') +test_no_auth_url = gremlin_server_url.format(45940) def test_connection(connection): diff --git a/gremlin-python/src/main/python/tests/driver/test_driver_remote_connection.py b/gremlin-python/src/main/python/tests/driver/test_driver_remote_connection.py index ff4d3618b5..360ea7c5c2 100644 --- a/gremlin-python/src/main/python/tests/driver/test_driver_remote_connection.py +++ b/gremlin-python/src/main/python/tests/driver/test_driver_remote_connection.py @@ -16,6 +16,7 @@ # specific language governing permissions and limitations # under the License. # +import os from gremlin_python import statics from gremlin_python.driver.protocol import GremlinServerError @@ -33,6 +34,8 @@ from gremlin_python.driver.serializer import GraphSONSerializersV2d0 __author__ = 'Marko A. Rodriguez (http://markorodriguez.com)' +gremlin_server_url = os.environ.get('GREMLIN_SERVER_URL', 'ws://localhost:{}/gremlin') +test_no_auth_url = gremlin_server_url.format(45940) class TestDriverRemoteConnection(object): def test_traversals(self, remote_connection): @@ -108,7 +111,7 @@ class TestDriverRemoteConnection(object): def test_lambda_traversals(self, remote_connection): statics.load_statics(globals()) - assert "remoteconnection[ws://localhost:45940/gremlin,gmodern]" == str(remote_connection) + assert "remoteconnection[{},gmodern]".format(test_no_auth_url) == str(remote_connection) g = traversal().withRemote(remote_connection) assert 24.0 == g.withSack(1.0, lambda: ("x -> x + 1", "gremlin-groovy")).V().both().sack().sum().next() diff --git a/gremlin-python/src/main/python/tests/driver/test_driver_remote_connection_threaded.py b/gremlin-python/src/main/python/tests/driver/test_driver_remote_connection_threaded.py index c3899a4d59..0234ad8dd7 100644 --- a/gremlin-python/src/main/python/tests/driver/test_driver_remote_connection_threaded.py +++ b/gremlin-python/src/main/python/tests/driver/test_driver_remote_connection_threaded.py @@ -17,6 +17,7 @@ # under the License. # import concurrent.futures +import os import sys from threading import Thread from six.moves import queue @@ -27,6 +28,8 @@ from gremlin_python.process.anonymous_traversal import traversal __author__ = 'David M. Brown (davebs...@gmail.com)' +gremlin_server_url = os.environ.get('GREMLIN_SERVER_URL', 'ws://localhost:{}/gremlin') +test_no_auth_url = gremlin_server_url.format(45940) def test_conns_in_threads(remote_connection): q = queue.Queue() @@ -59,8 +62,7 @@ def _executor(q, conn): if not conn: # This isn't a fixture so close manually close = True - conn = DriverRemoteConnection( - 'ws://localhost:45940/gremlin', 'gmodern', pool_size=4) + conn = DriverRemoteConnection(test_no_auth_url, 'gmodern', pool_size=4) try: g = traversal().withRemote(conn) future = g.V().promise() @@ -77,7 +79,7 @@ def _executor(q, conn): def handle_request(): try: - remote_connection = DriverRemoteConnection("ws://localhost:45940/gremlin", "g") + remote_connection = DriverRemoteConnection(test_no_auth_url, "g") g = traversal().withRemote(remote_connection) g.V().limit(1).toList() remote_connection.close() diff --git a/gremlin-python/src/main/python/tests/process/test_traversal.py b/gremlin-python/src/main/python/tests/process/test_traversal.py index 7dffcb8303..84ccb97aa6 100644 --- a/gremlin-python/src/main/python/tests/process/test_traversal.py +++ b/gremlin-python/src/main/python/tests/process/test_traversal.py @@ -31,7 +31,7 @@ from gremlin_python.process.traversal import P from gremlin_python.process.traversal import Binding, Bindings from gremlin_python.process.graph_traversal import __ -gremlin_server_url = 'ws://localhost:{}/gremlin' +gremlin_server_url = os.environ.get('GREMLIN_SERVER_URL', 'ws://localhost:{}/gremlin') anonymous_url = gremlin_server_url.format(45940) diff --git a/pom.xml b/pom.xml index 930cd79e9a..d12e8e570d 100644 --- a/pom.xml +++ b/pom.xml @@ -447,6 +447,7 @@ limitations under the License. <exclude>**/docfx/**</exclude> <exclude>**/go.sum</exclude> <exclude>**/coverage.out</exclude> + <exclude>**/gremlinconsoletest.egg-info/**</exclude> </excludes> <licenses> <license implementation="org.apache.rat.analysis.license.ApacheSoftwareLicense20"/>