SuccessConsole Output

Started calculate disk usage of build
Finished Calculation of disk usage of build in 0 seconds
Started calculate disk usage of workspace
Finished Calculation of disk usage of workspace in 0 seconds
[INFO]                                                                         
[INFO] ------------------------------------------------------------------------
[INFO] Building GeoGig Web API Automated Functional Tests 1.1.1-RC1
[INFO] ------------------------------------------------------------------------
[INFO] 
[INFO] --- maven-clean-plugin:2.5:clean (default-clean) @ geogig-web-api-functional-tests ---
[INFO] Deleting /home/hudson/genie.geogig/.jenkins/jobs/geogig-release/workspace/src/web/functional/target
[INFO] 
[INFO] --- git-commit-id-plugin:2.2.2:revision (default) @ geogig-web-api-functional-tests ---
[INFO] 
[INFO] --- maven-resources-plugin:2.6:resources (default-resources) @ geogig-web-api-functional-tests ---
[INFO] Using 'UTF-8' encoding to copy filtered resources.
[INFO] Copying 1 resource
[INFO] 
[INFO] --- maven-compiler-plugin:3.1:compile (default-compile) @ geogig-web-api-functional-tests ---
[INFO] No sources to compile
[INFO] 
[INFO] --- maven-resources-plugin:2.6:testResources (default-testResources) @ geogig-web-api-functional-tests ---
[INFO] Using 'UTF-8' encoding to copy filtered resources.
[INFO] Copying 50 resources
[INFO] 
[INFO] --- maven-compiler-plugin:3.1:testCompile (default-testCompile) @ geogig-web-api-functional-tests ---
[INFO] Changes detected - recompiling the module!
[INFO] Compiling 16 source files to /home/hudson/genie.geogig/.jenkins/jobs/geogig-release/workspace/src/web/functional/target/test-classes
[INFO] 
[INFO] --- maven-surefire-plugin:2.17:test (default-test) @ geogig-web-api-functional-tests ---
[INFO] Surefire report directory: /home/hudson/genie.geogig/.jenkins/jobs/geogig-release/workspace/src/web/functional/target/surefire-reports

-------------------------------------------------------
 T E S T S
-------------------------------------------------------

-------------------------------------------------------
 T E S T S
-------------------------------------------------------
Running org.geogig.web.functional.WebAPICucumberHooksTest
Running org.geogig.web.functional.RunFunctionalTest
Running org.geogig.web.functional.MissingResolversTest
Running org.geogig.web.functional.InitFunctionalTest
Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.077 sec - in org.geogig.web.functional.WebAPICucumberHooksTest
Feature: GeoGig Repository initialization tests specific to stand-alone server
# Copyright (c) 2017 Boundless and others.
# All rights reserved. This program and the accompanying materials
# are made available under the terms of the Eclipse Distribution License v1.0
# which accompanies this distribution, and is available at
# https://www.eclipse.org/org/documents/edl-v10.html
#
# Contributors:
# Erik Merkle (Boundless) - initial implementation
@CreateRepository @MissingBackend
Feature: Tests Init request behavior when certain repository backends backend are not available
[main] INFO org.mortbay.log - Logging to org.slf4j.impl.SimpleLogger(org.mortbay.log) via org.mortbay.log.Slf4jLog
[main] INFO org.mortbay.log - Logging to org.slf4j.impl.SimpleLogger(org.mortbay.log) via org.mortbay.log.Slf4jLog
@Commands @Add
Feature: Add
  The add command allows a user to stage features in the repository and is supported through the "/repos/{repository}/add" endpoint
  The command must be executed using the HTTP GET method
[main] INFO org.mortbay.log - Logging to org.slf4j.impl.SimpleLogger(org.mortbay.log) via org.mortbay.log.Slf4jLog

  Scenario: Init request for RocksDB repo with RocksDB backend missing                                                             # MissingResolvers.feature:13
    Given There is an empty multirepo server                                                                                       # WebAPICucumberHooks.setUpEmptyMultiRepo()
    And I have disabled backends: "Directory"                                                                                      # WebAPICucumberHooks.i_have_plugin_without_backend(String)
    When I "PUT" content-type "application/json" to "/repos/repo1/init" with                                                       # WebAPICucumberHooks.requestWithContent(String,String,String,String)
      """
      {
        "parentDirectory":"{@systemTempPath}"
      }
      """
    Then the response status should be '400'                                                                                       # WebAPICucumberHooks.checkStatusCode(int)
    And the response ContentType should be "application/xml"                                                                       # WebAPICucumberHooks.checkContentType(String)
    And the xpath "/response/success/text()" equals "false"                                                                        # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xpath "/response/error/text()" contains "No repository initializer found capable of handling this kind of URI: file:/" # WebAPICucumberHooks.checkXPathValueContains(String,String)

  Scenario: Init request for RocksDB repo with RocksDB backend missing, JSON response                                                    # MissingResolvers.feature:27
    Given There is an empty multirepo server                                                                                             # WebAPICucumberHooks.setUpEmptyMultiRepo()
    And I have disabled backends: "Directory"                                                                                            # WebAPICucumberHooks.i_have_plugin_without_backend(String)
    When I "PUT" content-type "application/json" to "/repos/repo1/init.json" with                                                        # WebAPICucumberHooks.requestWithContent(String,String,String,String)
      """
      {
        "parentDirectory":"{@systemTempPath}"
      }
      """
    Then the response status should be '400'                                                                                             # WebAPICucumberHooks.checkStatusCode(int)
    And the response ContentType should be "application/json"                                                                            # WebAPICucumberHooks.checkContentType(String)
    And the json object "response.success" equals "false"                                                                                # WebAPICucumberHooks.checkJSONResponse(String,String)
    And the json response "response.error" should contain "No repository initializer found capable of handling this kind of URI: file:/" # WebAPICucumberHooks.checkJSONResponseContains(String,String)

  Scenario: Init request for PostgreSQL repo with PostgreSQL backend missing                                                             # MissingResolvers.feature:41
    Given There is an empty multirepo server                                                                                             # WebAPICucumberHooks.setUpEmptyMultiRepo()
    And I have disabled backends: "PostgreSQL"                                                                                           # WebAPICucumberHooks.i_have_plugin_without_backend(String)
    When I "PUT" content-type "application/json" to "/repos/repo1/init" with                                                             # WebAPICucumberHooks.requestWithContent(String,String,String,String)
      """
      {
        "dbName":"database",
        "dbPassword":"password"
      }
      """
    Then the response status should be '400'                                                                                             # WebAPICucumberHooks.checkStatusCode(int)
    And the response ContentType should be "application/xml"                                                                             # WebAPICucumberHooks.checkContentType(String)
    And the xpath "/response/success/text()" equals "false"                                                                              # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xpath "/response/error/text()" contains "No repository initializer found capable of handling this kind of URI: postgresql:/" # WebAPICucumberHooks.checkXPathValueContains(String,String)

  Scenario: Init request for PostgreSQL repo with PostgreSQL backend missing, JSON response                                                    # MissingResolvers.feature:56
    Given There is an empty multirepo server                                                                                                   # WebAPICucumberHooks.setUpEmptyMultiRepo()
    And I have disabled backends: "PostgreSQL"                                                                                                 # WebAPICucumberHooks.i_have_plugin_without_backend(String)
    When I "PUT" content-type "application/json" to "/repos/repo1/init.json" with                                                              # WebAPICucumberHooks.requestWithContent(String,String,String,String)
      """
      {
        "dbName":"database",
        "dbPassword":"password"
      }
      """
    Then the response status should be '400'                                                                                                   # WebAPICucumberHooks.checkStatusCode(int)
    And the response ContentType should be "application/json"                                                                                  # WebAPICucumberHooks.checkContentType(String)
    And the json object "response.success" equals "false"                                                                                      # WebAPICucumberHooks.checkJSONResponse(String,String)
    And the json response "response.error" should contain "No repository initializer found capable of handling this kind of URI: postgresql:/" # WebAPICucumberHooks.checkJSONResponseContains(String,String)

  Scenario: Init request for RocksDB repo with PostgreSQL backend missing      # MissingResolvers.feature:71
    Given There is an empty multirepo server                                   # WebAPICucumberHooks.setUpEmptyMultiRepo()
    And I have disabled backends: "PostgreSQL"                                 # WebAPICucumberHooks.i_have_plugin_without_backend(String)
    When I "PUT" content-type "application/json" to "/repos/repo1/init" with   # WebAPICucumberHooks.requestWithContent(String,String,String,String)
      """
      {
        "parentDirectory":"{@systemTempPath}"
      }
      """
    Then the response status should be '201'                                   # WebAPICucumberHooks.checkStatusCode(int)
    And the response ContentType should be "application/xml"                   # WebAPICucumberHooks.checkContentType(String)
    And the xpath "/response/success/text()" equals "true"                     # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xpath "/response/repo/name/text()" equals "repo1"                  # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xpath "/response/repo/atom:link/@href" contains "/repos/repo1.xml" # WebAPICucumberHooks.checkXPathValueContains(String,String)
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo1 using FileRepositoryResolver

  Scenario: Init request for RocksDB repo with PostgreSQL backend missing, JSON response # MissingResolvers.feature:86
    Given There is an empty multirepo server                                             # WebAPICucumberHooks.setUpEmptyMultiRepo()
    And I have disabled backends: "PostgreSQL"                                           # WebAPICucumberHooks.i_have_plugin_without_backend(String)
    When I "PUT" content-type "application/json" to "/repos/repo1/init.json" with        # WebAPICucumberHooks.requestWithContent(String,String,String,String)
      """
      {
        "parentDirectory":"{@systemTempPath}"
      }
      """
    Then the response status should be '201'                                             # WebAPICucumberHooks.checkStatusCode(int)
    And the response ContentType should be "application/json"                            # WebAPICucumberHooks.checkContentType(String)
    And the json object "response.success" equals "true"                                 # WebAPICucumberHooks.checkJSONResponse(String,String)
    And the json object "response.repo.name" equals "repo1"                              # WebAPICucumberHooks.checkJSONResponse(String,String)
    And the json object "response.repo.href" ends with "/repos/repo1.json"               # WebAPICucumberHooks.checkJSONResponseEndsWith(String,String)

  Scenario: Init request for RocksDB repo with RocksDB and PostgreSQL backends missing                                             # MissingResolvers.feature:101
    Given There is an empty multirepo server                                                                                       # WebAPICucumberHooks.setUpEmptyMultiRepo()
    And I have disabled backends: "Directory, PostgreSQL"                                                                          # WebAPICucumberHooks.i_have_plugin_without_backend(String)
    When I "PUT" content-type "application/json" to "/repos/repo1/init" with                                                       # WebAPICucumberHooks.requestWithContent(String,String,String,String)
      """
      {
        "parentDirectory":"{@systemTempPath}"
      }
      """
    Then the response status should be '400'                                                                                       # WebAPICucumberHooks.checkStatusCode(int)
    And the response ContentType should be "application/xml"                                                                       # WebAPICucumberHooks.checkContentType(String)
    And the xpath "/response/success/text()" equals "false"                                                                        # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xpath "/response/error/text()" contains "No repository initializer found capable of handling this kind of URI: file:/" # WebAPICucumberHooks.checkXPathValueContains(String,String)

  Scenario: Init request for RocksDB repo with RocksDB and PostgreSQL backends missing, JSON response                                    # MissingResolvers.feature:115
    Given There is an empty multirepo server                                                                                             # WebAPICucumberHooks.setUpEmptyMultiRepo()
    And I have disabled backends: "Directory, PostgreSQL"                                                                                # WebAPICucumberHooks.i_have_plugin_without_backend(String)
    When I "PUT" content-type "application/json" to "/repos/repo1/init.json" with                                                        # WebAPICucumberHooks.requestWithContent(String,String,String,String)
      """
      {
        "parentDirectory":"{@systemTempPath}"
      }
      """
    Then the response status should be '400'                                                                                             # WebAPICucumberHooks.checkStatusCode(int)
    And the response ContentType should be "application/json"                                                                            # WebAPICucumberHooks.checkContentType(String)
    And the json object "response.success" equals "false"                                                                                # WebAPICucumberHooks.checkJSONResponse(String,String)
    And the json response "response.error" should contain "No repository initializer found capable of handling this kind of URI: file:/" # WebAPICucumberHooks.checkJSONResponseContains(String,String)

  Scenario: Init request for PostgreSQL repo with RocksDB and PostgreSQL backends missing                                                # MissingResolvers.feature:129
    Given There is an empty multirepo server                                                                                             # WebAPICucumberHooks.setUpEmptyMultiRepo()
    And I have disabled backends: "Directory, PostgreSQL"                                                                                # WebAPICucumberHooks.i_have_plugin_without_backend(String)
    When I "PUT" content-type "application/json" to "/repos/repo1/init" with                                                             # WebAPICucumberHooks.requestWithContent(String,String,String,String)
      """
      {
        "dbName":"database",
        "dbPassword":"password"
      }
      """
    Then the response status should be '400'                                                                                             # WebAPICucumberHooks.checkStatusCode(int)
    And the response ContentType should be "application/xml"                                                                             # WebAPICucumberHooks.checkContentType(String)
    And the xpath "/response/success/text()" equals "false"                                                                              # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xpath "/response/error/text()" contains "No repository initializer found capable of handling this kind of URI: postgresql:/" # WebAPICucumberHooks.checkXPathValueContains(String,String)
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()

  Scenario: Verify wrong HTTP method issues 405 "Method not allowed" # Add.feature:6
    Given There is an empty repository named repo1                   # WebAPICucumberHooks.setUpEmptyRepo(String)
    When I call "PUT /repos/repo1/add"                               # WebAPICucumberHooks.callURL(String)
    Then the response status should be '405'                         # WebAPICucumberHooks.checkStatusCode(int)
    And the response allowed methods should be "GET"                 # WebAPICucumberHooks.checkResponseAllowedMethods(String)

  Scenario: Init request for PostgreSQL repo with RocksDB and PostgreSQL backends missing, JSON response                                       # MissingResolvers.feature:144
    Given There is an empty multirepo server                                                                                                   # WebAPICucumberHooks.setUpEmptyMultiRepo()
    And I have disabled backends: "Directory, PostgreSQL"                                                                                      # WebAPICucumberHooks.i_have_plugin_without_backend(String)
    When I "PUT" content-type "application/json" to "/repos/repo1/init.json" with                                                              # WebAPICucumberHooks.requestWithContent(String,String,String,String)
      """
      {
        "dbName":"database",
        "dbPassword":"password"
      }
      """
    Then the response status should be '400'                                                                                                   # WebAPICucumberHooks.checkStatusCode(int)
    And the response ContentType should be "application/json"                                                                                  # WebAPICucumberHooks.checkContentType(String)
    And the json object "response.success" equals "false"                                                                                      # WebAPICucumberHooks.checkJSONResponse(String,String)
    And the json response "response.error" should contain "No repository initializer found capable of handling this kind of URI: postgresql:/" # WebAPICucumberHooks.checkJSONResponseContains(String,String)

10 Scenarios (10 passed)
72 Steps (72 passed)
0m2.225s

Tests run: 82, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 3.08 sec - in org.geogig.web.functional.MissingResolversTest
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo1 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()

  Scenario: Adding outside of a transaction issues 500 "Transaction required"      # Add.feature:12
    Given There is an empty repository named repo1                                 # WebAPICucumberHooks.setUpEmptyRepo(String)
    When I call "GET /repos/repo1/add"                                             # WebAPICucumberHooks.callURL(String)
    Then the response status should be '500'                                       # WebAPICucumberHooks.checkStatusCode(int)
    And the xpath "/response/error/text()" contains "No transaction was specified" # WebAPICucumberHooks.checkXPathValueContains(String,String)
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo1 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo1 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()

  Scenario: Adding outside of a repository issues 404 "Not found" # Add.feature:18
    Given There is an empty multirepo server                      # WebAPICucumberHooks.setUpEmptyMultiRepo()
    When I call "GET /repos/repo1/add"                            # WebAPICucumberHooks.callURL(String)
    Then the response status should be '404'                      # WebAPICucumberHooks.checkStatusCode(int)
    And the response ContentType should be "text/plain"           # WebAPICucumberHooks.checkContentType(String)
    And the response body should contain "Repository not found"   # WebAPICucumberHooks.checkResponseTextContains(String)
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo1 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo2 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()

  @CreateRepository
  Scenario: Verify trying to create a repo issues 409 "Conflict" when a repo with the same name already exists # InitConflict.feature:4
    Given There is a default multirepo server                                                                  # WebAPICucumberHooks.setUpDefaultMultiRepo()
    When I "PUT" content-type "application/json" to "/repos/repo1/init.json" with                              # WebAPICucumberHooks.requestWithContent(String,String,String,String)
      """
      {
      }
      """
    Then the response status should be '409'                                                                   # WebAPICucumberHooks.checkStatusCode(int)
    And the response ContentType should be "application/json"                                                  # WebAPICucumberHooks.checkContentType(String)
    And the json object "response.success" equals "false"                                                      # WebAPICucumberHooks.checkJSONResponse(String,String)
    And the json object "response.error" equals "Cannot run init on an already initialized repository."        # WebAPICucumberHooks.checkJSONResponse(String,String)
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()

  Scenario: Adding with no path filter stages all features                                               # Add.feature:25
    Given There is an empty repository named repo1                                                       # WebAPICucumberHooks.setUpEmptyRepo(String)
    And I have a transaction as "@txId" on the "repo1" repo                                              # WebAPICucumberHooks.beginTransactionAsVariable(String,String)
    And I have unstaged "Point.1" on the "repo1" repo in the "@txId" transaction                         # WebAPICucumberHooks.I_have_unstaged(String,String,String)
    And I have unstaged "Point.2" on the "repo1" repo in the "@txId" transaction                         # WebAPICucumberHooks.I_have_unstaged(String,String,String)
    And I have unstaged "Line.1" on the "repo1" repo in the "@txId" transaction                          # WebAPICucumberHooks.I_have_unstaged(String,String,String)
    And the repo1 repository's "STAGE_HEAD" in the @txId transaction should have the following features: # WebAPICucumberHooks.verifyRepositoryContentsTx(String,String,String,DataTable)
    When I call "GET /repos/repo1/add?transactionId={@txId}"                                             # WebAPICucumberHooks.callURL(String)
    Then the response status should be '200'                                                             # WebAPICucumberHooks.checkStatusCode(int)
    And the xpath "/response/success/text()" equals "true"                                               # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xpath "/response/Add/text()" equals "Success"                                                # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the repo1 repository's "STAGE_HEAD" in the @txId transaction should have the following features: # WebAPICucumberHooks.verifyRepositoryContentsTx(String,String,String,DataTable)
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo1 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()

  Scenario: Adding with a path filter stages specified features                                          # Add.feature:42
    Given There is an empty repository named repo1                                                       # WebAPICucumberHooks.setUpEmptyRepo(String)
    And I have a transaction as "@txId" on the "repo1" repo                                              # WebAPICucumberHooks.beginTransactionAsVariable(String,String)
    And I have unstaged "Point.1" on the "repo1" repo in the "@txId" transaction                         # WebAPICucumberHooks.I_have_unstaged(String,String,String)
    And I have unstaged "Point.2" on the "repo1" repo in the "@txId" transaction                         # WebAPICucumberHooks.I_have_unstaged(String,String,String)
    And I have unstaged "Line.1" on the "repo1" repo in the "@txId" transaction                          # WebAPICucumberHooks.I_have_unstaged(String,String,String)
    And the repo1 repository's "STAGE_HEAD" in the @txId transaction should have the following features: # WebAPICucumberHooks.verifyRepositoryContentsTx(String,String,String,DataTable)
    When I call "GET /repos/repo1/add?path=Points/Point.1&transactionId={@txId}"                         # WebAPICucumberHooks.callURL(String)
    Then the response status should be '200'                                                             # WebAPICucumberHooks.checkStatusCode(int)
    And the xpath "/response/success/text()" equals "true"                                               # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xpath "/response/Add/text()" equals "Success"                                                # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the repo1 repository's "STAGE_HEAD" in the @txId transaction should have the following features: # WebAPICucumberHooks.verifyRepositoryContentsTx(String,String,String,DataTable)
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo1 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo2 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()

  Scenario: Adding on a conflicted path resolves the conflict                     # Add.feature:58
    Given There is an empty repository named repo1                                # WebAPICucumberHooks.setUpEmptyRepo(String)
    And I have a transaction as "@txId" on the "repo1" repo                       # WebAPICucumberHooks.beginTransactionAsVariable(String,String)
    And There are conflicts on the "repo1" repo in the @txId transaction          # WebAPICucumberHooks.There_are_conflict(String,String)
    When I call "GET /repos/repo1/add?path=Points/Point.1&transactionId={@txId}"  # WebAPICucumberHooks.callURL(String)
    Then the response status should be '200'                                      # WebAPICucumberHooks.checkStatusCode(int)
    And the xpath "/response/success/text()" equals "true"                        # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xpath "/response/Add/text()" equals "Success"                         # WebAPICucumberHooks.checkXPathEquals(String,String)
    And There should be no conflicts on the "repo1" repo in the @txId transaction # WebAPICucumberHooks.There_should_be_no_conflicts(String,String)
@Repo @AffectedFeatures
Feature: AffectedFeatures
  The AffectedFeatures resource provides a list of features changed in a commit and is supported through the "/repos/{repository}/repo/affectedfeatures" endpoint
  The command must be executed using the HTTP GET method
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo1 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo1 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()

  @CreateRepository
  Scenario: Verify trying to create a repo issues 409 "Conflict" when a repo with the same name already exists, with parentDirectory # InitConflict.feature:17
    Given There is a default multirepo server                                                                                        # WebAPICucumberHooks.setUpDefaultMultiRepo()
    When I "PUT" content-type "application/json" to "/repos/repo1/init.json" with                                                    # WebAPICucumberHooks.requestWithContent(String,String,String,String)
      """
      {
        "parentDirectory": "{@systemTempPath}"
      }
      """
    Then the response status should be '409'                                                                                         # WebAPICucumberHooks.checkStatusCode(int)
    And the response ContentType should be "application/json"                                                                        # WebAPICucumberHooks.checkContentType(String)
    And the json object "response.success" equals "false"                                                                            # WebAPICucumberHooks.checkJSONResponse(String,String)
    And the json object "response.error" equals "Cannot run init on an already initialized repository."                              # WebAPICucumberHooks.checkJSONResponse(String,String)

2 Scenarios (2 passed)
12 Steps (12 passed)
0m4.313s

Tests run: 14, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 5.08 sec - in org.geogig.web.functional.InitFunctionalTest
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()

  Scenario: Verify wrong HTTP method issues 405 "Method not allowed" # AffectedFeatures.feature:6
    Given There is an empty repository named repo1                   # WebAPICucumberHooks.setUpEmptyRepo(String)
    When I call "PUT /repos/repo1/repo/affectedfeatures"             # WebAPICucumberHooks.callURL(String)
    Then the response status should be '405'                         # WebAPICucumberHooks.checkStatusCode(int)
    And the response allowed methods should be "GET"                 # WebAPICucumberHooks.checkResponseAllowedMethods(String)
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo1 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()

  Scenario: AffectedFeatures outside of a repository issues 404 "Not found" # AffectedFeatures.feature:12
    Given There is an empty multirepo server                                # WebAPICucumberHooks.setUpEmptyMultiRepo()
    When I call "GET /repos/repo1/repo/affectedfeatures"                    # WebAPICucumberHooks.callURL(String)
    Then the response status should be '404'                                # WebAPICucumberHooks.checkStatusCode(int)
    And the response ContentType should be "text/plain"                     # WebAPICucumberHooks.checkContentType(String)
    And the response body should contain "Repository not found"             # WebAPICucumberHooks.checkResponseTextContains(String)
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo1 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()

  Scenario: AffectedFeatures with no commit issues a 400 status code     # AffectedFeatures.feature:19
    Given There is an empty repository named repo1                       # WebAPICucumberHooks.setUpEmptyRepo(String)
    When I call "GET /repos/repo1/repo/affectedfeatures"                 # WebAPICucumberHooks.callURL(String)
    Then the response status should be '400'                             # WebAPICucumberHooks.checkStatusCode(int)
    And the response body should contain "You must specify a commit id." # WebAPICucumberHooks.checkResponseTextContains(String)
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo1 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()

  Scenario: AffectedFeatures with an invalid commit issues a 400 status code   # AffectedFeatures.feature:25
    Given There is an empty repository named repo1                             # WebAPICucumberHooks.setUpEmptyRepo(String)
    When I call "GET /repos/repo1/repo/affectedfeatures?commitId=invalid"      # WebAPICucumberHooks.callURL(String)
    Then the response status should be '400'                                   # WebAPICucumberHooks.checkStatusCode(int)
    And the response body should contain "You must specify a valid commit id." # WebAPICucumberHooks.checkResponseTextContains(String)
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo1 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo2 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()

  Scenario: AffectedFeatures lists all features changed in a commit                        # AffectedFeatures.feature:31
    Given There is a default multirepo server                                              # WebAPICucumberHooks.setUpDefaultMultiRepo()
    And I have committed "Point.1_modified" on the "repo1" repo in the "" transaction      # WebAPICucumberHooks.I_have_committed(String,String,String)
    When I call "GET /repos/repo1/repo/affectedfeatures?commitId={@ObjectId|repo1|master}" # WebAPICucumberHooks.callURL(String)
    Then the response status should be '200'                                               # WebAPICucumberHooks.checkStatusCode(int)
    And the response ContentType should be "text/plain"                                    # WebAPICucumberHooks.checkContentType(String)
    And the response body should contain "{@ObjectId|repo1|master~1:Points/Point.1}"       # WebAPICucumberHooks.checkResponseTextContains(String)
@Commands @Blame
Feature: Blame
  The blame command allows a user to see who last modified each attribute of a feature and is supported through the "/repos/{repository}/blame" endpoint
  The command must be executed using the HTTP GET method
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo1 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()

  Scenario: Verify wrong HTTP method issues 405 "Method not allowed" # Blame.feature:6
    Given There is an empty repository named repo1                   # WebAPICucumberHooks.setUpEmptyRepo(String)
    When I call "PUT /repos/repo1/blame"                             # WebAPICucumberHooks.callURL(String)
    Then the response status should be '405'                         # WebAPICucumberHooks.checkStatusCode(int)
    And the response allowed methods should be "GET"                 # WebAPICucumberHooks.checkResponseAllowedMethods(String)
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo1 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()

  Scenario: Calling blame without a feature path issues a 500 status code                         # Blame.feature:12
    Given There is an empty repository named repo1                                                # WebAPICucumberHooks.setUpEmptyRepo(String)
    When I call "GET /repos/repo1/blame"                                                          # WebAPICucumberHooks.callURL(String)
    Then the response status should be '500'                                                      # WebAPICucumberHooks.checkStatusCode(int)
    And the xpath "/response/error/text()" contains "Required parameter 'path' was not provided." # WebAPICucumberHooks.checkXPathValueContains(String,String)
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo1 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()

  Scenario: Calling blame with an invalid commit issues a 500 status code                # Blame.feature:18
    Given There is an empty repository named repo1                                       # WebAPICucumberHooks.setUpEmptyRepo(String)
    When I call "GET /repos/repo1/blame?commit=nonexistent&path=somePath"                # WebAPICucumberHooks.callURL(String)
    Then the response status should be '500'                                             # WebAPICucumberHooks.checkStatusCode(int)
    And the xpath "/response/error/text()" contains "Could not resolve branch or commit" # WebAPICucumberHooks.checkXPathValueContains(String,String)
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo1 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()

  Scenario: Calling blame with an invalid feature path issues a 500 status code        # Blame.feature:24
    Given There is an empty repository named repo1                                     # WebAPICucumberHooks.setUpEmptyRepo(String)
    When I call "GET /repos/repo1/blame?path=nonexistent"                              # WebAPICucumberHooks.callURL(String)
    Then the response status should be '500'                                           # WebAPICucumberHooks.checkStatusCode(int)
    And the xpath "/response/error/text()" contains "The supplied path does not exist" # WebAPICucumberHooks.checkXPathValueContains(String,String)
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo1 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo2 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()

  Scenario: Calling blame with a tree path issues a 500 status code                                   # Blame.feature:30
    Given There is a default multirepo server                                                         # WebAPICucumberHooks.setUpDefaultMultiRepo()
    When I call "GET /repos/repo1/blame?path=Points"                                                  # WebAPICucumberHooks.callURL(String)
    Then the response status should be '500'                                                          # WebAPICucumberHooks.checkStatusCode(int)
    And the xpath "/response/error/text()" contains "The supplied path does not resolve to a feature" # WebAPICucumberHooks.checkXPathValueContains(String,String)
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo1 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()

  Scenario: Calling blame with a feature path shows who modified each attribute                            # Blame.feature:36
    Given There is an empty repository named repo1                                                         # WebAPICucumberHooks.setUpEmptyRepo(String)
    And There is a feature with multiple authors on the "repo1" repo                                       # WebAPICucumberHooks.There_is_a_feature_with_multiple_authors(String)
    When I call "GET /repos/repo1/blame?path=Points/Point.1"                                               # WebAPICucumberHooks.callURL(String)
    Then the response status should be '200'                                                               # WebAPICucumberHooks.checkStatusCode(int)
    And the xpath "/response/success/text()" equals "true"                                                 # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xml response should contain "/response/Blame/Attribute" 3 times                                # WebAPICucumberHooks.checkXPathCadinality(String,int)
    And there is an xpath "/response/Blame/Attribute/commit/author/name/text()" that equals "Author1"      # WebAPICucumberHooks.checkOneXPathEquals(String,String)
    And there is an xpath "/response/Blame/Attribute/commit/message/text()" that equals "Added Point.1"    # WebAPICucumberHooks.checkOneXPathEquals(String,String)
    And there is an xpath "/response/Blame/Attribute/commit/author/name/text()" that equals "Author2"      # WebAPICucumberHooks.checkOneXPathEquals(String,String)
    And there is an xpath "/response/Blame/Attribute/commit/message/text()" that equals "Modified Point.1" # WebAPICucumberHooks.checkOneXPathEquals(String,String)
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo1 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()

  Scenario: Calling blame with a feature path and commit shows who modified each attribute # Blame.feature:48
    Given There is an empty repository named repo1                                         # WebAPICucumberHooks.setUpEmptyRepo(String)
    And There is a feature with multiple authors on the "repo1" repo                       # WebAPICucumberHooks.There_is_a_feature_with_multiple_authors(String)
    When I call "GET /repos/repo1/blame?path=Points/Point.1&commit=HEAD~1"                 # WebAPICucumberHooks.callURL(String)
    Then the response status should be '200'                                               # WebAPICucumberHooks.checkStatusCode(int)
    And the xpath "/response/success/text()" equals "true"                                 # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xml response should contain "/response/Blame/Attribute" 3 times                # WebAPICucumberHooks.checkXPathCadinality(String,int)
    And the xpath "/response/Blame/Attribute/commit/author/name/text()" equals "Author1"   # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xpath "/response/Blame/Attribute/commit/message/text()" equals "Added Point.1" # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the response body should not contain "Author2"                                     # WebAPICucumberHooks.checkResponseTextNotContains(String)
    And the response body should not contain "Modified Point.1"                            # WebAPICucumberHooks.checkResponseTextNotContains(String)
@Commands @Branch
Feature: Branch
  The branch command allows a user to create and list branches and is supported through the "/repos/{repository}/branch" endpoint
  The command must be executed using the HTTP GET method
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo1 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()

  Scenario: Verify wrong HTTP method issues 405 "Method not allowed" # Branch.feature:6
    Given There is an empty repository named repo1                   # WebAPICucumberHooks.setUpEmptyRepo(String)
    When I call "PUT /repos/repo1/branch"                            # WebAPICucumberHooks.callURL(String)
    Then the response status should be '405'                         # WebAPICucumberHooks.checkStatusCode(int)
    And the response allowed methods should be "GET"                 # WebAPICucumberHooks.checkResponseAllowedMethods(String)
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo1 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()

  Scenario: Calling branch without specifying list or a branch name issues a 500 status code # Branch.feature:12
    Given There is an empty repository named repo1                                           # WebAPICucumberHooks.setUpEmptyRepo(String)
    When I call "GET /repos/repo1/branch"                                                    # WebAPICucumberHooks.callURL(String)
    Then the response status should be '500'                                                 # WebAPICucumberHooks.checkStatusCode(int)
    And the xpath "/response/error/text()" contains "Nothing to do."                         # WebAPICucumberHooks.checkXPathValueContains(String,String)
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo1 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()

  Scenario: Calling branch with the list parameter lists all local branches          # Branch.feature:18
    Given There is an empty repository named repo1                                   # WebAPICucumberHooks.setUpEmptyRepo(String)
    And There are multiple branches on the "repo1" repo                              # WebAPICucumberHooks.There_are_multiple_branches(String)
    When I call "GET /repos/repo1/branch?list=true"                                  # WebAPICucumberHooks.callURL(String)
    Then the response status should be '200'                                         # WebAPICucumberHooks.checkStatusCode(int)
    And the xpath "/response/success/text()" equals "true"                           # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xml response should contain "/response/Local/Branch" 3 times             # WebAPICucumberHooks.checkXPathCadinality(String,int)
    And the xml response should contain "/response/Remote/Branch" 0 times            # WebAPICucumberHooks.checkXPathCadinality(String,int)
    And there is an xpath "/response/Local/Branch/name/text()" that equals "master"  # WebAPICucumberHooks.checkOneXPathEquals(String,String)
    And there is an xpath "/response/Local/Branch/name/text()" that equals "branch1" # WebAPICucumberHooks.checkOneXPathEquals(String,String)
    And there is an xpath "/response/Local/Branch/name/text()" that equals "branch2" # WebAPICucumberHooks.checkOneXPathEquals(String,String)
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo1 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()

  Scenario: Calling branch with the list and remotes parameters lists all local and remote branches # Branch.feature:30
    Given There is an empty repository named repo1                                                  # WebAPICucumberHooks.setUpEmptyRepo(String)
    And There are multiple branches on the "repo1" repo                                             # WebAPICucumberHooks.There_are_multiple_branches(String)
    When I call "GET /repos/repo1/branch?list=true&remotes=true"                                    # WebAPICucumberHooks.callURL(String)
    Then the response status should be '200'                                                        # WebAPICucumberHooks.checkStatusCode(int)
    And the xpath "/response/success/text()" equals "true"                                          # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xml response should contain "/response/Local/Branch" 3 times                            # WebAPICucumberHooks.checkXPathCadinality(String,int)
    And the xml response should contain "/response/Remote/Branch" 3 times                           # WebAPICucumberHooks.checkXPathCadinality(String,int)
    And there is an xpath "/response/Local/Branch/name/text()" that equals "master"                 # WebAPICucumberHooks.checkOneXPathEquals(String,String)
    And there is an xpath "/response/Local/Branch/name/text()" that equals "branch1"                # WebAPICucumberHooks.checkOneXPathEquals(String,String)
    And there is an xpath "/response/Local/Branch/name/text()" that equals "branch2"                # WebAPICucumberHooks.checkOneXPathEquals(String,String)
    And there is an xpath "/response/Remote/Branch/remoteName/text()" that equals "origin"          # WebAPICucumberHooks.checkOneXPathEquals(String,String)
    And there is an xpath "/response/Remote/Branch/name/text()" that equals "master_remote"         # WebAPICucumberHooks.checkOneXPathEquals(String,String)
    And there is an xpath "/response/Remote/Branch/name/text()" that equals "branch1_remote"        # WebAPICucumberHooks.checkOneXPathEquals(String,String)
    And there is an xpath "/response/Remote/Branch/name/text()" that equals "branch2_remote"        # WebAPICucumberHooks.checkOneXPathEquals(String,String)
    And the response body should contain "branch2_remote"                                           # WebAPICucumberHooks.checkResponseTextContains(String)
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo1 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo2 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()

  Scenario: Calling branch with a branch name creates a new branch                          # Branch.feature:47
    Given There is a default multirepo server                                               # WebAPICucumberHooks.setUpDefaultMultiRepo()
    When I call "GET /repos/repo1/branch?branchName=new_branch"                             # WebAPICucumberHooks.callURL(String)
    Then the response status should be '200'                                                # WebAPICucumberHooks.checkStatusCode(int)
    And the xpath "/response/success/text()" equals "true"                                  # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xpath "/response/BranchCreated/name/text()" equals "new_branch"                 # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xpath "/response/BranchCreated/source/text()" equals "{@ObjectId|repo1|master}" # WebAPICucumberHooks.checkXPathEquals(String,String)
    When I call "GET /repos/repo1/repo/manifest"                                            # WebAPICucumberHooks.callURL(String)
    Then the response body should contain "new_branch"                                      # WebAPICucumberHooks.checkResponseTextContains(String)
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo1 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo2 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()

  Scenario: Calling branch with a branch name and source creates a new branch from the source # Branch.feature:57
    Given There is a default multirepo server                                                 # WebAPICucumberHooks.setUpDefaultMultiRepo()
    When I call "GET /repos/repo1/branch?branchName=new_branch&source=branch1"                # WebAPICucumberHooks.callURL(String)
    Then the response status should be '200'                                                  # WebAPICucumberHooks.checkStatusCode(int)
    And the xpath "/response/success/text()" equals "true"                                    # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xpath "/response/BranchCreated/name/text()" equals "new_branch"                   # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xpath "/response/BranchCreated/source/text()" equals "{@ObjectId|repo1|branch1}"  # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xml response should contain "/response/BranchCreated/source" 1 times              # WebAPICucumberHooks.checkXPathCadinality(String,int)
    When I call "GET /repos/repo1/repo/manifest"                                              # WebAPICucumberHooks.callURL(String)
    Then the response body should contain "new_branch"                                        # WebAPICucumberHooks.checkResponseTextContains(String)
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo1 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo2 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()

  Scenario: Calling branch with a branch name that already exists issues a 400 status code   # Branch.feature:68
    Given There is a default multirepo server                                                # WebAPICucumberHooks.setUpDefaultMultiRepo()
    When I call "GET /repos/repo1/branch?branchName=branch1"                                 # WebAPICucumberHooks.callURL(String)
    Then the response status should be '400'                                                 # WebAPICucumberHooks.checkStatusCode(int)
    And the xpath "/response/error/text()" equals "A branch named 'branch1' already exists." # WebAPICucumberHooks.checkXPathEquals(String,String)
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo1 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo2 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()

  Scenario: Calling branch with a source that does not exist issues a 400 status code                   # Branch.feature:74
    Given There is a default multirepo server                                                           # WebAPICucumberHooks.setUpDefaultMultiRepo()
    When I call "GET /repos/repo1/branch?branchName=new_branch&source=nonexistent"                      # WebAPICucumberHooks.callURL(String)
    Then the response status should be '400'                                                            # WebAPICucumberHooks.checkStatusCode(int)
    And the xpath "/response/error/text()" equals "nonexistent does not resolve to a repository object" # WebAPICucumberHooks.checkXPathEquals(String,String)
@Commands @Cat
Feature: Cat
  The cat command allows a user to display the attributes of a repository object and is supported through the "/repos/{repository}/cat" endpoint
  The command must be executed using the HTTP GET method
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo1 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()

  Scenario: Verify wrong HTTP method issues 405 "Method not allowed" # Cat.feature:6
    Given There is an empty repository named repo1                   # WebAPICucumberHooks.setUpEmptyRepo(String)
    When I call "PUT /repos/repo1/cat"                               # WebAPICucumberHooks.callURL(String)
    Then the response status should be '405'                         # WebAPICucumberHooks.checkStatusCode(int)
    And the response allowed methods should be "GET"                 # WebAPICucumberHooks.checkResponseAllowedMethods(String)
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo1 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()

  Scenario: Calling cat without specifying an object id issues a 500 status code                      # Cat.feature:12
    Given There is an empty repository named repo1                                                    # WebAPICucumberHooks.setUpEmptyRepo(String)
    When I call "GET /repos/repo1/cat"                                                                # WebAPICucumberHooks.callURL(String)
    Then the response status should be '500'                                                          # WebAPICucumberHooks.checkStatusCode(int)
    And the xpath "/response/error/text()" contains "Required parameter 'objectid' was not provided." # WebAPICucumberHooks.checkXPathValueContains(String,String)
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo1 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()

  Scenario: Calling cat with an invalid object id issues a 400 status code                        # Cat.feature:18
    Given There is an empty repository named repo1                                                # WebAPICucumberHooks.setUpEmptyRepo(String)
    When I call "GET /repos/repo1/cat?objectid=notobjectid"                                       # WebAPICucumberHooks.callURL(String)
    Then the response status should be '400'                                                      # WebAPICucumberHooks.checkStatusCode(int)
    And the xpath "/response/error/text()" contains "You must specify a valid non-null ObjectId." # WebAPICucumberHooks.checkXPathValueContains(String,String)
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo1 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()

  Scenario: Calling cat with a nonexistent object id issues a 400 status code                                  # Cat.feature:24
    Given There is an empty repository named repo1                                                             # WebAPICucumberHooks.setUpEmptyRepo(String)
    When I call "GET /repos/repo1/cat?objectid=0123456789012345678901234567890123456789"                       # WebAPICucumberHooks.callURL(String)
    Then the response status should be '400'                                                                   # WebAPICucumberHooks.checkStatusCode(int)
    And the xpath "/response/error/text()" contains "The specified ObjectId was not found in the respository." # WebAPICucumberHooks.checkXPathValueContains(String,String)
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo1 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo2 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()

  Scenario: Calling cat on a commit returns details of that commit                              # Cat.feature:30
    Given There is a default multirepo server                                                   # WebAPICucumberHooks.setUpDefaultMultiRepo()
    When I call "GET /repos/repo1/cat?objectid={@ObjectId|repo1|master}"                        # WebAPICucumberHooks.callURL(String)
    Then the response status should be '200'                                                    # WebAPICucumberHooks.checkStatusCode(int)
    And the xpath "/response/success/text()" equals "true"                                      # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xpath "/response/commit/id/text()" equals "{@ObjectId|repo1|master}"                # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xpath "/response/commit/parents/id/text()" equals "{@ObjectId|repo1|master~1}"      # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xpath "/response/commit/author/name/text()" equals "geogigUser"                     # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xpath "/response/commit/author/email/text()" equals "repo1_Owner@geogig.org"        # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xpath "/response/commit/committer/name/text()" equals "geogigUser"                  # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xpath "/response/commit/committer/email/text()" equals "repo1_Owner@geogig.org"     # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xpath "/response/commit/message/text()" contains "merge branch branch2 onto master" # WebAPICucumberHooks.checkXPathValueContains(String,String)
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo1 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo2 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()

  Scenario: Calling cat on a feature returns details of that feature                             # Cat.feature:43
    Given There is a default multirepo server                                                    # WebAPICucumberHooks.setUpDefaultMultiRepo()
    When I call "GET /repos/repo1/cat?objectid={@ObjectId|repo1|master:Points/Point.1}"          # WebAPICucumberHooks.callURL(String)
    Then the response status should be '200'                                                     # WebAPICucumberHooks.checkStatusCode(int)
    And the xpath "/response/success/text()" equals "true"                                       # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xpath "/response/feature/id/text()" equals "{@ObjectId|repo1|master:Points/Point.1}" # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xml response should contain "/response/feature/attribute" 3 times                    # WebAPICucumberHooks.checkXPathCadinality(String,int)
    And the response body should contain "StringProp1_1"                                         # WebAPICucumberHooks.checkResponseTextContains(String)
    And the response body should contain "1000"                                                  # WebAPICucumberHooks.checkResponseTextContains(String)
    And the response body should contain "POINT (0 0)"                                           # WebAPICucumberHooks.checkResponseTextContains(String)
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo1 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo2 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()

  Scenario: Calling cat on a feature tree returns details of that tree                # Cat.feature:54
    Given There is a default multirepo server                                         # WebAPICucumberHooks.setUpDefaultMultiRepo()
    When I call "GET /repos/repo1/cat?objectid={@ObjectId|repo1|master:Points}"       # WebAPICucumberHooks.callURL(String)
    Then the response status should be '200'                                          # WebAPICucumberHooks.checkStatusCode(int)
    And the xpath "/response/success/text()" equals "true"                            # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xpath "/response/tree/id/text()" equals "{@ObjectId|repo1|master:Points}" # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xpath "/response/tree/size/text()" equals "3"                             # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xpath "/response/tree/numtrees/text()" equals "0"                         # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xml response should contain "/response/tree/feature" 3 times              # WebAPICucumberHooks.checkXPathCadinality(String,int)
    And the response body should contain "Point.1"                                    # WebAPICucumberHooks.checkResponseTextContains(String)
    And the response body should contain "Point.2"                                    # WebAPICucumberHooks.checkResponseTextContains(String)
    And the response body should contain "Point.3"                                    # WebAPICucumberHooks.checkResponseTextContains(String)
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo1 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo2 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()

  Scenario: Calling cat on a tag returns details of that tag                                                              # Cat.feature:67
    Given There is a default multirepo server                                                                             # WebAPICucumberHooks.setUpDefaultMultiRepo()
    And There is a tag called "tag1" on the "repo1" repo pointing to "{@ObjectId|repo1|master}" with the "My tag" message # WebAPICucumberHooks.There_is_a_tag(String,String,String,String)
    When I call "GET /repos/repo1/cat?objectid={@ObjectId|repo1|refs/tags/tag1}"                                          # WebAPICucumberHooks.callURL(String)
    Then the response status should be '200'                                                                              # WebAPICucumberHooks.checkStatusCode(int)
    And the xpath "/response/success/text()" equals "true"                                                                # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xpath "/response/tag/id/text()" equals "{@ObjectId|repo1|refs/tags/tag1}"                                     # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xpath "/response/tag/commitid/text()" equals "{@ObjectId|repo1|master}"                                       # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xpath "/response/tag/name/text()" equals "tag1"                                                               # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xpath "/response/tag/message/text()" equals "My tag"                                                          # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xpath "/response/tag/tagger/name/text()" equals "geogigUser"                                                  # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xpath "/response/tag/tagger/email/text()" equals "repo1_Owner@geogig.org"                                     # WebAPICucumberHooks.checkXPathEquals(String,String)
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo1 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo2 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()

  Scenario: Calling cat on a feature type returns details of that feature type          # Cat.feature:80
    Given There is a default multirepo server                                           # WebAPICucumberHooks.setUpDefaultMultiRepo()
    When I call "GET /repos/repo1/cat?objectid={@PointsTypeID}"                         # WebAPICucumberHooks.callURL(String)
    Then the response status should be '200'                                            # WebAPICucumberHooks.checkStatusCode(int)
    And the xpath "/response/success/text()" equals "true"                              # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xpath "/response/featuretype/id/text()" equals "{@PointsTypeID}"            # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xpath "/response/featuretype/name/text()" equals "http://geogig.org:Points" # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xml response should contain "/response/featuretype/attribute" 3 times       # WebAPICucumberHooks.checkXPathCadinality(String,int)
    And the response body should contain "sp"                                           # WebAPICucumberHooks.checkResponseTextContains(String)
    And the response body should contain "ip"                                           # WebAPICucumberHooks.checkResponseTextContains(String)
    And the response body should contain "geom"                                         # WebAPICucumberHooks.checkResponseTextContains(String)
@Commands @Checkout
Feature: Checkout
  The checkout command allows a user to switch branches or resolve conflicts and is supported through the "/repos/{repository}/checkout" endpoint
  The command must be executed using the HTTP GET method
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo1 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()

  Scenario: Verify wrong HTTP method issues 405 "Method not allowed" # Checkout.feature:6
    Given There is an empty repository named repo1                   # WebAPICucumberHooks.setUpEmptyRepo(String)
    When I call "PUT /repos/repo1/checkout"                          # WebAPICucumberHooks.callURL(String)
    Then the response status should be '405'                         # WebAPICucumberHooks.checkStatusCode(int)
    And the response allowed methods should be "GET"                 # WebAPICucumberHooks.checkResponseAllowedMethods(String)
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo1 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()

  Scenario: Checkout outside of a transaction issues 500 "Transaction required"    # Checkout.feature:12
    Given There is an empty repository named repo1                                 # WebAPICucumberHooks.setUpEmptyRepo(String)
    When I call "GET /repos/repo1/checkout"                                        # WebAPICucumberHooks.callURL(String)
    Then the response status should be '500'                                       # WebAPICucumberHooks.checkStatusCode(int)
    And the xpath "/response/error/text()" contains "No transaction was specified" # WebAPICucumberHooks.checkXPathValueContains(String,String)
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo1 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()

  Scenario: Checkout outside of a repository issues 404 "Not found" # Checkout.feature:18
    Given There is an empty multirepo server                        # WebAPICucumberHooks.setUpEmptyMultiRepo()
    When I call "GET /repos/repo1/checkout"                         # WebAPICucumberHooks.callURL(String)
    Then the response status should be '404'                        # WebAPICucumberHooks.checkStatusCode(int)
    And the response ContentType should be "text/plain"             # WebAPICucumberHooks.checkContentType(String)
    And the response body should contain "Repository not found"     # WebAPICucumberHooks.checkResponseTextContains(String)
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo1 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()

  Scenario: Calling checkout without specifying a branch or path issues a 500 status code         # Checkout.feature:25
    Given There is an empty repository named repo1                                                # WebAPICucumberHooks.setUpEmptyRepo(String)
    And I have a transaction as "@txId" on the "repo1" repo                                       # WebAPICucumberHooks.beginTransactionAsVariable(String,String)
    When I call "GET /repos/repo1/checkout?transactionId={@txId}"                                 # WebAPICucumberHooks.callURL(String)
    Then the response status should be '500'                                                      # WebAPICucumberHooks.checkStatusCode(int)
    And the xpath "/response/error/text()" contains "No branch or commit specified for checkout." # WebAPICucumberHooks.checkXPathValueContains(String,String)
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo1 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo2 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()

  Scenario: Calling checkout with a branch name changes the current branch       # Checkout.feature:32
    Given There is a default multirepo server                                    # WebAPICucumberHooks.setUpDefaultMultiRepo()
    And I have a transaction as "@txId" on the "repo1" repo                      # WebAPICucumberHooks.beginTransactionAsVariable(String,String)
    When I call "GET /repos/repo1/checkout?transactionId={@txId}&branch=branch1" # WebAPICucumberHooks.callURL(String)
    Then the response status should be '200'                                     # WebAPICucumberHooks.checkStatusCode(int)
    And the xpath "/response/success/text()" equals "true"                       # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xpath "/response/OldTarget/text()" equals "refs/heads/master"        # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xpath "/response/NewTarget/text()" equals "branch1"                  # WebAPICucumberHooks.checkXPathEquals(String,String)
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo1 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()

  Scenario: Calling checkout with a conflicted path with 'ours' will checkout 'our' version of the feature                     # Checkout.feature:41
    Given There is an empty repository named repo1                                                                             # WebAPICucumberHooks.setUpEmptyRepo(String)
    And I have a transaction as "@txId" on the "repo1" repo                                                                    # WebAPICucumberHooks.beginTransactionAsVariable(String,String)
    And There are conflicts on the "repo1" repo in the @txId transaction                                                       # WebAPICucumberHooks.There_are_conflict(String,String)
    When I call "GET /repos/repo1/checkout?transactionId={@txId}&path=Points/Point.1&ours=true"                                # WebAPICucumberHooks.callURL(String)
    Then the response status should be '200'                                                                                   # WebAPICucumberHooks.checkStatusCode(int)
    And the xpath "/response/success/text()" equals "true"                                                                     # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xpath "/response/Path/text()" equals "Points/Point.1"                                                              # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xpath "/response/Strategy/text()" equals "ours"                                                                    # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the variable "{@ObjectId|repo1|@txId|WORK_HEAD:Points/Point.1}" equals "{@ObjectId|repo1|@txId|master:Points/Point.1}" # WebAPICucumberHooks.checkVariableEquals(String,String)
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo1 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()

  Scenario: Calling checkout with a conflicted path with 'theirs' will checkout 'their' version of the feature                  # Checkout.feature:52
    Given There is an empty repository named repo1                                                                              # WebAPICucumberHooks.setUpEmptyRepo(String)
    And I have a transaction as "@txId" on the "repo1" repo                                                                     # WebAPICucumberHooks.beginTransactionAsVariable(String,String)
    And There are conflicts on the "repo1" repo in the @txId transaction                                                        # WebAPICucumberHooks.There_are_conflict(String,String)
    When I call "GET /repos/repo1/checkout?transactionId={@txId}&path=Points/Point.1&theirs=true"                               # WebAPICucumberHooks.callURL(String)
    Then the response status should be '200'                                                                                    # WebAPICucumberHooks.checkStatusCode(int)
    And the xpath "/response/success/text()" equals "true"                                                                      # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xpath "/response/Path/text()" equals "Points/Point.1"                                                               # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xpath "/response/Strategy/text()" equals "theirs"                                                                   # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the variable "{@ObjectId|repo1|@txId|WORK_HEAD:Points/Point.1}" equals "{@ObjectId|repo1|@txId|branch1:Points/Point.1}" # WebAPICucumberHooks.checkVariableEquals(String,String)
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo1 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()

  Scenario: Calling checkout with a conflicted path with neither 'ours' or 'theirs' issues a 500 status code                   # Checkout.feature:63
    Given There is an empty repository named repo1                                                                             # WebAPICucumberHooks.setUpEmptyRepo(String)
    And I have a transaction as "@txId" on the "repo1" repo                                                                    # WebAPICucumberHooks.beginTransactionAsVariable(String,String)
    And There are conflicts on the "repo1" repo in the @txId transaction                                                       # WebAPICucumberHooks.There_are_conflict(String,String)
    When I call "GET /repos/repo1/checkout?transactionId={@txId}&path=Points/Point.1"                                          # WebAPICucumberHooks.callURL(String)
    Then the response status should be '500'                                                                                   # WebAPICucumberHooks.checkStatusCode(int)
    And the xpath "/response/error/text()" equals "Please specify either ours or theirs to update the feature path specified." # WebAPICucumberHooks.checkXPathEquals(String,String)
@Commands @Commit
Feature: Commit
  The commit command allows a user to commit staged changes and is supported through the "/repos/{repository}/commit" endpoint
  The command must be executed using the HTTP GET method
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo1 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()

  Scenario: Verify wrong HTTP method issues 405 "Method not allowed" # Commit.feature:6
    Given There is an empty repository named repo1                   # WebAPICucumberHooks.setUpEmptyRepo(String)
    When I call "PUT /repos/repo1/commit"                            # WebAPICucumberHooks.callURL(String)
    Then the response status should be '405'                         # WebAPICucumberHooks.checkStatusCode(int)
    And the response allowed methods should be "GET"                 # WebAPICucumberHooks.checkResponseAllowedMethods(String)
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo1 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()

  Scenario: Commit outside of a transaction issues 500 "Transaction required"      # Commit.feature:12
    Given There is an empty repository named repo1                                 # WebAPICucumberHooks.setUpEmptyRepo(String)
    When I call "GET /repos/repo1/commit"                                          # WebAPICucumberHooks.callURL(String)
    Then the response status should be '500'                                       # WebAPICucumberHooks.checkStatusCode(int)
    And the xpath "/response/error/text()" contains "No transaction was specified" # WebAPICucumberHooks.checkXPathValueContains(String,String)
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo1 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()

  Scenario: Commit outside of a repository issues 404 "Not found" # Commit.feature:18
    Given There is an empty multirepo server                      # WebAPICucumberHooks.setUpEmptyMultiRepo()
    When I call "GET /repos/repo1/commit"                         # WebAPICucumberHooks.callURL(String)
    Then the response status should be '404'                      # WebAPICucumberHooks.checkStatusCode(int)
    And the response ContentType should be "text/plain"           # WebAPICucumberHooks.checkContentType(String)
    And the response body should contain "Repository not found"   # WebAPICucumberHooks.checkResponseTextContains(String)
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo1 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()

  Scenario: Calling commit with no changes creates an empty commit                    # Commit.feature:25
    Given There is an empty repository named repo1                                    # WebAPICucumberHooks.setUpEmptyRepo(String)
    And I have a transaction as "@txId" on the "repo1" repo                           # WebAPICucumberHooks.beginTransactionAsVariable(String,String)
    When I call "GET /repos/repo1/commit?transactionId={@txId}&message=My%20Message"  # WebAPICucumberHooks.callURL(String)
    Then the response status should be '200'                                          # WebAPICucumberHooks.checkStatusCode(int)
    And the xpath "/response/success/text()" equals "true"                            # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xpath "/response/commitId/text()" equals "{@ObjectId|repo1|@txId|master}" # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xpath "/response/added/text()" equals "0"                                 # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xpath "/response/changed/text()" equals "0"                               # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xpath "/response/deleted/text()" equals "0"                               # WebAPICucumberHooks.checkXPathEquals(String,String)
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo1 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()

  Scenario: Calling commit with unstaged features creates an empty commit             # Commit.feature:36
    Given There is an empty repository named repo1                                    # WebAPICucumberHooks.setUpEmptyRepo(String)
    And I have a transaction as "@txId" on the "repo1" repo                           # WebAPICucumberHooks.beginTransactionAsVariable(String,String)
    And I have unstaged "Point.1" on the "repo1" repo in the "@txId" transaction      # WebAPICucumberHooks.I_have_unstaged(String,String,String)
    And I have unstaged "Point.2" on the "repo1" repo in the "@txId" transaction      # WebAPICucumberHooks.I_have_unstaged(String,String,String)
    And I have unstaged "Line.1" on the "repo1" repo in the "@txId" transaction       # WebAPICucumberHooks.I_have_unstaged(String,String,String)
    When I call "GET /repos/repo1/commit?transactionId={@txId}&message=My%20Message"  # WebAPICucumberHooks.callURL(String)
    Then the response status should be '200'                                          # WebAPICucumberHooks.checkStatusCode(int)
    And the xpath "/response/success/text()" equals "true"                            # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xpath "/response/commitId/text()" equals "{@ObjectId|repo1|@txId|master}" # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xpath "/response/added/text()" equals "0"                                 # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xpath "/response/changed/text()" equals "0"                               # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xpath "/response/deleted/text()" equals "0"                               # WebAPICucumberHooks.checkXPathEquals(String,String)
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo1 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()

  Scenario: Calling commit with staged features commits all staged features           # Commit.feature:51
    Given There is an empty repository named repo1                                    # WebAPICucumberHooks.setUpEmptyRepo(String)
    And I have a transaction as "@txId" on the "repo1" repo                           # WebAPICucumberHooks.beginTransactionAsVariable(String,String)
    And I have staged "Point.1" on the "repo1" repo in the "@txId" transaction        # WebAPICucumberHooks.I_have_staged(String,String,String)
    And I have staged "Point.2" on the "repo1" repo in the "@txId" transaction        # WebAPICucumberHooks.I_have_staged(String,String,String)
    And I have staged "Line.1" on the "repo1" repo in the "@txId" transaction         # WebAPICucumberHooks.I_have_staged(String,String,String)
    When I call "GET /repos/repo1/commit?transactionId={@txId}&message=My%20Message"  # WebAPICucumberHooks.callURL(String)
    Then the response status should be '200'                                          # WebAPICucumberHooks.checkStatusCode(int)
    And the xpath "/response/success/text()" equals "true"                            # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xpath "/response/commitId/text()" equals "{@ObjectId|repo1|@txId|master}" # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xpath "/response/added/text()" equals "3"                                 # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xpath "/response/changed/text()" equals "0"                               # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xpath "/response/deleted/text()" equals "0"                               # WebAPICucumberHooks.checkXPathEquals(String,String)
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo1 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()

  Scenario: I should be able supply commit with a different author name and commit message                                               # Commit.feature:65
    Given There is an empty repository named repo1                                                                                       # WebAPICucumberHooks.setUpEmptyRepo(String)
    And I have a transaction as "@txId" on the "repo1" repo                                                                              # WebAPICucumberHooks.beginTransactionAsVariable(String,String)
    And I have staged "Point.1" on the "repo1" repo in the "@txId" transaction                                                           # WebAPICucumberHooks.I_have_staged(String,String,String)
    And I have staged "Point.2" on the "repo1" repo in the "@txId" transaction                                                           # WebAPICucumberHooks.I_have_staged(String,String,String)
    And I have staged "Line.1" on the "repo1" repo in the "@txId" transaction                                                            # WebAPICucumberHooks.I_have_staged(String,String,String)
    When I call "GET /repos/repo1/commit?transactionId={@txId}&message=My%20Message&authorName=myAuthor&authorEmail=myAuthor@geogig.org" # WebAPICucumberHooks.callURL(String)
    Then the response status should be '200'                                                                                             # WebAPICucumberHooks.checkStatusCode(int)
    And the xpath "/response/success/text()" equals "true"                                                                               # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xpath "/response/commitId/text()" equals "{@ObjectId|repo1|@txId|master}"                                                    # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xpath "/response/added/text()" equals "3"                                                                                    # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xpath "/response/changed/text()" equals "0"                                                                                  # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xpath "/response/deleted/text()" equals "0"                                                                                  # WebAPICucumberHooks.checkXPathEquals(String,String)
    When I call "GET /repos/repo1/cat?objectid={@ObjectId|repo1|@txId|master}"                                                           # WebAPICucumberHooks.callURL(String)
    Then the response status should be '200'                                                                                             # WebAPICucumberHooks.checkStatusCode(int)
    And the xpath "/response/success/text()" equals "true"                                                                               # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xpath "/response/commit/author/name/text()" equals "myAuthor"                                                                # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xpath "/response/commit/author/email/text()" equals "myAuthor@geogig.org"                                                    # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xpath "/response/commit/message/text()" contains "My Message"                                                                # WebAPICucumberHooks.checkXPathValueContains(String,String)
@Commands @Config
Feature: Config
  The config command allows a user to get and set config values and is supported through the "/repos/{repository}/config" endpoint
  The command must be executed using the HTTP GET or POST methods
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo1 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()

  Scenario: Verify wrong HTTP method issues 405 "Method not allowed" # Config.feature:6
    Given There is an empty repository named repo1                   # WebAPICucumberHooks.setUpEmptyRepo(String)
    When I call "DELETE /repos/repo1/config"                         # WebAPICucumberHooks.callURL(String)
    Then the response status should be '405'                         # WebAPICucumberHooks.checkStatusCode(int)
    And the response allowed methods should be "GET,POST"            # WebAPICucumberHooks.checkResponseAllowedMethods(String)
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo1 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()

  Scenario: Config outside of a repository issues 404 "Not found" # Config.feature:12
    Given There is an empty multirepo server                      # WebAPICucumberHooks.setUpEmptyMultiRepo()
    When I call "GET /repos/repo1/config"                         # WebAPICucumberHooks.callURL(String)
    Then the response status should be '404'                      # WebAPICucumberHooks.checkStatusCode(int)
    And the response ContentType should be "text/plain"           # WebAPICucumberHooks.checkContentType(String)
    And the response body should contain "Repository not found"   # WebAPICucumberHooks.checkResponseTextContains(String)
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo1 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()

  Scenario: Config POST without specifying a key issues a 400 status code                                 # Config.feature:19
    Given There is an empty repository named repo1                                                        # WebAPICucumberHooks.setUpEmptyRepo(String)
    When I call "POST /repos/repo1/config"                                                                # WebAPICucumberHooks.callURL(String)
    Then the response status should be '400'                                                              # WebAPICucumberHooks.checkStatusCode(int)
    And the xpath "/response/error/text()" contains "You must specify the key when setting a config key." # WebAPICucumberHooks.checkXPathValueContains(String,String)
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo1 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()

  Scenario: Config POST without specifying a value issues a 400 status code                                 # Config.feature:25
    Given There is an empty repository named repo1                                                          # WebAPICucumberHooks.setUpEmptyRepo(String)
    When I call "POST /repos/repo1/config?name=user.name"                                                   # WebAPICucumberHooks.callURL(String)
    Then the response status should be '400'                                                                # WebAPICucumberHooks.checkStatusCode(int)
    And the xpath "/response/error/text()" contains "You must specify the value when setting a config key." # WebAPICucumberHooks.checkXPathValueContains(String,String)
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo1 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()

  Scenario: Config POST with a name and value in the url sets the config entry and GET retrieves the set value # Config.feature:31
    Given There is an empty repository named repo1                                                             # WebAPICucumberHooks.setUpEmptyRepo(String)
    When I call "POST /repos/repo1/config?name=user.name&value=myUser"                                         # WebAPICucumberHooks.callURL(String)
    Then the response status should be '200'                                                                   # WebAPICucumberHooks.checkStatusCode(int)
    And the xpath "/response/success/text()" equals "true"                                                     # WebAPICucumberHooks.checkXPathEquals(String,String)
    When I call "GET /repos/repo1/config?name=user.name"                                                       # WebAPICucumberHooks.callURL(String)
    Then the response status should be '200'                                                                   # WebAPICucumberHooks.checkStatusCode(int)
    And the xpath "/response/value/text()" equals "myUser"                                                     # WebAPICucumberHooks.checkXPathEquals(String,String)
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo1 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()

  Scenario: Config POST with a name and value as json sets the config entry and GET retrieves the set value # Config.feature:40
    Given There is an empty repository named repo1                                                          # WebAPICucumberHooks.setUpEmptyRepo(String)
    When I "POST" content-type "application/json" to "/repos/repo1/config" with                             # WebAPICucumberHooks.requestWithContent(String,String,String,String)
      """
      {
        "name":"user.name",
        "value":"myUser"
      }
      """
    Then the response status should be '200'                                                                # WebAPICucumberHooks.checkStatusCode(int)
    And the xpath "/response/success/text()" equals "true"                                                  # WebAPICucumberHooks.checkXPathEquals(String,String)
    When I call "GET /repos/repo1/config?name=user.name"                                                    # WebAPICucumberHooks.callURL(String)
    Then the response status should be '200'                                                                # WebAPICucumberHooks.checkStatusCode(int)
    And the xpath "/response/value/text()" equals "myUser"                                                  # WebAPICucumberHooks.checkXPathEquals(String,String)
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo1 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()

  Scenario: Config POST with a name and value as xml sets the config entry and GET retrieves the set value # Config.feature:55
    Given There is an empty repository named repo1                                                         # WebAPICucumberHooks.setUpEmptyRepo(String)
    When I "POST" content-type "application/xml" to "/repos/repo1/config" with                             # WebAPICucumberHooks.requestWithContent(String,String,String,String)
      """
      <params>
        <name>user.name</name>
        <value>myUser</value>
      </params>
      """
    Then the response status should be '200'                                                               # WebAPICucumberHooks.checkStatusCode(int)
    And the xpath "/response/success/text()" equals "true"                                                 # WebAPICucumberHooks.checkXPathEquals(String,String)
    When I call "GET /repos/repo1/config?name=user.name"                                                   # WebAPICucumberHooks.callURL(String)
    Then the response status should be '200'                                                               # WebAPICucumberHooks.checkStatusCode(int)
    And the xpath "/response/value/text()" equals "myUser"                                                 # WebAPICucumberHooks.checkXPathEquals(String,String)
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo1 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()

  Scenario: Config GET without a name will list all config entries           # Config.feature:70
    Given There is an empty repository named repo1                           # WebAPICucumberHooks.setUpEmptyRepo(String)
    When I call "POST /repos/repo1/config?name=config.value1&value=myValue1" # WebAPICucumberHooks.callURL(String)
    And I call "POST /repos/repo1/config?name=config.value2&value=myValue2"  # WebAPICucumberHooks.callURL(String)
    When I call "GET /repos/repo1/config"                                    # WebAPICucumberHooks.callURL(String)
    Then the response status should be '200'                                 # WebAPICucumberHooks.checkStatusCode(int)
    And the xpath "/response/success/text()" equals "true"                   # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the response body should contain "config.value1"                     # WebAPICucumberHooks.checkResponseTextContains(String)
    And the response body should contain "myValue1"                          # WebAPICucumberHooks.checkResponseTextContains(String)
    And the response body should contain "config.value2"                     # WebAPICucumberHooks.checkResponseTextContains(String)
    And the response body should contain "myValue2"                          # WebAPICucumberHooks.checkResponseTextContains(String)
@RepositoryManagement @CreateRepository
Feature: Create Repository
  Creating a repository on the server is done through the "/repos/{repository}/init" command
  The command must be executed using the HTTP PUT method
  If a repository with the provided name already exists, then a 409 "Conflict" error code shall be returned
  If the command succeeds, the response status code is 201 "Created"

  Scenario: Verify wrong HTTP method issues 405 "Method not allowed" # CreateRepository.feature:8
    Given There is an empty multirepo server                         # WebAPICucumberHooks.setUpEmptyMultiRepo()
    When I call "GET /repos/repo1/init"                              # WebAPICucumberHooks.callURL(String)
    Then the response status should be '405'                         # WebAPICucumberHooks.checkStatusCode(int)
    And the response allowed methods should be "PUT"                 # WebAPICucumberHooks.checkResponseAllowedMethods(String)
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo2 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository extraRepo using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo1 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()

  @FileRepository
  Scenario: Verify trying to create an existing repo issues 409 "Conflict"                                # CreateRepository.feature:15
    Given There is a default multirepo server                                                             # WebAPICucumberHooks.setUpDefaultMultiRepo()
    And I have "extraRepo" that is not managed                                                            # WebAPICucumberHooks.setupExtraUnMangedRepo(String)
    When I "PUT" content-type "application/json" to "/repos/extraRepo/init" with                          # WebAPICucumberHooks.requestWithContent(String,String,String,String)
      """
      {
        "parentDirectory":"{@systemTempPath}"
      }
      """
    Then the response status should be '409'                                                              # WebAPICucumberHooks.checkStatusCode(int)
    And the response ContentType should be "application/xml"                                              # WebAPICucumberHooks.checkContentType(String)
    And the xpath "/response/success/text()" equals "false"                                               # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xpath "/response/error/text()" equals "Cannot run init on an already initialized repository." # WebAPICucumberHooks.checkXPathEquals(String,String)
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo1 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()

  Scenario: Create repository on empty server                                  # CreateRepository.feature:29
    Given There is an empty multirepo server                                   # WebAPICucumberHooks.setUpEmptyMultiRepo()
    When I call "PUT /repos/repo1/init"                                        # WebAPICucumberHooks.callURL(String)
    Then the response status should be '201'                                   # WebAPICucumberHooks.checkStatusCode(int)
    And the response ContentType should be "application/xml"                   # WebAPICucumberHooks.checkContentType(String)
    And the xpath "/response/success/text()" equals "true"                     # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xpath "/response/repo/name/text()" equals "repo1"                  # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xpath "/response/repo/atom:link/@href" contains "/repos/repo1.xml" # WebAPICucumberHooks.checkXPathValueContains(String,String)

  Scenario: Verify wrong HTTP method issues 405 "Method not allowed", JSON requested response # CreateRepository.feature:38
    Given There is an empty multirepo server                                                  # WebAPICucumberHooks.setUpEmptyMultiRepo()
    When I call "GET /repos/repo1/init.json"                                                  # WebAPICucumberHooks.callURL(String)
    Then the response status should be '405'                                                  # WebAPICucumberHooks.checkStatusCode(int)
    And the response allowed methods should be "PUT"                                          # WebAPICucumberHooks.checkResponseAllowedMethods(String)
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo2 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository extraRepo using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo1 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()

  @FileRepository
  Scenario: Verify trying to create an existing repo issues 409 "Conflict", JSON requested response     # CreateRepository.feature:45
    Given There is a default multirepo server                                                           # WebAPICucumberHooks.setUpDefaultMultiRepo()
    And I have "extraRepo" that is not managed                                                          # WebAPICucumberHooks.setupExtraUnMangedRepo(String)
    When I "PUT" content-type "application/json" to "/repos/extraRepo/init.json" with                   # WebAPICucumberHooks.requestWithContent(String,String,String,String)
      """
      {
        "parentDirectory":"{@systemTempPath}"
      }
      """
    Then the response status should be '409'                                                            # WebAPICucumberHooks.checkStatusCode(int)
    And the response ContentType should be "application/json"                                           # WebAPICucumberHooks.checkContentType(String)
    And the json object "response.success" equals "false"                                               # WebAPICucumberHooks.checkJSONResponse(String,String)
    And the json object "response.error" equals "Cannot run init on an already initialized repository." # WebAPICucumberHooks.checkJSONResponse(String,String)
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo1 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()

  Scenario: Create repository on empty server, JSON requested response     # CreateRepository.feature:59
    Given There is an empty multirepo server                               # WebAPICucumberHooks.setUpEmptyMultiRepo()
    When I call "PUT /repos/repo1/init.json"                               # WebAPICucumberHooks.callURL(String)
    Then the response status should be '201'                               # WebAPICucumberHooks.checkStatusCode(int)
    And the response ContentType should be "application/json"              # WebAPICucumberHooks.checkContentType(String)
    And the json object "response.success" equals "true"                   # WebAPICucumberHooks.checkJSONResponse(String,String)
    And the json object "response.repo.name" equals "repo1"                # WebAPICucumberHooks.checkJSONResponse(String,String)
    And the json object "response.repo.href" ends with "/repos/repo1.json" # WebAPICucumberHooks.checkJSONResponseEndsWith(String,String)
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo1 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()

  @FileRepository
  Scenario: Verify JSON fomratted response of Init with JSON formatted request parameters          # CreateRepository.feature:69
    Given There is an empty multirepo server                                                       # WebAPICucumberHooks.setUpEmptyMultiRepo()
    When I call "PUT /repos/repo1/init.json" with the System Temp Directory as the parentDirectory # WebAPICucumberHooks.callURLWithJSONPaylod(String)
    Then the response status should be '201'                                                       # WebAPICucumberHooks.checkStatusCode(int)
    And the response ContentType should be "application/json"                                      # WebAPICucumberHooks.checkContentType(String)
    And the json object "response.success" equals "true"                                           # WebAPICucumberHooks.checkJSONResponse(String,String)
    And the json object "response.repo.name" equals "repo1"                                        # WebAPICucumberHooks.checkJSONResponse(String,String)
    And the json object "response.repo.href" ends with "/repos/repo1.json"                         # WebAPICucumberHooks.checkJSONResponseEndsWith(String,String)
    And the parent directory of repository "repo1" equals System Temp directory                    # WebAPICucumberHooks.checkRepositoryParent(String)
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo1 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()

  @FileRepository
  Scenario: Verify XML fomratted response of Init with JSON formatted request parameters      # CreateRepository.feature:80
    Given There is an empty multirepo server                                                  # WebAPICucumberHooks.setUpEmptyMultiRepo()
    When I call "PUT /repos/repo1/init" with the System Temp Directory as the parentDirectory # WebAPICucumberHooks.callURLWithJSONPaylod(String)
    Then the response status should be '201'                                                  # WebAPICucumberHooks.checkStatusCode(int)
    And the response ContentType should be "application/xml"                                  # WebAPICucumberHooks.checkContentType(String)
    And the xpath "/response/success/text()" equals "true"                                    # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xpath "/response/repo/name/text()" equals "repo1"                                 # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xpath "/response/repo/atom:link/@href" contains "/repos/repo1.xml"                # WebAPICucumberHooks.checkXPathValueContains(String,String)
    And the parent directory of repository "repo1" equals System Temp directory               # WebAPICucumberHooks.checkRepositoryParent(String)
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo1 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()

  @FileRepository
  Scenario: Verify JSON fomratted response of Init with URL Form encoded request parameters                 # CreateRepository.feature:91
    Given There is an empty multirepo server                                                                # WebAPICucumberHooks.setUpEmptyMultiRepo()
    When I call "PUT /repos/repo1/init.json" with a URL encoded Form containing a parentDirectory parameter # WebAPICucumberHooks.callURLWithFormPaylod(String)
    Then the response status should be '201'                                                                # WebAPICucumberHooks.checkStatusCode(int)
    And the response ContentType should be "application/json"                                               # WebAPICucumberHooks.checkContentType(String)
    And the json object "response.success" equals "true"                                                    # WebAPICucumberHooks.checkJSONResponse(String,String)
    And the json object "response.repo.name" equals "repo1"                                                 # WebAPICucumberHooks.checkJSONResponse(String,String)
    And the json object "response.repo.href" ends with "/repos/repo1.json"                                  # WebAPICucumberHooks.checkJSONResponseEndsWith(String,String)
    And the parent directory of repository "repo1" equals System Temp directory                             # WebAPICucumberHooks.checkRepositoryParent(String)
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo1 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()

  @FileRepository
  Scenario: Verify XML fomratted response of Init with URL Form encoded request parameters             # CreateRepository.feature:102
    Given There is an empty multirepo server                                                           # WebAPICucumberHooks.setUpEmptyMultiRepo()
    When I call "PUT /repos/repo1/init" with a URL encoded Form containing a parentDirectory parameter # WebAPICucumberHooks.callURLWithFormPaylod(String)
    Then the response status should be '201'                                                           # WebAPICucumberHooks.checkStatusCode(int)
    And the response ContentType should be "application/xml"                                           # WebAPICucumberHooks.checkContentType(String)
    And the xpath "/response/success/text()" equals "true"                                             # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xpath "/response/repo/name/text()" equals "repo1"                                          # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xpath "/response/repo/atom:link/@href" contains "/repos/repo1.xml"                         # WebAPICucumberHooks.checkXPathValueContains(String,String)
    And the parent directory of repository "repo1" equals System Temp directory                        # WebAPICucumberHooks.checkRepositoryParent(String)
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo1 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()

  @FileRepository
  Scenario: Verify JSON fomratted response of Init with JSON formatted request parameters and Author          # CreateRepository.feature:113
    Given There is an empty multirepo server                                                                  # WebAPICucumberHooks.setUpEmptyMultiRepo()
    When I call "PUT /repos/repo1/init.json" with Author and the System Temp Directory as the parentDirectory # WebAPICucumberHooks.callURLWithJSONPayloadAndAuthor(String)
    Then the response status should be '201'                                                                  # WebAPICucumberHooks.checkStatusCode(int)
    And the response ContentType should be "application/json"                                                 # WebAPICucumberHooks.checkContentType(String)
    And the json object "response.success" equals "true"                                                      # WebAPICucumberHooks.checkJSONResponse(String,String)
    And the json object "response.repo.name" equals "repo1"                                                   # WebAPICucumberHooks.checkJSONResponse(String,String)
    And the json object "response.repo.href" ends with "/repos/repo1.json"                                    # WebAPICucumberHooks.checkJSONResponseEndsWith(String,String)
    And the parent directory of repository "repo1" equals System Temp directory                               # WebAPICucumberHooks.checkRepositoryParent(String)
    And the Author config of repository "repo1" is set                                                        # WebAPICucumberHooks.checkAuthorConfig(String)
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo1 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()

  @FileRepository
  Scenario: Verify XML fomratted response of Init with JSON formatted request parameters and Author      # CreateRepository.feature:125
    Given There is an empty multirepo server                                                             # WebAPICucumberHooks.setUpEmptyMultiRepo()
    When I call "PUT /repos/repo1/init" with Author and the System Temp Directory as the parentDirectory # WebAPICucumberHooks.callURLWithJSONPayloadAndAuthor(String)
    Then the response status should be '201'                                                             # WebAPICucumberHooks.checkStatusCode(int)
    And the response ContentType should be "application/xml"                                             # WebAPICucumberHooks.checkContentType(String)
    And the xpath "/response/success/text()" equals "true"                                               # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xpath "/response/repo/name/text()" equals "repo1"                                            # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xpath "/response/repo/atom:link/@href" contains "/repos/repo1.xml"                           # WebAPICucumberHooks.checkXPathValueContains(String,String)
    And the parent directory of repository "repo1" equals System Temp directory                          # WebAPICucumberHooks.checkRepositoryParent(String)
    And the Author config of repository "repo1" is set                                                   # WebAPICucumberHooks.checkAuthorConfig(String)
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo1 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()

  @FileRepository
  Scenario: Verify JSON fomratted response of Init with URL Form encoded request parameters and Author                 # CreateRepository.feature:137
    Given There is an empty multirepo server                                                                           # WebAPICucumberHooks.setUpEmptyMultiRepo()
    When I call "PUT /repos/repo1/init.json" with a URL encoded Form containing a parentDirectory parameter and Author # WebAPICucumberHooks.callURLWithFormPaylodWithAuthor(String)
    Then the response status should be '201'                                                                           # WebAPICucumberHooks.checkStatusCode(int)
    And the response ContentType should be "application/json"                                                          # WebAPICucumberHooks.checkContentType(String)
    And the json object "response.success" equals "true"                                                               # WebAPICucumberHooks.checkJSONResponse(String,String)
    And the json object "response.repo.name" equals "repo1"                                                            # WebAPICucumberHooks.checkJSONResponse(String,String)
    And the json object "response.repo.href" ends with "/repos/repo1.json"                                             # WebAPICucumberHooks.checkJSONResponseEndsWith(String,String)
    And the parent directory of repository "repo1" equals System Temp directory                                        # WebAPICucumberHooks.checkRepositoryParent(String)
    And the Author config of repository "repo1" is set                                                                 # WebAPICucumberHooks.checkAuthorConfig(String)
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo1 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()

  @FileRepository
  Scenario: Verify XML fomratted response of Init with URL Form encoded request parameters and Author             # CreateRepository.feature:149
    Given There is an empty multirepo server                                                                      # WebAPICucumberHooks.setUpEmptyMultiRepo()
    When I call "PUT /repos/repo1/init" with a URL encoded Form containing a parentDirectory parameter and Author # WebAPICucumberHooks.callURLWithFormPaylodWithAuthor(String)
    Then the response status should be '201'                                                                      # WebAPICucumberHooks.checkStatusCode(int)
    And the response ContentType should be "application/xml"                                                      # WebAPICucumberHooks.checkContentType(String)
    And the xpath "/response/success/text()" equals "true"                                                        # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xpath "/response/repo/name/text()" equals "repo1"                                                     # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xpath "/response/repo/atom:link/@href" contains "/repos/repo1.xml"                                    # WebAPICucumberHooks.checkXPathValueContains(String,String)
    And the parent directory of repository "repo1" equals System Temp directory                                   # WebAPICucumberHooks.checkRepositoryParent(String)
    And the Author config of repository "repo1" is set                                                            # WebAPICucumberHooks.checkAuthorConfig(String)

  Scenario: Verify Init with unsupported MediaType does not create a repository with defualt settings # CreateRepository.feature:160
    Given There is an empty multirepo server                                                          # WebAPICucumberHooks.setUpEmptyMultiRepo()
    When I call "PUT /repos/repo1/init.json" with an unsupported media type                           # WebAPICucumberHooks.callURLWithUnsupportedMediaType(String)
    Then the response status should be '400'                                                          # WebAPICucumberHooks.checkStatusCode(int)
    And there should be no "repo1" created                                                            # WebAPICucumberHooks.checkRepoNotInitialized(String)
@RepositoryManagement @DeleteRepository
Feature: Delete Repository
  Deleting a repository through the web API is a non reversible operation.
  * In order to avoid accidental deletion of repositories, it is a two-step process:
  * first a GET call to "/repos/{repository}/delete" returns an automatically generated token with the format:
  * <response><success>true</success><token>d713df9c703733e2</token></response>.
  * To actually delete the repository, a HTTP DELETE method call to "/repos/{repository}?token={token}" must be issued, with a valid and non expired token.
  * An attempt to delete a non existent repository, results in a 404 "Not found" error code.
  * A successfull DELETE operation returns a 200 status code,
  * the XML response body is <deleted>true</deleted>, the JSON response body is '{"deleted":true}'
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo2 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo1 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()

  Scenario: Requesting delete token with wrong HTTP Method issues 405 "Method not allowed" # DeleteRepository.feature:12
    Given There is a default multirepo server                                              # WebAPICucumberHooks.setUpDefaultMultiRepo()
    When I call "POST /repos/repo1/delete"                                                 # WebAPICucumberHooks.callURL(String)
    Then the response status should be '405'                                               # WebAPICucumberHooks.checkStatusCode(int)
    And the response allowed methods should be "GET"                                       # WebAPICucumberHooks.checkResponseAllowedMethods(String)
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository nonExistentRepo using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo2 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo1 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()

  Scenario: Requesting a delete token for a non existent repository issues 404 "Not found" # DeleteRepository.feature:18
    Given There is a default multirepo server                                              # WebAPICucumberHooks.setUpDefaultMultiRepo()
    When I call "GET /repos/nonExistentRepo/delete"                                        # WebAPICucumberHooks.callURL(String)
    Then the response status should be '404'                                               # WebAPICucumberHooks.checkStatusCode(int)
    And the response ContentType should be "text/plain"                                    # WebAPICucumberHooks.checkContentType(String)
    And the response body should contain "Repository not found"                            # WebAPICucumberHooks.checkResponseTextContains(String)
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository nonExistentRepo using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo2 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo1 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()

  Scenario: Try deleting a non existent repository issues 404 "Not found" # DeleteRepository.feature:25
    Given There is a default multirepo server                             # WebAPICucumberHooks.setUpDefaultMultiRepo()
    When I call "DELETE /repos/nonExistentRepo?token=someToken"           # WebAPICucumberHooks.callURL(String)
    Then the response status should be '404'                              # WebAPICucumberHooks.checkStatusCode(int)
    And the response ContentType should be "text/plain"                   # WebAPICucumberHooks.checkContentType(String)
    And the response body should contain "error:No repository to delete." # WebAPICucumberHooks.checkResponseTextContains(String)
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo2 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo1 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()

  Scenario: Succesfully delete a repository                       # DeleteRepository.feature:32
    Given There is a default multirepo server                     # WebAPICucumberHooks.setUpDefaultMultiRepo()
    When I call "GET /repos/repo2/delete"                         # WebAPICucumberHooks.callURL(String)
    Then the response status should be '200'                      # WebAPICucumberHooks.checkStatusCode(int)
    And the response ContentType should be "application/xml"      # WebAPICucumberHooks.checkContentType(String)
    And the xpath "/response/success/text()" equals "true"        # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xml response should contain "/response/token"         # WebAPICucumberHooks.checkResponseContainsXPath(String)
    Then I save the response "/response/token/text()" as "@token" # WebAPICucumberHooks.saveResponseXPathValueAsVariable(String,String)
    When I call "DELETE /repos/repo2?token={@token}"              # WebAPICucumberHooks.callURL(String)
    Then the response status should be '200'                      # WebAPICucumberHooks.checkStatusCode(int)
    And the response ContentType should be "application/xml"      # WebAPICucumberHooks.checkContentType(String)
    And the xpath "/deleted/text()" equals "repo2"                # WebAPICucumberHooks.checkXPathEquals(String,String)
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo2 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo1 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()

  Scenario: Requesting delete token with wrong HTTP Method issues 405 "Method not allowed", JSON requested response # DeleteRepository.feature:45
    Given There is a default multirepo server                                                                       # WebAPICucumberHooks.setUpDefaultMultiRepo()
    When I call "POST /repos/repo1/delete.json"                                                                     # WebAPICucumberHooks.callURL(String)
    Then the response status should be '405'                                                                        # WebAPICucumberHooks.checkStatusCode(int)
    And the response allowed methods should be "GET"                                                                # WebAPICucumberHooks.checkResponseAllowedMethods(String)
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository nonExistentRepo using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo2 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo1 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()

  Scenario: Requesting a delete token for a non existent repository issues 404 "Not found", JSON requested response # DeleteRepository.feature:51
    Given There is a default multirepo server                                                                       # WebAPICucumberHooks.setUpDefaultMultiRepo()
    When I call "GET /repos/nonExistentRepo/delete.json"                                                            # WebAPICucumberHooks.callURL(String)
    Then the response status should be '404'                                                                        # WebAPICucumberHooks.checkStatusCode(int)
    And the response ContentType should be "text/plain"                                                             # WebAPICucumberHooks.checkContentType(String)
    And the response body should contain "Repository not found"                                                     # WebAPICucumberHooks.checkResponseTextContains(String)
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository nonExistentRepo using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo2 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo1 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()

  Scenario: Try deleting a non existent repository issues 404 "Not found", JSON requested response # DeleteRepository.feature:58
    Given There is a default multirepo server                                                      # WebAPICucumberHooks.setUpDefaultMultiRepo()
    When I call "DELETE /repos/nonExistentRepo.json?token=someToken"                               # WebAPICucumberHooks.callURL(String)
    Then the response status should be '404'                                                       # WebAPICucumberHooks.checkStatusCode(int)
    And the response ContentType should be "text/plain"                                            # WebAPICucumberHooks.checkContentType(String)
    And the response body should contain "error:No repository to delete."                          # WebAPICucumberHooks.checkResponseTextContains(String)
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo2 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo1 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()

  Scenario: Succesfully delete a repository, JSON requested response # DeleteRepository.feature:65
    Given There is a default multirepo server                        # WebAPICucumberHooks.setUpDefaultMultiRepo()
    When I call "GET /repos/repo2/delete.json"                       # WebAPICucumberHooks.callURL(String)
    Then the response status should be '200'                         # WebAPICucumberHooks.checkStatusCode(int)
    And the response ContentType should be "application/json"        # WebAPICucumberHooks.checkContentType(String)
    And the json object "response.success" equals "true"             # WebAPICucumberHooks.checkJSONResponse(String,String)
    And the json response "response" should contain "token"          # WebAPICucumberHooks.checkJSONResponseContains(String,String)
    Then I save the json response "response.token" as "@token"       # WebAPICucumberHooks.saveResponseJSONValueAsVariable(String,String)
    When I call "DELETE /repos/repo2.json?token={@token}"            # WebAPICucumberHooks.callURL(String)
    Then the response status should be '200'                         # WebAPICucumberHooks.checkStatusCode(int)
    And the response ContentType should be "application/json"        # WebAPICucumberHooks.checkContentType(String)
    And the json object "deleted" equals "repo2"                     # WebAPICucumberHooks.checkJSONResponse(String,String)
@Repo @Depth
Feature: Depth
  The Depth resource returns the depth of the repository from a specific commit and is supported through the "/repos/{repository}/repo/getdepth" endpoint
  The command must be executed using the HTTP GET method
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo1 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()

  Scenario: Verify wrong HTTP method issues 405 "Method not allowed" # Depth.feature:6
    Given There is an empty repository named repo1                   # WebAPICucumberHooks.setUpEmptyRepo(String)
    When I call "PUT /repos/repo1/repo/getdepth"                     # WebAPICucumberHooks.callURL(String)
    Then the response status should be '405'                         # WebAPICucumberHooks.checkStatusCode(int)
    And the response allowed methods should be "GET"                 # WebAPICucumberHooks.checkResponseAllowedMethods(String)
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo1 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()

  Scenario: Depth outside of a repository issues 404 "Not found" # Depth.feature:12
    Given There is an empty multirepo server                     # WebAPICucumberHooks.setUpEmptyMultiRepo()
    When I call "GET /repos/repo1/repo/getdepth"                 # WebAPICucumberHooks.callURL(String)
    Then the response status should be '404'                     # WebAPICucumberHooks.checkStatusCode(int)
    And the response ContentType should be "text/plain"          # WebAPICucumberHooks.checkContentType(String)
    And the response body should contain "Repository not found"  # WebAPICucumberHooks.checkResponseTextContains(String)
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo1 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo2 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()

  Scenario: Depth with an invalid commit issues a 400 status code              # Depth.feature:19
    Given There is a default multirepo server                                  # WebAPICucumberHooks.setUpDefaultMultiRepo()
    When I call "GET /repos/repo1/repo/getdepth?commitId=invalid"              # WebAPICucumberHooks.callURL(String)
    Then the response status should be '400'                                   # WebAPICucumberHooks.checkStatusCode(int)
    And the response ContentType should be "text/plain"                        # WebAPICucumberHooks.checkContentType(String)
    And the response body should contain "You must specify a valid commit id." # WebAPICucumberHooks.checkResponseTextContains(String)
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo1 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo2 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()

  Scenario: Depth with no commit returns no depth for a non-shallow repository # Depth.feature:26
    Given There is a default multirepo server                                  # WebAPICucumberHooks.setUpDefaultMultiRepo()
    When I call "GET /repos/repo1/repo/getdepth"                               # WebAPICucumberHooks.callURL(String)
    Then the response status should be '200'                                   # WebAPICucumberHooks.checkStatusCode(int)
    And the response ContentType should be "text/plain"                        # WebAPICucumberHooks.checkContentType(String)
    And the response body should contain ""                                    # WebAPICucumberHooks.checkResponseTextContains(String)
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository shallow using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository full using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()

  @ShallowDepth
  Scenario: Depth with no commit returns the depth of a shallow repository # Depth.feature:34
    Given There is a default multirepo server with a shallow clone         # WebAPICucumberHooks.setUpDefaultMultiRepoWithShallowClone()
    When I call "GET /repos/shallow/repo/getdepth"                         # WebAPICucumberHooks.callURL(String)
    Then the response status should be '200'                               # WebAPICucumberHooks.checkStatusCode(int)
    And the response ContentType should be "text/plain"                    # WebAPICucumberHooks.checkContentType(String)
    And the response body should contain "1"                               # WebAPICucumberHooks.checkResponseTextContains(String)
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo1 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo2 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()

  Scenario: Depth with a commit returns the number of ancestors that commit has     # Depth.feature:41
    Given There is a default multirepo server                                       # WebAPICucumberHooks.setUpDefaultMultiRepo()
    When I call "GET /repos/repo1/repo/getdepth?commitId={@ObjectId|repo1|branch1}" # WebAPICucumberHooks.callURL(String)
    Then the response status should be '200'                                        # WebAPICucumberHooks.checkStatusCode(int)
    And the response ContentType should be "text/plain"                             # WebAPICucumberHooks.checkContentType(String)
    And the response body should contain "1"                                        # WebAPICucumberHooks.checkResponseTextContains(String)
    When I call "GET /repos/repo1/repo/getdepth?commitId={@ObjectId|repo1|master}"  # WebAPICucumberHooks.callURL(String)
    Then the response status should be '200'                                        # WebAPICucumberHooks.checkStatusCode(int)
    And the response ContentType should be "text/plain"                             # WebAPICucumberHooks.checkContentType(String)
    And the response body should contain "2"                                        # WebAPICucumberHooks.checkResponseTextContains(String)
@Commands @Diff
Feature: Diff
  The diff command allows a user to see the difference between two commits and is supported through the "/repos/{repository}/config" endpoint
  The command must be executed using the HTTP GET method
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo1 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()

  Scenario: Verify wrong HTTP method issues 405 "Method not allowed" # Diff.feature:6
    Given There is an empty repository named repo1                   # WebAPICucumberHooks.setUpEmptyRepo(String)
    When I call "PUT /repos/repo1/diff"                              # WebAPICucumberHooks.callURL(String)
    Then the response status should be '405'                         # WebAPICucumberHooks.checkStatusCode(int)
    And the response allowed methods should be "GET"                 # WebAPICucumberHooks.checkResponseAllowedMethods(String)
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo1 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()

  Scenario: Diff outside of a repository issues 404 "Not found" # Diff.feature:12
    Given There is an empty multirepo server                    # WebAPICucumberHooks.setUpEmptyMultiRepo()
    When I call "GET /repos/repo1/diff?oldRefSpec=someRefSpec"  # WebAPICucumberHooks.callURL(String)
    Then the response status should be '404'                    # WebAPICucumberHooks.checkStatusCode(int)
    And the response ContentType should be "text/plain"         # WebAPICucumberHooks.checkContentType(String)
    And the response body should contain "Repository not found" # WebAPICucumberHooks.checkResponseTextContains(String)
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo1 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()

  Scenario: Calling diff without specifying an old ref spec issues a 500 status code                    # Diff.feature:19
    Given There is an empty repository named repo1                                                      # WebAPICucumberHooks.setUpEmptyRepo(String)
    When I call "GET /repos/repo1/diff"                                                                 # WebAPICucumberHooks.callURL(String)
    Then the response status should be '500'                                                            # WebAPICucumberHooks.checkStatusCode(int)
    And the xpath "/response/error/text()" contains "Required parameter 'oldRefSpec' was not provided." # WebAPICucumberHooks.checkXPathValueContains(String,String)
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo1 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()

  Scenario: Calling diff with an empty old ref spec issues a 500 status code # Diff.feature:25
    Given There is an empty repository named repo1                           # WebAPICucumberHooks.setUpEmptyRepo(String)
    When I call "GET /repos/repo1/diff?oldRefSpec=%20"                       # WebAPICucumberHooks.callURL(String)
    Then the response status should be '500'                                 # WebAPICucumberHooks.checkStatusCode(int)
    And the xpath "/response/error/text()" contains "Invalid old ref spec"   # WebAPICucumberHooks.checkXPathValueContains(String,String)
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo1 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo2 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()

  Scenario: Calling diff with an old ref spec returns all of the changes since that commit # Diff.feature:31
    Given There is a default multirepo server                                              # WebAPICucumberHooks.setUpDefaultMultiRepo()
    When I call "GET /repos/repo1/diff?oldRefSpec=master~2"                                # WebAPICucumberHooks.callURL(String)
    Then the response status should be '200'                                               # WebAPICucumberHooks.checkStatusCode(int)
    And the xpath "/response/success/text()" equals "true"                                 # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xml response should contain "/response/diff" 6 times                           # WebAPICucumberHooks.checkXPathCadinality(String,int)
    And the response body should contain "Points/Point.2"                                  # WebAPICucumberHooks.checkResponseTextContains(String)
    And the response body should contain "Points/Point.3"                                  # WebAPICucumberHooks.checkResponseTextContains(String)
    And the response body should contain "Lines/Line.2"                                    # WebAPICucumberHooks.checkResponseTextContains(String)
    And the response body should contain "Lines/Line.3"                                    # WebAPICucumberHooks.checkResponseTextContains(String)
    And the response body should contain "Polygons/Polygon.2"                              # WebAPICucumberHooks.checkResponseTextContains(String)
    And the response body should contain "Polygons/Polygon.3"                              # WebAPICucumberHooks.checkResponseTextContains(String)
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo1 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo2 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()

  Scenario: Calling diff with two ref specs returns all of the changes since those commits # Diff.feature:44
    Given There is a default multirepo server                                              # WebAPICucumberHooks.setUpDefaultMultiRepo()
    When I call "GET /repos/repo1/diff?oldRefSpec=master~2&newRefSpec=master~1"            # WebAPICucumberHooks.callURL(String)
    Then the response status should be '200'                                               # WebAPICucumberHooks.checkStatusCode(int)
    And the xpath "/response/success/text()" equals "true"                                 # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xml response should contain "/response/diff" 3 times                           # WebAPICucumberHooks.checkXPathCadinality(String,int)
    And the response body should contain "Points/Point.2"                                  # WebAPICucumberHooks.checkResponseTextContains(String)
    And the response body should contain "Lines/Line.2"                                    # WebAPICucumberHooks.checkResponseTextContains(String)
    And the response body should contain "Polygons/Polygon.2"                              # WebAPICucumberHooks.checkResponseTextContains(String)
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo1 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo2 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()

  Scenario: Diff should support paging results                            # Diff.feature:54
    Given There is a default multirepo server                             # WebAPICucumberHooks.setUpDefaultMultiRepo()
    When I call "GET /repos/repo1/diff?oldRefSpec=master~2&page=0&show=2" # WebAPICucumberHooks.callURL(String)
    Then the response status should be '200'                              # WebAPICucumberHooks.checkStatusCode(int)
    And the xpath "/response/success/text()" equals "true"                # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xml response should contain "/response/diff" 2 times          # WebAPICucumberHooks.checkXPathCadinality(String,int)
    And the response body should contain "Points/Point.2"                 # WebAPICucumberHooks.checkResponseTextContains(String)
    And the response body should contain "Points/Point.3"                 # WebAPICucumberHooks.checkResponseTextContains(String)
    When I call "GET /repos/repo1/diff?oldRefSpec=master~2&page=1&show=2" # WebAPICucumberHooks.callURL(String)
    Then the response status should be '200'                              # WebAPICucumberHooks.checkStatusCode(int)
    And the xpath "/response/success/text()" equals "true"                # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xml response should contain "/response/diff" 2 times          # WebAPICucumberHooks.checkXPathCadinality(String,int)
    And the response body should contain "Polygons/Polygon.2"             # WebAPICucumberHooks.checkResponseTextContains(String)
    And the response body should contain "Polygons/Polygon.3"             # WebAPICucumberHooks.checkResponseTextContains(String)
    When I call "GET /repos/repo1/diff?oldRefSpec=master~2&page=2&show=2" # WebAPICucumberHooks.callURL(String)
    Then the response status should be '200'                              # WebAPICucumberHooks.checkStatusCode(int)
    And the xpath "/response/success/text()" equals "true"                # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xml response should contain "/response/diff" 2 times          # WebAPICucumberHooks.checkXPathCadinality(String,int)
    And the response body should contain "Lines/Line.2"                   # WebAPICucumberHooks.checkResponseTextContains(String)
    And the response body should contain "Lines/Line.3"                   # WebAPICucumberHooks.checkResponseTextContains(String)
@Commands @FeatureDiff
Feature: FeatureDiff
  The feature diff command allows a user to see the difference between two versions of a specific feature and is supported through the "/repos/{repository}/featurediff" endpoint
  The command must be executed using the HTTP GET method
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo1 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()

  Scenario: Verify wrong HTTP method issues 405 "Method not allowed" # FeatureDiff.feature:6
    Given There is an empty repository named repo1                   # WebAPICucumberHooks.setUpEmptyRepo(String)
    When I call "PUT /repos/repo1/featurediff"                       # WebAPICucumberHooks.callURL(String)
    Then the response status should be '405'                         # WebAPICucumberHooks.checkStatusCode(int)
    And the response allowed methods should be "GET"                 # WebAPICucumberHooks.checkResponseAllowedMethods(String)
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo1 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()

  Scenario: Feature diff outside of a repository issues 404 "Not found" # FeatureDiff.feature:12
    Given There is an empty multirepo server                            # WebAPICucumberHooks.setUpEmptyMultiRepo()
    When I call "GET /repos/repo1/featurediff?path=somePath"            # WebAPICucumberHooks.callURL(String)
    Then the response status should be '404'                            # WebAPICucumberHooks.checkStatusCode(int)
    And the response ContentType should be "text/plain"                 # WebAPICucumberHooks.checkContentType(String)
    And the response body should contain "Repository not found"         # WebAPICucumberHooks.checkResponseTextContains(String)
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo1 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()

  Scenario: Calling feature diff without specifying a path issues a 500 status code               # FeatureDiff.feature:19
    Given There is an empty repository named repo1                                                # WebAPICucumberHooks.setUpEmptyRepo(String)
    When I call "GET /repos/repo1/featurediff"                                                    # WebAPICucumberHooks.callURL(String)
    Then the response status should be '500'                                                      # WebAPICucumberHooks.checkStatusCode(int)
    And the xpath "/response/error/text()" contains "Required parameter 'path' was not provided." # WebAPICucumberHooks.checkXPathValueContains(String,String)
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo1 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()

  Scenario: Calling feature diff with an empty path issues a 500 status code     # FeatureDiff.feature:25
    Given There is an empty repository named repo1                               # WebAPICucumberHooks.setUpEmptyRepo(String)
    When I call "GET /repos/repo1/featurediff?path=%20"                          # WebAPICucumberHooks.callURL(String)
    Then the response status should be '500'                                     # WebAPICucumberHooks.checkStatusCode(int)
    And the xpath "/response/error/text()" contains "Invalid path was specified" # WebAPICucumberHooks.checkXPathValueContains(String,String)
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo1 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo2 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()

  Scenario: Feature diff should work for an added feature                                                # FeatureDiff.feature:31
    Given There is a default multirepo server                                                            # WebAPICucumberHooks.setUpDefaultMultiRepo()
    When I call "GET /repos/repo1/featurediff?path=Points/Point.3&oldTreeish=master~1&newTreeish=master" # WebAPICucumberHooks.callURL(String)
    Then the response status should be '200'                                                             # WebAPICucumberHooks.checkStatusCode(int)
    And the xpath "/response/success/text()" equals "true"                                               # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xml response should contain "/response/diff" 3 times                                         # WebAPICucumberHooks.checkXPathCadinality(String,int)
    And the response body should contain "ADDED"                                                         # WebAPICucumberHooks.checkResponseTextContains(String)
    And the response body should contain "StringProp1_3"                                                 # WebAPICucumberHooks.checkResponseTextContains(String)
    And the response body should contain "3000"                                                          # WebAPICucumberHooks.checkResponseTextContains(String)
    And the response body should contain "POINT (10 10)"                                                 # WebAPICucumberHooks.checkResponseTextContains(String)
    And the response body should not contain "MODIFIED"                                                  # WebAPICucumberHooks.checkResponseTextNotContains(String)
    And the response body should not contain "REMOVED"                                                   # WebAPICucumberHooks.checkResponseTextNotContains(String)
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo1 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo2 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()

  Scenario: Feature diff should work for a removed feature                                               # FeatureDiff.feature:44
    Given There is a default multirepo server                                                            # WebAPICucumberHooks.setUpDefaultMultiRepo()
    When I call "GET /repos/repo1/featurediff?path=Points/Point.3&oldTreeish=master&newTreeish=master~1" # WebAPICucumberHooks.callURL(String)
    Then the response status should be '200'                                                             # WebAPICucumberHooks.checkStatusCode(int)
    And the xpath "/response/success/text()" equals "true"                                               # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xml response should contain "/response/diff" 3 times                                         # WebAPICucumberHooks.checkXPathCadinality(String,int)
    And the response body should contain "REMOVED"                                                       # WebAPICucumberHooks.checkResponseTextContains(String)
    And the response body should contain "StringProp1_3"                                                 # WebAPICucumberHooks.checkResponseTextContains(String)
    And the response body should contain "3000"                                                          # WebAPICucumberHooks.checkResponseTextContains(String)
    And the response body should contain "POINT (10 10)"                                                 # WebAPICucumberHooks.checkResponseTextContains(String)
    And the response body should not contain "MODIFIED"                                                  # WebAPICucumberHooks.checkResponseTextNotContains(String)
    And the response body should not contain "ADDED"                                                     # WebAPICucumberHooks.checkResponseTextNotContains(String)
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo1 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()

  Scenario: Feature diff should work for a modified feature                                              # FeatureDiff.feature:57
    Given There is an empty repository named repo1                                                       # WebAPICucumberHooks.setUpEmptyRepo(String)
    And There is a feature with multiple authors on the "repo1" repo                                     # WebAPICucumberHooks.There_is_a_feature_with_multiple_authors(String)
    When I call "GET /repos/repo1/featurediff?path=Points/Point.1&oldTreeish=master~1&newTreeish=master" # WebAPICucumberHooks.callURL(String)
    Then the response status should be '200'                                                             # WebAPICucumberHooks.checkStatusCode(int)
    And the xpath "/response/success/text()" equals "true"                                               # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xml response should contain "/response/diff" 1 times                                         # WebAPICucumberHooks.checkXPathCadinality(String,int)
    And the xpath "/response/diff/attributename/text()" equals "ip"                                      # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xpath "/response/diff/changetype/text()" equals "MODIFIED"                                   # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xpath "/response/diff/oldvalue/text()" equals "1000"                                         # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xpath "/response/diff/newvalue/text()" equals "1500"                                         # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the response body should not contain "ADDED"                                                     # WebAPICucumberHooks.checkResponseTextNotContains(String)
    And the response body should not contain "REMOVED"                                                   # WebAPICucumberHooks.checkResponseTextNotContains(String)
@Commands @Fetch
Feature: Fetch
  The fetch command allows a user to fetch the changes from a remote repo and is supported through the "/repos/{repository}/featurediff" endpoint
  The command must be executed using the HTTP GET method
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo1 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()

  Scenario: Verify wrong HTTP method issues 405 "Method not allowed" # Fetch.feature:6
    Given There is an empty repository named repo1                   # WebAPICucumberHooks.setUpEmptyRepo(String)
    When I call "PUT /repos/repo1/fetch"                             # WebAPICucumberHooks.callURL(String)
    Then the response status should be '405'                         # WebAPICucumberHooks.checkStatusCode(int)
    And the response allowed methods should be "GET"                 # WebAPICucumberHooks.checkResponseAllowedMethods(String)
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo1 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()

  Scenario: Fetch outside of a repository issues 404 "Not found" # Fetch.feature:12
    Given There is an empty multirepo server                     # WebAPICucumberHooks.setUpEmptyMultiRepo()
    When I call "GET /repos/repo1/fetch"                         # WebAPICucumberHooks.callURL(String)
    Then the response status should be '404'                     # WebAPICucumberHooks.checkStatusCode(int)
    And the response ContentType should be "text/plain"          # WebAPICucumberHooks.checkContentType(String)
    And the response body should contain "Repository not found"  # WebAPICucumberHooks.checkResponseTextContains(String)
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo1 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()

  Scenario: Fetching without specifying a remote issues a 500 status code              # Fetch.feature:19
    Given There is an empty repository named repo1                                     # WebAPICucumberHooks.setUpEmptyRepo(String)
    When I call "GET /repos/repo1/fetch"                                               # WebAPICucumberHooks.callURL(String)
    Then the response status should be '500'                                           # WebAPICucumberHooks.checkStatusCode(int)
    And the xpath "/response/error/text()" contains "Nothing specified to fetch from." # WebAPICucumberHooks.checkXPathValueContains(String,String)
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo3 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo4 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo2 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo1 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()

  Scenario: Fetching with a remote name specified should fetch from that remote # Fetch.feature:25
    Given There is a default multirepo server with remotes                      # WebAPICucumberHooks.setUpDefaultMultiRepoWithRemotes()
    When I call "GET /repos/repo3/fetch?remote=repo1"                           # WebAPICucumberHooks.callURL(String)
    Then the response status should be '200'                                    # WebAPICucumberHooks.checkStatusCode(int)
    And the xpath "/response/success/text()" equals "true"                      # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xml response should contain "/response/Fetch/Remote" 1 times        # WebAPICucumberHooks.checkXPathCadinality(String,int)
    And the xml response should contain "/response/Fetch/Remote/Branch" 2 times # WebAPICucumberHooks.checkXPathCadinality(String,int)
    And the response body should contain "branch1"                              # WebAPICucumberHooks.checkResponseTextContains(String)
    And the response body should contain "master"                               # WebAPICucumberHooks.checkResponseTextContains(String)
[main] INFO org.mortbay.log - jetty-6.1.5
[main] INFO org.mortbay.log - Started SelectChannelConnector@0.0.0.0:8182
[main] INFO org.locationtech.geogig.plumbing.CreateDeduplicator - No DeduplicationService service found, using default heap based one
[btpool3-1] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo1 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.plumbing.CreateDeduplicator - No DeduplicationService service found, using default heap based one
[main] INFO org.locationtech.geogig.plumbing.CreateDeduplicator - No DeduplicationService service found, using default heap based one
[btpool3-1] INFO org.locationtech.geogig.rest.repository.BatchedObjectResource - Serving request to send objects based on message {"want":["8762315e76a1370c06f0f12708c35be1b758ea50","2f56f667e1e7bf9b1e83912ad3e81951b7cc9c3f"],"have":[]}
[btpool3-1] INFO org.locationtech.geogig.plumbing.CreateDeduplicator - No DeduplicationService service found, using default heap based one
[btpool3-1] INFO org.locationtech.geogig.remote.BinaryPackedObjects - scanning for previsit list...
[btpool3-1] INFO org.locationtech.geogig.remote.BinaryPackedObjects - Previsit list built in 14.77 μs for 0 ids: []. Calculating reachable content ids...
[btpool3-1] INFO org.locationtech.geogig.remote.BinaryPackedObjects - reachableContentIds took 3.498 ms for 0 ids
[btpool3-1] INFO org.locationtech.geogig.remote.BinaryPackedObjects - obtaining post order iterator on range...
[btpool3-1] INFO org.locationtech.geogig.remote.BinaryPackedObjects - PostOrderIterator.range took 381.7 μs
[btpool3-1] INFO org.locationtech.geogig.remote.BinaryPackedObjects - writing objects to remote...
[main] INFO org.locationtech.geogig.remote.HttpRemoteRepo - Processed 19 objects. Inserted: 19. Existing: 0. Time: 13.10 ms. Compressed size: 989 bytes. Uncompressed size: 3,179 bytes.
[btpool3-1] INFO org.locationtech.geogig.rest.repository.BatchedObjectResource - Serving request to send objects based on message {"want":["b4930ddf559abb450c7e4d245064ece0078e02e1"],"have":["8762315e76a1370c06f0f12708c35be1b758ea50"]}
[btpool3-1] INFO org.locationtech.geogig.plumbing.CreateDeduplicator - No DeduplicationService service found, using default heap based one
[btpool3-1] INFO org.locationtech.geogig.remote.BinaryPackedObjects - scanning for previsit list...
[btpool3-1] INFO org.locationtech.geogig.remote.BinaryPackedObjects - Previsit list built in 1.929 μs for 1 ids: [8762315e76a1370c06f0f12708c35be1b758ea50]. Calculating reachable content ids...
[btpool3-1] INFO org.locationtech.geogig.remote.BinaryPackedObjects - reachableContentIds took 842.9 μs for 11 ids
[btpool3-1] INFO org.locationtech.geogig.remote.BinaryPackedObjects - obtaining post order iterator on range...
[btpool3-1] INFO org.locationtech.geogig.remote.BinaryPackedObjects - PostOrderIterator.range took 11.21 μs
[btpool3-1] INFO org.locationtech.geogig.remote.BinaryPackedObjects - writing objects to remote...
[main] INFO org.locationtech.geogig.remote.HttpRemoteRepo - Processed 8 objects. Inserted: 8. Existing: 0. Time: 1.912 ms. Compressed size: 656 bytes. Uncompressed size: 1,488 bytes.
[btpool3-1] INFO org.locationtech.geogig.rest.repository.BatchedObjectResource - Serving request to send objects based on message {"want":["e9e192d0e63d79748053af8242d0d26ca90a97d8","c8fc762a188ec6ec3b76bc270ceb512340a7424a"],"have":["8762315e76a1370c06f0f12708c35be1b758ea50","b4930ddf559abb450c7e4d245064ece0078e02e1","2f56f667e1e7bf9b1e83912ad3e81951b7cc9c3f"]}
[btpool3-1] INFO org.locationtech.geogig.plumbing.CreateDeduplicator - No DeduplicationService service found, using default heap based one
[btpool3-1] INFO org.locationtech.geogig.remote.BinaryPackedObjects - scanning for previsit list...
[btpool3-1] INFO org.locationtech.geogig.remote.BinaryPackedObjects - Previsit list built in 2.243 μs for 3 ids: [8762315e76a1370c06f0f12708c35be1b758ea50, b4930ddf559abb450c7e4d245064ece0078e02e1, 2f56f667e1e7bf9b1e83912ad3e81951b7cc9c3f]. Calculating reachable content ids...
[btpool3-1] INFO org.locationtech.geogig.remote.BinaryPackedObjects - reachableContentIds took 1.090 ms for 27 ids
[btpool3-1] INFO org.locationtech.geogig.remote.BinaryPackedObjects - obtaining post order iterator on range...
[btpool3-1] INFO org.locationtech.geogig.remote.BinaryPackedObjects - PostOrderIterator.range took 23.73 μs
[btpool3-1] INFO org.locationtech.geogig.remote.BinaryPackedObjects - writing objects to remote...
[main] INFO org.locationtech.geogig.remote.HttpRemoteRepo - Processed 6 objects. Inserted: 6. Existing: 0. Time: 1.574 ms. Compressed size: 777 bytes. Uncompressed size: 1,673 bytes.
[main] INFO org.locationtech.geogig.plumbing.CreateDeduplicator - No DeduplicationService service found, using default heap based one
[main] INFO org.locationtech.geogig.plumbing.CreateDeduplicator - No DeduplicationService service found, using default heap based one
[main] INFO org.locationtech.geogig.plumbing.CreateDeduplicator - No DeduplicationService service found, using default heap based one
[main] INFO org.locationtech.geogig.plumbing.CreateDeduplicator - No DeduplicationService service found, using default heap based one
[btpool3-1] INFO org.locationtech.geogig.rest.repository.BatchedObjectResource - Serving request to send objects based on message {"want":["8762315e76a1370c06f0f12708c35be1b758ea50","2f56f667e1e7bf9b1e83912ad3e81951b7cc9c3f"],"have":[]}
[btpool3-1] INFO org.locationtech.geogig.plumbing.CreateDeduplicator - No DeduplicationService service found, using default heap based one
[btpool3-1] INFO org.locationtech.geogig.remote.BinaryPackedObjects - scanning for previsit list...
[btpool3-1] INFO org.locationtech.geogig.remote.BinaryPackedObjects - Previsit list built in 14.15 μs for 0 ids: []. Calculating reachable content ids...
[btpool3-1] INFO org.locationtech.geogig.remote.BinaryPackedObjects - reachableContentIds took 16.80 μs for 0 ids
[btpool3-1] INFO org.locationtech.geogig.remote.BinaryPackedObjects - obtaining post order iterator on range...
[btpool3-1] INFO org.locationtech.geogig.remote.BinaryPackedObjects - PostOrderIterator.range took 8.970 μs
[btpool3-1] INFO org.locationtech.geogig.remote.BinaryPackedObjects - writing objects to remote...
[main] INFO org.locationtech.geogig.remote.HttpRemoteRepo - Processed 19 objects. Inserted: 19. Existing: 0. Time: 4.794 ms. Compressed size: 989 bytes. Uncompressed size: 3,179 bytes.
[btpool3-1] INFO org.locationtech.geogig.rest.repository.BatchedObjectResource - Serving request to send objects based on message {"want":["b4930ddf559abb450c7e4d245064ece0078e02e1","e9e192d0e63d79748053af8242d0d26ca90a97d8","c8fc762a188ec6ec3b76bc270ceb512340a7424a"],"have":["8762315e76a1370c06f0f12708c35be1b758ea50","2f56f667e1e7bf9b1e83912ad3e81951b7cc9c3f"]}
[btpool3-1] INFO org.locationtech.geogig.plumbing.CreateDeduplicator - No DeduplicationService service found, using default heap based one
[btpool3-1] INFO org.locationtech.geogig.remote.BinaryPackedObjects - scanning for previsit list...
[btpool3-1] INFO org.locationtech.geogig.remote.BinaryPackedObjects - Previsit list built in 2.006 μs for 2 ids: [8762315e76a1370c06f0f12708c35be1b758ea50, 2f56f667e1e7bf9b1e83912ad3e81951b7cc9c3f]. Calculating reachable content ids...
[btpool3-1] INFO org.locationtech.geogig.remote.BinaryPackedObjects - reachableContentIds took 865.7 μs for 19 ids
[btpool3-1] INFO org.locationtech.geogig.remote.BinaryPackedObjects - obtaining post order iterator on range...
[btpool3-1] INFO org.locationtech.geogig.remote.BinaryPackedObjects - PostOrderIterator.range took 11.56 μs
[btpool3-1] INFO org.locationtech.geogig.remote.BinaryPackedObjects - writing objects to remote...
[main] INFO org.locationtech.geogig.remote.HttpRemoteRepo - Processed 14 objects. Inserted: 14. Existing: 0. Time: 3.193 ms. Compressed size: 1,065 bytes. Uncompressed size: 3,161 bytes.
[main] INFO org.locationtech.geogig.plumbing.CreateDeduplicator - No DeduplicationService service found, using default heap based one
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo3 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.plumbing.CreateDeduplicator - No DeduplicationService service found, using default heap based one
[main] INFO org.locationtech.geogig.plumbing.CreateDeduplicator - No DeduplicationService service found, using default heap based one
[btpool3-1] INFO org.locationtech.geogig.rest.repository.BatchedObjectResource - Serving request to send objects based on message {"want":["8762315e76a1370c06f0f12708c35be1b758ea50","2f56f667e1e7bf9b1e83912ad3e81951b7cc9c3f"],"have":[]}
[btpool3-1] INFO org.locationtech.geogig.plumbing.CreateDeduplicator - No DeduplicationService service found, using default heap based one
[btpool3-1] INFO org.locationtech.geogig.remote.BinaryPackedObjects - scanning for previsit list...
[btpool3-1] INFO org.locationtech.geogig.remote.BinaryPackedObjects - Previsit list built in 2.428 μs for 0 ids: []. Calculating reachable content ids...
[btpool3-1] INFO org.locationtech.geogig.remote.BinaryPackedObjects - reachableContentIds took 14.25 μs for 0 ids
[btpool3-1] INFO org.locationtech.geogig.remote.BinaryPackedObjects - obtaining post order iterator on range...
[btpool3-1] INFO org.locationtech.geogig.remote.BinaryPackedObjects - PostOrderIterator.range took 7.940 μs
[btpool3-1] INFO org.locationtech.geogig.remote.BinaryPackedObjects - writing objects to remote...
[main] INFO org.locationtech.geogig.remote.HttpRemoteRepo - Processed 19 objects. Inserted: 19. Existing: 0. Time: 4.534 ms. Compressed size: 989 bytes. Uncompressed size: 3,179 bytes.
[btpool3-1] INFO org.locationtech.geogig.rest.repository.BatchedObjectResource - Serving request to send objects based on message {"want":["b4930ddf559abb450c7e4d245064ece0078e02e1","e9e192d0e63d79748053af8242d0d26ca90a97d8","c8fc762a188ec6ec3b76bc270ceb512340a7424a"],"have":["8762315e76a1370c06f0f12708c35be1b758ea50","2f56f667e1e7bf9b1e83912ad3e81951b7cc9c3f"]}
[btpool3-1] INFO org.locationtech.geogig.plumbing.CreateDeduplicator - No DeduplicationService service found, using default heap based one
[btpool3-1] INFO org.locationtech.geogig.remote.BinaryPackedObjects - scanning for previsit list...
[btpool3-1] INFO org.locationtech.geogig.remote.BinaryPackedObjects - Previsit list built in 1.965 μs for 2 ids: [8762315e76a1370c06f0f12708c35be1b758ea50, 2f56f667e1e7bf9b1e83912ad3e81951b7cc9c3f]. Calculating reachable content ids...
[btpool3-1] INFO org.locationtech.geogig.remote.BinaryPackedObjects - reachableContentIds took 679.5 μs for 19 ids
[btpool3-1] INFO org.locationtech.geogig.remote.BinaryPackedObjects - obtaining post order iterator on range...
[btpool3-1] INFO org.locationtech.geogig.remote.BinaryPackedObjects - PostOrderIterator.range took 23.78 μs
[btpool3-1] INFO org.locationtech.geogig.remote.BinaryPackedObjects - writing objects to remote...
[main] INFO org.locationtech.geogig.remote.HttpRemoteRepo - Processed 14 objects. Inserted: 14. Existing: 0. Time: 2.984 ms. Compressed size: 1,065 bytes. Uncompressed size: 3,161 bytes.
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo4 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo2 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()

  @HttpTest
  Scenario: Fetching with an http remote name specified should fetch from that remote # Fetch.feature:36
    Given There is a default multirepo server with http remotes                       # WebAPICucumberHooks.setUpDefaultMultiRepoWithHttpRemotes()
    When I call "GET /repos/repo3/fetch?remote=repo1"                                 # WebAPICucumberHooks.callURL(String)
    Then the response status should be '200'                                          # WebAPICucumberHooks.checkStatusCode(int)
    And the xpath "/response/success/text()" equals "true"                            # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xml response should contain "/response/Fetch/Remote" 1 times              # WebAPICucumberHooks.checkXPathCadinality(String,int)
    And the xml response should contain "/response/Fetch/Remote/Branch" 2 times       # WebAPICucumberHooks.checkXPathCadinality(String,int)
    And the response body should contain "branch1"                                    # WebAPICucumberHooks.checkResponseTextContains(String)
    And the response body should contain "master"                                     # WebAPICucumberHooks.checkResponseTextContains(String)
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo3 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo4 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo2 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo1 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()

  Scenario: Fetching with all should fetch from all remotes                     # Fetch.feature:46
    Given There is a default multirepo server with remotes                      # WebAPICucumberHooks.setUpDefaultMultiRepoWithRemotes()
    When I call "GET /repos/repo3/fetch?all=true"                               # WebAPICucumberHooks.callURL(String)
    Then the response status should be '200'                                    # WebAPICucumberHooks.checkStatusCode(int)
    And the xpath "/response/success/text()" equals "true"                      # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xml response should contain "/response/Fetch/Remote" 2 times        # WebAPICucumberHooks.checkXPathCadinality(String,int)
    And the xml response should contain "/response/Fetch/Remote/Branch" 5 times # WebAPICucumberHooks.checkXPathCadinality(String,int)
    And the response body should contain "branch1"                              # WebAPICucumberHooks.checkResponseTextContains(String)
    And the response body should contain "branch2"                              # WebAPICucumberHooks.checkResponseTextContains(String)
    And the response body should contain "master"                               # WebAPICucumberHooks.checkResponseTextContains(String)
    And the response body should contain "ADDED_REF"                            # WebAPICucumberHooks.checkResponseTextContains(String)
    And the response body should not contain "REMOVED_REF"                      # WebAPICucumberHooks.checkResponseTextNotContains(String)
    And the response body should not contain "UPDATED_REF"                      # WebAPICucumberHooks.checkResponseTextNotContains(String)
[main] INFO org.mortbay.log - jetty-6.1.5
[main] INFO org.mortbay.log - Started SelectChannelConnector@0.0.0.0:8182
[main] INFO org.locationtech.geogig.plumbing.CreateDeduplicator - No DeduplicationService service found, using default heap based one
[btpool4-1] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo1 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.plumbing.CreateDeduplicator - No DeduplicationService service found, using default heap based one
[main] INFO org.locationtech.geogig.plumbing.CreateDeduplicator - No DeduplicationService service found, using default heap based one
[btpool4-1] INFO org.locationtech.geogig.rest.repository.BatchedObjectResource - Serving request to send objects based on message {"want":["d6b56d22946ee4b4bc4e89e31ea924ff11be023a","c5dfba452946d405825431409379e60114e31d61"],"have":[]}
[btpool4-1] INFO org.locationtech.geogig.plumbing.CreateDeduplicator - No DeduplicationService service found, using default heap based one
[btpool4-1] INFO org.locationtech.geogig.remote.BinaryPackedObjects - scanning for previsit list...
[btpool4-1] INFO org.locationtech.geogig.remote.BinaryPackedObjects - Previsit list built in 3.036 μs for 0 ids: []. Calculating reachable content ids...
[btpool4-1] INFO org.locationtech.geogig.remote.BinaryPackedObjects - reachableContentIds took 17.28 μs for 0 ids
[btpool4-1] INFO org.locationtech.geogig.remote.BinaryPackedObjects - obtaining post order iterator on range...
[btpool4-1] INFO org.locationtech.geogig.remote.BinaryPackedObjects - PostOrderIterator.range took 10.87 μs
[btpool4-1] INFO org.locationtech.geogig.remote.BinaryPackedObjects - writing objects to remote...
[main] INFO org.locationtech.geogig.remote.HttpRemoteRepo - Processed 19 objects. Inserted: 19. Existing: 0. Time: 4.101 ms. Compressed size: 990 bytes. Uncompressed size: 3,179 bytes.
[btpool4-1] INFO org.locationtech.geogig.rest.repository.BatchedObjectResource - Serving request to send objects based on message {"want":["533b3ae5c40abf365ef8f183d942c2f9c82d6372"],"have":["d6b56d22946ee4b4bc4e89e31ea924ff11be023a"]}
[btpool4-1] INFO org.locationtech.geogig.plumbing.CreateDeduplicator - No DeduplicationService service found, using default heap based one
[btpool4-1] INFO org.locationtech.geogig.remote.BinaryPackedObjects - scanning for previsit list...
[btpool4-1] INFO org.locationtech.geogig.remote.BinaryPackedObjects - Previsit list built in 2.601 μs for 1 ids: [d6b56d22946ee4b4bc4e89e31ea924ff11be023a]. Calculating reachable content ids...
[btpool4-1] INFO org.locationtech.geogig.remote.BinaryPackedObjects - reachableContentIds took 494.3 μs for 11 ids
[btpool4-1] INFO org.locationtech.geogig.remote.BinaryPackedObjects - obtaining post order iterator on range...
[btpool4-1] INFO org.locationtech.geogig.remote.BinaryPackedObjects - PostOrderIterator.range took 13.02 μs
[btpool4-1] INFO org.locationtech.geogig.remote.BinaryPackedObjects - writing objects to remote...
[main] INFO org.locationtech.geogig.remote.HttpRemoteRepo - Processed 8 objects. Inserted: 8. Existing: 0. Time: 1.615 ms. Compressed size: 657 bytes. Uncompressed size: 1,488 bytes.
[btpool4-1] INFO org.locationtech.geogig.rest.repository.BatchedObjectResource - Serving request to send objects based on message {"want":["4b0079905be6ba678aeeb3082e84414ef5a4b9f5","defe141d3eea6db0b332e046406c2e11692a6fd2"],"have":["533b3ae5c40abf365ef8f183d942c2f9c82d6372","d6b56d22946ee4b4bc4e89e31ea924ff11be023a","c5dfba452946d405825431409379e60114e31d61"]}
[btpool4-1] INFO org.locationtech.geogig.plumbing.CreateDeduplicator - No DeduplicationService service found, using default heap based one
[btpool4-1] INFO org.locationtech.geogig.remote.BinaryPackedObjects - scanning for previsit list...
[btpool4-1] INFO org.locationtech.geogig.remote.BinaryPackedObjects - Previsit list built in 2.557 μs for 3 ids: [533b3ae5c40abf365ef8f183d942c2f9c82d6372, d6b56d22946ee4b4bc4e89e31ea924ff11be023a, c5dfba452946d405825431409379e60114e31d61]. Calculating reachable content ids...
[btpool4-1] INFO org.locationtech.geogig.remote.BinaryPackedObjects - reachableContentIds took 786.8 μs for 27 ids
[btpool4-1] INFO org.locationtech.geogig.remote.BinaryPackedObjects - obtaining post order iterator on range...
[btpool4-1] INFO org.locationtech.geogig.remote.BinaryPackedObjects - PostOrderIterator.range took 26.52 μs
[btpool4-1] INFO org.locationtech.geogig.remote.BinaryPackedObjects - writing objects to remote...
[main] INFO org.locationtech.geogig.remote.HttpRemoteRepo - Processed 6 objects. Inserted: 6. Existing: 0. Time: 1.302 ms. Compressed size: 777 bytes. Uncompressed size: 1,673 bytes.
[main] INFO org.locationtech.geogig.plumbing.CreateDeduplicator - No DeduplicationService service found, using default heap based one
[main] INFO org.locationtech.geogig.plumbing.CreateDeduplicator - No DeduplicationService service found, using default heap based one
[main] INFO org.locationtech.geogig.plumbing.CreateDeduplicator - No DeduplicationService service found, using default heap based one
[main] INFO org.locationtech.geogig.plumbing.CreateDeduplicator - No DeduplicationService service found, using default heap based one
[btpool4-1] INFO org.locationtech.geogig.rest.repository.BatchedObjectResource - Serving request to send objects based on message {"want":["d6b56d22946ee4b4bc4e89e31ea924ff11be023a","c5dfba452946d405825431409379e60114e31d61"],"have":[]}
[btpool4-1] INFO org.locationtech.geogig.plumbing.CreateDeduplicator - No DeduplicationService service found, using default heap based one
[btpool4-1] INFO org.locationtech.geogig.remote.BinaryPackedObjects - scanning for previsit list...
[btpool4-1] INFO org.locationtech.geogig.remote.BinaryPackedObjects - Previsit list built in 2.861 μs for 0 ids: []. Calculating reachable content ids...
[btpool4-1] INFO org.locationtech.geogig.remote.BinaryPackedObjects - reachableContentIds took 16.99 μs for 0 ids
[btpool4-1] INFO org.locationtech.geogig.remote.BinaryPackedObjects - obtaining post order iterator on range...
[btpool4-1] INFO org.locationtech.geogig.remote.BinaryPackedObjects - PostOrderIterator.range took 11.43 μs
[btpool4-1] INFO org.locationtech.geogig.remote.BinaryPackedObjects - writing objects to remote...
[main] INFO org.locationtech.geogig.remote.HttpRemoteRepo - Processed 19 objects. Inserted: 19. Existing: 0. Time: 4.549 ms. Compressed size: 990 bytes. Uncompressed size: 3,179 bytes.
[btpool4-1] INFO org.locationtech.geogig.rest.repository.BatchedObjectResource - Serving request to send objects based on message {"want":["533b3ae5c40abf365ef8f183d942c2f9c82d6372","4b0079905be6ba678aeeb3082e84414ef5a4b9f5","defe141d3eea6db0b332e046406c2e11692a6fd2"],"have":["d6b56d22946ee4b4bc4e89e31ea924ff11be023a","c5dfba452946d405825431409379e60114e31d61"]}
[btpool4-1] INFO org.locationtech.geogig.plumbing.CreateDeduplicator - No DeduplicationService service found, using default heap based one
[btpool4-1] INFO org.locationtech.geogig.remote.BinaryPackedObjects - scanning for previsit list...
[btpool4-1] INFO org.locationtech.geogig.remote.BinaryPackedObjects - Previsit list built in 2.592 μs for 2 ids: [d6b56d22946ee4b4bc4e89e31ea924ff11be023a, c5dfba452946d405825431409379e60114e31d61]. Calculating reachable content ids...
[btpool4-1] INFO org.locationtech.geogig.remote.BinaryPackedObjects - reachableContentIds took 924.6 μs for 19 ids
[btpool4-1] INFO org.locationtech.geogig.remote.BinaryPackedObjects - obtaining post order iterator on range...
[btpool4-1] INFO org.locationtech.geogig.remote.BinaryPackedObjects - PostOrderIterator.range took 13.57 μs
[btpool4-1] INFO org.locationtech.geogig.remote.BinaryPackedObjects - writing objects to remote...
[main] INFO org.locationtech.geogig.remote.HttpRemoteRepo - Processed 14 objects. Inserted: 14. Existing: 0. Time: 2.542 ms. Compressed size: 1,065 bytes. Uncompressed size: 3,161 bytes.
[main] INFO org.locationtech.geogig.plumbing.CreateDeduplicator - No DeduplicationService service found, using default heap based one
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo3 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.plumbing.CreateDeduplicator - No DeduplicationService service found, using default heap based one
[main] INFO org.locationtech.geogig.plumbing.CreateDeduplicator - No DeduplicationService service found, using default heap based one
[btpool4-1] INFO org.locationtech.geogig.rest.repository.BatchedObjectResource - Serving request to send objects based on message {"want":["d6b56d22946ee4b4bc4e89e31ea924ff11be023a","c5dfba452946d405825431409379e60114e31d61"],"have":[]}
[btpool4-1] INFO org.locationtech.geogig.plumbing.CreateDeduplicator - No DeduplicationService service found, using default heap based one
[btpool4-1] INFO org.locationtech.geogig.remote.BinaryPackedObjects - scanning for previsit list...
[btpool4-1] INFO org.locationtech.geogig.remote.BinaryPackedObjects - Previsit list built in 2.956 μs for 0 ids: []. Calculating reachable content ids...
[btpool4-1] INFO org.locationtech.geogig.remote.BinaryPackedObjects - reachableContentIds took 16.65 μs for 0 ids
[btpool4-1] INFO org.locationtech.geogig.remote.BinaryPackedObjects - obtaining post order iterator on range...
[btpool4-1] INFO org.locationtech.geogig.remote.BinaryPackedObjects - PostOrderIterator.range took 10.98 μs
[btpool4-1] INFO org.locationtech.geogig.remote.BinaryPackedObjects - writing objects to remote...
[main] INFO org.locationtech.geogig.remote.HttpRemoteRepo - Processed 19 objects. Inserted: 19. Existing: 0. Time: 3.997 ms. Compressed size: 990 bytes. Uncompressed size: 3,179 bytes.
[btpool4-1] INFO org.locationtech.geogig.rest.repository.BatchedObjectResource - Serving request to send objects based on message {"want":["533b3ae5c40abf365ef8f183d942c2f9c82d6372","4b0079905be6ba678aeeb3082e84414ef5a4b9f5","defe141d3eea6db0b332e046406c2e11692a6fd2"],"have":["d6b56d22946ee4b4bc4e89e31ea924ff11be023a","c5dfba452946d405825431409379e60114e31d61"]}
[btpool4-1] INFO org.locationtech.geogig.plumbing.CreateDeduplicator - No DeduplicationService service found, using default heap based one
[btpool4-1] INFO org.locationtech.geogig.remote.BinaryPackedObjects - scanning for previsit list...
[btpool4-1] INFO org.locationtech.geogig.remote.BinaryPackedObjects - Previsit list built in 2.833 μs for 2 ids: [d6b56d22946ee4b4bc4e89e31ea924ff11be023a, c5dfba452946d405825431409379e60114e31d61]. Calculating reachable content ids...
[btpool4-1] INFO org.locationtech.geogig.remote.BinaryPackedObjects - reachableContentIds took 619.3 μs for 19 ids
[btpool4-1] INFO org.locationtech.geogig.remote.BinaryPackedObjects - obtaining post order iterator on range...
[btpool4-1] INFO org.locationtech.geogig.remote.BinaryPackedObjects - PostOrderIterator.range took 13.81 μs
[btpool4-1] INFO org.locationtech.geogig.remote.BinaryPackedObjects - writing objects to remote...
[main] INFO org.locationtech.geogig.remote.HttpRemoteRepo - Processed 14 objects. Inserted: 14. Existing: 0. Time: 2.319 ms. Compressed size: 1,065 bytes. Uncompressed size: 3,161 bytes.
[main] INFO org.locationtech.geogig.plumbing.CreateDeduplicator - No DeduplicationService service found, using default heap based one
[btpool4-1] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo2 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.plumbing.CreateDeduplicator - No DeduplicationService service found, using default heap based one
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo4 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()

  @HttpTest
  Scenario: Fetching with all should fetch from all http remotes                # Fetch.feature:61
    Given There is a default multirepo server with http remotes                 # WebAPICucumberHooks.setUpDefaultMultiRepoWithHttpRemotes()
    When I call "GET /repos/repo3/fetch?all=true"                               # WebAPICucumberHooks.callURL(String)
    Then the response status should be '200'                                    # WebAPICucumberHooks.checkStatusCode(int)
    And the xpath "/response/success/text()" equals "true"                      # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xml response should contain "/response/Fetch/Remote" 2 times        # WebAPICucumberHooks.checkXPathCadinality(String,int)
    And the xml response should contain "/response/Fetch/Remote/Branch" 5 times # WebAPICucumberHooks.checkXPathCadinality(String,int)
    And the response body should contain "branch1"                              # WebAPICucumberHooks.checkResponseTextContains(String)
    And the response body should contain "branch2"                              # WebAPICucumberHooks.checkResponseTextContains(String)
    And the response body should contain "master"                               # WebAPICucumberHooks.checkResponseTextContains(String)
    And the response body should contain "ADDED_REF"                            # WebAPICucumberHooks.checkResponseTextContains(String)
    And the response body should not contain "REMOVED_REF"                      # WebAPICucumberHooks.checkResponseTextNotContains(String)
    And the response body should not contain "UPDATED_REF"                      # WebAPICucumberHooks.checkResponseTextNotContains(String)
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo2 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo4 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo3 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo1 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()

  Scenario: Fetching with prune should prune remote branches that were deleted                       # Fetch.feature:75
    Given There is a default multirepo server with remotes                                           # WebAPICucumberHooks.setUpDefaultMultiRepoWithRemotes()
    When I call "GET /repos/repo2/fetch?all=true&prune=true"                                         # WebAPICucumberHooks.callURL(String)
    Then the response status should be '200'                                                         # WebAPICucumberHooks.checkStatusCode(int)
    And the xpath "/response/success/text()" equals "true"                                           # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xml response should contain "/response/Fetch/Remote" 1 times                             # WebAPICucumberHooks.checkXPathCadinality(String,int)
    And the xml response should contain "/response/Fetch/Remote/Branch" 1 times                      # WebAPICucumberHooks.checkXPathCadinality(String,int)
    And the xpath "/response/Fetch/Remote/Branch/changeType/text()" equals "REMOVED_REF"             # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xpath "/response/Fetch/Remote/Branch/name/text()" equals "branch2"                       # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xpath "/response/Fetch/Remote/Branch/oldValue/text()" equals "{@ObjectId|repo2|branch2}" # WebAPICucumberHooks.checkXPathEquals(String,String)
[main] INFO org.mortbay.log - jetty-6.1.5
[main] INFO org.mortbay.log - Started SelectChannelConnector@0.0.0.0:8182
[main] INFO org.locationtech.geogig.plumbing.CreateDeduplicator - No DeduplicationService service found, using default heap based one
[btpool5-1] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo1 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.plumbing.CreateDeduplicator - No DeduplicationService service found, using default heap based one
[main] INFO org.locationtech.geogig.plumbing.CreateDeduplicator - No DeduplicationService service found, using default heap based one
[btpool5-1] INFO org.locationtech.geogig.rest.repository.BatchedObjectResource - Serving request to send objects based on message {"want":["1b020c2bfec47be083925bfcbb9e61936b36c0ee","ecd2184336df6cbc5c71652bd10c8d494352941c"],"have":[]}
[btpool5-1] INFO org.locationtech.geogig.plumbing.CreateDeduplicator - No DeduplicationService service found, using default heap based one
[btpool5-1] INFO org.locationtech.geogig.remote.BinaryPackedObjects - scanning for previsit list...
[btpool5-1] INFO org.locationtech.geogig.remote.BinaryPackedObjects - Previsit list built in 2.368 μs for 0 ids: []. Calculating reachable content ids...
[btpool5-1] INFO org.locationtech.geogig.remote.BinaryPackedObjects - reachableContentIds took 15.12 μs for 0 ids
[btpool5-1] INFO org.locationtech.geogig.remote.BinaryPackedObjects - obtaining post order iterator on range...
[btpool5-1] INFO org.locationtech.geogig.remote.BinaryPackedObjects - PostOrderIterator.range took 7.731 μs
[btpool5-1] INFO org.locationtech.geogig.remote.BinaryPackedObjects - writing objects to remote...
[main] INFO org.locationtech.geogig.remote.HttpRemoteRepo - Processed 19 objects. Inserted: 19. Existing: 0. Time: 4.043 ms. Compressed size: 989 bytes. Uncompressed size: 3,179 bytes.
[btpool5-1] INFO org.locationtech.geogig.rest.repository.BatchedObjectResource - Serving request to send objects based on message {"want":["3f3ed6f9c8d96c5c925a274d1a503e1e7485ee16"],"have":["1b020c2bfec47be083925bfcbb9e61936b36c0ee"]}
[btpool5-1] INFO org.locationtech.geogig.plumbing.CreateDeduplicator - No DeduplicationService service found, using default heap based one
[btpool5-1] INFO org.locationtech.geogig.remote.BinaryPackedObjects - scanning for previsit list...
[btpool5-1] INFO org.locationtech.geogig.remote.BinaryPackedObjects - Previsit list built in 1.972 μs for 1 ids: [1b020c2bfec47be083925bfcbb9e61936b36c0ee]. Calculating reachable content ids...
[btpool5-1] INFO org.locationtech.geogig.remote.BinaryPackedObjects - reachableContentIds took 527.2 μs for 11 ids
[btpool5-1] INFO org.locationtech.geogig.remote.BinaryPackedObjects - obtaining post order iterator on range...
[btpool5-1] INFO org.locationtech.geogig.remote.BinaryPackedObjects - PostOrderIterator.range took 23.96 μs
[btpool5-1] INFO org.locationtech.geogig.remote.BinaryPackedObjects - writing objects to remote...
[main] INFO org.locationtech.geogig.remote.HttpRemoteRepo - Processed 8 objects. Inserted: 8. Existing: 0. Time: 1.385 ms. Compressed size: 656 bytes. Uncompressed size: 1,488 bytes.
[btpool5-1] INFO org.locationtech.geogig.rest.repository.BatchedObjectResource - Serving request to send objects based on message {"want":["3f16d9136787fbcb56672151467d01b6591c0d66","455f2eaf34ba91a0f2b90f2ed1b2e8164d9a7098"],"have":["ecd2184336df6cbc5c71652bd10c8d494352941c","1b020c2bfec47be083925bfcbb9e61936b36c0ee","3f3ed6f9c8d96c5c925a274d1a503e1e7485ee16"]}
[btpool5-1] INFO org.locationtech.geogig.plumbing.CreateDeduplicator - No DeduplicationService service found, using default heap based one
[btpool5-1] INFO org.locationtech.geogig.remote.BinaryPackedObjects - scanning for previsit list...
[btpool5-1] INFO org.locationtech.geogig.remote.BinaryPackedObjects - Previsit list built in 1.967 μs for 3 ids: [ecd2184336df6cbc5c71652bd10c8d494352941c, 1b020c2bfec47be083925bfcbb9e61936b36c0ee, 3f3ed6f9c8d96c5c925a274d1a503e1e7485ee16]. Calculating reachable content ids...
[btpool5-1] INFO org.locationtech.geogig.remote.BinaryPackedObjects - reachableContentIds took 926.9 μs for 27 ids
[btpool5-1] INFO org.locationtech.geogig.remote.BinaryPackedObjects - obtaining post order iterator on range...
[btpool5-1] INFO org.locationtech.geogig.remote.BinaryPackedObjects - PostOrderIterator.range took 23.66 μs
[btpool5-1] INFO org.locationtech.geogig.remote.BinaryPackedObjects - writing objects to remote...
[main] INFO org.locationtech.geogig.remote.HttpRemoteRepo - Processed 6 objects. Inserted: 6. Existing: 0. Time: 1.214 ms. Compressed size: 777 bytes. Uncompressed size: 1,673 bytes.
[main] INFO org.locationtech.geogig.plumbing.CreateDeduplicator - No DeduplicationService service found, using default heap based one
[main] INFO org.locationtech.geogig.plumbing.CreateDeduplicator - No DeduplicationService service found, using default heap based one
[main] INFO org.locationtech.geogig.plumbing.CreateDeduplicator - No DeduplicationService service found, using default heap based one
[main] INFO org.locationtech.geogig.plumbing.CreateDeduplicator - No DeduplicationService service found, using default heap based one
[btpool5-1] INFO org.locationtech.geogig.rest.repository.BatchedObjectResource - Serving request to send objects based on message {"want":["1b020c2bfec47be083925bfcbb9e61936b36c0ee","ecd2184336df6cbc5c71652bd10c8d494352941c"],"have":[]}
[btpool5-1] INFO org.locationtech.geogig.plumbing.CreateDeduplicator - No DeduplicationService service found, using default heap based one
[btpool5-1] INFO org.locationtech.geogig.remote.BinaryPackedObjects - scanning for previsit list...
[btpool5-1] INFO org.locationtech.geogig.remote.BinaryPackedObjects - Previsit list built in 2.240 μs for 0 ids: []. Calculating reachable content ids...
[btpool5-1] INFO org.locationtech.geogig.remote.BinaryPackedObjects - reachableContentIds took 14.64 μs for 0 ids
[btpool5-1] INFO org.locationtech.geogig.remote.BinaryPackedObjects - obtaining post order iterator on range...
[btpool5-1] INFO org.locationtech.geogig.remote.BinaryPackedObjects - PostOrderIterator.range took 8.315 μs
[btpool5-1] INFO org.locationtech.geogig.remote.BinaryPackedObjects - writing objects to remote...
[main] INFO org.locationtech.geogig.remote.HttpRemoteRepo - Processed 19 objects. Inserted: 19. Existing: 0. Time: 3.630 ms. Compressed size: 989 bytes. Uncompressed size: 3,179 bytes.
[btpool5-1] INFO org.locationtech.geogig.rest.repository.BatchedObjectResource - Serving request to send objects based on message {"want":["3f3ed6f9c8d96c5c925a274d1a503e1e7485ee16","3f16d9136787fbcb56672151467d01b6591c0d66","455f2eaf34ba91a0f2b90f2ed1b2e8164d9a7098"],"have":["ecd2184336df6cbc5c71652bd10c8d494352941c","1b020c2bfec47be083925bfcbb9e61936b36c0ee"]}
[btpool5-1] INFO org.locationtech.geogig.plumbing.CreateDeduplicator - No DeduplicationService service found, using default heap based one
[btpool5-1] INFO org.locationtech.geogig.remote.BinaryPackedObjects - scanning for previsit list...
[btpool5-1] INFO org.locationtech.geogig.remote.BinaryPackedObjects - Previsit list built in 2.211 μs for 2 ids: [ecd2184336df6cbc5c71652bd10c8d494352941c, 1b020c2bfec47be083925bfcbb9e61936b36c0ee]. Calculating reachable content ids...
[btpool5-1] INFO org.locationtech.geogig.remote.BinaryPackedObjects - reachableContentIds took 602.6 μs for 19 ids
[btpool5-1] INFO org.locationtech.geogig.remote.BinaryPackedObjects - obtaining post order iterator on range...
[btpool5-1] INFO org.locationtech.geogig.remote.BinaryPackedObjects - PostOrderIterator.range took 22.72 μs
[btpool5-1] INFO org.locationtech.geogig.remote.BinaryPackedObjects - writing objects to remote...
[main] INFO org.locationtech.geogig.remote.HttpRemoteRepo - Processed 14 objects. Inserted: 14. Existing: 0. Time: 3.125 ms. Compressed size: 1,065 bytes. Uncompressed size: 3,161 bytes.
[main] INFO org.locationtech.geogig.plumbing.CreateDeduplicator - No DeduplicationService service found, using default heap based one
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo2 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.plumbing.CreateDeduplicator - No DeduplicationService service found, using default heap based one
[main] INFO org.locationtech.geogig.plumbing.CreateDeduplicator - No DeduplicationService service found, using default heap based one
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo4 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo3 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()

  @HttpTest
  Scenario: Fetching with prune should prune remote branches that were deleted from http remote      # Fetch.feature:87
    Given There is a default multirepo server with http remotes                                      # WebAPICucumberHooks.setUpDefaultMultiRepoWithHttpRemotes()
    When I call "GET /repos/repo2/fetch?all=true&prune=true"                                         # WebAPICucumberHooks.callURL(String)
    Then the response status should be '200'                                                         # WebAPICucumberHooks.checkStatusCode(int)
    And the xpath "/response/success/text()" equals "true"                                           # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xml response should contain "/response/Fetch/Remote" 1 times                             # WebAPICucumberHooks.checkXPathCadinality(String,int)
    And the xml response should contain "/response/Fetch/Remote/Branch" 1 times                      # WebAPICucumberHooks.checkXPathCadinality(String,int)
    And the xpath "/response/Fetch/Remote/Branch/changeType/text()" equals "REMOVED_REF"             # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xpath "/response/Fetch/Remote/Branch/name/text()" equals "branch2"                       # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xpath "/response/Fetch/Remote/Branch/oldValue/text()" equals "{@ObjectId|repo2|branch2}" # WebAPICucumberHooks.checkXPathEquals(String,String)
@GeopackageSupport @GeoPackageExport
Feature: Export GeoPackage
  The GeoPackage export Web-API allows for downloading a repository snapshot or a subset of it as a GeoPackage file.
  It is possible to filter out the downloaded content indicating the names of the layers to include from a given
  root tree, and to specify a bounding box to filter out the included features.
  Also, a flag can be passed as argument to indicate the generated geopackage shall include the Geogig GeoPackage
  extension, allowing to transparently log every change to a tracked layer in an audit table that can later be
  replyed on top of the repository.  
  
  API Spec: GET /repos/<repo>/export[.xml|.json]?format=gpkg[&root=<refspec>][&path=<layerName>[,<layerName>]+][&bbox=<boundingBox>][&interchange=<true|false>]

  Scenario: Verify wrong HTTP method issues 405 "Method not allowed" # GeoPackageExport.feature:12
    Given There is an empty multirepo server                         # WebAPICucumberHooks.setUpEmptyMultiRepo()
    When I call "POST /repos/repo1/export?format=gpkg"               # WebAPICucumberHooks.callURL(String)
    Then the response status should be '405'                         # WebAPICucumberHooks.checkStatusCode(int)
    And the response allowed methods should be "GET"                 # WebAPICucumberHooks.checkResponseAllowedMethods(String)
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo1 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo2 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()

  Scenario: Verify missing "format=gpkg" argument issues 400 "Bad request"       # GeoPackageExport.feature:18
    Given There is a default multirepo server                                    # WebAPICucumberHooks.setUpDefaultMultiRepo()
    When I call "GET /repos/repo1/export"                                        # WebAPICucumberHooks.callURL(String)
    Then the response status should be '400'                                     # WebAPICucumberHooks.checkStatusCode(int)
    And the response ContentType should be "application/xml"                     # WebAPICucumberHooks.checkContentType(String)
    And the xpath "/response/success/text()" equals "false"                      # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xpath "/response/error/text()" contains "output format not provided" # WebAPICucumberHooks.checkXPathValueContains(String,String)
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo1 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo2 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()

  Scenario: Verify unsupported output format argument issues 400 "Bad request"  # GeoPackageExport.feature:26
    Given There is a default multirepo server                                   # WebAPICucumberHooks.setUpDefaultMultiRepo()
    When I call "GET /repos/repo1/export?format=badFormat"                      # WebAPICucumberHooks.callURL(String)
    Then the response status should be '400'                                    # WebAPICucumberHooks.checkStatusCode(int)
    And the response ContentType should be "application/xml"                    # WebAPICucumberHooks.checkContentType(String)
    And the xpath "/response/success/text()" equals "false"                     # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xpath "/response/error/text()" contains "Unsupported output format" # WebAPICucumberHooks.checkXPathValueContains(String,String)
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository badRepo using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()

  Scenario: Verify export on a non existent repository issues 404 "Not found" # GeoPackageExport.feature:34
    Given There is an empty multirepo server                                  # WebAPICucumberHooks.setUpEmptyMultiRepo()
    When I call "GET /repos/badRepo/export?format=gpkg"                       # WebAPICucumberHooks.callURL(String)
    Then the response status should be '404'                                  # WebAPICucumberHooks.checkStatusCode(int)
    And the response ContentType should be "text/plain"                       # WebAPICucumberHooks.checkContentType(String)
    And the response body should contain "Repository not found"               # WebAPICucumberHooks.checkResponseTextContains(String)
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo1 using FileRepositoryResolver
[main] INFO org.mortbay.log - Task %s finished: %s
Found gpkg tables: [Polygons, Points, Lines]
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo2 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()

  Scenario: Export defaults: all layers from current head                                         # GeoPackageExport.feature:41
    Given There is a default multirepo server                                                     # WebAPICucumberHooks.setUpDefaultMultiRepo()
    When I call "GET /repos/repo1/export?format=gpkg"                                             # WebAPICucumberHooks.callURL(String)
    Then the response is an XML async task @taskId                                                # WebAPICucumberHooks.checkResponseIsAnXMLAsyncTask(String)
    And the task @taskId description contains "Export to Geopackage database"                     # WebAPICucumberHooks.the_task_taskId_description_contains(String,String)
    And when the task @taskId finishes                                                            # WebAPICucumberHooks.waitForAsyncTaskToFinish(String)
    Then the task @taskId status is FINISHED                                                      # WebAPICucumberHooks.checkAsyncTaskStatus(String,AsyncContext$Status)
    And the task @taskId result contains "atom:link/@href" with value "/tasks/{@taskId}/download" # WebAPICucumberHooks.the_task_taskId_result_contains_with_value(String,String,String)
    When I call "GET /tasks/{@taskId}/download"                                                   # WebAPICucumberHooks.callURL(String)
    Then the result is a valid GeoPackage file                                                    # WebAPICucumberHooks.gpkg_CheckResponseIsGeoPackage()

  Scenario: Verify wrong HTTP method issues 405 "Method not allowed", JSON requested response # GeoPackageExport.feature:52
    Given There is an empty multirepo server                                                  # WebAPICucumberHooks.setUpEmptyMultiRepo()
    When I call "POST /repos/repo1/export.json?format=gpkg"                                   # WebAPICucumberHooks.callURL(String)
    Then the response status should be '405'                                                  # WebAPICucumberHooks.checkStatusCode(int)
    And the response allowed methods should be "GET"                                          # WebAPICucumberHooks.checkResponseAllowedMethods(String)
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo1 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo2 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()

  Scenario: Verify missing "format=gpkg" argument issues 400 "Bad request", JSON requested response # GeoPackageExport.feature:58
    Given There is a default multirepo server                                                       # WebAPICucumberHooks.setUpDefaultMultiRepo()
    When I call "GET /repos/repo1/export.json"                                                      # WebAPICucumberHooks.callURL(String)
    Then the response status should be '400'                                                        # WebAPICucumberHooks.checkStatusCode(int)
    And the response ContentType should be "application/json"                                       # WebAPICucumberHooks.checkContentType(String)
    And the json object "response.success" equals "false"                                           # WebAPICucumberHooks.checkJSONResponse(String,String)
    And the json object "response.error" equals "output format not provided"                        # WebAPICucumberHooks.checkJSONResponse(String,String)
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo1 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo2 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()

  Scenario: Verify unsupported output format argument issues 400 "Bad request", JSON requested response # GeoPackageExport.feature:66
    Given There is a default multirepo server                                                           # WebAPICucumberHooks.setUpDefaultMultiRepo()
    When I call "GET /repos/repo1/export.json?format=badFormat"                                         # WebAPICucumberHooks.callURL(String)
    Then the response status should be '400'                                                            # WebAPICucumberHooks.checkStatusCode(int)
    And the response ContentType should be "application/json"                                           # WebAPICucumberHooks.checkContentType(String)
    And the json object "response.success" equals "false"                                               # WebAPICucumberHooks.checkJSONResponse(String,String)
    And the json object "response.error" equals "Unsupported output format: badFormat"                  # WebAPICucumberHooks.checkJSONResponse(String,String)
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository badRepo using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()

  Scenario: Verify export on a non existent repository issues 404 "Not found", JSON requested response # GeoPackageExport.feature:74
    Given There is an empty multirepo server                                                           # WebAPICucumberHooks.setUpEmptyMultiRepo()
    When I call "GET /repos/badRepo/export.json?format=gpkg"                                           # WebAPICucumberHooks.callURL(String)
    Then the response status should be '404'                                                           # WebAPICucumberHooks.checkStatusCode(int)
    And the response ContentType should be "text/plain"                                                # WebAPICucumberHooks.checkContentType(String)
    And the response body should contain "Repository not found"                                        # WebAPICucumberHooks.checkResponseTextContains(String)
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo1 using FileRepositoryResolver
[main] INFO org.mortbay.log - Task %s finished: %s
Found gpkg tables: [Lines, Points, Polygons]
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo2 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()

  Scenario: Export defaults: all layers from current head, JSON requested response                                # GeoPackageExport.feature:81
    Given There is a default multirepo server                                                                     # WebAPICucumberHooks.setUpDefaultMultiRepo()
    When I call "GET /repos/repo1/export.json?format=gpkg"                                                        # WebAPICucumberHooks.callURL(String)
    Then the response is a JSON async task @taskId                                                                # WebAPICucumberHooks.checkResponseIsAJsonAsyncTask(String)
    And the JSON task @taskId description contains "Export to Geopackage database"                                # WebAPICucumberHooks.theJsonTaskTaskIdDescriptionContains(String,String)
    And when the JSON task @taskId finishes                                                                       # WebAPICucumberHooks.waitForAsyncJsonTaskToFinish(String)
    Then the JSON task @taskId status is FINISHED                                                                 # WebAPICucumberHooks.checkAsyncJsonTaskStatus(String,AsyncContext$Status)
    And the JSON task @taskId result contains "task.result.atom:link.href" with value "/tasks/{@taskId}/download" # WebAPICucumberHooks.theJsonTaskTaskIdResultContainsWithValue(String,String,String)
    When I call "GET /tasks/{@taskId}/download"                                                                   # WebAPICucumberHooks.callURL(String)
    Then the result is a valid GeoPackage file                                                                    # WebAPICucumberHooks.gpkg_CheckResponseIsGeoPackage()
@GeopackageSupport @GeoPackageImport
Feature: Import GeoPackage
  The GeoPackage import Web-API allows for uploading a set of layers from a GeoPackage file
  onto a repository snapshot and create a new commit reflecting the imported contents. 
  The GeoPackage file is sent as a POST form arument named "fileUpload". 
  Other URL arguments can be used to control some aspects of the import.
  
  API Spec: POST /repos/<repo>/import?format=gpkg[&add=<true|false>][&alter=<true|false>]

  Scenario: Verify wrong HTTP method issues 405 "Method not allowed" # GeoPackageImport.feature:10
    Given There is an empty multirepo server                         # WebAPICucumberHooks.setUpEmptyMultiRepo()
    When I call "GET /repos/repo1/import?format=gpkg"                # WebAPICucumberHooks.callURL(String)
    Then the response status should be '405'                         # WebAPICucumberHooks.checkStatusCode(int)
    And the response allowed methods should be "POST"                # WebAPICucumberHooks.checkResponseAllowedMethods(String)
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo1 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()

  Scenario: Verify missing "format=gpkg" argument issues 400 "Bad request" # GeoPackageImport.feature:16
    Given There is an empty repository named repo1                         # WebAPICucumberHooks.setUpEmptyRepo(String)
    And I have a transaction as "@txId" on the "repo1" repo                # WebAPICucumberHooks.beginTransactionAsVariable(String,String)
    When I call "POST /repos/repo1/import?transactionId={@txId}"           # WebAPICucumberHooks.callURL(String)
    Then the response status should be '400'                               # WebAPICucumberHooks.checkStatusCode(int)
    And the response ContentType should be "application/xml"               # WebAPICucumberHooks.checkContentType(String)
    And the response xml matches                                           # WebAPICucumberHooks.checkXmlResponseMatches(String)
      """
      <response><success>false</success><error>missing required 'format' parameter</error></response>
      """
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo1 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()

  Scenario: Verify unsupported output format argument issues 400 "Bad request"    # GeoPackageImport.feature:27
    Given There is an empty repository named repo1                                # WebAPICucumberHooks.setUpEmptyRepo(String)
    And I have a transaction as "@txId" on the "repo1" repo                       # WebAPICucumberHooks.beginTransactionAsVariable(String,String)
    When I call "POST /repos/repo1/import?format=badFormat&transactionId={@txId}" # WebAPICucumberHooks.callURL(String)
    Then the response status should be '400'                                      # WebAPICucumberHooks.checkStatusCode(int)
    And the response ContentType should be "application/xml"                      # WebAPICucumberHooks.checkContentType(String)
    And the response xml matches                                                  # WebAPICucumberHooks.checkXmlResponseMatches(String)
      """
      <response><success>false</success><error>Unsupported input format: 'badFormat'</error></response>
      """
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository badRepo using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()

  Scenario: Verify import to a non existent repository issues 404 "Not found"    # GeoPackageImport.feature:38
    Given There is an empty multirepo server                                     # WebAPICucumberHooks.setUpEmptyMultiRepo()
    And I have a geopackage file @gpkgFile                                       # WebAPICucumberHooks.gpkg_CreateSampleGeopackage(String)
    When I post @gpkgFile as "fileUpload" to "/repos/badRepo/import?format=gpkg" # WebAPICucumberHooks.gpkg_UploadFile(String,String,String)
    Then the response status should be '404'                                     # WebAPICucumberHooks.checkStatusCode(int)
    And the response ContentType should be "text/plain"                          # WebAPICucumberHooks.checkContentType(String)
    And the response body should contain "Repository not found"                  # WebAPICucumberHooks.checkResponseTextContains(String)
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository targetRepo using FileRepositoryResolver
[main] INFO org.mortbay.log - Task %s finished: %s
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()

  Scenario: Import to an empty repository                                                                 # GeoPackageImport.feature:46
    Given There is an empty repository named targetRepo                                                   # WebAPICucumberHooks.setUpEmptyRepo(String)
    And I have a geopackage file @gpkgFile                                                                # WebAPICucumberHooks.gpkg_CreateSampleGeopackage(String)
    And I have a transaction as "@txId" on the "targetRepo" repo                                          # WebAPICucumberHooks.beginTransactionAsVariable(String,String)
    When I post @gpkgFile as "fileUpload" to "/repos/targetRepo/import?format=gpkg&transactionId={@txId}" # WebAPICucumberHooks.gpkg_UploadFile(String,String,String)
    Then the response status should be '200'                                                              # WebAPICucumberHooks.checkStatusCode(int)
    And the response is an XML async task @taskId                                                         # WebAPICucumberHooks.checkResponseIsAnXMLAsyncTask(String)
    And the task @taskId description contains "Importing GeoPackage database file."                       # WebAPICucumberHooks.the_task_taskId_description_contains(String,String)
    And when the task @taskId finishes                                                                    # WebAPICucumberHooks.waitForAsyncTaskToFinish(String)
    Then the task @taskId status is FINISHED                                                              # WebAPICucumberHooks.checkAsyncTaskStatus(String,AsyncContext$Status)
    And the xpath "/task/result/commit/id/text()" equals "{@ObjectId|targetRepo|@txId|master}"            # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xml response should contain "/task/result/commit/tree"                                        # WebAPICucumberHooks.checkResponseContainsXPath(String)
    And I end the transaction with id "@txId" on the "targetRepo" repo                                    # WebAPICucumberHooks.endTransaction(String,String)
    And the targetRepo repository's "HEAD" should have the following features:                            # WebAPICucumberHooks.verifyRepositoryContents(String,String,DataTable)
    And I prune the task @taskId                                                                          # WebAPICucumberHooks.prune_task(String)
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo1 using FileRepositoryResolver
[main] INFO org.mortbay.log - Task %s finished: %s
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo2 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()

  Scenario: Import an interchange geopackage with fast-forward merge                                                                               # GeoPackageImport.feature:66
    Given There is a default multirepo server                                                                                                      # WebAPICucumberHooks.setUpDefaultMultiRepo()
    And I export Points from "repo1" to a geopackage file with audit logs as @gpkgFile                                                             # WebAPICucumberHooks.gpkg_ExportAuditLogs(String,String)
    And I have a transaction as "@txId" on the "repo1" repo                                                                                        # WebAPICucumberHooks.beginTransactionAsVariable(String,String)
    When I add Points/4 to the geopackage file @gpkgFile                                                                                           # WebAPICucumberHooks.gpkg_AddFeature(String)
    And I post @gpkgFile as "fileUpload" to "/repos/repo1/import?format=gpkg&message=Imported%20Geopackage&interchange=true&transactionId={@txId}" # WebAPICucumberHooks.gpkg_UploadFile(String,String,String)
    Then the response status should be '200'                                                                                                       # WebAPICucumberHooks.checkStatusCode(int)
    And the response is an XML async task @taskId                                                                                                  # WebAPICucumberHooks.checkResponseIsAnXMLAsyncTask(String)
    And the task @taskId description contains "Importing GeoPackage database file."                                                                # WebAPICucumberHooks.the_task_taskId_description_contains(String,String)
    And when the task @taskId finishes                                                                                                             # WebAPICucumberHooks.waitForAsyncTaskToFinish(String)
    Then the task @taskId status is FINISHED                                                                                                       # WebAPICucumberHooks.checkAsyncTaskStatus(String,AsyncContext$Status)
    And the xpath "/task/result/newCommit/id/text()" equals "{@ObjectId|repo1|@txId|master}"                                                       # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xml response should contain "/task/result/newCommit/tree"                                                                              # WebAPICucumberHooks.checkResponseContainsXPath(String)
    And the xpath "/task/result/newCommit/message" equals "Imported Geopackage"                                                                    # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xpath "/task/result/importCommit/id/text()" equals "{@ObjectId|repo1|@txId|master}"                                                    # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xml response should contain "/task/result/importCommit/tree"                                                                           # WebAPICucumberHooks.checkResponseContainsXPath(String)
    And the xpath "/task/result/importCommit/message" equals "Imported Geopackage"                                                                 # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xpath "/task/result/NewFeatures/type/@name" equals "Points"                                                                            # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xml response should contain "/task/result/NewFeatures/type/id/@provided" 1 times                                                       # WebAPICucumberHooks.checkXPathCadinality(String,int)
    And the xml response should contain "/task/result/NewFeatures/type/id/@assigned" 1 times                                                       # WebAPICucumberHooks.checkXPathCadinality(String,int)
    And I save the response "/task/result/NewFeatures/type/id/@assigned" as "@newFeatureId"                                                        # WebAPICucumberHooks.saveResponseXPathValueAsVariable(String,String)
    And I end the transaction with id "@txId" on the "repo1" repo                                                                                  # WebAPICucumberHooks.endTransaction(String,String)
    And the repo1 repository's "HEAD" should have the following features:                                                                          # WebAPICucumberHooks.verifyRepositoryContents(String,String,DataTable)
    And I prune the task @taskId                                                                                                                   # WebAPICucumberHooks.prune_task(String)
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo1 using FileRepositoryResolver
[main] INFO org.mortbay.log - Task %s finished: %s
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo2 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()

  Scenario: Import an interchange geopackage with non-conflicting merge                                                                            # GeoPackageImport.feature:96
    Given There is a default multirepo server                                                                                                      # WebAPICucumberHooks.setUpDefaultMultiRepo()
    And I export Points from "repo1" to a geopackage file with audit logs as @gpkgFile                                                             # WebAPICucumberHooks.gpkg_ExportAuditLogs(String,String)
    When I add Points/4 to the geopackage file @gpkgFile                                                                                           # WebAPICucumberHooks.gpkg_AddFeature(String)
    And I have removed "Point.1" on the "repo1" repo in the "" transaction                                                                         # WebAPICucumberHooks.I_have_removed(String,String,String)
    And I have a transaction as "@txId" on the "repo1" repo                                                                                        # WebAPICucumberHooks.beginTransactionAsVariable(String,String)
    And I post @gpkgFile as "fileUpload" to "/repos/repo1/import?format=gpkg&message=Imported%20Geopackage&interchange=true&transactionId={@txId}" # WebAPICucumberHooks.gpkg_UploadFile(String,String,String)
    Then the response status should be '200'                                                                                                       # WebAPICucumberHooks.checkStatusCode(int)
    And the response is an XML async task @taskId                                                                                                  # WebAPICucumberHooks.checkResponseIsAnXMLAsyncTask(String)
    And the task @taskId description contains "Importing GeoPackage database file."                                                                # WebAPICucumberHooks.the_task_taskId_description_contains(String,String)
    And when the task @taskId finishes                                                                                                             # WebAPICucumberHooks.waitForAsyncTaskToFinish(String)
    Then the task @taskId status is FINISHED                                                                                                       # WebAPICucumberHooks.checkAsyncTaskStatus(String,AsyncContext$Status)
    And the xpath "/task/result/newCommit/id/text()" equals "{@ObjectId|repo1|@txId|master}"                                                       # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xml response should contain "/task/result/newCommit/tree"                                                                              # WebAPICucumberHooks.checkResponseContainsXPath(String)
    And the xpath "/task/result/newCommit/message" equals "Merge: Imported Geopackage"                                                             # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xpath "/task/result/importCommit/id/text()" equals "{@ObjectId|repo1|@txId|master^2}"                                                  # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xml response should contain "/task/result/importCommit/tree"                                                                           # WebAPICucumberHooks.checkResponseContainsXPath(String)
    And the xpath "/task/result/importCommit/message" equals "Imported Geopackage"                                                                 # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xpath "/task/result/NewFeatures/type/@name" equals "Points"                                                                            # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xml response should contain "/task/result/NewFeatures/type/id/@provided" 1 times                                                       # WebAPICucumberHooks.checkXPathCadinality(String,int)
    And the xml response should contain "/task/result/NewFeatures/type/id/@assigned" 1 times                                                       # WebAPICucumberHooks.checkXPathCadinality(String,int)
    And I save the response "/task/result/NewFeatures/type/id/@assigned" as "@newFeatureId"                                                        # WebAPICucumberHooks.saveResponseXPathValueAsVariable(String,String)
    And I end the transaction with id "@txId" on the "repo1" repo                                                                                  # WebAPICucumberHooks.endTransaction(String,String)
    And the repo1 repository's "HEAD" should have the following features:                                                                          # WebAPICucumberHooks.verifyRepositoryContents(String,String,DataTable)
    And I prune the task @taskId                                                                                                                   # WebAPICucumberHooks.prune_task(String)
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo1 using FileRepositoryResolver
[main] INFO org.mortbay.log - Task %s finished: %s
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo2 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()

  Scenario: Import an interchange geopackage with conflicting merge                                                                                # GeoPackageImport.feature:126
    Given There is a default multirepo server                                                                                                      # WebAPICucumberHooks.setUpDefaultMultiRepo()
    And I export Points from "repo1" to a geopackage file with audit logs as @gpkgFile                                                             # WebAPICucumberHooks.gpkg_ExportAuditLogs(String,String)
    When I modify the Point features in the geopackage file @gpkgFile                                                                              # WebAPICucumberHooks.gpkg_ModifyFeature(String)
    And I add Points/4 to the geopackage file @gpkgFile                                                                                            # WebAPICucumberHooks.gpkg_AddFeature(String)
    And I have removed "Point.1" on the "repo1" repo in the "" transaction                                                                         # WebAPICucumberHooks.I_have_removed(String,String,String)
    And I have a transaction as "@txId" on the "repo1" repo                                                                                        # WebAPICucumberHooks.beginTransactionAsVariable(String,String)
    And I post @gpkgFile as "fileUpload" to "/repos/repo1/import?format=gpkg&message=Imported%20Geopackage&interchange=true&transactionId={@txId}" # WebAPICucumberHooks.gpkg_UploadFile(String,String,String)
    Then the response status should be '200'                                                                                                       # WebAPICucumberHooks.checkStatusCode(int)
    And the response is an XML async task @taskId                                                                                                  # WebAPICucumberHooks.checkResponseIsAnXMLAsyncTask(String)
    And the task @taskId description contains "Importing GeoPackage database file."                                                                # WebAPICucumberHooks.the_task_taskId_description_contains(String,String)
    And when the task @taskId finishes                                                                                                             # WebAPICucumberHooks.waitForAsyncTaskToFinish(String)
    Then the task @taskId status is FAILED                                                                                                         # WebAPICucumberHooks.checkAsyncTaskStatus(String,AsyncContext$Status)
    And the xml response should contain "/task/result/import/importCommit/id"                                                                      # WebAPICucumberHooks.checkResponseContainsXPath(String)
    And I save the response "/task/result/import/importCommit/id/text()" as "@importCommit"                                                        # WebAPICucumberHooks.saveResponseXPathValueAsVariable(String,String)
    And the xml response should contain "/task/result/import/importCommit/tree"                                                                    # WebAPICucumberHooks.checkResponseContainsXPath(String)
    And the xpath "/task/result/import/importCommit/message" equals "Imported Geopackage"                                                          # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xpath "/task/result/Merge/ours/text()" equals "{@ObjectId|repo1|@txId|master}"                                                         # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xpath "/task/result/Merge/theirs/text()" equals "{@importCommit}"                                                                      # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xpath "/task/result/Merge/ancestor/text()" equals "{@ObjectId|repo1|@txId|master~1}"                                                   # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xpath "/task/result/import/NewFeatures/type/@name" equals "Points"                                                                     # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xml response should contain "/task/result/import/NewFeatures/type/id/@provided" 1 times                                                # WebAPICucumberHooks.checkXPathCadinality(String,int)
    And the xml response should contain "/task/result/import/NewFeatures/type/id/@assigned" 1 times                                                # WebAPICucumberHooks.checkXPathCadinality(String,int)
    And I save the response "/task/result/import/NewFeatures/type/id/@assigned" as "@newFeatureId"                                                 # WebAPICucumberHooks.saveResponseXPathValueAsVariable(String,String)
    And the xpath "/task/result/Merge/conflicts" equals "1"                                                                                        # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the repo1 repository's "WORK_HEAD" in the @txId transaction should have the following features:                                            # WebAPICucumberHooks.verifyRepositoryContentsTx(String,String,String,DataTable)
    And I prune the task @taskId                                                                                                                   # WebAPICucumberHooks.prune_task(String)

  #<task><id>1</id><status>FINISHED</status><transactionId>c4da5a9b-5b09-4cb6-9055-e340d02b57ac</transactionId><description>Importing GeoPackage database file.</description><atom:link xmlns:atom="http://www.w3.org/2005/Atom" rel="alternate" href="/tasks/1.xml" type="application/xml"/><result><RevCommit><id>a1cde458d0658e096998b740b2eaa7b10796e624</id><treeId>37987a1d4afbf60be906d55576392965654d5d9c</treeId></RevCommit></result></task>
  # JSON tests
  Scenario: Verify wrong HTTP method issues 405 "Method not allowed", JSON requested response # GeoPackageImport.feature:162
    Given There is an empty multirepo server                                                  # WebAPICucumberHooks.setUpEmptyMultiRepo()
    When I call "GET /repos/repo1/import.json?format=gpkg"                                    # WebAPICucumberHooks.callURL(String)
    Then the response status should be '405'                                                  # WebAPICucumberHooks.checkStatusCode(int)
    And the response allowed methods should be "POST"                                         # WebAPICucumberHooks.checkResponseAllowedMethods(String)
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo1 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()

  Scenario: Verify missing "format=gpkg" argument issues 400 "Bad request", JSON requested response # GeoPackageImport.feature:168
    Given There is an empty repository named repo1                                                  # WebAPICucumberHooks.setUpEmptyRepo(String)
    And I have a transaction as "@txId" on the "repo1" repo                                         # WebAPICucumberHooks.beginTransactionAsVariable(String,String)
    When I call "POST /repos/repo1/import.json?transactionId={@txId}"                               # WebAPICucumberHooks.callURL(String)
    Then the response status should be '400'                                                        # WebAPICucumberHooks.checkStatusCode(int)
    And the response ContentType should be "application/json"                                       # WebAPICucumberHooks.checkContentType(String)
    And the json object "response.success" equals "false"                                           # WebAPICucumberHooks.checkJSONResponse(String,String)
    And the json object "response.error" equals "missing required 'format' parameter"               # WebAPICucumberHooks.checkJSONResponse(String,String)
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo1 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()

  Scenario: Verify unsupported output format argument issues 400 "Bad request", JSON requested response # GeoPackageImport.feature:177
    Given There is an empty repository named repo1                                                      # WebAPICucumberHooks.setUpEmptyRepo(String)
    And I have a transaction as "@txId" on the "repo1" repo                                             # WebAPICucumberHooks.beginTransactionAsVariable(String,String)
    When I call "POST /repos/repo1/import.json?format=badFormat&transactionId={@txId}"                  # WebAPICucumberHooks.callURL(String)
    Then the response status should be '400'                                                            # WebAPICucumberHooks.checkStatusCode(int)
    And the response ContentType should be "application/json"                                           # WebAPICucumberHooks.checkContentType(String)
    And the json object "response.success" equals "false"                                               # WebAPICucumberHooks.checkJSONResponse(String,String)
    And the json object "response.error" equals "Unsupported input format: 'badFormat'"                 # WebAPICucumberHooks.checkJSONResponse(String,String)
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository badRepo using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()

  Scenario: Verify import to a non existent repository issues 404 "Not found", JSON requested response # GeoPackageImport.feature:186
    Given There is an empty multirepo server                                                           # WebAPICucumberHooks.setUpEmptyMultiRepo()
    And I have a geopackage file @gpkgFile                                                             # WebAPICucumberHooks.gpkg_CreateSampleGeopackage(String)
    When I post @gpkgFile as "fileUpload" to "/repos/badRepo/import.json?format=gpkg"                  # WebAPICucumberHooks.gpkg_UploadFile(String,String,String)
    Then the response status should be '404'                                                           # WebAPICucumberHooks.checkStatusCode(int)
    And the response ContentType should be "text/plain"                                                # WebAPICucumberHooks.checkContentType(String)
    And the response body should contain "Repository not found"                                        # WebAPICucumberHooks.checkResponseTextContains(String)
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository targetRepo using FileRepositoryResolver
[main] INFO org.mortbay.log - Task %s finished: %s
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()

  Scenario: Import to an empty repository, JSON requested response                                             # GeoPackageImport.feature:194
    Given There is an empty repository named targetRepo                                                        # WebAPICucumberHooks.setUpEmptyRepo(String)
    And I have a geopackage file @gpkgFile                                                                     # WebAPICucumberHooks.gpkg_CreateSampleGeopackage(String)
    And I have a transaction as "@txId" on the "targetRepo" repo                                               # WebAPICucumberHooks.beginTransactionAsVariable(String,String)
    When I post @gpkgFile as "fileUpload" to "/repos/targetRepo/import.json?format=gpkg&transactionId={@txId}" # WebAPICucumberHooks.gpkg_UploadFile(String,String,String)
    Then the response status should be '200'                                                                   # WebAPICucumberHooks.checkStatusCode(int)
    And the response is a JSON async task @taskId                                                              # WebAPICucumberHooks.checkResponseIsAJsonAsyncTask(String)
    And the JSON task @taskId description contains "Importing GeoPackage database file."                       # WebAPICucumberHooks.theJsonTaskTaskIdDescriptionContains(String,String)
    And when the JSON task @taskId finishes                                                                    # WebAPICucumberHooks.waitForAsyncJsonTaskToFinish(String)
    Then the JSON task @taskId status is FINISHED                                                              # WebAPICucumberHooks.checkAsyncJsonTaskStatus(String,AsyncContext$Status)
    And the json object "task.result.commit.id" equals "{@ObjectId|targetRepo|@txId|master}"                   # WebAPICucumberHooks.checkJSONResponse(String,String)
    And the json response "task.result.commit" should contain "tree"                                           # WebAPICucumberHooks.checkJSONResponseContains(String,String)
    And I end the transaction with id "@txId" on the "targetRepo" repo                                         # WebAPICucumberHooks.endTransaction(String,String)
    And the targetRepo repository's "HEAD" should have the following features:                                 # WebAPICucumberHooks.verifyRepositoryContents(String,String,DataTable)
    And I prune the task @taskId                                                                               # WebAPICucumberHooks.prune_task(String)
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo1 using FileRepositoryResolver
[main] INFO org.mortbay.log - Task %s finished: %s
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo2 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()

  Scenario: Import an interchange geopackage with fast-forward merge, JSON requested response                                                           # GeoPackageImport.feature:214
    Given There is a default multirepo server                                                                                                           # WebAPICucumberHooks.setUpDefaultMultiRepo()
    And I export Points from "repo1" to a geopackage file with audit logs as @gpkgFile                                                                  # WebAPICucumberHooks.gpkg_ExportAuditLogs(String,String)
    And I have a transaction as "@txId" on the "repo1" repo                                                                                             # WebAPICucumberHooks.beginTransactionAsVariable(String,String)
    When I add Points/4 to the geopackage file @gpkgFile                                                                                                # WebAPICucumberHooks.gpkg_AddFeature(String)
    And I post @gpkgFile as "fileUpload" to "/repos/repo1/import.json?format=gpkg&message=Imported%20Geopackage&interchange=true&transactionId={@txId}" # WebAPICucumberHooks.gpkg_UploadFile(String,String,String)
    Then the response status should be '200'                                                                                                            # WebAPICucumberHooks.checkStatusCode(int)
    And the response is a JSON async task @taskId                                                                                                       # WebAPICucumberHooks.checkResponseIsAJsonAsyncTask(String)
    And the JSON task @taskId description contains "Importing GeoPackage database file."                                                                # WebAPICucumberHooks.theJsonTaskTaskIdDescriptionContains(String,String)
    And when the JSON task @taskId finishes                                                                                                             # WebAPICucumberHooks.waitForAsyncJsonTaskToFinish(String)
    Then the JSON task @taskId status is FINISHED                                                                                                       # WebAPICucumberHooks.checkAsyncJsonTaskStatus(String,AsyncContext$Status)
    And the json object "task.result.newCommit.id" equals "{@ObjectId|repo1|@txId|master}"                                                              # WebAPICucumberHooks.checkJSONResponse(String,String)
    And the json response "task.result.newCommit" should contain "tree"                                                                                 # WebAPICucumberHooks.checkJSONResponseContains(String,String)
    And the json object "task.result.newCommit.message" equals "Imported Geopackage"                                                                    # WebAPICucumberHooks.checkJSONResponse(String,String)
    And the json object "task.result.importCommit.id" equals "{@ObjectId|repo1|@txId|master}"                                                           # WebAPICucumberHooks.checkJSONResponse(String,String)
    And the json response "task.result.importCommit" should contain "tree"                                                                              # WebAPICucumberHooks.checkJSONResponseContains(String,String)
    And the json object "task.result.importCommit.message" equals "Imported Geopackage"                                                                 # WebAPICucumberHooks.checkJSONResponse(String,String)
    And the json object "task.result.NewFeatures.type[0].name" equals "Points"                                                                          # WebAPICucumberHooks.checkJSONResponse(String,String)
    And the json response "task.result.NewFeatures.type[0].id[0].provided" should contain ""                                                            # WebAPICucumberHooks.checkJSONResponseContains(String,String)
    And the json response "task.result.NewFeatures.type[0].id[0].assigned" should contain ""                                                            # WebAPICucumberHooks.checkJSONResponseContains(String,String)
    And I save the json response "task.result.NewFeatures.type[0].id[0].assigned" as "@newFeatureId"                                                    # WebAPICucumberHooks.saveResponseJSONValueAsVariable(String,String)
    And I end the transaction with id "@txId" on the "repo1" repo                                                                                       # WebAPICucumberHooks.endTransaction(String,String)
    And the repo1 repository's "HEAD" should have the following features:                                                                               # WebAPICucumberHooks.verifyRepositoryContents(String,String,DataTable)
    And I prune the task @taskId                                                                                                                        # WebAPICucumberHooks.prune_task(String)
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo1 using FileRepositoryResolver
[main] INFO org.mortbay.log - Task %s finished: %s
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo2 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()

  Scenario: Import an interchange geopackage with non-conflicting merge, JSON requested response                                                        # GeoPackageImport.feature:244
    Given There is a default multirepo server                                                                                                           # WebAPICucumberHooks.setUpDefaultMultiRepo()
    And I export Points from "repo1" to a geopackage file with audit logs as @gpkgFile                                                                  # WebAPICucumberHooks.gpkg_ExportAuditLogs(String,String)
    When I add Points/4 to the geopackage file @gpkgFile                                                                                                # WebAPICucumberHooks.gpkg_AddFeature(String)
    And I have removed "Point.1" on the "repo1" repo in the "" transaction                                                                              # WebAPICucumberHooks.I_have_removed(String,String,String)
    And I have a transaction as "@txId" on the "repo1" repo                                                                                             # WebAPICucumberHooks.beginTransactionAsVariable(String,String)
    And I post @gpkgFile as "fileUpload" to "/repos/repo1/import.json?format=gpkg&message=Imported%20Geopackage&interchange=true&transactionId={@txId}" # WebAPICucumberHooks.gpkg_UploadFile(String,String,String)
    Then the response status should be '200'                                                                                                            # WebAPICucumberHooks.checkStatusCode(int)
    And the response is a JSON async task @taskId                                                                                                       # WebAPICucumberHooks.checkResponseIsAJsonAsyncTask(String)
    And the JSON task @taskId description contains "Importing GeoPackage database file."                                                                # WebAPICucumberHooks.theJsonTaskTaskIdDescriptionContains(String,String)
    And when the JSON task @taskId finishes                                                                                                             # WebAPICucumberHooks.waitForAsyncJsonTaskToFinish(String)
    Then the JSON task @taskId status is FINISHED                                                                                                       # WebAPICucumberHooks.checkAsyncJsonTaskStatus(String,AsyncContext$Status)
    And the json object "task.result.newCommit.id" equals "{@ObjectId|repo1|@txId|master}"                                                              # WebAPICucumberHooks.checkJSONResponse(String,String)
    And the json response "task.result.newCommit" should contain "tree"                                                                                 # WebAPICucumberHooks.checkJSONResponseContains(String,String)
    And the json object "task.result.newCommit.message" equals "Merge: Imported Geopackage"                                                             # WebAPICucumberHooks.checkJSONResponse(String,String)
    And the json object "task.result.importCommit.id" equals "{@ObjectId|repo1|@txId|master^2}"                                                         # WebAPICucumberHooks.checkJSONResponse(String,String)
    And the json response "task.result.importCommit" should contain "tree"                                                                              # WebAPICucumberHooks.checkJSONResponseContains(String,String)
    And the json object "task.result.importCommit.message" equals "Imported Geopackage"                                                                 # WebAPICucumberHooks.checkJSONResponse(String,String)
    And the json object "task.result.NewFeatures.type[0].name" equals "Points"                                                                          # WebAPICucumberHooks.checkJSONResponse(String,String)
    And the json response "task.result.NewFeatures.type[0].id[0].provided" should contain ""                                                            # WebAPICucumberHooks.checkJSONResponseContains(String,String)
    And the json response "task.result.NewFeatures.type[0].id[0].assigned" should contain ""                                                            # WebAPICucumberHooks.checkJSONResponseContains(String,String)
    And I save the json response "task.result.NewFeatures.type[0].id[0].assigned" as "@newFeatureId"                                                    # WebAPICucumberHooks.saveResponseJSONValueAsVariable(String,String)
    And I end the transaction with id "@txId" on the "repo1" repo                                                                                       # WebAPICucumberHooks.endTransaction(String,String)
    And the repo1 repository's "HEAD" should have the following features:                                                                               # WebAPICucumberHooks.verifyRepositoryContents(String,String,DataTable)
    And I prune the task @taskId                                                                                                                        # WebAPICucumberHooks.prune_task(String)
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo1 using FileRepositoryResolver
[main] INFO org.mortbay.log - Task %s finished: %s
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo2 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()

  Scenario: Import an interchange geopackage with conflicting merge, JSON requested response                                                            # GeoPackageImport.feature:274
    Given There is a default multirepo server                                                                                                           # WebAPICucumberHooks.setUpDefaultMultiRepo()
    And I export Points from "repo1" to a geopackage file with audit logs as @gpkgFile                                                                  # WebAPICucumberHooks.gpkg_ExportAuditLogs(String,String)
    When I modify the Point features in the geopackage file @gpkgFile                                                                                   # WebAPICucumberHooks.gpkg_ModifyFeature(String)
    And I add Points/4 to the geopackage file @gpkgFile                                                                                                 # WebAPICucumberHooks.gpkg_AddFeature(String)
    And I have removed "Point.1" on the "repo1" repo in the "" transaction                                                                              # WebAPICucumberHooks.I_have_removed(String,String,String)
    And I have a transaction as "@txId" on the "repo1" repo                                                                                             # WebAPICucumberHooks.beginTransactionAsVariable(String,String)
    And I post @gpkgFile as "fileUpload" to "/repos/repo1/import.json?format=gpkg&message=Imported%20Geopackage&interchange=true&transactionId={@txId}" # WebAPICucumberHooks.gpkg_UploadFile(String,String,String)
    Then the response status should be '200'                                                                                                            # WebAPICucumberHooks.checkStatusCode(int)
    And the response is a JSON async task @taskId                                                                                                       # WebAPICucumberHooks.checkResponseIsAJsonAsyncTask(String)
    And the JSON task @taskId description contains "Importing GeoPackage database file."                                                                # WebAPICucumberHooks.theJsonTaskTaskIdDescriptionContains(String,String)
    And when the JSON task @taskId finishes                                                                                                             # WebAPICucumberHooks.waitForAsyncJsonTaskToFinish(String)
    Then the JSON task @taskId status is FAILED                                                                                                         # WebAPICucumberHooks.checkAsyncJsonTaskStatus(String,AsyncContext$Status)
    And the json response "task.result.Merge" should contain "ours"                                                                                     # WebAPICucumberHooks.checkJSONResponseContains(String,String)
    And the json response "task.result.Merge" should contain "theirs"                                                                                   # WebAPICucumberHooks.checkJSONResponseContains(String,String)
    And the json response "task.result.Merge" should contain "ancestor"                                                                                 # WebAPICucumberHooks.checkJSONResponseContains(String,String)
    And the json response "task.result.import.importCommit" should contain "id"                                                                         # WebAPICucumberHooks.checkJSONResponseContains(String,String)
    And I save the json response "task.result.import.importCommit.id" as "@importCommit"                                                                # WebAPICucumberHooks.saveResponseJSONValueAsVariable(String,String)
    And the json response "task.result.import.importCommit" should contain "tree"                                                                       # WebAPICucumberHooks.checkJSONResponseContains(String,String)
    And the json object "task.result.import.importCommit.message" equals "Imported Geopackage"                                                          # WebAPICucumberHooks.checkJSONResponse(String,String)
    And the json object "task.result.Merge.ours" equals "{@ObjectId|repo1|@txId|master}"                                                                # WebAPICucumberHooks.checkJSONResponse(String,String)
    And the json object "task.result.Merge.theirs" equals "{@importCommit}"                                                                             # WebAPICucumberHooks.checkJSONResponse(String,String)
    And the json object "task.result.Merge.ancestor" equals "{@ObjectId|repo1|@txId|master~1}"                                                          # WebAPICucumberHooks.checkJSONResponse(String,String)
    And the json object "task.result.import.NewFeatures.type[0].name" equals "Points"                                                                   # WebAPICucumberHooks.checkJSONResponse(String,String)
    And the json response "task.result.import.NewFeatures.type[0].id[0].provided" should contain ""                                                     # WebAPICucumberHooks.checkJSONResponseContains(String,String)
    And the json response "task.result.import.NewFeatures.type[0].id[0].assigned" should contain ""                                                     # WebAPICucumberHooks.checkJSONResponseContains(String,String)
    And I save the json response "task.result.import.NewFeatures.type[0].id[0].assigned" as "@newFeatureId"                                             # WebAPICucumberHooks.saveResponseJSONValueAsVariable(String,String)
    And the json object "task.result.Merge.conflicts" equals "1"                                                                                        # WebAPICucumberHooks.checkJSONResponse(String,String)
    And the repo1 repository's "WORK_HEAD" in the @txId transaction should have the following features:                                                 # WebAPICucumberHooks.verifyRepositoryContentsTx(String,String,String,DataTable)
    And I prune the task @taskId                                                                                                                        # WebAPICucumberHooks.prune_task(String)
@Commands @GetCommitGraph
Feature: GetCommitGraph
  The get commit graph command allows a user to retrieve the commit graph of a repo and is supported through the "/repos/{repository}/getCommitGraph" endpoint
  The command must be executed using the HTTP GET method
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo1 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()

  Scenario: Verify wrong HTTP method issues 405 "Method not allowed" # GetCommitGraph.feature:6
    Given There is an empty repository named repo1                   # WebAPICucumberHooks.setUpEmptyRepo(String)
    When I call "PUT /repos/repo1/getCommitGraph"                    # WebAPICucumberHooks.callURL(String)
    Then the response status should be '405'                         # WebAPICucumberHooks.checkStatusCode(int)
    And the response allowed methods should be "GET"                 # WebAPICucumberHooks.checkResponseAllowedMethods(String)
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo1 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()

  Scenario: Getting the commit graph outside of a repository issues 404 "Not found" # GetCommitGraph.feature:12
    Given There is an empty multirepo server                                        # WebAPICucumberHooks.setUpEmptyMultiRepo()
    When I call "GET /repos/repo1/getCommitGraph?commitId=someId"                   # WebAPICucumberHooks.callURL(String)
    Then the response status should be '404'                                        # WebAPICucumberHooks.checkStatusCode(int)
    And the response ContentType should be "text/plain"                             # WebAPICucumberHooks.checkContentType(String)
    And the response body should contain "Repository not found"                     # WebAPICucumberHooks.checkResponseTextContains(String)
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo1 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()

  Scenario: Getting the commit graph without specifying a commit issues a 500 status code             # GetCommitGraph.feature:19
    Given There is an empty repository named repo1                                                    # WebAPICucumberHooks.setUpEmptyRepo(String)
    When I call "GET /repos/repo1/getCommitGraph"                                                     # WebAPICucumberHooks.callURL(String)
    Then the response status should be '500'                                                          # WebAPICucumberHooks.checkStatusCode(int)
    And the xpath "/response/error/text()" contains "Required parameter 'commitId' was not provided." # WebAPICucumberHooks.checkXPathValueContains(String,String)
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo1 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo2 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()

  Scenario: Getting the commit graph without specifying a depth returns the full graph # GetCommitGraph.feature:25
    Given There is a default multirepo server                                          # WebAPICucumberHooks.setUpDefaultMultiRepo()
    When I call "GET /repos/repo1/getCommitGraph?commitId={@ObjectId|repo1|master}"    # WebAPICucumberHooks.callURL(String)
    Then the response status should be '200'                                           # WebAPICucumberHooks.checkStatusCode(int)
    And the xpath "/response/success/text()" equals "true"                             # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xml response should contain "/response/commit" 5 times                     # WebAPICucumberHooks.checkXPathCadinality(String,int)
    And the response body should contain "{@ObjectId|repo1|master}"                    # WebAPICucumberHooks.checkResponseTextContains(String)
    And the response body should contain "{@ObjectId|repo1|master~1}"                  # WebAPICucumberHooks.checkResponseTextContains(String)
    And the response body should contain "{@ObjectId|repo1|master~2}"                  # WebAPICucumberHooks.checkResponseTextContains(String)
    And the response body should contain "{@ObjectId|repo1|branch1}"                   # WebAPICucumberHooks.checkResponseTextContains(String)
    And the response body should contain "{@ObjectId|repo1|branch2}"                   # WebAPICucumberHooks.checkResponseTextContains(String)
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo1 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo2 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()

  Scenario: Getting the commit graph with a depth of 0 returns the full graph               # GetCommitGraph.feature:37
    Given There is a default multirepo server                                               # WebAPICucumberHooks.setUpDefaultMultiRepo()
    When I call "GET /repos/repo1/getCommitGraph?commitId={@ObjectId|repo1|master}&depth=0" # WebAPICucumberHooks.callURL(String)
    Then the response status should be '200'                                                # WebAPICucumberHooks.checkStatusCode(int)
    And the xpath "/response/success/text()" equals "true"                                  # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xml response should contain "/response/commit" 5 times                          # WebAPICucumberHooks.checkXPathCadinality(String,int)
    And the response body should contain "{@ObjectId|repo1|master}"                         # WebAPICucumberHooks.checkResponseTextContains(String)
    And the response body should contain "{@ObjectId|repo1|master~1}"                       # WebAPICucumberHooks.checkResponseTextContains(String)
    And the response body should contain "{@ObjectId|repo1|master~2}"                       # WebAPICucumberHooks.checkResponseTextContains(String)
    And the response body should contain "{@ObjectId|repo1|branch1}"                        # WebAPICucumberHooks.checkResponseTextContains(String)
    And the response body should contain "{@ObjectId|repo1|branch2}"                        # WebAPICucumberHooks.checkResponseTextContains(String)
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo1 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo2 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()

  Scenario: Getting the commit graph with a depth of 2 returns only the commit and its parents # GetCommitGraph.feature:49
    Given There is a default multirepo server                                                  # WebAPICucumberHooks.setUpDefaultMultiRepo()
    When I call "GET /repos/repo1/getCommitGraph?commitId={@ObjectId|repo1|master}&depth=2"    # WebAPICucumberHooks.callURL(String)
    Then the response status should be '200'                                                   # WebAPICucumberHooks.checkStatusCode(int)
    And the xpath "/response/success/text()" equals "true"                                     # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xml response should contain "/response/commit" 3 times                             # WebAPICucumberHooks.checkXPathCadinality(String,int)
    And the response body should contain "{@ObjectId|repo1|master}"                            # WebAPICucumberHooks.checkResponseTextContains(String)
    And the response body should contain "{@ObjectId|repo1|master~1}"                          # WebAPICucumberHooks.checkResponseTextContains(String)
    And the response body should contain "{@ObjectId|repo1|branch2}"                           # WebAPICucumberHooks.checkResponseTextContains(String)
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo1 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo2 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()

  Scenario: Getting the commit graph should support paging                                        # GetCommitGraph.feature:59
    Given There is a default multirepo server                                                     # WebAPICucumberHooks.setUpDefaultMultiRepo()
    When I call "GET /repos/repo1/getCommitGraph?commitId={@ObjectId|repo1|master}&show=2"        # WebAPICucumberHooks.callURL(String)
    Then the response status should be '200'                                                      # WebAPICucumberHooks.checkStatusCode(int)
    And the xpath "/response/success/text()" equals "true"                                        # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xml response should contain "/response/commit" 2 times                                # WebAPICucumberHooks.checkXPathCadinality(String,int)
    And the response body should contain "{@ObjectId|repo1|master}"                               # WebAPICucumberHooks.checkResponseTextContains(String)
    And the response body should contain "{@ObjectId|repo1|master~1}"                             # WebAPICucumberHooks.checkResponseTextContains(String)
    When I call "GET /repos/repo1/getCommitGraph?commitId={@ObjectId|repo1|master}&show=2&page=1" # WebAPICucumberHooks.callURL(String)
    Then the response status should be '200'                                                      # WebAPICucumberHooks.checkStatusCode(int)
    And the xpath "/response/success/text()" equals "true"                                        # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xml response should contain "/response/commit" 2 times                                # WebAPICucumberHooks.checkXPathCadinality(String,int)
    And the response body should contain "{@ObjectId|repo1|branch2}"                              # WebAPICucumberHooks.checkResponseTextContains(String)
    And the response body should contain "{@ObjectId|repo1|master~2}"                             # WebAPICucumberHooks.checkResponseTextContains(String)
    When I call "GET /repos/repo1/getCommitGraph?commitId={@ObjectId|repo1|master}&show=2&page=2" # WebAPICucumberHooks.callURL(String)
    Then the response status should be '200'                                                      # WebAPICucumberHooks.checkStatusCode(int)
    And the xpath "/response/success/text()" equals "true"                                        # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xml response should contain "/response/commit" 1 times                                # WebAPICucumberHooks.checkXPathCadinality(String,int)
    And the response body should contain "{@ObjectId|repo1|branch1}"                              # WebAPICucumberHooks.checkResponseTextContains(String)
@Commands @IndexCreate
Feature: IndexCreate
  The Index Create command allows a user to add spatial index to a specified layer
  The command must be executed using the HTTP PUT method
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository noRepo using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo1 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()

  Scenario: Create index fails when repository does not exist      # IndexCreate.feature:6
    Given There is an empty repository named repo1                 # WebAPICucumberHooks.setUpEmptyRepo(String)
    When I call "PUT /repos/noRepo/index/create?treeRefSpec=Point" # WebAPICucumberHooks.callURL(String)
    Then the response body should contain "Repository not found."  # WebAPICucumberHooks.checkResponseTextContains(String)
    Then the response status should be '404'                       # WebAPICucumberHooks.checkStatusCode(int)

  Scenario: Verify method not allowed on incorrect request type    # IndexCreate.feature:12
    Given There is a repo with some data                           # WebAPICucumberHooks.setUpRepoWithData()
    When I call "GET /repos/repo1/index/create?treeRefSpec=Points" # WebAPICucumberHooks.callURL(String)
    Then the response status should be '405'                       # WebAPICucumberHooks.checkStatusCode(int)
    And the response allowed methods should be "PUT"               # WebAPICucumberHooks.checkResponseAllowedMethods(String)
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo1 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()

  Scenario: Create index fails when feature tree does not exist                # IndexCreate.feature:18
    Given There is an empty repository named repo1                             # WebAPICucumberHooks.setUpEmptyRepo(String)
    And I have a transaction as "@txId" on the "repo1" repo                    # WebAPICucumberHooks.beginTransactionAsVariable(String,String)
    And I have staged "Point.1" on the "repo1" repo in the "@txId" transaction # WebAPICucumberHooks.I_have_staged(String,String,String)
    When I call "PUT /repos/repo1/index/create?treeRefSpec=Point"              # WebAPICucumberHooks.callURL(String)
    Then the response body should contain "Can't find feature tree"            # WebAPICucumberHooks.checkResponseTextContains(String)
    And the response status should be '400'                                    # WebAPICucumberHooks.checkStatusCode(int)
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo1 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()

  Scenario: Verify success after adding spatial index                                  # IndexCreate.feature:26
    Given There is a repo with some data                                               # WebAPICucumberHooks.setUpRepoWithData()
    When I call "PUT /repos/repo1/index/create?treeRefSpec=Points"                     # WebAPICucumberHooks.callURL(String)
    Then the xpath "/response/success/text()" equals "true"                            # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xpath "/response/index/treeName/text()" equals "Points"                    # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the response status should be '201'                                            # WebAPICucumberHooks.checkStatusCode(int)
    And the repo1 repository's "HEAD:Points" index bounds should be "-90,-180,90,180"  # WebAPICucumberHooks.verifyIndexBounds(String,String,String)
    And the repo1 repository's "HEAD:Points" index should have the following features: # WebAPICucumberHooks.verifyIndexContents(String,String,DataTable)
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo1 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()

  Scenario: Verify creating index with attribute                                             # IndexCreate.feature:37
    Given There is a repo with some data                                                     # WebAPICucumberHooks.setUpRepoWithData()
    When I call "PUT /repos/repo1/index/create?treeRefSpec=Points&extraAttributes=sp"        # WebAPICucumberHooks.callURL(String)
    Then the xpath "/response/success/text()" equals "true"                                  # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xpath "/response/index/treeName/text()" equals "Points"                          # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the response status should be '201'                                                  # WebAPICucumberHooks.checkStatusCode(int)
    And the repo1 repository's "HEAD:Points" index bounds should be "-90,-180,90,180"        # WebAPICucumberHooks.verifyIndexBounds(String,String,String)
    And the repo1 repository's "HEAD:Points" index should track the extra attribute "sp"     # WebAPICucumberHooks.verifyIndexExtraAttributes(String,String,String)
    And the repo1 repository's "HEAD:Points" index should not track the extra attribute "ip" # WebAPICucumberHooks.verifyIndexNotExtraAttributes(String,String,String)
    And the repo1 repository's "HEAD:Points" index should have the following features:       # WebAPICucumberHooks.verifyIndexContents(String,String,DataTable)
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo1 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()

  Scenario: Verify creating index with bounds                                                # IndexCreate.feature:50
    Given There is a repo with some data                                                     # WebAPICucumberHooks.setUpRepoWithData()
    When I call "PUT /repos/repo1/index/create?treeRefSpec=Points&bounds=-60,-45,60,45"      # WebAPICucumberHooks.callURL(String)
    Then the xpath "/response/success/text()" equals "true"                                  # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xpath "/response/index/treeName/text()" equals "Points"                          # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the response status should be '201'                                                  # WebAPICucumberHooks.checkStatusCode(int)
    And the repo1 repository's "HEAD:Points" index bounds should be "-60,-45,60,45"          # WebAPICucumberHooks.verifyIndexBounds(String,String,String)
    And the repo1 repository's "HEAD:Points" index should not track the extra attribute "sp" # WebAPICucumberHooks.verifyIndexNotExtraAttributes(String,String,String)
    And the repo1 repository's "HEAD:Points" index should not track the extra attribute "ip" # WebAPICucumberHooks.verifyIndexNotExtraAttributes(String,String,String)
    And the repo1 repository's "HEAD:Points" index should have the following features:       # WebAPICucumberHooks.verifyIndexContents(String,String,DataTable)
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo1 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()

  Scenario: Verify creating index with extra attribute                                                   # IndexCreate.feature:63
    Given There is a repo with some data                                                                 # WebAPICucumberHooks.setUpRepoWithData()
    When I call "PUT /repos/repo1/index/create?treeRefSpec=Points&extraAttributes=sp&extraAttributes=ip" # WebAPICucumberHooks.callURL(String)
    Then the xpath "/response/success/text()" equals "true"                                              # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xpath "/response/index/treeName/text()" equals "Points"                                      # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the response status should be '201'                                                              # WebAPICucumberHooks.checkStatusCode(int)
    And the repo1 repository's "HEAD:Points" index bounds should be "-90,-180,90,180"                    # WebAPICucumberHooks.verifyIndexBounds(String,String,String)
    And the repo1 repository's "HEAD:Points" index should track the extra attribute "sp"                 # WebAPICucumberHooks.verifyIndexExtraAttributes(String,String,String)
    And the repo1 repository's "HEAD:Points" index should track the extra attribute "ip"                 # WebAPICucumberHooks.verifyIndexExtraAttributes(String,String,String)
    And the repo1 repository's "HEAD:Points" index should have the following features:                   # WebAPICucumberHooks.verifyIndexContents(String,String,DataTable)
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo1 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo2 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()

  Scenario: Verify creating index with full history                                        # IndexCreate.feature:76
    Given There is a default multirepo server                                              # WebAPICucumberHooks.setUpDefaultMultiRepo()
    When I call "PUT /repos/repo1/index/create?treeRefSpec=Points&indexHistory=true"       # WebAPICucumberHooks.callURL(String)
    Then the xpath "/response/success/text()" equals "true"                                # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xpath "/response/index/treeName/text()" equals "Points"                        # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the response status should be '201'                                                # WebAPICucumberHooks.checkStatusCode(int)
    And the repo1 repository's "HEAD:Points" index bounds should be "-90,-180,90,180"      # WebAPICucumberHooks.verifyIndexBounds(String,String,String)
    And the repo1 repository's "HEAD:Points" index should have the following features:     # WebAPICucumberHooks.verifyIndexContents(String,String,DataTable)
    And the repo1 repository's "branch1:Points" index should have the following features:  # WebAPICucumberHooks.verifyIndexContents(String,String,DataTable)
    And the repo1 repository's "branch2:Points" index should have the following features:  # WebAPICucumberHooks.verifyIndexContents(String,String,DataTable)
    And the repo1 repository's "master~2:Points" index should have the following features: # WebAPICucumberHooks.verifyIndexContents(String,String,DataTable)
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo1 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo2 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()

  Scenario: Verify creating index with full history and extra attributes                                # IndexCreate.feature:100
    Given There is a default multirepo server                                                           # WebAPICucumberHooks.setUpDefaultMultiRepo()
    When I call "PUT /repos/repo1/index/create?treeRefSpec=Points&extraAttributes=sp&indexHistory=true" # WebAPICucumberHooks.callURL(String)
    Then the xpath "/response/success/text()" equals "true"                                             # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xpath "/response/index/treeName/text()" equals "Points"                                     # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the response status should be '201'                                                             # WebAPICucumberHooks.checkStatusCode(int)
    And the repo1 repository's "HEAD:Points" index bounds should be "-90,-180,90,180"                   # WebAPICucumberHooks.verifyIndexBounds(String,String,String)
    And the repo1 repository's "HEAD:Points" index should track the extra attribute "sp"                # WebAPICucumberHooks.verifyIndexExtraAttributes(String,String,String)
    And the repo1 repository's "HEAD:Points" index should not track the extra attribute "ip"            # WebAPICucumberHooks.verifyIndexNotExtraAttributes(String,String,String)
    And the repo1 repository's "HEAD:Points" index should have the following features:                  # WebAPICucumberHooks.verifyIndexContents(String,String,DataTable)
    And the repo1 repository's "branch1:Points" index should track the extra attribute "sp"             # WebAPICucumberHooks.verifyIndexExtraAttributes(String,String,String)
    And the repo1 repository's "branch1:Points" index should not track the extra attribute "ip"         # WebAPICucumberHooks.verifyIndexNotExtraAttributes(String,String,String)
    And the repo1 repository's "branch1:Points" index should have the following features:               # WebAPICucumberHooks.verifyIndexContents(String,String,DataTable)
    And the repo1 repository's "branch2:Points" index should track the extra attribute "sp"             # WebAPICucumberHooks.verifyIndexExtraAttributes(String,String,String)
    And the repo1 repository's "branch2:Points" index should not track the extra attribute "ip"         # WebAPICucumberHooks.verifyIndexNotExtraAttributes(String,String,String)
    And the repo1 repository's "branch2:Points" index should have the following features:               # WebAPICucumberHooks.verifyIndexContents(String,String,DataTable)
    And the repo1 repository's "master~2:Points" index should track the extra attribute "sp"            # WebAPICucumberHooks.verifyIndexExtraAttributes(String,String,String)
    And the repo1 repository's "master~2:Points" index should not track the extra attribute "ip"        # WebAPICucumberHooks.verifyIndexNotExtraAttributes(String,String,String)
    And the repo1 repository's "master~2:Points" index should have the following features:              # WebAPICucumberHooks.verifyIndexContents(String,String,DataTable)

  Scenario: Verify 500 status code when tree ref spec is not provided                                  # IndexCreate.feature:132
    Given There is a repo with some data                                                               # WebAPICucumberHooks.setUpRepoWithData()
    When I call "PUT /repos/repo1/index/create?extraAttributes=sp"                                     # WebAPICucumberHooks.callURL(String)
    Then the xpath "/response/success/text()" equals "false"                                           # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xpath "/response/error/text()" equals "Required parameter 'treeRefSpec' was not provided." # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the response status should be '500'                                                            # WebAPICucumberHooks.checkStatusCode(int)
@Commands @IndexDrop
Feature: IndexDrop
  The Index Drop command allows a user to remove an existing index from the repository
  The command must be executed using the HTTP DELETE method
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository noRepo using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()

  Scenario: Index drop fails with non-existent repository            # IndexDrop.feature:6
    Given There is an empty multirepo server                         # WebAPICucumberHooks.setUpEmptyMultiRepo()
    When I call "DELETE /repos/noRepo/index/drop?treeRefSpec=Points" # WebAPICucumberHooks.callURL(String)
    Then the response body should contain "Repository not found."    # WebAPICucumberHooks.checkResponseTextContains(String)
    And the response status should be '404'                          # WebAPICucumberHooks.checkStatusCode(int)

  Scenario: Verify method not allowed on incorrect request type  # IndexDrop.feature:12
    Given There is a repo with some data                         # WebAPICucumberHooks.setUpRepoWithData()
    When I call "GET /repos/repo1/index/drop?treeRefSpec=Points" # WebAPICucumberHooks.callURL(String)
    Then the response status should be '405'                     # WebAPICucumberHooks.checkStatusCode(int)
    And the response allowed methods should be "DELETE"          # WebAPICucumberHooks.checkResponseAllowedMethods(String)
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo1 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()

  Scenario: Verify dropping spatial index                                                    # IndexDrop.feature:18
    Given There is a repo with some data                                                     # WebAPICucumberHooks.setUpRepoWithData()
    When I call "PUT /repos/repo1/index/create?treeRefSpec=Points"                           # WebAPICucumberHooks.callURL(String)
    Then the repo1 repository's "HEAD:Points" index bounds should be "-90,-180,90,180"       # WebAPICucumberHooks.verifyIndexBounds(String,String,String)
    And the repo1 repository's "HEAD:Points" index should not track the extra attribute "sp" # WebAPICucumberHooks.verifyIndexNotExtraAttributes(String,String,String)
    And the repo1 repository's "HEAD:Points" index should not track the extra attribute "ip" # WebAPICucumberHooks.verifyIndexNotExtraAttributes(String,String,String)
    And the repo1 repository's "HEAD:Points" index should have the following features:       # WebAPICucumberHooks.verifyIndexContents(String,String,DataTable)
    When I call "DELETE /repos/repo1/index/drop?treeRefSpec=Points"                          # WebAPICucumberHooks.callURL(String)
    Then the xpath "/response/success/text()" equals "true"                                  # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xpath "/response/dropped/treeName/text()" equals "Points"                        # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the repo1 repository's "HEAD:Points" should not have an index                        # WebAPICucumberHooks.noIndexAtCommit(String,String)
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo1 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()

  Scenario: Verify 500 status code when tree ref spec is not provided                                  # IndexDrop.feature:32
    Given There is a repo with some data                                                               # WebAPICucumberHooks.setUpRepoWithData()
    When I call "PUT /repos/repo1/index/create?treeRefSpec=Points&extraAttributes=sp"                  # WebAPICucumberHooks.callURL(String)
    Then the repo1 repository's "HEAD:Points" index bounds should be "-90,-180,90,180"                 # WebAPICucumberHooks.verifyIndexBounds(String,String,String)
    And the repo1 repository's "HEAD:Points" index should track the extra attribute "sp"               # WebAPICucumberHooks.verifyIndexExtraAttributes(String,String,String)
    And the repo1 repository's "HEAD:Points" index should not track the extra attribute "ip"           # WebAPICucumberHooks.verifyIndexNotExtraAttributes(String,String,String)
    And the repo1 repository's "HEAD:Points" index should have the following features:                 # WebAPICucumberHooks.verifyIndexContents(String,String,DataTable)
    When I call "DELETE /repos/repo1/index/drop"                                                       # WebAPICucumberHooks.callURL(String)
    Then the xpath "/response/success/text()" equals "false"                                           # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xpath "/response/error/text()" equals "Required parameter 'treeRefSpec' was not provided." # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the response status should be '500'                                                            # WebAPICucumberHooks.checkStatusCode(int)
@Commands @IndexList
Feature: IndexList
  The Index List command allows a user to display spatial index info for a feature tree
  The command must be executed using the HTTP GET method
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository noRepo using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()

  Scenario: Index list fails non-existent repository                   # IndexList.feature:6
    Given There is a repo with some data                               # WebAPICucumberHooks.setUpRepoWithData()
    When I call "GET /repos/noRepo/index/list?treeName=does_not_exist" # WebAPICucumberHooks.callURL(String)
    Then the response body should contain "Repository not found."      # WebAPICucumberHooks.checkResponseTextContains(String)
    And the response status should be '404'                            # WebAPICucumberHooks.checkStatusCode(int)
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo1 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()

  Scenario: Verify method not allowed on incorrect request type   # IndexList.feature:12
    Given There is a repo with some data                          # WebAPICucumberHooks.setUpRepoWithData()
    And I call "PUT /repos/repo1/index/create?treeRefSpec=Points" # WebAPICucumberHooks.callURL(String)
    When I call "POST /repos/repo1/index/list"                    # WebAPICucumberHooks.callURL(String)
    Then the response status should be '405'                      # WebAPICucumberHooks.checkStatusCode(int)
    And the response allowed methods should be "GET"              # WebAPICucumberHooks.checkResponseAllowedMethods(String)
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo1 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo2 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()

  Scenario: Verify index list return for all feature trees                       # IndexList.feature:19
    Given There is a default multirepo server                                    # WebAPICucumberHooks.setUpDefaultMultiRepo()
    And I call "PUT /repos/repo1/index/create?treeRefSpec=Points"                # WebAPICucumberHooks.callURL(String)
    And I call "PUT /repos/repo1/index/create?treeRefSpec=Lines"                 # WebAPICucumberHooks.callURL(String)
    When I call "GET /repos/repo1/index/list"                                    # WebAPICucumberHooks.callURL(String)
    Then the xpath "/response/success/text()" equals "true"                      # WebAPICucumberHooks.checkXPathEquals(String,String)
    And there is an xpath "/response/index/treeName/text()" that equals "Points" # WebAPICucumberHooks.checkOneXPathEquals(String,String)
    And there is an xpath "/response/index/treeName/text()" that equals "Lines"  # WebAPICucumberHooks.checkOneXPathEquals(String,String)
    And the response status should be '200'                                      # WebAPICucumberHooks.checkStatusCode(int)
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo1 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()

  Scenario: Verify correct index list return for a feature tree     # IndexList.feature:29
    Given There is a repo with some data                            # WebAPICucumberHooks.setUpRepoWithData()
    And I call "PUT /repos/repo1/index/create?treeRefSpec=Points"   # WebAPICucumberHooks.callURL(String)
    And I call "PUT /repos/repo1/index/create?treeRefSpec=Lines"    # WebAPICucumberHooks.callURL(String)
    When I call "GET /repos/repo1/index/list?treeName=Points"       # WebAPICucumberHooks.callURL(String)
    Then the xpath "/response/success/text()" equals "true"         # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xpath "/response/index/treeName/text()" equals "Points" # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the response body should not contain "Lines"                # WebAPICucumberHooks.checkResponseTextNotContains(String)
    And the response status should be '200'                         # WebAPICucumberHooks.checkStatusCode(int)
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo1 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()

  Scenario: Verify failed index list return for non-existent feature tree                                    # IndexList.feature:39
    Given There is a repo with some data                                                                     # WebAPICucumberHooks.setUpRepoWithData()
    When I call "GET /repos/repo1/index/list?treeName=does_not_exist"                                        # WebAPICucumberHooks.callURL(String)
    Then the xpath "/response/success/text()" equals "false"                                                 # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xpath "/response/error/text()" equals "The provided tree name was not found in the HEAD commit." # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the response status should be '404'                                                                  # WebAPICucumberHooks.checkStatusCode(int)
@Commands @IndexRebuild
Feature: IndexRebuild
  The Index Rebuild command allows a user to rebuild the spatial index for a specified layer
  The command must be executed using the HTTP POST method
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo1 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()

  Scenario: Index Rebuild fails for non-existent repository        # IndexRebuild.feature:6
    Given There is an empty multirepo server                       # WebAPICucumberHooks.setUpEmptyMultiRepo()
    When I call "PUT /repos/repo1/index/create?treeRefSpec=Points" # WebAPICucumberHooks.callURL(String)
    Then the response body should contain "Repository not found."  # WebAPICucumberHooks.checkResponseTextContains(String)
    And the response status should be '404'                        # WebAPICucumberHooks.checkStatusCode(int)
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo1 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()

  Scenario: Verify method not allowed on incorrect request type     # IndexRebuild.feature:12
    Given There is a repo with some data                            # WebAPICucumberHooks.setUpRepoWithData()
    And I call "PUT /repos/repo1/index/create?treeRefSpec=Points"   # WebAPICucumberHooks.callURL(String)
    When I call "GET /repos/repo1/index/rebuild?treeRefSpec=Points" # WebAPICucumberHooks.callURL(String)
    Then the response status should be '405'                        # WebAPICucumberHooks.checkStatusCode(int)
    And the response allowed methods should be "POST"               # WebAPICucumberHooks.checkResponseAllowedMethods(String)
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo1 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo2 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()

  Scenario: Verify quad tree after rebuilding spatial index                                      # IndexRebuild.feature:19
    Given There is a default multirepo server                                                    # WebAPICucumberHooks.setUpDefaultMultiRepo()
    And I call "PUT /repos/repo1/index/create?treeRefSpec=Points&extraAttributes=sp"             # WebAPICucumberHooks.callURL(String)
    And the repo1 repository's "HEAD:Points" index should track the extra attribute "sp"         # WebAPICucumberHooks.verifyIndexExtraAttributes(String,String,String)
    And the repo1 repository's "HEAD:Points" index should not track the extra attribute "ip"     # WebAPICucumberHooks.verifyIndexNotExtraAttributes(String,String,String)
    Then the repo1 repository's "HEAD:Points" index should have the following features:          # WebAPICucumberHooks.verifyIndexContents(String,String,DataTable)
    And the repo1 repository's "branch1:Points" should not have an index                         # WebAPICucumberHooks.noIndexAtCommit(String,String)
    And the repo1 repository's "branch2:Points" should not have an index                         # WebAPICucumberHooks.noIndexAtCommit(String,String)
    And the repo1 repository's "master~2:Points" should not have an index                        # WebAPICucumberHooks.noIndexAtCommit(String,String)
    When I call "POST /repos/repo1/index/rebuild?treeRefSpec=Points"                             # WebAPICucumberHooks.callURL(String)
    Then the xpath "/response/success/text()" equals "true"                                      # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xpath "/response/treesRebuilt/text()" equals "4"                                     # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the repo1 repository's "HEAD:Points" index should track the extra attribute "sp"         # WebAPICucumberHooks.verifyIndexExtraAttributes(String,String,String)
    And the repo1 repository's "HEAD:Points" index should not track the extra attribute "ip"     # WebAPICucumberHooks.verifyIndexNotExtraAttributes(String,String,String)
    And the repo1 repository's "HEAD:Points" index should have the following features:           # WebAPICucumberHooks.verifyIndexContents(String,String,DataTable)
    And the repo1 repository's "branch1:Points" index should track the extra attribute "sp"      # WebAPICucumberHooks.verifyIndexExtraAttributes(String,String,String)
    And the repo1 repository's "branch1:Points" index should not track the extra attribute "ip"  # WebAPICucumberHooks.verifyIndexNotExtraAttributes(String,String,String)
    And the repo1 repository's "branch1:Points" index should have the following features:        # WebAPICucumberHooks.verifyIndexContents(String,String,DataTable)
    And the repo1 repository's "branch2:Points" index should track the extra attribute "sp"      # WebAPICucumberHooks.verifyIndexExtraAttributes(String,String,String)
    And the repo1 repository's "branch2:Points" index should not track the extra attribute "ip"  # WebAPICucumberHooks.verifyIndexNotExtraAttributes(String,String,String)
    And the repo1 repository's "branch2:Points" index should have the following features:        # WebAPICucumberHooks.verifyIndexContents(String,String,DataTable)
    And the repo1 repository's "master~2:Points" index should track the extra attribute "sp"     # WebAPICucumberHooks.verifyIndexExtraAttributes(String,String,String)
    And the repo1 repository's "master~2:Points" index should not track the extra attribute "ip" # WebAPICucumberHooks.verifyIndexNotExtraAttributes(String,String,String)
    And the repo1 repository's "master~2:Points" index should have the following features:       # WebAPICucumberHooks.verifyIndexContents(String,String,DataTable)
    And the response status should be '201'                                                      # WebAPICucumberHooks.checkStatusCode(int)
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo1 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()

  Scenario: Verify 500 status code when tree ref spec is not provided                                  # IndexRebuild.feature:61
    Given There is a repo with some data                                                               # WebAPICucumberHooks.setUpRepoWithData()
    When I call "PUT /repos/repo1/index/create?treeRefSpec=Points&extraAttributes=sp"                  # WebAPICucumberHooks.callURL(String)
    Then the repo1 repository's "HEAD:Points" index bounds should be "-90,-180,90,180"                 # WebAPICucumberHooks.verifyIndexBounds(String,String,String)
    And the repo1 repository's "HEAD:Points" index should track the extra attribute "sp"               # WebAPICucumberHooks.verifyIndexExtraAttributes(String,String,String)
    And the repo1 repository's "HEAD:Points" index should not track the extra attribute "ip"           # WebAPICucumberHooks.verifyIndexNotExtraAttributes(String,String,String)
    And the repo1 repository's "HEAD:Points" index should have the following features:                 # WebAPICucumberHooks.verifyIndexContents(String,String,DataTable)
    When I call "POST /repos/repo1/index/rebuild"                                                      # WebAPICucumberHooks.callURL(String)
    Then the xpath "/response/success/text()" equals "false"                                           # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xpath "/response/error/text()" equals "Required parameter 'treeRefSpec' was not provided." # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the response status should be '500'                                                            # WebAPICucumberHooks.checkStatusCode(int)
@Commands @IndexUpdate
Feature: IndexUpdate
  The Index Update command allows a user to update the spatial index with extra attributes
  The command must be executed using the HTTP POST method
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository noRepo using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()

  Scenario: Index update fails with non-existent repository                                      # IndexUpdate.feature:6
    Given There is an empty multirepo server                                                     # WebAPICucumberHooks.setUpEmptyMultiRepo()
    When I call "POST /repos/noRepo/index/update?treeRefSpec=Points&extraAttributes=ip&add=true" # WebAPICucumberHooks.callURL(String)
    Then the response body should contain "Repository not found."                                # WebAPICucumberHooks.checkResponseTextContains(String)
    And the response status should be '404'                                                      # WebAPICucumberHooks.checkStatusCode(int)

  Scenario: Verify method not allowed on incorrect request type                                # IndexUpdate.feature:12
    Given There is a repo with some data                                                       # WebAPICucumberHooks.setUpRepoWithData()
    When I call "GET /repos/repo1/index/update?treeRefSpec=Points&extraAttributes=ip&add=true" # WebAPICucumberHooks.callURL(String)
    Then the response status should be '405'                                                   # WebAPICucumberHooks.checkStatusCode(int)
    And the response allowed methods should be "POST"                                          # WebAPICucumberHooks.checkResponseAllowedMethods(String)
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo1 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()

  Scenario: Verify updating spatial index by adding attributes                                  # IndexUpdate.feature:18
    Given There is a repo with some data                                                        # WebAPICucumberHooks.setUpRepoWithData()
    When I call "PUT /repos/repo1/index/create?treeRefSpec=Points"                              # WebAPICucumberHooks.callURL(String)
    Then the repo1 repository's "HEAD:Points" index bounds should be "-90,-180,90,180"          # WebAPICucumberHooks.verifyIndexBounds(String,String,String)
    And the repo1 repository's "HEAD:Points" index should not track the extra attribute "sp"    # WebAPICucumberHooks.verifyIndexNotExtraAttributes(String,String,String)
    And the repo1 repository's "HEAD:Points" index should not track the extra attribute "ip"    # WebAPICucumberHooks.verifyIndexNotExtraAttributes(String,String,String)
    And the repo1 repository's "HEAD:Points" index should have the following features:          # WebAPICucumberHooks.verifyIndexContents(String,String,DataTable)
    When I call "POST /repos/repo1/index/update?treeRefSpec=Points&extraAttributes=sp"          # WebAPICucumberHooks.callURL(String)
    Then the xpath "/response/success/text()" equals "true"                                     # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xpath "/response/index/treeName/text()" equals "Points"                             # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the repo1 repository's "HEAD:Points" index should track the extra attribute "sp"        # WebAPICucumberHooks.verifyIndexExtraAttributes(String,String,String)
    And the repo1 repository's "HEAD:Points" index should not track the extra attribute "ip"    # WebAPICucumberHooks.verifyIndexNotExtraAttributes(String,String,String)
    And the repo1 repository's "HEAD:Points" index should have the following features:          # WebAPICucumberHooks.verifyIndexContents(String,String,DataTable)
    And the response status should be '201'                                                     # WebAPICucumberHooks.checkStatusCode(int)
    When I call "POST /repos/repo1/index/update?treeRefSpec=Points&extraAttributes=ip&add=true" # WebAPICucumberHooks.callURL(String)
    Then the xpath "/response/success/text()" equals "true"                                     # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xpath "/response/index/treeName/text()" equals "Points"                             # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the repo1 repository's "HEAD:Points" index should track the extra attribute "sp"        # WebAPICucumberHooks.verifyIndexExtraAttributes(String,String,String)
    And the repo1 repository's "HEAD:Points" index should track the extra attribute "ip"        # WebAPICucumberHooks.verifyIndexExtraAttributes(String,String,String)
    And the repo1 repository's "HEAD:Points" index should have the following features:          # WebAPICucumberHooks.verifyIndexContents(String,String,DataTable)
    And the response status should be '201'                                                     # WebAPICucumberHooks.checkStatusCode(int)
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo1 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()

  Scenario: Verify success when overwriting the attributes of an index                                # IndexUpdate.feature:46
    Given There is a repo with some data                                                              # WebAPICucumberHooks.setUpRepoWithData()
    When I call "PUT /repos/repo1/index/create?treeRefSpec=Points&extraAttributes=sp"                 # WebAPICucumberHooks.callURL(String)
    Then the repo1 repository's "HEAD:Points" index bounds should be "-90,-180,90,180"                # WebAPICucumberHooks.verifyIndexBounds(String,String,String)
    And the repo1 repository's "HEAD:Points" index should track the extra attribute "sp"              # WebAPICucumberHooks.verifyIndexExtraAttributes(String,String,String)
    And the repo1 repository's "HEAD:Points" index should not track the extra attribute "ip"          # WebAPICucumberHooks.verifyIndexNotExtraAttributes(String,String,String)
    And the repo1 repository's "HEAD:Points" index should have the following features:                # WebAPICucumberHooks.verifyIndexContents(String,String,DataTable)
    When I call "POST /repos/repo1/index/update?treeRefSpec=Points&extraAttributes=ip&overwrite=true" # WebAPICucumberHooks.callURL(String)
    Then the xpath "/response/success/text()" equals "true"                                           # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xpath "/response/index/treeName/text()" equals "Points"                                   # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the repo1 repository's "HEAD:Points" index bounds should be "-90,-180,90,180"                 # WebAPICucumberHooks.verifyIndexBounds(String,String,String)
    And the repo1 repository's "HEAD:Points" index should not track the extra attribute "sp"          # WebAPICucumberHooks.verifyIndexNotExtraAttributes(String,String,String)
    And the repo1 repository's "HEAD:Points" index should track the extra attribute "ip"              # WebAPICucumberHooks.verifyIndexExtraAttributes(String,String,String)
    And the repo1 repository's "HEAD:Points" index should have the following features:                # WebAPICucumberHooks.verifyIndexContents(String,String,DataTable)
    And the response status should be '201'                                                           # WebAPICucumberHooks.checkStatusCode(int)
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo1 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()

  Scenario: Verify success when removing the attributes of an index                          # IndexUpdate.feature:66
    Given There is a repo with some data                                                     # WebAPICucumberHooks.setUpRepoWithData()
    When I call "PUT /repos/repo1/index/create?treeRefSpec=Points&extraAttributes=sp"        # WebAPICucumberHooks.callURL(String)
    Then the repo1 repository's "HEAD:Points" index bounds should be "-90,-180,90,180"       # WebAPICucumberHooks.verifyIndexBounds(String,String,String)
    And the repo1 repository's "HEAD:Points" index should track the extra attribute "sp"     # WebAPICucumberHooks.verifyIndexExtraAttributes(String,String,String)
    And the repo1 repository's "HEAD:Points" index should not track the extra attribute "ip" # WebAPICucumberHooks.verifyIndexNotExtraAttributes(String,String,String)
    And the repo1 repository's "HEAD:Points" index should have the following features:       # WebAPICucumberHooks.verifyIndexContents(String,String,DataTable)
    When I call "POST /repos/repo1/index/update?treeRefSpec=Points&overwrite=true"           # WebAPICucumberHooks.callURL(String)
    Then the xpath "/response/success/text()" equals "true"                                  # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xpath "/response/index/treeName/text()" equals "Points"                          # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the repo1 repository's "HEAD:Points" index bounds should be "-90,-180,90,180"        # WebAPICucumberHooks.verifyIndexBounds(String,String,String)
    And the repo1 repository's "HEAD:Points" index should not track the extra attribute "sp" # WebAPICucumberHooks.verifyIndexNotExtraAttributes(String,String,String)
    And the repo1 repository's "HEAD:Points" index should not track the extra attribute "ip" # WebAPICucumberHooks.verifyIndexNotExtraAttributes(String,String,String)
    And the repo1 repository's "HEAD:Points" index should have the following features:       # WebAPICucumberHooks.verifyIndexContents(String,String,DataTable)
    And the response status should be '201'                                                  # WebAPICucumberHooks.checkStatusCode(int)
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo1 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()

  Scenario: Verify success when updating the bounds                                          # IndexUpdate.feature:86
    Given There is a repo with some data                                                     # WebAPICucumberHooks.setUpRepoWithData()
    When I call "PUT /repos/repo1/index/create?treeRefSpec=Points&extraAttributes=sp"        # WebAPICucumberHooks.callURL(String)
    Then the repo1 repository's "HEAD:Points" index bounds should be "-90,-180,90,180"       # WebAPICucumberHooks.verifyIndexBounds(String,String,String)
    And the repo1 repository's "HEAD:Points" index should track the extra attribute "sp"     # WebAPICucumberHooks.verifyIndexExtraAttributes(String,String,String)
    And the repo1 repository's "HEAD:Points" index should not track the extra attribute "ip" # WebAPICucumberHooks.verifyIndexNotExtraAttributes(String,String,String)
    And the repo1 repository's "HEAD:Points" index should have the following features:       # WebAPICucumberHooks.verifyIndexContents(String,String,DataTable)
    When I call "POST /repos/repo1/index/update?treeRefSpec=Points&bounds=-60,-45,60,45"     # WebAPICucumberHooks.callURL(String)
    Then the xpath "/response/success/text()" equals "true"                                  # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xpath "/response/index/treeName/text()" equals "Points"                          # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the repo1 repository's "HEAD:Points" index bounds should be "-60,-45,60,45"          # WebAPICucumberHooks.verifyIndexBounds(String,String,String)
    And the repo1 repository's "HEAD:Points" index should track the extra attribute "sp"     # WebAPICucumberHooks.verifyIndexExtraAttributes(String,String,String)
    And the repo1 repository's "HEAD:Points" index should not track the extra attribute "ip" # WebAPICucumberHooks.verifyIndexNotExtraAttributes(String,String,String)
    And the repo1 repository's "HEAD:Points" index should have the following features:       # WebAPICucumberHooks.verifyIndexContents(String,String,DataTable)
    And the response status should be '201'                                                  # WebAPICucumberHooks.checkStatusCode(int)
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo1 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo2 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()

  Scenario: Verify success when updating the whole history of an index                                                  # IndexUpdate.feature:106
    Given There is a default multirepo server                                                                           # WebAPICucumberHooks.setUpDefaultMultiRepo()
    When I call "PUT /repos/repo1/index/create?treeRefSpec=Points&extraAttributes=sp&indexHistory=true"                 # WebAPICucumberHooks.callURL(String)
    Then the repo1 repository's "HEAD:Points" index bounds should be "-90,-180,90,180"                                  # WebAPICucumberHooks.verifyIndexBounds(String,String,String)
    And the repo1 repository's "HEAD:Points" index should track the extra attribute "sp"                                # WebAPICucumberHooks.verifyIndexExtraAttributes(String,String,String)
    And the repo1 repository's "HEAD:Points" index should not track the extra attribute "ip"                            # WebAPICucumberHooks.verifyIndexNotExtraAttributes(String,String,String)
    And the repo1 repository's "HEAD:Points" index should have the following features:                                  # WebAPICucumberHooks.verifyIndexContents(String,String,DataTable)
    And the repo1 repository's "branch1:Points" index should track the extra attribute "sp"                             # WebAPICucumberHooks.verifyIndexExtraAttributes(String,String,String)
    And the repo1 repository's "branch1:Points" index should not track the extra attribute "ip"                         # WebAPICucumberHooks.verifyIndexNotExtraAttributes(String,String,String)
    And the repo1 repository's "branch1:Points" index should have the following features:                               # WebAPICucumberHooks.verifyIndexContents(String,String,DataTable)
    And the repo1 repository's "branch2:Points" index should track the extra attribute "sp"                             # WebAPICucumberHooks.verifyIndexExtraAttributes(String,String,String)
    And the repo1 repository's "branch2:Points" index should not track the extra attribute "ip"                         # WebAPICucumberHooks.verifyIndexNotExtraAttributes(String,String,String)
    And the repo1 repository's "branch2:Points" index should have the following features:                               # WebAPICucumberHooks.verifyIndexContents(String,String,DataTable)
    And the repo1 repository's "master~2:Points" index should track the extra attribute "sp"                            # WebAPICucumberHooks.verifyIndexExtraAttributes(String,String,String)
    And the repo1 repository's "master~2:Points" index should not track the extra attribute "ip"                        # WebAPICucumberHooks.verifyIndexNotExtraAttributes(String,String,String)
    And the repo1 repository's "master~2:Points" index should have the following features:                              # WebAPICucumberHooks.verifyIndexContents(String,String,DataTable)
    When I call "POST /repos/repo1/index/update?treeRefSpec=Points&extraAttributes=ip&overwrite=true&indexHistory=true" # WebAPICucumberHooks.callURL(String)
    Then the xpath "/response/success/text()" equals "true"                                                             # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xpath "/response/index/treeName/text()" equals "Points"                                                     # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the repo1 repository's "HEAD:Points" index bounds should be "-90,-180,90,180"                                   # WebAPICucumberHooks.verifyIndexBounds(String,String,String)
    And the repo1 repository's "HEAD:Points" index should not track the extra attribute "sp"                            # WebAPICucumberHooks.verifyIndexNotExtraAttributes(String,String,String)
    And the repo1 repository's "HEAD:Points" index should track the extra attribute "ip"                                # WebAPICucumberHooks.verifyIndexExtraAttributes(String,String,String)
    And the repo1 repository's "HEAD:Points" index should have the following features:                                  # WebAPICucumberHooks.verifyIndexContents(String,String,DataTable)
    And the repo1 repository's "branch1:Points" index should not track the extra attribute "sp"                         # WebAPICucumberHooks.verifyIndexNotExtraAttributes(String,String,String)
    And the repo1 repository's "branch1:Points" index should track the extra attribute "ip"                             # WebAPICucumberHooks.verifyIndexExtraAttributes(String,String,String)
    And the repo1 repository's "branch1:Points" index should have the following features:                               # WebAPICucumberHooks.verifyIndexContents(String,String,DataTable)
    And the repo1 repository's "branch2:Points" index should not track the extra attribute "sp"                         # WebAPICucumberHooks.verifyIndexNotExtraAttributes(String,String,String)
    And the repo1 repository's "branch2:Points" index should track the extra attribute "ip"                             # WebAPICucumberHooks.verifyIndexExtraAttributes(String,String,String)
    And the repo1 repository's "branch2:Points" index should have the following features:                               # WebAPICucumberHooks.verifyIndexContents(String,String,DataTable)
    And the repo1 repository's "master~2:Points" index should not track the extra attribute "sp"                        # WebAPICucumberHooks.verifyIndexNotExtraAttributes(String,String,String)
    And the repo1 repository's "master~2:Points" index should track the extra attribute "ip"                            # WebAPICucumberHooks.verifyIndexExtraAttributes(String,String,String)
    And the repo1 repository's "master~2:Points" index should have the following features:                              # WebAPICucumberHooks.verifyIndexContents(String,String,DataTable)
    And the response status should be '201'                                                                             # WebAPICucumberHooks.checkStatusCode(int)
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo1 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo2 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()

  Scenario: Verify success when updating only the head commit of an index                               # IndexUpdate.feature:165
    Given There is a default multirepo server                                                           # WebAPICucumberHooks.setUpDefaultMultiRepo()
    When I call "PUT /repos/repo1/index/create?treeRefSpec=Points&extraAttributes=sp&indexHistory=true" # WebAPICucumberHooks.callURL(String)
    Then the repo1 repository's "HEAD:Points" index bounds should be "-90,-180,90,180"                  # WebAPICucumberHooks.verifyIndexBounds(String,String,String)
    And the repo1 repository's "HEAD:Points" index should track the extra attribute "sp"                # WebAPICucumberHooks.verifyIndexExtraAttributes(String,String,String)
    And the repo1 repository's "HEAD:Points" index should not track the extra attribute "ip"            # WebAPICucumberHooks.verifyIndexNotExtraAttributes(String,String,String)
    And the repo1 repository's "HEAD:Points" index should have the following features:                  # WebAPICucumberHooks.verifyIndexContents(String,String,DataTable)
    And the repo1 repository's "branch1:Points" index should track the extra attribute "sp"             # WebAPICucumberHooks.verifyIndexExtraAttributes(String,String,String)
    And the repo1 repository's "branch1:Points" index should not track the extra attribute "ip"         # WebAPICucumberHooks.verifyIndexNotExtraAttributes(String,String,String)
    And the repo1 repository's "branch1:Points" index should have the following features:               # WebAPICucumberHooks.verifyIndexContents(String,String,DataTable)
    And the repo1 repository's "branch2:Points" index should track the extra attribute "sp"             # WebAPICucumberHooks.verifyIndexExtraAttributes(String,String,String)
    And the repo1 repository's "branch2:Points" index should not track the extra attribute "ip"         # WebAPICucumberHooks.verifyIndexNotExtraAttributes(String,String,String)
    And the repo1 repository's "branch2:Points" index should have the following features:               # WebAPICucumberHooks.verifyIndexContents(String,String,DataTable)
    And the repo1 repository's "master~2:Points" index should track the extra attribute "sp"            # WebAPICucumberHooks.verifyIndexExtraAttributes(String,String,String)
    And the repo1 repository's "master~2:Points" index should not track the extra attribute "ip"        # WebAPICucumberHooks.verifyIndexNotExtraAttributes(String,String,String)
    And the repo1 repository's "master~2:Points" index should have the following features:              # WebAPICucumberHooks.verifyIndexContents(String,String,DataTable)
    When I call "POST /repos/repo1/index/update?treeRefSpec=Points&extraAttributes=ip&overwrite=true"   # WebAPICucumberHooks.callURL(String)
    Then the xpath "/response/success/text()" equals "true"                                             # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xpath "/response/index/treeName/text()" equals "Points"                                     # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the repo1 repository's "HEAD:Points" index bounds should be "-90,-180,90,180"                   # WebAPICucumberHooks.verifyIndexBounds(String,String,String)
    And the repo1 repository's "HEAD:Points" index should not track the extra attribute "sp"            # WebAPICucumberHooks.verifyIndexNotExtraAttributes(String,String,String)
    And the repo1 repository's "HEAD:Points" index should track the extra attribute "ip"                # WebAPICucumberHooks.verifyIndexExtraAttributes(String,String,String)
    And the repo1 repository's "HEAD:Points" index should have the following features:                  # WebAPICucumberHooks.verifyIndexContents(String,String,DataTable)
    And the repo1 repository's "branch1:Points" index should track the extra attribute "sp"             # WebAPICucumberHooks.verifyIndexExtraAttributes(String,String,String)
    And the repo1 repository's "branch1:Points" index should not track the extra attribute "ip"         # WebAPICucumberHooks.verifyIndexNotExtraAttributes(String,String,String)
    And the repo1 repository's "branch1:Points" index should have the following features:               # WebAPICucumberHooks.verifyIndexContents(String,String,DataTable)
    And the repo1 repository's "branch2:Points" index should track the extra attribute "sp"             # WebAPICucumberHooks.verifyIndexExtraAttributes(String,String,String)
    And the repo1 repository's "branch2:Points" index should not track the extra attribute "ip"         # WebAPICucumberHooks.verifyIndexNotExtraAttributes(String,String,String)
    And the repo1 repository's "branch2:Points" index should have the following features:               # WebAPICucumberHooks.verifyIndexContents(String,String,DataTable)
    And the repo1 repository's "master~2:Points" index should track the extra attribute "sp"            # WebAPICucumberHooks.verifyIndexExtraAttributes(String,String,String)
    And the repo1 repository's "master~2:Points" index should not track the extra attribute "ip"        # WebAPICucumberHooks.verifyIndexNotExtraAttributes(String,String,String)
    And the repo1 repository's "master~2:Points" index should have the following features:              # WebAPICucumberHooks.verifyIndexContents(String,String,DataTable)
    And the response status should be '201'                                                             # WebAPICucumberHooks.checkStatusCode(int)
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo1 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()

  Scenario: Verify 500 status code when tree ref spec is not provided                                  # IndexUpdate.feature:224
    Given There is a repo with some data                                                               # WebAPICucumberHooks.setUpRepoWithData()
    When I call "PUT /repos/repo1/index/create?treeRefSpec=Points&extraAttributes=sp"                  # WebAPICucumberHooks.callURL(String)
    Then the repo1 repository's "HEAD:Points" index bounds should be "-90,-180,90,180"                 # WebAPICucumberHooks.verifyIndexBounds(String,String,String)
    And the repo1 repository's "HEAD:Points" index should track the extra attribute "sp"               # WebAPICucumberHooks.verifyIndexExtraAttributes(String,String,String)
    And the repo1 repository's "HEAD:Points" index should not track the extra attribute "ip"           # WebAPICucumberHooks.verifyIndexNotExtraAttributes(String,String,String)
    And the repo1 repository's "HEAD:Points" index should have the following features:                 # WebAPICucumberHooks.verifyIndexContents(String,String,DataTable)
    When I call "POST /repos/repo1/index/update"                                                       # WebAPICucumberHooks.callURL(String)
    Then the xpath "/response/success/text()" equals "false"                                           # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xpath "/response/error/text()" equals "Required parameter 'treeRefSpec' was not provided." # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the response status should be '500'                                                            # WebAPICucumberHooks.checkStatusCode(int)
@RepositoryManagement @ListRepositories
Feature: List repositories
    In order to find out which repsitories are being served,
    As a Geogig Web API User,
    I want to get a list of available repositories

  Scenario: List repositories on a server with no repositories # ListRepositories.feature:7
    Given There is an empty multirepo server                   # WebAPICucumberHooks.setUpEmptyMultiRepo()
    When I call "GET /repos/"                                  # WebAPICucumberHooks.callURL(String)
    Then the response status should be '200'                   # WebAPICucumberHooks.checkStatusCode(int)
    And the response ContentType should be "application/xml"   # WebAPICucumberHooks.checkContentType(String)
    And the xml response should not contain "/repos/repo"      # WebAPICucumberHooks.responseDoesNotContainXPath(String)
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo2 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo1 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()

  Scenario: Get list of repositories in default format             # ListRepositories.feature:14
    Given There is a default multirepo server                      # WebAPICucumberHooks.setUpDefaultMultiRepo()
    When I call "GET /repos/"                                      # WebAPICucumberHooks.callURL(String)
    Then the response status should be '200'                       # WebAPICucumberHooks.checkStatusCode(int)
    And the response ContentType should be "application/xml"       # WebAPICucumberHooks.checkContentType(String)
    And the xml response should contain "/repos/repo/name" 2 times # WebAPICucumberHooks.checkXPathCadinality(String,int)

  Scenario: List repositories on a server with no repositories, JSON requested response # ListRepositories.feature:21
    Given There is an empty multirepo server                                            # WebAPICucumberHooks.setUpEmptyMultiRepo()
    When I call "GET /repos.json/"                                                      # WebAPICucumberHooks.callURL(String)
    Then the response status should be '200'                                            # WebAPICucumberHooks.checkStatusCode(int)
    And the response ContentType should be "application/json"                           # WebAPICucumberHooks.checkContentType(String)
    And the json response "repos" contains an empty "repo" array                        # WebAPICucumberHooks.checkJSONResponseContainsEmptyArray(String,String)
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo2 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo1 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()

  Scenario: Get list of repositories in default format, JSON requested response       # ListRepositories.feature:28
    Given There is a default multirepo server                                         # WebAPICucumberHooks.setUpDefaultMultiRepo()
    When I call "GET /repos.json/"                                                    # WebAPICucumberHooks.callURL(String)
    Then the response status should be '200'                                          # WebAPICucumberHooks.checkStatusCode(int)
    And the response ContentType should be "application/json"                         # WebAPICucumberHooks.checkContentType(String)
    And the json response "repos.repo" should contain "name" 2 times                  # WebAPICucumberHooks.checkJSONResponseContains(String,String,int)
    And the json response "repos.repo" should contain "href" 2 times                  # WebAPICucumberHooks.checkJSONResponseContains(String,String,int)
    And the json response "repos.repo" attribute "href" should each contain "/repos/" # WebAPICucumberHooks.checkJsonArrayContains(String,String,String)
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo2 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo1 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()

  Scenario: Get Repository info in JSON format                       # ListRepositories.feature:37
    Given There is a default multirepo server                        # WebAPICucumberHooks.setUpDefaultMultiRepo()
    When I call "GET /repos.json"                                    # WebAPICucumberHooks.callURL(String)
    Then the response status should be '200'                         # WebAPICucumberHooks.checkStatusCode(int)
    And the response ContentType should be "application/json"        # WebAPICucumberHooks.checkContentType(String)
    And the json response "repos.repo" should contain "href" 2 times # WebAPICucumberHooks.checkJSONResponseContains(String,String,int)
    Then I save the first href link from "repos.repo" as "@href"     # WebAPICucumberHooks.saveHrefLinkFromJSONResponse(String,String)
    When I call "GET {@href}"                                        # WebAPICucumberHooks.callURL(String)
    Then the response status should be '200'                         # WebAPICucumberHooks.checkStatusCode(int)
    And the response ContentType should be "application/json"        # WebAPICucumberHooks.checkContentType(String)
    And the json response "repository" should contain "name"         # WebAPICucumberHooks.checkJSONResponseContains(String,String)
    And the json response "repository" should contain "location"     # WebAPICucumberHooks.checkJSONResponseContains(String,String)
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo2 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo1 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()

  Scenario: Get Repository info in XML format                           # ListRepositories.feature:50
    Given There is a default multirepo server                           # WebAPICucumberHooks.setUpDefaultMultiRepo()
    When I call "GET /repos.xml"                                        # WebAPICucumberHooks.callURL(String)
    Then the response status should be '200'                            # WebAPICucumberHooks.checkStatusCode(int)
    And the response ContentType should be "application/xml"            # WebAPICucumberHooks.checkContentType(String)
    And the xml response should contain "/repos/repo/atom:link" 2 times # WebAPICucumberHooks.checkXPathCadinality(String,int)
@Commands @Log
Feature: Log
  The log command allows a user to view the commit log of a repo and is supported through the "/repos/{repository}/log" endpoint
  The command must be executed using the HTTP GET method
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo1 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()

  Scenario: Verify wrong HTTP method issues 405 "Method not allowed" # Log.feature:6
    Given There is an empty repository named repo1                   # WebAPICucumberHooks.setUpEmptyRepo(String)
    When I call "PUT /repos/repo1/log"                               # WebAPICucumberHooks.callURL(String)
    Then the response status should be '405'                         # WebAPICucumberHooks.checkStatusCode(int)
    And the response allowed methods should be "GET"                 # WebAPICucumberHooks.checkResponseAllowedMethods(String)
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo1 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()

  Scenario: Log outside of a repository issues 404 "Not found"  # Log.feature:12
    Given There is an empty multirepo server                    # WebAPICucumberHooks.setUpEmptyMultiRepo()
    When I call "GET /repos/repo1/log"                          # WebAPICucumberHooks.callURL(String)
    Then the response status should be '404'                    # WebAPICucumberHooks.checkStatusCode(int)
    And the response ContentType should be "text/plain"         # WebAPICucumberHooks.checkContentType(String)
    And the response body should contain "Repository not found" # WebAPICucumberHooks.checkResponseTextContains(String)
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo1 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo2 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()

  Scenario: Log will return the history of the current branch                                                # Log.feature:19
    Given There is a default multirepo server                                                                # WebAPICucumberHooks.setUpDefaultMultiRepo()
    When I call "GET /repos/repo1/log"                                                                       # WebAPICucumberHooks.callURL(String)
    Then the response status should be '200'                                                                 # WebAPICucumberHooks.checkStatusCode(int)
    And the xpath "/response/success/text()" equals "true"                                                   # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xml response should contain "/response/commit" 5 times                                           # WebAPICucumberHooks.checkXPathCadinality(String,int)
    And there is an xpath "/response/commit/id/text()" that equals "{@ObjectId|repo1|master}"                # WebAPICucumberHooks.checkOneXPathEquals(String,String)
    And there is an xpath "/response/commit/message/text()" that contains "merge branch branch2 onto master" # WebAPICucumberHooks.checkOneXPathValueContains(String,String)
    And there is an xpath "/response/commit/id/text()" that equals "{@ObjectId|repo1|master~1}"              # WebAPICucumberHooks.checkOneXPathEquals(String,String)
    And there is an xpath "/response/commit/message/text()" that contains "merge branch branch1 onto master" # WebAPICucumberHooks.checkOneXPathValueContains(String,String)
    And there is an xpath "/response/commit/id/text()" that equals "{@ObjectId|repo1|master~2}"              # WebAPICucumberHooks.checkOneXPathEquals(String,String)
    And there is an xpath "/response/commit/message/text()" that contains "point1, line1, poly1"             # WebAPICucumberHooks.checkOneXPathValueContains(String,String)
    And there is an xpath "/response/commit/id/text()" that equals "{@ObjectId|repo1|branch1}"               # WebAPICucumberHooks.checkOneXPathEquals(String,String)
    And there is an xpath "/response/commit/message/text()" that contains "point2, line2, poly2"             # WebAPICucumberHooks.checkOneXPathValueContains(String,String)
    And there is an xpath "/response/commit/id/text()" that equals "{@ObjectId|repo1|branch2}"               # WebAPICucumberHooks.checkOneXPathEquals(String,String)
    And there is an xpath "/response/commit/message/text()" that contains "point3, line3, poly3"             # WebAPICucumberHooks.checkOneXPathValueContains(String,String)
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo1 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo2 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()

  Scenario: The firstParentOnly parameter limits the log to the first parent of each commit                  # Log.feature:36
    Given There is a default multirepo server                                                                # WebAPICucumberHooks.setUpDefaultMultiRepo()
    When I call "GET /repos/repo1/log?firstParentOnly=true"                                                  # WebAPICucumberHooks.callURL(String)
    Then the response status should be '200'                                                                 # WebAPICucumberHooks.checkStatusCode(int)
    And the xpath "/response/success/text()" equals "true"                                                   # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xml response should contain "/response/commit" 3 times                                           # WebAPICucumberHooks.checkXPathCadinality(String,int)
    And there is an xpath "/response/commit/id/text()" that equals "{@ObjectId|repo1|master}"                # WebAPICucumberHooks.checkOneXPathEquals(String,String)
    And there is an xpath "/response/commit/message/text()" that contains "merge branch branch2 onto master" # WebAPICucumberHooks.checkOneXPathValueContains(String,String)
    And there is an xpath "/response/commit/id/text()" that equals "{@ObjectId|repo1|master~1}"              # WebAPICucumberHooks.checkOneXPathEquals(String,String)
    And there is an xpath "/response/commit/message/text()" that contains "merge branch branch1 onto master" # WebAPICucumberHooks.checkOneXPathValueContains(String,String)
    And there is an xpath "/response/commit/id/text()" that equals "{@ObjectId|repo1|master~2}"              # WebAPICucumberHooks.checkOneXPathEquals(String,String)
    And there is an xpath "/response/commit/message/text()" that contains "point1, line1, poly1"             # WebAPICucumberHooks.checkOneXPathValueContains(String,String)
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo1 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo2 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()

  Scenario: The offset parameter skips a number of log entries                                   # Log.feature:49
    Given There is a default multirepo server                                                    # WebAPICucumberHooks.setUpDefaultMultiRepo()
    When I call "GET /repos/repo1/log?offset=2"                                                  # WebAPICucumberHooks.callURL(String)
    Then the response status should be '200'                                                     # WebAPICucumberHooks.checkStatusCode(int)
    And the xpath "/response/success/text()" equals "true"                                       # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xml response should contain "/response/commit" 3 times                               # WebAPICucumberHooks.checkXPathCadinality(String,int)
    And there is an xpath "/response/commit/id/text()" that equals "{@ObjectId|repo1|master~2}"  # WebAPICucumberHooks.checkOneXPathEquals(String,String)
    And there is an xpath "/response/commit/message/text()" that contains "point1, line1, poly1" # WebAPICucumberHooks.checkOneXPathValueContains(String,String)
    And there is an xpath "/response/commit/id/text()" that equals "{@ObjectId|repo1|branch1}"   # WebAPICucumberHooks.checkOneXPathEquals(String,String)
    And there is an xpath "/response/commit/message/text()" that contains "point2, line2, poly2" # WebAPICucumberHooks.checkOneXPathValueContains(String,String)
    And there is an xpath "/response/commit/id/text()" that equals "{@ObjectId|repo1|branch2}"   # WebAPICucumberHooks.checkOneXPathEquals(String,String)
    And there is an xpath "/response/commit/message/text()" that contains "point3, line3, poly3" # WebAPICucumberHooks.checkOneXPathValueContains(String,String)
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo1 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo2 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()

  Scenario: The limit parameter limits the number of entries returned                                        # Log.feature:62
    Given There is a default multirepo server                                                                # WebAPICucumberHooks.setUpDefaultMultiRepo()
    When I call "GET /repos/repo1/log?limit=2"                                                               # WebAPICucumberHooks.callURL(String)
    Then the response status should be '200'                                                                 # WebAPICucumberHooks.checkStatusCode(int)
    And the xpath "/response/success/text()" equals "true"                                                   # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xml response should contain "/response/commit" 2 times                                           # WebAPICucumberHooks.checkXPathCadinality(String,int)
    And there is an xpath "/response/commit/id/text()" that equals "{@ObjectId|repo1|master}"                # WebAPICucumberHooks.checkOneXPathEquals(String,String)
    And there is an xpath "/response/commit/message/text()" that contains "merge branch branch2 onto master" # WebAPICucumberHooks.checkOneXPathValueContains(String,String)
    And there is an xpath "/response/commit/id/text()" that equals "{@ObjectId|repo1|master~1}"              # WebAPICucumberHooks.checkOneXPathEquals(String,String)
    And there is an xpath "/response/commit/message/text()" that contains "merge branch branch1 onto master" # WebAPICucumberHooks.checkOneXPathValueContains(String,String)
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo1 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo2 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()

  Scenario: The since parameter limits the log to commits that happened after it                             # Log.feature:73
    Given There is a default multirepo server                                                                # WebAPICucumberHooks.setUpDefaultMultiRepo()
    When I call "GET /repos/repo1/log?since=master~1"                                                        # WebAPICucumberHooks.callURL(String)
    Then the response status should be '200'                                                                 # WebAPICucumberHooks.checkStatusCode(int)
    And the xpath "/response/success/text()" equals "true"                                                   # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xml response should contain "/response/commit" 1 times                                           # WebAPICucumberHooks.checkXPathCadinality(String,int)
    And there is an xpath "/response/commit/id/text()" that equals "{@ObjectId|repo1|master}"                # WebAPICucumberHooks.checkOneXPathEquals(String,String)
    And there is an xpath "/response/commit/message/text()" that contains "merge branch branch2 onto master" # WebAPICucumberHooks.checkOneXPathValueContains(String,String)
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo1 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo2 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()

  Scenario: The until parameter limits the log to commits that happened before it                            # Log.feature:82
    Given There is a default multirepo server                                                                # WebAPICucumberHooks.setUpDefaultMultiRepo()
    When I call "GET /repos/repo1/log?until=master~1"                                                        # WebAPICucumberHooks.callURL(String)
    Then the response status should be '200'                                                                 # WebAPICucumberHooks.checkStatusCode(int)
    And the xpath "/response/success/text()" equals "true"                                                   # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xml response should contain "/response/commit" 3 times                                           # WebAPICucumberHooks.checkXPathCadinality(String,int)
    And there is an xpath "/response/commit/id/text()" that equals "{@ObjectId|repo1|master~1}"              # WebAPICucumberHooks.checkOneXPathEquals(String,String)
    And there is an xpath "/response/commit/message/text()" that contains "merge branch branch1 onto master" # WebAPICucumberHooks.checkOneXPathValueContains(String,String)
    And there is an xpath "/response/commit/id/text()" that equals "{@ObjectId|repo1|master~2}"              # WebAPICucumberHooks.checkOneXPathEquals(String,String)
    And there is an xpath "/response/commit/message/text()" that contains "point1, line1, poly1"             # WebAPICucumberHooks.checkOneXPathValueContains(String,String)
    And there is an xpath "/response/commit/id/text()" that equals "{@ObjectId|repo1|branch1}"               # WebAPICucumberHooks.checkOneXPathEquals(String,String)
    And there is an xpath "/response/commit/message/text()" that contains "point2, line2, poly2"             # WebAPICucumberHooks.checkOneXPathValueContains(String,String)
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo1 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo2 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()

  Scenario: The countChanges parameter counts the number of features affected by each commit    # Log.feature:95
    Given There is a default multirepo server                                                   # WebAPICucumberHooks.setUpDefaultMultiRepo()
    When I call "GET /repos/repo1/log?since=master~1&countChanges=true"                         # WebAPICucumberHooks.callURL(String)
    Then the response status should be '200'                                                    # WebAPICucumberHooks.checkStatusCode(int)
    And the xpath "/response/success/text()" equals "true"                                      # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xml response should contain "/response/commit" 1 times                              # WebAPICucumberHooks.checkXPathCadinality(String,int)
    And the xpath "/response/commit/id/text()" equals "{@ObjectId|repo1|master}"                # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xpath "/response/commit/message/text()" contains "merge branch branch2 onto master" # WebAPICucumberHooks.checkXPathValueContains(String,String)
    And the xpath "/response/commit/adds/text()" equals "3"                                     # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xpath "/response/commit/modifies/text()" equals "0"                                 # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xpath "/response/commit/removes/text()" equals "0"                                  # WebAPICucumberHooks.checkXPathEquals(String,String)
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo1 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo2 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()

  Scenario: The returnRange parameter returns the first and last commit as well as the number of commits in the range # Log.feature:107
    Given There is a default multirepo server                                                                         # WebAPICucumberHooks.setUpDefaultMultiRepo()
    When I call "GET /repos/repo1/log?returnRange=true"                                                               # WebAPICucumberHooks.callURL(String)
    Then the response status should be '200'                                                                          # WebAPICucumberHooks.checkStatusCode(int)
    And the xpath "/response/success/text()" equals "true"                                                            # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xpath "/response/untilCommit/id/text()" equals "{@ObjectId|repo1|master}"                                 # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xpath "/response/untilCommit/message/text()" contains "merge branch branch2 onto master"                  # WebAPICucumberHooks.checkXPathValueContains(String,String)
    And the xpath "/response/sinceCommit/id/text()" equals "{@ObjectId|repo1|master~2}"                               # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xpath "/response/sinceCommit/message/text()" contains "point1, line1, poly1"                              # WebAPICucumberHooks.checkXPathValueContains(String,String)
    And the xpath "/response/numCommits/text()" equals "5"                                                            # WebAPICucumberHooks.checkXPathEquals(String,String)
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo1 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()

  Scenario: The path parameter limits the log to commits that affected that path                # Log.feature:118
    Given There is an empty repository named repo1                                              # WebAPICucumberHooks.setUpEmptyRepo(String)
    And I have committed "Point.1" on the "repo1" repo in the "" transaction                    # WebAPICucumberHooks.I_have_committed(String,String,String)
    And I have committed "Line.2" on the "repo1" repo in the "" transaction                     # WebAPICucumberHooks.I_have_committed(String,String,String)
    And I have committed "Point.2" on the "repo1" repo in the "" transaction                    # WebAPICucumberHooks.I_have_committed(String,String,String)
    And I have committed "Polygon.1" on the "repo1" repo in the "" transaction                  # WebAPICucumberHooks.I_have_committed(String,String,String)
    And I have committed "Polygon.2" on the "repo1" repo in the "" transaction                  # WebAPICucumberHooks.I_have_committed(String,String,String)
    When I call "GET /repos/repo1/log?path=Points"                                              # WebAPICucumberHooks.callURL(String)
    Then the response status should be '200'                                                    # WebAPICucumberHooks.checkStatusCode(int)
    And the xpath "/response/success/text()" equals "true"                                      # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xml response should contain "/response/commit" 2 times                              # WebAPICucumberHooks.checkXPathCadinality(String,int)
    And there is an xpath "/response/commit/id/text()" that equals "{@ObjectId|repo1|master~2}" # WebAPICucumberHooks.checkOneXPathEquals(String,String)
    And there is an xpath "/response/commit/message/text()" that contains "Added Point.2"       # WebAPICucumberHooks.checkOneXPathValueContains(String,String)
    And there is an xpath "/response/commit/id/text()" that equals "{@ObjectId|repo1|master~4}" # WebAPICucumberHooks.checkOneXPathEquals(String,String)
    And there is an xpath "/response/commit/message/text()" that contains "Added Point.1"       # WebAPICucumberHooks.checkOneXPathValueContains(String,String)
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo1 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo2 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()

  Scenario: Using the summary parameter without a path issues a 500 status code                                  # Log.feature:134
    Given There is a default multirepo server                                                                    # WebAPICucumberHooks.setUpDefaultMultiRepo()
    When I call "GET /repos/repo1/log?summary=true"                                                              # WebAPICucumberHooks.callURL(String)
    Then the response status should be '500'                                                                     # WebAPICucumberHooks.checkStatusCode(int)
    And the xpath "/response/error/text()" equals "You must specify a feature type path when getting a summary." # WebAPICucumberHooks.checkXPathEquals(String,String)
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo1 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo2 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()

  Scenario: Using the summary parameter without using text/csv content type issues a 500 status code                        # Log.feature:140
    Given There is a default multirepo server                                                                               # WebAPICucumberHooks.setUpDefaultMultiRepo()
    When I call "GET /repos/repo1/log?path=Points&summary=true"                                                             # WebAPICucumberHooks.callURL(String)
    Then the response status should be '500'                                                                                # WebAPICucumberHooks.checkStatusCode(int)
    And the xpath "/response/error/text()" equals "Unsupported Media Type: This response is only compatible with text/csv." # WebAPICucumberHooks.checkXPathEquals(String,String)
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo1 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo2 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()

  Scenario: The summary parameter summarizes all of the changes to a feature type as a CSV # Log.feature:146
    Given There is a default multirepo server                                              # WebAPICucumberHooks.setUpDefaultMultiRepo()
    When I call "GET /repos/repo1/log.csv?since=master~1&path=Points&summary=true"         # WebAPICucumberHooks.callURL(String)
    Then the response status should be '200'                                               # WebAPICucumberHooks.checkStatusCode(int)
    And the response ContentType should be "text/csv"                                      # WebAPICucumberHooks.checkContentType(String)
    And the response body should contain "ADDED,Points/Point.3"                            # WebAPICucumberHooks.checkResponseTextContains(String)
    And the response body should contain "{@ObjectId|repo1|master}"                        # WebAPICucumberHooks.checkResponseTextContains(String)
    And the response body should not contain "ADDED,Points/Point.2"                        # WebAPICucumberHooks.checkResponseTextNotContains(String)
    And the response body should not contain "ADDED,Points/Point.1"                        # WebAPICucumberHooks.checkResponseTextNotContains(String)
    And the response body should not contain "Lines"                                       # WebAPICucumberHooks.checkResponseTextNotContains(String)
    And the response body should not contain "Polygons"                                    # WebAPICucumberHooks.checkResponseTextNotContains(String)
@Commands @LsTree
Feature: LsTree
  The LsTree command allows a user to view the contents of a tree in the repository and is supported through the "/repos/{repository}/ls-tree" endpoint
  The command must be executed using the HTTP GET method
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo1 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()

  Scenario: Verify wrong HTTP method issues 405 "Method not allowed" # LsTree.feature:6
    Given There is an empty repository named repo1                   # WebAPICucumberHooks.setUpEmptyRepo(String)
    When I call "PUT /repos/repo1/ls-tree"                           # WebAPICucumberHooks.callURL(String)
    Then the response status should be '405'                         # WebAPICucumberHooks.checkStatusCode(int)
    And the response allowed methods should be "GET"                 # WebAPICucumberHooks.checkResponseAllowedMethods(String)
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo1 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()

  Scenario: LsTree outside of a repository issues 404 "Not found" # LsTree.feature:12
    Given There is an empty multirepo server                      # WebAPICucumberHooks.setUpEmptyMultiRepo()
    When I call "GET /repos/repo1/ls-tree"                        # WebAPICucumberHooks.callURL(String)
    Then the response status should be '404'                      # WebAPICucumberHooks.checkStatusCode(int)
    And the response ContentType should be "text/plain"           # WebAPICucumberHooks.checkContentType(String)
    And the response body should contain "Repository not found"   # WebAPICucumberHooks.checkResponseTextContains(String)
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo1 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo2 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()

  Scenario: By default, LsTree lists the children of the root tree # LsTree.feature:19
    Given There is a default multirepo server                      # WebAPICucumberHooks.setUpDefaultMultiRepo()
    When I call "GET /repos/repo1/ls-tree"                         # WebAPICucumberHooks.callURL(String)
    Then the response status should be '200'                       # WebAPICucumberHooks.checkStatusCode(int)
    And the xpath "/response/success/text()" equals "true"         # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xml response should contain "/response/node" 3 times   # WebAPICucumberHooks.checkXPathCadinality(String,int)
    And the response body should contain "Points"                  # WebAPICucumberHooks.checkResponseTextContains(String)
    And the response body should contain "Lines"                   # WebAPICucumberHooks.checkResponseTextContains(String)
    And the response body should contain "Polygons"                # WebAPICucumberHooks.checkResponseTextContains(String)
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo1 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo2 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()

  Scenario: Supplying the onlyTree parameter to LsTree lists only trees # LsTree.feature:29
    Given There is a default multirepo server                           # WebAPICucumberHooks.setUpDefaultMultiRepo()
    When I call "GET /repos/repo1/ls-tree?onlyTree=true&recursive=true" # WebAPICucumberHooks.callURL(String)
    Then the response status should be '200'                            # WebAPICucumberHooks.checkStatusCode(int)
    And the xpath "/response/success/text()" equals "true"              # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xml response should contain "/response/node" 3 times        # WebAPICucumberHooks.checkXPathCadinality(String,int)
    And the response body should contain "Points"                       # WebAPICucumberHooks.checkResponseTextContains(String)
    And the response body should contain "Lines"                        # WebAPICucumberHooks.checkResponseTextContains(String)
    And the response body should contain "Polygons"                     # WebAPICucumberHooks.checkResponseTextContains(String)
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo1 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo2 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()

  Scenario: Supplying the recursive parameter to LsTree lists all features # LsTree.feature:39
    Given There is a default multirepo server                              # WebAPICucumberHooks.setUpDefaultMultiRepo()
    When I call "GET /repos/repo1/ls-tree?recursive=true"                  # WebAPICucumberHooks.callURL(String)
    Then the response status should be '200'                               # WebAPICucumberHooks.checkStatusCode(int)
    And the xpath "/response/success/text()" equals "true"                 # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xml response should contain "/response/node" 9 times           # WebAPICucumberHooks.checkXPathCadinality(String,int)
    And the response body should contain "Point.1"                         # WebAPICucumberHooks.checkResponseTextContains(String)
    And the response body should contain "Point.2"                         # WebAPICucumberHooks.checkResponseTextContains(String)
    And the response body should contain "Point.3"                         # WebAPICucumberHooks.checkResponseTextContains(String)
    And the response body should contain "Line.1"                          # WebAPICucumberHooks.checkResponseTextContains(String)
    And the response body should contain "Line.2"                          # WebAPICucumberHooks.checkResponseTextContains(String)
    And the response body should contain "Line.3"                          # WebAPICucumberHooks.checkResponseTextContains(String)
    And the response body should contain "Polygon.1"                       # WebAPICucumberHooks.checkResponseTextContains(String)
    And the response body should contain "Polygon.2"                       # WebAPICucumberHooks.checkResponseTextContains(String)
    And the response body should contain "Polygon.3"                       # WebAPICucumberHooks.checkResponseTextContains(String)
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo1 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo2 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()

  Scenario: Supplying both the recursive and showTree parameters lists all trees and features # LsTree.feature:55
    Given There is a default multirepo server                                                 # WebAPICucumberHooks.setUpDefaultMultiRepo()
    When I call "GET /repos/repo1/ls-tree?recursive=true&showTree=true"                       # WebAPICucumberHooks.callURL(String)
    Then the response status should be '200'                                                  # WebAPICucumberHooks.checkStatusCode(int)
    And the xpath "/response/success/text()" equals "true"                                    # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xml response should contain "/response/node" 12 times                             # WebAPICucumberHooks.checkXPathCadinality(String,int)
    And the response body should contain "Points"                                             # WebAPICucumberHooks.checkResponseTextContains(String)
    And the response body should contain "Lines"                                              # WebAPICucumberHooks.checkResponseTextContains(String)
    And the response body should contain "Polygons"                                           # WebAPICucumberHooks.checkResponseTextContains(String)
    And the response body should contain "Point.1"                                            # WebAPICucumberHooks.checkResponseTextContains(String)
    And the response body should contain "Point.2"                                            # WebAPICucumberHooks.checkResponseTextContains(String)
    And the response body should contain "Point.3"                                            # WebAPICucumberHooks.checkResponseTextContains(String)
    And the response body should contain "Line.1"                                             # WebAPICucumberHooks.checkResponseTextContains(String)
    And the response body should contain "Line.2"                                             # WebAPICucumberHooks.checkResponseTextContains(String)
    And the response body should contain "Line.3"                                             # WebAPICucumberHooks.checkResponseTextContains(String)
    And the response body should contain "Polygon.1"                                          # WebAPICucumberHooks.checkResponseTextContains(String)
    And the response body should contain "Polygon.2"                                          # WebAPICucumberHooks.checkResponseTextContains(String)
    And the response body should contain "Polygon.3"                                          # WebAPICucumberHooks.checkResponseTextContains(String)
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo1 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo2 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()

  Scenario: Providing a refspec lists the features of the tree it resolves to # LsTree.feature:74
    Given There is a default multirepo server                                 # WebAPICucumberHooks.setUpDefaultMultiRepo()
    When I call "GET /repos/repo1/ls-tree?recursive=true&path=branch1:Points" # WebAPICucumberHooks.callURL(String)
    Then the response status should be '200'                                  # WebAPICucumberHooks.checkStatusCode(int)
    And the xpath "/response/success/text()" equals "true"                    # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xml response should contain "/response/node" 2 times              # WebAPICucumberHooks.checkXPathCadinality(String,int)
    And the response body should contain "Point.1"                            # WebAPICucumberHooks.checkResponseTextContains(String)
    And the response body should contain "Point.2"                            # WebAPICucumberHooks.checkResponseTextContains(String)
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo1 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo2 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()

  Scenario: Supplying the verbose parameter lists more information about each node # LsTree.feature:83
    Given There is a default multirepo server                                      # WebAPICucumberHooks.setUpDefaultMultiRepo()
    When I call "GET /repos/repo1/ls-tree?verbose=true"                            # WebAPICucumberHooks.callURL(String)
    Then the response status should be '200'                                       # WebAPICucumberHooks.checkStatusCode(int)
    And the xpath "/response/success/text()" equals "true"                         # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xml response should contain "/response/node" 3 times                   # WebAPICucumberHooks.checkXPathCadinality(String,int)
    And the response body should contain "Points"                                  # WebAPICucumberHooks.checkResponseTextContains(String)
    And the response body should contain "{@PointsTypeID}"                         # WebAPICucumberHooks.checkResponseTextContains(String)
    And the response body should contain "{@ObjectId|repo1|master:Points}"         # WebAPICucumberHooks.checkResponseTextContains(String)
    And the response body should contain "Lines"                                   # WebAPICucumberHooks.checkResponseTextContains(String)
    And the response body should contain "{@LinesTypeID}"                          # WebAPICucumberHooks.checkResponseTextContains(String)
    And the response body should contain "{@ObjectId|repo1|master:Lines}"          # WebAPICucumberHooks.checkResponseTextContains(String)
    And the response body should contain "Polygons"                                # WebAPICucumberHooks.checkResponseTextContains(String)
    And the response body should contain "{@PolysTypeID}"                          # WebAPICucumberHooks.checkResponseTextContains(String)
    And the response body should contain "{@ObjectId|repo1|master:Polygons}"       # WebAPICucumberHooks.checkResponseTextContains(String)
@Repo @Manifest
Feature: Manifest
  The manifest resources provides a list of all the branches in the repository and is supported through the "/repos/{repository}/repo/manifest" endpoint
  The command must be executed using the HTTP GET method
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo1 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()

  Scenario: Verify wrong HTTP method issues 405 "Method not allowed" # Manifest.feature:6
    Given There is an empty repository named repo1                   # WebAPICucumberHooks.setUpEmptyRepo(String)
    When I call "PUT /repos/repo1/repo/manifest"                     # WebAPICucumberHooks.callURL(String)
    Then the response status should be '405'                         # WebAPICucumberHooks.checkStatusCode(int)
    And the response allowed methods should be "GET"                 # WebAPICucumberHooks.checkResponseAllowedMethods(String)
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo1 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo2 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()

  Scenario: Manifest lists all of the branches in the repository                           # Manifest.feature:12
    Given There is a default multirepo server                                              # WebAPICucumberHooks.setUpDefaultMultiRepo()
    When I call "GET /repos/repo1/repo/manifest"                                           # WebAPICucumberHooks.callURL(String)
    Then the response status should be '200'                                               # WebAPICucumberHooks.checkStatusCode(int)
    And the response ContentType should be "text/plain"                                    # WebAPICucumberHooks.checkContentType(String)
    And the response body should contain "HEAD refs/heads/master {@ObjectId|repo1|master}" # WebAPICucumberHooks.checkResponseTextContains(String)
    And the response body should contain "refs/heads/master {@ObjectId|repo1|master}"      # WebAPICucumberHooks.checkResponseTextContains(String)
    And the response body should contain "refs/heads/branch1 {@ObjectId|repo1|branch1}"    # WebAPICucumberHooks.checkResponseTextContains(String)
    And the response body should contain "refs/heads/branch2 {@ObjectId|repo1|branch2}"    # WebAPICucumberHooks.checkResponseTextContains(String)
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo2 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo1 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo4 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo3 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()

  Scenario: Manifest also lists remote branches when the remotes parameter is specified          # Manifest.feature:22
    Given There is a default multirepo server with remotes                                       # WebAPICucumberHooks.setUpDefaultMultiRepoWithRemotes()
    When I call "GET /repos/repo2/repo/manifest?remotes=true"                                    # WebAPICucumberHooks.callURL(String)
    Then the response status should be '200'                                                     # WebAPICucumberHooks.checkStatusCode(int)
    And the response ContentType should be "text/plain"                                          # WebAPICucumberHooks.checkContentType(String)
    And the response body should contain "HEAD refs/heads/master {@ObjectId|repo2|master}"       # WebAPICucumberHooks.checkResponseTextContains(String)
    And the response body should contain "refs/heads/master {@ObjectId|repo2|master}"            # WebAPICucumberHooks.checkResponseTextContains(String)
    And the response body should contain "refs/heads/branch1 {@ObjectId|repo2|branch1}"          # WebAPICucumberHooks.checkResponseTextContains(String)
    And the response body should contain "refs/heads/branch2 {@ObjectId|repo2|branch2}"          # WebAPICucumberHooks.checkResponseTextContains(String)
    And the response body should contain "refs/remotes/origin/HEAD {@ObjectId|repo1|master}"     # WebAPICucumberHooks.checkResponseTextContains(String)
    And the response body should contain "refs/remotes/origin/master {@ObjectId|repo1|master}"   # WebAPICucumberHooks.checkResponseTextContains(String)
    And the response body should contain "refs/remotes/origin/branch1 {@ObjectId|repo1|branch1}" # WebAPICucumberHooks.checkResponseTextContains(String)
    And the response body should contain "refs/remotes/origin/branch2 {@ObjectId|repo1|branch2}" # WebAPICucumberHooks.checkResponseTextContains(String)
@Commands @Merge
Feature: Merge
  The merge command allows a user to merge two branches and is supported through the "/repos/{repository}/merge" endpoint
  The command must be executed using the HTTP GET method
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo1 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()

  Scenario: Verify wrong HTTP method issues 405 "Method not allowed" # Merge.feature:6
    Given There is an empty repository named repo1                   # WebAPICucumberHooks.setUpEmptyRepo(String)
    When I call "PUT /repos/repo1/merge"                             # WebAPICucumberHooks.callURL(String)
    Then the response status should be '405'                         # WebAPICucumberHooks.checkStatusCode(int)
    And the response allowed methods should be "GET"                 # WebAPICucumberHooks.checkResponseAllowedMethods(String)
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo1 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()

  Scenario: Merge outside of a transaction issues 500 "Transaction required"       # Merge.feature:12
    Given There is an empty repository named repo1                                 # WebAPICucumberHooks.setUpEmptyRepo(String)
    When I call "GET /repos/repo1/merge?commit=branch1"                            # WebAPICucumberHooks.callURL(String)
    Then the response status should be '500'                                       # WebAPICucumberHooks.checkStatusCode(int)
    And the xpath "/response/error/text()" contains "No transaction was specified" # WebAPICucumberHooks.checkXPathValueContains(String,String)
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo1 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()

  Scenario: Merge outside of a repository issues 404 "Not found" # Merge.feature:18
    Given There is an empty multirepo server                     # WebAPICucumberHooks.setUpEmptyMultiRepo()
    When I call "GET /repos/repo1/merge?commit=branch1"          # WebAPICucumberHooks.callURL(String)
    Then the response status should be '404'                     # WebAPICucumberHooks.checkStatusCode(int)
    And the response ContentType should be "text/plain"          # WebAPICucumberHooks.checkContentType(String)
    And the response body should contain "Repository not found"  # WebAPICucumberHooks.checkResponseTextContains(String)
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo1 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()

  Scenario: Calling merge with no commit to merge issues a 500 status code                        # Merge.feature:25
    Given There is an empty repository named repo1                                                # WebAPICucumberHooks.setUpEmptyRepo(String)
    And I have a transaction as "@txId" on the "repo1" repo                                       # WebAPICucumberHooks.beginTransactionAsVariable(String,String)
    When I call "GET /repos/repo1/merge?transactionId={@txId}"                                    # WebAPICucumberHooks.callURL(String)
    Then the response status should be '500'                                                      # WebAPICucumberHooks.checkStatusCode(int)
    And the xpath "/response/error/text()" equals "Required parameter 'commit' was not provided." # WebAPICucumberHooks.checkXPathEquals(String,String)
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo1 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()

  Scenario: Merging two branches returns the details of the merge                                # Merge.feature:32
    Given There is a repository with multiple branches named repo1                               # WebAPICucumberHooks.setUpMultipleBranches(String)
    And I have a transaction as "@txId" on the "repo1" repo                                      # WebAPICucumberHooks.beginTransactionAsVariable(String,String)
    When I call "GET /repos/repo1/merge?transactionId={@txId}&commit=non_conflicting"            # WebAPICucumberHooks.callURL(String)
    Then the response status should be '200'                                                     # WebAPICucumberHooks.checkStatusCode(int)
    And the xpath "/response/success/text()" equals "true"                                       # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xpath "/response/Merge/ours/text()" equals "{@ObjectId|repo1|master_original}"       # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xpath "/response/Merge/theirs/text()" equals "{@ObjectId|repo1|non_conflicting}"     # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xpath "/response/Merge/ancestor/text()" equals "{@ObjectId|repo1|non_conflicting~1}" # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xpath "/response/Merge/mergedCommit/text()" equals "{@ObjectId|repo1|@txId|master}"  # WebAPICucumberHooks.checkXPathEquals(String,String)
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo1 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()

  Scenario: Supplying author information to merge is applied to the merge commit                                                          # Merge.feature:43
    Given There is a repository with multiple branches named repo1                                                                        # WebAPICucumberHooks.setUpMultipleBranches(String)
    And I have a transaction as "@txId" on the "repo1" repo                                                                               # WebAPICucumberHooks.beginTransactionAsVariable(String,String)
    When I call "GET /repos/repo1/merge?transactionId={@txId}&commit=non_conflicting&authorName=myAuthor&authorEmail=myAuthor@geogig.org" # WebAPICucumberHooks.callURL(String)
    Then the response status should be '200'                                                                                              # WebAPICucumberHooks.checkStatusCode(int)
    And the xpath "/response/success/text()" equals "true"                                                                                # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xpath "/response/Merge/ours/text()" equals "{@ObjectId|repo1|master_original}"                                                # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xpath "/response/Merge/theirs/text()" equals "{@ObjectId|repo1|non_conflicting}"                                              # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xpath "/response/Merge/ancestor/text()" equals "{@ObjectId|repo1|non_conflicting~1}"                                          # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xpath "/response/Merge/mergedCommit/text()" equals "{@ObjectId|repo1|@txId|master}"                                           # WebAPICucumberHooks.checkXPathEquals(String,String)
    When I call "GET /repos/repo1/cat?objectid={@ObjectId|repo1|@txId|master}"                                                            # WebAPICucumberHooks.callURL(String)
    Then the response status should be '200'                                                                                              # WebAPICucumberHooks.checkStatusCode(int)
    And the xpath "/response/success/text()" equals "true"                                                                                # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xpath "/response/commit/author/name/text()" equals "myAuthor"                                                                 # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xpath "/response/commit/author/email/text()" equals "myAuthor@geogig.org"                                                     # WebAPICucumberHooks.checkXPathEquals(String,String)
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo1 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()

  Scenario: Supplying the noCommit parameter prevents the merge commit from being created              # Merge.feature:59
    Given There is a repository with multiple branches named repo1                                     # WebAPICucumberHooks.setUpMultipleBranches(String)
    And I have a transaction as "@txId" on the "repo1" repo                                            # WebAPICucumberHooks.beginTransactionAsVariable(String,String)
    When I call "GET /repos/repo1/merge?transactionId={@txId}&commit=non_conflicting&noCommit=true"    # WebAPICucumberHooks.callURL(String)
    Then the response status should be '200'                                                           # WebAPICucumberHooks.checkStatusCode(int)
    And the xpath "/response/success/text()" equals "true"                                             # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xpath "/response/Merge/ours/text()" equals "{@ObjectId|repo1|master_original}"             # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xpath "/response/Merge/theirs/text()" equals "{@ObjectId|repo1|non_conflicting}"           # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xpath "/response/Merge/ancestor/text()" equals "{@ObjectId|repo1|non_conflicting~1}"       # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xpath "/response/Merge/mergedCommit/text()" equals "{@ObjectId|repo1|master_original}"     # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the variable "{@ObjectId|repo1|@txId|master}" equals "{@ObjectId|repo1|@txId|master_original}" # WebAPICucumberHooks.checkVariableEquals(String,String)
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo1 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()

  Scenario: Merging a conflicting branch returns details of the conflicts                                             # Merge.feature:71
    Given There is a repository with multiple branches named repo1                                                    # WebAPICucumberHooks.setUpMultipleBranches(String)
    And I have a transaction as "@txId" on the "repo1" repo                                                           # WebAPICucumberHooks.beginTransactionAsVariable(String,String)
    When I call "GET /repos/repo1/merge?transactionId={@txId}&commit=conflicting"                                     # WebAPICucumberHooks.callURL(String)
    Then the response status should be '200'                                                                          # WebAPICucumberHooks.checkStatusCode(int)
    And the xpath "/response/success/text()" equals "true"                                                            # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xpath "/response/Merge/ours/text()" equals "{@ObjectId|repo1|master_original}"                            # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xpath "/response/Merge/theirs/text()" equals "{@ObjectId|repo1|conflicting}"                              # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xpath "/response/Merge/ancestor/text()" equals "{@ObjectId|repo1|conflicting~1}"                          # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xpath "/response/Merge/conflicts/text()" equals "1"                                                       # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xpath "/response/Merge/Feature/change/text()" equals "CONFLICT"                                           # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xpath "/response/Merge/Feature/id/text()" equals "Points/Point.1"                                         # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xpath "/response/Merge/Feature/ourvalue/text()" equals "{@ObjectId|repo1|master_original:Points/Point.1}" # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xpath "/response/Merge/Feature/theirvalue/text()" equals "0000000000000000000000000000000000000000"       # WebAPICucumberHooks.checkXPathEquals(String,String)
@Repo @MergeFeature
Feature: MergeFeature
  The MergeFeature resource provides a method of merging two conflicting features and is supported through the "/repos/{repository}/repo/mergefeature" endpoint
  The command must be executed using the HTTP GET method
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo1 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()

  Scenario: Verify wrong HTTP method issues 405 "Method not allowed" # MergeFeature.feature:6
    Given There is an empty repository named repo1                   # WebAPICucumberHooks.setUpEmptyRepo(String)
    When I call "GET /repos/repo1/repo/mergefeature"                 # WebAPICucumberHooks.callURL(String)
    Then the response status should be '405'                         # WebAPICucumberHooks.checkStatusCode(int)
    And the response allowed methods should be "POST"                # WebAPICucumberHooks.checkResponseAllowedMethods(String)
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo1 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()

  Scenario: MergeFeature outside of a repository issues 404 "Not found" # MergeFeature.feature:12
    Given There is an empty multirepo server                            # WebAPICucumberHooks.setUpEmptyMultiRepo()
    When I call "POST /repos/repo1/repo/mergefeature"                   # WebAPICucumberHooks.callURL(String)
    Then the response status should be '404'                            # WebAPICucumberHooks.checkStatusCode(int)
    And the response ContentType should be "text/plain"                 # WebAPICucumberHooks.checkContentType(String)
    And the response body should contain "Repository not found"         # WebAPICucumberHooks.checkResponseTextContains(String)
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo1 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()

  Scenario: MergeFeature with no json payload issues a 400 status code # MergeFeature.feature:19
    Given There is an empty repository named repo1                     # WebAPICucumberHooks.setUpEmptyRepo(String)
    When I call "POST /repos/repo1/repo/mergefeature"                  # WebAPICucumberHooks.callURL(String)
    Then the response status should be '400'                           # WebAPICucumberHooks.checkStatusCode(int)
    And the response body should contain "Invalid POST data."          # WebAPICucumberHooks.checkResponseTextContains(String)
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo1 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()

  Scenario: MergeFeature with an invalid json payload issues a 400 status code       # MergeFeature.feature:25
    Given There is an empty repository named repo1                                   # WebAPICucumberHooks.setUpEmptyRepo(String)
    When I "POST" content-type "text/plain" to "/repos/repo1/repo/mergefeature" with # WebAPICucumberHooks.requestWithContent(String,String,String,String)
      """
      "unexpected format"
      """
    Then the response status should be '400'                                         # WebAPICucumberHooks.checkStatusCode(int)
    And the response body should contain "Invalid POST data."                        # WebAPICucumberHooks.checkResponseTextContains(String)
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo1 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()

  Scenario: MergeFeature without a feature issues a 400 status code                        # MergeFeature.feature:34
    Given There is an empty repository named repo1                                         # WebAPICucumberHooks.setUpEmptyRepo(String)
    When I "POST" content-type "application/json" to "/repos/repo1/repo/mergefeature" with # WebAPICucumberHooks.requestWithContent(String,String,String,String)
      """
      {}
      """
    Then the response status should be '400'                                               # WebAPICucumberHooks.checkStatusCode(int)
    And the response body should contain "Invalid POST data."                              # WebAPICucumberHooks.checkResponseTextContains(String)
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo1 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()

  Scenario: MergeFeature without an "ours" id issues a 400 status code                     # MergeFeature.feature:43
    Given There is an empty repository named repo1                                         # WebAPICucumberHooks.setUpEmptyRepo(String)
    When I "POST" content-type "application/json" to "/repos/repo1/repo/mergefeature" with # WebAPICucumberHooks.requestWithContent(String,String,String,String)
      """
      {
        "path"="Points/Point.1"
      }
      """
    Then the response status should be '400'                                               # WebAPICucumberHooks.checkStatusCode(int)
    And the response body should contain "Invalid POST data."                              # WebAPICucumberHooks.checkResponseTextContains(String)
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo1 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo2 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()

  Scenario: MergeFeature without a "theirs" id issues a 400 status code                    # MergeFeature.feature:54
    Given There is a default multirepo server                                              # WebAPICucumberHooks.setUpDefaultMultiRepo()
    When I "POST" content-type "application/json" to "/repos/repo1/repo/mergefeature" with # WebAPICucumberHooks.requestWithContent(String,String,String,String)
      """
      {
        "path"="Points/Point.1",
        "ours"="{@ObjectId|repo1|master}"
      }
      """
    Then the response status should be '400'                                               # WebAPICucumberHooks.checkStatusCode(int)
    And the response body should contain "Invalid POST data."                              # WebAPICucumberHooks.checkResponseTextContains(String)
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo1 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo2 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()

  Scenario: MergeFeature without any merges issues a 400 status code                       # MergeFeature.feature:66
    Given There is a default multirepo server                                              # WebAPICucumberHooks.setUpDefaultMultiRepo()
    When I "POST" content-type "application/json" to "/repos/repo1/repo/mergefeature" with # WebAPICucumberHooks.requestWithContent(String,String,String,String)
      """
      {
        "path"="Points/Point.1",
        "ours"="{@ObjectId|repo1|master}",
        "theirs"="{@ObjectId|repo1|branch1}"
      }
      """
    Then the response status should be '400'                                               # WebAPICucumberHooks.checkStatusCode(int)
    And the response body should contain "Invalid POST data."                              # WebAPICucumberHooks.checkResponseTextContains(String)
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo1 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo2 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()

  Scenario: MergeFeature builds a new feature from provided merges using ours and theirs (both features are the same) # MergeFeature.feature:79
    Given There is a default multirepo server                                                                         # WebAPICucumberHooks.setUpDefaultMultiRepo()
    When I "POST" content-type "application/json" to "/repos/repo1/repo/mergefeature" with                            # WebAPICucumberHooks.requestWithContent(String,String,String,String)
      """
      {
        "path"="Points/Point.1",
        "ours"="{@ObjectId|repo1|master}",
        "theirs"="{@ObjectId|repo1|branch1}",
        "merges"={
          "ip"={"ours"=true},
          "sp"={"theirs"=true},
          "geom"={"ours"=true}
        }
      }
      """
    Then the response status should be '200'                                                                          # WebAPICucumberHooks.checkStatusCode(int)
    And the response body should contain "{@ObjectId|repo1|master:Points/Point.1}"                                    # WebAPICucumberHooks.checkResponseTextContains(String)
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo1 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo2 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()

  Scenario: MergeFeature builds a new feature from provided merges with custom values (both features are the same) # MergeFeature.feature:97
    Given There is a default multirepo server                                                                      # WebAPICucumberHooks.setUpDefaultMultiRepo()
    When I "POST" content-type "application/json" to "/repos/repo1/repo/mergefeature" with                         # WebAPICucumberHooks.requestWithContent(String,String,String,String)
      """
      {
        "path"="Points/Point.1",
        "ours"="{@ObjectId|repo1|master}",
        "theirs"="{@ObjectId|repo1|branch1}",
        "merges"={
          "ip"={"value"=500},
          "sp"={"value"="new"},
          "geom"={"value"="POINT (1 1)"}
        }
      }
      """
    Then the response status should be '200'                                                                       # WebAPICucumberHooks.checkStatusCode(int)
    And the response body should not contain "{@ObjectId|repo1|master:Points/Point.1}"                             # WebAPICucumberHooks.checkResponseTextNotContains(String)
    And the response body should not contain "{@ObjectId|repo1|branch1:Points/Point.1}"                            # WebAPICucumberHooks.checkResponseTextNotContains(String)
    And I save the response as "@featureId"                                                                        # WebAPICucumberHooks.saveResponseAsVariable(String)
    When I call "GET /repos/repo1/cat?objectid={@featureId}"                                                       # WebAPICucumberHooks.callURL(String)
    Then the response status should be '200'                                                                       # WebAPICucumberHooks.checkStatusCode(int)
    And the xpath "/response/success/text()" equals "true"                                                         # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xpath "/response/feature/id/text()" equals "{@featureId}"                                              # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xml response should contain "/response/feature/attribute" 3 times                                      # WebAPICucumberHooks.checkXPathCadinality(String,int)
    And the response body should contain "new"                                                                     # WebAPICucumberHooks.checkResponseTextContains(String)
    And the response body should contain "500"                                                                     # WebAPICucumberHooks.checkResponseTextContains(String)
    And the response body should contain "POINT (1 1)"                                                             # WebAPICucumberHooks.checkResponseTextContains(String)
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo1 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo2 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()

  Scenario: MergeFeature builds a new feature from provided merges (different versions of the same feature) # MergeFeature.feature:125
    Given There is a default multirepo server                                                               # WebAPICucumberHooks.setUpDefaultMultiRepo()
    And I have committed "Point.1_modified" on the "repo1" repo in the "" transaction                       # WebAPICucumberHooks.I_have_committed(String,String,String)
    When I "POST" content-type "application/json" to "/repos/repo1/repo/mergefeature" with                  # WebAPICucumberHooks.requestWithContent(String,String,String,String)
      """
      {
        "path"="Points/Point.1",
        "ours"="{@ObjectId|repo1|master}",
        "theirs"="{@ObjectId|repo1|branch1}",
        "merges"={
          "ip"={"ours"=true},
          "sp"={"theirs"=true},
          "geom"={"value"="POINT (1 1)"}
        }
      }
      """
    Then the response status should be '200'                                                                # WebAPICucumberHooks.checkStatusCode(int)
    And the response body should not contain "{@ObjectId|repo1|master:Points/Point.1}"                      # WebAPICucumberHooks.checkResponseTextNotContains(String)
    And the response body should not contain "{@ObjectId|repo1|branch1:Points/Point.1}"                     # WebAPICucumberHooks.checkResponseTextNotContains(String)
    And I save the response as "@featureId"                                                                 # WebAPICucumberHooks.saveResponseAsVariable(String)
    When I call "GET /repos/repo1/cat?objectid={@featureId}"                                                # WebAPICucumberHooks.callURL(String)
    Then the response status should be '200'                                                                # WebAPICucumberHooks.checkStatusCode(int)
    And the xpath "/response/success/text()" equals "true"                                                  # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xpath "/response/feature/id/text()" equals "{@featureId}"                                       # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xml response should contain "/response/feature/attribute" 3 times                               # WebAPICucumberHooks.checkXPathCadinality(String,int)
    And the response body should contain "1500"                                                             # WebAPICucumberHooks.checkResponseTextContains(String)
    And the response body should contain "StringProp1_1"                                                    # WebAPICucumberHooks.checkResponseTextContains(String)
    And the response body should contain "POINT (1 1)"                                                      # WebAPICucumberHooks.checkResponseTextContains(String)
@Repo @ObjectExists
Feature: ObjectExists
  The ObjectExists resource is used to determine if an objectId exists in the repository and is supported through the "/repos/{repository}/repo/exists" endpoint
  The command must be executed using the HTTP GET method
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo1 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()

  Scenario: Verify wrong HTTP method issues 405 "Method not allowed" # ObjectExists.feature:6
    Given There is an empty repository named repo1                   # WebAPICucumberHooks.setUpEmptyRepo(String)
    When I call "PUT /repos/repo1/repo/exists"                       # WebAPICucumberHooks.callURL(String)
    Then the response status should be '405'                         # WebAPICucumberHooks.checkStatusCode(int)
    And the response allowed methods should be "GET"                 # WebAPICucumberHooks.checkResponseAllowedMethods(String)
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo1 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()

  Scenario: ObjectExists outside of a repository issues 404 "Not found" # ObjectExists.feature:12
    Given There is an empty multirepo server                            # WebAPICucumberHooks.setUpEmptyMultiRepo()
    When I call "GET /repos/repo1/repo/exists"                          # WebAPICucumberHooks.callURL(String)
    Then the response status should be '404'                            # WebAPICucumberHooks.checkStatusCode(int)
    And the response ContentType should be "text/plain"                 # WebAPICucumberHooks.checkContentType(String)
    And the response body should contain "Repository not found"         # WebAPICucumberHooks.checkResponseTextContains(String)
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo1 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()

  Scenario: ObjectExists with no object id issues a 400 status code       # ObjectExists.feature:19
    Given There is an empty repository named repo1                        # WebAPICucumberHooks.setUpEmptyRepo(String)
    When I call "GET /repos/repo1/repo/exists"                            # WebAPICucumberHooks.callURL(String)
    Then the response status should be '400'                              # WebAPICucumberHooks.checkStatusCode(int)
    And the response body should contain "You must specify an object id." # WebAPICucumberHooks.checkResponseTextContains(String)
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo1 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()

  Scenario: ObjectExists with an invalid object id issues a 400 status code    # ObjectExists.feature:25
    Given There is an empty repository named repo1                             # WebAPICucumberHooks.setUpEmptyRepo(String)
    When I call "GET /repos/repo1/repo/exists?oid=invalid"                     # WebAPICucumberHooks.callURL(String)
    Then the response status should be '400'                                   # WebAPICucumberHooks.checkStatusCode(int)
    And the response body should contain "You must specify a valid object id." # WebAPICucumberHooks.checkResponseTextContains(String)
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo1 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo2 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()

  Scenario: ObjectExists with a nonexistent object id returns "0"                           # ObjectExists.feature:31
    Given There is a default multirepo server                                               # WebAPICucumberHooks.setUpDefaultMultiRepo()
    When I call "GET /repos/repo1/repo/exists?oid=0123456789012345678901234567890123456789" # WebAPICucumberHooks.callURL(String)
    Then the response status should be '200'                                                # WebAPICucumberHooks.checkStatusCode(int)
    And the response ContentType should be "text/plain"                                     # WebAPICucumberHooks.checkContentType(String)
    And the response body should contain "0"                                                # WebAPICucumberHooks.checkResponseTextContains(String)
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo1 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo2 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()

  Scenario: ObjectExists with an existing object id returns "1"                            # ObjectExists.feature:38
    Given There is a default multirepo server                                              # WebAPICucumberHooks.setUpDefaultMultiRepo()
    When I call "GET /repos/repo1/repo/exists?oid={@ObjectId|repo1|master:Points/Point.1}" # WebAPICucumberHooks.callURL(String)
    Then the response status should be '200'                                               # WebAPICucumberHooks.checkStatusCode(int)
    And the response ContentType should be "text/plain"                                    # WebAPICucumberHooks.checkContentType(String)
    And the response body should contain "1"                                               # WebAPICucumberHooks.checkResponseTextContains(String)
@Repo @Parents
Feature: Parents
  The Parents resource returns the parents of a specific commit and is supported through the "/repos/{repository}/repo/getparents" endpoint
  The command must be executed using the HTTP GET method
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo1 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()

  Scenario: Verify wrong HTTP method issues 405 "Method not allowed" # Parents.feature:6
    Given There is an empty repository named repo1                   # WebAPICucumberHooks.setUpEmptyRepo(String)
    When I call "PUT /repos/repo1/repo/getparents"                   # WebAPICucumberHooks.callURL(String)
    Then the response status should be '405'                         # WebAPICucumberHooks.checkStatusCode(int)
    And the response allowed methods should be "GET"                 # WebAPICucumberHooks.checkResponseAllowedMethods(String)
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo1 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()

  Scenario: Parents outside of a repository issues 404 "Not found" # Parents.feature:12
    Given There is an empty multirepo server                       # WebAPICucumberHooks.setUpEmptyMultiRepo()
    When I call "GET /repos/repo1/repo/getparents"                 # WebAPICucumberHooks.callURL(String)
    Then the response status should be '404'                       # WebAPICucumberHooks.checkStatusCode(int)
    And the response ContentType should be "text/plain"            # WebAPICucumberHooks.checkContentType(String)
    And the response body should contain "Repository not found"    # WebAPICucumberHooks.checkResponseTextContains(String)
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo1 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo2 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()

  Scenario: Parents with an invalid commit issues a 400 status code            # Parents.feature:19
    Given There is a default multirepo server                                  # WebAPICucumberHooks.setUpDefaultMultiRepo()
    When I call "GET /repos/repo1/repo/getparents?commitId=invalid"            # WebAPICucumberHooks.callURL(String)
    Then the response status should be '400'                                   # WebAPICucumberHooks.checkStatusCode(int)
    And the response ContentType should be "text/plain"                        # WebAPICucumberHooks.checkContentType(String)
    And the response body should contain "You must specify a valid commit id." # WebAPICucumberHooks.checkResponseTextContains(String)
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo1 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo2 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()

  Scenario: Parents with no commit returns no parents   # Parents.feature:26
    Given There is a default multirepo server           # WebAPICucumberHooks.setUpDefaultMultiRepo()
    When I call "GET /repos/repo1/repo/getparents"      # WebAPICucumberHooks.callURL(String)
    Then the response status should be '200'            # WebAPICucumberHooks.checkStatusCode(int)
    And the response ContentType should be "text/plain" # WebAPICucumberHooks.checkContentType(String)
    And the response body should contain ""             # WebAPICucumberHooks.checkResponseTextContains(String)
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo1 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo2 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()

  Scenario: Parents with a commit returns the parents of that commit                 # Parents.feature:33
    Given There is a default multirepo server                                        # WebAPICucumberHooks.setUpDefaultMultiRepo()
    When I call "GET /repos/repo1/repo/getparents?commitId={@ObjectId|repo1|master}" # WebAPICucumberHooks.callURL(String)
    Then the response status should be '200'                                         # WebAPICucumberHooks.checkStatusCode(int)
    And the response ContentType should be "text/plain"                              # WebAPICucumberHooks.checkContentType(String)
    And the response body should contain "{@ObjectId|repo1|master~1}"                # WebAPICucumberHooks.checkResponseTextContains(String)
    And the response body should contain "{@ObjectId|repo1|branch2}"                 # WebAPICucumberHooks.checkResponseTextContains(String)
@Commands @Pull
Feature: Pull
  The pull command allows a user to merge a remote branch into a local one and is supported through the "/repos/{repository}/pull" endpoint
  The command must be executed using the HTTP GET method
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo1 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()

  Scenario: Verify wrong HTTP method issues 405 "Method not allowed" # Pull.feature:6
    Given There is an empty repository named repo1                   # WebAPICucumberHooks.setUpEmptyRepo(String)
    When I call "PUT /repos/repo1/pull"                              # WebAPICucumberHooks.callURL(String)
    Then the response status should be '405'                         # WebAPICucumberHooks.checkStatusCode(int)
    And the response allowed methods should be "GET"                 # WebAPICucumberHooks.checkResponseAllowedMethods(String)
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo1 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()

  Scenario: Pull outside of a repository issues 404 "Not found" # Pull.feature:12
    Given There is an empty multirepo server                    # WebAPICucumberHooks.setUpEmptyMultiRepo()
    When I call "GET /repos/repo1/pull"                         # WebAPICucumberHooks.callURL(String)
    Then the response status should be '404'                    # WebAPICucumberHooks.checkStatusCode(int)
    And the response ContentType should be "text/plain"         # WebAPICucumberHooks.checkContentType(String)
    And the response body should contain "Repository not found" # WebAPICucumberHooks.checkResponseTextContains(String)
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo4 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo1 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo2 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo3 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()

  Scenario: Pulling from a remote with remote changes updates the local ref                    # Pull.feature:19
    Given There is a default multirepo server with remotes                                     # WebAPICucumberHooks.setUpDefaultMultiRepoWithRemotes()
    And the variable "{@ObjectId|repo4|master}" equals "{@ObjectId|repo1|master~2}"            # WebAPICucumberHooks.checkVariableEquals(String,String)
    When I call "GET /repos/repo4/pull?remoteName=origin&ref=master"                           # WebAPICucumberHooks.callURL(String)
    Then the response status should be '200'                                                   # WebAPICucumberHooks.checkStatusCode(int)
    And the xpath "/response/success/text()" equals "true"                                     # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xpath "/response/Pull/Merge/ours/text()" equals "{@ObjectId|repo1|master~2}"       # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xpath "/response/Pull/Merge/theirs/text()" equals "{@ObjectId|repo1|master}"       # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xpath "/response/Pull/Merge/ancestor/text()" equals "{@ObjectId|repo1|master~2}"   # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xpath "/response/Pull/Merge/mergedCommit/text()" equals "{@ObjectId|repo1|master}" # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xpath "/response/Pull/Added/text()" equals "6"                                     # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xpath "/response/Pull/Modified/text()" equals "0"                                  # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xpath "/response/Pull/Removed/text()" equals "0"                                   # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the variable "{@ObjectId|repo4|master}" equals "{@ObjectId|repo1|master}"              # WebAPICucumberHooks.checkVariableEquals(String,String)
[main] INFO org.mortbay.log - jetty-6.1.5
[main] INFO org.mortbay.log - Started SelectChannelConnector@0.0.0.0:8182
[main] INFO org.locationtech.geogig.plumbing.CreateDeduplicator - No DeduplicationService service found, using default heap based one
[btpool6-1] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo1 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.plumbing.CreateDeduplicator - No DeduplicationService service found, using default heap based one
[main] INFO org.locationtech.geogig.plumbing.CreateDeduplicator - No DeduplicationService service found, using default heap based one
[btpool6-1] INFO org.locationtech.geogig.rest.repository.BatchedObjectResource - Serving request to send objects based on message {"want":["7e9da76b02617010e0a358706a0235d8ad1158e0","f82711cd2664a411875beb61c8d2d856e4457fe4"],"have":[]}
[btpool6-1] INFO org.locationtech.geogig.plumbing.CreateDeduplicator - No DeduplicationService service found, using default heap based one
[btpool6-1] INFO org.locationtech.geogig.remote.BinaryPackedObjects - scanning for previsit list...
[btpool6-1] INFO org.locationtech.geogig.remote.BinaryPackedObjects - Previsit list built in 2.596 μs for 0 ids: []. Calculating reachable content ids...
[btpool6-1] INFO org.locationtech.geogig.remote.BinaryPackedObjects - reachableContentIds took 17.56 μs for 0 ids
[btpool6-1] INFO org.locationtech.geogig.remote.BinaryPackedObjects - obtaining post order iterator on range...
[btpool6-1] INFO org.locationtech.geogig.remote.BinaryPackedObjects - PostOrderIterator.range took 7.823 μs
[btpool6-1] INFO org.locationtech.geogig.remote.BinaryPackedObjects - writing objects to remote...
[main] INFO org.locationtech.geogig.remote.HttpRemoteRepo - Processed 19 objects. Inserted: 19. Existing: 0. Time: 3.999 ms. Compressed size: 988 bytes. Uncompressed size: 3,179 bytes.
[btpool6-1] INFO org.locationtech.geogig.rest.repository.BatchedObjectResource - Serving request to send objects based on message {"want":["143086ed135ce7f3161dbfb1ec159c29b89628e9"],"have":["7e9da76b02617010e0a358706a0235d8ad1158e0"]}
[btpool6-1] INFO org.locationtech.geogig.plumbing.CreateDeduplicator - No DeduplicationService service found, using default heap based one
[btpool6-1] INFO org.locationtech.geogig.remote.BinaryPackedObjects - scanning for previsit list...
[btpool6-1] INFO org.locationtech.geogig.remote.BinaryPackedObjects - Previsit list built in 2.249 μs for 1 ids: [7e9da76b02617010e0a358706a0235d8ad1158e0]. Calculating reachable content ids...
[btpool6-1] INFO org.locationtech.geogig.remote.BinaryPackedObjects - reachableContentIds took 398.5 μs for 11 ids
[btpool6-1] INFO org.locationtech.geogig.remote.BinaryPackedObjects - obtaining post order iterator on range...
[btpool6-1] INFO org.locationtech.geogig.remote.BinaryPackedObjects - PostOrderIterator.range took 9.085 μs
[btpool6-1] INFO org.locationtech.geogig.remote.BinaryPackedObjects - writing objects to remote...
[main] INFO org.locationtech.geogig.remote.HttpRemoteRepo - Processed 8 objects. Inserted: 8. Existing: 0. Time: 1.193 ms. Compressed size: 656 bytes. Uncompressed size: 1,488 bytes.
[btpool6-1] INFO org.locationtech.geogig.rest.repository.BatchedObjectResource - Serving request to send objects based on message {"want":["0819391c3f80996f380df94cf6062f81e1a41a42","577734737e2a139a5057eb7aa0fb1af76b2ccd7f"],"have":["143086ed135ce7f3161dbfb1ec159c29b89628e9","7e9da76b02617010e0a358706a0235d8ad1158e0","f82711cd2664a411875beb61c8d2d856e4457fe4"]}
[btpool6-1] INFO org.locationtech.geogig.plumbing.CreateDeduplicator - No DeduplicationService service found, using default heap based one
[btpool6-1] INFO org.locationtech.geogig.remote.BinaryPackedObjects - scanning for previsit list...
[btpool6-1] INFO org.locationtech.geogig.remote.BinaryPackedObjects - Previsit list built in 2.497 μs for 3 ids: [143086ed135ce7f3161dbfb1ec159c29b89628e9, 7e9da76b02617010e0a358706a0235d8ad1158e0, f82711cd2664a411875beb61c8d2d856e4457fe4]. Calculating reachable content ids...
[btpool6-1] INFO org.locationtech.geogig.remote.BinaryPackedObjects - reachableContentIds took 616.4 μs for 27 ids
[btpool6-1] INFO org.locationtech.geogig.remote.BinaryPackedObjects - obtaining post order iterator on range...
[btpool6-1] INFO org.locationtech.geogig.remote.BinaryPackedObjects - PostOrderIterator.range took 10.41 μs
[btpool6-1] INFO org.locationtech.geogig.remote.BinaryPackedObjects - writing objects to remote...
[main] INFO org.locationtech.geogig.remote.HttpRemoteRepo - Processed 6 objects. Inserted: 6. Existing: 0. Time: 1.132 ms. Compressed size: 776 bytes. Uncompressed size: 1,673 bytes.
[main] INFO org.locationtech.geogig.plumbing.CreateDeduplicator - No DeduplicationService service found, using default heap based one
[main] INFO org.locationtech.geogig.plumbing.CreateDeduplicator - No DeduplicationService service found, using default heap based one
[main] INFO org.locationtech.geogig.plumbing.CreateDeduplicator - No DeduplicationService service found, using default heap based one
[main] INFO org.locationtech.geogig.plumbing.CreateDeduplicator - No DeduplicationService service found, using default heap based one
[btpool6-1] INFO org.locationtech.geogig.rest.repository.BatchedObjectResource - Serving request to send objects based on message {"want":["7e9da76b02617010e0a358706a0235d8ad1158e0","f82711cd2664a411875beb61c8d2d856e4457fe4"],"have":[]}
[btpool6-1] INFO org.locationtech.geogig.plumbing.CreateDeduplicator - No DeduplicationService service found, using default heap based one
[btpool6-1] INFO org.locationtech.geogig.remote.BinaryPackedObjects - scanning for previsit list...
[btpool6-1] INFO org.locationtech.geogig.remote.BinaryPackedObjects - Previsit list built in 14.20 μs for 0 ids: []. Calculating reachable content ids...
[btpool6-1] INFO org.locationtech.geogig.remote.BinaryPackedObjects - reachableContentIds took 13.87 μs for 0 ids
[btpool6-1] INFO org.locationtech.geogig.remote.BinaryPackedObjects - obtaining post order iterator on range...
[btpool6-1] INFO org.locationtech.geogig.remote.BinaryPackedObjects - PostOrderIterator.range took 7.713 μs
[btpool6-1] INFO org.locationtech.geogig.remote.BinaryPackedObjects - writing objects to remote...
[main] INFO org.locationtech.geogig.remote.HttpRemoteRepo - Processed 19 objects. Inserted: 19. Existing: 0. Time: 3.300 ms. Compressed size: 988 bytes. Uncompressed size: 3,179 bytes.
[btpool6-1] INFO org.locationtech.geogig.rest.repository.BatchedObjectResource - Serving request to send objects based on message {"want":["143086ed135ce7f3161dbfb1ec159c29b89628e9","0819391c3f80996f380df94cf6062f81e1a41a42","577734737e2a139a5057eb7aa0fb1af76b2ccd7f"],"have":["f82711cd2664a411875beb61c8d2d856e4457fe4","7e9da76b02617010e0a358706a0235d8ad1158e0"]}
[btpool6-1] INFO org.locationtech.geogig.plumbing.CreateDeduplicator - No DeduplicationService service found, using default heap based one
[btpool6-1] INFO org.locationtech.geogig.remote.BinaryPackedObjects - scanning for previsit list...
[btpool6-1] INFO org.locationtech.geogig.remote.BinaryPackedObjects - Previsit list built in 2.306 μs for 2 ids: [f82711cd2664a411875beb61c8d2d856e4457fe4, 7e9da76b02617010e0a358706a0235d8ad1158e0]. Calculating reachable content ids...
[btpool6-1] INFO org.locationtech.geogig.remote.BinaryPackedObjects - reachableContentIds took 480.2 μs for 19 ids
[btpool6-1] INFO org.locationtech.geogig.remote.BinaryPackedObjects - obtaining post order iterator on range...
[btpool6-1] INFO org.locationtech.geogig.remote.BinaryPackedObjects - PostOrderIterator.range took 10.08 μs
[btpool6-1] INFO org.locationtech.geogig.remote.BinaryPackedObjects - writing objects to remote...
[main] INFO org.locationtech.geogig.remote.HttpRemoteRepo - Processed 14 objects. Inserted: 14. Existing: 0. Time: 2.490 ms. Compressed size: 1,064 bytes. Uncompressed size: 3,161 bytes.
[main] INFO org.locationtech.geogig.plumbing.CreateDeduplicator - No DeduplicationService service found, using default heap based one
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo4 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.plumbing.CreateDeduplicator - No DeduplicationService service found, using default heap based one
[main] INFO org.locationtech.geogig.plumbing.CreateDeduplicator - No DeduplicationService service found, using default heap based one
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo2 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo3 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()

  @HttpTest
  Scenario: Pulling from an http remote with remote changes updates the local ref              # Pull.feature:35
    Given There is a default multirepo server with http remotes                                # WebAPICucumberHooks.setUpDefaultMultiRepoWithHttpRemotes()
    And the variable "{@ObjectId|repo4|master}" equals "{@ObjectId|repo1|master~2}"            # WebAPICucumberHooks.checkVariableEquals(String,String)
    When I call "GET /repos/repo4/pull?remoteName=origin&ref=master"                           # WebAPICucumberHooks.callURL(String)
    Then the response status should be '200'                                                   # WebAPICucumberHooks.checkStatusCode(int)
    And the xpath "/response/success/text()" equals "true"                                     # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xpath "/response/Pull/Merge/ours/text()" equals "{@ObjectId|repo1|master~2}"       # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xpath "/response/Pull/Merge/theirs/text()" equals "{@ObjectId|repo1|master}"       # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xpath "/response/Pull/Merge/ancestor/text()" equals "{@ObjectId|repo1|master~2}"   # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xpath "/response/Pull/Merge/mergedCommit/text()" equals "{@ObjectId|repo1|master}" # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xpath "/response/Pull/Added/text()" equals "6"                                     # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xpath "/response/Pull/Modified/text()" equals "0"                                  # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xpath "/response/Pull/Removed/text()" equals "0"                                   # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the variable "{@ObjectId|repo4|master}" equals "{@ObjectId|repo1|master}"              # WebAPICucumberHooks.checkVariableEquals(String,String)
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo4 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo1 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo2 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo3 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()

  Scenario: Pulling from a remote with both local and remote changes creates a merge commit                                                    # Pull.feature:50
    Given There is a default multirepo server with remotes                                                                                     # WebAPICucumberHooks.setUpDefaultMultiRepoWithRemotes()
    And I have a transaction as "@txId" on the "repo4" repo                                                                                    # WebAPICucumberHooks.beginTransactionAsVariable(String,String)
    And I have committed "Point.1_modified" on the "repo4" repo in the "@txId" transaction                                                     # WebAPICucumberHooks.I_have_committed(String,String,String)
    When I call "GET /repos/repo4/pull?transactionId={@txId}&remoteName=origin&ref=master&authorName=myAuthor&authorEmail=myAuthor@geogig.org" # WebAPICucumberHooks.callURL(String)
    Then the response status should be '200'                                                                                                   # WebAPICucumberHooks.checkStatusCode(int)
    And the xpath "/response/success/text()" equals "true"                                                                                     # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xpath "/response/Pull/Merge/ours/text()" equals "{@ObjectId|repo4|@txId|master~1}"                                                 # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xpath "/response/Pull/Merge/theirs/text()" equals "{@ObjectId|repo1|master}"                                                       # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xpath "/response/Pull/Merge/ancestor/text()" equals "{@ObjectId|repo1|master~2}"                                                   # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xpath "/response/Pull/Merge/mergedCommit/text()" equals "{@ObjectId|repo4|@txId|master}"                                           # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xpath "/response/Pull/Added/text()" equals "6"                                                                                     # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xpath "/response/Pull/Modified/text()" equals "0"                                                                                  # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xpath "/response/Pull/Removed/text()" equals "0"                                                                                   # WebAPICucumberHooks.checkXPathEquals(String,String)
    When I call "GET /repos/repo4/cat?objectid={@ObjectId|repo4|@txId|master}"                                                                 # WebAPICucumberHooks.callURL(String)
    Then the response status should be '200'                                                                                                   # WebAPICucumberHooks.checkStatusCode(int)
    And the xpath "/response/success/text()" equals "true"                                                                                     # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xpath "/response/commit/author/name/text()" equals "myAuthor"                                                                      # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xpath "/response/commit/author/email/text()" equals "myAuthor@geogig.org"                                                          # WebAPICucumberHooks.checkXPathEquals(String,String)
[main] INFO org.mortbay.log - jetty-6.1.5
[main] INFO org.mortbay.log - Started SelectChannelConnector@0.0.0.0:8182
[main] INFO org.locationtech.geogig.plumbing.CreateDeduplicator - No DeduplicationService service found, using default heap based one
[btpool7-1] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo1 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.plumbing.CreateDeduplicator - No DeduplicationService service found, using default heap based one
[main] INFO org.locationtech.geogig.plumbing.CreateDeduplicator - No DeduplicationService service found, using default heap based one
[btpool7-1] INFO org.locationtech.geogig.rest.repository.BatchedObjectResource - Serving request to send objects based on message {"want":["e1bd487d9dc58e95c7caf94153488b8e283479b1","b63c2c8610c43c2fb3da52812e9bb1aaa5607a7e"],"have":[]}
[btpool7-1] INFO org.locationtech.geogig.plumbing.CreateDeduplicator - No DeduplicationService service found, using default heap based one
[btpool7-1] INFO org.locationtech.geogig.remote.BinaryPackedObjects - scanning for previsit list...
[btpool7-1] INFO org.locationtech.geogig.remote.BinaryPackedObjects - Previsit list built in 2.273 μs for 0 ids: []. Calculating reachable content ids...
[btpool7-1] INFO org.locationtech.geogig.remote.BinaryPackedObjects - reachableContentIds took 13.32 μs for 0 ids
[btpool7-1] INFO org.locationtech.geogig.remote.BinaryPackedObjects - obtaining post order iterator on range...
[btpool7-1] INFO org.locationtech.geogig.remote.BinaryPackedObjects - PostOrderIterator.range took 7.540 μs
[btpool7-1] INFO org.locationtech.geogig.remote.BinaryPackedObjects - writing objects to remote...
[main] INFO org.locationtech.geogig.remote.HttpRemoteRepo - Processed 19 objects. Inserted: 19. Existing: 0. Time: 3.104 ms. Compressed size: 989 bytes. Uncompressed size: 3,179 bytes.
[btpool7-1] INFO org.locationtech.geogig.rest.repository.BatchedObjectResource - Serving request to send objects based on message {"want":["43fedc89b1a522901ef7d38940725e64b67aaa33"],"have":["e1bd487d9dc58e95c7caf94153488b8e283479b1"]}
[btpool7-1] INFO org.locationtech.geogig.plumbing.CreateDeduplicator - No DeduplicationService service found, using default heap based one
[btpool7-1] INFO org.locationtech.geogig.remote.BinaryPackedObjects - scanning for previsit list...
[btpool7-1] INFO org.locationtech.geogig.remote.BinaryPackedObjects - Previsit list built in 2.267 μs for 1 ids: [e1bd487d9dc58e95c7caf94153488b8e283479b1]. Calculating reachable content ids...
[btpool7-1] INFO org.locationtech.geogig.remote.BinaryPackedObjects - reachableContentIds took 435.4 μs for 11 ids
[btpool7-1] INFO org.locationtech.geogig.remote.BinaryPackedObjects - obtaining post order iterator on range...
[btpool7-1] INFO org.locationtech.geogig.remote.BinaryPackedObjects - PostOrderIterator.range took 23.07 μs
[btpool7-1] INFO org.locationtech.geogig.remote.BinaryPackedObjects - writing objects to remote...
[main] INFO org.locationtech.geogig.remote.HttpRemoteRepo - Processed 8 objects. Inserted: 8. Existing: 0. Time: 1.385 ms. Compressed size: 657 bytes. Uncompressed size: 1,488 bytes.
[btpool7-1] INFO org.locationtech.geogig.rest.repository.BatchedObjectResource - Serving request to send objects based on message {"want":["046c420ef5b2815790811136e78957b2f6fbee26","58fa146fee0d26b31217e54c6030cdd4d997b0fe"],"have":["e1bd487d9dc58e95c7caf94153488b8e283479b1","b63c2c8610c43c2fb3da52812e9bb1aaa5607a7e","43fedc89b1a522901ef7d38940725e64b67aaa33"]}
[btpool7-1] INFO org.locationtech.geogig.plumbing.CreateDeduplicator - No DeduplicationService service found, using default heap based one
[btpool7-1] INFO org.locationtech.geogig.remote.BinaryPackedObjects - scanning for previsit list...
[btpool7-1] INFO org.locationtech.geogig.remote.BinaryPackedObjects - Previsit list built in 2.201 μs for 3 ids: [e1bd487d9dc58e95c7caf94153488b8e283479b1, b63c2c8610c43c2fb3da52812e9bb1aaa5607a7e, 43fedc89b1a522901ef7d38940725e64b67aaa33]. Calculating reachable content ids...
[btpool7-1] INFO org.locationtech.geogig.remote.BinaryPackedObjects - reachableContentIds took 519.7 μs for 27 ids
[btpool7-1] INFO org.locationtech.geogig.remote.BinaryPackedObjects - obtaining post order iterator on range...
[btpool7-1] INFO org.locationtech.geogig.remote.BinaryPackedObjects - PostOrderIterator.range took 9.819 μs
[btpool7-1] INFO org.locationtech.geogig.remote.BinaryPackedObjects - writing objects to remote...
[main] INFO org.locationtech.geogig.remote.HttpRemoteRepo - Processed 6 objects. Inserted: 6. Existing: 0. Time: 1.104 ms. Compressed size: 777 bytes. Uncompressed size: 1,673 bytes.
[main] INFO org.locationtech.geogig.plumbing.CreateDeduplicator - No DeduplicationService service found, using default heap based one
[main] INFO org.locationtech.geogig.plumbing.CreateDeduplicator - No DeduplicationService service found, using default heap based one
[main] INFO org.locationtech.geogig.plumbing.CreateDeduplicator - No DeduplicationService service found, using default heap based one
[main] INFO org.locationtech.geogig.plumbing.CreateDeduplicator - No DeduplicationService service found, using default heap based one
[btpool7-1] INFO org.locationtech.geogig.rest.repository.BatchedObjectResource - Serving request to send objects based on message {"want":["e1bd487d9dc58e95c7caf94153488b8e283479b1","b63c2c8610c43c2fb3da52812e9bb1aaa5607a7e"],"have":[]}
[btpool7-1] INFO org.locationtech.geogig.plumbing.CreateDeduplicator - No DeduplicationService service found, using default heap based one
[btpool7-1] INFO org.locationtech.geogig.remote.BinaryPackedObjects - scanning for previsit list...
[btpool7-1] INFO org.locationtech.geogig.remote.BinaryPackedObjects - Previsit list built in 2.332 μs for 0 ids: []. Calculating reachable content ids...
[btpool7-1] INFO org.locationtech.geogig.remote.BinaryPackedObjects - reachableContentIds took 13.72 μs for 0 ids
[btpool7-1] INFO org.locationtech.geogig.remote.BinaryPackedObjects - obtaining post order iterator on range...
[btpool7-1] INFO org.locationtech.geogig.remote.BinaryPackedObjects - PostOrderIterator.range took 7.293 μs
[btpool7-1] INFO org.locationtech.geogig.remote.BinaryPackedObjects - writing objects to remote...
[main] INFO org.locationtech.geogig.remote.HttpRemoteRepo - Processed 19 objects. Inserted: 19. Existing: 0. Time: 3.811 ms. Compressed size: 989 bytes. Uncompressed size: 3,179 bytes.
[btpool7-1] INFO org.locationtech.geogig.rest.repository.BatchedObjectResource - Serving request to send objects based on message {"want":["43fedc89b1a522901ef7d38940725e64b67aaa33","046c420ef5b2815790811136e78957b2f6fbee26","58fa146fee0d26b31217e54c6030cdd4d997b0fe"],"have":["e1bd487d9dc58e95c7caf94153488b8e283479b1","b63c2c8610c43c2fb3da52812e9bb1aaa5607a7e"]}
[btpool7-1] INFO org.locationtech.geogig.plumbing.CreateDeduplicator - No DeduplicationService service found, using default heap based one
[btpool7-1] INFO org.locationtech.geogig.remote.BinaryPackedObjects - scanning for previsit list...
[btpool7-1] INFO org.locationtech.geogig.remote.BinaryPackedObjects - Previsit list built in 2.097 μs for 2 ids: [e1bd487d9dc58e95c7caf94153488b8e283479b1, b63c2c8610c43c2fb3da52812e9bb1aaa5607a7e]. Calculating reachable content ids...
[btpool7-1] INFO org.locationtech.geogig.remote.BinaryPackedObjects - reachableContentIds took 413.4 μs for 19 ids
[btpool7-1] INFO org.locationtech.geogig.remote.BinaryPackedObjects - obtaining post order iterator on range...
[btpool7-1] INFO org.locationtech.geogig.remote.BinaryPackedObjects - PostOrderIterator.range took 9.304 μs
[btpool7-1] INFO org.locationtech.geogig.remote.BinaryPackedObjects - writing objects to remote...
[main] INFO org.locationtech.geogig.remote.HttpRemoteRepo - Processed 14 objects. Inserted: 14. Existing: 0. Time: 2.401 ms. Compressed size: 1,065 bytes. Uncompressed size: 3,161 bytes.
[main] INFO org.locationtech.geogig.plumbing.CreateDeduplicator - No DeduplicationService service found, using default heap based one
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo4 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.plumbing.CreateDeduplicator - No DeduplicationService service found, using default heap based one
[main] INFO org.locationtech.geogig.plumbing.CreateDeduplicator - No DeduplicationService service found, using default heap based one
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo2 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo3 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()

  @HttpTest
  Scenario: Pulling from an http remote with both local and remote changes creates a merge commit                                              # Pull.feature:71
    Given There is a default multirepo server with http remotes                                                                                # WebAPICucumberHooks.setUpDefaultMultiRepoWithHttpRemotes()
    And I have a transaction as "@txId" on the "repo4" repo                                                                                    # WebAPICucumberHooks.beginTransactionAsVariable(String,String)
    And I have committed "Point.1_modified" on the "repo4" repo in the "@txId" transaction                                                     # WebAPICucumberHooks.I_have_committed(String,String,String)
    When I call "GET /repos/repo4/pull?transactionId={@txId}&remoteName=origin&ref=master&authorName=myAuthor&authorEmail=myAuthor@geogig.org" # WebAPICucumberHooks.callURL(String)
    Then the response status should be '200'                                                                                                   # WebAPICucumberHooks.checkStatusCode(int)
    And the xpath "/response/success/text()" equals "true"                                                                                     # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xpath "/response/Pull/Merge/ours/text()" equals "{@ObjectId|repo4|@txId|master~1}"                                                 # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xpath "/response/Pull/Merge/theirs/text()" equals "{@ObjectId|repo1|master}"                                                       # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xpath "/response/Pull/Merge/ancestor/text()" equals "{@ObjectId|repo1|master~2}"                                                   # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xpath "/response/Pull/Merge/mergedCommit/text()" equals "{@ObjectId|repo4|@txId|master}"                                           # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xpath "/response/Pull/Added/text()" equals "6"                                                                                     # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xpath "/response/Pull/Modified/text()" equals "0"                                                                                  # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xpath "/response/Pull/Removed/text()" equals "0"                                                                                   # WebAPICucumberHooks.checkXPathEquals(String,String)
    When I call "GET /repos/repo4/cat?objectid={@ObjectId|repo4|@txId|master}"                                                                 # WebAPICucumberHooks.callURL(String)
    Then the response status should be '200'                                                                                                   # WebAPICucumberHooks.checkStatusCode(int)
    And the xpath "/response/success/text()" equals "true"                                                                                     # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xpath "/response/commit/author/name/text()" equals "myAuthor"                                                                      # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xpath "/response/commit/author/email/text()" equals "myAuthor@geogig.org"                                                          # WebAPICucumberHooks.checkXPathEquals(String,String)
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo4 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo1 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo2 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo3 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()

  Scenario: Pulling from a remote with conflicting changes returns the details of the conflict                                                 # Pull.feature:91
    Given There is a default multirepo server with remotes                                                                                     # WebAPICucumberHooks.setUpDefaultMultiRepoWithRemotes()
    And I have a transaction as "@txId" on the "repo4" repo                                                                                    # WebAPICucumberHooks.beginTransactionAsVariable(String,String)
    And I have committed "Point.2_modified" on the "repo4" repo in the "@txId" transaction                                                     # WebAPICucumberHooks.I_have_committed(String,String,String)
    When I call "GET /repos/repo4/pull?transactionId={@txId}&remoteName=origin&ref=master&authorName=myAuthor&authorEmail=myAuthor@geogig.org" # WebAPICucumberHooks.callURL(String)
    Then the response status should be '200'                                                                                                   # WebAPICucumberHooks.checkStatusCode(int)
    And the xpath "/response/success/text()" equals "true"                                                                                     # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xpath "/response/Merge/ours/text()" equals "{@ObjectId|repo4|@txId|master}"                                                        # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xpath "/response/Merge/theirs/text()" equals "{@ObjectId|repo1|master}"                                                            # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xpath "/response/Merge/ancestor/text()" equals "{@ObjectId|repo1|master~2}"                                                        # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xpath "/response/Merge/conflicts/text()" equals "1"                                                                                # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xml response should contain "/response/Merge/Feature" 6 times                                                                      # WebAPICucumberHooks.checkXPathCadinality(String,int)
    And the response body should contain "CONFLICT"                                                                                            # WebAPICucumberHooks.checkResponseTextContains(String)
    And the response body should contain "<theirvalue>{@ObjectId|repo1|master:Points/Point.2}</theirvalue>"                                    # WebAPICucumberHooks.checkResponseTextContains(String)
    And the response body should contain "<ourvalue>{@ObjectId|repo4|@txId|master:Points/Point.2}</ourvalue>"                                  # WebAPICucumberHooks.checkResponseTextContains(String)
[main] INFO org.mortbay.log - jetty-6.1.5
[main] INFO org.mortbay.log - Started SelectChannelConnector@0.0.0.0:8182
[main] INFO org.locationtech.geogig.plumbing.CreateDeduplicator - No DeduplicationService service found, using default heap based one
[btpool8-1] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo1 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.plumbing.CreateDeduplicator - No DeduplicationService service found, using default heap based one
[main] INFO org.locationtech.geogig.plumbing.CreateDeduplicator - No DeduplicationService service found, using default heap based one
[btpool8-1] INFO org.locationtech.geogig.rest.repository.BatchedObjectResource - Serving request to send objects based on message {"want":["ac3f99d1d76fddd6b3b4c9d17c0e802dd50ef030","33394d495893e8bd45731fa57db0d9ef7e522655"],"have":[]}
[btpool8-1] INFO org.locationtech.geogig.plumbing.CreateDeduplicator - No DeduplicationService service found, using default heap based one
[btpool8-1] INFO org.locationtech.geogig.remote.BinaryPackedObjects - scanning for previsit list...
[btpool8-1] INFO org.locationtech.geogig.remote.BinaryPackedObjects - Previsit list built in 2.394 μs for 0 ids: []. Calculating reachable content ids...
[btpool8-1] INFO org.locationtech.geogig.remote.BinaryPackedObjects - reachableContentIds took 16.73 μs for 0 ids
[btpool8-1] INFO org.locationtech.geogig.remote.BinaryPackedObjects - obtaining post order iterator on range...
[btpool8-1] INFO org.locationtech.geogig.remote.BinaryPackedObjects - PostOrderIterator.range took 8.058 μs
[btpool8-1] INFO org.locationtech.geogig.remote.BinaryPackedObjects - writing objects to remote...
[main] INFO org.locationtech.geogig.remote.HttpRemoteRepo - Processed 19 objects. Inserted: 19. Existing: 0. Time: 3.064 ms. Compressed size: 989 bytes. Uncompressed size: 3,179 bytes.
[btpool8-1] INFO org.locationtech.geogig.rest.repository.BatchedObjectResource - Serving request to send objects based on message {"want":["2a874742405057b8bdb82ade309945889c43605e"],"have":["ac3f99d1d76fddd6b3b4c9d17c0e802dd50ef030"]}
[btpool8-1] INFO org.locationtech.geogig.plumbing.CreateDeduplicator - No DeduplicationService service found, using default heap based one
[btpool8-1] INFO org.locationtech.geogig.remote.BinaryPackedObjects - scanning for previsit list...
[btpool8-1] INFO org.locationtech.geogig.remote.BinaryPackedObjects - Previsit list built in 2.201 μs for 1 ids: [ac3f99d1d76fddd6b3b4c9d17c0e802dd50ef030]. Calculating reachable content ids...
[btpool8-1] INFO org.locationtech.geogig.remote.BinaryPackedObjects - reachableContentIds took 308.5 μs for 11 ids
[btpool8-1] INFO org.locationtech.geogig.remote.BinaryPackedObjects - obtaining post order iterator on range...
[btpool8-1] INFO org.locationtech.geogig.remote.BinaryPackedObjects - PostOrderIterator.range took 8.841 μs
[btpool8-1] INFO org.locationtech.geogig.remote.BinaryPackedObjects - writing objects to remote...
[main] INFO org.locationtech.geogig.remote.HttpRemoteRepo - Processed 8 objects. Inserted: 8. Existing: 0. Time: 1.086 ms. Compressed size: 657 bytes. Uncompressed size: 1,488 bytes.
[btpool8-1] INFO org.locationtech.geogig.rest.repository.BatchedObjectResource - Serving request to send objects based on message {"want":["f01a9b556034db02ae72e3421e18f9b821483e20","a4785d413691720ae5c1dedd021a8bb3c165a7bb"],"have":["ac3f99d1d76fddd6b3b4c9d17c0e802dd50ef030","2a874742405057b8bdb82ade309945889c43605e","33394d495893e8bd45731fa57db0d9ef7e522655"]}
[btpool8-1] INFO org.locationtech.geogig.plumbing.CreateDeduplicator - No DeduplicationService service found, using default heap based one
[btpool8-1] INFO org.locationtech.geogig.remote.BinaryPackedObjects - scanning for previsit list...
[btpool8-1] INFO org.locationtech.geogig.remote.BinaryPackedObjects - Previsit list built in 2.153 μs for 3 ids: [ac3f99d1d76fddd6b3b4c9d17c0e802dd50ef030, 2a874742405057b8bdb82ade309945889c43605e, 33394d495893e8bd45731fa57db0d9ef7e522655]. Calculating reachable content ids...
[btpool8-1] INFO org.locationtech.geogig.remote.BinaryPackedObjects - reachableContentIds took 483.2 μs for 27 ids
[btpool8-1] INFO org.locationtech.geogig.remote.BinaryPackedObjects - obtaining post order iterator on range...
[btpool8-1] INFO org.locationtech.geogig.remote.BinaryPackedObjects - PostOrderIterator.range took 21.88 μs
[btpool8-1] INFO org.locationtech.geogig.remote.BinaryPackedObjects - writing objects to remote...
[main] INFO org.locationtech.geogig.remote.HttpRemoteRepo - Processed 6 objects. Inserted: 6. Existing: 0. Time: 950.7 μs. Compressed size: 777 bytes. Uncompressed size: 1,673 bytes.
[main] INFO org.locationtech.geogig.plumbing.CreateDeduplicator - No DeduplicationService service found, using default heap based one
[main] INFO org.locationtech.geogig.plumbing.CreateDeduplicator - No DeduplicationService service found, using default heap based one
[main] INFO org.locationtech.geogig.plumbing.CreateDeduplicator - No DeduplicationService service found, using default heap based one
[main] INFO org.locationtech.geogig.plumbing.CreateDeduplicator - No DeduplicationService service found, using default heap based one
[btpool8-1] INFO org.locationtech.geogig.rest.repository.BatchedObjectResource - Serving request to send objects based on message {"want":["ac3f99d1d76fddd6b3b4c9d17c0e802dd50ef030","33394d495893e8bd45731fa57db0d9ef7e522655"],"have":[]}
[btpool8-1] INFO org.locationtech.geogig.plumbing.CreateDeduplicator - No DeduplicationService service found, using default heap based one
[btpool8-1] INFO org.locationtech.geogig.remote.BinaryPackedObjects - scanning for previsit list...
[btpool8-1] INFO org.locationtech.geogig.remote.BinaryPackedObjects - Previsit list built in 2.613 μs for 0 ids: []. Calculating reachable content ids...
[btpool8-1] INFO org.locationtech.geogig.remote.BinaryPackedObjects - reachableContentIds took 15.85 μs for 0 ids
[btpool8-1] INFO org.locationtech.geogig.remote.BinaryPackedObjects - obtaining post order iterator on range...
[btpool8-1] INFO org.locationtech.geogig.remote.BinaryPackedObjects - PostOrderIterator.range took 7.811 μs
[btpool8-1] INFO org.locationtech.geogig.remote.BinaryPackedObjects - writing objects to remote...
[main] INFO org.locationtech.geogig.remote.HttpRemoteRepo - Processed 19 objects. Inserted: 19. Existing: 0. Time: 3.001 ms. Compressed size: 989 bytes. Uncompressed size: 3,179 bytes.
[btpool8-1] INFO org.locationtech.geogig.rest.repository.BatchedObjectResource - Serving request to send objects based on message {"want":["2a874742405057b8bdb82ade309945889c43605e","f01a9b556034db02ae72e3421e18f9b821483e20","a4785d413691720ae5c1dedd021a8bb3c165a7bb"],"have":["ac3f99d1d76fddd6b3b4c9d17c0e802dd50ef030","33394d495893e8bd45731fa57db0d9ef7e522655"]}
[btpool8-1] INFO org.locationtech.geogig.plumbing.CreateDeduplicator - No DeduplicationService service found, using default heap based one
[btpool8-1] INFO org.locationtech.geogig.remote.BinaryPackedObjects - scanning for previsit list...
[btpool8-1] INFO org.locationtech.geogig.remote.BinaryPackedObjects - Previsit list built in 2.320 μs for 2 ids: [ac3f99d1d76fddd6b3b4c9d17c0e802dd50ef030, 33394d495893e8bd45731fa57db0d9ef7e522655]. Calculating reachable content ids...
[btpool8-1] INFO org.locationtech.geogig.remote.BinaryPackedObjects - reachableContentIds took 417.8 μs for 19 ids
[btpool8-1] INFO org.locationtech.geogig.remote.BinaryPackedObjects - obtaining post order iterator on range...
[btpool8-1] INFO org.locationtech.geogig.remote.BinaryPackedObjects - PostOrderIterator.range took 21.13 μs
[btpool8-1] INFO org.locationtech.geogig.remote.BinaryPackedObjects - writing objects to remote...
[main] INFO org.locationtech.geogig.remote.HttpRemoteRepo - Processed 14 objects. Inserted: 14. Existing: 0. Time: 1.829 ms. Compressed size: 1,065 bytes. Uncompressed size: 3,161 bytes.
[main] INFO org.locationtech.geogig.plumbing.CreateDeduplicator - No DeduplicationService service found, using default heap based one
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo4 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.plumbing.CreateDeduplicator - No DeduplicationService service found, using default heap based one
[main] INFO org.locationtech.geogig.plumbing.CreateDeduplicator - No DeduplicationService service found, using default heap based one
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo2 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo3 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()

  @HttpTest
  Scenario: Pulling from an http remote with conflicting changes returns the details of the conflict                                           # Pull.feature:108
    Given There is a default multirepo server with http remotes                                                                                # WebAPICucumberHooks.setUpDefaultMultiRepoWithHttpRemotes()
    And I have a transaction as "@txId" on the "repo4" repo                                                                                    # WebAPICucumberHooks.beginTransactionAsVariable(String,String)
    And I have committed "Point.2_modified" on the "repo4" repo in the "@txId" transaction                                                     # WebAPICucumberHooks.I_have_committed(String,String,String)
    When I call "GET /repos/repo4/pull?transactionId={@txId}&remoteName=origin&ref=master&authorName=myAuthor&authorEmail=myAuthor@geogig.org" # WebAPICucumberHooks.callURL(String)
    Then the response status should be '200'                                                                                                   # WebAPICucumberHooks.checkStatusCode(int)
    And the xpath "/response/success/text()" equals "true"                                                                                     # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xpath "/response/Merge/ours/text()" equals "{@ObjectId|repo4|@txId|master}"                                                        # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xpath "/response/Merge/theirs/text()" equals "{@ObjectId|repo1|master}"                                                            # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xpath "/response/Merge/ancestor/text()" equals "{@ObjectId|repo1|master~2}"                                                        # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xpath "/response/Merge/conflicts/text()" equals "1"                                                                                # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xml response should contain "/response/Merge/Feature" 6 times                                                                      # WebAPICucumberHooks.checkXPathCadinality(String,int)
    And the response body should contain "CONFLICT"                                                                                            # WebAPICucumberHooks.checkResponseTextContains(String)
    And the response body should contain "<theirvalue>{@ObjectId|repo1|master:Points/Point.2}</theirvalue>"                                    # WebAPICucumberHooks.checkResponseTextContains(String)
    And the response body should contain "<ourvalue>{@ObjectId|repo4|@txId|master:Points/Point.2}</ourvalue>"                                  # WebAPICucumberHooks.checkResponseTextContains(String)
@Commands @Push
Feature: Push
  The push command allows a user to push a local branch to a remote and is supported through the "/repos/{repository}/push" endpoint
  The command must be executed using the HTTP GET method
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo1 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()

  Scenario: Verify wrong HTTP method issues 405 "Method not allowed" # Push.feature:6
    Given There is an empty repository named repo1                   # WebAPICucumberHooks.setUpEmptyRepo(String)
    When I call "PUT /repos/repo1/push"                              # WebAPICucumberHooks.callURL(String)
    Then the response status should be '405'                         # WebAPICucumberHooks.checkStatusCode(int)
    And the response allowed methods should be "GET"                 # WebAPICucumberHooks.checkResponseAllowedMethods(String)
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo1 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()

  Scenario: Push outside of a repository issues 404 "Not found" # Push.feature:12
    Given There is an empty multirepo server                    # WebAPICucumberHooks.setUpEmptyMultiRepo()
    When I call "GET /repos/repo1/push"                         # WebAPICucumberHooks.callURL(String)
    Then the response status should be '404'                    # WebAPICucumberHooks.checkStatusCode(int)
    And the response ContentType should be "text/plain"         # WebAPICucumberHooks.checkContentType(String)
    And the response body should contain "Repository not found" # WebAPICucumberHooks.checkResponseTextContains(String)
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo1 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.plumbing.SendPack - Pushing Ref[refs/heads/master -> 667ec2d7778c20b5d8f48ba28beb210c5e66fb7a] to refs/remotes/repo4/master(master)
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo4 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo2 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo3 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()

  Scenario: Pushing changes to a remote results in a success                      # Push.feature:19
    Given There is a default multirepo server with remotes                        # WebAPICucumberHooks.setUpDefaultMultiRepoWithRemotes()
    When I call "GET /repos/repo1/push?remoteName=repo4&ref=master"               # WebAPICucumberHooks.callURL(String)
    Then the response status should be '200'                                      # WebAPICucumberHooks.checkStatusCode(int)
    And the xpath "/response/success/text()" equals "true"                        # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xpath "/response/Push/text()" equals "Success"                        # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xpath "/response/dataPushed/text()" equals "true"                     # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the variable "{@ObjectId|repo1|master}" equals "{@ObjectId|repo4|master}" # WebAPICucumberHooks.checkVariableEquals(String,String)
    When I call "GET /repos/repo1/push?remoteName=repo4&ref=master"               # WebAPICucumberHooks.callURL(String)
    Then the response status should be '200'                                      # WebAPICucumberHooks.checkStatusCode(int)
    And the xpath "/response/success/text()" equals "true"                        # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xpath "/response/Push/text()" equals "Success"                        # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xpath "/response/dataPushed/text()" equals "false"                    # WebAPICucumberHooks.checkXPathEquals(String,String)
[main] INFO org.mortbay.log - jetty-6.1.5
[main] INFO org.mortbay.log - Started SelectChannelConnector@0.0.0.0:8182
[main] INFO org.locationtech.geogig.plumbing.CreateDeduplicator - No DeduplicationService service found, using default heap based one
[btpool9-1] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo1 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.plumbing.CreateDeduplicator - No DeduplicationService service found, using default heap based one
[main] INFO org.locationtech.geogig.plumbing.CreateDeduplicator - No DeduplicationService service found, using default heap based one
[btpool9-1] INFO org.locationtech.geogig.rest.repository.BatchedObjectResource - Serving request to send objects based on message {"want":["0de6d78394108fe8e662c8d48abea6ee20fbccfd","8a26ec9ef52cc0fda89880ed7d30594b78577da4"],"have":[]}
[btpool9-1] INFO org.locationtech.geogig.plumbing.CreateDeduplicator - No DeduplicationService service found, using default heap based one
[btpool9-1] INFO org.locationtech.geogig.remote.BinaryPackedObjects - scanning for previsit list...
[btpool9-1] INFO org.locationtech.geogig.remote.BinaryPackedObjects - Previsit list built in 2.446 μs for 0 ids: []. Calculating reachable content ids...
[btpool9-1] INFO org.locationtech.geogig.remote.BinaryPackedObjects - reachableContentIds took 16.11 μs for 0 ids
[btpool9-1] INFO org.locationtech.geogig.remote.BinaryPackedObjects - obtaining post order iterator on range...
[btpool9-1] INFO org.locationtech.geogig.remote.BinaryPackedObjects - PostOrderIterator.range took 16.83 μs
[btpool9-1] INFO org.locationtech.geogig.remote.BinaryPackedObjects - writing objects to remote...
[main] INFO org.locationtech.geogig.remote.HttpRemoteRepo - Processed 19 objects. Inserted: 19. Existing: 0. Time: 3.086 ms. Compressed size: 989 bytes. Uncompressed size: 3,179 bytes.
[btpool9-1] INFO org.locationtech.geogig.rest.repository.BatchedObjectResource - Serving request to send objects based on message {"want":["9bbf8ac9ee627477e2d74d5f75037d3b99470c57"],"have":["0de6d78394108fe8e662c8d48abea6ee20fbccfd"]}
[btpool9-1] INFO org.locationtech.geogig.plumbing.CreateDeduplicator - No DeduplicationService service found, using default heap based one
[btpool9-1] INFO org.locationtech.geogig.remote.BinaryPackedObjects - scanning for previsit list...
[btpool9-1] INFO org.locationtech.geogig.remote.BinaryPackedObjects - Previsit list built in 2.215 μs for 1 ids: [0de6d78394108fe8e662c8d48abea6ee20fbccfd]. Calculating reachable content ids...
[btpool9-1] INFO org.locationtech.geogig.remote.BinaryPackedObjects - reachableContentIds took 315.5 μs for 11 ids
[btpool9-1] INFO org.locationtech.geogig.remote.BinaryPackedObjects - obtaining post order iterator on range...
[btpool9-1] INFO org.locationtech.geogig.remote.BinaryPackedObjects - PostOrderIterator.range took 8.813 μs
[btpool9-1] INFO org.locationtech.geogig.remote.BinaryPackedObjects - writing objects to remote...
[main] INFO org.locationtech.geogig.remote.HttpRemoteRepo - Processed 8 objects. Inserted: 8. Existing: 0. Time: 1.317 ms. Compressed size: 660 bytes. Uncompressed size: 1,488 bytes.
[btpool9-1] INFO org.locationtech.geogig.rest.repository.BatchedObjectResource - Serving request to send objects based on message {"want":["4cd5104c6bb0593df3faac129a04b62b1583a0eb","c2a3b71ec4e156987f3b18270c4849aba9f15187"],"have":["9bbf8ac9ee627477e2d74d5f75037d3b99470c57","8a26ec9ef52cc0fda89880ed7d30594b78577da4","0de6d78394108fe8e662c8d48abea6ee20fbccfd"]}
[btpool9-1] INFO org.locationtech.geogig.plumbing.CreateDeduplicator - No DeduplicationService service found, using default heap based one
[btpool9-1] INFO org.locationtech.geogig.remote.BinaryPackedObjects - scanning for previsit list...
[btpool9-1] INFO org.locationtech.geogig.remote.BinaryPackedObjects - Previsit list built in 2.154 μs for 3 ids: [9bbf8ac9ee627477e2d74d5f75037d3b99470c57, 8a26ec9ef52cc0fda89880ed7d30594b78577da4, 0de6d78394108fe8e662c8d48abea6ee20fbccfd]. Calculating reachable content ids...
[btpool9-1] INFO org.locationtech.geogig.remote.BinaryPackedObjects - reachableContentIds took 498.3 μs for 27 ids
[btpool9-1] INFO org.locationtech.geogig.remote.BinaryPackedObjects - obtaining post order iterator on range...
[btpool9-1] INFO org.locationtech.geogig.remote.BinaryPackedObjects - PostOrderIterator.range took 20.61 μs
[btpool9-1] INFO org.locationtech.geogig.remote.BinaryPackedObjects - writing objects to remote...
[main] INFO org.locationtech.geogig.remote.HttpRemoteRepo - Processed 6 objects. Inserted: 6. Existing: 0. Time: 938.7 μs. Compressed size: 777 bytes. Uncompressed size: 1,673 bytes.
[main] INFO org.locationtech.geogig.plumbing.CreateDeduplicator - No DeduplicationService service found, using default heap based one
[main] INFO org.locationtech.geogig.plumbing.CreateDeduplicator - No DeduplicationService service found, using default heap based one
[main] INFO org.locationtech.geogig.plumbing.CreateDeduplicator - No DeduplicationService service found, using default heap based one
[main] INFO org.locationtech.geogig.plumbing.CreateDeduplicator - No DeduplicationService service found, using default heap based one
[btpool9-1] INFO org.locationtech.geogig.rest.repository.BatchedObjectResource - Serving request to send objects based on message {"want":["0de6d78394108fe8e662c8d48abea6ee20fbccfd","8a26ec9ef52cc0fda89880ed7d30594b78577da4"],"have":[]}
[btpool9-1] INFO org.locationtech.geogig.plumbing.CreateDeduplicator - No DeduplicationService service found, using default heap based one
[btpool9-1] INFO org.locationtech.geogig.remote.BinaryPackedObjects - scanning for previsit list...
[btpool9-1] INFO org.locationtech.geogig.remote.BinaryPackedObjects - Previsit list built in 2.575 μs for 0 ids: []. Calculating reachable content ids...
[btpool9-1] INFO org.locationtech.geogig.remote.BinaryPackedObjects - reachableContentIds took 15.71 μs for 0 ids
[btpool9-1] INFO org.locationtech.geogig.remote.BinaryPackedObjects - obtaining post order iterator on range...
[btpool9-1] INFO org.locationtech.geogig.remote.BinaryPackedObjects - PostOrderIterator.range took 7.810 μs
[btpool9-1] INFO org.locationtech.geogig.remote.BinaryPackedObjects - writing objects to remote...
[main] INFO org.locationtech.geogig.remote.HttpRemoteRepo - Processed 19 objects. Inserted: 19. Existing: 0. Time: 2.827 ms. Compressed size: 989 bytes. Uncompressed size: 3,179 bytes.
[btpool9-1] INFO org.locationtech.geogig.rest.repository.BatchedObjectResource - Serving request to send objects based on message {"want":["9bbf8ac9ee627477e2d74d5f75037d3b99470c57","4cd5104c6bb0593df3faac129a04b62b1583a0eb","c2a3b71ec4e156987f3b18270c4849aba9f15187"],"have":["8a26ec9ef52cc0fda89880ed7d30594b78577da4","0de6d78394108fe8e662c8d48abea6ee20fbccfd"]}
[btpool9-1] INFO org.locationtech.geogig.plumbing.CreateDeduplicator - No DeduplicationService service found, using default heap based one
[btpool9-1] INFO org.locationtech.geogig.remote.BinaryPackedObjects - scanning for previsit list...
[btpool9-1] INFO org.locationtech.geogig.remote.BinaryPackedObjects - Previsit list built in 2.410 μs for 2 ids: [8a26ec9ef52cc0fda89880ed7d30594b78577da4, 0de6d78394108fe8e662c8d48abea6ee20fbccfd]. Calculating reachable content ids...
[btpool9-1] INFO org.locationtech.geogig.remote.BinaryPackedObjects - reachableContentIds took 425.9 μs for 19 ids
[btpool9-1] INFO org.locationtech.geogig.remote.BinaryPackedObjects - obtaining post order iterator on range...
[btpool9-1] INFO org.locationtech.geogig.remote.BinaryPackedObjects - PostOrderIterator.range took 19.90 μs
[btpool9-1] INFO org.locationtech.geogig.remote.BinaryPackedObjects - writing objects to remote...
[main] INFO org.locationtech.geogig.remote.HttpRemoteRepo - Processed 14 objects. Inserted: 14. Existing: 0. Time: 1.929 ms. Compressed size: 1,069 bytes. Uncompressed size: 3,161 bytes.
[main] INFO org.locationtech.geogig.plumbing.CreateDeduplicator - No DeduplicationService service found, using default heap based one
[main] INFO org.locationtech.geogig.plumbing.CreateDeduplicator - No DeduplicationService service found, using default heap based one
[btpool9-1] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo4 using FileRepositoryResolver
[btpool9-1] INFO org.locationtech.geogig.rest.repository.PushManager - Updating ref 'refs/heads/master'[0de6d78394108fe8e662c8d48abea6ee20fbccfd] -> c2a3b71ec4e156987f3b18270c4849aba9f15187
[main] INFO org.locationtech.geogig.plumbing.SendPack - Pushing Ref[refs/heads/master -> c2a3b71ec4e156987f3b18270c4849aba9f15187] to refs/remotes/repo4/master(master)
[main] INFO org.locationtech.geogig.plumbing.CreateDeduplicator - No DeduplicationService service found, using default heap based one
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo2 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo3 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()

  @HttpTest
  Scenario: Pushing changes to an http remote results in a success                # Push.feature:34
    Given There is a default multirepo server with http remotes                   # WebAPICucumberHooks.setUpDefaultMultiRepoWithHttpRemotes()
    When I call "GET /repos/repo1/push?remoteName=repo4&ref=master"               # WebAPICucumberHooks.callURL(String)
    Then the response status should be '200'                                      # WebAPICucumberHooks.checkStatusCode(int)
    And the xpath "/response/success/text()" equals "true"                        # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xpath "/response/Push/text()" equals "Success"                        # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xpath "/response/dataPushed/text()" equals "true"                     # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the variable "{@ObjectId|repo1|master}" equals "{@ObjectId|repo4|master}" # WebAPICucumberHooks.checkVariableEquals(String,String)
    When I call "GET /repos/repo1/push?remoteName=repo4&ref=master"               # WebAPICucumberHooks.callURL(String)
    Then the response status should be '200'                                      # WebAPICucumberHooks.checkStatusCode(int)
    And the xpath "/response/success/text()" equals "true"                        # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xpath "/response/Push/text()" equals "Success"                        # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xpath "/response/dataPushed/text()" equals "false"                    # WebAPICucumberHooks.checkXPathEquals(String,String)
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo4 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo2 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo3 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo1 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()

  Scenario: Pushing changes to a remote with other changes issues a 500 status code                                                           # Push.feature:48
    Given There is a default multirepo server with remotes                                                                                    # WebAPICucumberHooks.setUpDefaultMultiRepoWithRemotes()
    And I have a transaction as "@txId" on the "repo4" repo                                                                                   # WebAPICucumberHooks.beginTransactionAsVariable(String,String)
    And I have committed "Point.1_modified" on the "repo4" repo in the "@txId" transaction                                                    # WebAPICucumberHooks.I_have_committed(String,String,String)
    When I call "GET /repos/repo4/push?transactionId={@txId}&remoteName=origin&ref=master"                                                    # WebAPICucumberHooks.callURL(String)
    Then the response status should be '500'                                                                                                  # WebAPICucumberHooks.checkStatusCode(int)
    And the xpath "/response/error/text()" equals "Push failed: The remote repository has changes that would be lost in the event of a push." # WebAPICucumberHooks.checkXPathEquals(String,String)
[main] INFO org.mortbay.log - jetty-6.1.5
[main] INFO org.mortbay.log - Started SelectChannelConnector@0.0.0.0:8182
[main] INFO org.locationtech.geogig.plumbing.CreateDeduplicator - No DeduplicationService service found, using default heap based one
[btpool10-1] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo1 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.plumbing.CreateDeduplicator - No DeduplicationService service found, using default heap based one
[main] INFO org.locationtech.geogig.plumbing.CreateDeduplicator - No DeduplicationService service found, using default heap based one
[btpool10-1] INFO org.locationtech.geogig.rest.repository.BatchedObjectResource - Serving request to send objects based on message {"want":["e3fd14aae21a62976d0d729c3b00a450407d0dfc","e0f82a32712b3d1675872192bd2e689f7fa0803c"],"have":[]}
[btpool10-1] INFO org.locationtech.geogig.plumbing.CreateDeduplicator - No DeduplicationService service found, using default heap based one
[btpool10-1] INFO org.locationtech.geogig.remote.BinaryPackedObjects - scanning for previsit list...
[btpool10-1] INFO org.locationtech.geogig.remote.BinaryPackedObjects - Previsit list built in 2.982 μs for 0 ids: []. Calculating reachable content ids...
[btpool10-1] INFO org.locationtech.geogig.remote.BinaryPackedObjects - reachableContentIds took 43.87 μs for 0 ids
[btpool10-1] INFO org.locationtech.geogig.remote.BinaryPackedObjects - obtaining post order iterator on range...
[btpool10-1] INFO org.locationtech.geogig.remote.BinaryPackedObjects - PostOrderIterator.range took 10.11 μs
[btpool10-1] INFO org.locationtech.geogig.remote.BinaryPackedObjects - writing objects to remote...
[main] INFO org.locationtech.geogig.remote.HttpRemoteRepo - Processed 19 objects. Inserted: 19. Existing: 0. Time: 3.991 ms. Compressed size: 988 bytes. Uncompressed size: 3,179 bytes.
[btpool10-1] INFO org.locationtech.geogig.rest.repository.BatchedObjectResource - Serving request to send objects based on message {"want":["83f0d7974241d849702c99e841dcc7035e336980"],"have":["e3fd14aae21a62976d0d729c3b00a450407d0dfc"]}
[btpool10-1] INFO org.locationtech.geogig.plumbing.CreateDeduplicator - No DeduplicationService service found, using default heap based one
[btpool10-1] INFO org.locationtech.geogig.remote.BinaryPackedObjects - scanning for previsit list...
[btpool10-1] INFO org.locationtech.geogig.remote.BinaryPackedObjects - Previsit list built in 2.220 μs for 1 ids: [e3fd14aae21a62976d0d729c3b00a450407d0dfc]. Calculating reachable content ids...
[btpool10-1] INFO org.locationtech.geogig.remote.BinaryPackedObjects - reachableContentIds took 313.1 μs for 11 ids
[btpool10-1] INFO org.locationtech.geogig.remote.BinaryPackedObjects - obtaining post order iterator on range...
[btpool10-1] INFO org.locationtech.geogig.remote.BinaryPackedObjects - PostOrderIterator.range took 8.464 μs
[btpool10-1] INFO org.locationtech.geogig.remote.BinaryPackedObjects - writing objects to remote...
[main] INFO org.locationtech.geogig.remote.HttpRemoteRepo - Processed 8 objects. Inserted: 8. Existing: 0. Time: 1.072 ms. Compressed size: 656 bytes. Uncompressed size: 1,488 bytes.
[btpool10-1] INFO org.locationtech.geogig.rest.repository.BatchedObjectResource - Serving request to send objects based on message {"want":["6ba57939fb06c65f6323a62e4b6e3c8373482569","9e79406226778f54119a21355a924040d6db315f"],"have":["83f0d7974241d849702c99e841dcc7035e336980","e3fd14aae21a62976d0d729c3b00a450407d0dfc","e0f82a32712b3d1675872192bd2e689f7fa0803c"]}
[btpool10-1] INFO org.locationtech.geogig.plumbing.CreateDeduplicator - No DeduplicationService service found, using default heap based one
[btpool10-1] INFO org.locationtech.geogig.remote.BinaryPackedObjects - scanning for previsit list...
[btpool10-1] INFO org.locationtech.geogig.remote.BinaryPackedObjects - Previsit list built in 2.175 μs for 3 ids: [83f0d7974241d849702c99e841dcc7035e336980, e3fd14aae21a62976d0d729c3b00a450407d0dfc, e0f82a32712b3d1675872192bd2e689f7fa0803c]. Calculating reachable content ids...
[btpool10-1] INFO org.locationtech.geogig.remote.BinaryPackedObjects - reachableContentIds took 499.6 μs for 27 ids
[btpool10-1] INFO org.locationtech.geogig.remote.BinaryPackedObjects - obtaining post order iterator on range...
[btpool10-1] INFO org.locationtech.geogig.remote.BinaryPackedObjects - PostOrderIterator.range took 9.495 μs
[btpool10-1] INFO org.locationtech.geogig.remote.BinaryPackedObjects - writing objects to remote...
[main] INFO org.locationtech.geogig.remote.HttpRemoteRepo - Processed 6 objects. Inserted: 6. Existing: 0. Time: 1.010 ms. Compressed size: 776 bytes. Uncompressed size: 1,673 bytes.
[main] INFO org.locationtech.geogig.plumbing.CreateDeduplicator - No DeduplicationService service found, using default heap based one
[main] INFO org.locationtech.geogig.plumbing.CreateDeduplicator - No DeduplicationService service found, using default heap based one
[main] INFO org.locationtech.geogig.plumbing.CreateDeduplicator - No DeduplicationService service found, using default heap based one
[main] INFO org.locationtech.geogig.plumbing.CreateDeduplicator - No DeduplicationService service found, using default heap based one
[btpool10-1] INFO org.locationtech.geogig.rest.repository.BatchedObjectResource - Serving request to send objects based on message {"want":["e3fd14aae21a62976d0d729c3b00a450407d0dfc","e0f82a32712b3d1675872192bd2e689f7fa0803c"],"have":[]}
[btpool10-1] INFO org.locationtech.geogig.plumbing.CreateDeduplicator - No DeduplicationService service found, using default heap based one
[btpool10-1] INFO org.locationtech.geogig.remote.BinaryPackedObjects - scanning for previsit list...
[btpool10-1] INFO org.locationtech.geogig.remote.BinaryPackedObjects - Previsit list built in 2.530 μs for 0 ids: []. Calculating reachable content ids...
[btpool10-1] INFO org.locationtech.geogig.remote.BinaryPackedObjects - reachableContentIds took 15.80 μs for 0 ids
[btpool10-1] INFO org.locationtech.geogig.remote.BinaryPackedObjects - obtaining post order iterator on range...
[btpool10-1] INFO org.locationtech.geogig.remote.BinaryPackedObjects - PostOrderIterator.range took 7.804 μs
[btpool10-1] INFO org.locationtech.geogig.remote.BinaryPackedObjects - writing objects to remote...
[main] INFO org.locationtech.geogig.remote.HttpRemoteRepo - Processed 19 objects. Inserted: 19. Existing: 0. Time: 2.843 ms. Compressed size: 988 bytes. Uncompressed size: 3,179 bytes.
[btpool10-1] INFO org.locationtech.geogig.rest.repository.BatchedObjectResource - Serving request to send objects based on message {"want":["83f0d7974241d849702c99e841dcc7035e336980","6ba57939fb06c65f6323a62e4b6e3c8373482569","9e79406226778f54119a21355a924040d6db315f"],"have":["e3fd14aae21a62976d0d729c3b00a450407d0dfc","e0f82a32712b3d1675872192bd2e689f7fa0803c"]}
[btpool10-1] INFO org.locationtech.geogig.plumbing.CreateDeduplicator - No DeduplicationService service found, using default heap based one
[btpool10-1] INFO org.locationtech.geogig.remote.BinaryPackedObjects - scanning for previsit list...
[btpool10-1] INFO org.locationtech.geogig.remote.BinaryPackedObjects - Previsit list built in 2.167 μs for 2 ids: [e3fd14aae21a62976d0d729c3b00a450407d0dfc, e0f82a32712b3d1675872192bd2e689f7fa0803c]. Calculating reachable content ids...
[btpool10-1] INFO org.locationtech.geogig.remote.BinaryPackedObjects - reachableContentIds took 402.9 μs for 19 ids
[btpool10-1] INFO org.locationtech.geogig.remote.BinaryPackedObjects - obtaining post order iterator on range...
[btpool10-1] INFO org.locationtech.geogig.remote.BinaryPackedObjects - PostOrderIterator.range took 21.03 μs
[btpool10-1] INFO org.locationtech.geogig.remote.BinaryPackedObjects - writing objects to remote...
[main] INFO org.locationtech.geogig.remote.HttpRemoteRepo - Processed 14 objects. Inserted: 14. Existing: 0. Time: 1.768 ms. Compressed size: 1,064 bytes. Uncompressed size: 3,161 bytes.
[main] INFO org.locationtech.geogig.plumbing.CreateDeduplicator - No DeduplicationService service found, using default heap based one
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo4 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.plumbing.CreateDeduplicator - No DeduplicationService service found, using default heap based one
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo2 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo3 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()

  @HttpTest
  Scenario: Pushing changes to an http remote with other changes issues a 500 status code                                                     # Push.feature:57
    Given There is a default multirepo server with http remotes                                                                               # WebAPICucumberHooks.setUpDefaultMultiRepoWithHttpRemotes()
    And I have a transaction as "@txId" on the "repo4" repo                                                                                   # WebAPICucumberHooks.beginTransactionAsVariable(String,String)
    And I have committed "Point.1_modified" on the "repo4" repo in the "@txId" transaction                                                    # WebAPICucumberHooks.I_have_committed(String,String,String)
    When I call "GET /repos/repo4/push?transactionId={@txId}&remoteName=origin&ref=master"                                                    # WebAPICucumberHooks.callURL(String)
    Then the response status should be '500'                                                                                                  # WebAPICucumberHooks.checkStatusCode(int)
    And the xpath "/response/error/text()" equals "Push failed: The remote repository has changes that would be lost in the event of a push." # WebAPICucumberHooks.checkXPathEquals(String,String)
@Commands @RebuildGraph
Feature: RebuildGraph
  The RebuildGraph command allows a user to rebuild the graph database of a repository and is supported through the "/repos/{repository}/rebuildgraph" endpoint
  The command must be executed using the HTTP GET method
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo1 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()

  Scenario: Verify wrong HTTP method issues 405 "Method not allowed" # RebuildGraph.feature:6
    Given There is an empty repository named repo1                   # WebAPICucumberHooks.setUpEmptyRepo(String)
    When I call "PUT /repos/repo1/rebuildgraph"                      # WebAPICucumberHooks.callURL(String)
    Then the response status should be '405'                         # WebAPICucumberHooks.checkStatusCode(int)
    And the response allowed methods should be "GET"                 # WebAPICucumberHooks.checkResponseAllowedMethods(String)
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo1 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()

  Scenario: RebuildGraph outside of a repository issues 404 "Not found" # RebuildGraph.feature:12
    Given There is an empty multirepo server                            # WebAPICucumberHooks.setUpEmptyMultiRepo()
    When I call "GET /repos/repo1/rebuildgraph"                         # WebAPICucumberHooks.callURL(String)
    Then the response status should be '404'                            # WebAPICucumberHooks.checkStatusCode(int)
    And the response ContentType should be "text/plain"                 # WebAPICucumberHooks.checkContentType(String)
    And the response body should contain "Repository not found"         # WebAPICucumberHooks.checkResponseTextContains(String)
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo1 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo2 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()

  Scenario: RebuildGraph restores missing entries in the graph database                # RebuildGraph.feature:19
    Given There is a default multirepo server                                          # WebAPICucumberHooks.setUpDefaultMultiRepo()
    And The graph database on the "repo1" repo has been truncated                      # WebAPICucumberHooks.Truncate_graph_database(String)
    When I call "GET /repos/repo1/rebuildgraph"                                        # WebAPICucumberHooks.callURL(String)
    Then the response status should be '200'                                           # WebAPICucumberHooks.checkStatusCode(int)
    And the xpath "/response/success/text()" equals "true"                             # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xpath "/response/RebuildGraph/updatedGraphElements/text()" equals "4"      # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xml response should contain "/response/RebuildGraph/UpdatedObject" 4 times # WebAPICucumberHooks.checkXPathCadinality(String,int)
    And the response body should contain "{@ObjectId|repo1|master}"                    # WebAPICucumberHooks.checkResponseTextContains(String)
    And the response body should contain "{@ObjectId|repo1|branch1}"                   # WebAPICucumberHooks.checkResponseTextContains(String)
    And the response body should contain "{@ObjectId|repo1|branch2}"                   # WebAPICucumberHooks.checkResponseTextContains(String)
    And the response body should contain "{@ObjectId|repo1|master~1}"                  # WebAPICucumberHooks.checkResponseTextContains(String)
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo1 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo2 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()

  Scenario: The quiet flag prevents all of the restored commits from being reported    # RebuildGraph.feature:32
    Given There is a default multirepo server                                          # WebAPICucumberHooks.setUpDefaultMultiRepo()
    And The graph database on the "repo1" repo has been truncated                      # WebAPICucumberHooks.Truncate_graph_database(String)
    When I call "GET /repos/repo1/rebuildgraph?quiet=true"                             # WebAPICucumberHooks.callURL(String)
    Then the response status should be '200'                                           # WebAPICucumberHooks.checkStatusCode(int)
    And the xpath "/response/success/text()" equals "true"                             # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xpath "/response/RebuildGraph/updatedGraphElements/text()" equals "4"      # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xml response should contain "/response/RebuildGraph/UpdatedObject" 0 times # WebAPICucumberHooks.checkXPathCadinality(String,int)
@Commands @RefParse
Feature: RefParse
  The RefParse command allows a user to get the details of a ref by name and is supported through the "/repos/{repository}/refparse" endpoint
  The command must be executed using the HTTP GET method
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo1 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()

  Scenario: Verify wrong HTTP method issues 405 "Method not allowed" # RefParse.feature:6
    Given There is an empty repository named repo1                   # WebAPICucumberHooks.setUpEmptyRepo(String)
    When I call "PUT /repos/repo1/refparse"                          # WebAPICucumberHooks.callURL(String)
    Then the response status should be '405'                         # WebAPICucumberHooks.checkStatusCode(int)
    And the response allowed methods should be "GET"                 # WebAPICucumberHooks.checkResponseAllowedMethods(String)
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo1 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()

  Scenario: RefParse outside of a repository issues 404 "Not found" # RefParse.feature:12
    Given There is an empty multirepo server                        # WebAPICucumberHooks.setUpEmptyMultiRepo()
    When I call "GET /repos/repo1/refparse?name=someRef"            # WebAPICucumberHooks.callURL(String)
    Then the response status should be '404'                        # WebAPICucumberHooks.checkStatusCode(int)
    And the response ContentType should be "text/plain"             # WebAPICucumberHooks.checkContentType(String)
    And the response body should contain "Repository not found"     # WebAPICucumberHooks.checkResponseTextContains(String)
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo1 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()

  Scenario: Calling RefParse without a ref name issues a 500 status code                        # RefParse.feature:19
    Given There is an empty repository named repo1                                              # WebAPICucumberHooks.setUpEmptyRepo(String)
    When I call "GET /repos/repo1/refparse"                                                     # WebAPICucumberHooks.callURL(String)
    Then the response status should be '500'                                                    # WebAPICucumberHooks.checkStatusCode(int)
    And the xpath "/response/error/text()" equals "Required parameter 'name' was not provided." # WebAPICucumberHooks.checkXPathEquals(String,String)
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo1 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()

  Scenario: Calling RefParse with a nonexistent name issues a 500 status code          # RefParse.feature:25
    Given There is an empty repository named repo1                                     # WebAPICucumberHooks.setUpEmptyRepo(String)
    When I call "GET /repos/repo1/refparse?name=nonexistent"                           # WebAPICucumberHooks.callURL(String)
    Then the response status should be '500'                                           # WebAPICucumberHooks.checkStatusCode(int)
    And the xpath "/response/error/text()" equals "Unable to parse the provided name." # WebAPICucumberHooks.checkXPathEquals(String,String)
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo1 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo2 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()

  Scenario: Calling RefParse with a ref name returns the details of that ref        # RefParse.feature:31
    Given There is a default multirepo server                                       # WebAPICucumberHooks.setUpDefaultMultiRepo()
    When I call "GET /repos/repo1/refparse?name=master"                             # WebAPICucumberHooks.callURL(String)
    Then the response status should be '200'                                        # WebAPICucumberHooks.checkStatusCode(int)
    And the xpath "/response/success/text()" equals "true"                          # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xpath "/response/Ref/name/text()" equals "refs/heads/master"            # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xpath "/response/Ref/objectId/text()" equals "{@ObjectId|repo1|master}" # WebAPICucumberHooks.checkXPathEquals(String,String)
@Commands @Remote
Feature: Remote
  The remote command allows a user to manage the remotes of a repository and is supported through the "/repos/{repository}/remote" endpoint
  The command must be executed using the HTTP GET method
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo1 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()

  Scenario: Verify wrong HTTP method issues 405 "Method not allowed" # RemoteManagement.feature:6
    Given There is an empty repository named repo1                   # WebAPICucumberHooks.setUpEmptyRepo(String)
    When I call "PUT /repos/repo1/remote"                            # WebAPICucumberHooks.callURL(String)
    Then the response status should be '405'                         # WebAPICucumberHooks.checkStatusCode(int)
    And the response allowed methods should be "GET"                 # WebAPICucumberHooks.checkResponseAllowedMethods(String)
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo1 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()

  Scenario: Remote outside of a repository issues 404 "Not found" # RemoteManagement.feature:12
    Given There is an empty multirepo server                      # WebAPICucumberHooks.setUpEmptyMultiRepo()
    When I call "GET /repos/repo1/remote"                         # WebAPICucumberHooks.callURL(String)
    Then the response status should be '404'                      # WebAPICucumberHooks.checkStatusCode(int)
    And the response ContentType should be "text/plain"           # WebAPICucumberHooks.checkContentType(String)
    And the response body should contain "Repository not found"   # WebAPICucumberHooks.checkResponseTextContains(String)
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo3 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo4 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo2 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo1 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()

  Scenario: Supplying the list parameter will list all remotes     # RemoteManagement.feature:19
    Given There is a default multirepo server with remotes         # WebAPICucumberHooks.setUpDefaultMultiRepoWithRemotes()
    When I call "GET /repos/repo3/remote?list=true"                # WebAPICucumberHooks.callURL(String)
    Then the response status should be '200'                       # WebAPICucumberHooks.checkStatusCode(int)
    And the xpath "/response/success/text()" equals "true"         # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xml response should contain "/response/Remote" 2 times # WebAPICucumberHooks.checkXPathCadinality(String,int)
    And the response body should contain "repo1"                   # WebAPICucumberHooks.checkResponseTextContains(String)
    And the response body should contain "repo2"                   # WebAPICucumberHooks.checkResponseTextContains(String)
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo2 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo4 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo3 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo1 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()

  Scenario: Supplying the list parameter with verbose will list more detail of all remotes # RemoteManagement.feature:28
    Given There is a default multirepo server with remotes                                 # WebAPICucumberHooks.setUpDefaultMultiRepoWithRemotes()
    When I call "GET /repos/repo2/remote?list=true&verbose=true"                           # WebAPICucumberHooks.callURL(String)
    Then the response status should be '200'                                               # WebAPICucumberHooks.checkStatusCode(int)
    And the xpath "/response/success/text()" equals "true"                                 # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xpath "/response/Remote/name/text()" equals "origin"                           # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xml response should contain "/response/Remote/url" 1 times                     # WebAPICucumberHooks.checkXPathCadinality(String,int)
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo3 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo4 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo2 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo1 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()

  Scenario: Supplying the ping parameter without a remote name issues a 400 status code # RemoteManagement.feature:36
    Given There is a default multirepo server with remotes                              # WebAPICucumberHooks.setUpDefaultMultiRepoWithRemotes()
    When I call "GET /repos/repo3/remote?ping=true"                                     # WebAPICucumberHooks.callURL(String)
    Then the response status should be '400'                                            # WebAPICucumberHooks.checkStatusCode(int)
    And the xpath "/response/error/text()" equals "MISSING_NAME"                        # WebAPICucumberHooks.checkXPathEquals(String,String)
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo3 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo4 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo2 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo1 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()

  Scenario: Pinging a reachable remote returns as successful         # RemoteManagement.feature:42
    Given There is a default multirepo server with remotes           # WebAPICucumberHooks.setUpDefaultMultiRepoWithRemotes()
    When I call "GET /repos/repo3/remote?remoteName=repo1&ping=true" # WebAPICucumberHooks.callURL(String)
    Then the response status should be '200'                         # WebAPICucumberHooks.checkStatusCode(int)
    And the xpath "/response/success/text()" equals "true"           # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xpath "/response/ping/success/text()" equals "true"      # WebAPICucumberHooks.checkXPathEquals(String,String)
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo3 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo4 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo2 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo1 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()

  Scenario: Pinging a nonexistent remote returns as not successful         # RemoteManagement.feature:49
    Given There is a default multirepo server with remotes                 # WebAPICucumberHooks.setUpDefaultMultiRepoWithRemotes()
    When I call "GET /repos/repo3/remote?remoteName=nonexistent&ping=true" # WebAPICucumberHooks.callURL(String)
    Then the response status should be '200'                               # WebAPICucumberHooks.checkStatusCode(int)
    And the xpath "/response/success/text()" equals "true"                 # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xpath "/response/ping/success/text()" equals "false"           # WebAPICucumberHooks.checkXPathEquals(String,String)
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo3 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo4 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo2 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo1 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()

  Scenario: Supplying the remove parameter without a remote name issues a 500 status code # RemoteManagement.feature:56
    Given There is a default multirepo server with remotes                                # WebAPICucumberHooks.setUpDefaultMultiRepoWithRemotes()
    When I call "GET /repos/repo3/remote?remove=true"                                     # WebAPICucumberHooks.callURL(String)
    Then the response status should be '500'                                              # WebAPICucumberHooks.checkStatusCode(int)
    And the xpath "/response/error/text()" equals "No remote was specified."              # WebAPICucumberHooks.checkXPathEquals(String,String)
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo3 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo4 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo2 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo1 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()

  Scenario: Removing a nonexistent remote issues a 400 status code           # RemoteManagement.feature:62
    Given There is a default multirepo server with remotes                   # WebAPICucumberHooks.setUpDefaultMultiRepoWithRemotes()
    When I call "GET /repos/repo3/remote?remove=true&remoteName=nonexistent" # WebAPICucumberHooks.callURL(String)
    Then the response status should be '400'                                 # WebAPICucumberHooks.checkStatusCode(int)
    And the xpath "/response/error/text()" equals "REMOTE_NOT_FOUND"         # WebAPICucumberHooks.checkXPathEquals(String,String)
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo3 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo4 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo2 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo1 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()

  Scenario: Removing a valid remote name removes the remote            # RemoteManagement.feature:68
    Given There is a default multirepo server with remotes             # WebAPICucumberHooks.setUpDefaultMultiRepoWithRemotes()
    When I call "GET /repos/repo3/remote?remove=true&remoteName=repo1" # WebAPICucumberHooks.callURL(String)
    Then the response status should be '200'                           # WebAPICucumberHooks.checkStatusCode(int)
    And the xpath "/response/success/text()" equals "true"             # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xpath "/response/name/text()" equals "repo1"               # WebAPICucumberHooks.checkXPathEquals(String,String)
    When I call "GET /repos/repo3/remote?list=true"                    # WebAPICucumberHooks.callURL(String)
    Then the response status should be '200'                           # WebAPICucumberHooks.checkStatusCode(int)
    And the xpath "/response/success/text()" equals "true"             # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xml response should contain "/response/Remote" 1 times     # WebAPICucumberHooks.checkXPathCadinality(String,int)
    And the response body should not contain "repo1"                   # WebAPICucumberHooks.checkResponseTextNotContains(String)
    And the response body should contain "repo2"                       # WebAPICucumberHooks.checkResponseTextContains(String)
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo3 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo4 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo2 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo1 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()

  Scenario: Supplying the update parameter without a remote name issues a 500 status code # RemoteManagement.feature:81
    Given There is a default multirepo server with remotes                                # WebAPICucumberHooks.setUpDefaultMultiRepoWithRemotes()
    When I call "GET /repos/repo3/remote?update=true"                                     # WebAPICucumberHooks.callURL(String)
    Then the response status should be '500'                                              # WebAPICucumberHooks.checkStatusCode(int)
    And the xpath "/response/error/text()" equals "No remote was specified."              # WebAPICucumberHooks.checkXPathEquals(String,String)
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo3 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo4 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo2 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo1 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()

  Scenario: Supplying the update parameter without a remote url issues a 500 status code # RemoteManagement.feature:87
    Given There is a default multirepo server with remotes                               # WebAPICucumberHooks.setUpDefaultMultiRepoWithRemotes()
    When I call "GET /repos/repo3/remote?update=true&remoteName=repo1"                   # WebAPICucumberHooks.callURL(String)
    Then the response status should be '500'                                             # WebAPICucumberHooks.checkStatusCode(int)
    And the xpath "/response/error/text()" equals "No URL was specified."                # WebAPICucumberHooks.checkXPathEquals(String,String)
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo2 using FileRepositoryResolver
java.lang.IllegalArgumentException: Update indexes does not support symbolic references
	at com.google.common.base.Preconditions.checkArgument(Preconditions.java:122)
	at org.locationtech.geogig.porcelain.index.UpdateIndexesOp.setRef(UpdateIndexesOp.java:49)
	at org.locationtech.geogig.hooks.builtin.UpdateIndexesHook.post(UpdateIndexesHook.java:56)
	at org.locationtech.geogig.hooks.CommandHookChain.runPostHooks(CommandHookChain.java:65)
	at org.locationtech.geogig.hooks.CommandHooksDecorator$HooksListener.postCall(CommandHooksDecorator.java:60)
	at org.locationtech.geogig.repository.AbstractGeoGigOp.notifyPost(AbstractGeoGigOp.java:179)
	at org.locationtech.geogig.repository.AbstractGeoGigOp.call(AbstractGeoGigOp.java:155)
	at org.locationtech.geogig.porcelain.RemoteRemoveOp._call(RemoteRemoveOp.java:76)
	at org.locationtech.geogig.porcelain.RemoteRemoveOp._call(RemoteRemoveOp.java:31)
	at org.locationtech.geogig.repository.AbstractGeoGigOp.call(AbstractGeoGigOp.java:154)
	at org.locationtech.geogig.web.api.commands.RemoteManagement.remoteUpdate(RemoteManagement.java:229)
	at org.locationtech.geogig.web.api.commands.RemoteManagement.runInternal(RemoteManagement.java:187)
	at org.locationtech.geogig.web.api.AbstractWebAPICommand.run(AbstractWebAPICommand.java:147)
	at org.locationtech.geogig.rest.repository.CommandResource.runCommand(CommandResource.java:252)
	at org.locationtech.geogig.rest.repository.CommandResource.processRequest(CommandResource.java:193)
	at org.locationtech.geogig.rest.repository.CommandResource.getRepresentation(CommandResource.java:239)
	at org.restlet.resource.Resource.handleGet(Resource.java:415)
	at org.restlet.Finder.handle(Finder.java:292)
	at org.restlet.Filter.doHandle(Filter.java:105)
	at org.restlet.Filter.handle(Filter.java:134)
	at org.restlet.Router.handle(Router.java:444)
	at org.restlet.Filter.doHandle(Filter.java:105)
	at org.restlet.Filter.handle(Filter.java:134)
	at org.restlet.Router.handle(Router.java:444)
	at org.restlet.Filter.doHandle(Filter.java:105)
	at org.restlet.Filter.handle(Filter.java:134)
	at org.restlet.Filter.doHandle(Filter.java:105)
	at org.restlet.Filter.handle(Filter.java:134)
	at org.restlet.Filter.doHandle(Filter.java:105)
	at org.restlet.Filter.handle(Filter.java:134)
	at org.restlet.Filter.doHandle(Filter.java:105)
	at com.noelios.restlet.StatusFilter.doHandle(StatusFilter.java:87)
	at org.restlet.Filter.handle(Filter.java:134)
	at org.restlet.Filter.doHandle(Filter.java:105)
	at org.restlet.Filter.handle(Filter.java:134)
	at com.noelios.restlet.application.ApplicationHelper.handle(ApplicationHelper.java:96)
	at org.restlet.Application.handle(Application.java:293)
	at org.restlet.Uniform.handle(Uniform.java:97)
	at org.geogig.web.functional.DefaultFunctionalTestContext.callInternal(DefaultFunctionalTestContext.java:223)
	at org.geogig.web.functional.FunctionalTestContext.call(FunctionalTestContext.java:290)
	at org.geogig.web.functional.WebAPICucumberHooks.callURL(WebAPICucumberHooks.java:659)
	at sun.reflect.GeneratedMethodAccessor52.invoke(Unknown Source)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:498)
	at cucumber.runtime.Utils$1.call(Utils.java:37)
	at cucumber.runtime.Timeout.timeout(Timeout.java:13)
	at cucumber.runtime.Utils.invoke(Utils.java:31)
	at cucumber.runtime.java.JavaStepDefinition.execute(JavaStepDefinition.java:38)
	at cucumber.runtime.StepDefinitionMatch.runStep(StepDefinitionMatch.java:37)
	at cucumber.runtime.Runtime.runStep(Runtime.java:299)
	at cucumber.runtime.model.StepContainer.runStep(StepContainer.java:44)
	at cucumber.runtime.model.StepContainer.runSteps(StepContainer.java:39)
	at cucumber.runtime.model.CucumberScenario.run(CucumberScenario.java:44)
	at cucumber.runtime.junit.ExecutionUnitRunner.run(ExecutionUnitRunner.java:91)
	at cucumber.runtime.junit.FeatureRunner.runChild(FeatureRunner.java:63)
	at cucumber.runtime.junit.FeatureRunner.runChild(FeatureRunner.java:18)
	at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
	at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
	at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
	at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
	at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
	at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
	at cucumber.runtime.junit.FeatureRunner.run(FeatureRunner.java:70)
	at cucumber.api.junit.Cucumber.runChild(Cucumber.java:93)
	at cucumber.api.junit.Cucumber.runChild(Cucumber.java:37)
	at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
	at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
	at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
	at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
	at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
	at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
	at cucumber.api.junit.Cucumber.run(Cucumber.java:98)
	at org.apache.maven.surefire.junit4.JUnit4Provider.execute(JUnit4Provider.java:264)
	at org.apache.maven.surefire.junit4.JUnit4Provider.executeTestSet(JUnit4Provider.java:153)
	at org.apache.maven.surefire.junit4.JUnit4Provider.invoke(JUnit4Provider.java:124)
	at org.apache.maven.surefire.booter.ForkedBooter.invokeProviderInSameClassLoader(ForkedBooter.java:200)
	at org.apache.maven.surefire.booter.ForkedBooter.runSuitesInProcess(ForkedBooter.java:153)
	at org.apache.maven.surefire.booter.ForkedBooter.main(ForkedBooter.java:103)
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo4 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo3 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo1 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()

  Scenario: Supplying a new url with the update parameter updates a remote               # RemoteManagement.feature:93
    Given There is a default multirepo server with remotes                               # WebAPICucumberHooks.setUpDefaultMultiRepoWithRemotes()
    When I call "GET /repos/repo2/remote?update=true&remoteName=origin&remoteURL=newUrl" # WebAPICucumberHooks.callURL(String)
    Then the response status should be '200'                                             # WebAPICucumberHooks.checkStatusCode(int)
    And the xpath "/response/success/text()" equals "true"                               # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xpath "/response/name/text()" equals "origin"                                # WebAPICucumberHooks.checkXPathEquals(String,String)
    When I call "GET /repos/repo2/remote?list=true&verbose=true"                         # WebAPICucumberHooks.callURL(String)
    Then the response status should be '200'                                             # WebAPICucumberHooks.checkStatusCode(int)
    And the xpath "/response/success/text()" equals "true"                               # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xpath "/response/Remote/name/text()" equals "origin"                         # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xpath "/response/Remote/url/text()" equals "newUrl"                          # WebAPICucumberHooks.checkXPathEquals(String,String)
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo3 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo4 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo2 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo1 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()

  Scenario: Supplying a new name with the update parameter renames a remote                               # RemoteManagement.feature:105
    Given There is a default multirepo server with remotes                                                # WebAPICucumberHooks.setUpDefaultMultiRepoWithRemotes()
    When I call "GET /repos/repo3/remote?update=true&remoteName=repo1&remoteURL=repo1url&newName=renamed" # WebAPICucumberHooks.callURL(String)
    Then the response status should be '200'                                                              # WebAPICucumberHooks.checkStatusCode(int)
    And the xpath "/response/success/text()" equals "true"                                                # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xpath "/response/name/text()" equals "renamed"                                                # WebAPICucumberHooks.checkXPathEquals(String,String)
    When I call "GET /repos/repo3/remote?list=true"                                                       # WebAPICucumberHooks.callURL(String)
    Then the response status should be '200'                                                              # WebAPICucumberHooks.checkStatusCode(int)
    And the xpath "/response/success/text()" equals "true"                                                # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xml response should contain "/response/Remote" 2 times                                        # WebAPICucumberHooks.checkXPathCadinality(String,int)
    And the response body should contain "renamed"                                                        # WebAPICucumberHooks.checkResponseTextContains(String)
    And the response body should contain "repo2"                                                          # WebAPICucumberHooks.checkResponseTextContains(String)
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo3 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo4 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo2 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo1 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()

  Scenario: Supplying the add parameter without a remote name issues a 500 status code # RemoteManagement.feature:118
    Given There is a default multirepo server with remotes                             # WebAPICucumberHooks.setUpDefaultMultiRepoWithRemotes()
    When I call "GET /repos/repo3/remote?add=true"                                     # WebAPICucumberHooks.callURL(String)
    Then the response status should be '500'                                           # WebAPICucumberHooks.checkStatusCode(int)
    And the xpath "/response/error/text()" equals "No remote was specified."           # WebAPICucumberHooks.checkXPathEquals(String,String)
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo3 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo4 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo2 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo1 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()

  Scenario: Supplying the add parameter without a remote url issues a 500 status code # RemoteManagement.feature:124
    Given There is a default multirepo server with remotes                            # WebAPICucumberHooks.setUpDefaultMultiRepoWithRemotes()
    When I call "GET /repos/repo3/remote?add=true&remoteName=newRemote"               # WebAPICucumberHooks.callURL(String)
    Then the response status should be '500'                                          # WebAPICucumberHooks.checkStatusCode(int)
    And the xpath "/response/error/text()" equals "No URL was specified."             # WebAPICucumberHooks.checkXPathEquals(String,String)
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo3 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo4 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo2 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo1 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()

  Scenario: Supplying add with valid parameters adds a new remote                        # RemoteManagement.feature:130
    Given There is a default multirepo server with remotes                               # WebAPICucumberHooks.setUpDefaultMultiRepoWithRemotes()
    When I call "GET /repos/repo3/remote?add=true&remoteName=newRemote&remoteURL=newUrl" # WebAPICucumberHooks.callURL(String)
    Then the response status should be '200'                                             # WebAPICucumberHooks.checkStatusCode(int)
    And the xpath "/response/success/text()" equals "true"                               # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xpath "/response/name/text()" equals "newRemote"                             # WebAPICucumberHooks.checkXPathEquals(String,String)
    When I call "GET /repos/repo3/remote?list=true"                                      # WebAPICucumberHooks.callURL(String)
    Then the response status should be '200'                                             # WebAPICucumberHooks.checkStatusCode(int)
    And the xpath "/response/success/text()" equals "true"                               # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xml response should contain "/response/Remote" 3 times                       # WebAPICucumberHooks.checkXPathCadinality(String,int)
    And the response body should contain "repo1"                                         # WebAPICucumberHooks.checkResponseTextContains(String)
    And the response body should contain "repo2"                                         # WebAPICucumberHooks.checkResponseTextContains(String)
    And the response body should contain "newRemote"                                     # WebAPICucumberHooks.checkResponseTextContains(String)
@Commands @Remove
Feature: Remove
  The remove command allows a user to remove features from the repository and is supported through the "/repos/{repository}/remove" endpoint
  The command must be executed using the HTTP GET method
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo1 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()

  Scenario: Verify wrong HTTP method issues 405 "Method not allowed" # Remove.feature:6
    Given There is an empty repository named repo1                   # WebAPICucumberHooks.setUpEmptyRepo(String)
    When I call "PUT /repos/repo1/remove"                            # WebAPICucumberHooks.callURL(String)
    Then the response status should be '405'                         # WebAPICucumberHooks.checkStatusCode(int)
    And the response allowed methods should be "GET"                 # WebAPICucumberHooks.checkResponseAllowedMethods(String)
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo1 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()

  Scenario: Removing outside of a transaction issues 500 "Transaction required"    # Remove.feature:12
    Given There is an empty repository named repo1                                 # WebAPICucumberHooks.setUpEmptyRepo(String)
    When I call "GET /repos/repo1/remove?path=somePath"                            # WebAPICucumberHooks.callURL(String)
    Then the response status should be '500'                                       # WebAPICucumberHooks.checkStatusCode(int)
    And the xpath "/response/error/text()" contains "No transaction was specified" # WebAPICucumberHooks.checkXPathValueContains(String,String)
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo1 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()

  Scenario: Removing outside of a repository issues 404 "Not found" # Remove.feature:18
    Given There is an empty multirepo server                        # WebAPICucumberHooks.setUpEmptyMultiRepo()
    When I call "GET /repos/repo1/remove?path=somePath"             # WebAPICucumberHooks.callURL(String)
    Then the response status should be '404'                        # WebAPICucumberHooks.checkStatusCode(int)
    And the response ContentType should be "text/plain"             # WebAPICucumberHooks.checkContentType(String)
    And the response body should contain "Repository not found"     # WebAPICucumberHooks.checkResponseTextContains(String)
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo1 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()

  Scenario: Removing with no path issues a 500 status code                                      # Remove.feature:25
    Given There is an empty repository named repo1                                              # WebAPICucumberHooks.setUpEmptyRepo(String)
    And I have a transaction as "@txId" on the "repo1" repo                                     # WebAPICucumberHooks.beginTransactionAsVariable(String,String)
    When I call "GET /repos/repo1/remove?transactionId={@txId}"                                 # WebAPICucumberHooks.callURL(String)
    Then the response status should be '500'                                                    # WebAPICucumberHooks.checkStatusCode(int)
    And the xpath "/response/error/text()" equals "Required parameter 'path' was not provided." # WebAPICucumberHooks.checkXPathEquals(String,String)
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo1 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo2 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()

  Scenario: Removing with a feature path removes the specified feature                                   # Remove.feature:32
    Given There is a default multirepo server                                                            # WebAPICucumberHooks.setUpDefaultMultiRepo()
    And I have a transaction as "@txId" on the "repo1" repo                                              # WebAPICucumberHooks.beginTransactionAsVariable(String,String)
    And the repo1 repository's "STAGE_HEAD" in the @txId transaction should have the following features: # WebAPICucumberHooks.verifyRepositoryContentsTx(String,String,String,DataTable)
    When I call "GET /repos/repo1/remove?path=Points/Point.1&transactionId={@txId}"                      # WebAPICucumberHooks.callURL(String)
    Then the response status should be '200'                                                             # WebAPICucumberHooks.checkStatusCode(int)
    And the xpath "/response/success/text()" equals "true"                                               # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xpath "/response/Deleted/text()" equals "Points/Point.1"                                     # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the repo1 repository's "STAGE_HEAD" in the @txId transaction should have the following features: # WebAPICucumberHooks.verifyRepositoryContentsTx(String,String,String,DataTable)
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo1 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo2 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()

  Scenario: Removing with a tree path and no recursive parameter issues a 400 status code                               # Remove.feature:50
    Given There is a default multirepo server                                                                           # WebAPICucumberHooks.setUpDefaultMultiRepo()
    And I have a transaction as "@txId" on the "repo1" repo                                                             # WebAPICucumberHooks.beginTransactionAsVariable(String,String)
    When I call "GET /repos/repo1/remove?path=Points&transactionId={@txId}"                                             # WebAPICucumberHooks.callURL(String)
    Then the response status should be '400'                                                                            # WebAPICucumberHooks.checkStatusCode(int)
    And the xpath "/response/error/text()" equals "Cannot remove tree Points if recursive or truncate is not specified" # WebAPICucumberHooks.checkXPathEquals(String,String)
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo1 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo2 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()

  Scenario: Removing with a tree path and the recursive parameter removes the specified feature tree     # Remove.feature:57
    Given There is a default multirepo server                                                            # WebAPICucumberHooks.setUpDefaultMultiRepo()
    And I have a transaction as "@txId" on the "repo1" repo                                              # WebAPICucumberHooks.beginTransactionAsVariable(String,String)
    And the repo1 repository's "STAGE_HEAD" in the @txId transaction should have the following features: # WebAPICucumberHooks.verifyRepositoryContentsTx(String,String,String,DataTable)
    When I call "GET /repos/repo1/remove?path=Points&recursive=true&transactionId={@txId}"               # WebAPICucumberHooks.callURL(String)
    Then the response status should be '200'                                                             # WebAPICucumberHooks.checkStatusCode(int)
    And the xpath "/response/success/text()" equals "true"                                               # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xpath "/response/Deleted/text()" equals "Points"                                             # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the repo1 repository's "STAGE_HEAD" in the @txId transaction should have the following features: # WebAPICucumberHooks.verifyRepositoryContentsTx(String,String,String,DataTable)
@RepositoryManagement @RenameRepository
Feature: Rename repository
  Repositories being served throught the Web API are served through the "/repos/<repository name>" entry point.
  The name of a repository is unique across a Web API instance.
  Renaming a repository is done through a "POST /repos/<repository name>/rename?name={new name}" call.
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository nonExistingRepo using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()

  Scenario: Calling rename to a non existing repo issues 404 "Not Found" # RenameRepository.feature:7
    Given There is an empty multirepo server                             # WebAPICucumberHooks.setUpEmptyMultiRepo()
    When I call "POST /repos/nonExistingRepo/rename?name=renamedRepo"    # WebAPICucumberHooks.callURL(String)
    Then the response status should be '404'                             # WebAPICucumberHooks.checkStatusCode(int)
    And the response ContentType should be "text/plain"                  # WebAPICucumberHooks.checkContentType(String)
    And the response body should contain "Repository not found"          # WebAPICucumberHooks.checkResponseTextContains(String)
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo2 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo1 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()

  Scenario: Calling rename on a repo using the wrong HTTP method issues 405 "Method not allowed" # RenameRepository.feature:14
    Given There is a default multirepo server                                                    # WebAPICucumberHooks.setUpDefaultMultiRepo()
    When I call "GET /repos/repo1/rename?name=renamedRepo"                                       # WebAPICucumberHooks.callURL(String)
    Then the response status should be '405'                                                     # WebAPICucumberHooks.checkStatusCode(int)
    And the response allowed methods should be "POST"                                            # WebAPICucumberHooks.checkResponseAllowedMethods(String)
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo1 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo2 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()

  Scenario: Trying to assign a duplicated name to a repo issues 400 "Bad request"               # RenameRepository.feature:20
    Given There is a default multirepo server                                                   # WebAPICucumberHooks.setUpDefaultMultiRepo()
    When I call "POST /repos/repo1/rename?name=repo2"                                           # WebAPICucumberHooks.callURL(String)
    Then the response status should be '400'                                                    # WebAPICucumberHooks.checkStatusCode(int)
    And the response ContentType should be "application/xml"                                    # WebAPICucumberHooks.checkContentType(String)
    And the xpath "/response/success/text()" equals "false"                                     # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xpath "/response/error/text()" equals "A repository with that name already exists." # WebAPICucumberHooks.checkXPathEquals(String,String)
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo1 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo2 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()

  Scenario: Renaming a repository returns a link to the new location issues 301 "Moved permanently" # RenameRepository.feature:28
    Given There is a default multirepo server                                                       # WebAPICucumberHooks.setUpDefaultMultiRepo()
    When I call "POST /repos/repo1/rename?name=repo1Renamed"                                        # WebAPICucumberHooks.callURL(String)
    Then the response status should be '301'                                                        # WebAPICucumberHooks.checkStatusCode(int)
    And the response ContentType should be "application/xml"                                        # WebAPICucumberHooks.checkContentType(String)
    And the xpath "/response/success/text()" equals "true"                                          # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xpath "/response/repo/name/text()" equals "repo1Renamed"                                # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xpath "/response/repo/atom:link/@href" contains "/repos/repo1Renamed.xml"               # WebAPICucumberHooks.checkXPathValueContains(String,String)
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository nonExistingRepo using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()

  Scenario: Calling rename to a non existing repo issues 404 "Not Found", JSON requested response # RenameRepository.feature:37
    Given There is an empty multirepo server                                                      # WebAPICucumberHooks.setUpEmptyMultiRepo()
    When I call "POST /repos/nonExistingRepo/rename.json?name=renamedRepo"                        # WebAPICucumberHooks.callURL(String)
    Then the response status should be '404'                                                      # WebAPICucumberHooks.checkStatusCode(int)
    And the response ContentType should be "text/plain"                                           # WebAPICucumberHooks.checkContentType(String)
    And the response body should contain "Repository not found"                                   # WebAPICucumberHooks.checkResponseTextContains(String)
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo2 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo1 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()

  Scenario: Calling rename on a repo using the wrong HTTP method issues 405 "Method not allowed", JSON requested response # RenameRepository.feature:44
    Given There is a default multirepo server                                                                             # WebAPICucumberHooks.setUpDefaultMultiRepo()
    When I call "GET /repos/repo1/rename.json?name=renamedRepo"                                                           # WebAPICucumberHooks.callURL(String)
    Then the response status should be '405'                                                                              # WebAPICucumberHooks.checkStatusCode(int)
    And the response allowed methods should be "POST"                                                                     # WebAPICucumberHooks.checkResponseAllowedMethods(String)
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo1 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo2 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()

  Scenario: Trying to assign a duplicated name to a repo issues 400 "Bad request", JSON requested response # RenameRepository.feature:51
    Given There is a default multirepo server                                                              # WebAPICucumberHooks.setUpDefaultMultiRepo()
    When I call "POST /repos/repo1/rename.json?name=repo2"                                                 # WebAPICucumberHooks.callURL(String)
    Then the response status should be '400'                                                               # WebAPICucumberHooks.checkStatusCode(int)
    And the response ContentType should be "application/json"                                              # WebAPICucumberHooks.checkContentType(String)
    And the json object "response.success" equals "false"                                                  # WebAPICucumberHooks.checkJSONResponse(String,String)
    And the json object "response.error" equals "A repository with that name already exists."              # WebAPICucumberHooks.checkJSONResponse(String,String)
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo1 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo2 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()

  Scenario: Renaming a repository returns a link to the new location issues 301 "Moved permanently", JSON requested response # RenameRepository.feature:59
    Given There is a default multirepo server                                                                                # WebAPICucumberHooks.setUpDefaultMultiRepo()
    When I call "POST /repos/repo1/rename.json?name=repo1Renamed"                                                            # WebAPICucumberHooks.callURL(String)
    Then the response status should be '301'                                                                                 # WebAPICucumberHooks.checkStatusCode(int)
    And the response ContentType should be "application/json"                                                                # WebAPICucumberHooks.checkContentType(String)
    And the json object "response.success" equals "true"                                                                     # WebAPICucumberHooks.checkJSONResponse(String,String)
    And the json object "response.repo.name" equals "repo1Renamed"                                                           # WebAPICucumberHooks.checkJSONResponse(String,String)
    And the json object "response.repo.href" ends with "/repos/repo1Renamed.json"                                            # WebAPICucumberHooks.checkJSONResponseEndsWith(String,String)
@Commands @ReportMergeScenario
Feature: ReportMergeScenario
  The ReportMergeScenario command allows a user to see the results of a merge between two branches and is supported through the "/repos/{repository}/reportMergeScenario" endpoint
  The command must be executed using the HTTP GET method
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo1 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()

  Scenario: Verify wrong HTTP method issues 405 "Method not allowed" # ReportMergeScenario.feature:6
    Given There is an empty repository named repo1                   # WebAPICucumberHooks.setUpEmptyRepo(String)
    When I call "PUT /repos/repo1/reportMergeScenario"               # WebAPICucumberHooks.callURL(String)
    Then the response status should be '405'                         # WebAPICucumberHooks.checkStatusCode(int)
    And the response allowed methods should be "GET"                 # WebAPICucumberHooks.checkResponseAllowedMethods(String)
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo1 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()

  Scenario: ReportMergeScenario outside of a repository issues 404 "Not found"              # ReportMergeScenario.feature:12
    Given There is an empty multirepo server                                                # WebAPICucumberHooks.setUpEmptyMultiRepo()
    When I call "GET /repos/repo1/reportMergeScenario?ourCommit=master&theirCommit=branch1" # WebAPICucumberHooks.callURL(String)
    Then the response status should be '404'                                                # WebAPICucumberHooks.checkStatusCode(int)
    And the response ContentType should be "text/plain"                                     # WebAPICucumberHooks.checkContentType(String)
    And the response body should contain "Repository not found"                             # WebAPICucumberHooks.checkResponseTextContains(String)
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo1 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()

  Scenario: Calling ReportMergeScenario with no "our" commit issues a 500 status code                # ReportMergeScenario.feature:19
    Given There is an empty repository named repo1                                                   # WebAPICucumberHooks.setUpEmptyRepo(String)
    When I call "GET /repos/repo1/reportMergeScenario?theirCommit=branch1"                           # WebAPICucumberHooks.callURL(String)
    Then the response status should be '500'                                                         # WebAPICucumberHooks.checkStatusCode(int)
    And the xpath "/response/error/text()" equals "Required parameter 'ourCommit' was not provided." # WebAPICucumberHooks.checkXPathEquals(String,String)
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo1 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()

  Scenario: Calling ReportMergeScenario with no "their" commit issues a 500 status code                # ReportMergeScenario.feature:25
    Given There is an empty repository named repo1                                                     # WebAPICucumberHooks.setUpEmptyRepo(String)
    When I call "GET /repos/repo1/reportMergeScenario?ourCommit=master"                                # WebAPICucumberHooks.callURL(String)
    Then the response status should be '500'                                                           # WebAPICucumberHooks.checkStatusCode(int)
    And the xpath "/response/error/text()" equals "Required parameter 'theirCommit' was not provided." # WebAPICucumberHooks.checkXPathEquals(String,String)
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo1 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()

  Scenario: Calling ReportMergeScenario with an invalid "our" commit issues a 500 status code              # ReportMergeScenario.feature:31
    Given There is a repository with multiple branches named repo1                                         # WebAPICucumberHooks.setUpMultipleBranches(String)
    When I call "GET /repos/repo1/reportMergeScenario?ourCommit=nonexistent&theirCommit=branch1"           # WebAPICucumberHooks.callURL(String)
    Then the response status should be '500'                                                               # WebAPICucumberHooks.checkStatusCode(int)
    And the xpath "/response/error/text()" equals "'our' commit could not be resolved to a commit object." # WebAPICucumberHooks.checkXPathEquals(String,String)
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo1 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()

  Scenario: Calling ReportMergeScenario with an invalid "their" commit issues a 500 status code              # ReportMergeScenario.feature:37
    Given There is a repository with multiple branches named repo1                                           # WebAPICucumberHooks.setUpMultipleBranches(String)
    When I call "GET /repos/repo1/reportMergeScenario?ourCommit=master&theirCommit=nonexistent"              # WebAPICucumberHooks.callURL(String)
    Then the response status should be '500'                                                                 # WebAPICucumberHooks.checkStatusCode(int)
    And the xpath "/response/error/text()" equals "'their' commit could not be resolved to a commit object." # WebAPICucumberHooks.checkXPathEquals(String,String)
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo1 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()

  Scenario: ReportMergeScenario with two valid commits returns the details of the merge             # ReportMergeScenario.feature:43
    Given There is a repository with multiple branches named repo1                                  # WebAPICucumberHooks.setUpMultipleBranches(String)
    When I call "GET /repos/repo1/reportMergeScenario?ourCommit=master&theirCommit=non_conflicting" # WebAPICucumberHooks.callURL(String)
    Then the response status should be '200'                                                        # WebAPICucumberHooks.checkStatusCode(int)
    And the xpath "/response/success/text()" equals "true"                                          # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xpath "/response/Merge/Feature/change/text()" equals "ADDED"                            # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xpath "/response/Merge/Feature/id/text()" equals "Points/Point.2"                       # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xpath "/response/Merge/Feature/geometry/text()" equals "POINT (-10 -10)"                # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xpath "/response/Merge/Feature/crs/text()" equals "EPSG:4326"                           # WebAPICucumberHooks.checkXPathEquals(String,String)
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo1 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()

  Scenario: ReportMergeScenario with conflicting commits returns the details of the merge                       # ReportMergeScenario.feature:53
    Given There is a repository with multiple branches named repo1                                              # WebAPICucumberHooks.setUpMultipleBranches(String)
    When I call "GET /repos/repo1/reportMergeScenario?ourCommit=master&theirCommit=conflicting"                 # WebAPICucumberHooks.callURL(String)
    Then the response status should be '200'                                                                    # WebAPICucumberHooks.checkStatusCode(int)
    And the xpath "/response/success/text()" equals "true"                                                      # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xpath "/response/Merge/Feature/change/text()" equals "CONFLICT"                                     # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xpath "/response/Merge/Feature/id/text()" equals "Points/Point.1"                                   # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xpath "/response/Merge/Feature/ourvalue/text()" equals "{@ObjectId|repo1|master:Points/Point.1}"    # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xpath "/response/Merge/Feature/theirvalue/text()" equals "0000000000000000000000000000000000000000" # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xpath "/response/Merge/Feature/geometry/text()" equals "POINT (0 0)"                                # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xpath "/response/Merge/Feature/crs/text()" equals "EPSG:4326"                                       # WebAPICucumberHooks.checkXPathEquals(String,String)
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo1 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo2 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()

  Scenario: ReportMergeScenario supports paging                                                                        # ReportMergeScenario.feature:65
    Given There is a default multirepo server                                                                          # WebAPICucumberHooks.setUpDefaultMultiRepo()
    When I call "GET /repos/repo1/reportMergeScenario?ourCommit=master~2&theirCommit=branch1&elementsPerPage=2&page=0" # WebAPICucumberHooks.callURL(String)
    Then the response status should be '200'                                                                           # WebAPICucumberHooks.checkStatusCode(int)
    And the xpath "/response/success/text()" equals "true"                                                             # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xml response should contain "/response/Merge/Feature" 2 times                                              # WebAPICucumberHooks.checkXPathCadinality(String,int)
    And the response body should contain "Points/Point.2"                                                              # WebAPICucumberHooks.checkResponseTextContains(String)
    And the response body should contain "Polygons/Polygon.2"                                                          # WebAPICucumberHooks.checkResponseTextContains(String)
    When I call "GET /repos/repo1/reportMergeScenario?ourCommit=master~2&theirCommit=branch1&elementsPerPage=2&page=1" # WebAPICucumberHooks.callURL(String)
    And the xpath "/response/success/text()" equals "true"                                                             # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xml response should contain "/response/Merge/Feature" 1 times                                              # WebAPICucumberHooks.checkXPathCadinality(String,int)
    And the response body should contain "Lines/Line.2"                                                                # WebAPICucumberHooks.checkResponseTextContains(String)
@Commands @ResolveConflict
Feature: ResolveConflict
  The ResolveConflict command allows a user to resolve a conflict with a specific objectId and is supported through the "/repos/{repository}/resolveconflict" endpoint
  The command must be executed using the HTTP GET method
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo1 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()

  Scenario: Verify wrong HTTP method issues 405 "Method not allowed" # ResolveConflict.feature:6
    Given There is an empty repository named repo1                   # WebAPICucumberHooks.setUpEmptyRepo(String)
    When I call "PUT /repos/repo1/resolveconflict"                   # WebAPICucumberHooks.callURL(String)
    Then the response status should be '405'                         # WebAPICucumberHooks.checkStatusCode(int)
    And the response allowed methods should be "GET"                 # WebAPICucumberHooks.checkResponseAllowedMethods(String)
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo1 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()

  Scenario: ResolveConflict outside of a transaction issues 500 "Transaction required" # ResolveConflict.feature:12
    Given There is an empty repository named repo1                                     # WebAPICucumberHooks.setUpEmptyRepo(String)
    When I call "GET /repos/repo1/resolveconflict?path=somePath/1&objectid=someId"     # WebAPICucumberHooks.callURL(String)
    Then the response status should be '500'                                           # WebAPICucumberHooks.checkStatusCode(int)
    And the xpath "/response/error/text()" contains "No transaction was specified"     # WebAPICucumberHooks.checkXPathValueContains(String,String)
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo1 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()

  Scenario: ResolveConflict outside of a repository issues 404 "Not found"         # ResolveConflict.feature:18
    Given There is an empty multirepo server                                       # WebAPICucumberHooks.setUpEmptyMultiRepo()
    When I call "GET /repos/repo1/resolveconflict?path=somePath/1&objectid=someId" # WebAPICucumberHooks.callURL(String)
    Then the response status should be '404'                                       # WebAPICucumberHooks.checkStatusCode(int)
    And the response ContentType should be "text/plain"                            # WebAPICucumberHooks.checkContentType(String)
    And the response body should contain "Repository not found"                    # WebAPICucumberHooks.checkResponseTextContains(String)
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo1 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()

  Scenario: ResolveConflict without a path issues a 500 status code                               # ResolveConflict.feature:25
    Given There is an empty repository named repo1                                                # WebAPICucumberHooks.setUpEmptyRepo(String)
    And I have a transaction as "@txId" on the "repo1" repo                                       # WebAPICucumberHooks.beginTransactionAsVariable(String,String)
    When I call "GET /repos/repo1/resolveconflict?transactionId={@txId}&objectid=someId"          # WebAPICucumberHooks.callURL(String)
    Then the response status should be '500'                                                      # WebAPICucumberHooks.checkStatusCode(int)
    And the xpath "/response/error/text()" contains "Required parameter 'path' was not provided." # WebAPICucumberHooks.checkXPathValueContains(String,String)
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo1 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()

  Scenario: ResolveConflict without an object ID issues a 500 status code                             # ResolveConflict.feature:32
    Given There is an empty repository named repo1                                                    # WebAPICucumberHooks.setUpEmptyRepo(String)
    And I have a transaction as "@txId" on the "repo1" repo                                           # WebAPICucumberHooks.beginTransactionAsVariable(String,String)
    When I call "GET /repos/repo1/resolveconflict?transactionId={@txId}&path=Points/Point.1"          # WebAPICucumberHooks.callURL(String)
    Then the response status should be '500'                                                          # WebAPICucumberHooks.checkStatusCode(int)
    And the xpath "/response/error/text()" contains "Required parameter 'objectid' was not provided." # WebAPICucumberHooks.checkXPathValueContains(String,String)
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo1 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()

  Scenario: ResolveConflict with an invalid path issues a 400 status code                                                                   # ResolveConflict.feature:39
    Given There is an empty repository named repo1                                                                                          # WebAPICucumberHooks.setUpEmptyRepo(String)
    And I have a transaction as "@txId" on the "repo1" repo                                                                                 # WebAPICucumberHooks.beginTransactionAsVariable(String,String)
    And There are conflicts on the "repo1" repo in the @txId transaction                                                                    # WebAPICucumberHooks.There_are_conflict(String,String)
    When I call "GET /repos/repo1/resolveconflict?transactionId={@txId}&path=Points&objectid={@ObjectId|repo1|@txId|master:Points/Point.1}" # WebAPICucumberHooks.callURL(String)
    Then the response status should be '400'                                                                                                # WebAPICucumberHooks.checkStatusCode(int)
    And the xpath "/response/error/text()" equals "empty child path: '/'"                                                                   # WebAPICucumberHooks.checkXPathEquals(String,String)
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo1 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()

  Scenario: ResolveConflict with valid parameters resolves the conflict                                                                               # ResolveConflict.feature:47
    Given There is an empty repository named repo1                                                                                                    # WebAPICucumberHooks.setUpEmptyRepo(String)
    And I have a transaction as "@txId" on the "repo1" repo                                                                                           # WebAPICucumberHooks.beginTransactionAsVariable(String,String)
    And There are conflicts on the "repo1" repo in the @txId transaction                                                                              # WebAPICucumberHooks.There_are_conflict(String,String)
    When I call "GET /repos/repo1/resolveconflict?transactionId={@txId}&path=Points/Point.1&objectid={@ObjectId|repo1|@txId|master~1:Points/Point.1}" # WebAPICucumberHooks.callURL(String)
    Then the response status should be '200'                                                                                                          # WebAPICucumberHooks.checkStatusCode(int)
    And the xpath "/response/success/text()" equals "true"                                                                                            # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xpath "/response/Add/text()" equals "Success"                                                                                             # WebAPICucumberHooks.checkXPathEquals(String,String)
    And There should be no conflicts on the "repo1" repo in the @txId transaction                                                                     # WebAPICucumberHooks.There_should_be_no_conflicts(String,String)
    And the variable "{@ObjectId|repo1|@txId|STAGE_HEAD:Points/Point.1}" equals "{@ObjectId|repo1|@txId|master~1:Points/Point.1}"                     # WebAPICucumberHooks.checkVariableEquals(String,String)
@Commands @RevertFeature
Feature: RevertFeature
  The RevertFeature command allows a user to undo the changes made to a feature and is supported through the "/repos/{repository}/revertfeature" endpoint
  The command must be executed using the HTTP GET method
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo1 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()

  Scenario: Verify wrong HTTP method issues 405 "Method not allowed" # RevertFeature.feature:6
    Given There is an empty repository named repo1                   # WebAPICucumberHooks.setUpEmptyRepo(String)
    When I call "PUT /repos/repo1/revertfeature"                     # WebAPICucumberHooks.callURL(String)
    Then the response status should be '405'                         # WebAPICucumberHooks.checkStatusCode(int)
    And the response allowed methods should be "GET"                 # WebAPICucumberHooks.checkResponseAllowedMethods(String)
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo1 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()

  Scenario: RevertFeature outside of a transaction issues 500 "Transaction required"                   # RevertFeature.feature:12
    Given There is an empty repository named repo1                                                     # WebAPICucumberHooks.setUpEmptyRepo(String)
    When I call "GET /repos/repo1/revertfeature?path=somePath/1&newCommitId=someId&oldCommitId=someId" # WebAPICucumberHooks.callURL(String)
    Then the response status should be '500'                                                           # WebAPICucumberHooks.checkStatusCode(int)
    And the xpath "/response/error/text()" contains "No transaction was specified"                     # WebAPICucumberHooks.checkXPathValueContains(String,String)
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo1 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()

  Scenario: RevertFeature outside of a repository issues 404 "Not found"                               # RevertFeature.feature:18
    Given There is an empty multirepo server                                                           # WebAPICucumberHooks.setUpEmptyMultiRepo()
    When I call "GET /repos/repo1/revertfeature?path=somePath/1&newCommitId=someId&oldCommitId=someId" # WebAPICucumberHooks.callURL(String)
    Then the response status should be '404'                                                           # WebAPICucumberHooks.checkStatusCode(int)
    And the response ContentType should be "text/plain"                                                # WebAPICucumberHooks.checkContentType(String)
    And the response body should contain "Repository not found"                                        # WebAPICucumberHooks.checkResponseTextContains(String)
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo1 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo2 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()

  Scenario: RevertFeature without a path issues a 500 status code                                                                                # RevertFeature.feature:25
    Given There is a default multirepo server                                                                                                    # WebAPICucumberHooks.setUpDefaultMultiRepo()
    And I have a transaction as "@txId" on the "repo1" repo                                                                                      # WebAPICucumberHooks.beginTransactionAsVariable(String,String)
    When I call "GET /repos/repo1/revertfeature?transactionId={@txId}&oldCommitId={@ObjectId|repo1|master}&newCommitId={@ObjectId|repo1|master}" # WebAPICucumberHooks.callURL(String)
    Then the response status should be '500'                                                                                                     # WebAPICucumberHooks.checkStatusCode(int)
    And the xpath "/response/error/text()" contains "Required parameter 'path' was not provided."                                                # WebAPICucumberHooks.checkXPathValueContains(String,String)
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo1 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo2 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()

  Scenario: RevertFeature without a new commit ID issues a 500 status code                                                      # RevertFeature.feature:32
    Given There is a default multirepo server                                                                                   # WebAPICucumberHooks.setUpDefaultMultiRepo()
    And I have a transaction as "@txId" on the "repo1" repo                                                                     # WebAPICucumberHooks.beginTransactionAsVariable(String,String)
    When I call "GET /repos/repo1/revertfeature?transactionId={@txId}&path=Points/Point.1&oldCommitId={@ObjectId|repo1|master}" # WebAPICucumberHooks.callURL(String)
    Then the response status should be '500'                                                                                    # WebAPICucumberHooks.checkStatusCode(int)
    And the xpath "/response/error/text()" contains "Required parameter 'newCommitId' was not provided."                        # WebAPICucumberHooks.checkXPathValueContains(String,String)
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo1 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo2 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()

  Scenario: RevertFeature without an old commit ID issues a 500 status code                                                     # RevertFeature.feature:39
    Given There is a default multirepo server                                                                                   # WebAPICucumberHooks.setUpDefaultMultiRepo()
    And I have a transaction as "@txId" on the "repo1" repo                                                                     # WebAPICucumberHooks.beginTransactionAsVariable(String,String)
    When I call "GET /repos/repo1/revertfeature?transactionId={@txId}&path=Points/Point.1&newCommitId={@ObjectId|repo1|master}" # WebAPICucumberHooks.callURL(String)
    Then the response status should be '500'                                                                                    # WebAPICucumberHooks.checkStatusCode(int)
    And the xpath "/response/error/text()" contains "Required parameter 'oldCommitId' was not provided."                        # WebAPICucumberHooks.checkXPathValueContains(String,String)
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo1 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo2 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()

  Scenario: RevertFeature with an invalid path issues a 500 status code                                                                                             # RevertFeature.feature:46
    Given There is a default multirepo server                                                                                                                       # WebAPICucumberHooks.setUpDefaultMultiRepo()
    And I have a transaction as "@txId" on the "repo1" repo                                                                                                         # WebAPICucumberHooks.beginTransactionAsVariable(String,String)
    When I call "GET /repos/repo1/revertfeature?transactionId={@txId}&path=nonexistent&oldCommitId={@ObjectId|repo1|master~1}&newCommitId={@ObjectId|repo1|master}" # WebAPICucumberHooks.callURL(String)
    Then the response status should be '500'                                                                                                                        # WebAPICucumberHooks.checkStatusCode(int)
    And the xpath "/response/error/text()" equals "The feature was not found in either commit tree."                                                                # WebAPICucumberHooks.checkXPathEquals(String,String)
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo1 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo2 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()

  Scenario: RevertFeature on an added feature removes that feature                                                                                                     # RevertFeature.feature:53
    Given There is a default multirepo server                                                                                                                          # WebAPICucumberHooks.setUpDefaultMultiRepo()
    And I have a transaction as "@txId" on the "repo1" repo                                                                                                            # WebAPICucumberHooks.beginTransactionAsVariable(String,String)
    When I call "GET /repos/repo1/revertfeature?transactionId={@txId}&path=Points/Point.3&oldCommitId={@ObjectId|repo1|master~1}&newCommitId={@ObjectId|repo1|master}" # WebAPICucumberHooks.callURL(String)
    Then the response status should be '200'                                                                                                                           # WebAPICucumberHooks.checkStatusCode(int)
    And the xpath "/response/success/text()" equals "true"                                                                                                             # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the repo1 repository's "master" in the @txId transaction should have the following features:                                                                   # WebAPICucumberHooks.verifyRepositoryContentsTx(String,String,String,DataTable)
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo1 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()

  Scenario: RevertFeature on a modified feature undoes the change                                                                                                      # RevertFeature.feature:65
    Given There is an empty repository named repo1                                                                                                                     # WebAPICucumberHooks.setUpEmptyRepo(String)
    And There is a feature with multiple authors on the "repo1" repo                                                                                                   # WebAPICucumberHooks.There_is_a_feature_with_multiple_authors(String)
    And I have a transaction as "@txId" on the "repo1" repo                                                                                                            # WebAPICucumberHooks.beginTransactionAsVariable(String,String)
    When I call "GET /repos/repo1/revertfeature?transactionId={@txId}&path=Points/Point.1&oldCommitId={@ObjectId|repo1|master~1}&newCommitId={@ObjectId|repo1|master}" # WebAPICucumberHooks.callURL(String)
    Then the response status should be '200'                                                                                                                           # WebAPICucumberHooks.checkStatusCode(int)
    And the xpath "/response/success/text()" equals "true"                                                                                                             # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the variable "{@ObjectId|repo1|@txId|master:Points/Point.1}" equals "{@ObjectId|repo1|@txId|master~2:Points/Point.1}"                                          # WebAPICucumberHooks.checkVariableEquals(String,String)
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo1 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()

  Scenario: RevertFeature on a removed feature adds it back                                                                                                                      # RevertFeature.feature:74
    Given There is a repository with multiple branches named repo1                                                                                                               # WebAPICucumberHooks.setUpMultipleBranches(String)
    And I have checked out "conflicting" on the "repo1" repo                                                                                                                     # WebAPICucumberHooks.I_have_checked_out(String,String)
    And I have a transaction as "@txId" on the "repo1" repo                                                                                                                      # WebAPICucumberHooks.beginTransactionAsVariable(String,String)
    And the repo1 repository's "conflicting" in the @txId transaction should have the following features:                                                                        # WebAPICucumberHooks.verifyRepositoryContentsTx(String,String,String,DataTable)
    When I call "GET /repos/repo1/revertfeature?transactionId={@txId}&path=Points/Point.1&oldCommitId={@ObjectId|repo1|conflicting~1}&newCommitId={@ObjectId|repo1|conflicting}" # WebAPICucumberHooks.callURL(String)
    Then the response status should be '200'                                                                                                                                     # WebAPICucumberHooks.checkStatusCode(int)
    And the xpath "/response/success/text()" equals "true"                                                                                                                       # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the repo1 repository's "conflicting" in the @txId transaction should have the following features:                                                                        # WebAPICucumberHooks.verifyRepositoryContentsTx(String,String,String,DataTable)
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo1 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()

  Scenario: If a feature has changed since the 'new' commit id, conflicts may be thrown                                                                                                        # RevertFeature.feature:88
    Given There is a repository with multiple branches named repo1                                                                                                                             # WebAPICucumberHooks.setUpMultipleBranches(String)
    And I have checked out "conflicting" on the "repo1" repo                                                                                                                                   # WebAPICucumberHooks.I_have_checked_out(String,String)
    And I have a transaction as "@txId" on the "repo1" repo                                                                                                                                    # WebAPICucumberHooks.beginTransactionAsVariable(String,String)
    And I have committed "Point.1_modified" on the "repo1" repo in the "@txId" transaction                                                                                                     # WebAPICucumberHooks.I_have_committed(String,String,String)
    When I call "GET /repos/repo1/revertfeature?transactionId={@txId}&path=Points/Point.1&oldCommitId={@ObjectId|repo1|@txId|conflicting~2}&newCommitId={@ObjectId|repo1|@txId|conflicting~1}" # WebAPICucumberHooks.callURL(String)
    Then the response status should be '200'                                                                                                                                                   # WebAPICucumberHooks.checkStatusCode(int)
    And the xpath "/response/success/text()" equals "true"                                                                                                                                     # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xpath "/response/Merge/conflicts/text()" equals "1"                                                                                                                                # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xpath "/response/Merge/Feature/change/text()" equals "CONFLICT"                                                                                                                    # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xpath "/response/Merge/Feature/id/text()" equals "Points/Point.1"                                                                                                                  # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xpath "/response/Merge/Feature/ourvalue/text()" equals "{@ObjectId|repo1|@txId|conflicting:Points/Point.1}"                                                                        # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xpath "/response/Merge/Feature/theirvalue/text()" equals "{@ObjectId|repo1|@txId|conflicting~2:Points/Point.1}"                                                                    # WebAPICucumberHooks.checkXPathEquals(String,String)
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo1 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()

  Scenario: Supplying author information applies to the reverted commit as well as the merge commit                                                                                                                        # RevertFeature.feature:102
    Given There is an empty repository named repo1                                                                                                                                                                         # WebAPICucumberHooks.setUpEmptyRepo(String)
    And There is a feature with multiple authors on the "repo1" repo                                                                                                                                                       # WebAPICucumberHooks.There_is_a_feature_with_multiple_authors(String)
    And I have a transaction as "@txId" on the "repo1" repo                                                                                                                                                                # WebAPICucumberHooks.beginTransactionAsVariable(String,String)
    And I have committed "Point.2" on the "repo1" repo in the "@txId" transaction                                                                                                                                          # WebAPICucumberHooks.I_have_committed(String,String,String)
    When I call "GET /repos/repo1/revertfeature?transactionId={@txId}&path=Points/Point.1&oldCommitId={@ObjectId|repo1|master~1}&newCommitId={@ObjectId|repo1|master}&authorName=myAuthor&authorEmail=myAuthor@geogig.org" # WebAPICucumberHooks.callURL(String)
    Then the response status should be '200'                                                                                                                                                                               # WebAPICucumberHooks.checkStatusCode(int)
    And the xpath "/response/success/text()" equals "true"                                                                                                                                                                 # WebAPICucumberHooks.checkXPathEquals(String,String)
    When I call "GET /repos/repo1/cat?objectid={@ObjectId|repo1|@txId|master}"                                                                                                                                             # WebAPICucumberHooks.callURL(String)
    Then the response status should be '200'                                                                                                                                                                               # WebAPICucumberHooks.checkStatusCode(int)
    And the xpath "/response/commit/author/name/text()" equals "myAuthor"                                                                                                                                                  # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xpath "/response/commit/author/email/text()" equals "myAuthor@geogig.org"                                                                                                                                      # WebAPICucumberHooks.checkXPathEquals(String,String)
    When I call "GET /repos/repo1/cat?objectid={@ObjectId|repo1|@txId|master^2}"                                                                                                                                           # WebAPICucumberHooks.callURL(String)
    Then the response status should be '200'                                                                                                                                                                               # WebAPICucumberHooks.checkStatusCode(int)
    And the xpath "/response/commit/author/name/text()" equals "myAuthor"                                                                                                                                                  # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xpath "/response/commit/author/email/text()" equals "myAuthor@geogig.org"                                                                                                                                      # WebAPICucumberHooks.checkXPathEquals(String,String)
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo1 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()

  Scenario: Supplying a commit message applies to the revert commit                                                                                                                               # RevertFeature.feature:119
    Given There is an empty repository named repo1                                                                                                                                                # WebAPICucumberHooks.setUpEmptyRepo(String)
    And There is a feature with multiple authors on the "repo1" repo                                                                                                                              # WebAPICucumberHooks.There_is_a_feature_with_multiple_authors(String)
    And I have a transaction as "@txId" on the "repo1" repo                                                                                                                                       # WebAPICucumberHooks.beginTransactionAsVariable(String,String)
    And I have committed "Point.2" on the "repo1" repo in the "@txId" transaction                                                                                                                 # WebAPICucumberHooks.I_have_committed(String,String,String)
    When I call "GET /repos/repo1/revertfeature?transactionId={@txId}&path=Points/Point.1&oldCommitId={@ObjectId|repo1|master~1}&newCommitId={@ObjectId|repo1|master}&commitMessage=My%20Message" # WebAPICucumberHooks.callURL(String)
    Then the response status should be '200'                                                                                                                                                      # WebAPICucumberHooks.checkStatusCode(int)
    And the xpath "/response/success/text()" equals "true"                                                                                                                                        # WebAPICucumberHooks.checkXPathEquals(String,String)
    When I call "GET /repos/repo1/cat?objectid={@ObjectId|repo1|@txId|master^2}"                                                                                                                  # WebAPICucumberHooks.callURL(String)
    Then the response status should be '200'                                                                                                                                                      # WebAPICucumberHooks.checkStatusCode(int)
    And the xpath "/response/commit/message/text()" equals "My Message"                                                                                                                           # WebAPICucumberHooks.checkXPathEquals(String,String)
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo1 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()

  Scenario: Supplying a merge message applies to the merge commit                                                                                                                                # RevertFeature.feature:131
    Given There is an empty repository named repo1                                                                                                                                               # WebAPICucumberHooks.setUpEmptyRepo(String)
    And There is a feature with multiple authors on the "repo1" repo                                                                                                                             # WebAPICucumberHooks.There_is_a_feature_with_multiple_authors(String)
    And I have a transaction as "@txId" on the "repo1" repo                                                                                                                                      # WebAPICucumberHooks.beginTransactionAsVariable(String,String)
    And I have committed "Point.2" on the "repo1" repo in the "@txId" transaction                                                                                                                # WebAPICucumberHooks.I_have_committed(String,String,String)
    When I call "GET /repos/repo1/revertfeature?transactionId={@txId}&path=Points/Point.1&oldCommitId={@ObjectId|repo1|master~1}&newCommitId={@ObjectId|repo1|master}&mergeMessage=My%20Message" # WebAPICucumberHooks.callURL(String)
    Then the response status should be '200'                                                                                                                                                     # WebAPICucumberHooks.checkStatusCode(int)
    And the xpath "/response/success/text()" equals "true"                                                                                                                                       # WebAPICucumberHooks.checkXPathEquals(String,String)
    When I call "GET /repos/repo1/cat?objectid={@ObjectId|repo1|@txId|master}"                                                                                                                   # WebAPICucumberHooks.callURL(String)
    Then the response status should be '200'                                                                                                                                                     # WebAPICucumberHooks.checkStatusCode(int)
    And the xpath "/response/commit/message/text()" equals "My Message"                                                                                                                          # WebAPICucumberHooks.checkXPathEquals(String,String)
@Commands @Statistics
Feature: Statistics
  The Statistics command allows a user to summarize the changes made to a branch and is supported through the "/repos/{repository}/statistics" endpoint
  The command must be executed using the HTTP GET method
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo1 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()

  Scenario: Verify wrong HTTP method issues 405 "Method not allowed" # Statistics.feature:6
    Given There is an empty repository named repo1                   # WebAPICucumberHooks.setUpEmptyRepo(String)
    When I call "PUT /repos/repo1/statistics"                        # WebAPICucumberHooks.callURL(String)
    Then the response status should be '405'                         # WebAPICucumberHooks.checkStatusCode(int)
    And the response allowed methods should be "GET"                 # WebAPICucumberHooks.checkResponseAllowedMethods(String)
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo1 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()

  Scenario: Statistics outside of a repository issues 404 "Not found" # Statistics.feature:12
    Given There is an empty multirepo server                          # WebAPICucumberHooks.setUpEmptyMultiRepo()
    When I call "GET /repos/repo1/statistics"                         # WebAPICucumberHooks.callURL(String)
    Then the response status should be '404'                          # WebAPICucumberHooks.checkStatusCode(int)
    And the response ContentType should be "text/plain"               # WebAPICucumberHooks.checkContentType(String)
    And the response body should contain "Repository not found"       # WebAPICucumberHooks.checkResponseTextContains(String)
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo1 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo2 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()

  Scenario: Statistics summarizes the changes made to the repository                                             # Statistics.feature:19
    Given There is a default multirepo server                                                                    # WebAPICucumberHooks.setUpDefaultMultiRepo()
    When I call "GET /repos/repo1/statistics"                                                                    # WebAPICucumberHooks.callURL(String)
    Then the response status should be '200'                                                                     # WebAPICucumberHooks.checkStatusCode(int)
    And the xpath "/response/success/text()" equals "true"                                                       # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xml response should contain "/response/Statistics/FeatureTypes/FeatureType" 3 times                  # WebAPICucumberHooks.checkXPathCadinality(String,int)
    And there is an xpath "/response/Statistics/FeatureTypes/FeatureType/name/text()" that contains "Points"     # WebAPICucumberHooks.checkOneXPathValueContains(String,String)
    And there is an xpath "/response/Statistics/FeatureTypes/FeatureType/name/text()" that contains "Lines"      # WebAPICucumberHooks.checkOneXPathValueContains(String,String)
    And there is an xpath "/response/Statistics/FeatureTypes/FeatureType/name/text()" that contains "Polygons"   # WebAPICucumberHooks.checkOneXPathValueContains(String,String)
    And the xpath "/response/Statistics/FeatureTypes/totalFeatureTypes/text()" equals "3"                        # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xpath "/response/Statistics/FeatureTypes/totalFeatures/text()" equals "9"                            # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xpath "/response/Statistics/latestCommit/id/text()" equals "{@ObjectId|repo1|master}"                # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xpath "/response/Statistics/latestCommit/message/text()" contains "merge branch branch2 onto master" # WebAPICucumberHooks.checkXPathValueContains(String,String)
    And the xpath "/response/Statistics/firstCommit/id/text()" equals "{@ObjectId|repo1|master~2}"               # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xpath "/response/Statistics/firstCommit/message/text()" contains "point1, line1, poly1"              # WebAPICucumberHooks.checkXPathValueContains(String,String)
    And the xpath "/response/Statistics/Authors/Author/name/text()" equals "geogigUser"                          # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xpath "/response/Statistics/Authors/Author/email/text()" equals "repo1_Owner@geogig.org"             # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xpath "/response/Statistics/Authors/totalAuthors/text()" equals "1"                                  # WebAPICucumberHooks.checkXPathEquals(String,String)
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo1 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo2 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()

  Scenario: Statistics summarizes the changes since a particular timestamp up to a specific commit               # Statistics.feature:38
    Given There is a default multirepo server                                                                    # WebAPICucumberHooks.setUpDefaultMultiRepo()
    When I call "GET /repos/repo1/statistics?since=0&branch=master~1"                                            # WebAPICucumberHooks.callURL(String)
    Then the response status should be '200'                                                                     # WebAPICucumberHooks.checkStatusCode(int)
    And the xpath "/response/success/text()" equals "true"                                                       # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xml response should contain "/response/Statistics/FeatureTypes/FeatureType" 3 times                  # WebAPICucumberHooks.checkXPathCadinality(String,int)
    And there is an xpath "/response/Statistics/FeatureTypes/FeatureType/name/text()" that equals "Points"       # WebAPICucumberHooks.checkOneXPathEquals(String,String)
    And there is an xpath "/response/Statistics/FeatureTypes/FeatureType/numFeatures/text()" that equals "2"     # WebAPICucumberHooks.checkOneXPathEquals(String,String)
    And there is an xpath "/response/Statistics/FeatureTypes/FeatureType/name/text()" that equals "Lines"        # WebAPICucumberHooks.checkOneXPathEquals(String,String)
    And there is an xpath "/response/Statistics/FeatureTypes/FeatureType/name/text()" that equals "Polygons"     # WebAPICucumberHooks.checkOneXPathEquals(String,String)
    And the xpath "/response/Statistics/FeatureTypes/totalFeatureTypes/text()" equals "3"                        # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xpath "/response/Statistics/FeatureTypes/totalFeatures/text()" equals "6"                            # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xpath "/response/Statistics/latestCommit/id/text()" equals "{@ObjectId|repo1|master~1}"              # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xpath "/response/Statistics/latestCommit/message/text()" contains "merge branch branch1 onto master" # WebAPICucumberHooks.checkXPathValueContains(String,String)
    And the xpath "/response/Statistics/firstCommit/id/text()" equals "{@ObjectId|repo1|master~2}"               # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xpath "/response/Statistics/firstCommit/message/text()" contains "point1, line1, poly1"              # WebAPICucumberHooks.checkXPathValueContains(String,String)
    And the xpath "/response/Statistics/Authors/Author/name/text()" equals "geogigUser"                          # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xpath "/response/Statistics/Authors/Author/email/text()" equals "repo1_Owner@geogig.org"             # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xpath "/response/Statistics/Authors/totalAuthors/text()" equals "1"                                  # WebAPICucumberHooks.checkXPathEquals(String,String)
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo1 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo2 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()

  Scenario: Statistics can summarize the changes made to a specific path                                         # Statistics.feature:58
    Given There is a default multirepo server                                                                    # WebAPICucumberHooks.setUpDefaultMultiRepo()
    When I call "GET /repos/repo1/statistics?path=Points"                                                        # WebAPICucumberHooks.callURL(String)
    Then the response status should be '200'                                                                     # WebAPICucumberHooks.checkStatusCode(int)
    And the xpath "/response/success/text()" equals "true"                                                       # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xml response should contain "/response/Statistics/FeatureTypes/FeatureType" 1 times                  # WebAPICucumberHooks.checkXPathCadinality(String,int)
    And the xpath "/response/Statistics/FeatureTypes/FeatureType/name/text()" equals "Points"                    # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xpath "/response/Statistics/FeatureTypes/FeatureType/numFeatures/text()" equals "3"                  # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xpath "/response/Statistics/latestCommit/id/text()" equals "{@ObjectId|repo1|master}"                # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xpath "/response/Statistics/latestCommit/message/text()" contains "merge branch branch2 onto master" # WebAPICucumberHooks.checkXPathValueContains(String,String)
    And the xpath "/response/Statistics/firstCommit/id/text()" equals "{@ObjectId|repo1|master~2}"               # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xpath "/response/Statistics/firstCommit/message/text()" contains "point1, line1, poly1"              # WebAPICucumberHooks.checkXPathValueContains(String,String)
    And the xpath "/response/Statistics/Authors/Author/name/text()" equals "geogigUser"                          # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xpath "/response/Statistics/Authors/Author/email/text()" equals "repo1_Owner@geogig.org"             # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xpath "/response/Statistics/Authors/totalAuthors/text()" equals "1"                                  # WebAPICucumberHooks.checkXPathEquals(String,String)
@Commands @Status
Feature: Status
  The Status command allows a user to see the current state of the repository and is supported through the "/repos/{repository}/status" endpoint
  The command must be executed using the HTTP GET method
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo1 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()

  Scenario: Verify wrong HTTP method issues 405 "Method not allowed" # Status.feature:6
    Given There is an empty repository named repo1                   # WebAPICucumberHooks.setUpEmptyRepo(String)
    When I call "PUT /repos/repo1/status"                            # WebAPICucumberHooks.callURL(String)
    Then the response status should be '405'                         # WebAPICucumberHooks.checkStatusCode(int)
    And the response allowed methods should be "GET"                 # WebAPICucumberHooks.checkResponseAllowedMethods(String)
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo1 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()

  Scenario: Status outside of a repository issues 404 "Not found" # Status.feature:12
    Given There is an empty multirepo server                      # WebAPICucumberHooks.setUpEmptyMultiRepo()
    When I call "GET /repos/repo1/status"                         # WebAPICucumberHooks.callURL(String)
    Then the response status should be '404'                      # WebAPICucumberHooks.checkStatusCode(int)
    And the response ContentType should be "text/plain"           # WebAPICucumberHooks.checkContentType(String)
    And the response body should contain "Repository not found"   # WebAPICucumberHooks.checkResponseTextContains(String)
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo1 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()

  Scenario: Status shows the current branch and all staged and unstaged features # Status.feature:19
    Given There is an empty repository named repo1                               # WebAPICucumberHooks.setUpEmptyRepo(String)
    And I have a transaction as "@txId" on the "repo1" repo                      # WebAPICucumberHooks.beginTransactionAsVariable(String,String)
    And I have staged "Line.1" on the "repo1" repo in the "@txId" transaction    # WebAPICucumberHooks.I_have_staged(String,String,String)
    And I have unstaged "Point.1" on the "repo1" repo in the "@txId" transaction # WebAPICucumberHooks.I_have_unstaged(String,String,String)
    And I have unstaged "Point.2" on the "repo1" repo in the "@txId" transaction # WebAPICucumberHooks.I_have_unstaged(String,String,String)
    When I call "GET /repos/repo1/status?transactionId={@txId}"                  # WebAPICucumberHooks.callURL(String)
    Then the response status should be '200'                                     # WebAPICucumberHooks.checkStatusCode(int)
    And the xpath "/response/success/text()" equals "true"                       # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xpath "/response/header/branch/text()" equals "master"               # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xpath "/response/staged/changeType/text()" equals "ADDED"            # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xpath "/response/staged/newPath/text()" equals "Lines/Line.1"        # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xml response should contain "/response/unstaged" 2 times             # WebAPICucumberHooks.checkXPathCadinality(String,int)
    And the response body should contain "Points/Point.1"                        # WebAPICucumberHooks.checkResponseTextContains(String)
    And the response body should contain "Points/Point.2"                        # WebAPICucumberHooks.checkResponseTextContains(String)
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo1 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()

  Scenario: Status shows conflicted features                                                                    # Status.feature:35
    Given There is an empty repository named repo1                                                              # WebAPICucumberHooks.setUpEmptyRepo(String)
    And I have a transaction as "@txId" on the "repo1" repo                                                     # WebAPICucumberHooks.beginTransactionAsVariable(String,String)
    And There are conflicts on the "repo1" repo in the @txId transaction                                        # WebAPICucumberHooks.There_are_conflict(String,String)
    When I call "GET /repos/repo1/status?transactionId={@txId}"                                                 # WebAPICucumberHooks.callURL(String)
    Then the response status should be '200'                                                                    # WebAPICucumberHooks.checkStatusCode(int)
    And the xpath "/response/success/text()" equals "true"                                                      # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xpath "/response/header/branch/text()" equals "master"                                              # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xpath "/response/unmerged/changeType/text()" equals "CONFLICT"                                      # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xpath "/response/unmerged/path/text()" equals "Points/Point.1"                                      # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xpath "/response/unmerged/ours/text()" equals "{@ObjectId|repo1|@txId|master:Points/Point.1}"       # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xpath "/response/unmerged/theirs/text()" equals "0000000000000000000000000000000000000000"          # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xpath "/response/unmerged/ancestor/text()" equals "{@ObjectId|repo1|@txId|master~1:Points/Point.1}" # WebAPICucumberHooks.checkXPathEquals(String,String)
@Commands @Tag
Feature: Tag
  The Tag command allows a user to create, list, and delete tags and is supported through the "/repos/{repository}/tag" endpoint
  The command must be executed using the HTTP GET, POST, or DELETE methods
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo1 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()

  Scenario: Verify wrong HTTP method issues 405 "Method not allowed" # Tag.feature:6
    Given There is an empty repository named repo1                   # WebAPICucumberHooks.setUpEmptyRepo(String)
    When I call "PUT /repos/repo1/tag"                               # WebAPICucumberHooks.callURL(String)
    Then the response status should be '405'                         # WebAPICucumberHooks.checkStatusCode(int)
    And the response allowed methods should be "GET,POST,DELETE"     # WebAPICucumberHooks.checkResponseAllowedMethods(String)
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo1 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()

  Scenario: Tag outside of a repository issues 404 "Not found"  # Tag.feature:12
    Given There is an empty multirepo server                    # WebAPICucumberHooks.setUpEmptyMultiRepo()
    When I call "GET /repos/repo1/tag"                          # WebAPICucumberHooks.callURL(String)
    Then the response status should be '404'                    # WebAPICucumberHooks.checkStatusCode(int)
    And the response ContentType should be "text/plain"         # WebAPICucumberHooks.checkContentType(String)
    And the response body should contain "Repository not found" # WebAPICucumberHooks.checkResponseTextContains(String)
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo1 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()

  Scenario: Issuing a POST request to tag without a name issues a 500 status code                                                              # Tag.feature:19
    Given There is an empty repository named repo1                                                                                             # WebAPICucumberHooks.setUpEmptyRepo(String)
    When I call "POST /repos/repo1/tag"                                                                                                        # WebAPICucumberHooks.callURL(String)
    Then the response status should be '500'                                                                                                   # WebAPICucumberHooks.checkStatusCode(int)
    And the xpath "/response/error/text()" contains "You must specify list or delete, or provide a name, message, and commit for the new tag." # WebAPICucumberHooks.checkXPathValueContains(String,String)
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo1 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()

  Scenario: Issuing a POST request to tag without a commit issues a 500 status code                  # Tag.feature:25
    Given There is an empty repository named repo1                                                   # WebAPICucumberHooks.setUpEmptyRepo(String)
    When I call "POST /repos/repo1/tag?name=newTag"                                                  # WebAPICucumberHooks.callURL(String)
    Then the response status should be '500'                                                         # WebAPICucumberHooks.checkStatusCode(int)
    And the xpath "/response/error/text()" contains "You must specify a commit to point the tag to." # WebAPICucumberHooks.checkXPathValueContains(String,String)
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo1 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()

  Scenario: Issuing a POST request to tag with an invalid commit issues a 500 status code  # Tag.feature:31
    Given There is an empty repository named repo1                                         # WebAPICucumberHooks.setUpEmptyRepo(String)
    When I call "POST /repos/repo1/tag?name=newTag&commit=nonexistent"                     # WebAPICucumberHooks.callURL(String)
    Then the response status should be '500'                                               # WebAPICucumberHooks.checkStatusCode(int)
    And the xpath "/response/error/text()" contains "'nonexistent' could not be resolved." # WebAPICucumberHooks.checkXPathValueContains(String,String)
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo1 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo2 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()

  Scenario: Issuing a POST request to tag with valid parameters creates a tag         # Tag.feature:37
    Given There is a default multirepo server                                         # WebAPICucumberHooks.setUpDefaultMultiRepo()
    When I call "POST /repos/repo1/tag?name=newTag&commit=master&message=My%20Tag"    # WebAPICucumberHooks.callURL(String)
    Then the response status should be '200'                                          # WebAPICucumberHooks.checkStatusCode(int)
    And the xpath "/response/success/text()" equals "true"                            # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xml response should contain "/response/Tag/id" 1 times                    # WebAPICucumberHooks.checkXPathCadinality(String,int)
    And the xpath "/response/Tag/commitid/text()" equals "{@ObjectId|repo1|master}"   # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xpath "/response/Tag/name/text()" equals "newTag"                         # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xpath "/response/Tag/message/text()" equals "My Tag"                      # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xpath "/response/Tag/tagger/name/text()" equals "geogigUser"              # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xpath "/response/Tag/tagger/email/text()" equals "repo1_Owner@geogig.org" # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xml response should contain "/response/Tag/tagger/timestamp" 1 times      # WebAPICucumberHooks.checkXPathCadinality(String,int)
    And the xml response should contain "/response/Tag/tagger/timeZoneOffset" 1 times # WebAPICucumberHooks.checkXPathCadinality(String,int)
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo1 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo2 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()

  Scenario: Issuing a GET request to tag lists all tags                                           # Tag.feature:51
    Given There is a default multirepo server                                                     # WebAPICucumberHooks.setUpDefaultMultiRepo()
    And I call "POST /repos/repo1/tag?name=tag1&commit=master&message=My%20Tag%201"               # WebAPICucumberHooks.callURL(String)
    And I call "POST /repos/repo1/tag?name=tag2&commit=branch1&message=My%20Tag%202"              # WebAPICucumberHooks.callURL(String)
    When I call "GET /repos/repo1/tag"                                                            # WebAPICucumberHooks.callURL(String)
    Then the response status should be '200'                                                      # WebAPICucumberHooks.checkStatusCode(int)
    And the xpath "/response/success/text()" equals "true"                                        # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xml response should contain "/response/Tag" 2 times                                   # WebAPICucumberHooks.checkXPathCadinality(String,int)
    And there is an xpath "/response/Tag/commitid/text()" that equals "{@ObjectId|repo1|master}"  # WebAPICucumberHooks.checkOneXPathEquals(String,String)
    And there is an xpath "/response/Tag/name/text()" that equals "tag1"                          # WebAPICucumberHooks.checkOneXPathEquals(String,String)
    And there is an xpath "/response/Tag/message/text()" that equals "My Tag 1"                   # WebAPICucumberHooks.checkOneXPathEquals(String,String)
    And there is an xpath "/response/Tag/commitid/text()" that equals "{@ObjectId|repo1|branch1}" # WebAPICucumberHooks.checkOneXPathEquals(String,String)
    And there is an xpath "/response/Tag/name/text()" that equals "tag2"                          # WebAPICucumberHooks.checkOneXPathEquals(String,String)
    And there is an xpath "/response/Tag/message/text()" that equals "My Tag 2"                   # WebAPICucumberHooks.checkOneXPathEquals(String,String)
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo1 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()

  Scenario: Issuing a DELETE request to tag without a name issues a 500 status code          # Tag.feature:66
    Given There is an empty repository named repo1                                           # WebAPICucumberHooks.setUpEmptyRepo(String)
    When I call "DELETE /repos/repo1/tag"                                                    # WebAPICucumberHooks.callURL(String)
    Then the response status should be '500'                                                 # WebAPICucumberHooks.checkStatusCode(int)
    And the xpath "/response/error/text()" equals "You must specify the tag name to delete." # WebAPICucumberHooks.checkXPathEquals(String,String)
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo1 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo2 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()

  Scenario: Issuing a DELETE request to tag deletes the tag                                  # Tag.feature:72
    Given There is a default multirepo server                                                # WebAPICucumberHooks.setUpDefaultMultiRepo()
    And I call "POST /repos/repo1/tag?name=tag1&commit=master&message=My%20Tag%201"          # WebAPICucumberHooks.callURL(String)
    And I call "POST /repos/repo1/tag?name=tag2&commit=branch1&message=My%20Tag%202"         # WebAPICucumberHooks.callURL(String)
    When I call "DELETE /repos/repo1/tag?name=tag1"                                          # WebAPICucumberHooks.callURL(String)
    Then the response status should be '200'                                                 # WebAPICucumberHooks.checkStatusCode(int)
    And the xpath "/response/success/text()" equals "true"                                   # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xml response should contain "/response/DeletedTag/id" 1 times                    # WebAPICucumberHooks.checkXPathCadinality(String,int)
    And the xpath "/response/DeletedTag/commitid/text()" equals "{@ObjectId|repo1|master}"   # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xpath "/response/DeletedTag/name/text()" equals "tag1"                           # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xpath "/response/DeletedTag/message/text()" equals "My Tag 1"                    # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xpath "/response/DeletedTag/tagger/name/text()" equals "geogigUser"              # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xpath "/response/DeletedTag/tagger/email/text()" equals "repo1_Owner@geogig.org" # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xml response should contain "/response/DeletedTag/tagger/timestamp" 1 times      # WebAPICucumberHooks.checkXPathCadinality(String,int)
    And the xml response should contain "/response/DeletedTag/tagger/timeZoneOffset" 1 times # WebAPICucumberHooks.checkXPathCadinality(String,int)
    When I call "GET /repos/repo1/tag"                                                       # WebAPICucumberHooks.callURL(String)
    Then the response status should be '200'                                                 # WebAPICucumberHooks.checkStatusCode(int)
    And the xpath "/response/success/text()" equals "true"                                   # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xml response should contain "/response/Tag/id" 1 times                           # WebAPICucumberHooks.checkXPathCadinality(String,int)
    And the xpath "/response/Tag/commitid/text()" equals "{@ObjectId|repo1|branch1}"         # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xpath "/response/Tag/name/text()" equals "tag2"                                  # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xpath "/response/Tag/message/text()" equals "My Tag 2"                           # WebAPICucumberHooks.checkXPathEquals(String,String)
@Commands @Transaction
Feature: Transaction
  Transactions allow a user to perform work without affecting the main repository is supported through the "/repos/{repository}/beginTransaction" endpoint
  The command must be executed using the HTTP GET method
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo1 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()

  Scenario: Verify wrong HTTP method on begin transaction issues 405 "Method not allowed" # Transaction.feature:6
    Given There is an empty repository named repo1                                        # WebAPICucumberHooks.setUpEmptyRepo(String)
    When I call "PUT /repos/repo1/beginTransaction"                                       # WebAPICucumberHooks.callURL(String)
    Then the response status should be '405'                                              # WebAPICucumberHooks.checkStatusCode(int)
    And the response allowed methods should be "GET"                                      # WebAPICucumberHooks.checkResponseAllowedMethods(String)
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo1 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()

  Scenario: Beginning a transaction outside of a repository issues 404 "Not found" # Transaction.feature:12
    Given There is an empty multirepo server                                       # WebAPICucumberHooks.setUpEmptyMultiRepo()
    When I call "GET /repos/repo1/beginTransaction"                                # WebAPICucumberHooks.callURL(String)
    Then the response status should be '404'                                       # WebAPICucumberHooks.checkStatusCode(int)
    And the response ContentType should be "text/plain"                            # WebAPICucumberHooks.checkContentType(String)
    And the response body should contain "Repository not found"                    # WebAPICucumberHooks.checkResponseTextContains(String)
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo1 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()

  Scenario: Verify wrong HTTP method on end transaction issues 405 "Method not allowed" # Transaction.feature:19
    Given There is an empty repository named repo1                                      # WebAPICucumberHooks.setUpEmptyRepo(String)
    When I call "PUT /repos/repo1/endTransaction"                                       # WebAPICucumberHooks.callURL(String)
    Then the response status should be '405'                                            # WebAPICucumberHooks.checkStatusCode(int)
    And the response allowed methods should be "GET"                                    # WebAPICucumberHooks.checkResponseAllowedMethods(String)
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo1 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()

  Scenario: Ending a transaction outside of a repository issues 404 "Not found" # Transaction.feature:25
    Given There is an empty multirepo server                                    # WebAPICucumberHooks.setUpEmptyMultiRepo()
    When I call "GET /repos/repo1/endTransaction"                               # WebAPICucumberHooks.callURL(String)
    Then the response status should be '404'                                    # WebAPICucumberHooks.checkStatusCode(int)
    And the response ContentType should be "text/plain"                         # WebAPICucumberHooks.checkContentType(String)
    And the response body should contain "Repository not found"                 # WebAPICucumberHooks.checkResponseTextContains(String)
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo1 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()

  Scenario: Ending a transaction outside of a transaction issues 500 "Transaction required" # Transaction.feature:32
    Given There is an empty repository named repo1                                          # WebAPICucumberHooks.setUpEmptyRepo(String)
    When I call "GET /repos/repo1/endTransaction"                                           # WebAPICucumberHooks.callURL(String)
    Then the response status should be '500'                                                # WebAPICucumberHooks.checkStatusCode(int)
    And the xpath "/response/error/text()" contains "No transaction was specified"          # WebAPICucumberHooks.checkXPathValueContains(String,String)
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo1 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()

  Scenario: Work on a transaction does not affect the main repository                     # Transaction.feature:38
    Given There is a repository with multiple branches named repo1                        # WebAPICucumberHooks.setUpMultipleBranches(String)
    When I call "GET /repos/repo1/beginTransaction"                                       # WebAPICucumberHooks.callURL(String)
    Then the response status should be '200'                                              # WebAPICucumberHooks.checkStatusCode(int)
    And the xpath "/response/success/text()" equals "true"                                # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xml response should contain "/response/Transaction/ID"                        # WebAPICucumberHooks.checkResponseContainsXPath(String)
    And I save the response "/response/Transaction/ID/text()" as "@txId"                  # WebAPICucumberHooks.saveResponseXPathValueAsVariable(String,String)
    When I have committed "Point.2" on the "repo1" repo in the "@txId" transaction        # WebAPICucumberHooks.I_have_committed(String,String,String)
    Then the variable "{@ObjectId|repo1|master:Points/Point.2}" equals ""                 # WebAPICucumberHooks.checkVariableEquals(String,String)
    And the variable "{@ObjectId|repo1|@txId|master~1}" equals "{@ObjectId|repo1|master}" # WebAPICucumberHooks.checkVariableEquals(String,String)
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo1 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()

  Scenario: Ending a transaction moves the work to the main repository                           # Transaction.feature:49
    Given There is a repository with multiple branches named repo1                               # WebAPICucumberHooks.setUpMultipleBranches(String)
    When I call "GET /repos/repo1/beginTransaction"                                              # WebAPICucumberHooks.callURL(String)
    Then the response status should be '200'                                                     # WebAPICucumberHooks.checkStatusCode(int)
    And the xpath "/response/success/text()" equals "true"                                       # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xml response should contain "/response/Transaction/ID"                               # WebAPICucumberHooks.checkResponseContainsXPath(String)
    And I save the response "/response/Transaction/ID/text()" as "@txId"                         # WebAPICucumberHooks.saveResponseXPathValueAsVariable(String,String)
    When I have committed "Point.2" on the "repo1" repo in the "@txId" transaction               # WebAPICucumberHooks.I_have_committed(String,String,String)
    Then the variable "{@ObjectId|repo1|master:Points/Point.2}" equals ""                        # WebAPICucumberHooks.checkVariableEquals(String,String)
    And the variable "{@ObjectId|repo1|@txId|master~1}" equals "{@ObjectId|repo1|master}"        # WebAPICucumberHooks.checkVariableEquals(String,String)
    When I call "GET /repos/repo1/endTransaction?transactionId={@txId}"                          # WebAPICucumberHooks.callURL(String)
    Then the response status should be '200'                                                     # WebAPICucumberHooks.checkStatusCode(int)
    And the xpath "/response/success/text()" equals "true"                                       # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xpath "/response/Transaction/ID/text()" equals "{@txId}"                             # WebAPICucumberHooks.checkXPathEquals(String,String)
    When I call "GET /repos/repo1/cat?objectid={@ObjectId|repo1|master:Points/Point.2}"          # WebAPICucumberHooks.callURL(String)
    Then the response status should be '200'                                                     # WebAPICucumberHooks.checkStatusCode(int)
    And the xpath "/response/success/text()" equals "true"                                       # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xpath "/response/feature/id/text()" equals "{@ObjectId|repo1|master:Points/Point.2}" # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xml response should contain "/response/feature/attribute" 3 times                    # WebAPICucumberHooks.checkXPathCadinality(String,int)
    And the response body should contain "StringProp1_2"                                         # WebAPICucumberHooks.checkResponseTextContains(String)
    And the response body should contain "2000"                                                  # WebAPICucumberHooks.checkResponseTextContains(String)
    And the response body should contain "POINT (-10 -10)"                                       # WebAPICucumberHooks.checkResponseTextContains(String)
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo1 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()

  Scenario: Canceling a transaction leaves the main repository without changes            # Transaction.feature:72
    Given There is a repository with multiple branches named repo1                        # WebAPICucumberHooks.setUpMultipleBranches(String)
    When I call "GET /repos/repo1/beginTransaction"                                       # WebAPICucumberHooks.callURL(String)
    Then the response status should be '200'                                              # WebAPICucumberHooks.checkStatusCode(int)
    And the xpath "/response/success/text()" equals "true"                                # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xml response should contain "/response/Transaction/ID"                        # WebAPICucumberHooks.checkResponseContainsXPath(String)
    And I save the response "/response/Transaction/ID/text()" as "@txId"                  # WebAPICucumberHooks.saveResponseXPathValueAsVariable(String,String)
    When I have committed "Point.2" on the "repo1" repo in the "@txId" transaction        # WebAPICucumberHooks.I_have_committed(String,String,String)
    Then the variable "{@ObjectId|repo1|master:Points/Point.2}" equals ""                 # WebAPICucumberHooks.checkVariableEquals(String,String)
    And the variable "{@ObjectId|repo1|@txId|master~1}" equals "{@ObjectId|repo1|master}" # WebAPICucumberHooks.checkVariableEquals(String,String)
    When I call "GET /repos/repo1/endTransaction?transactionId={@txId}&cancel=true"       # WebAPICucumberHooks.callURL(String)
    Then the response status should be '200'                                              # WebAPICucumberHooks.checkStatusCode(int)
    And the xpath "/response/success/text()" equals "true"                                # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xpath "/response/Transaction/ID/text()" equals "{@txId}"                      # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the variable "{@ObjectId|repo1|master:Points/Point.2}" equals ""                  # WebAPICucumberHooks.checkVariableEquals(String,String)
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo1 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()

  Scenario: Ending a transaction with conflicting changes returns details of the conflict                      # Transaction.feature:88
    Given There is a repository with multiple branches named repo1                                             # WebAPICucumberHooks.setUpMultipleBranches(String)
    When I call "GET /repos/repo1/beginTransaction"                                                            # WebAPICucumberHooks.callURL(String)
    Then the response status should be '200'                                                                   # WebAPICucumberHooks.checkStatusCode(int)
    And the xpath "/response/success/text()" equals "true"                                                     # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xml response should contain "/response/Transaction/ID"                                             # WebAPICucumberHooks.checkResponseContainsXPath(String)
    And I save the response "/response/Transaction/ID/text()" as "@txId"                                       # WebAPICucumberHooks.saveResponseXPathValueAsVariable(String,String)
    When I call "GET /repos/repo1/beginTransaction"                                                            # WebAPICucumberHooks.callURL(String)
    Then the response status should be '200'                                                                   # WebAPICucumberHooks.checkStatusCode(int)
    And the xpath "/response/success/text()" equals "true"                                                     # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xml response should contain "/response/Transaction/ID"                                             # WebAPICucumberHooks.checkResponseContainsXPath(String)
    And I save the response "/response/Transaction/ID/text()" as "@txId2"                                      # WebAPICucumberHooks.saveResponseXPathValueAsVariable(String,String)
    When I have removed "Point.1_modified" on the "repo1" repo in the "@txId" transaction                      # WebAPICucumberHooks.I_have_removed(String,String,String)
    And I have committed "Point.1" on the "repo1" repo in the "@txId2" transaction                             # WebAPICucumberHooks.I_have_committed(String,String,String)
    When I call "GET /repos/repo1/endTransaction?transactionId={@txId2}"                                       # WebAPICucumberHooks.callURL(String)
    Then the response status should be '200'                                                                   # WebAPICucumberHooks.checkStatusCode(int)
    And the xpath "/response/success/text()" equals "true"                                                     # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xpath "/response/Transaction/ID/text()" equals "{@txId2}"                                          # WebAPICucumberHooks.checkXPathEquals(String,String)
    When I call "GET /repos/repo1/endTransaction?transactionId={@txId}"                                        # WebAPICucumberHooks.callURL(String)
    Then the response status should be '200'                                                                   # WebAPICucumberHooks.checkStatusCode(int)
    And the xpath "/response/success/text()" equals "true"                                                     # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xpath "/response/Merge/theirs/text()" equals "{@ObjectId|repo1|master}"                            # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xpath "/response/Merge/ours/text()" equals "{@ObjectId|repo1|@txId|master}"                        # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xpath "/response/Merge/ancestor/text()" equals "{@ObjectId|repo1|master~1}"                        # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xpath "/response/Merge/conflicts/text()" equals "1"                                                # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xpath "/response/Merge/Feature/change/text()" equals "CONFLICT"                                    # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xpath "/response/Merge/Feature/id/text()" equals "Points/Point.1"                                  # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xpath "/response/Merge/Feature/ourvalue/text()" equals "0000000000000000000000000000000000000000"  # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xpath "/response/Merge/Feature/theirvalue/text()" equals "{@ObjectId|repo1|master:Points/Point.1}" # WebAPICucumberHooks.checkXPathEquals(String,String)
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo1 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()

  Scenario: Fixing transaction conflicts and ending again is successful                                        # Transaction.feature:118
    Given There is a repository with multiple branches named repo1                                             # WebAPICucumberHooks.setUpMultipleBranches(String)
    When I call "GET /repos/repo1/beginTransaction"                                                            # WebAPICucumberHooks.callURL(String)
    Then the response status should be '200'                                                                   # WebAPICucumberHooks.checkStatusCode(int)
    And the xpath "/response/success/text()" equals "true"                                                     # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xml response should contain "/response/Transaction/ID"                                             # WebAPICucumberHooks.checkResponseContainsXPath(String)
    And I save the response "/response/Transaction/ID/text()" as "@txId"                                       # WebAPICucumberHooks.saveResponseXPathValueAsVariable(String,String)
    When I call "GET /repos/repo1/beginTransaction"                                                            # WebAPICucumberHooks.callURL(String)
    Then the response status should be '200'                                                                   # WebAPICucumberHooks.checkStatusCode(int)
    And the xpath "/response/success/text()" equals "true"                                                     # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xml response should contain "/response/Transaction/ID"                                             # WebAPICucumberHooks.checkResponseContainsXPath(String)
    And I save the response "/response/Transaction/ID/text()" as "@txId2"                                      # WebAPICucumberHooks.saveResponseXPathValueAsVariable(String,String)
    And I have removed "Point.1_modified" on the "repo1" repo in the "@txId" transaction                       # WebAPICucumberHooks.I_have_removed(String,String,String)
    And I have committed "Point.1" on the "repo1" repo in the "@txId2" transaction                             # WebAPICucumberHooks.I_have_committed(String,String,String)
    When I call "GET /repos/repo1/endTransaction?transactionId={@txId2}"                                       # WebAPICucumberHooks.callURL(String)
    Then the response status should be '200'                                                                   # WebAPICucumberHooks.checkStatusCode(int)
    And the xpath "/response/success/text()" equals "true"                                                     # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xpath "/response/Transaction/ID/text()" equals "{@txId2}"                                          # WebAPICucumberHooks.checkXPathEquals(String,String)
    When I call "GET /repos/repo1/endTransaction?transactionId={@txId}"                                        # WebAPICucumberHooks.callURL(String)
    Then the response status should be '200'                                                                   # WebAPICucumberHooks.checkStatusCode(int)
    And the xpath "/response/success/text()" equals "true"                                                     # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xpath "/response/Merge/theirs/text()" equals "{@ObjectId|repo1|master}"                            # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xpath "/response/Merge/ours/text()" equals "{@ObjectId|repo1|@txId|master}"                        # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xpath "/response/Merge/ancestor/text()" equals "{@ObjectId|repo1|master~1}"                        # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xpath "/response/Merge/conflicts/text()" equals "1"                                                # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xpath "/response/Merge/Feature/change/text()" equals "CONFLICT"                                    # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xpath "/response/Merge/Feature/id/text()" equals "Points/Point.1"                                  # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xpath "/response/Merge/Feature/ourvalue/text()" equals "0000000000000000000000000000000000000000"  # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xpath "/response/Merge/Feature/theirvalue/text()" equals "{@ObjectId|repo1|master:Points/Point.1}" # WebAPICucumberHooks.checkXPathEquals(String,String)
    Then I have committed "Point.1" on the "repo1" repo in the "@txId" transaction                             # WebAPICucumberHooks.I_have_committed(String,String,String)
    When I call "GET /repos/repo1/endTransaction?transactionId={@txId}"                                        # WebAPICucumberHooks.callURL(String)
    Then the response status should be '200'                                                                   # WebAPICucumberHooks.checkStatusCode(int)
    And the xpath "/response/success/text()" equals "true"                                                     # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xpath "/response/Transaction/ID/text()" equals "{@txId}"                                           # WebAPICucumberHooks.checkXPathEquals(String,String)
    When I call "GET /repos/repo1/cat?objectid={@ObjectId|repo1|master:Points/Point.1}"                        # WebAPICucumberHooks.callURL(String)
    Then the response status should be '200'                                                                   # WebAPICucumberHooks.checkStatusCode(int)
    And the xpath "/response/success/text()" equals "true"                                                     # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xpath "/response/feature/id/text()" equals "{@ObjectId|repo1|master:Points/Point.1}"               # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xml response should contain "/response/feature/attribute" 3 times                                  # WebAPICucumberHooks.checkXPathCadinality(String,int)
    And the response body should contain "StringProp1_1"                                                       # WebAPICucumberHooks.checkResponseTextContains(String)
    And the response body should contain "1000"                                                                # WebAPICucumberHooks.checkResponseTextContains(String)
    And the response body should contain "POINT (0 0)"                                                         # WebAPICucumberHooks.checkResponseTextContains(String)
@Commands @UpdateRef
Feature: UpdateRef
  The UpdateRef command allows a user to manually change the value of a ref and is supported through the "/repos/{repository}/updateref" endpoint
  The command must be executed using the HTTP GET method
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo1 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()

  Scenario: Verify wrong HTTP method issues 405 "Method not allowed" # UpdateRef.feature:6
    Given There is an empty repository named repo1                   # WebAPICucumberHooks.setUpEmptyRepo(String)
    When I call "PUT /repos/repo1/updateref"                         # WebAPICucumberHooks.callURL(String)
    Then the response status should be '405'                         # WebAPICucumberHooks.checkStatusCode(int)
    And the response allowed methods should be "GET"                 # WebAPICucumberHooks.checkResponseAllowedMethods(String)
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo1 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()

  Scenario: UpdateRef outside of a repository issues 404 "Not found" # UpdateRef.feature:12
    Given There is an empty multirepo server                         # WebAPICucumberHooks.setUpEmptyMultiRepo()
    When I call "GET /repos/repo1/updateref?name=master"             # WebAPICucumberHooks.callURL(String)
    Then the response status should be '404'                         # WebAPICucumberHooks.checkStatusCode(int)
    And the response ContentType should be "text/plain"              # WebAPICucumberHooks.checkContentType(String)
    And the response body should contain "Repository not found"      # WebAPICucumberHooks.checkResponseTextContains(String)
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo1 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()

  Scenario: Calling UpdateRef without a ref name issues a 500 status code                       # UpdateRef.feature:19
    Given There is an empty repository named repo1                                              # WebAPICucumberHooks.setUpEmptyRepo(String)
    When I call "GET /repos/repo1/updateref"                                                    # WebAPICucumberHooks.callURL(String)
    Then the response status should be '500'                                                    # WebAPICucumberHooks.checkStatusCode(int)
    And the xpath "/response/error/text()" equals "Required parameter 'name' was not provided." # WebAPICucumberHooks.checkXPathEquals(String,String)
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo1 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()

  Scenario: Calling UpdateRef without a new value or delete specified issues a 500 status code                                                # UpdateRef.feature:25
    Given There is an empty repository named repo1                                                                                            # WebAPICucumberHooks.setUpEmptyRepo(String)
    When I call "GET /repos/repo1/updateref?name=master"                                                                                      # WebAPICucumberHooks.callURL(String)
    Then the response status should be '500'                                                                                                  # WebAPICucumberHooks.checkStatusCode(int)
    And the xpath "/response/error/text()" equals "Nothing specified to update with, must specify either deletion or new value to update to." # WebAPICucumberHooks.checkXPathEquals(String,String)
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo1 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()

  Scenario: Calling UpdateRef without a nonexistent name issues a 500 status code # UpdateRef.feature:31
    Given There is an empty repository named repo1                                # WebAPICucumberHooks.setUpEmptyRepo(String)
    When I call "GET /repos/repo1/updateref?name=nonexistent&delete=true"         # WebAPICucumberHooks.callURL(String)
    Then the response status should be '500'                                      # WebAPICucumberHooks.checkStatusCode(int)
    And the xpath "/response/error/text()" equals "Invalid name: nonexistent"     # WebAPICucumberHooks.checkXPathEquals(String,String)
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo1 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo2 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()

  Scenario: Calling UpdateRef with a new value updates the ref                              # UpdateRef.feature:37
    Given There is a default multirepo server                                               # WebAPICucumberHooks.setUpDefaultMultiRepo()
    When I call "GET /repos/repo1/updateref?name=master&newValue={@ObjectId|repo1|branch1}" # WebAPICucumberHooks.callURL(String)
    Then the response status should be '200'                                                # WebAPICucumberHooks.checkStatusCode(int)
    And the xpath "/response/success/text()" equals "true"                                  # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xpath "/response/ChangedRef/name/text()" equals "refs/heads/master"             # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xpath "/response/ChangedRef/objectId/text()" equals "{@ObjectId|repo1|branch1}" # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the variable "{@ObjectId|repo1|master}" equals "{@ObjectId|repo1|branch1}"          # WebAPICucumberHooks.checkVariableEquals(String,String)
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo1 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo2 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()

  Scenario: Calling UpdateRef with the delete parameter deletes the ref                        # UpdateRef.feature:46
    Given There is a default multirepo server                                                  # WebAPICucumberHooks.setUpDefaultMultiRepo()
    When I call "GET /repos/repo1/updateref?name=branch1&delete=true"                          # WebAPICucumberHooks.callURL(String)
    Then the response status should be '200'                                                   # WebAPICucumberHooks.checkStatusCode(int)
    And the xpath "/response/success/text()" equals "true"                                     # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xpath "/response/ChangedRef/name/text()" equals "refs/heads/branch1"               # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xpath "/response/ChangedRef/objectId/text()" equals "{@ObjectId|repo1|master^1^2}" # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the variable "{@ObjectId|repo1|branch1}" equals ""                                     # WebAPICucumberHooks.checkVariableEquals(String,String)
@Commands @Version
Feature: Version
  The Version command allows a user to see the geogig version and is supported through the "/repos/{repository}/version" endpoint
  The command must be executed using the HTTP GET method
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo1 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()

  Scenario: Verify wrong HTTP method issues 405 "Method not allowed" # Version.feature:6
    Given There is an empty repository named repo1                   # WebAPICucumberHooks.setUpEmptyRepo(String)
    When I call "PUT /repos/repo1/version"                           # WebAPICucumberHooks.callURL(String)
    Then the response status should be '405'                         # WebAPICucumberHooks.checkStatusCode(int)
    And the response allowed methods should be "GET"                 # WebAPICucumberHooks.checkResponseAllowedMethods(String)
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo1 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()

  Scenario: Version outside of a repository issues 404 "Not found" # Version.feature:12
    Given There is an empty multirepo server                       # WebAPICucumberHooks.setUpEmptyMultiRepo()
    When I call "GET /repos/repo1/version"                         # WebAPICucumberHooks.callURL(String)
    Then the response status should be '404'                       # WebAPICucumberHooks.checkStatusCode(int)
    And the response ContentType should be "text/plain"            # WebAPICucumberHooks.checkContentType(String)
    And the response body should contain "Repository not found"    # WebAPICucumberHooks.checkResponseTextContains(String)
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Loading repository repo1 using FileRepositoryResolver
[main] INFO org.locationtech.geogig.web.MultiRepositoryProvider - Disposing repository {}. Cause: manually removed by remove() or invalidateAll()

  Scenario: Version returns geogig version details                               # Version.feature:19
    Given There is an empty repository named repo1                               # WebAPICucumberHooks.setUpEmptyRepo(String)
    When I call "GET /repos/repo1/version"                                       # WebAPICucumberHooks.callURL(String)
    Then the response status should be '200'                                     # WebAPICucumberHooks.checkStatusCode(int)
    And the xpath "/response/success/text()" equals "true"                       # WebAPICucumberHooks.checkXPathEquals(String,String)
    And the xml response should contain "/response/ProjectVersion" 1 times       # WebAPICucumberHooks.checkXPathCadinality(String,int)
    And the xml response should contain "/response/BuildTime" 1 times            # WebAPICucumberHooks.checkXPathCadinality(String,int)
    And the xml response should contain "/response/BuildUserName" 1 times        # WebAPICucumberHooks.checkXPathCadinality(String,int)
    And the xml response should contain "/response/BuildUserEmail" 1 times       # WebAPICucumberHooks.checkXPathCadinality(String,int)
    And the xml response should contain "/response/GitBranch" 1 times            # WebAPICucumberHooks.checkXPathCadinality(String,int)
    And the xml response should contain "/response/GitCommitID" 1 times          # WebAPICucumberHooks.checkXPathCadinality(String,int)
    And the xml response should contain "/response/GitCommitTime" 1 times        # WebAPICucumberHooks.checkXPathCadinality(String,int)
    And the xml response should contain "/response/GitCommitAuthorName" 1 times  # WebAPICucumberHooks.checkXPathCadinality(String,int)
    And the xml response should contain "/response/GitCommitAuthorEmail" 1 times # WebAPICucumberHooks.checkXPathCadinality(String,int)
    And the xml response should contain "/response/GitCommitMessage" 1 times     # WebAPICucumberHooks.checkXPathCadinality(String,int)

359 Scenarios (359 passed)
2805 Steps (2805 passed)
2m25.296s

Tests run: 3164, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 147.88 sec - in org.geogig.web.functional.RunFunctionalTest

Results :

Tests run: 3261, Failures: 0, Errors: 0, Skipped: 0

[JENKINS] Recording test results
[INFO] 
[INFO] --- maven-jar-plugin:2.4:jar (default-jar) @ geogig-web-api-functional-tests ---
[INFO] Building jar: /home/hudson/genie.geogig/.jenkins/jobs/geogig-release/workspace/src/web/functional/target/geogig-web-api-functional-tests-1.1.1-RC1.jar
[INFO] 
[INFO] --- maven-jar-plugin:2.4:test-jar (default) @ geogig-web-api-functional-tests ---
[INFO] Building jar: /home/hudson/genie.geogig/.jenkins/jobs/geogig-release/workspace/src/web/functional/target/geogig-web-api-functional-tests-1.1.1-RC1-tests.jar
[INFO] 
[INFO] >>> maven-source-plugin:2.2.1:jar (attach-sources) > generate-sources @ geogig-web-api-functional-tests >>>
[INFO] 
[INFO] --- git-commit-id-plugin:2.2.2:revision (default) @ geogig-web-api-functional-tests ---
[WARNING] Failed to getClass for org.apache.maven.plugin.source.SourceJarMojo
[INFO] 
[INFO] <<< maven-source-plugin:2.2.1:jar (attach-sources) < generate-sources @ geogig-web-api-functional-tests <<<
[INFO] 
[INFO] --- maven-source-plugin:2.2.1:jar (attach-sources) @ geogig-web-api-functional-tests ---
[INFO] Building jar: /home/hudson/genie.geogig/.jenkins/jobs/geogig-release/workspace/src/web/functional/target/geogig-web-api-functional-tests-1.1.1-RC1-sources.jar
[INFO] 
[INFO] >>> maven-source-plugin:2.2.1:test-jar (attach-sources) > generate-sources @ geogig-web-api-functional-tests >>>
[INFO] 
[INFO] --- git-commit-id-plugin:2.2.2:revision (default) @ geogig-web-api-functional-tests ---
[WARNING] Failed to getClass for org.apache.maven.plugin.source.TestSourceJarMojo
[INFO] 
[INFO] <<< maven-source-plugin:2.2.1:test-jar (attach-sources) < generate-sources @ geogig-web-api-functional-tests <<<
[INFO] 
[INFO] --- maven-source-plugin:2.2.1:test-jar (attach-sources) @ geogig-web-api-functional-tests ---
[INFO] Building jar: /home/hudson/genie.geogig/.jenkins/jobs/geogig-release/workspace/src/web/functional/target/geogig-web-api-functional-tests-1.1.1-RC1-test-sources.jar
[INFO] 
[INFO] --- maven-install-plugin:2.4:install (default-install) @ geogig-web-api-functional-tests ---
[INFO] Installing /home/hudson/genie.geogig/.jenkins/jobs/geogig-release/workspace/src/web/functional/target/geogig-web-api-functional-tests-1.1.1-RC1.jar to /home/hudson/genie.geogig/.jenkins/jobs/geogig-release/workspace/.repository/org/locationtech/geogig/geogig-web-api-functional-tests/1.1.1-RC1/geogig-web-api-functional-tests-1.1.1-RC1.jar
[INFO] Installing /home/hudson/genie.geogig/.jenkins/jobs/geogig-release/workspace/src/web/functional/pom.xml to /home/hudson/genie.geogig/.jenkins/jobs/geogig-release/workspace/.repository/org/locationtech/geogig/geogig-web-api-functional-tests/1.1.1-RC1/geogig-web-api-functional-tests-1.1.1-RC1.pom
[INFO] Installing /home/hudson/genie.geogig/.jenkins/jobs/geogig-release/workspace/src/web/functional/target/geogig-web-api-functional-tests-1.1.1-RC1-tests.jar to /home/hudson/genie.geogig/.jenkins/jobs/geogig-release/workspace/.repository/org/locationtech/geogig/geogig-web-api-functional-tests/1.1.1-RC1/geogig-web-api-functional-tests-1.1.1-RC1-tests.jar
[INFO] Installing /home/hudson/genie.geogig/.jenkins/jobs/geogig-release/workspace/src/web/functional/target/geogig-web-api-functional-tests-1.1.1-RC1-sources.jar to /home/hudson/genie.geogig/.jenkins/jobs/geogig-release/workspace/.repository/org/locationtech/geogig/geogig-web-api-functional-tests/1.1.1-RC1/geogig-web-api-functional-tests-1.1.1-RC1-sources.jar
[INFO] Installing /home/hudson/genie.geogig/.jenkins/jobs/geogig-release/workspace/src/web/functional/target/geogig-web-api-functional-tests-1.1.1-RC1-test-sources.jar to /home/hudson/genie.geogig/.jenkins/jobs/geogig-release/workspace/.repository/org/locationtech/geogig/geogig-web-api-functional-tests/1.1.1-RC1/geogig-web-api-functional-tests-1.1.1-RC1-test-sources.jar
[JENKINS] Archiving disabled