You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@tinkerpop.apache.org by sp...@apache.org on 2018/02/24 16:53:22 UTC

tinkerpop git commit: Added some docs about Gherkin tests CTR

Repository: tinkerpop
Updated Branches:
  refs/heads/tp32 d97056443 -> 5b4bd0074


Added some docs about Gherkin tests CTR


Project: http://git-wip-us.apache.org/repos/asf/tinkerpop/repo
Commit: http://git-wip-us.apache.org/repos/asf/tinkerpop/commit/5b4bd007
Tree: http://git-wip-us.apache.org/repos/asf/tinkerpop/tree/5b4bd007
Diff: http://git-wip-us.apache.org/repos/asf/tinkerpop/diff/5b4bd007

Branch: refs/heads/tp32
Commit: 5b4bd0074f5547ecb9b08a751a3b7b0988835ed8
Parents: d970564
Author: Stephen Mallette <sp...@genoprime.com>
Authored: Sat Feb 24 11:51:27 2018 -0500
Committer: Stephen Mallette <sp...@genoprime.com>
Committed: Sat Feb 24 11:51:27 2018 -0500

----------------------------------------------------------------------
 docs/src/dev/developer/for-committers.asciidoc | 216 +++++++++++++++++++-
 1 file changed, 215 insertions(+), 1 deletion(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/5b4bd007/docs/src/dev/developer/for-committers.asciidoc
----------------------------------------------------------------------
diff --git a/docs/src/dev/developer/for-committers.asciidoc b/docs/src/dev/developer/for-committers.asciidoc
index 14fa90a..b44de9a 100644
--- a/docs/src/dev/developer/for-committers.asciidoc
+++ b/docs/src/dev/developer/for-committers.asciidoc
@@ -174,7 +174,14 @@ for an example.
 
 === Gremlin Language Test Cases
 
-When writing a test case for a Gremlin step, be sure to use the following conventions.
+Test cases for the Gremlin Language currently requires that the newly developed test be added in three places:
+
+1. As a test written in Java in the `gremlin-test` module within the subpackages of
+`org.apache.tinkerpop.gremlin.process.traversal.step`
+2. As a test written in Groovy in the `gremlin-groovy-test` module within the same subpackage structure as `gremlin-test`
+3. As a test written in Gherkin in the `gremlin-test` module in the `/features` subdirectory
+
+When writing a Java test case for a Gremlin step, be sure to use the following conventions.
 
 * The name of the traversal generator should start with `get`, use `X` for brackets, `_` for space, and the Gremlin-Groovy sugar syntax.
 ** `get_g_V_hasLabelXpersonX_groupXaX_byXageX_byXsumX_name()`
@@ -189,6 +196,213 @@ When writing a test case for a Gremlin step, be sure to use the following conven
 ** `checkResults(Arrays.asList("marko","josh"), traversal)`
 ** `checkMap(new HashMap<String,Long>() {{ put("marko",1l); }}, traversal.next())`
 
+Groovy tests are implemented by extending the Java test and implementing the abstract method that produces the
+traversal. Simply follow existing patterns in those tests - they are self-evident.
+
+Gherkin tests follow some important conventions and have a sub-language that must be adhered to for the tests to
+function properly. Note that Gherkin tests are designed to support the testing of GLVs and at some point will likely
+replace the Java tests (Groovy tests have already been removed in 3.3.x). If a new Java test is added and an associated
+Gherkin tests is not, the overall build will fail the `FeatureCoverageTest` of `gremlin-test` which validates that all
+tests written in Java are also implemented in Gherkin.
+
+The basic syntax of a Gherkin test is as follows:
+
+[source,gherkin]
+----
+Scenario: g_VX1X_unionXrepeatXoutX_timesX2X__outX_name
+  Given the modern graph
+  And using the parameter v1Id defined as "v[marko].id"
+  And the traversal of
+    """
+    g.V(v1Id).union(__.repeat(__.out()).times(2), __.out()).values("name")
+    """
+  When iterated to list
+  Then the result should be unordered
+    | result |
+    | ripple |
+    | lop |
+    | lop   |
+    | vadas |
+    | josh  |
+----
+
+==== Scenario Name
+
+The name of the scenario needs to match the name of the Java test. If it does not then the `FeatureCoverageTest` will
+fail.
+
+==== Given
+
+"Given" sets the context of the test. Specifically, it establishes the graph that will be used for the test. It
+conforms to the pattern of "Given the _xxx_ graph" where the "xxx" may be one of the following:
+
+* empty
+* modern
+* classic
+* crew
+* sink
+* grateful
+
+Never modify the data of any of the graphs except for the "empty" graph. The "empty" graph is the only graph that is
+guaranteed to be refreshed between tests. The "empty" graph maybe be modified by the traversal under test or by an
+additional "Given" option:
+
+[source,gherkin]
+----
+Given the empty graph
+And the graph initializer of
+  """
+  g.addV("person").property(T.id, 1).property("name", "marko").property("age", 29).as("marko").
+    addV("person").property(T.id, 2).property("name", "vadas").property("age", 27).as("vadas").
+    addV("software").property(T.id, 3).property("name", "lop").property("lang", "java").as("lop").
+    addV("person").property(T.id, 4).property("name","josh").property("age", 32).as("josh").
+    addV("software").property(T.id, 5).property("name", "ripple").property("lang", "java").as("ripple").
+    addV("person").property(T.id, 6).property("name", "peter").property("age", 35).as('peter').
+    addE("knows").from("marko").to("vadas").property(T.id, 7).property("weight", 0.5).
+    addE("knows").from("marko").to("josh").property(T.id, 8).property("weight", 1.0).
+    addE("created").from("marko").to("lop").property(T.id, 9).property("weight", 0.4).
+    addE("created").from("josh").to("ripple").property(T.id, 10).property("weight", 1.0).
+    addE("created").from("josh").to("lop").property(T.id, 11).property("weight", 0.4).
+    addE("created").from("peter").to("lop").property(T.id, 12).property("weight", 0.2)
+  """
+----
+
+The above configuration will use the "empty" graph and initialize it with the specified traversal. In this case, that
+traversal loads the "empty" graph with the "modern" graph.
+
+Once the graph for the test is defined, the context can be expanded to include parameters that will be applied to the
+traversal under test. Any variable value being used in the traversal under test, especially ones that require a
+specific type, should be defined as parameters. The structure for parameter definition looks like this:
+
+[source,gherkin]
+----
+Given the modern graph
+And using the parameter v1Id defined as "v[marko].id"
+----
+
+In the above example, "v1Id" is the name of the parameter that will be used in the traversal. The end of that line in
+quotes is the value of that parameter and should use the type system notation that has been developed for the TinkerPop
+Gherkin tests. The type system notation ensures that different language variants have the ability to construct the
+appropriate types expected by the tests.
+
+The syntax of the type notation involves a prefix character to help denote the type, a value between two square
+brackets, optionally suffixed with some additional notation depending on the primary type.
+
+* Edge - *e[_xxx_]* - The "xxx" should be replaced with a representation of an edge in the form of the
+`vertex_name-edgelabel->vertex_name`. This syntax may also include the `.id` suffix which would indicate getting the
+edge identifier or the `.sid` suffix which gets a string representation of the edge identifier.
+* Lambda - *c[_xxx_]* - The "xxx" should contain a lambda written in Groovy.
+* List - *l[_xxx_,_yyy_,_zzz_,...]* - A comma separated collection of values that make up the list should be added to
+between the square brackets. These values respect the type system thus allowing for creation of lists of vertices,
+edges, maps, and any other available type.
+* Map - *m[_xxx_]* - The "xxx" should be replaced with a JSON string. Note that keys and values will be parsed using
+the type notation system so that it is possible to have maps containing arbitrary keys and values.
+* Numeric - *d[_xxx_]._y_* - The "xxx" should be replaced with a number. The suffix denoted by "y" should always be
+included to further qualify the type of numeric. The following options are available:
+** *d* - 32-bit Double
+** *f* - 32-bit Float
+** *i* - 32-bit Integer
+** *l* - 64-bit Long
+** *m* - Arbitrary-precision signed decimal numbers (i.e. BigDecimal in Java)
+* Path - *p[_xxx_,_yyy_,_zzz_,...]* - A comma separated collection of values that make up the `Path` should be added to
+between the square brackets. These values respect the type system thus allowing for creation of `Path` of vertices,
+edges, maps, and any other available type.
+* Set - *s[_xxx_,_yyy_,_zzz_,...]* - A comma separated collection of values that make up the set should be added to
+between the square brackets. These values respect the type system thus allowing for creation of sets of vertices,
+edges, maps, and any other available type.
+* String - Any value not using the system notation will be interpreted as a string.
+* T - *t[_xxx_]* - The "xxx" should be replaced with a value of the `T` enum, such as `id` or `label`.
+* Vertex - *v[_xxx_]* - The "xxx" should be replaced with the "name" property of a vertex in the graph. This syntax may
+include the `.id` suffix which would indicate getting the vertex identifier or the `.sid` suffix which gets a string
+representation of the edge identifier.
+
+Finally, specify the traversal under test with the "Given" option "and the traversal":
+
+[source,gherkin]
+----
+And the traversal of
+  """
+  g.V(v1Id).union(__.repeat(__.out()).times(2), __.out()).values("name")
+  """
+----
+
+It will be the results of this traversal that end up being asserted by Gherkin. When writing these test traversals,
+be sure to always use the method and enum prefixes. For example, use  `__.out()` for an anonymous traversal rather
+than just `out()` and prefer `Scope.local` rather than just `local`.
+
+If a particular test cannot be written in Gherkin for some reason or cannot be otherwise supported by a GLV, first,
+consider whether or not this test can be re-written in Java so that it will work for GLVs and then, second, if it
+cannot, then use the following syntax for unsupported tests:
+
+[source,gherkin]
+----
+Scenario: g_V_outXcreatedX_groupCountXxX_capXxX
+  Given an unsupported test
+  Then nothing should happen because
+    """
+    The result returned is not supported under GraphSON 2.x and therefore cannot be properly asserted. More
+    specifically it has vertex keys which basically get toString()'d under GraphSON 2.x. This test can be supported
+    with GraphSON 3.x.
+    """
+----
+
+==== When
+
+The "When" options get the result from the traversal in preparation for assertion. There are two options to iterate:
+
+* "When iterated to list" - iterates the entire traversal into a list result that is asserted
+* "When iterated next" - gets the first value from the traversal as the result to be asserted
+
+There should be only one "When" defined in a scenario.
+
+==== Then
+
+The "Then" options handle the assertion of the result. There are several options to consider:
+
+* "the result should have a count of _xxx_" - assumes a list value in the result and counts the number of values
+in it
+* "the result should be empty" - no results
+* "the result should be ordered" - the exact results and should appear in the order presented
+* "the result should be unordered" - the exact results but can appear any order
+* "the result should be of" - results can be any of the specified values and in any order (use when guarantees
+regarding the exact results cannot be pre-determined easily - see the `range()` step tests for examples)
+
+These final three types of assertions mentioned above should be followed by a Gherkin table that has one column, where
+each row value in that column represents a value to assert in the result. These values are type notation respected as
+shown in the following example:
+
+[source,gherkin]
+----
+Then the result should be unordered
+  | result |
+  | ripple |
+  | lop |
+  | lop   |
+  | vadas |
+  | josh  |
+----
+
+Another method of assertion is to test mutations in the original graph. Again, mutations should only occur on the
+"empty" graph, but they can be validated as follows:
+
+[source,gherkin]
+----
+Scenario: g_V_outE_drop
+  Given the empty graph
+  And the graph initializer of
+    """
+    g.addV().as("a").addV().as("b").addE("knows").to("a")
+    """
+  And the traversal of
+    """
+    g.V().outE().drop()
+    """
+  When iterated to list
+  Then the result should be empty
+  And the graph should return 2 for count of "g.V()"
+  And the graph should return 0 for count of "g.E()"
+----
+
 == Developing Benchmarks
 
 Benchmarks are a useful tool to track performance between TinkerPop versions and also as tools to aid development