From ca8bab0eae0a45a92f5177d5f228fea16ed5f661 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Fri, 21 Jun 2024 10:56:35 +0000 Subject: [PATCH 01/16] prepare for next development iteration --- core/access/pom.xml | 2 +- core/cache/pom.xml | 2 +- core/common-util/pom.xml | 2 +- core/data/pom.xml | 2 +- core/exception/pom.xml | 2 +- core/graph/pom.xml | 2 +- core/operation/pom.xml | 2 +- core/pom.xml | 2 +- core/serialisation/pom.xml | 2 +- core/store/pom.xml | 2 +- core/type/pom.xml | 2 +- example/basic/basic-model/pom.xml | 2 +- example/basic/basic-rest/pom.xml | 2 +- example/basic/pom.xml | 2 +- example/federated-demo/pom.xml | 2 +- example/pom.xml | 2 +- example/road-traffic/pom.xml | 2 +- example/road-traffic/road-traffic-demo/pom.xml | 2 +- example/road-traffic/road-traffic-generators/pom.xml | 2 +- example/road-traffic/road-traffic-model/pom.xml | 2 +- example/road-traffic/road-traffic-rest/pom.xml | 2 +- integration-test/pom.xml | 2 +- library/bitmap-library/pom.xml | 2 +- library/cache-library/hazelcast-cache-service/pom.xml | 2 +- library/cache-library/jcs-cache-service/pom.xml | 2 +- library/cache-library/pom.xml | 2 +- library/flink-library/pom.xml | 2 +- library/hdfs-library/pom.xml | 2 +- library/pom.xml | 2 +- library/sketches-library/pom.xml | 2 +- library/spark/pom.xml | 2 +- library/spark/spark-accumulo-library/pom.xml | 2 +- library/spark/spark-library/pom.xml | 2 +- library/time-library/pom.xml | 2 +- library/tinkerpop/pom.xml | 2 +- pom.xml | 2 +- rest-api/accumulo-rest/pom.xml | 2 +- rest-api/common-rest/pom.xml | 2 +- rest-api/common-rest/src/main/resources/version.properties | 2 +- rest-api/core-rest/pom.xml | 2 +- rest-api/map-rest/pom.xml | 2 +- rest-api/pom.xml | 2 +- rest-api/spring-rest/pom.xml | 2 +- store-implementation/accumulo-store/pom.xml | 2 +- store-implementation/federated-store/pom.xml | 2 +- store-implementation/map-store/pom.xml | 2 +- store-implementation/pom.xml | 2 +- store-implementation/proxy-store/pom.xml | 2 +- 48 files changed, 48 insertions(+), 48 deletions(-) diff --git a/core/access/pom.xml b/core/access/pom.xml index 0f71727dcc0..fea431697d0 100644 --- a/core/access/pom.xml +++ b/core/access/pom.xml @@ -19,7 +19,7 @@ core uk.gov.gchq.gaffer - 2.2.2 + 2.2.3-SNAPSHOT 4.0.0 diff --git a/core/cache/pom.xml b/core/cache/pom.xml index 587329e0d88..67a4e76364a 100644 --- a/core/cache/pom.xml +++ b/core/cache/pom.xml @@ -19,7 +19,7 @@ core uk.gov.gchq.gaffer - 2.2.2 + 2.2.3-SNAPSHOT 4.0.0 diff --git a/core/common-util/pom.xml b/core/common-util/pom.xml index 7b37fb1d8ff..06c7d31b622 100644 --- a/core/common-util/pom.xml +++ b/core/common-util/pom.xml @@ -20,7 +20,7 @@ uk.gov.gchq.gaffer core - 2.2.2 + 2.2.3-SNAPSHOT common-util diff --git a/core/data/pom.xml b/core/data/pom.xml index 90c374daef8..fc38e89f5c9 100644 --- a/core/data/pom.xml +++ b/core/data/pom.xml @@ -19,7 +19,7 @@ uk.gov.gchq.gaffer core - 2.2.2 + 2.2.3-SNAPSHOT 4.0.0 diff --git a/core/exception/pom.xml b/core/exception/pom.xml index 49c6e8ac3ec..e948d1f3610 100644 --- a/core/exception/pom.xml +++ b/core/exception/pom.xml @@ -19,7 +19,7 @@ core uk.gov.gchq.gaffer - 2.2.2 + 2.2.3-SNAPSHOT 4.0.0 diff --git a/core/graph/pom.xml b/core/graph/pom.xml index 70abb3bf78a..b7720d02577 100644 --- a/core/graph/pom.xml +++ b/core/graph/pom.xml @@ -19,7 +19,7 @@ uk.gov.gchq.gaffer core - 2.2.2 + 2.2.3-SNAPSHOT 4.0.0 diff --git a/core/operation/pom.xml b/core/operation/pom.xml index 5f97eaaad97..68e5833a994 100644 --- a/core/operation/pom.xml +++ b/core/operation/pom.xml @@ -19,7 +19,7 @@ uk.gov.gchq.gaffer core - 2.2.2 + 2.2.3-SNAPSHOT 4.0.0 diff --git a/core/pom.xml b/core/pom.xml index 0b57541e6c0..5ac81ac663e 100644 --- a/core/pom.xml +++ b/core/pom.xml @@ -19,7 +19,7 @@ uk.gov.gchq.gaffer gaffer2 - 2.2.2 + 2.2.3-SNAPSHOT 4.0.0 diff --git a/core/serialisation/pom.xml b/core/serialisation/pom.xml index 7d1767e76ba..3873a729c6d 100644 --- a/core/serialisation/pom.xml +++ b/core/serialisation/pom.xml @@ -19,7 +19,7 @@ uk.gov.gchq.gaffer core - 2.2.2 + 2.2.3-SNAPSHOT 4.0.0 diff --git a/core/store/pom.xml b/core/store/pom.xml index 644cd98d81a..f3ae1c30a85 100644 --- a/core/store/pom.xml +++ b/core/store/pom.xml @@ -19,7 +19,7 @@ uk.gov.gchq.gaffer core - 2.2.2 + 2.2.3-SNAPSHOT 4.0.0 diff --git a/core/type/pom.xml b/core/type/pom.xml index dd39f62f8e6..309e2633b79 100644 --- a/core/type/pom.xml +++ b/core/type/pom.xml @@ -20,7 +20,7 @@ uk.gov.gchq.gaffer core - 2.2.2 + 2.2.3-SNAPSHOT type diff --git a/example/basic/basic-model/pom.xml b/example/basic/basic-model/pom.xml index 7d6e9ed1b8b..f70fa4638f7 100644 --- a/example/basic/basic-model/pom.xml +++ b/example/basic/basic-model/pom.xml @@ -19,7 +19,7 @@ uk.gov.gchq.gaffer basic - 2.2.2 + 2.2.3-SNAPSHOT 4.0.0 diff --git a/example/basic/basic-rest/pom.xml b/example/basic/basic-rest/pom.xml index fb073c6c713..21c659b61ac 100644 --- a/example/basic/basic-rest/pom.xml +++ b/example/basic/basic-rest/pom.xml @@ -19,7 +19,7 @@ uk.gov.gchq.gaffer basic - 2.2.2 + 2.2.3-SNAPSHOT 4.0.0 diff --git a/example/basic/pom.xml b/example/basic/pom.xml index e4b44658de8..6ea4ba1d0b6 100644 --- a/example/basic/pom.xml +++ b/example/basic/pom.xml @@ -19,7 +19,7 @@ uk.gov.gchq.gaffer example - 2.2.2 + 2.2.3-SNAPSHOT 4.0.0 diff --git a/example/federated-demo/pom.xml b/example/federated-demo/pom.xml index d9984fa3005..a56d1868764 100644 --- a/example/federated-demo/pom.xml +++ b/example/federated-demo/pom.xml @@ -19,7 +19,7 @@ uk.gov.gchq.gaffer example - 2.2.2 + 2.2.3-SNAPSHOT 4.0.0 diff --git a/example/pom.xml b/example/pom.xml index 1c4d7ec15b1..04b14accb82 100644 --- a/example/pom.xml +++ b/example/pom.xml @@ -21,7 +21,7 @@ uk.gov.gchq.gaffer gaffer2 - 2.2.2 + 2.2.3-SNAPSHOT example diff --git a/example/road-traffic/pom.xml b/example/road-traffic/pom.xml index 367f1701a99..f0a936d211e 100644 --- a/example/road-traffic/pom.xml +++ b/example/road-traffic/pom.xml @@ -19,7 +19,7 @@ uk.gov.gchq.gaffer example - 2.2.2 + 2.2.3-SNAPSHOT 4.0.0 diff --git a/example/road-traffic/road-traffic-demo/pom.xml b/example/road-traffic/road-traffic-demo/pom.xml index e82dc693218..a0ee3bdfdfe 100644 --- a/example/road-traffic/road-traffic-demo/pom.xml +++ b/example/road-traffic/road-traffic-demo/pom.xml @@ -19,7 +19,7 @@ uk.gov.gchq.gaffer road-traffic - 2.2.2 + 2.2.3-SNAPSHOT 4.0.0 diff --git a/example/road-traffic/road-traffic-generators/pom.xml b/example/road-traffic/road-traffic-generators/pom.xml index 86a7466dbe0..fe0134d0965 100644 --- a/example/road-traffic/road-traffic-generators/pom.xml +++ b/example/road-traffic/road-traffic-generators/pom.xml @@ -19,7 +19,7 @@ uk.gov.gchq.gaffer road-traffic - 2.2.2 + 2.2.3-SNAPSHOT 4.0.0 diff --git a/example/road-traffic/road-traffic-model/pom.xml b/example/road-traffic/road-traffic-model/pom.xml index a65d159f668..ff0f9591a76 100644 --- a/example/road-traffic/road-traffic-model/pom.xml +++ b/example/road-traffic/road-traffic-model/pom.xml @@ -19,7 +19,7 @@ uk.gov.gchq.gaffer road-traffic - 2.2.2 + 2.2.3-SNAPSHOT 4.0.0 diff --git a/example/road-traffic/road-traffic-rest/pom.xml b/example/road-traffic/road-traffic-rest/pom.xml index 8ff20fc4324..6fcc9a685f0 100644 --- a/example/road-traffic/road-traffic-rest/pom.xml +++ b/example/road-traffic/road-traffic-rest/pom.xml @@ -19,7 +19,7 @@ uk.gov.gchq.gaffer road-traffic - 2.2.2 + 2.2.3-SNAPSHOT 4.0.0 diff --git a/integration-test/pom.xml b/integration-test/pom.xml index 890763574f7..df13dcac182 100644 --- a/integration-test/pom.xml +++ b/integration-test/pom.xml @@ -21,7 +21,7 @@ uk.gov.gchq.gaffer gaffer2 - 2.2.2 + 2.2.3-SNAPSHOT integration-test diff --git a/library/bitmap-library/pom.xml b/library/bitmap-library/pom.xml index bcaf02800ad..02beda687bf 100644 --- a/library/bitmap-library/pom.xml +++ b/library/bitmap-library/pom.xml @@ -19,7 +19,7 @@ uk.gov.gchq.gaffer library - 2.2.2 + 2.2.3-SNAPSHOT 4.0.0 diff --git a/library/cache-library/hazelcast-cache-service/pom.xml b/library/cache-library/hazelcast-cache-service/pom.xml index d5561add1a2..031d6bf1e8d 100644 --- a/library/cache-library/hazelcast-cache-service/pom.xml +++ b/library/cache-library/hazelcast-cache-service/pom.xml @@ -19,7 +19,7 @@ uk.gov.gchq.gaffer cache-library - 2.2.2 + 2.2.3-SNAPSHOT 4.0.0 diff --git a/library/cache-library/jcs-cache-service/pom.xml b/library/cache-library/jcs-cache-service/pom.xml index d8ccb590309..d0b2ecc91d0 100644 --- a/library/cache-library/jcs-cache-service/pom.xml +++ b/library/cache-library/jcs-cache-service/pom.xml @@ -19,7 +19,7 @@ uk.gov.gchq.gaffer cache-library - 2.2.2 + 2.2.3-SNAPSHOT 4.0.0 diff --git a/library/cache-library/pom.xml b/library/cache-library/pom.xml index 8742a8b54e7..23c4e16d80f 100644 --- a/library/cache-library/pom.xml +++ b/library/cache-library/pom.xml @@ -19,7 +19,7 @@ uk.gov.gchq.gaffer library - 2.2.2 + 2.2.3-SNAPSHOT 4.0.0 diff --git a/library/flink-library/pom.xml b/library/flink-library/pom.xml index 90a386ebc02..7e558a85dd2 100644 --- a/library/flink-library/pom.xml +++ b/library/flink-library/pom.xml @@ -19,7 +19,7 @@ library uk.gov.gchq.gaffer - 2.2.2 + 2.2.3-SNAPSHOT 4.0.0 diff --git a/library/hdfs-library/pom.xml b/library/hdfs-library/pom.xml index 9962a4831d2..6c9b93e33ad 100644 --- a/library/hdfs-library/pom.xml +++ b/library/hdfs-library/pom.xml @@ -20,7 +20,7 @@ uk.gov.gchq.gaffer library - 2.2.2 + 2.2.3-SNAPSHOT hdfs-library diff --git a/library/pom.xml b/library/pom.xml index ba0cad5e140..8d2ab25a776 100644 --- a/library/pom.xml +++ b/library/pom.xml @@ -19,7 +19,7 @@ uk.gov.gchq.gaffer gaffer2 - 2.2.2 + 2.2.3-SNAPSHOT 4.0.0 diff --git a/library/sketches-library/pom.xml b/library/sketches-library/pom.xml index 62314d8c774..5049fbdc44d 100644 --- a/library/sketches-library/pom.xml +++ b/library/sketches-library/pom.xml @@ -20,7 +20,7 @@ uk.gov.gchq.gaffer library - 2.2.2 + 2.2.3-SNAPSHOT sketches-library diff --git a/library/spark/pom.xml b/library/spark/pom.xml index 635897a4674..05ed3f4580d 100644 --- a/library/spark/pom.xml +++ b/library/spark/pom.xml @@ -20,7 +20,7 @@ uk.gov.gchq.gaffer library - 2.2.2 + 2.2.3-SNAPSHOT spark diff --git a/library/spark/spark-accumulo-library/pom.xml b/library/spark/spark-accumulo-library/pom.xml index 31187b70322..cb9c47a1147 100644 --- a/library/spark/spark-accumulo-library/pom.xml +++ b/library/spark/spark-accumulo-library/pom.xml @@ -20,7 +20,7 @@ uk.gov.gchq.gaffer spark - 2.2.2 + 2.2.3-SNAPSHOT spark-accumulo-library diff --git a/library/spark/spark-library/pom.xml b/library/spark/spark-library/pom.xml index 9d1ee370677..eb59c252f9b 100644 --- a/library/spark/spark-library/pom.xml +++ b/library/spark/spark-library/pom.xml @@ -20,7 +20,7 @@ uk.gov.gchq.gaffer spark - 2.2.2 + 2.2.3-SNAPSHOT spark-library diff --git a/library/time-library/pom.xml b/library/time-library/pom.xml index 46664f37179..a29f69b97de 100644 --- a/library/time-library/pom.xml +++ b/library/time-library/pom.xml @@ -20,7 +20,7 @@ uk.gov.gchq.gaffer library - 2.2.2 + 2.2.3-SNAPSHOT time-library diff --git a/library/tinkerpop/pom.xml b/library/tinkerpop/pom.xml index e0bdae1e1f2..277a855acfd 100644 --- a/library/tinkerpop/pom.xml +++ b/library/tinkerpop/pom.xml @@ -19,7 +19,7 @@ uk.gov.gchq.gaffer library - 2.2.2 + 2.2.3-SNAPSHOT 4.0.0 diff --git a/pom.xml b/pom.xml index 67afea5d0be..04f7e53bb94 100644 --- a/pom.xml +++ b/pom.xml @@ -21,7 +21,7 @@ uk.gov.gchq.gaffer gaffer2 pom - 2.2.2 + 2.2.3-SNAPSHOT ${project.groupId}:${project.artifactId} A scalable Graph database framework diff --git a/rest-api/accumulo-rest/pom.xml b/rest-api/accumulo-rest/pom.xml index b2302f44a3a..a34047f218e 100644 --- a/rest-api/accumulo-rest/pom.xml +++ b/rest-api/accumulo-rest/pom.xml @@ -20,7 +20,7 @@ uk.gov.gchq.gaffer rest-api - 2.2.2 + 2.2.3-SNAPSHOT accumulo-rest diff --git a/rest-api/common-rest/pom.xml b/rest-api/common-rest/pom.xml index a1b26edea60..b532ef51601 100644 --- a/rest-api/common-rest/pom.xml +++ b/rest-api/common-rest/pom.xml @@ -19,7 +19,7 @@ rest-api uk.gov.gchq.gaffer - 2.2.2 + 2.2.3-SNAPSHOT 4.0.0 diff --git a/rest-api/common-rest/src/main/resources/version.properties b/rest-api/common-rest/src/main/resources/version.properties index 1923ce9446f..da62e8a961c 100644 --- a/rest-api/common-rest/src/main/resources/version.properties +++ b/rest-api/common-rest/src/main/resources/version.properties @@ -13,5 +13,5 @@ # See the License for the specific language governing permissions and # limitations under the License. # -gaffer.version=2.2.2 +gaffer.version=2.2.3-SNAPSHOT koryphe.version=${koryphe.version} diff --git a/rest-api/core-rest/pom.xml b/rest-api/core-rest/pom.xml index 7e5f7f80624..5297d357c69 100644 --- a/rest-api/core-rest/pom.xml +++ b/rest-api/core-rest/pom.xml @@ -20,7 +20,7 @@ uk.gov.gchq.gaffer rest-api - 2.2.2 + 2.2.3-SNAPSHOT core-rest diff --git a/rest-api/map-rest/pom.xml b/rest-api/map-rest/pom.xml index bc15daade15..c597f3cad40 100644 --- a/rest-api/map-rest/pom.xml +++ b/rest-api/map-rest/pom.xml @@ -20,7 +20,7 @@ uk.gov.gchq.gaffer rest-api - 2.2.2 + 2.2.3-SNAPSHOT map-rest diff --git a/rest-api/pom.xml b/rest-api/pom.xml index c5bc0e692c5..f60d38c9354 100644 --- a/rest-api/pom.xml +++ b/rest-api/pom.xml @@ -20,7 +20,7 @@ gaffer2 uk.gov.gchq.gaffer - 2.2.2 + 2.2.3-SNAPSHOT rest-api diff --git a/rest-api/spring-rest/pom.xml b/rest-api/spring-rest/pom.xml index e24a5bc48ed..8390c547008 100644 --- a/rest-api/spring-rest/pom.xml +++ b/rest-api/spring-rest/pom.xml @@ -19,7 +19,7 @@ rest-api uk.gov.gchq.gaffer - 2.2.2 + 2.2.3-SNAPSHOT 4.0.0 diff --git a/store-implementation/accumulo-store/pom.xml b/store-implementation/accumulo-store/pom.xml index aefdc559741..605b1c72c13 100644 --- a/store-implementation/accumulo-store/pom.xml +++ b/store-implementation/accumulo-store/pom.xml @@ -21,7 +21,7 @@ uk.gov.gchq.gaffer store-implementation - 2.2.2 + 2.2.3-SNAPSHOT accumulo-store diff --git a/store-implementation/federated-store/pom.xml b/store-implementation/federated-store/pom.xml index 01655176b5d..ca2c8532991 100644 --- a/store-implementation/federated-store/pom.xml +++ b/store-implementation/federated-store/pom.xml @@ -21,7 +21,7 @@ uk.gov.gchq.gaffer store-implementation - 2.2.2 + 2.2.3-SNAPSHOT federated-store diff --git a/store-implementation/map-store/pom.xml b/store-implementation/map-store/pom.xml index 5a9485eb625..188f5836dee 100755 --- a/store-implementation/map-store/pom.xml +++ b/store-implementation/map-store/pom.xml @@ -21,7 +21,7 @@ uk.gov.gchq.gaffer store-implementation - 2.2.2 + 2.2.3-SNAPSHOT map-store diff --git a/store-implementation/pom.xml b/store-implementation/pom.xml index 3511bad0924..13366749642 100644 --- a/store-implementation/pom.xml +++ b/store-implementation/pom.xml @@ -19,7 +19,7 @@ uk.gov.gchq.gaffer gaffer2 - 2.2.2 + 2.2.3-SNAPSHOT 4.0.0 diff --git a/store-implementation/proxy-store/pom.xml b/store-implementation/proxy-store/pom.xml index 63d13770a96..02206957e5b 100644 --- a/store-implementation/proxy-store/pom.xml +++ b/store-implementation/proxy-store/pom.xml @@ -21,7 +21,7 @@ uk.gov.gchq.gaffer store-implementation - 2.2.2 + 2.2.3-SNAPSHOT proxy-store From 287e795f4df2096c88f1a75bf7f3e3afadf7b44f Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Fri, 21 Jun 2024 12:37:53 +0000 Subject: [PATCH 02/16] prepare for next development iteration --- core/access/pom.xml | 2 +- core/cache/pom.xml | 2 +- core/common-util/pom.xml | 2 +- core/data/pom.xml | 2 +- core/exception/pom.xml | 2 +- core/graph/pom.xml | 2 +- core/operation/pom.xml | 2 +- core/pom.xml | 2 +- core/serialisation/pom.xml | 2 +- core/store/pom.xml | 2 +- core/type/pom.xml | 2 +- example/basic/basic-model/pom.xml | 2 +- example/basic/basic-rest/pom.xml | 2 +- example/basic/pom.xml | 2 +- example/federated-demo/pom.xml | 2 +- example/pom.xml | 2 +- example/road-traffic/pom.xml | 2 +- example/road-traffic/road-traffic-demo/pom.xml | 2 +- example/road-traffic/road-traffic-generators/pom.xml | 2 +- example/road-traffic/road-traffic-model/pom.xml | 2 +- example/road-traffic/road-traffic-rest/pom.xml | 2 +- integration-test/pom.xml | 2 +- library/bitmap-library/pom.xml | 2 +- library/cache-library/hazelcast-cache-service/pom.xml | 2 +- library/cache-library/jcs-cache-service/pom.xml | 2 +- library/cache-library/pom.xml | 2 +- library/flink-library/pom.xml | 2 +- library/hdfs-library/pom.xml | 2 +- library/pom.xml | 2 +- library/sketches-library/pom.xml | 2 +- library/spark/pom.xml | 2 +- library/spark/spark-accumulo-library/pom.xml | 2 +- library/spark/spark-library/pom.xml | 2 +- library/time-library/pom.xml | 2 +- library/tinkerpop/pom.xml | 2 +- pom.xml | 2 +- rest-api/accumulo-rest/pom.xml | 2 +- rest-api/common-rest/pom.xml | 2 +- rest-api/common-rest/src/main/resources/version.properties | 2 +- rest-api/core-rest/pom.xml | 2 +- rest-api/map-rest/pom.xml | 2 +- rest-api/pom.xml | 2 +- rest-api/spring-rest/pom.xml | 2 +- store-implementation/accumulo-store/pom.xml | 2 +- store-implementation/federated-store/pom.xml | 2 +- store-implementation/map-store/pom.xml | 2 +- store-implementation/pom.xml | 2 +- store-implementation/proxy-store/pom.xml | 2 +- 48 files changed, 48 insertions(+), 48 deletions(-) diff --git a/core/access/pom.xml b/core/access/pom.xml index fea431697d0..cab2bd7828a 100644 --- a/core/access/pom.xml +++ b/core/access/pom.xml @@ -19,7 +19,7 @@ core uk.gov.gchq.gaffer - 2.2.3-SNAPSHOT + 2.2.4-SNAPSHOT 4.0.0 diff --git a/core/cache/pom.xml b/core/cache/pom.xml index 67a4e76364a..823497187db 100644 --- a/core/cache/pom.xml +++ b/core/cache/pom.xml @@ -19,7 +19,7 @@ core uk.gov.gchq.gaffer - 2.2.3-SNAPSHOT + 2.2.4-SNAPSHOT 4.0.0 diff --git a/core/common-util/pom.xml b/core/common-util/pom.xml index 06c7d31b622..f2750af8edc 100644 --- a/core/common-util/pom.xml +++ b/core/common-util/pom.xml @@ -20,7 +20,7 @@ uk.gov.gchq.gaffer core - 2.2.3-SNAPSHOT + 2.2.4-SNAPSHOT common-util diff --git a/core/data/pom.xml b/core/data/pom.xml index fc38e89f5c9..3056d9d1dfd 100644 --- a/core/data/pom.xml +++ b/core/data/pom.xml @@ -19,7 +19,7 @@ uk.gov.gchq.gaffer core - 2.2.3-SNAPSHOT + 2.2.4-SNAPSHOT 4.0.0 diff --git a/core/exception/pom.xml b/core/exception/pom.xml index e948d1f3610..857e5bdbf30 100644 --- a/core/exception/pom.xml +++ b/core/exception/pom.xml @@ -19,7 +19,7 @@ core uk.gov.gchq.gaffer - 2.2.3-SNAPSHOT + 2.2.4-SNAPSHOT 4.0.0 diff --git a/core/graph/pom.xml b/core/graph/pom.xml index b7720d02577..c81608894af 100644 --- a/core/graph/pom.xml +++ b/core/graph/pom.xml @@ -19,7 +19,7 @@ uk.gov.gchq.gaffer core - 2.2.3-SNAPSHOT + 2.2.4-SNAPSHOT 4.0.0 diff --git a/core/operation/pom.xml b/core/operation/pom.xml index 68e5833a994..861eea7fa43 100644 --- a/core/operation/pom.xml +++ b/core/operation/pom.xml @@ -19,7 +19,7 @@ uk.gov.gchq.gaffer core - 2.2.3-SNAPSHOT + 2.2.4-SNAPSHOT 4.0.0 diff --git a/core/pom.xml b/core/pom.xml index 5ac81ac663e..151de6e10c3 100644 --- a/core/pom.xml +++ b/core/pom.xml @@ -19,7 +19,7 @@ uk.gov.gchq.gaffer gaffer2 - 2.2.3-SNAPSHOT + 2.2.4-SNAPSHOT 4.0.0 diff --git a/core/serialisation/pom.xml b/core/serialisation/pom.xml index 3873a729c6d..b714fbce8f4 100644 --- a/core/serialisation/pom.xml +++ b/core/serialisation/pom.xml @@ -19,7 +19,7 @@ uk.gov.gchq.gaffer core - 2.2.3-SNAPSHOT + 2.2.4-SNAPSHOT 4.0.0 diff --git a/core/store/pom.xml b/core/store/pom.xml index f3ae1c30a85..183fa2bc27d 100644 --- a/core/store/pom.xml +++ b/core/store/pom.xml @@ -19,7 +19,7 @@ uk.gov.gchq.gaffer core - 2.2.3-SNAPSHOT + 2.2.4-SNAPSHOT 4.0.0 diff --git a/core/type/pom.xml b/core/type/pom.xml index 309e2633b79..9aec903c218 100644 --- a/core/type/pom.xml +++ b/core/type/pom.xml @@ -20,7 +20,7 @@ uk.gov.gchq.gaffer core - 2.2.3-SNAPSHOT + 2.2.4-SNAPSHOT type diff --git a/example/basic/basic-model/pom.xml b/example/basic/basic-model/pom.xml index f70fa4638f7..d283ea5e368 100644 --- a/example/basic/basic-model/pom.xml +++ b/example/basic/basic-model/pom.xml @@ -19,7 +19,7 @@ uk.gov.gchq.gaffer basic - 2.2.3-SNAPSHOT + 2.2.4-SNAPSHOT 4.0.0 diff --git a/example/basic/basic-rest/pom.xml b/example/basic/basic-rest/pom.xml index 21c659b61ac..d1feb5741ad 100644 --- a/example/basic/basic-rest/pom.xml +++ b/example/basic/basic-rest/pom.xml @@ -19,7 +19,7 @@ uk.gov.gchq.gaffer basic - 2.2.3-SNAPSHOT + 2.2.4-SNAPSHOT 4.0.0 diff --git a/example/basic/pom.xml b/example/basic/pom.xml index 6ea4ba1d0b6..a9dc3ebfd32 100644 --- a/example/basic/pom.xml +++ b/example/basic/pom.xml @@ -19,7 +19,7 @@ uk.gov.gchq.gaffer example - 2.2.3-SNAPSHOT + 2.2.4-SNAPSHOT 4.0.0 diff --git a/example/federated-demo/pom.xml b/example/federated-demo/pom.xml index a56d1868764..1f9991c2554 100644 --- a/example/federated-demo/pom.xml +++ b/example/federated-demo/pom.xml @@ -19,7 +19,7 @@ uk.gov.gchq.gaffer example - 2.2.3-SNAPSHOT + 2.2.4-SNAPSHOT 4.0.0 diff --git a/example/pom.xml b/example/pom.xml index 04b14accb82..afcdb26edd5 100644 --- a/example/pom.xml +++ b/example/pom.xml @@ -21,7 +21,7 @@ uk.gov.gchq.gaffer gaffer2 - 2.2.3-SNAPSHOT + 2.2.4-SNAPSHOT example diff --git a/example/road-traffic/pom.xml b/example/road-traffic/pom.xml index f0a936d211e..1865d995add 100644 --- a/example/road-traffic/pom.xml +++ b/example/road-traffic/pom.xml @@ -19,7 +19,7 @@ uk.gov.gchq.gaffer example - 2.2.3-SNAPSHOT + 2.2.4-SNAPSHOT 4.0.0 diff --git a/example/road-traffic/road-traffic-demo/pom.xml b/example/road-traffic/road-traffic-demo/pom.xml index a0ee3bdfdfe..5c6e680fd47 100644 --- a/example/road-traffic/road-traffic-demo/pom.xml +++ b/example/road-traffic/road-traffic-demo/pom.xml @@ -19,7 +19,7 @@ uk.gov.gchq.gaffer road-traffic - 2.2.3-SNAPSHOT + 2.2.4-SNAPSHOT 4.0.0 diff --git a/example/road-traffic/road-traffic-generators/pom.xml b/example/road-traffic/road-traffic-generators/pom.xml index fe0134d0965..26bdc643f56 100644 --- a/example/road-traffic/road-traffic-generators/pom.xml +++ b/example/road-traffic/road-traffic-generators/pom.xml @@ -19,7 +19,7 @@ uk.gov.gchq.gaffer road-traffic - 2.2.3-SNAPSHOT + 2.2.4-SNAPSHOT 4.0.0 diff --git a/example/road-traffic/road-traffic-model/pom.xml b/example/road-traffic/road-traffic-model/pom.xml index ff0f9591a76..3c06acbf9fe 100644 --- a/example/road-traffic/road-traffic-model/pom.xml +++ b/example/road-traffic/road-traffic-model/pom.xml @@ -19,7 +19,7 @@ uk.gov.gchq.gaffer road-traffic - 2.2.3-SNAPSHOT + 2.2.4-SNAPSHOT 4.0.0 diff --git a/example/road-traffic/road-traffic-rest/pom.xml b/example/road-traffic/road-traffic-rest/pom.xml index 6fcc9a685f0..334852707a3 100644 --- a/example/road-traffic/road-traffic-rest/pom.xml +++ b/example/road-traffic/road-traffic-rest/pom.xml @@ -19,7 +19,7 @@ uk.gov.gchq.gaffer road-traffic - 2.2.3-SNAPSHOT + 2.2.4-SNAPSHOT 4.0.0 diff --git a/integration-test/pom.xml b/integration-test/pom.xml index df13dcac182..f35fb741b19 100644 --- a/integration-test/pom.xml +++ b/integration-test/pom.xml @@ -21,7 +21,7 @@ uk.gov.gchq.gaffer gaffer2 - 2.2.3-SNAPSHOT + 2.2.4-SNAPSHOT integration-test diff --git a/library/bitmap-library/pom.xml b/library/bitmap-library/pom.xml index 02beda687bf..f0bb69f1d84 100644 --- a/library/bitmap-library/pom.xml +++ b/library/bitmap-library/pom.xml @@ -19,7 +19,7 @@ uk.gov.gchq.gaffer library - 2.2.3-SNAPSHOT + 2.2.4-SNAPSHOT 4.0.0 diff --git a/library/cache-library/hazelcast-cache-service/pom.xml b/library/cache-library/hazelcast-cache-service/pom.xml index 031d6bf1e8d..868099fa4c0 100644 --- a/library/cache-library/hazelcast-cache-service/pom.xml +++ b/library/cache-library/hazelcast-cache-service/pom.xml @@ -19,7 +19,7 @@ uk.gov.gchq.gaffer cache-library - 2.2.3-SNAPSHOT + 2.2.4-SNAPSHOT 4.0.0 diff --git a/library/cache-library/jcs-cache-service/pom.xml b/library/cache-library/jcs-cache-service/pom.xml index d0b2ecc91d0..a9f56719447 100644 --- a/library/cache-library/jcs-cache-service/pom.xml +++ b/library/cache-library/jcs-cache-service/pom.xml @@ -19,7 +19,7 @@ uk.gov.gchq.gaffer cache-library - 2.2.3-SNAPSHOT + 2.2.4-SNAPSHOT 4.0.0 diff --git a/library/cache-library/pom.xml b/library/cache-library/pom.xml index 23c4e16d80f..4a2912b33a8 100644 --- a/library/cache-library/pom.xml +++ b/library/cache-library/pom.xml @@ -19,7 +19,7 @@ uk.gov.gchq.gaffer library - 2.2.3-SNAPSHOT + 2.2.4-SNAPSHOT 4.0.0 diff --git a/library/flink-library/pom.xml b/library/flink-library/pom.xml index 7e558a85dd2..8218c1686dc 100644 --- a/library/flink-library/pom.xml +++ b/library/flink-library/pom.xml @@ -19,7 +19,7 @@ library uk.gov.gchq.gaffer - 2.2.3-SNAPSHOT + 2.2.4-SNAPSHOT 4.0.0 diff --git a/library/hdfs-library/pom.xml b/library/hdfs-library/pom.xml index 6c9b93e33ad..ec058e9ba9d 100644 --- a/library/hdfs-library/pom.xml +++ b/library/hdfs-library/pom.xml @@ -20,7 +20,7 @@ uk.gov.gchq.gaffer library - 2.2.3-SNAPSHOT + 2.2.4-SNAPSHOT hdfs-library diff --git a/library/pom.xml b/library/pom.xml index 8d2ab25a776..d798c2ff4c8 100644 --- a/library/pom.xml +++ b/library/pom.xml @@ -19,7 +19,7 @@ uk.gov.gchq.gaffer gaffer2 - 2.2.3-SNAPSHOT + 2.2.4-SNAPSHOT 4.0.0 diff --git a/library/sketches-library/pom.xml b/library/sketches-library/pom.xml index 5049fbdc44d..aeb793154cc 100644 --- a/library/sketches-library/pom.xml +++ b/library/sketches-library/pom.xml @@ -20,7 +20,7 @@ uk.gov.gchq.gaffer library - 2.2.3-SNAPSHOT + 2.2.4-SNAPSHOT sketches-library diff --git a/library/spark/pom.xml b/library/spark/pom.xml index 05ed3f4580d..52ccd51c3b5 100644 --- a/library/spark/pom.xml +++ b/library/spark/pom.xml @@ -20,7 +20,7 @@ uk.gov.gchq.gaffer library - 2.2.3-SNAPSHOT + 2.2.4-SNAPSHOT spark diff --git a/library/spark/spark-accumulo-library/pom.xml b/library/spark/spark-accumulo-library/pom.xml index cb9c47a1147..2aca5d223bc 100644 --- a/library/spark/spark-accumulo-library/pom.xml +++ b/library/spark/spark-accumulo-library/pom.xml @@ -20,7 +20,7 @@ uk.gov.gchq.gaffer spark - 2.2.3-SNAPSHOT + 2.2.4-SNAPSHOT spark-accumulo-library diff --git a/library/spark/spark-library/pom.xml b/library/spark/spark-library/pom.xml index eb59c252f9b..05f0d7242ac 100644 --- a/library/spark/spark-library/pom.xml +++ b/library/spark/spark-library/pom.xml @@ -20,7 +20,7 @@ uk.gov.gchq.gaffer spark - 2.2.3-SNAPSHOT + 2.2.4-SNAPSHOT spark-library diff --git a/library/time-library/pom.xml b/library/time-library/pom.xml index a29f69b97de..1d1189bd425 100644 --- a/library/time-library/pom.xml +++ b/library/time-library/pom.xml @@ -20,7 +20,7 @@ uk.gov.gchq.gaffer library - 2.2.3-SNAPSHOT + 2.2.4-SNAPSHOT time-library diff --git a/library/tinkerpop/pom.xml b/library/tinkerpop/pom.xml index 277a855acfd..43ce2f67cba 100644 --- a/library/tinkerpop/pom.xml +++ b/library/tinkerpop/pom.xml @@ -19,7 +19,7 @@ uk.gov.gchq.gaffer library - 2.2.3-SNAPSHOT + 2.2.4-SNAPSHOT 4.0.0 diff --git a/pom.xml b/pom.xml index 04f7e53bb94..1d225061b01 100644 --- a/pom.xml +++ b/pom.xml @@ -21,7 +21,7 @@ uk.gov.gchq.gaffer gaffer2 pom - 2.2.3-SNAPSHOT + 2.2.4-SNAPSHOT ${project.groupId}:${project.artifactId} A scalable Graph database framework diff --git a/rest-api/accumulo-rest/pom.xml b/rest-api/accumulo-rest/pom.xml index a34047f218e..e3f1d37c2d0 100644 --- a/rest-api/accumulo-rest/pom.xml +++ b/rest-api/accumulo-rest/pom.xml @@ -20,7 +20,7 @@ uk.gov.gchq.gaffer rest-api - 2.2.3-SNAPSHOT + 2.2.4-SNAPSHOT accumulo-rest diff --git a/rest-api/common-rest/pom.xml b/rest-api/common-rest/pom.xml index b532ef51601..66e79ae2ded 100644 --- a/rest-api/common-rest/pom.xml +++ b/rest-api/common-rest/pom.xml @@ -19,7 +19,7 @@ rest-api uk.gov.gchq.gaffer - 2.2.3-SNAPSHOT + 2.2.4-SNAPSHOT 4.0.0 diff --git a/rest-api/common-rest/src/main/resources/version.properties b/rest-api/common-rest/src/main/resources/version.properties index da62e8a961c..706d6dc1b52 100644 --- a/rest-api/common-rest/src/main/resources/version.properties +++ b/rest-api/common-rest/src/main/resources/version.properties @@ -13,5 +13,5 @@ # See the License for the specific language governing permissions and # limitations under the License. # -gaffer.version=2.2.3-SNAPSHOT +gaffer.version=2.2.4-SNAPSHOT koryphe.version=${koryphe.version} diff --git a/rest-api/core-rest/pom.xml b/rest-api/core-rest/pom.xml index 5297d357c69..abc25d42583 100644 --- a/rest-api/core-rest/pom.xml +++ b/rest-api/core-rest/pom.xml @@ -20,7 +20,7 @@ uk.gov.gchq.gaffer rest-api - 2.2.3-SNAPSHOT + 2.2.4-SNAPSHOT core-rest diff --git a/rest-api/map-rest/pom.xml b/rest-api/map-rest/pom.xml index c597f3cad40..0bb79c3c604 100644 --- a/rest-api/map-rest/pom.xml +++ b/rest-api/map-rest/pom.xml @@ -20,7 +20,7 @@ uk.gov.gchq.gaffer rest-api - 2.2.3-SNAPSHOT + 2.2.4-SNAPSHOT map-rest diff --git a/rest-api/pom.xml b/rest-api/pom.xml index f60d38c9354..9410d48feb1 100644 --- a/rest-api/pom.xml +++ b/rest-api/pom.xml @@ -20,7 +20,7 @@ gaffer2 uk.gov.gchq.gaffer - 2.2.3-SNAPSHOT + 2.2.4-SNAPSHOT rest-api diff --git a/rest-api/spring-rest/pom.xml b/rest-api/spring-rest/pom.xml index 8390c547008..87cf6752ff4 100644 --- a/rest-api/spring-rest/pom.xml +++ b/rest-api/spring-rest/pom.xml @@ -19,7 +19,7 @@ rest-api uk.gov.gchq.gaffer - 2.2.3-SNAPSHOT + 2.2.4-SNAPSHOT 4.0.0 diff --git a/store-implementation/accumulo-store/pom.xml b/store-implementation/accumulo-store/pom.xml index 605b1c72c13..7cb6039c1f2 100644 --- a/store-implementation/accumulo-store/pom.xml +++ b/store-implementation/accumulo-store/pom.xml @@ -21,7 +21,7 @@ uk.gov.gchq.gaffer store-implementation - 2.2.3-SNAPSHOT + 2.2.4-SNAPSHOT accumulo-store diff --git a/store-implementation/federated-store/pom.xml b/store-implementation/federated-store/pom.xml index ca2c8532991..a84f6e240d0 100644 --- a/store-implementation/federated-store/pom.xml +++ b/store-implementation/federated-store/pom.xml @@ -21,7 +21,7 @@ uk.gov.gchq.gaffer store-implementation - 2.2.3-SNAPSHOT + 2.2.4-SNAPSHOT federated-store diff --git a/store-implementation/map-store/pom.xml b/store-implementation/map-store/pom.xml index 188f5836dee..419850f8216 100755 --- a/store-implementation/map-store/pom.xml +++ b/store-implementation/map-store/pom.xml @@ -21,7 +21,7 @@ uk.gov.gchq.gaffer store-implementation - 2.2.3-SNAPSHOT + 2.2.4-SNAPSHOT map-store diff --git a/store-implementation/pom.xml b/store-implementation/pom.xml index 13366749642..056dd92f825 100644 --- a/store-implementation/pom.xml +++ b/store-implementation/pom.xml @@ -19,7 +19,7 @@ uk.gov.gchq.gaffer gaffer2 - 2.2.3-SNAPSHOT + 2.2.4-SNAPSHOT 4.0.0 diff --git a/store-implementation/proxy-store/pom.xml b/store-implementation/proxy-store/pom.xml index 02206957e5b..440e1e73bfc 100644 --- a/store-implementation/proxy-store/pom.xml +++ b/store-implementation/proxy-store/pom.xml @@ -21,7 +21,7 @@ uk.gov.gchq.gaffer store-implementation - 2.2.3-SNAPSHOT + 2.2.4-SNAPSHOT proxy-store From d948fa5a1b01eb2005b80dfb1be2ce14e30b1401 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Fri, 21 Jun 2024 13:41:05 +0000 Subject: [PATCH 03/16] prepare for next development iteration --- core/access/pom.xml | 2 +- core/cache/pom.xml | 2 +- core/common-util/pom.xml | 2 +- core/data/pom.xml | 2 +- core/exception/pom.xml | 2 +- core/graph/pom.xml | 2 +- core/operation/pom.xml | 2 +- core/pom.xml | 2 +- core/serialisation/pom.xml | 2 +- core/store/pom.xml | 2 +- core/type/pom.xml | 2 +- example/basic/basic-model/pom.xml | 2 +- example/basic/basic-rest/pom.xml | 2 +- example/basic/pom.xml | 2 +- example/federated-demo/pom.xml | 2 +- example/pom.xml | 2 +- example/road-traffic/pom.xml | 2 +- example/road-traffic/road-traffic-demo/pom.xml | 2 +- example/road-traffic/road-traffic-generators/pom.xml | 2 +- example/road-traffic/road-traffic-model/pom.xml | 2 +- example/road-traffic/road-traffic-rest/pom.xml | 2 +- integration-test/pom.xml | 2 +- library/bitmap-library/pom.xml | 2 +- library/cache-library/hazelcast-cache-service/pom.xml | 2 +- library/cache-library/jcs-cache-service/pom.xml | 2 +- library/cache-library/pom.xml | 2 +- library/flink-library/pom.xml | 2 +- library/hdfs-library/pom.xml | 2 +- library/pom.xml | 2 +- library/sketches-library/pom.xml | 2 +- library/spark/pom.xml | 2 +- library/spark/spark-accumulo-library/pom.xml | 2 +- library/spark/spark-library/pom.xml | 2 +- library/time-library/pom.xml | 2 +- library/tinkerpop/pom.xml | 2 +- pom.xml | 2 +- rest-api/accumulo-rest/pom.xml | 2 +- rest-api/common-rest/pom.xml | 2 +- rest-api/common-rest/src/main/resources/version.properties | 2 +- rest-api/core-rest/pom.xml | 2 +- rest-api/map-rest/pom.xml | 2 +- rest-api/pom.xml | 2 +- rest-api/spring-rest/pom.xml | 2 +- store-implementation/accumulo-store/pom.xml | 2 +- store-implementation/federated-store/pom.xml | 2 +- store-implementation/map-store/pom.xml | 2 +- store-implementation/pom.xml | 2 +- store-implementation/proxy-store/pom.xml | 2 +- 48 files changed, 48 insertions(+), 48 deletions(-) diff --git a/core/access/pom.xml b/core/access/pom.xml index cab2bd7828a..0ea463ccdd2 100644 --- a/core/access/pom.xml +++ b/core/access/pom.xml @@ -19,7 +19,7 @@ core uk.gov.gchq.gaffer - 2.2.4-SNAPSHOT + 2.2.5-SNAPSHOT 4.0.0 diff --git a/core/cache/pom.xml b/core/cache/pom.xml index 823497187db..12e5e4cfc19 100644 --- a/core/cache/pom.xml +++ b/core/cache/pom.xml @@ -19,7 +19,7 @@ core uk.gov.gchq.gaffer - 2.2.4-SNAPSHOT + 2.2.5-SNAPSHOT 4.0.0 diff --git a/core/common-util/pom.xml b/core/common-util/pom.xml index f2750af8edc..eefd13dd796 100644 --- a/core/common-util/pom.xml +++ b/core/common-util/pom.xml @@ -20,7 +20,7 @@ uk.gov.gchq.gaffer core - 2.2.4-SNAPSHOT + 2.2.5-SNAPSHOT common-util diff --git a/core/data/pom.xml b/core/data/pom.xml index 3056d9d1dfd..f87246ff29c 100644 --- a/core/data/pom.xml +++ b/core/data/pom.xml @@ -19,7 +19,7 @@ uk.gov.gchq.gaffer core - 2.2.4-SNAPSHOT + 2.2.5-SNAPSHOT 4.0.0 diff --git a/core/exception/pom.xml b/core/exception/pom.xml index 857e5bdbf30..e16328f7384 100644 --- a/core/exception/pom.xml +++ b/core/exception/pom.xml @@ -19,7 +19,7 @@ core uk.gov.gchq.gaffer - 2.2.4-SNAPSHOT + 2.2.5-SNAPSHOT 4.0.0 diff --git a/core/graph/pom.xml b/core/graph/pom.xml index c81608894af..9c0350a1c3f 100644 --- a/core/graph/pom.xml +++ b/core/graph/pom.xml @@ -19,7 +19,7 @@ uk.gov.gchq.gaffer core - 2.2.4-SNAPSHOT + 2.2.5-SNAPSHOT 4.0.0 diff --git a/core/operation/pom.xml b/core/operation/pom.xml index 861eea7fa43..ec9db9994ec 100644 --- a/core/operation/pom.xml +++ b/core/operation/pom.xml @@ -19,7 +19,7 @@ uk.gov.gchq.gaffer core - 2.2.4-SNAPSHOT + 2.2.5-SNAPSHOT 4.0.0 diff --git a/core/pom.xml b/core/pom.xml index 151de6e10c3..000c43babc9 100644 --- a/core/pom.xml +++ b/core/pom.xml @@ -19,7 +19,7 @@ uk.gov.gchq.gaffer gaffer2 - 2.2.4-SNAPSHOT + 2.2.5-SNAPSHOT 4.0.0 diff --git a/core/serialisation/pom.xml b/core/serialisation/pom.xml index b714fbce8f4..0b5b72e91e2 100644 --- a/core/serialisation/pom.xml +++ b/core/serialisation/pom.xml @@ -19,7 +19,7 @@ uk.gov.gchq.gaffer core - 2.2.4-SNAPSHOT + 2.2.5-SNAPSHOT 4.0.0 diff --git a/core/store/pom.xml b/core/store/pom.xml index 183fa2bc27d..5e9a62549d5 100644 --- a/core/store/pom.xml +++ b/core/store/pom.xml @@ -19,7 +19,7 @@ uk.gov.gchq.gaffer core - 2.2.4-SNAPSHOT + 2.2.5-SNAPSHOT 4.0.0 diff --git a/core/type/pom.xml b/core/type/pom.xml index 9aec903c218..c2ad4dafdda 100644 --- a/core/type/pom.xml +++ b/core/type/pom.xml @@ -20,7 +20,7 @@ uk.gov.gchq.gaffer core - 2.2.4-SNAPSHOT + 2.2.5-SNAPSHOT type diff --git a/example/basic/basic-model/pom.xml b/example/basic/basic-model/pom.xml index d283ea5e368..b34324c64a6 100644 --- a/example/basic/basic-model/pom.xml +++ b/example/basic/basic-model/pom.xml @@ -19,7 +19,7 @@ uk.gov.gchq.gaffer basic - 2.2.4-SNAPSHOT + 2.2.5-SNAPSHOT 4.0.0 diff --git a/example/basic/basic-rest/pom.xml b/example/basic/basic-rest/pom.xml index d1feb5741ad..e6e46d0c566 100644 --- a/example/basic/basic-rest/pom.xml +++ b/example/basic/basic-rest/pom.xml @@ -19,7 +19,7 @@ uk.gov.gchq.gaffer basic - 2.2.4-SNAPSHOT + 2.2.5-SNAPSHOT 4.0.0 diff --git a/example/basic/pom.xml b/example/basic/pom.xml index a9dc3ebfd32..c66d5d4c5ac 100644 --- a/example/basic/pom.xml +++ b/example/basic/pom.xml @@ -19,7 +19,7 @@ uk.gov.gchq.gaffer example - 2.2.4-SNAPSHOT + 2.2.5-SNAPSHOT 4.0.0 diff --git a/example/federated-demo/pom.xml b/example/federated-demo/pom.xml index 1f9991c2554..481612d100a 100644 --- a/example/federated-demo/pom.xml +++ b/example/federated-demo/pom.xml @@ -19,7 +19,7 @@ uk.gov.gchq.gaffer example - 2.2.4-SNAPSHOT + 2.2.5-SNAPSHOT 4.0.0 diff --git a/example/pom.xml b/example/pom.xml index afcdb26edd5..f2c5a13cf2d 100644 --- a/example/pom.xml +++ b/example/pom.xml @@ -21,7 +21,7 @@ uk.gov.gchq.gaffer gaffer2 - 2.2.4-SNAPSHOT + 2.2.5-SNAPSHOT example diff --git a/example/road-traffic/pom.xml b/example/road-traffic/pom.xml index 1865d995add..34b9d220352 100644 --- a/example/road-traffic/pom.xml +++ b/example/road-traffic/pom.xml @@ -19,7 +19,7 @@ uk.gov.gchq.gaffer example - 2.2.4-SNAPSHOT + 2.2.5-SNAPSHOT 4.0.0 diff --git a/example/road-traffic/road-traffic-demo/pom.xml b/example/road-traffic/road-traffic-demo/pom.xml index 5c6e680fd47..2f1093505db 100644 --- a/example/road-traffic/road-traffic-demo/pom.xml +++ b/example/road-traffic/road-traffic-demo/pom.xml @@ -19,7 +19,7 @@ uk.gov.gchq.gaffer road-traffic - 2.2.4-SNAPSHOT + 2.2.5-SNAPSHOT 4.0.0 diff --git a/example/road-traffic/road-traffic-generators/pom.xml b/example/road-traffic/road-traffic-generators/pom.xml index 26bdc643f56..4a5eca8f6c1 100644 --- a/example/road-traffic/road-traffic-generators/pom.xml +++ b/example/road-traffic/road-traffic-generators/pom.xml @@ -19,7 +19,7 @@ uk.gov.gchq.gaffer road-traffic - 2.2.4-SNAPSHOT + 2.2.5-SNAPSHOT 4.0.0 diff --git a/example/road-traffic/road-traffic-model/pom.xml b/example/road-traffic/road-traffic-model/pom.xml index 3c06acbf9fe..f2b069b9c22 100644 --- a/example/road-traffic/road-traffic-model/pom.xml +++ b/example/road-traffic/road-traffic-model/pom.xml @@ -19,7 +19,7 @@ uk.gov.gchq.gaffer road-traffic - 2.2.4-SNAPSHOT + 2.2.5-SNAPSHOT 4.0.0 diff --git a/example/road-traffic/road-traffic-rest/pom.xml b/example/road-traffic/road-traffic-rest/pom.xml index 334852707a3..8cc45f0ebeb 100644 --- a/example/road-traffic/road-traffic-rest/pom.xml +++ b/example/road-traffic/road-traffic-rest/pom.xml @@ -19,7 +19,7 @@ uk.gov.gchq.gaffer road-traffic - 2.2.4-SNAPSHOT + 2.2.5-SNAPSHOT 4.0.0 diff --git a/integration-test/pom.xml b/integration-test/pom.xml index f35fb741b19..505792ee734 100644 --- a/integration-test/pom.xml +++ b/integration-test/pom.xml @@ -21,7 +21,7 @@ uk.gov.gchq.gaffer gaffer2 - 2.2.4-SNAPSHOT + 2.2.5-SNAPSHOT integration-test diff --git a/library/bitmap-library/pom.xml b/library/bitmap-library/pom.xml index f0bb69f1d84..522e23271c3 100644 --- a/library/bitmap-library/pom.xml +++ b/library/bitmap-library/pom.xml @@ -19,7 +19,7 @@ uk.gov.gchq.gaffer library - 2.2.4-SNAPSHOT + 2.2.5-SNAPSHOT 4.0.0 diff --git a/library/cache-library/hazelcast-cache-service/pom.xml b/library/cache-library/hazelcast-cache-service/pom.xml index 868099fa4c0..d4b1b0c9337 100644 --- a/library/cache-library/hazelcast-cache-service/pom.xml +++ b/library/cache-library/hazelcast-cache-service/pom.xml @@ -19,7 +19,7 @@ uk.gov.gchq.gaffer cache-library - 2.2.4-SNAPSHOT + 2.2.5-SNAPSHOT 4.0.0 diff --git a/library/cache-library/jcs-cache-service/pom.xml b/library/cache-library/jcs-cache-service/pom.xml index a9f56719447..a8407dc8dd7 100644 --- a/library/cache-library/jcs-cache-service/pom.xml +++ b/library/cache-library/jcs-cache-service/pom.xml @@ -19,7 +19,7 @@ uk.gov.gchq.gaffer cache-library - 2.2.4-SNAPSHOT + 2.2.5-SNAPSHOT 4.0.0 diff --git a/library/cache-library/pom.xml b/library/cache-library/pom.xml index 4a2912b33a8..98e04430307 100644 --- a/library/cache-library/pom.xml +++ b/library/cache-library/pom.xml @@ -19,7 +19,7 @@ uk.gov.gchq.gaffer library - 2.2.4-SNAPSHOT + 2.2.5-SNAPSHOT 4.0.0 diff --git a/library/flink-library/pom.xml b/library/flink-library/pom.xml index 8218c1686dc..a7b280a2fe2 100644 --- a/library/flink-library/pom.xml +++ b/library/flink-library/pom.xml @@ -19,7 +19,7 @@ library uk.gov.gchq.gaffer - 2.2.4-SNAPSHOT + 2.2.5-SNAPSHOT 4.0.0 diff --git a/library/hdfs-library/pom.xml b/library/hdfs-library/pom.xml index ec058e9ba9d..f7e379d3c08 100644 --- a/library/hdfs-library/pom.xml +++ b/library/hdfs-library/pom.xml @@ -20,7 +20,7 @@ uk.gov.gchq.gaffer library - 2.2.4-SNAPSHOT + 2.2.5-SNAPSHOT hdfs-library diff --git a/library/pom.xml b/library/pom.xml index d798c2ff4c8..e3c337a2e90 100644 --- a/library/pom.xml +++ b/library/pom.xml @@ -19,7 +19,7 @@ uk.gov.gchq.gaffer gaffer2 - 2.2.4-SNAPSHOT + 2.2.5-SNAPSHOT 4.0.0 diff --git a/library/sketches-library/pom.xml b/library/sketches-library/pom.xml index aeb793154cc..eaf300157ca 100644 --- a/library/sketches-library/pom.xml +++ b/library/sketches-library/pom.xml @@ -20,7 +20,7 @@ uk.gov.gchq.gaffer library - 2.2.4-SNAPSHOT + 2.2.5-SNAPSHOT sketches-library diff --git a/library/spark/pom.xml b/library/spark/pom.xml index 52ccd51c3b5..000d3628b95 100644 --- a/library/spark/pom.xml +++ b/library/spark/pom.xml @@ -20,7 +20,7 @@ uk.gov.gchq.gaffer library - 2.2.4-SNAPSHOT + 2.2.5-SNAPSHOT spark diff --git a/library/spark/spark-accumulo-library/pom.xml b/library/spark/spark-accumulo-library/pom.xml index 2aca5d223bc..a2237a289c6 100644 --- a/library/spark/spark-accumulo-library/pom.xml +++ b/library/spark/spark-accumulo-library/pom.xml @@ -20,7 +20,7 @@ uk.gov.gchq.gaffer spark - 2.2.4-SNAPSHOT + 2.2.5-SNAPSHOT spark-accumulo-library diff --git a/library/spark/spark-library/pom.xml b/library/spark/spark-library/pom.xml index 05f0d7242ac..93af89768e2 100644 --- a/library/spark/spark-library/pom.xml +++ b/library/spark/spark-library/pom.xml @@ -20,7 +20,7 @@ uk.gov.gchq.gaffer spark - 2.2.4-SNAPSHOT + 2.2.5-SNAPSHOT spark-library diff --git a/library/time-library/pom.xml b/library/time-library/pom.xml index 1d1189bd425..82d7c8ea4be 100644 --- a/library/time-library/pom.xml +++ b/library/time-library/pom.xml @@ -20,7 +20,7 @@ uk.gov.gchq.gaffer library - 2.2.4-SNAPSHOT + 2.2.5-SNAPSHOT time-library diff --git a/library/tinkerpop/pom.xml b/library/tinkerpop/pom.xml index 43ce2f67cba..5545ac221b3 100644 --- a/library/tinkerpop/pom.xml +++ b/library/tinkerpop/pom.xml @@ -19,7 +19,7 @@ uk.gov.gchq.gaffer library - 2.2.4-SNAPSHOT + 2.2.5-SNAPSHOT 4.0.0 diff --git a/pom.xml b/pom.xml index 1d225061b01..b2c476f7b44 100644 --- a/pom.xml +++ b/pom.xml @@ -21,7 +21,7 @@ uk.gov.gchq.gaffer gaffer2 pom - 2.2.4-SNAPSHOT + 2.2.5-SNAPSHOT ${project.groupId}:${project.artifactId} A scalable Graph database framework diff --git a/rest-api/accumulo-rest/pom.xml b/rest-api/accumulo-rest/pom.xml index e3f1d37c2d0..d2064f7e41b 100644 --- a/rest-api/accumulo-rest/pom.xml +++ b/rest-api/accumulo-rest/pom.xml @@ -20,7 +20,7 @@ uk.gov.gchq.gaffer rest-api - 2.2.4-SNAPSHOT + 2.2.5-SNAPSHOT accumulo-rest diff --git a/rest-api/common-rest/pom.xml b/rest-api/common-rest/pom.xml index 66e79ae2ded..5b7a1a593cb 100644 --- a/rest-api/common-rest/pom.xml +++ b/rest-api/common-rest/pom.xml @@ -19,7 +19,7 @@ rest-api uk.gov.gchq.gaffer - 2.2.4-SNAPSHOT + 2.2.5-SNAPSHOT 4.0.0 diff --git a/rest-api/common-rest/src/main/resources/version.properties b/rest-api/common-rest/src/main/resources/version.properties index 706d6dc1b52..e26645a4bc2 100644 --- a/rest-api/common-rest/src/main/resources/version.properties +++ b/rest-api/common-rest/src/main/resources/version.properties @@ -13,5 +13,5 @@ # See the License for the specific language governing permissions and # limitations under the License. # -gaffer.version=2.2.4-SNAPSHOT +gaffer.version=2.2.5-SNAPSHOT koryphe.version=${koryphe.version} diff --git a/rest-api/core-rest/pom.xml b/rest-api/core-rest/pom.xml index abc25d42583..68f50685d8e 100644 --- a/rest-api/core-rest/pom.xml +++ b/rest-api/core-rest/pom.xml @@ -20,7 +20,7 @@ uk.gov.gchq.gaffer rest-api - 2.2.4-SNAPSHOT + 2.2.5-SNAPSHOT core-rest diff --git a/rest-api/map-rest/pom.xml b/rest-api/map-rest/pom.xml index 0bb79c3c604..5939cb55692 100644 --- a/rest-api/map-rest/pom.xml +++ b/rest-api/map-rest/pom.xml @@ -20,7 +20,7 @@ uk.gov.gchq.gaffer rest-api - 2.2.4-SNAPSHOT + 2.2.5-SNAPSHOT map-rest diff --git a/rest-api/pom.xml b/rest-api/pom.xml index 9410d48feb1..2c2fb373ac9 100644 --- a/rest-api/pom.xml +++ b/rest-api/pom.xml @@ -20,7 +20,7 @@ gaffer2 uk.gov.gchq.gaffer - 2.2.4-SNAPSHOT + 2.2.5-SNAPSHOT rest-api diff --git a/rest-api/spring-rest/pom.xml b/rest-api/spring-rest/pom.xml index 87cf6752ff4..2586053a29c 100644 --- a/rest-api/spring-rest/pom.xml +++ b/rest-api/spring-rest/pom.xml @@ -19,7 +19,7 @@ rest-api uk.gov.gchq.gaffer - 2.2.4-SNAPSHOT + 2.2.5-SNAPSHOT 4.0.0 diff --git a/store-implementation/accumulo-store/pom.xml b/store-implementation/accumulo-store/pom.xml index 7cb6039c1f2..a8242feead6 100644 --- a/store-implementation/accumulo-store/pom.xml +++ b/store-implementation/accumulo-store/pom.xml @@ -21,7 +21,7 @@ uk.gov.gchq.gaffer store-implementation - 2.2.4-SNAPSHOT + 2.2.5-SNAPSHOT accumulo-store diff --git a/store-implementation/federated-store/pom.xml b/store-implementation/federated-store/pom.xml index a84f6e240d0..a524814433c 100644 --- a/store-implementation/federated-store/pom.xml +++ b/store-implementation/federated-store/pom.xml @@ -21,7 +21,7 @@ uk.gov.gchq.gaffer store-implementation - 2.2.4-SNAPSHOT + 2.2.5-SNAPSHOT federated-store diff --git a/store-implementation/map-store/pom.xml b/store-implementation/map-store/pom.xml index 419850f8216..e8d5e7eed23 100755 --- a/store-implementation/map-store/pom.xml +++ b/store-implementation/map-store/pom.xml @@ -21,7 +21,7 @@ uk.gov.gchq.gaffer store-implementation - 2.2.4-SNAPSHOT + 2.2.5-SNAPSHOT map-store diff --git a/store-implementation/pom.xml b/store-implementation/pom.xml index 056dd92f825..977b278ad9e 100644 --- a/store-implementation/pom.xml +++ b/store-implementation/pom.xml @@ -19,7 +19,7 @@ uk.gov.gchq.gaffer gaffer2 - 2.2.4-SNAPSHOT + 2.2.5-SNAPSHOT 4.0.0 diff --git a/store-implementation/proxy-store/pom.xml b/store-implementation/proxy-store/pom.xml index 440e1e73bfc..49198263731 100644 --- a/store-implementation/proxy-store/pom.xml +++ b/store-implementation/proxy-store/pom.xml @@ -21,7 +21,7 @@ uk.gov.gchq.gaffer store-implementation - 2.2.4-SNAPSHOT + 2.2.5-SNAPSHOT proxy-store From 4520b257eedfc93a953d607d69fa0466467a608e Mon Sep 17 00:00:00 2001 From: tb06904 <141412860+tb06904@users.noreply.github.com> Date: Mon, 1 Jul 2024 08:44:33 +0000 Subject: [PATCH 04/16] Gh-3244 fix ci versioning (#3245) * move to revision property * update ci * update ignore --- .github/release-notes.yml | 2 +- .github/workflows/create-hotfix-branch.yaml | 2 +- .github/workflows/create-release-branch.yaml | 2 +- .github/workflows/release.yaml | 9 +++-- .gitignore | 5 +-- core/access/pom.xml | 4 +-- core/cache/pom.xml | 4 +-- core/common-util/pom.xml | 2 +- core/data/pom.xml | 4 +-- core/exception/pom.xml | 4 +-- core/graph/pom.xml | 4 +-- core/operation/pom.xml | 4 +-- core/pom.xml | 5 +-- core/serialisation/pom.xml | 4 +-- core/store/pom.xml | 2 +- core/type/pom.xml | 4 +-- example/basic/basic-model/pom.xml | 4 +-- example/basic/basic-rest/pom.xml | 2 +- example/basic/pom.xml | 5 +-- example/federated-demo/pom.xml | 2 +- example/pom.xml | 5 +-- example/road-traffic/pom.xml | 5 +-- .../road-traffic/road-traffic-demo/pom.xml | 2 +- .../road-traffic-generators/pom.xml | 4 +-- .../road-traffic/road-traffic-model/pom.xml | 4 +-- .../road-traffic/road-traffic-rest/pom.xml | 2 +- integration-test/pom.xml | 4 +-- library/bitmap-library/pom.xml | 4 +-- .../hazelcast-cache-service/pom.xml | 2 +- .../cache-library/jcs-cache-service/pom.xml | 4 +-- library/cache-library/pom.xml | 4 +-- library/flink-library/pom.xml | 4 +-- library/hdfs-library/pom.xml | 4 +-- library/pom.xml | 5 +-- library/sketches-library/pom.xml | 2 +- library/spark/pom.xml | 4 +-- library/spark/spark-accumulo-library/pom.xml | 4 +-- library/spark/spark-library/pom.xml | 4 +-- library/time-library/pom.xml | 4 +-- library/tinkerpop/pom.xml | 2 +- pom.xml | 35 ++++++++++++++++++- rest-api/accumulo-rest/pom.xml | 2 +- rest-api/common-rest/pom.xml | 4 +-- rest-api/core-rest/pom.xml | 4 +-- rest-api/map-rest/pom.xml | 2 +- rest-api/pom.xml | 5 +-- rest-api/spring-rest/pom.xml | 4 +-- store-implementation/accumulo-store/pom.xml | 4 +-- store-implementation/federated-store/pom.xml | 4 +-- store-implementation/map-store/pom.xml | 4 +-- store-implementation/pom.xml | 5 +-- store-implementation/proxy-store/pom.xml | 4 +-- 52 files changed, 134 insertions(+), 90 deletions(-) diff --git a/.github/release-notes.yml b/.github/release-notes.yml index 74535a000fd..9b58699c5bc 100644 --- a/.github/release-notes.yml +++ b/.github/release-notes.yml @@ -1,4 +1,4 @@ -releasenotes: +changelog: sections: - title: "Headliners" emoji: ":star:" diff --git a/.github/workflows/create-hotfix-branch.yaml b/.github/workflows/create-hotfix-branch.yaml index 86508eb261f..cfcc4c4c981 100644 --- a/.github/workflows/create-hotfix-branch.yaml +++ b/.github/workflows/create-hotfix-branch.yaml @@ -53,7 +53,7 @@ jobs: - name: Update versions run: | - mvn versions:set -DnewVersion=$RELEASE_VERSION -DgenerateBackupPoms=false + mvn versions:set-property -Dproperty=revision -DnewVersion=${RELEASE_VERSION} -DgenerateBackupPoms=false sed -i'' -e "s/^gaffer.version=.*/gaffer.version=$RELEASE_VERSION/" rest-api/common-rest/src/main/resources/version.properties - name: Push to hotfix branch diff --git a/.github/workflows/create-release-branch.yaml b/.github/workflows/create-release-branch.yaml index e4ae794d1f8..5117cc4164c 100644 --- a/.github/workflows/create-release-branch.yaml +++ b/.github/workflows/create-release-branch.yaml @@ -53,7 +53,7 @@ jobs: - name: Update versions run: | - mvn versions:set -DnewVersion=$RELEASE_VERSION -DgenerateBackupPoms=false + mvn versions:set-property -Dproperty=revision -DnewVersion=${RELEASE_VERSION} -DgenerateBackupPoms=false sed -i'' -e "s/^gaffer.version=.*/gaffer.version=$RELEASE_VERSION/" rest-api/common-rest/src/main/resources/version.properties - name: Push to release branch diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index f5a731f1850..37fde540f14 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -95,7 +95,10 @@ jobs: - name: Update develop branch run: | git checkout develop - mvn release:update-versions -B + mvn versions:set-property -Dproperty=revision -DnewVersion=$(echo ${{ github.event.milestone.title }} | cut -c 2-)-SNAPSHOT + mvn build-helper:parse-version versions:set-property \ + -Dproperty=revision \ + -DnewVersion=\${parsedVersion.majorVersion}.\${parsedVersion.minorVersion}.\${parsedVersion.nextIncrementalVersion}-SNAPSHOT NEW_GAFFER_VERSION=$(mvn -q help:evaluate -DforceStdout -Dexpression=pom.version) sed -i'' -e "s/^gaffer.version=.*/gaffer.version=$NEW_GAFFER_VERSION/" rest-api/common-rest/src/main/resources/version.properties git commit -a -m "prepare for next development iteration" @@ -181,12 +184,12 @@ jobs: with: distribution: 'zulu' java-version: '8' - + - name: Checkout release uses: actions/checkout@v4 with: ref: ${{ needs.create-release-tag.outputs.branch_name }} - + - name: Decode CodeSigning key env: CODE_SIGNING_KEY: ${{ secrets.CODE_SIGNING_KEY }} diff --git a/.gitignore b/.gitignore index c0de98738b0..2e22cd36844 100755 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,4 @@ -# Copyright 2016 Crown Copyright +# Copyright 2016-2024 Crown Copyright # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -29,4 +29,5 @@ parquet_data/ **/.vscode example/real-federated-store/*.properties example/real-federated-store/*.json -example/real-federated-store/*.jar \ No newline at end of file +example/real-federated-store/*.jar +.flattened-pom.xml diff --git a/core/access/pom.xml b/core/access/pom.xml index 0ea463ccdd2..e37e6b359fc 100644 --- a/core/access/pom.xml +++ b/core/access/pom.xml @@ -1,6 +1,6 @@ + 2.3.0-SNAPSHOT + false UTF-8 false @@ -124,6 +127,7 @@ 3.1.0 3.12.1 3.4.1 + 1.5.0 @@ -1083,6 +1087,35 @@ -Dgpg.passphrase=${gpg.passphrase} + + + org.codehaus.mojo + flatten-maven-plugin + ${flatten.plugin.version} + + true + + resolveCiFriendliesOnly + + + + + flatten + process-resources + + flatten + + + + + flatten.clean + clean + + clean + + + + org.apache.maven.plugins maven-enforcer-plugin diff --git a/rest-api/accumulo-rest/pom.xml b/rest-api/accumulo-rest/pom.xml index d2064f7e41b..dca4427862e 100644 --- a/rest-api/accumulo-rest/pom.xml +++ b/rest-api/accumulo-rest/pom.xml @@ -20,7 +20,7 @@ uk.gov.gchq.gaffer rest-api - 2.2.5-SNAPSHOT + ${revision} accumulo-rest diff --git a/rest-api/common-rest/pom.xml b/rest-api/common-rest/pom.xml index 5b7a1a593cb..e6e299312d0 100644 --- a/rest-api/common-rest/pom.xml +++ b/rest-api/common-rest/pom.xml @@ -1,6 +1,6 @@ @@ -108,7 +107,7 @@ test-jar test - + uk.gov.gchq.gaffer federated-store ${project.parent.version} @@ -156,6 +155,18 @@ + + + org.apache.maven.plugins + maven-jar-plugin + + + + test-jar + + + + diff --git a/library/tinkerpop/src/main/java/uk/gov/gchq/gaffer/tinkerpop/GafferPopGraph.java b/library/tinkerpop/src/main/java/uk/gov/gchq/gaffer/tinkerpop/GafferPopGraph.java index 46c9822d7cd..42f55e88f25 100755 --- a/library/tinkerpop/src/main/java/uk/gov/gchq/gaffer/tinkerpop/GafferPopGraph.java +++ b/library/tinkerpop/src/main/java/uk/gov/gchq/gaffer/tinkerpop/GafferPopGraph.java @@ -215,6 +215,12 @@ public enum HasStepFilterStage { */ public static final String NOT_READ_ONLY_ELEMENTS = "gaffer.elements.notreadonly"; + /** + * Key for use in the store properties to allow setting the file location of + * the GafferPop properties file from a store properties file. + */ + public static final String GAFFERPOP_PROPERTIES = "gaffer.gafferpop.properties"; + /** * The vertex label for vertex IDs. These are {@link GafferPopVertex}s that * don't have any properties, just an ID value and a label of 'id'. @@ -707,15 +713,15 @@ public T execute(final OperationChain opChain) { } } } - // Use the requested user based on variables - User user = new User.Builder() - .userId(variables.getUserId()) - .dataAuths(variables.getDataAuths()) - .build(); + + // Add the current chain to the list of chains ran so far for this query (it is reset by the graph step) + List currentChain = variables.getLastOperationChain().getOperations(); + currentChain.add(opChain); + variables.set(GafferPopGraphVariables.LAST_OPERATION_CHAIN, new OperationChain<>(currentChain)); try { LOGGER.info("GafferPop operation chain called: {}", opChain.toOverviewString()); - return graph.execute(opChain, user); + return graph.execute(opChain, variables.getUser()); } catch (final Exception e) { LOGGER.error("Operation chain failed: {}", e.getMessage()); throw new RuntimeException("GafferPop operation failed: " + e.getMessage(), e); @@ -989,13 +995,14 @@ private IncludeIncomingOutgoingType getInOutType(final Direction direction) { * @param variables The variables */ public void setDefaultVariables(final GafferPopGraphVariables variables) { + LOGGER.info("Resetting graph variables to defaults"); variables.set(GafferPopGraphVariables.OP_OPTIONS, Collections.unmodifiableMap(opOptions)); - variables.set(GafferPopGraphVariables.USER_ID, defaultUser.getUserId()); - variables.set(GafferPopGraphVariables.DATA_AUTHS, configuration().getStringArray(DATA_AUTHS)); + variables.set(GafferPopGraphVariables.USER, defaultUser); variables.set(GafferPopGraphVariables.GET_ALL_ELEMENTS_LIMIT, configuration().getInteger(GET_ALL_ELEMENTS_LIMIT, DEFAULT_GET_ALL_ELEMENTS_LIMIT)); variables.set(GafferPopGraphVariables.HAS_STEP_FILTER_STAGE, configuration().getString(HAS_STEP_FILTER_STAGE, DEFAULT_HAS_STEP_FILTER_STAGE.toString())); + variables.set(GafferPopGraphVariables.LAST_OPERATION_CHAIN, new OperationChain()); } /** diff --git a/library/tinkerpop/src/main/java/uk/gov/gchq/gaffer/tinkerpop/GafferPopGraphVariables.java b/library/tinkerpop/src/main/java/uk/gov/gchq/gaffer/tinkerpop/GafferPopGraphVariables.java index b4da01707b6..05f2f71307f 100644 --- a/library/tinkerpop/src/main/java/uk/gov/gchq/gaffer/tinkerpop/GafferPopGraphVariables.java +++ b/library/tinkerpop/src/main/java/uk/gov/gchq/gaffer/tinkerpop/GafferPopGraphVariables.java @@ -21,6 +21,9 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import uk.gov.gchq.gaffer.operation.OperationChain; +import uk.gov.gchq.gaffer.user.User; + import java.util.HashMap; import java.util.Map; import java.util.Optional; @@ -36,15 +39,20 @@ public final class GafferPopGraphVariables implements Graph.Variables { public static final String OP_OPTIONS = "operationOptions"; /** - * Variable key for the list of data auths for the user interacting with the graph. + * Variable key for the list of data auths for the default user. */ public static final String DATA_AUTHS = "dataAuths"; /** - * Variable key for the userId of who is interacting with the graph. + * Variable key for the userId used for constructing a default user. */ public static final String USER_ID = "userId"; + /** + * Variable key for the user who is interacting with the graph. + */ + public static final String USER = "user"; + /** * The max number of elements that can be returned by GetAllElements */ @@ -55,6 +63,16 @@ public final class GafferPopGraphVariables implements Graph.Variables { */ public static final String HAS_STEP_FILTER_STAGE = "hasStepFilterStage"; + /** + * Key used in a with step to include a opencypher query traversal + */ + public static final String CYPHER_KEY = "cypher"; + + /** + * The variable with the last Gaffer operation chain that was ran from the Gremlin query + */ + public static final String LAST_OPERATION_CHAIN = "lastOperation"; + private final Map variables; @@ -91,17 +109,15 @@ public void set(final String key, final Object value) { } else if (value instanceof Map) { variables.put(key, value); } else { - LOGGER.error(VAR_UPDATE_ERROR_STRING, OP_OPTIONS, value.getClass()); + LOGGER.error(VAR_UPDATE_ERROR_STRING, key, value.getClass()); } break; - case DATA_AUTHS: - if (value instanceof String[]) { + case USER: + if (value instanceof User) { variables.put(key, value); - } else if (value instanceof String) { - variables.put(key, ((String) value).split(",")); } else { - LOGGER.error(VAR_UPDATE_ERROR_STRING, DATA_AUTHS, value.getClass()); + LOGGER.error(VAR_UPDATE_ERROR_STRING, key, value.getClass()); } break; @@ -137,25 +153,8 @@ public Map getOperationOptions() { return new HashMap<>(); } - /** - * Gets the list of data auths. - * - * @return List of data auths. - */ - public String[] getDataAuths() { - if (variables.containsKey(DATA_AUTHS)) { - return (String[]) variables.get(DATA_AUTHS); - } - return new String[0]; - } - - /** - * Gets the current user ID. - * - * @return The user ID - */ - public String getUserId() { - return (String) variables.get(USER_ID); + public User getUser() { + return (User) variables.get(USER); } public Integer getAllElementsLimit() { @@ -166,6 +165,10 @@ public String getHasStepFilterStage() { return (String) variables.get(HAS_STEP_FILTER_STAGE); } + public OperationChain getLastOperationChain() { + return (OperationChain) variables.get(LAST_OPERATION_CHAIN); + } + public String toString() { return StringFactory.graphVariablesString(this); } diff --git a/library/tinkerpop/src/main/java/uk/gov/gchq/gaffer/tinkerpop/process/traversal/step/GafferPopGraphStep.java b/library/tinkerpop/src/main/java/uk/gov/gchq/gaffer/tinkerpop/process/traversal/step/GafferPopGraphStep.java index 3268c35a522..fafee9b8148 100644 --- a/library/tinkerpop/src/main/java/uk/gov/gchq/gaffer/tinkerpop/process/traversal/step/GafferPopGraphStep.java +++ b/library/tinkerpop/src/main/java/uk/gov/gchq/gaffer/tinkerpop/process/traversal/step/GafferPopGraphStep.java @@ -52,12 +52,11 @@ /** * Custom GafferPop GraphStep provides Gaffer specific optimisations - * for the initial GraphStep in a query. Also responsible for parsing - * any options passed via a 'with()' call on the query. + * for the initial GraphStep in a query. + * Also responsible for parsing any options passed via a 'with()' step + * on the query. * *
- * g.with("userId", "user").V()   // userId extracted to be used in the operation executions
- * g.with("dataAuths", "write-access,read-access").V()   // user access controls to apply on the user
  * g.with("operationOptions", ["graphId:graph1", "opt1:val1"]).V()   // operation options extracted and applied
  * 
*/ diff --git a/library/tinkerpop/src/main/java/uk/gov/gchq/gaffer/tinkerpop/process/traversal/strategy/optimisation/GafferPopGraphStepStrategy.java b/library/tinkerpop/src/main/java/uk/gov/gchq/gaffer/tinkerpop/process/traversal/strategy/optimisation/GafferPopGraphStepStrategy.java index dccbd3a46f5..497eae8a485 100644 --- a/library/tinkerpop/src/main/java/uk/gov/gchq/gaffer/tinkerpop/process/traversal/strategy/optimisation/GafferPopGraphStepStrategy.java +++ b/library/tinkerpop/src/main/java/uk/gov/gchq/gaffer/tinkerpop/process/traversal/strategy/optimisation/GafferPopGraphStepStrategy.java @@ -31,16 +31,18 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import uk.gov.gchq.gaffer.tinkerpop.GafferPopGraphVariables; import uk.gov.gchq.gaffer.tinkerpop.process.traversal.step.GafferPopGraphStep; +import java.util.Map; import java.util.Optional; /** * The {@link GraphStep} strategy for GafferPop, this will replace the default * {@link GraphStep} of a query to add Gaffer optimisations. Such as gathering * any {@link HasStep}s so that a Gaffer View can be constructed for the query. - * Will also handle the translation any Cypher queries passed in a with() step - * into a Gremlin traversal. + * Will also handle the translation of Cypher queries passed via a with() + * step in the Gremlin traversal. * *
  * g.V().hasLabel()    // replaced by GafferPopGraphStep
@@ -52,27 +54,25 @@ public final class GafferPopGraphStepStrategy extends AbstractTraversalStrategy<
     private static final Logger LOGGER = LoggerFactory.getLogger(GafferPopGraphStepStrategy.class);
     private static final GafferPopGraphStepStrategy INSTANCE = new GafferPopGraphStepStrategy();
 
-    /**
-     * Key used in a with step to include a opencypher query traversal
-     */
-    public static final String CYPHER_KEY = "cypher";
-
     private GafferPopGraphStepStrategy() {
     }
 
     @Override
     public void apply(final Admin traversal) {
-        // Check for any options on the traversal
+        // Parse any options on the traversal
         Optional optionsStrategy = traversal.getStrategies().getStrategy(OptionsStrategy.class);
-        // Translate and add a cypher traversal in if that key has been set
-        if (optionsStrategy.isPresent() && optionsStrategy.get().getOptions().containsKey(CYPHER_KEY)) {
-            LOGGER.info("Replacing traversal with translated Cypher query");
-            CypherAst ast = CypherAst.parse((String) optionsStrategy.get().getOptions().get(CYPHER_KEY));
-            Admin translatedCypher = ast.buildTranslation(Translator.builder().traversal().enableCypherExtensions().build()).asAdmin();
+        if (optionsStrategy.isPresent()) {
+            Map options = optionsStrategy.get().getOptions();
+            // Translate and add a cypher traversal in if that key has been set
+            if (options.containsKey(GafferPopGraphVariables.CYPHER_KEY)) {
+                LOGGER.info("Replacing traversal with translated Cypher query");
+                CypherAst ast = CypherAst.parse((String) options.get(GafferPopGraphVariables.CYPHER_KEY));
+                Admin translatedCypher = ast.buildTranslation(Translator.builder().traversal().enableCypherExtensions().build()).asAdmin();
 
-            // Add the cypher traversal
-            TraversalHelper.insertTraversal(0, translatedCypher, traversal);
-            LOGGER.debug("New traversal is: {}", traversal);
+                // Add the cypher traversal
+                TraversalHelper.insertTraversal(0, translatedCypher, traversal);
+                LOGGER.debug("New traversal is: {}", traversal);
+            }
         }
 
         TraversalHelper.getStepsOfClass(GraphStep.class, traversal).forEach(originalGraphStep -> {
diff --git a/library/tinkerpop/src/main/java/uk/gov/gchq/gaffer/tinkerpop/server/auth/ExampleGafferPopAuthenticator.java b/library/tinkerpop/src/main/java/uk/gov/gchq/gaffer/tinkerpop/server/auth/ExampleGafferPopAuthenticator.java
deleted file mode 100644
index 19f997c4a3f..00000000000
--- a/library/tinkerpop/src/main/java/uk/gov/gchq/gaffer/tinkerpop/server/auth/ExampleGafferPopAuthenticator.java
+++ /dev/null
@@ -1,135 +0,0 @@
-/*
- * Copyright 2024 Crown Copyright
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package uk.gov.gchq.gaffer.tinkerpop.server.auth;
-
-import org.apache.tinkerpop.gremlin.server.auth.AuthenticatedUser;
-import org.apache.tinkerpop.gremlin.server.auth.AuthenticationException;
-import org.apache.tinkerpop.gremlin.server.auth.Authenticator;
-
-import java.net.InetAddress;
-import java.nio.charset.StandardCharsets;
-import java.util.Arrays;
-import java.util.HashMap;
-import java.util.Map;
-
-/**
- * An example authenticator class for GafferPop, this should not
- * be used in production as it allows all user and password combinations.
- * The class is intended as a template for an deployment specific class
- * that hooks into a proper authorisation mechanism such as LDAP etc.
- */
-public class ExampleGafferPopAuthenticator implements Authenticator {
-
-    @Override
-    public boolean requireAuthentication() {
-        return true;
-    }
-
-    @Override
-    public void setup(final Map config) {
-        // Nothing to do
-    }
-
-    @Override
-    public SaslNegotiator newSaslNegotiator(final InetAddress remoteAddress) {
-        return new PlainTextSaslAuthenticator();
-    }
-
-
-    @Override
-    public AuthenticatedUser authenticate(final Map credentials) throws AuthenticationException {
-        // Get the username from the credentials set by the SASL negotiator
-        final String username = credentials.get("username");
-        return new AuthenticatedUser(username);
-    }
-
-    /**
-     * Very simple SASL authenticator that will just extract username and password
-     * from plain text.
-     */
-    private class PlainTextSaslAuthenticator implements Authenticator.SaslNegotiator {
-        private static final byte NUL = 0;
-        private boolean complete = false;
-        private String username;
-        private String password;
-
-        @Override
-        public byte[] evaluateResponse(final byte[] clientResponse) throws AuthenticationException {
-            decodeCredentials(clientResponse);
-            complete = true;
-            return new byte[0];
-        }
-
-        @Override
-        public boolean isComplete() {
-            return complete;
-        }
-
-        @Override
-        public AuthenticatedUser getAuthenticatedUser() throws AuthenticationException {
-            if (!complete) {
-                throw new AuthenticationException("SASL negotiation not complete");
-            }
-            final Map credentials = new HashMap<>();
-            credentials.put("username", username);
-            credentials.put("password", password);
-            return authenticate(credentials);
-        }
-
-        /**
-         * SASL PLAIN mechanism specifies that credentials are encoded in a
-         * sequence of UTF-8 bytes, delimited by 0 (US-ASCII NUL).
-         * The form is :
-         *
-         * 
-         * authzIdNULauthnIdNULpasswordNUL
-         * 
- * - * @param bytes encoded credentials string sent by the client - * @throws AuthenticationException If issue decoding - */ - private void decodeCredentials(final byte[] bytes) throws AuthenticationException { - byte[] user = null; - byte[] pass = null; - int end = bytes.length; - // Loop over the byte array to extract the user and password - for (int i = bytes.length - 1; i >= 0; i--) { - if (bytes[i] != NUL) { - continue; - } - - if (pass == null) { - pass = Arrays.copyOfRange(bytes, i + 1, end); - } else if (user == null) { - user = Arrays.copyOfRange(bytes, i + 1, end); - } - end = i; - } - - if (user == null) { - throw new AuthenticationException("Authentication ID must not be null"); - } - if (pass == null) { - throw new AuthenticationException("Password must not be null"); - } - - username = new String(user, StandardCharsets.UTF_8); - password = new String(pass, StandardCharsets.UTF_8); - } - } - -} diff --git a/library/tinkerpop/src/main/java/uk/gov/gchq/gaffer/tinkerpop/server/auth/GafferPopAuthoriser.java b/library/tinkerpop/src/main/java/uk/gov/gchq/gaffer/tinkerpop/server/auth/GafferPopAuthoriser.java deleted file mode 100644 index 00a65045c91..00000000000 --- a/library/tinkerpop/src/main/java/uk/gov/gchq/gaffer/tinkerpop/server/auth/GafferPopAuthoriser.java +++ /dev/null @@ -1,129 +0,0 @@ -/* - * Copyright 2024 Crown Copyright - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package uk.gov.gchq.gaffer.tinkerpop.server.auth; - -import org.apache.tinkerpop.gremlin.process.computer.traversal.strategy.verification.VertexProgramRestrictionStrategy; -import org.apache.tinkerpop.gremlin.process.traversal.Bytecode; -import org.apache.tinkerpop.gremlin.process.traversal.Bytecode.Instruction; -import org.apache.tinkerpop.gremlin.process.traversal.strategy.verification.ReadOnlyStrategy; -import org.apache.tinkerpop.gremlin.process.traversal.util.BytecodeHelper; -import org.apache.tinkerpop.gremlin.server.auth.AuthenticatedUser; -import org.apache.tinkerpop.gremlin.server.authz.AuthorizationException; -import org.apache.tinkerpop.gremlin.server.authz.Authorizer; -import org.apache.tinkerpop.gremlin.util.message.RequestMessage; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import uk.gov.gchq.gaffer.tinkerpop.GafferPopGraphVariables; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; -import java.util.Map; - -/** - * The {@link Authorizer} for GafferPop, responsible for checking a query from a - * gremlin server user is valid and ensuring the current authorised user ID is - * passed on to the GafferPop graph. This should be used along side a instance - * specific Authenticator to provide user management for gremlin server connections. - */ -public class GafferPopAuthoriser implements Authorizer { - private static final Logger LOGGER = LoggerFactory.getLogger(GafferPopAuthoriser.class); - public static final String REJECT_BYTECODE = "User not authorized for bytecode requests on %s"; - public static final String REJECT_LAMBDA = "lambdas"; - public static final String REJECT_MUTATE = "the ReadOnlyStrategy"; - public static final String REJECT_OLAP = "the VertexProgramRestrictionStrategy"; - public static final String REJECT_STRING = "User not authorized for string-based requests."; - - /** - * This method is called once upon system startup to initialize the - * {@code GafferAuthoriser}. - */ - @Override - public void setup(final Map config) { - // Nothing to setup - } - - /** - * Checks whether a user is authorized to have a gremlin bytecode request from a client answered and raises an - * {@link AuthorizationException} if this is not the case. If authorised will modify the bytecode to inject the - * users details via a 'with()' step so the Gaffer graph can run with the correct user. - * - * @param user {@link AuthenticatedUser} that needs authorization. - * @param bytecode The gremlin {@link Bytecode} request to authorize the user for. - * @param aliases A {@link Map} with a single key/value pair that maps the name of the TraversalSource in the - * {@link Bytecode} request to name of one configured in Gremlin Server. - * @return The original or modified {@link Bytecode} to be used for further processing. - */ - @Override - public Bytecode authorize(final AuthenticatedUser user, final Bytecode bytecode, final Map aliases) throws AuthorizationException { - final boolean runsLambda = BytecodeHelper.getLambdaLanguage(bytecode).isPresent(); - final boolean touchesReadOnlyStrategy = bytecode.toString().contains(ReadOnlyStrategy.class.getSimpleName()); - final boolean touchesOLAPRestriction = bytecode.toString().contains(VertexProgramRestrictionStrategy.class.getSimpleName()); - - final List rejections = new ArrayList<>(); - // Reject use of Lambdas - if (runsLambda) { - rejections.add(REJECT_LAMBDA); - } - // Reject any modification steps to the graph via gremlin - if (touchesReadOnlyStrategy) { - rejections.add(REJECT_MUTATE); - } - // Reject use of OLAP operations - if (touchesOLAPRestriction) { - rejections.add(REJECT_OLAP); - } - - // Formulate a rejection message - String rejectMessage = REJECT_BYTECODE; - if (!rejections.isEmpty()) { - rejectMessage += " using " + String.join(", ", rejections); - throw new AuthorizationException(String.format(rejectMessage, aliases.values())); - } - - // Prevent overriding the user ID in a 'with()' block as we will set it based on the authenticated user - for (final Instruction i : bytecode.getStepInstructions()) { - LOGGER.debug("Found query operator: {} with args: {}", i.getOperator(), i.getArguments()); - if (i.getOperator().equals("with") && Arrays.asList(i.getArguments()).contains(GafferPopGraphVariables.USER_ID)) { - throw new AuthorizationException("Can't override current user ID from within a query"); - } - } - - // Add the user ID to the query - bytecode.addSource("with", GafferPopGraphVariables.USER_ID, user.getName()); - - return bytecode; - } - - /** - * Checks whether a user is authorized to have a script request from a gremlin - * client answered and raises an {@link AuthorizationException} if this is not - * the case. - * - * @param user {@link AuthenticatedUser} that needs authorization. - * @param msg {@link RequestMessage} in which the ARGS_GREMLIN - * argument can contain an arbitrary succession of script - * statements. - */ - @Override - public void authorize(final AuthenticatedUser user, final RequestMessage msg) throws AuthorizationException { - // Not supported in GafferPop - throw new AuthorizationException(REJECT_STRING); - } - -} diff --git a/library/tinkerpop/src/test/java/uk/gov/gchq/gaffer/tinkerpop/GafferPopGraphTest.java b/library/tinkerpop/src/test/java/uk/gov/gchq/gaffer/tinkerpop/GafferPopGraphTest.java index aedc9fc2d35..25ef6aafc7e 100644 --- a/library/tinkerpop/src/test/java/uk/gov/gchq/gaffer/tinkerpop/GafferPopGraphTest.java +++ b/library/tinkerpop/src/test/java/uk/gov/gchq/gaffer/tinkerpop/GafferPopGraphTest.java @@ -79,10 +79,9 @@ void shouldConstructGafferPopGraphWithOnlyConfig() { final Map variables = graph.variables().asMap(); assertThat(variables) .hasSize(5) - .containsEntry(GafferPopGraphVariables.USER_ID, expectedUser.getUserId()) + .containsEntry(GafferPopGraphVariables.USER, expectedUser) .containsEntry(GafferPopGraphVariables.GET_ALL_ELEMENTS_LIMIT, 1) .containsEntry(GafferPopGraphVariables.HAS_STEP_FILTER_STAGE, HasStepFilterStage.POST_TRANSFORM.toString()) - .containsEntry(GafferPopGraphVariables.DATA_AUTHS, new String[]{"auth1", "auth2"}) .containsKey(GafferPopGraphVariables.OP_OPTIONS); final Map opOptions = (Map) variables.get(GafferPopGraphVariables.OP_OPTIONS); @@ -105,10 +104,9 @@ void shouldConstructGafferPopGraphWithConfigFile() { final Map variables = graph.variables().asMap(); assertThat(variables) .hasSize(5) - .containsEntry(GafferPopGraphVariables.USER_ID, expectedUser.getUserId()) + .containsEntry(GafferPopGraphVariables.USER, expectedUser) .containsEntry(GafferPopGraphVariables.GET_ALL_ELEMENTS_LIMIT, 2) .containsEntry(GafferPopGraphVariables.HAS_STEP_FILTER_STAGE, HasStepFilterStage.POST_AGGREGATION.toString()) - .containsEntry(GafferPopGraphVariables.DATA_AUTHS, new String[]{}) .containsKey(GafferPopGraphVariables.OP_OPTIONS); final Map opOptions = (Map) variables.get(GafferPopGraphVariables.OP_OPTIONS); @@ -130,8 +128,7 @@ void shouldConstructGafferPopGraph() { final Map variables = graph.variables().asMap(); assertThat(variables) .hasSize(5) - .containsEntry(GafferPopGraphVariables.DATA_AUTHS, expectedUser.getDataAuths().toArray()) - .containsEntry(GafferPopGraphVariables.USER_ID, expectedUser.getUserId()) + .containsEntry(GafferPopGraphVariables.USER, expectedUser) .containsEntry(GafferPopGraphVariables.GET_ALL_ELEMENTS_LIMIT, GafferPopGraph.DEFAULT_GET_ALL_ELEMENTS_LIMIT) .containsEntry(GafferPopGraphVariables.HAS_STEP_FILTER_STAGE, diff --git a/library/tinkerpop/src/test/java/uk/gov/gchq/gaffer/tinkerpop/GafferPopGraphVariablesTest.java b/library/tinkerpop/src/test/java/uk/gov/gchq/gaffer/tinkerpop/GafferPopGraphVariablesTest.java index cfa6d9a629b..aa2810da1b5 100644 --- a/library/tinkerpop/src/test/java/uk/gov/gchq/gaffer/tinkerpop/GafferPopGraphVariablesTest.java +++ b/library/tinkerpop/src/test/java/uk/gov/gchq/gaffer/tinkerpop/GafferPopGraphVariablesTest.java @@ -18,6 +18,8 @@ import org.junit.jupiter.api.Test; +import uk.gov.gchq.gaffer.user.User; + import java.util.Arrays; import java.util.List; import java.util.concurrent.ConcurrentHashMap; @@ -48,18 +50,22 @@ void shouldAllowSettingGafferPopVariables() { // Given given(graph.variables()).willReturn(variables); final String testUserId = "testUserId"; - final String testDataAuths = "auth1,auth2"; + final String[] testDataAuths = {"auth1", "auth2"}; + final User testUser = new User.Builder() + .userId(testUserId) + .dataAuths(testDataAuths) + .build(); final List testOpOptions = Arrays.asList("graphId:graph1", "other:other"); final GafferPopGraphVariables graphVariables = (GafferPopGraphVariables) graph.variables(); // When - graphVariables.set(GafferPopGraphVariables.USER_ID, testUserId); + graphVariables.set(GafferPopGraphVariables.USER, testUser); graphVariables.set(GafferPopGraphVariables.DATA_AUTHS, testDataAuths); graphVariables.set(GafferPopGraphVariables.OP_OPTIONS, testOpOptions); // Then - assertThat(graphVariables.getUserId()).isEqualTo(testUserId); - assertThat(graphVariables.getDataAuths()).containsExactlyInAnyOrder((testDataAuths.split(","))); + assertThat(graphVariables.getUser().getUserId()).isEqualTo(testUserId); + assertThat(graphVariables.getUser().getDataAuths()).containsExactlyInAnyOrder(testDataAuths); assertThat(graphVariables.getOperationOptions()).containsOnly( entry("graphId", "graph1"), entry("other", "other")); diff --git a/library/tinkerpop/src/test/java/uk/gov/gchq/gaffer/tinkerpop/process/traversal/step/GafferPopGraphStepTest.java b/library/tinkerpop/src/test/java/uk/gov/gchq/gaffer/tinkerpop/process/traversal/step/GafferPopGraphStepTest.java index 01ace2fc6bc..539eb8a7470 100644 --- a/library/tinkerpop/src/test/java/uk/gov/gchq/gaffer/tinkerpop/process/traversal/step/GafferPopGraphStepTest.java +++ b/library/tinkerpop/src/test/java/uk/gov/gchq/gaffer/tinkerpop/process/traversal/step/GafferPopGraphStepTest.java @@ -50,21 +50,14 @@ void shouldUpdateGraphVariablesOnGremlinWithStep() { // Given final GafferPopGraph graph = GafferPopGraph.open(GafferPopTestUtil.TEST_CONFIGURATION_1, getGafferGraph()); final GafferPopGraphVariables graphVariables = (GafferPopGraphVariables) graph.variables(); - final String testUserId = "testUserId"; - final String testDataAuths = "auth1,auth2"; final List testOpOptions = Arrays.asList("graphId:graph1", "other:other"); final GraphTraversalSource g = graph.traversal(); // When - g.with(GafferPopGraphVariables.USER_ID, testUserId) - .with(GafferPopGraphVariables.DATA_AUTHS, testDataAuths) - .with(GafferPopGraphVariables.OP_OPTIONS, testOpOptions) - .V().toList(); + g.with(GafferPopGraphVariables.OP_OPTIONS, testOpOptions).V().toList(); // Then - assertThat(graphVariables.getUserId()).isEqualTo(testUserId); - assertThat(graphVariables.getDataAuths()).containsExactlyInAnyOrder((testDataAuths.split(","))); assertThat(graphVariables.getOperationOptions()).containsOnly( entry("graphId", "graph1"), entry("other", "other")); diff --git a/library/tinkerpop/src/test/java/uk/gov/gchq/gaffer/tinkerpop/process/traversal/strategy/GafferPopGraphStepStrategyCypherIT.java b/library/tinkerpop/src/test/java/uk/gov/gchq/gaffer/tinkerpop/process/traversal/strategy/GafferPopGraphStepStrategyCypherIT.java index 07c8b4252a7..c4040fea4a9 100644 --- a/library/tinkerpop/src/test/java/uk/gov/gchq/gaffer/tinkerpop/process/traversal/strategy/GafferPopGraphStepStrategyCypherIT.java +++ b/library/tinkerpop/src/test/java/uk/gov/gchq/gaffer/tinkerpop/process/traversal/strategy/GafferPopGraphStepStrategyCypherIT.java @@ -33,7 +33,7 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatExceptionOfType; -import static uk.gov.gchq.gaffer.tinkerpop.process.traversal.strategy.optimisation.GafferPopGraphStepStrategy.CYPHER_KEY; +import static uk.gov.gchq.gaffer.tinkerpop.GafferPopGraphVariables.CYPHER_KEY; import static uk.gov.gchq.gaffer.tinkerpop.util.modern.GafferPopModernTestUtils.JOSH; import static uk.gov.gchq.gaffer.tinkerpop.util.modern.GafferPopModernTestUtils.MARKO; import static uk.gov.gchq.gaffer.tinkerpop.util.modern.GafferPopModernTestUtils.PETER; diff --git a/library/tinkerpop/src/test/java/uk/gov/gchq/gaffer/tinkerpop/server/auth/ExampleGafferPopAuthenticatorTest.java b/library/tinkerpop/src/test/java/uk/gov/gchq/gaffer/tinkerpop/server/auth/ExampleGafferPopAuthenticatorTest.java deleted file mode 100644 index b9c0604a128..00000000000 --- a/library/tinkerpop/src/test/java/uk/gov/gchq/gaffer/tinkerpop/server/auth/ExampleGafferPopAuthenticatorTest.java +++ /dev/null @@ -1,90 +0,0 @@ -/* - * Copyright 2024 Crown Copyright - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package uk.gov.gchq.gaffer.tinkerpop.server.auth; - -import org.apache.tinkerpop.gremlin.server.auth.AuthenticationException; -import org.apache.tinkerpop.gremlin.server.auth.Authenticator; -import org.junit.jupiter.api.BeforeAll; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.TestInstance; -import org.junit.jupiter.api.TestInstance.Lifecycle; - -import static org.assertj.core.api.Assertions.assertThat; - -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.util.HashMap; -import java.util.Map; - -@TestInstance(Lifecycle.PER_CLASS) -class ExampleGafferPopAuthenticatorTest { - private ExampleGafferPopAuthenticator authenticator; - - @BeforeAll - void setup() { - authenticator = new ExampleGafferPopAuthenticator(); - } - - @Test - void shouldAlwaysRequireAuthentication() { - assertThat(authenticator.requireAuthentication()).isTrue(); - } - - @Test - void shouldCreateNewPlainTextSaslNegotiator() { - // Given - final Authenticator.SaslNegotiator negotiator1 = authenticator.newSaslNegotiator(null); - final Authenticator.SaslNegotiator negotiator2 = authenticator.newSaslNegotiator(null); - - // Then - assertThat(negotiator1).isNotEqualTo(negotiator2); - } - - @Test - void shouldAuthenticateWithPlainText() throws AuthenticationException { - final String user = "test"; - final String pass = "pass"; - final Map credentials = new HashMap<>(); - credentials.put("username", user); - credentials.put("password", pass); - - assertThat(authenticator.authenticate(credentials).getName()).isEqualTo(user); - } - - @Test - void shouldParseSaslPlainTextResponse() throws AuthenticationException, IOException { - // Given - final Authenticator.SaslNegotiator negotiator = authenticator.newSaslNegotiator(null); - final String user = "test"; - final String pass = "pass"; - - // Create a byte array for the response, this is representative of what the gremlin server is passed - final ByteArrayOutputStream stream = new ByteArrayOutputStream(); - final byte[] nul = new byte[] {0}; - stream.write(nul); - stream.write(user.getBytes()); - stream.write(nul); - stream.write(pass.getBytes()); - - // When - negotiator.evaluateResponse(stream.toByteArray()); - - // Then - assertThat(negotiator.isComplete()).isTrue(); - assertThat(negotiator.getAuthenticatedUser().getName()).isEqualTo(user); - } -} diff --git a/library/tinkerpop/src/test/java/uk/gov/gchq/gaffer/tinkerpop/server/auth/GafferPopAuthoriserTest.java b/library/tinkerpop/src/test/java/uk/gov/gchq/gaffer/tinkerpop/server/auth/GafferPopAuthoriserTest.java deleted file mode 100644 index d4598214281..00000000000 --- a/library/tinkerpop/src/test/java/uk/gov/gchq/gaffer/tinkerpop/server/auth/GafferPopAuthoriserTest.java +++ /dev/null @@ -1,137 +0,0 @@ -/* - * Copyright 2024 Crown Copyright - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package uk.gov.gchq.gaffer.tinkerpop.server.auth; - -import org.apache.tinkerpop.gremlin.process.computer.traversal.strategy.verification.VertexProgramRestrictionStrategy; -import org.apache.tinkerpop.gremlin.process.traversal.Bytecode; -import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversalSource; -import org.apache.tinkerpop.gremlin.process.traversal.strategy.verification.ReadOnlyStrategy; -import org.apache.tinkerpop.gremlin.server.auth.AuthenticatedUser; -import org.apache.tinkerpop.gremlin.server.authz.AuthorizationException; -import org.apache.tinkerpop.gremlin.util.function.Lambda; -import org.junit.jupiter.api.BeforeAll; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.TestInstance; -import org.junit.jupiter.api.TestInstance.Lifecycle; - -import uk.gov.gchq.gaffer.commonutil.StreamUtil; -import uk.gov.gchq.gaffer.graph.Graph; -import uk.gov.gchq.gaffer.mapstore.MapStoreProperties; -import uk.gov.gchq.gaffer.tinkerpop.GafferPopGraph; -import uk.gov.gchq.gaffer.tinkerpop.GafferPopGraphVariables; -import uk.gov.gchq.gaffer.tinkerpop.util.GafferPopTestUtil; - -import java.util.HashMap; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assertions.assertThatExceptionOfType; - -@TestInstance(Lifecycle.PER_CLASS) -class GafferPopAuthoriserTest { - - private static final MapStoreProperties PROPERTIES = MapStoreProperties.loadStoreProperties(StreamUtil.openStream( - GafferPopAuthoriserTest.class, "/gaffer/map-store.properties")); - private static final String TEST_USERNAME = "testUser"; - private GafferPopAuthoriser authoriser; - - @BeforeAll - void setup() { - authoriser = new GafferPopAuthoriser(); - authoriser.setup(new HashMap()); - } - - @Test - void shouldNotAuthoriseLambdaBytecodeRequest() { - // Given - final GafferPopGraph graph = GafferPopGraph.open(GafferPopTestUtil.TEST_CONFIGURATION_1, getGafferGraph()); - final GraphTraversalSource g = graph.traversal(); - final Bytecode bytecode = g.V().map(Lambda.function("it.get()")).asAdmin().getBytecode(); - - // Then - assertThatExceptionOfType(AuthorizationException.class) - .isThrownBy(() -> - authoriser.authorize(new AuthenticatedUser(TEST_USERNAME), bytecode, new HashMap())) - .withMessageContaining(GafferPopAuthoriser.REJECT_LAMBDA); - } - - @Test - void shouldNotAuthoriseMutatingBytecodeRequest() { - // Given - final GafferPopGraph graph = GafferPopGraph.open(GafferPopTestUtil.TEST_CONFIGURATION_1, getGafferGraph()); - final GraphTraversalSource g = graph.traversal(); - final Bytecode bytecode = g.withoutStrategies(ReadOnlyStrategy.class) - .V().addV().asAdmin().getBytecode(); - - // Then - assertThatExceptionOfType(AuthorizationException.class) - .isThrownBy(() -> - authoriser.authorize(new AuthenticatedUser(TEST_USERNAME), bytecode, new HashMap())) - .withMessageContaining(GafferPopAuthoriser.REJECT_MUTATE); - } - - - @Test - void shouldNotAuthoriseOLAPBytecodeRequest() { - // Given - final GafferPopGraph graph = GafferPopGraph.open(GafferPopTestUtil.TEST_CONFIGURATION_1, getGafferGraph()); - final GraphTraversalSource g = graph.traversal(); - final Bytecode bytecode = g.withoutStrategies(VertexProgramRestrictionStrategy.class) - .withComputer().V().asAdmin().getBytecode(); - - // Then - assertThatExceptionOfType(AuthorizationException.class) - .isThrownBy(() -> - authoriser.authorize(new AuthenticatedUser(TEST_USERNAME), bytecode, new HashMap())) - .withMessageContaining(GafferPopAuthoriser.REJECT_OLAP); - } - - @Test - void shouldNotAuthoriseSettingUserInRequest() { - // Given - final GafferPopGraph graph = GafferPopGraph.open(GafferPopTestUtil.TEST_CONFIGURATION_1, getGafferGraph()); - final GraphTraversalSource g = graph.traversal(); - final Bytecode bytecode = g.V().asAdmin().getBytecode(); - // Add the with() step separately otherwise it's converted to the OptionsStrategy - // by the asAdmin() call before we can compare. - bytecode.addStep("with", GafferPopGraphVariables.USER_ID, "notAllowed"); - - // Then - assertThatExceptionOfType(AuthorizationException.class) - .isThrownBy(() -> - authoriser.authorize(new AuthenticatedUser(TEST_USERNAME), bytecode, new HashMap())); - } - - @Test - void shouldInjectUserIdIntoRequest() throws AuthorizationException { - // Given - final GafferPopGraph graph = GafferPopGraph.open(GafferPopTestUtil.TEST_CONFIGURATION_1, getGafferGraph()); - final GraphTraversalSource g = graph.traversal(); - final Bytecode bytecode = g.V().asAdmin().getBytecode(); - final Bytecode expectedBytecode = g.V().asAdmin().getBytecode(); - // Add the with() step separately otherwise it's converted to the OptionsStrategy - // by the asAdmin() call before we can compare. - expectedBytecode.addSource("with", GafferPopGraphVariables.USER_ID, TEST_USERNAME); - - // Then - assertThat(authoriser.authorize(new AuthenticatedUser(TEST_USERNAME), bytecode, new HashMap())) - .isEqualTo(expectedBytecode); - } - - private Graph getGafferGraph() { - return GafferPopTestUtil.getGafferGraph(this.getClass(), PROPERTIES); - } -} diff --git a/pom.xml b/pom.xml index 8106202347e..25626464c92 100644 --- a/pom.xml +++ b/pom.xml @@ -98,6 +98,7 @@ 3.4.14 5.15.0 1.36.0 + 3.7.1 2.17 diff --git a/rest-api/spring-rest/pom.xml b/rest-api/spring-rest/pom.xml index 63cf96acdc9..521ab6fb6e3 100644 --- a/rest-api/spring-rest/pom.xml +++ b/rest-api/spring-rest/pom.xml @@ -60,6 +60,11 @@ jcs-cache-service ${project.parent.version} + + uk.gov.gchq.gaffer + tinkerpop + ${project.parent.version} + @@ -102,6 +107,10 @@ + + org.springframework.boot + spring-boot-starter-websocket + org.glassfish.jersey.inject jersey-hk2 @@ -132,6 +141,19 @@ junit-jupiter-engine test + + uk.gov.gchq.gaffer + tinkerpop + ${project.parent.version} + test-jar + test + + + org.apache.tinkerpop + gremlin-driver + ${tinkerpop.version} + test + diff --git a/rest-api/spring-rest/src/main/java/uk/gov/gchq/gaffer/rest/GafferWebApplication.java b/rest-api/spring-rest/src/main/java/uk/gov/gchq/gaffer/rest/GafferWebApplication.java index 127b5faf2b1..bc4790ee084 100644 --- a/rest-api/spring-rest/src/main/java/uk/gov/gchq/gaffer/rest/GafferWebApplication.java +++ b/rest-api/spring-rest/src/main/java/uk/gov/gchq/gaffer/rest/GafferWebApplication.java @@ -23,7 +23,7 @@ import org.springframework.boot.web.servlet.support.SpringBootServletInitializer; @OpenAPIDefinition(servers = { - @Server(url = "/rest", description = "Default Server URL") }) + @Server(url = "/", description = "Default Server URL") }) @SpringBootApplication public class GafferWebApplication extends SpringBootServletInitializer { diff --git a/rest-api/spring-rest/src/main/java/uk/gov/gchq/gaffer/rest/config/FactoryConfig.java b/rest-api/spring-rest/src/main/java/uk/gov/gchq/gaffer/rest/config/FactoryConfig.java index 445eb07619d..d2d6eac7fc2 100644 --- a/rest-api/spring-rest/src/main/java/uk/gov/gchq/gaffer/rest/config/FactoryConfig.java +++ b/rest-api/spring-rest/src/main/java/uk/gov/gchq/gaffer/rest/config/FactoryConfig.java @@ -1,5 +1,5 @@ /* - * Copyright 2020 Crown Copyright + * Copyright 2020-2024 Crown Copyright * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -29,7 +29,8 @@ import uk.gov.gchq.gaffer.rest.factory.DefaultExamplesFactory; import uk.gov.gchq.gaffer.rest.factory.ExamplesFactory; import uk.gov.gchq.gaffer.rest.factory.GraphFactory; -import uk.gov.gchq.gaffer.rest.factory.UserFactory; +import uk.gov.gchq.gaffer.rest.factory.spring.AbstractUserFactory; +import uk.gov.gchq.gaffer.rest.factory.spring.UnknownUserFactory; import javax.annotation.PostConstruct; @@ -42,6 +43,8 @@ public class FactoryConfig { private static final Logger LOGGER = LoggerFactory.getLogger(FactoryConfig.class); + public static final String USER_FACTORY_CLASS_DEFAULT = UnknownUserFactory.class.getName(); + private Environment environment; @Autowired @@ -77,7 +80,7 @@ public GraphFactory createGraphFactory() throws IllegalAccessException, Instanti } @Bean - public UserFactory createUserFactory() throws IllegalAccessException, InstantiationException { + public AbstractUserFactory createUserFactory() throws IllegalAccessException, InstantiationException { return getDefaultUserFactory().newInstance(); } @@ -98,13 +101,12 @@ private Class getDefaultGraphFactory() { } } - private Class getDefaultUserFactory() { - final String userFactoryClass = System.getProperty(SystemProperty.USER_FACTORY_CLASS, - SystemProperty.USER_FACTORY_CLASS_DEFAULT); + private Class getDefaultUserFactory() { + final String userFactoryClass = System.getProperty(SystemProperty.USER_FACTORY_CLASS, USER_FACTORY_CLASS_DEFAULT); try { return Class.forName(userFactoryClass) - .asSubclass(UserFactory.class); + .asSubclass(AbstractUserFactory.class); } catch (final ClassNotFoundException e) { throw new IllegalArgumentException("Unable to create user factory from class: " + userFactoryClass, e); } diff --git a/rest-api/spring-rest/src/main/java/uk/gov/gchq/gaffer/rest/config/GremlinConfig.java b/rest-api/spring-rest/src/main/java/uk/gov/gchq/gaffer/rest/config/GremlinConfig.java new file mode 100644 index 00000000000..a13d12d5c3f --- /dev/null +++ b/rest-api/spring-rest/src/main/java/uk/gov/gchq/gaffer/rest/config/GremlinConfig.java @@ -0,0 +1,58 @@ +/* + * Copyright 2024 Crown Copyright + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package uk.gov.gchq.gaffer.rest.config; + +import org.apache.commons.configuration2.builder.fluent.Configurations; +import org.apache.commons.configuration2.ex.ConfigurationException; +import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversalSource; +import org.apache.tinkerpop.gremlin.structure.Graph; +import org.apache.tinkerpop.gremlin.structure.util.empty.EmptyGraph; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +import uk.gov.gchq.gaffer.rest.factory.GraphFactory; +import uk.gov.gchq.gaffer.tinkerpop.GafferPopGraph; + +@Configuration +public class GremlinConfig { + + private static final Logger LOGGER = LoggerFactory.getLogger(GremlinConfig.class); + + /** + * Default path to look for a GafferPop properties file if not defined in the store properties. + */ + private static final String DEFAULT_PROPERTIES = "/gaffer/gafferpop.properties"; + + @Bean + public GraphTraversalSource graphTraversalSource(final GraphFactory graphFactory) throws Exception { + // Determine where to look for the GafferPop properties + String gafferPopProperties = graphFactory.getGraph().getStoreProperties().get(GafferPopGraph.GAFFERPOP_PROPERTIES); + if (gafferPopProperties == null) { + LOGGER.warn("GafferPop properties file was not specified using default location: {}", DEFAULT_PROPERTIES); + gafferPopProperties = DEFAULT_PROPERTIES; + } + // Obtain the graph traversal + try (Graph graph = GafferPopGraph.open(new Configurations().properties(gafferPopProperties), graphFactory.getGraph())) { + return graph.traversal(); + } catch (final ConfigurationException e) { + LOGGER.error("Error loading GafferPop config, Gremlin will be unavailable: {}", e.getMessage()); + return EmptyGraph.instance().traversal(); + } + } +} diff --git a/rest-api/spring-rest/src/main/java/uk/gov/gchq/gaffer/rest/config/GremlinWebSocketConfig.java b/rest-api/spring-rest/src/main/java/uk/gov/gchq/gaffer/rest/config/GremlinWebSocketConfig.java new file mode 100644 index 00000000000..f7ebd01029b --- /dev/null +++ b/rest-api/spring-rest/src/main/java/uk/gov/gchq/gaffer/rest/config/GremlinWebSocketConfig.java @@ -0,0 +1,47 @@ +/* + * Copyright 2024 Crown Copyright + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package uk.gov.gchq.gaffer.rest.config; + +import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversalSource; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Configuration; +import org.springframework.web.socket.config.annotation.EnableWebSocket; +import org.springframework.web.socket.config.annotation.WebSocketConfigurer; +import org.springframework.web.socket.config.annotation.WebSocketHandlerRegistry; + +import uk.gov.gchq.gaffer.rest.factory.spring.AbstractUserFactory; +import uk.gov.gchq.gaffer.rest.handler.GremlinWebSocketHandler; + +@Configuration +@EnableWebSocket +public class GremlinWebSocketConfig implements WebSocketConfigurer { + + private final GraphTraversalSource g; + private final AbstractUserFactory userFactory; + + @Autowired + public GremlinWebSocketConfig(final GraphTraversalSource g, final AbstractUserFactory userFactory) { + this.g = g; + this.userFactory = userFactory; + } + + @Override + public void registerWebSocketHandlers(final WebSocketHandlerRegistry registry) { + registry.addHandler(new GremlinWebSocketHandler(g, userFactory), "/gremlin"); + } + +} diff --git a/rest-api/spring-rest/src/main/java/uk/gov/gchq/gaffer/rest/controller/GremlinController.java b/rest-api/spring-rest/src/main/java/uk/gov/gchq/gaffer/rest/controller/GremlinController.java new file mode 100644 index 00000000000..af6d5e0c449 --- /dev/null +++ b/rest-api/spring-rest/src/main/java/uk/gov/gchq/gaffer/rest/controller/GremlinController.java @@ -0,0 +1,189 @@ +/* + * Copyright 2024 Crown Copyright + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package uk.gov.gchq.gaffer.rest.controller; + +import io.swagger.v3.oas.annotations.tags.Tag; +import org.apache.tinkerpop.gremlin.groovy.engine.GremlinExecutor; +import org.apache.tinkerpop.gremlin.jsr223.ConcurrentBindings; +import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversalSource; +import org.apache.tinkerpop.gremlin.structure.Graph; +import org.apache.tinkerpop.gremlin.structure.util.empty.EmptyGraph; +import org.json.JSONObject; +import org.opencypher.gremlin.translation.CypherAst; +import org.opencypher.gremlin.translation.translator.Translator; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.HttpHeaders; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestHeader; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import uk.gov.gchq.gaffer.core.exception.GafferRuntimeException; +import uk.gov.gchq.gaffer.exception.SerialisationException; +import uk.gov.gchq.gaffer.jsonserialisation.JSONSerialiser; +import uk.gov.gchq.gaffer.operation.Operation; +import uk.gov.gchq.gaffer.operation.OperationChain; +import uk.gov.gchq.gaffer.rest.factory.spring.AbstractUserFactory; +import uk.gov.gchq.gaffer.tinkerpop.GafferPopGraph; +import uk.gov.gchq.gaffer.tinkerpop.GafferPopGraphVariables; + +import java.nio.charset.StandardCharsets; +import java.util.LinkedList; + +import static org.springframework.http.MediaType.APPLICATION_JSON_VALUE; +import static org.springframework.http.MediaType.TEXT_PLAIN_VALUE; + +@RestController +@Tag(name = "gremlin") +@RequestMapping("/rest/gremlin") +public class GremlinController { + + // Keys for response JSON + public static final String EXPLAIN_OVERVIEW_KEY = "overview"; + public static final String EXPLAIN_OP_CHAIN_KEY = "chain"; + public static final String EXPLAIN_GREMLIN_KEY = "gremlin"; + + private final ConcurrentBindings bindings = new ConcurrentBindings(); + private final AbstractUserFactory userFactory; + private final Graph graph; + + @Autowired + public GremlinController(final GraphTraversalSource g, final AbstractUserFactory userFactory) { + bindings.putIfAbsent("g", g); + graph = g.getGraph(); + this.userFactory = userFactory; + } + + /** + * Explains what Gaffer operations are run for a given gremlin query. + * + * @param httpHeaders The request headers. + * @param gremlinQuery The gremlin groovy query. + * @return JSON response with explanation in. + */ + @PostMapping(path = "/explain", consumes = TEXT_PLAIN_VALUE, produces = APPLICATION_JSON_VALUE) + @io.swagger.v3.oas.annotations.Operation( + summary = "Explain a Gremlin Query", + description = "Runs a Gremlin query and outputs an explanation of what Gaffer operations were executed on the graph") + public String explain(@RequestHeader final HttpHeaders httpHeaders, @RequestBody final String gremlinQuery) { + return runGremlinAndGetExplain(gremlinQuery, httpHeaders).toString(); + } + + /** + * Explains what Gaffer operations are ran for a given cypher query, + * will translate to Gremlin using {@link CypherAst} before executing. + * + * @param httpHeaders The request headers. + * @param cypherQuery Opencypher query. + * @return JSON response with explanation in. + */ + @PostMapping(path = "/cypher/explain", consumes = TEXT_PLAIN_VALUE, produces = APPLICATION_JSON_VALUE) + @io.swagger.v3.oas.annotations.Operation( + summary = "Explain a Cypher Query Executed via Gremlin", + description = "Translates a Cypher query to Gremlin and outputs an explanation of what Gaffer operations" + + "were executed on the graph, note will always append a '.toList()' to the translation") + public String cypherExplain(@RequestHeader final HttpHeaders httpHeaders, @RequestBody final String cypherQuery) { + + final CypherAst ast = CypherAst.parse(cypherQuery); + // Translate the cypher to gremlin, always add a .toList() otherwise Gremlin wont execute it as its lazy + final String translation = ast.buildTranslation(Translator.builder().gremlinGroovy().enableCypherExtensions().build()) + ".toList()"; + + JSONObject response = runGremlinAndGetExplain(translation, httpHeaders); + response.put(EXPLAIN_GREMLIN_KEY, translation); + return response.toString(); + } + + /** + * Gets an explanation of the last chain of operations ran on a GafferPop graph. + * This essentially shows how a Gremlin query mapped to a Gaffer operation + * chain. + * Note due to how Gaffer maps to Tinkerpop some filtering steps in the Gremlin + * query may be absent from the operation chains in the explain as it may have + * been done in the Tinkerpop framework instead. + * + * @param graph The GafferPop graph + * @return A JSON payload with an overview and full JSON representation of the + * chain in. + */ + public static JSONObject getGafferPopExplanation(final GafferPopGraph graph) { + JSONObject result = new JSONObject(); + // Get the last operation chain that ran + LinkedList operations = new LinkedList<>(); + ((GafferPopGraphVariables) graph.variables()) + .getLastOperationChain() + .getOperations() + .forEach(op -> { + if (op instanceof OperationChain) { + operations.addAll(((OperationChain) op).flatten()); + } else { + operations.add(op); + } + }); + OperationChain flattenedChain = new OperationChain<>(operations); + String overview = flattenedChain.toOverviewString(); + + result.put(EXPLAIN_OVERVIEW_KEY, overview); + try { + result.put(EXPLAIN_OP_CHAIN_KEY, new JSONObject(new String(JSONSerialiser.serialise(flattenedChain), StandardCharsets.UTF_8))); + } catch (final SerialisationException e) { + result.put(EXPLAIN_OP_CHAIN_KEY, "FAILED TO SERIALISE OPERATION CHAIN"); + } + + return result; + } + + /** + * Executes a given Gremlin query on the graph then formats a JSON response with + * the executed Gaffer operations in. + * + * @param gremlinQuery The Gremlin groovy query. + * @param httpHeaders The headers for the request. + * @return JSON explanation. + */ + private JSONObject runGremlinAndGetExplain(final String gremlinQuery, final HttpHeaders httpHeaders) { + // Check we actually have a graph instance to use + GafferPopGraph gafferPopGraph; + if (graph instanceof EmptyGraph) { + throw new GafferRuntimeException("There is no GafferPop Graph configured"); + } else { + gafferPopGraph = (GafferPopGraph) graph; + } + // Hooks for user auth + userFactory.setHttpHeaders(httpHeaders); + graph.variables().set(GafferPopGraphVariables.USER, userFactory.createUser()); + + JSONObject explain = new JSONObject(); + try (GremlinExecutor gremlinExecutor = GremlinExecutor.build().globalBindings(bindings).create()) { + gafferPopGraph.setDefaultVariables((GafferPopGraphVariables) gafferPopGraph.variables()); + // Execute the query note this will actually run the query which we need + // as Gremlin will skip steps if there is no input from the previous ones + gremlinExecutor.eval(gremlinQuery).join(); + + // Get the chain and reset the variables + explain = getGafferPopExplanation(gafferPopGraph); + gafferPopGraph.setDefaultVariables((GafferPopGraphVariables) gafferPopGraph.variables()); + } catch (final InterruptedException e) { + Thread.currentThread().interrupt(); + } catch (final Exception e) { + throw new GafferRuntimeException("Failed to evaluate Gremlin query: " + e.getMessage(), e); + } + + return explain; + } + +} diff --git a/rest-api/spring-rest/src/main/java/uk/gov/gchq/gaffer/rest/controller/IGraphConfigurationController.java b/rest-api/spring-rest/src/main/java/uk/gov/gchq/gaffer/rest/controller/IGraphConfigurationController.java index 6cb43224cf1..ea7732745f8 100644 --- a/rest-api/spring-rest/src/main/java/uk/gov/gchq/gaffer/rest/controller/IGraphConfigurationController.java +++ b/rest-api/spring-rest/src/main/java/uk/gov/gchq/gaffer/rest/controller/IGraphConfigurationController.java @@ -1,5 +1,5 @@ /* - * Copyright 2020-2023 Crown Copyright + * Copyright 2020-2024 Crown Copyright * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -32,7 +32,7 @@ import static org.springframework.web.bind.annotation.RequestMethod.GET; @Tag(name = "config") -@RequestMapping("/graph/config") +@RequestMapping("/rest/graph/config") public interface IGraphConfigurationController { @RequestMapping( diff --git a/rest-api/spring-rest/src/main/java/uk/gov/gchq/gaffer/rest/controller/IJobController.java b/rest-api/spring-rest/src/main/java/uk/gov/gchq/gaffer/rest/controller/IJobController.java index e42c67c00b5..6d766b6ba76 100644 --- a/rest-api/spring-rest/src/main/java/uk/gov/gchq/gaffer/rest/controller/IJobController.java +++ b/rest-api/spring-rest/src/main/java/uk/gov/gchq/gaffer/rest/controller/IJobController.java @@ -1,5 +1,5 @@ /* - * Copyright 2020-2022 Crown Copyright + * Copyright 2020-2024 Crown Copyright * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -30,7 +30,7 @@ import static org.springframework.http.MediaType.APPLICATION_JSON_VALUE; @Tag(name = "job") -@RequestMapping("/graph/jobs") +@RequestMapping("/rest/graph/jobs") public interface IJobController { @PostMapping( diff --git a/rest-api/spring-rest/src/main/java/uk/gov/gchq/gaffer/rest/controller/IOperationController.java b/rest-api/spring-rest/src/main/java/uk/gov/gchq/gaffer/rest/controller/IOperationController.java index ec9556cb50f..669f928cd2a 100644 --- a/rest-api/spring-rest/src/main/java/uk/gov/gchq/gaffer/rest/controller/IOperationController.java +++ b/rest-api/spring-rest/src/main/java/uk/gov/gchq/gaffer/rest/controller/IOperationController.java @@ -1,5 +1,5 @@ /* - * Copyright 2020-2023 Crown Copyright + * Copyright 2020-2024 Crown Copyright * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -31,7 +31,7 @@ import static org.springframework.web.bind.annotation.RequestMethod.POST; @Tag(name = "operations") -@RequestMapping("/graph/operations") +@RequestMapping("/rest/graph/operations") public interface IOperationController { @RequestMapping( diff --git a/rest-api/spring-rest/src/main/java/uk/gov/gchq/gaffer/rest/controller/IPropertiesController.java b/rest-api/spring-rest/src/main/java/uk/gov/gchq/gaffer/rest/controller/IPropertiesController.java index b8ce52118e2..ed14c810b3f 100644 --- a/rest-api/spring-rest/src/main/java/uk/gov/gchq/gaffer/rest/controller/IPropertiesController.java +++ b/rest-api/spring-rest/src/main/java/uk/gov/gchq/gaffer/rest/controller/IPropertiesController.java @@ -1,5 +1,5 @@ /* - * Copyright 2020-2022 Crown Copyright + * Copyright 2020-2024 Crown Copyright * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -27,7 +27,7 @@ import static org.springframework.web.bind.annotation.RequestMethod.GET; @Tag(name = "properties") -@RequestMapping("/properties") +@RequestMapping("/rest/properties") public interface IPropertiesController { @RequestMapping( diff --git a/rest-api/spring-rest/src/main/java/uk/gov/gchq/gaffer/rest/controller/IStatusController.java b/rest-api/spring-rest/src/main/java/uk/gov/gchq/gaffer/rest/controller/IStatusController.java index 6ca24ff7e27..24b73577f89 100644 --- a/rest-api/spring-rest/src/main/java/uk/gov/gchq/gaffer/rest/controller/IStatusController.java +++ b/rest-api/spring-rest/src/main/java/uk/gov/gchq/gaffer/rest/controller/IStatusController.java @@ -1,5 +1,5 @@ /* - * Copyright 2020-2022 Crown Copyright + * Copyright 2020-2024 Crown Copyright * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -26,7 +26,7 @@ import static org.springframework.web.bind.annotation.RequestMethod.GET; @Tag(name = "status") -@RequestMapping("/graph/status") +@RequestMapping("/rest/graph/status") public interface IStatusController { @RequestMapping( diff --git a/rest-api/spring-rest/src/main/java/uk/gov/gchq/gaffer/rest/controller/VersionController.java b/rest-api/spring-rest/src/main/java/uk/gov/gchq/gaffer/rest/controller/VersionController.java index 3027ba64faa..b4ffe5cafc6 100644 --- a/rest-api/spring-rest/src/main/java/uk/gov/gchq/gaffer/rest/controller/VersionController.java +++ b/rest-api/spring-rest/src/main/java/uk/gov/gchq/gaffer/rest/controller/VersionController.java @@ -1,5 +1,5 @@ /* - * Copyright 2023 Crown Copyright + * Copyright 2023-2024 Crown Copyright * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -35,7 +35,7 @@ public class VersionController { * * @return Version of the graph */ - @GetMapping(path = "/graph/version", produces = TEXT_PLAIN_VALUE) + @GetMapping(path = "/rest/graph/version", produces = TEXT_PLAIN_VALUE) @Operation(summary = "Retrieves the version of the Gaffer Graph") public String getGafferVersion() { // Return the preloaded version string from the common-rest library diff --git a/rest-api/spring-rest/src/main/java/uk/gov/gchq/gaffer/rest/factory/spring/AbstractUserFactory.java b/rest-api/spring-rest/src/main/java/uk/gov/gchq/gaffer/rest/factory/spring/AbstractUserFactory.java new file mode 100644 index 00000000000..f61456c8576 --- /dev/null +++ b/rest-api/spring-rest/src/main/java/uk/gov/gchq/gaffer/rest/factory/spring/AbstractUserFactory.java @@ -0,0 +1,47 @@ +/* + * Copyright 2024 Crown Copyright + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package uk.gov.gchq.gaffer.rest.factory.spring; + +import org.springframework.http.HttpHeaders; + +import uk.gov.gchq.gaffer.rest.factory.UserFactory; +import uk.gov.gchq.gaffer.user.User; + +/** + * The base abstract {@link UserFactory} implementation for the spring + * rest API. Allows setting the http headers for use in authorisation. + */ +public class AbstractUserFactory implements UserFactory { + + HttpHeaders httpHeaders; + + @Override + public User createUser() { + throw new UnsupportedOperationException("Unimplemented method 'createUser'"); + } + + /** + * Allow setting the {@link HttpHeaders} the user factory may use + * to carry out authorisation. + * + * @param httpHeaders the headers + */ + public void setHttpHeaders(final HttpHeaders httpHeaders) { + this.httpHeaders = httpHeaders; + } + +} diff --git a/rest-api/spring-rest/src/main/java/uk/gov/gchq/gaffer/rest/factory/spring/UnknownUserFactory.java b/rest-api/spring-rest/src/main/java/uk/gov/gchq/gaffer/rest/factory/spring/UnknownUserFactory.java new file mode 100644 index 00000000000..9fc77c7cb15 --- /dev/null +++ b/rest-api/spring-rest/src/main/java/uk/gov/gchq/gaffer/rest/factory/spring/UnknownUserFactory.java @@ -0,0 +1,36 @@ +/* + * Copyright 2024 Crown Copyright + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package uk.gov.gchq.gaffer.rest.factory.spring; + +import uk.gov.gchq.gaffer.user.User; + +import static uk.gov.gchq.gaffer.user.User.UNKNOWN_USER_ID; + +/** + * Default implementation of the {@link AbstractUserFactory}. + * Always returns an empty {@link User} object (representing an unknown user). + */ +public class UnknownUserFactory extends AbstractUserFactory { + + @Override + public User createUser() { + return new User.Builder() + .userId(UNKNOWN_USER_ID) + .opAuth("user") + .build(); + } +} diff --git a/rest-api/spring-rest/src/main/java/uk/gov/gchq/gaffer/rest/handler/GremlinWebSocketHandler.java b/rest-api/spring-rest/src/main/java/uk/gov/gchq/gaffer/rest/handler/GremlinWebSocketHandler.java new file mode 100644 index 00000000000..1564a5bfd4a --- /dev/null +++ b/rest-api/spring-rest/src/main/java/uk/gov/gchq/gaffer/rest/handler/GremlinWebSocketHandler.java @@ -0,0 +1,238 @@ +/* + * Copyright 2024 Crown Copyright + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package uk.gov.gchq.gaffer.rest.handler; + +import io.netty.buffer.ByteBuf; +import io.netty.buffer.PooledByteBufAllocator; +import io.netty.buffer.Unpooled; +import io.opentelemetry.api.trace.Span; +import io.opentelemetry.api.trace.StatusCode; +import io.opentelemetry.context.Context; +import io.opentelemetry.context.Scope; +import org.apache.tinkerpop.gremlin.groovy.engine.GremlinExecutor; +import org.apache.tinkerpop.gremlin.jsr223.ConcurrentBindings; +import org.apache.tinkerpop.gremlin.process.remote.traversal.DefaultRemoteTraverser; +import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversalSource; +import org.apache.tinkerpop.gremlin.structure.Graph; +import org.apache.tinkerpop.gremlin.util.MessageSerializer; +import org.apache.tinkerpop.gremlin.util.Tokens; +import org.apache.tinkerpop.gremlin.util.function.FunctionUtils; +import org.apache.tinkerpop.gremlin.util.iterator.IteratorUtils; +import org.apache.tinkerpop.gremlin.util.message.RequestMessage; +import org.apache.tinkerpop.gremlin.util.message.ResponseMessage; +import org.apache.tinkerpop.gremlin.util.message.ResponseStatusCode; +import org.apache.tinkerpop.gremlin.util.ser.GraphBinaryMessageSerializerV1; +import org.apache.tinkerpop.gremlin.util.ser.GraphSONMessageSerializerV3; +import org.apache.tinkerpop.gremlin.util.ser.MessageTextSerializer; +import org.apache.tinkerpop.gremlin.util.ser.SerTokens; +import org.json.JSONObject; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.web.socket.BinaryMessage; +import org.springframework.web.socket.WebSocketSession; +import org.springframework.web.socket.handler.BinaryWebSocketHandler; + +import uk.gov.gchq.gaffer.commonutil.otel.OtelUtil; +import uk.gov.gchq.gaffer.rest.controller.GremlinController; +import uk.gov.gchq.gaffer.rest.factory.spring.AbstractUserFactory; +import uk.gov.gchq.gaffer.tinkerpop.GafferPopGraph; +import uk.gov.gchq.gaffer.tinkerpop.GafferPopGraphVariables; + +import java.io.IOException; +import java.nio.ByteBuffer; +import java.nio.charset.StandardCharsets; +import java.util.AbstractMap.SimpleEntry; +import java.util.Collections; +import java.util.Map; +import java.util.UUID; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +/** + * Websocket handler for accepting and responding to Gremlin queries. + * This enables an endpoint that acts like a Gremlin server which will + * run requests on the current Gaffer graph via the GafferPop library. + */ +public class GremlinWebSocketHandler extends BinaryWebSocketHandler { + private static final Logger LOGGER = LoggerFactory.getLogger(GremlinWebSocketHandler.class); + + /** + * The default serialiser used for Gremlin queries if the serialiser for mime type is not found. + */ + private static final MessageSerializer DEFAULT_SERIALISER = new GraphBinaryMessageSerializerV1(); + + // Mappings of mime types and serialisers + private final Map> serialisers = Stream.of( + new SimpleEntry<>(SerTokens.MIME_GRAPHBINARY_V1, new GraphBinaryMessageSerializerV1()), + new SimpleEntry<>(SerTokens.MIME_GRAPHSON_V3, new GraphSONMessageSerializerV3()), + new SimpleEntry<>(SerTokens.MIME_JSON, new GraphSONMessageSerializerV3())) + .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)); + + private final ExecutorService executorService = Context.taskWrapping(Executors.newFixedThreadPool(4)); + private final ConcurrentBindings bindings = new ConcurrentBindings(); + private final AbstractUserFactory userFactory; + private final Graph graph; + + /** + * Constructor + * + * @param g The graph traversal source + * @param userFactory The user factory + */ + public GremlinWebSocketHandler(final GraphTraversalSource g, final AbstractUserFactory userFactory) { + bindings.putIfAbsent("g", g); + graph = g.getGraph(); + this.userFactory = userFactory; + } + + @Override + protected void handleBinaryMessage(final WebSocketSession session, final BinaryMessage message) throws Exception { + ByteBuf byteBuf = convertToByteBuf(message); + + // Read the start bytes to find the type to correctly deserialise + byte[] bytes = new byte[byteBuf.readByte()]; + byteBuf.readBytes(bytes); + String mimeType = new String(bytes, StandardCharsets.UTF_8); + + // Use the relevant serialiser for the mime type (cast to text is required to send response as String) + MessageTextSerializer serialiser = (MessageTextSerializer) serialisers.getOrDefault(mimeType, DEFAULT_SERIALISER); + LOGGER.debug("Using Tinkerpop serialiser: {}", serialiser.getClass().getSimpleName()); + + // Deserialise the request ensuring to discard the already read bytes + RequestMessage request = serialiser.deserializeRequest(byteBuf.discardReadBytes()); + + // Handle and respond + sendBinaryResponse(session, serialiser, handleGremlinRequest(session, request)); + } + + /** + * Extracts the relevant information from a {@link RequestMessage} and validates + * the Gremlin query requested before executing on the current graph. Formulates + * the result into a {@link ResponseMessage} to be sent back to the client. + * + * @param session The current websocket session. + * @param request The Gremlin request. + * @return The response message containing the result. + */ + private ResponseMessage handleGremlinRequest(final WebSocketSession session, final RequestMessage request) { + final UUID requestId = request.getRequestId(); + ResponseMessage responseMessage; + LOGGER.info("QUERY IS: {} ", request.getArgs().get(Tokens.ARGS_GREMLIN)); + + // OpenTelemetry hooks + Span span = OtelUtil.startSpan(this.getClass().getName(), "Gremlin Request: " + requestId.toString()); + span.setAttribute("gaffer.gremlin.query", request.getArgs().get(Tokens.ARGS_GREMLIN).toString()); + + // Execute the query + try (Scope scope = span.makeCurrent(); + GremlinExecutor gremlinExecutor = GremlinExecutor.build() + .globalBindings(bindings) + .executorService(executorService) + .create()) { + // Set current headers for potential authorisation then set the user + userFactory.setHttpHeaders(session.getHandshakeHeaders()); + graph.variables().set(GafferPopGraphVariables.USER, userFactory.createUser()); + + // Run the query using the gremlin executor service + Object result = gremlinExecutor.eval( + request.getArgs().get(Tokens.ARGS_GREMLIN), + request.getArg(Tokens.ARGS_LANGUAGE), + request.getArgOrDefault(Tokens.ARGS_BINDINGS, Collections.emptyMap()), + request.getArgOrDefault(Tokens.ARGS_EVAL_TIMEOUT, null), + FunctionUtils.wrapFunction(output -> + // Need to replicate what TraversalOpProcessor does with a bytecode op, it converts + // results to Traverser so that GLVs can handle the results. Don't quite get the same + // benefit here as the bulk has to be 1 since we've already resolved the result + request.getOp().equals(Tokens.OPS_BYTECODE) + ? IteratorUtils.asList(output).stream().map(r -> new DefaultRemoteTraverser(r, 1)) + .collect(Collectors.toList()) + : IteratorUtils.asList(output))) + .get(); + + // Provide an debug explanation for the query that just ran + span.addEvent("Request complete"); + if (graph instanceof GafferPopGraph) { + JSONObject gafferOperationChain = GremlinController.getGafferPopExplanation((GafferPopGraph) graph); + span.setAttribute("gaffer.gremlin.explain", gafferOperationChain.toString()); + LOGGER.debug("{}", gafferOperationChain); + } + + // Build the response + responseMessage = ResponseMessage.build(requestId) + .code(ResponseStatusCode.SUCCESS) + .result(result).create(); + + } catch (final InterruptedException e) { + Thread.currentThread().interrupt(); + responseMessage = ResponseMessage.build(requestId) + .code(ResponseStatusCode.SERVER_ERROR) + .statusMessage(e.getMessage()).create(); + span.setStatus(StatusCode.ERROR, e.getMessage()); + span.recordException(e); + } catch (final Exception e) { + responseMessage = ResponseMessage.build(requestId) + .code(ResponseStatusCode.SERVER_ERROR) + .statusMessage(e.getMessage()).create(); + span.setStatus(StatusCode.ERROR, e.getMessage()); + span.recordException(e); + } finally { + span.end(); + } + + return responseMessage; + + } + + /** + * Serialises and sends a response using the current session. + * + * @param session Current websocket session + * @param serialiser The serialiser to use for the message + * @param response The response message + * @throws IOException If fail to serialise or send + */ + private void sendBinaryResponse(final WebSocketSession session, final MessageSerializer serialiser, final ResponseMessage response) throws IOException { + // Serialise response and read the bytes into a byte array + ByteBuf responseByteBuf = serialiser.serializeResponseAsBinary(response, PooledByteBufAllocator.DEFAULT); + byte[] responseBytes = new byte[responseByteBuf.readableBytes()]; + responseByteBuf.readBytes(responseBytes); + // Send response + session.sendMessage(new BinaryMessage(responseBytes)); + } + + /** + * Simple method to help the conversion between {@link BinaryMessage} + * and {@link ByteBuf} type. + * + * @param message the binary web socket message. + * @return A netty byte buffer for the message. + */ + private ByteBuf convertToByteBuf(final BinaryMessage message) { + ByteBuffer byteBuffer = message.getPayload(); + + if (byteBuffer.hasArray()) { + return Unpooled.wrappedBuffer(byteBuffer.array(), byteBuffer.position(), byteBuffer.remaining()); + } else { + byte[] byteArray = new byte[byteBuffer.remaining()]; + byteBuffer.get(byteArray); + return Unpooled.wrappedBuffer(byteArray); + } + } + +} diff --git a/rest-api/spring-rest/src/main/resources/application.yml b/rest-api/spring-rest/src/main/resources/application.yml index 06936a4979a..c495df8ccad 100644 --- a/rest-api/spring-rest/src/main/resources/application.yml +++ b/rest-api/spring-rest/src/main/resources/application.yml @@ -21,7 +21,7 @@ gaffer: schemas: rest-api/spring-rest/src/main/resources/schemas server: - servlet.context-path: /rest + servlet.context-path: / # Configuration to replicate previous Swagger UI style springdoc: diff --git a/rest-api/spring-rest/src/test/java/uk/gov/gchq/gaffer/rest/config/FactoryConfigTest.java b/rest-api/spring-rest/src/test/java/uk/gov/gchq/gaffer/rest/config/FactoryConfigTest.java index 601c0e33dfc..4fbe603dfa1 100644 --- a/rest-api/spring-rest/src/test/java/uk/gov/gchq/gaffer/rest/config/FactoryConfigTest.java +++ b/rest-api/spring-rest/src/test/java/uk/gov/gchq/gaffer/rest/config/FactoryConfigTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2020-2021 Crown Copyright + * Copyright 2020-2024 Crown Copyright * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -26,7 +26,7 @@ import uk.gov.gchq.gaffer.rest.factory.DefaultGraphFactory; import uk.gov.gchq.gaffer.rest.factory.MockGraphFactory; import uk.gov.gchq.gaffer.rest.factory.MockUserFactory; -import uk.gov.gchq.gaffer.rest.factory.UnknownUserFactory; +import uk.gov.gchq.gaffer.rest.factory.spring.UnknownUserFactory; import java.util.Properties; diff --git a/rest-api/spring-rest/src/test/java/uk/gov/gchq/gaffer/rest/controller/GremlinControllerTest.java b/rest-api/spring-rest/src/test/java/uk/gov/gchq/gaffer/rest/controller/GremlinControllerTest.java new file mode 100644 index 00000000000..d5cd4e79169 --- /dev/null +++ b/rest-api/spring-rest/src/test/java/uk/gov/gchq/gaffer/rest/controller/GremlinControllerTest.java @@ -0,0 +1,174 @@ +/* + * Copyright 2024 Crown Copyright + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package uk.gov.gchq.gaffer.rest.controller; + +import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversalSource; +import org.apache.tinkerpop.gremlin.structure.Graph; +import org.json.JSONArray; +import org.json.JSONObject; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; +import org.springframework.boot.test.context.TestConfiguration; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Import; +import org.springframework.test.context.junit.jupiter.SpringExtension; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.test.web.servlet.MvcResult; +import org.springframework.test.web.servlet.request.MockMvcRequestBuilders; + +import uk.gov.gchq.gaffer.operation.impl.get.GetElements; +import uk.gov.gchq.gaffer.rest.factory.spring.AbstractUserFactory; +import uk.gov.gchq.gaffer.rest.factory.spring.UnknownUserFactory; +import uk.gov.gchq.gaffer.tinkerpop.util.GafferPopTestUtil.StoreType; +import uk.gov.gchq.gaffer.tinkerpop.util.modern.GafferPopModernTestUtils; + +import java.util.Arrays; +import java.util.List; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.springframework.http.MediaType.TEXT_PLAIN_VALUE; +import static uk.gov.gchq.gaffer.tinkerpop.util.modern.GafferPopModernTestUtils.MARKO; + +@ExtendWith(SpringExtension.class) +@WebMvcTest(value = GremlinController.class) +@Import(GremlinControllerTest.TestConfig.class) +class GremlinControllerTest { + + private static final String GREMLIN_EXPLAIN_ENDPOINT = "/rest/gremlin/explain"; + private static final String CYPHER_EXPLAIN_ENDPOINT = "/rest/gremlin/cypher/explain"; + + @TestConfiguration + static class TestConfig { + @Bean + public GraphTraversalSource g() { + Graph graph = GafferPopModernTestUtils.createModernGraph(TestConfig.class, StoreType.MAP); + return graph.traversal(); + } + + @Bean + public AbstractUserFactory userFactory() { + return new UnknownUserFactory(); + } + } + + @Autowired + private MockMvc mockMvc; + + @Autowired + private GraphTraversalSource g; + + @Test + void shouldReturnExplainOfValidGremlinQuery() throws Exception { + // Given + String gremlinString = "g.V('" + MARKO.getId() + "').toList()"; + List expectedOperations = Arrays.asList(GetElements.class.getName()); + + // When + MvcResult result = mockMvc + .perform(MockMvcRequestBuilders + .post(GREMLIN_EXPLAIN_ENDPOINT) + .content(gremlinString) + .contentType(TEXT_PLAIN_VALUE)) + .andReturn(); + + // Then + // Ensure OK response + assertThat(result.getResponse().getStatus()).isEqualTo(200); + + // Get and check response + JSONObject jsonResponse = new JSONObject(result.getResponse().getContentAsString()); + assertThat(jsonResponse.has(GremlinController.EXPLAIN_OVERVIEW_KEY)).isTrue(); + assertThat(jsonResponse.has(GremlinController.EXPLAIN_OP_CHAIN_KEY)).isTrue(); + + // Check the operations that ran are as expected + JSONArray operations = jsonResponse.getJSONObject("chain").getJSONArray("operations"); + assertThat(operations) + .map(json -> ((JSONObject) json).getString("class")) + .containsExactlyElementsOf(expectedOperations); + } + + @Test + void shouldRejectMalformedGremlinQuery() throws Exception { + // Given + String gremlinString = "g.V().stepDoesNotExist().toList()"; + + // When + MvcResult result = mockMvc + .perform(MockMvcRequestBuilders + .post(GREMLIN_EXPLAIN_ENDPOINT) + .content(gremlinString) + .contentType(TEXT_PLAIN_VALUE)) + .andReturn(); + + // Then + // Expect a server error response + assertThat(result.getResponse().getStatus()).isEqualTo(500); + } + + @Test + void shouldReturnExplainOfValidCypherQuery() throws Exception { + // Given + String cypherString = "MATCH (p:person) WHERE ID(p) = '" + MARKO.getId() + "' RETURN p"; + List expectedOperations = Arrays.asList(GetElements.class.getName()); + + // When + MvcResult result = mockMvc + .perform(MockMvcRequestBuilders + .post(CYPHER_EXPLAIN_ENDPOINT) + .content(cypherString) + .contentType(TEXT_PLAIN_VALUE)) + .andReturn(); + + // Then + // Ensure OK response + assertThat(result.getResponse().getStatus()).isEqualTo(200); + + // Get and check response + JSONObject jsonResponse = new JSONObject(result.getResponse().getContentAsString()); + assertThat(jsonResponse.has(GremlinController.EXPLAIN_OVERVIEW_KEY)).isTrue(); + assertThat(jsonResponse.has(GremlinController.EXPLAIN_OP_CHAIN_KEY)).isTrue(); + assertThat(jsonResponse.has(GremlinController.EXPLAIN_GREMLIN_KEY)).isTrue(); + + // Check the operations that ran are as expected + JSONArray operations = jsonResponse.getJSONObject("chain").getJSONArray("operations"); + assertThat(operations) + .map(json -> ((JSONObject) json).getString("class")) + .containsExactlyElementsOf(expectedOperations); + } + + @Test + void shouldRejectMalformedCypherQuery() throws Exception { + // Given + String cypherString = "MATCH (p:person) WHERE RETURN p"; + + // When + MvcResult result = mockMvc + .perform(MockMvcRequestBuilders + .post(CYPHER_EXPLAIN_ENDPOINT) + .content(cypherString) + .contentType(TEXT_PLAIN_VALUE)) + .andReturn(); + + // Then + // Expect a server error response + assertThat(result.getResponse().getStatus()).isEqualTo(500); + } + + +} diff --git a/rest-api/spring-rest/src/test/java/uk/gov/gchq/gaffer/rest/controller/VersionControllerTest.java b/rest-api/spring-rest/src/test/java/uk/gov/gchq/gaffer/rest/controller/VersionControllerTest.java index d50e3a137c5..5855c4c3abb 100644 --- a/rest-api/spring-rest/src/test/java/uk/gov/gchq/gaffer/rest/controller/VersionControllerTest.java +++ b/rest-api/spring-rest/src/test/java/uk/gov/gchq/gaffer/rest/controller/VersionControllerTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2023 Crown Copyright + * Copyright 2023-2024 Crown Copyright * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -48,7 +48,7 @@ void sendRequestAndCheckForValidVersion() throws Exception { // Perform mock request to the endpoint RequestBuilder requestBuilder = MockMvcRequestBuilders - .get("/graph/version") + .get("/rest/graph/version") .accept(TEXT_PLAIN_VALUE); MvcResult result = mockMvc.perform(requestBuilder).andReturn(); diff --git a/rest-api/spring-rest/src/test/java/uk/gov/gchq/gaffer/rest/factory/MockUserFactory.java b/rest-api/spring-rest/src/test/java/uk/gov/gchq/gaffer/rest/factory/MockUserFactory.java index a57f178acd5..b2ffc36146e 100644 --- a/rest-api/spring-rest/src/test/java/uk/gov/gchq/gaffer/rest/factory/MockUserFactory.java +++ b/rest-api/spring-rest/src/test/java/uk/gov/gchq/gaffer/rest/factory/MockUserFactory.java @@ -1,5 +1,5 @@ /* - * Copyright 2020 Crown Copyright + * Copyright 2020-2024 Crown Copyright * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -13,14 +13,16 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + package uk.gov.gchq.gaffer.rest.factory; +import uk.gov.gchq.gaffer.rest.factory.spring.AbstractUserFactory; import uk.gov.gchq.gaffer.store.Context; import uk.gov.gchq.gaffer.user.User; import static org.mockito.Mockito.mock; -public class MockUserFactory implements UserFactory { +public class MockUserFactory extends AbstractUserFactory { final User user = mock(User.class); diff --git a/rest-api/spring-rest/src/test/java/uk/gov/gchq/gaffer/rest/integration/controller/AbstractRestApiIT.java b/rest-api/spring-rest/src/test/java/uk/gov/gchq/gaffer/rest/integration/controller/AbstractRestApiIT.java index 5b8e3640605..f8274cc8d68 100644 --- a/rest-api/spring-rest/src/test/java/uk/gov/gchq/gaffer/rest/integration/controller/AbstractRestApiIT.java +++ b/rest-api/spring-rest/src/test/java/uk/gov/gchq/gaffer/rest/integration/controller/AbstractRestApiIT.java @@ -1,5 +1,5 @@ /* - * Copyright 2020-2022 Crown Copyright + * Copyright 2020-2024 Crown Copyright * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -82,11 +82,12 @@ protected int getPort() { } protected String getContextPath() { - return contextPath; + // All the rest endpoints are under /rest context + return contextPath + "rest"; } protected String getBaseURl() { - return "http://localhost:" + port + "/" + contextPath; + return "http://localhost:" + port + "/" + getContextPath(); } protected ResponseEntity get(final String path, final Class responseBodyClass) { diff --git a/rest-api/spring-rest/src/test/java/uk/gov/gchq/gaffer/rest/integration/handler/GremlinWebSocketIT.java b/rest-api/spring-rest/src/test/java/uk/gov/gchq/gaffer/rest/integration/handler/GremlinWebSocketIT.java new file mode 100644 index 00000000000..2dba6d0a30c --- /dev/null +++ b/rest-api/spring-rest/src/test/java/uk/gov/gchq/gaffer/rest/integration/handler/GremlinWebSocketIT.java @@ -0,0 +1,148 @@ +/* + * Copyright 2024 Crown Copyright + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package uk.gov.gchq.gaffer.rest.integration.handler; + +import org.apache.tinkerpop.gremlin.driver.Client; +import org.apache.tinkerpop.gremlin.driver.Cluster; +import org.apache.tinkerpop.gremlin.driver.Result; +import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversalSource; +import org.apache.tinkerpop.gremlin.structure.Graph; +import org.apache.tinkerpop.gremlin.util.ser.GraphSONMessageSerializerV3; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.test.context.TestConfiguration; +import org.springframework.boot.test.web.server.LocalServerPort; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Import; +import org.springframework.context.annotation.Profile; +import org.springframework.test.context.ActiveProfiles; +import org.springframework.test.context.junit.jupiter.SpringExtension; + +import uk.gov.gchq.gaffer.rest.factory.spring.AbstractUserFactory; +import uk.gov.gchq.gaffer.rest.factory.spring.UnknownUserFactory; +import uk.gov.gchq.gaffer.tinkerpop.util.GafferPopTestUtil.StoreType; +import uk.gov.gchq.gaffer.tinkerpop.util.modern.GafferPopModernTestUtils; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatExceptionOfType; +import static uk.gov.gchq.gaffer.tinkerpop.GafferPopGraphVariables.CYPHER_KEY; +import static uk.gov.gchq.gaffer.tinkerpop.util.modern.GafferPopModernTestUtils.JOSH; +import static uk.gov.gchq.gaffer.tinkerpop.util.modern.GafferPopModernTestUtils.MARKO; +import static uk.gov.gchq.gaffer.tinkerpop.util.modern.GafferPopModernTestUtils.PETER; +import static uk.gov.gchq.gaffer.tinkerpop.util.modern.GafferPopModernTestUtils.VADAS; + +import java.util.LinkedHashMap; +import java.util.List; +import java.util.concurrent.ExecutionException; +import java.util.stream.Collectors; + +/** + * Integration testing for the Gremlin websocket. Testing is fairly simple as + * GafferPop is more heavily tested in its own module, focus of testing here is + * ensuring the websocket can at least accept Gremlin and GafferPop related + * queries via a standard tinkerpop client connection. + */ +@ExtendWith(SpringExtension.class) +@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) +@Import(GremlinWebSocketIT.TestConfig.class) +@ActiveProfiles("test") +class GremlinWebSocketIT { + + @TestConfiguration + static class TestConfig { + + @Bean + @Profile("test") + public GraphTraversalSource g() { + Graph graph = GafferPopModernTestUtils.createModernGraph(TestConfig.class, StoreType.MAP); + return graph.traversal(); + } + + @Bean + @Profile("test") + public AbstractUserFactory userFactory() { + return new UnknownUserFactory(); + } + } + + @LocalServerPort + private Integer port; + + @Autowired + private GraphTraversalSource g; + + private Client client; + + @BeforeEach + void setup() { + // Set up a client connection to the server + Cluster cluster = Cluster.build() + .addContactPoint("localhost") + .port(port) + .serializer(new GraphSONMessageSerializerV3()).create(); + this.client = cluster.connect(); + } + + @Test + void shouldAcceptBasicGremlinQueries() { + // Given + String query = "g.V().hasLabel('person').toList()"; + + // When + List results = client.submit(query).stream().collect(Collectors.toList()); + + // Then + assertThat(results) + .map(result -> result.getElement().id()) + .containsExactlyInAnyOrder( + MARKO.getId(), + VADAS.getId(), + PETER.getId(), + JOSH.getId()); + } + + @Test + void shouldRejectMalformedGremlinQueries() { + // Given + String query = "g.V().thisStepDoesNotExist().toList()"; + + // When/Then + assertThatExceptionOfType(ExecutionException.class) + .isThrownBy(() -> client.submit(query).all().get()) + .withMessageContaining("groovy.lang.MissingMethodException"); + } + + @Test + void shouldAcceptQueryWithCypher() { + // Given + String cypherQuery = "MATCH (p:person) WHERE ID(p) = '" + MARKO.getId() + "' RETURN p.name"; + String gremlinQuery = "g.with(\"" + CYPHER_KEY + "\", " + "\"" + cypherQuery + "\").call().toList()"; + + // When + List results = client.submit(gremlinQuery).stream().collect(Collectors.toList()); + + // Then + // Cypher returns each result under the project name e.g. 'p' so we need to extract + assertThat(results) + .flatMap(result -> ((LinkedHashMap) result.getObject()).values()) + .containsExactly(MARKO.getName()); + } + +} diff --git a/rest-api/spring-rest/src/test/resources/gaffer/schema/elements.json b/rest-api/spring-rest/src/test/resources/gaffer/schema/elements.json new file mode 100644 index 00000000000..2bf7bb63960 --- /dev/null +++ b/rest-api/spring-rest/src/test/resources/gaffer/schema/elements.json @@ -0,0 +1,49 @@ +{ + "entities": { + "vertex": { + "vertex": "id" + }, + "person": { + "vertex": "person", + "properties": { + "name": "name.string", + "age": "age.integer" + } + }, + "software": { + "vertex": "software", + "properties": { + "name": "name.string", + "lang": "name.string" + } + } + }, + "edges": { + "knows": { + "source": "person", + "destination": "person", + "directed": "true", + "properties": { + "weight": "weight.double" + } + }, + "created": { + "source": "person", + "destination": "software", + "directed": "true", + "properties": { + "weight": "weight.double" + } + }, + "dependsOn": { + "source": "software", + "destination": "software", + "directed": "true" + }, + "encapsulates": { + "source": "software", + "destination": "software", + "directed": "true" + } + } +} diff --git a/rest-api/spring-rest/src/test/resources/gaffer/schema/types.json b/rest-api/spring-rest/src/test/resources/gaffer/schema/types.json new file mode 100644 index 00000000000..601bc87a04a --- /dev/null +++ b/rest-api/spring-rest/src/test/resources/gaffer/schema/types.json @@ -0,0 +1,34 @@ +{ + "types": { + "id": { + "class": "java.lang.String" + }, + "person": { + "class": "java.lang.String" + }, + "software": { + "class": "java.lang.String" + }, + "true": { + "class": "java.lang.Boolean" + }, + "name.string": { + "class": "java.lang.String", + "aggregateFunction": { + "class": "uk.gov.gchq.koryphe.impl.binaryoperator.First" + } + }, + "age.integer": { + "class": "java.lang.Integer", + "aggregateFunction": { + "class": "uk.gov.gchq.koryphe.impl.binaryoperator.First" + } + }, + "weight.double": { + "class": "java.lang.Double", + "aggregateFunction": { + "class": "uk.gov.gchq.koryphe.impl.binaryoperator.First" + } + } + } +} From 0d7f7a7c7d802588621d866fe2cdfd4fa325806e Mon Sep 17 00:00:00 2001 From: cn337131 <141730190+cn337131@users.noreply.github.com> Date: Fri, 19 Jul 2024 14:25:10 +0000 Subject: [PATCH 10/16] Gh-3250: GetElementsWithinSet bug fix (#3251) * initial testing and changes * tidy up, remove bug test and copyright headers * fix commented out lines * additional federated tests * reduce duplicate tests * checkstyle * add inOutType * copyright * fix version variable * address comments --------- Co-authored-by: wb36499 <166839644+wb36499@users.noreply.github.com> --- .../src/main/resources/version.properties | 2 +- .../operation/impl/GetElementsWithinSet.java | 20 +- ...GetElementsWithinSetDeletedElementsIT.java | 4 +- .../GetElementsWithinSetHandlerTest.java | 181 ++++++++++-- .../impl/GetElementsWithinSetTest.java | 35 ++- ...ederatedStoreGetElementsWithinSetTest.java | 273 ++++++++++++++++++ 6 files changed, 467 insertions(+), 48 deletions(-) create mode 100644 store-implementation/federated-store/src/test/java/uk/gov/gchq/gaffer/federatedstore/FederatedStoreGetElementsWithinSetTest.java diff --git a/rest-api/common-rest/src/main/resources/version.properties b/rest-api/common-rest/src/main/resources/version.properties index e26645a4bc2..8cb4d96428b 100644 --- a/rest-api/common-rest/src/main/resources/version.properties +++ b/rest-api/common-rest/src/main/resources/version.properties @@ -13,5 +13,5 @@ # See the License for the specific language governing permissions and # limitations under the License. # -gaffer.version=2.2.5-SNAPSHOT +gaffer.version=${project.version} koryphe.version=${koryphe.version} diff --git a/store-implementation/accumulo-store/src/main/java/uk/gov/gchq/gaffer/accumulostore/operation/impl/GetElementsWithinSet.java b/store-implementation/accumulo-store/src/main/java/uk/gov/gchq/gaffer/accumulostore/operation/impl/GetElementsWithinSet.java index 3697c7b0ca6..8c18f284e56 100644 --- a/store-implementation/accumulo-store/src/main/java/uk/gov/gchq/gaffer/accumulostore/operation/impl/GetElementsWithinSet.java +++ b/store-implementation/accumulo-store/src/main/java/uk/gov/gchq/gaffer/accumulostore/operation/impl/GetElementsWithinSet.java @@ -1,5 +1,5 @@ /* - * Copyright 2016-2020 Crown Copyright + * Copyright 2016-2024 Crown Copyright * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -24,7 +24,7 @@ import uk.gov.gchq.gaffer.data.element.id.EntityId; import uk.gov.gchq.gaffer.data.elementdefinition.view.View; import uk.gov.gchq.gaffer.operation.Operation; -import uk.gov.gchq.gaffer.operation.graph.GraphFilters; +import uk.gov.gchq.gaffer.operation.graph.SeededGraphFilters; import uk.gov.gchq.gaffer.operation.io.InputOutput; import uk.gov.gchq.gaffer.operation.io.MultiEntityIdInput; import uk.gov.gchq.gaffer.operation.serialisation.TypeReferenceImpl; @@ -44,11 +44,12 @@ public class GetElementsWithinSet implements InputOutput, Iterable>, MultiEntityIdInput, - GraphFilters { + SeededGraphFilters { private View view; private DirectedType directedType; private Iterable input; private Map options; + private IncludeIncomingOutgoingType includeIncomingOutGoing; @Override public View getView() { @@ -95,10 +96,21 @@ public void setOptions(final Map options) { this.options = options; } + @Override + public IncludeIncomingOutgoingType getIncludeIncomingOutGoing() { + return includeIncomingOutGoing; + } + + @Override + public void setIncludeIncomingOutGoing(final IncludeIncomingOutgoingType inOutType) { + this.includeIncomingOutGoing = inOutType; + } + @Override public GetElementsWithinSet shallowClone() { return new GetElementsWithinSet.Builder() .view(view) + .inOutType(includeIncomingOutGoing) .directedType(directedType) .input(input) .options(options) @@ -108,7 +120,7 @@ public GetElementsWithinSet shallowClone() { public static class Builder extends Operation.BaseBuilder implements InputOutput.Builder, Iterable, Builder>, MultiEntityIdInput.Builder, - GraphFilters.Builder { + SeededGraphFilters.Builder { public Builder() { super(new GetElementsWithinSet()); } diff --git a/store-implementation/accumulo-store/src/test/java/uk/gov/gchq/gaffer/accumulostore/integration/delete/GetElementsWithinSetDeletedElementsIT.java b/store-implementation/accumulo-store/src/test/java/uk/gov/gchq/gaffer/accumulostore/integration/delete/GetElementsWithinSetDeletedElementsIT.java index 878ebfeacc4..24469883650 100644 --- a/store-implementation/accumulo-store/src/test/java/uk/gov/gchq/gaffer/accumulostore/integration/delete/GetElementsWithinSetDeletedElementsIT.java +++ b/store-implementation/accumulo-store/src/test/java/uk/gov/gchq/gaffer/accumulostore/integration/delete/GetElementsWithinSetDeletedElementsIT.java @@ -1,5 +1,5 @@ /* - * Copyright 2017-2020 Crown Copyright + * Copyright 2017-2024 Crown Copyright * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -18,6 +18,7 @@ import uk.gov.gchq.gaffer.accumulostore.operation.impl.GetElementsWithinSet; import uk.gov.gchq.gaffer.data.element.Element; +import uk.gov.gchq.gaffer.operation.graph.SeededGraphFilters.IncludeIncomingOutgoingType; public class GetElementsWithinSetDeletedElementsIT extends AbstractDeletedElementsIT> { @@ -25,6 +26,7 @@ public class GetElementsWithinSetDeletedElementsIT extends AbstractDeletedElemen protected GetElementsWithinSet createGetOperation() { return new GetElementsWithinSet.Builder() .input((Object[]) VERTICES) + .inOutType(IncludeIncomingOutgoingType.OUTGOING) .build(); } } diff --git a/store-implementation/accumulo-store/src/test/java/uk/gov/gchq/gaffer/accumulostore/operation/handler/GetElementsWithinSetHandlerTest.java b/store-implementation/accumulo-store/src/test/java/uk/gov/gchq/gaffer/accumulostore/operation/handler/GetElementsWithinSetHandlerTest.java index 7fb10bcf8df..387d539b6f6 100644 --- a/store-implementation/accumulo-store/src/test/java/uk/gov/gchq/gaffer/accumulostore/operation/handler/GetElementsWithinSetHandlerTest.java +++ b/store-implementation/accumulo-store/src/test/java/uk/gov/gchq/gaffer/accumulostore/operation/handler/GetElementsWithinSetHandlerTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2016-2021 Crown Copyright + * Copyright 2016-2024 Crown Copyright * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -39,6 +39,7 @@ import uk.gov.gchq.gaffer.data.elementdefinition.view.ViewElementDefinition; import uk.gov.gchq.gaffer.operation.OperationException; import uk.gov.gchq.gaffer.operation.data.EntitySeed; +import uk.gov.gchq.gaffer.operation.graph.SeededGraphFilters.IncludeIncomingOutgoingType; import uk.gov.gchq.gaffer.operation.impl.add.AddElements; import uk.gov.gchq.gaffer.store.Context; import uk.gov.gchq.gaffer.store.StoreException; @@ -69,18 +70,21 @@ public class GetElementsWithinSetHandlerTest { .source("A0") .dest("A23") .directed(true) + .matchedVertex(EdgeId.MatchedVertex.SOURCE) .build(); private static Edge expectedEdge2 = new Edge.Builder() .group(TestGroups.EDGE) .source("A0") .dest("A23") .directed(true) + .matchedVertex(EdgeId.MatchedVertex.SOURCE) .build(); private static Edge expectedEdge3 = new Edge.Builder() .group(TestGroups.EDGE) .source("A0") .dest("A23") .directed(true) + .matchedVertex(EdgeId.MatchedVertex.SOURCE) .build(); private static Entity expectedEntity1 = new Entity.Builder() .group(TestGroups.ENTITY) @@ -101,12 +105,14 @@ public class GetElementsWithinSetHandlerTest { .source("A0") .dest("A23") .directed(true) + .matchedVertex(EdgeId.MatchedVertex.SOURCE) .build(); private static Edge expectedSummarisedEdgePropertiesFiltered = new Edge.Builder() .group(TestGroups.EDGE) .source("A0") .dest("A23") .directed(true) + .matchedVertex(EdgeId.MatchedVertex.SOURCE) .property(AccumuloPropertyNames.COUNT, 23 * 3) .build(); @@ -160,12 +166,12 @@ public void reInitialise() throws StoreException, OperationException, TableExist } @Test - public void shouldReturnElementsNoSummarisationByteEntityStore() throws OperationException { + void shouldReturnElementsNoSummarisationByteEntityStore() throws OperationException { shouldReturnElementsNoSummarisation(BYTE_ENTITY_STORE); } @Test - public void shouldReturnElementsNoSummarisationGaffer1Store() throws OperationException { + void shouldReturnElementsNoSummarisationGaffer1Store() throws OperationException { shouldReturnElementsNoSummarisation(GAFFER_1_KEY_STORE); } @@ -187,7 +193,7 @@ private void shouldReturnElementsNoSummarisation(final AccumuloStore store) thro } @Test - public void shouldSummariseByteEntityStore() throws OperationException { + void shouldSummariseByteEntityStore() throws OperationException { final View view = new View.Builder(defaultView) .entity(TestGroups.ENTITY, new ViewElementDefinition.Builder() .groupBy() @@ -200,11 +206,11 @@ public void shouldSummariseByteEntityStore() throws OperationException { .build()) .build(); - runTest(BYTE_ENTITY_STORE, view, expectedSummarisedEdge, expectedEntity1, expectedEntity2); + runTest(BYTE_ENTITY_STORE, view, IncludeIncomingOutgoingType.OUTGOING, expectedSummarisedEdge, expectedEntity1, expectedEntity2); } @Test - public void shouldSummariseGaffer1Store() throws OperationException { + void shouldSummariseGaffer1Store() throws OperationException { final View view = new View.Builder(defaultView) .entity(TestGroups.ENTITY, new ViewElementDefinition.Builder() .groupBy() @@ -217,11 +223,11 @@ public void shouldSummariseGaffer1Store() throws OperationException { .build()) .build(); - runTest(GAFFER_1_KEY_STORE, view, expectedSummarisedEdge, expectedEntity1, expectedEntity2); + runTest(GAFFER_1_KEY_STORE, view, IncludeIncomingOutgoingType.OUTGOING, expectedSummarisedEdge, expectedEntity1, expectedEntity2); } @Test - public void shouldReturnOnlyEdgesWhenViewContainsNoEntitiesByteEntityStore() throws OperationException { + void shouldReturnOnlyEdgesWhenViewContainsNoEntitiesByteEntityStore() throws OperationException { final View view = new View.Builder() .edge(TestGroups.EDGE, new ViewElementDefinition.Builder() .groupBy() @@ -231,11 +237,11 @@ public void shouldReturnOnlyEdgesWhenViewContainsNoEntitiesByteEntityStore() thr .build()) .build(); - runTest(BYTE_ENTITY_STORE, view, expectedSummarisedEdge); + runTest(BYTE_ENTITY_STORE, view, IncludeIncomingOutgoingType.OUTGOING, expectedSummarisedEdge); } @Test - public void shouldReturnOnlyEdgesWhenViewContainsNoEntitiesGaffer1Store() throws OperationException { + void shouldReturnOnlyEdgesWhenViewContainsNoEntitiesGaffer1Store() throws OperationException { final View view = new View.Builder() .edge(TestGroups.EDGE, new ViewElementDefinition.Builder() .groupBy() @@ -245,11 +251,11 @@ public void shouldReturnOnlyEdgesWhenViewContainsNoEntitiesGaffer1Store() throws .build()) .build(); - runTest(GAFFER_1_KEY_STORE, view, expectedSummarisedEdge); + runTest(GAFFER_1_KEY_STORE, view, IncludeIncomingOutgoingType.OUTGOING, expectedSummarisedEdge); } @Test - public void shouldReturnOnlyEdgesWhenViewContainsNoEntitiesPropertiesFilteredByteEntityStore() throws OperationException { + void shouldReturnOnlyEdgesWhenViewContainsNoEntitiesPropertiesFilteredByteEntityStore() throws OperationException { final View view = new View.Builder() .edge(TestGroups.EDGE, new ViewElementDefinition.Builder() .properties(Collections.singleton(AccumuloPropertyNames.COUNT)) @@ -261,11 +267,11 @@ public void shouldReturnOnlyEdgesWhenViewContainsNoEntitiesPropertiesFilteredByt .build()) .build(); - runTest(BYTE_ENTITY_STORE, view, expectedSummarisedEdgePropertiesFiltered); + runTest(BYTE_ENTITY_STORE, view, IncludeIncomingOutgoingType.OUTGOING, expectedSummarisedEdgePropertiesFiltered); } @Test - public void shouldReturnOnlyEdgesWhenViewContainsNoEntitiesPropertiesFilteredGaffer1Store() throws OperationException { + void shouldReturnOnlyEdgesWhenViewContainsNoEntitiesPropertiesFilteredGaffer1Store() throws OperationException { final View view = new View.Builder() .edge(TestGroups.EDGE, new ViewElementDefinition.Builder() .properties(Collections.singleton(AccumuloPropertyNames.COUNT)) @@ -277,11 +283,11 @@ public void shouldReturnOnlyEdgesWhenViewContainsNoEntitiesPropertiesFilteredGaf .build()) .build(); - runTest(GAFFER_1_KEY_STORE, view, expectedSummarisedEdgePropertiesFiltered); + runTest(GAFFER_1_KEY_STORE, view, IncludeIncomingOutgoingType.OUTGOING, expectedSummarisedEdgePropertiesFiltered); } @Test - public void shouldReturnOnlyEdgesWhenViewContainsNoEntitiesPropertiesEmptySetByteEntityStore() throws OperationException { + void shouldReturnOnlyEdgesWhenViewContainsNoEntitiesPropertiesEmptySetByteEntityStore() throws OperationException { final View view = new View.Builder() .edge(TestGroups.EDGE, new ViewElementDefinition.Builder() .properties(Collections.emptySet()) @@ -293,11 +299,11 @@ public void shouldReturnOnlyEdgesWhenViewContainsNoEntitiesPropertiesEmptySetByt .build()) .build(); - runTest(BYTE_ENTITY_STORE, view, expectedSummarisedEdgePropertiesEmptySet); + runTest(BYTE_ENTITY_STORE, view, IncludeIncomingOutgoingType.OUTGOING, expectedSummarisedEdgePropertiesEmptySet); } @Test - public void shouldReturnOnlyEdgesWhenViewContainsNoEntitiesPropertiesEmptySetGaffer1Store() throws OperationException { + void shouldReturnOnlyEdgesWhenViewContainsNoEntitiesPropertiesEmptySetGaffer1Store() throws OperationException { final View view = new View.Builder() .edge(TestGroups.EDGE, new ViewElementDefinition.Builder() .properties(Collections.emptySet()) @@ -309,33 +315,152 @@ public void shouldReturnOnlyEdgesWhenViewContainsNoEntitiesPropertiesEmptySetGaf .build()) .build(); - runTest(GAFFER_1_KEY_STORE, view, expectedSummarisedEdgePropertiesEmptySet); + runTest(GAFFER_1_KEY_STORE, view, IncludeIncomingOutgoingType.OUTGOING, expectedSummarisedEdgePropertiesEmptySet); } @Test - public void shouldReturnOnlyEntitiesWhenViewContainsNoEdgesByteEntityStore() throws OperationException { + void shouldReturnOnlyEntitiesWhenViewContainsNoEdgesByteEntityStore() throws OperationException { final View view = new View.Builder() .entity(TestGroups.ENTITY, new ViewElementDefinition.Builder() .groupBy() .build()) .build(); - runTest(BYTE_ENTITY_STORE, view, expectedEntity1, expectedEntity2); + runTest(BYTE_ENTITY_STORE, view, IncludeIncomingOutgoingType.OUTGOING, expectedEntity1, expectedEntity2); } @Test - public void shouldReturnOnlyEntitiesWhenViewContainsNoEdgesGaffer1Store() throws OperationException { + void shouldReturnOnlyEntitiesWhenViewContainsNoEdgesGaffer1Store() throws OperationException { final View view = new View.Builder() .entity(TestGroups.ENTITY, new ViewElementDefinition.Builder() .groupBy() .build()) .build(); - runTest(GAFFER_1_KEY_STORE, view, expectedEntity1, expectedEntity2); + runTest(GAFFER_1_KEY_STORE, view, IncludeIncomingOutgoingType.OUTGOING, expectedEntity1, expectedEntity2); } - private void runTest(final AccumuloStore store, final View view, final Element... expectedElements) throws OperationException { + @Test + void shouldGetIncomingEdgesOnlyGaffer1Store() throws OperationException { + final View view = new View.Builder() + .edge(TestGroups.EDGE, new ViewElementDefinition.Builder() + .properties(Collections.emptySet()) + .groupBy() + .build()) + .build(); + + // Incoming edge should have matched vertex DESTINATION + final Edge expectedEdge = new Edge.Builder() + .group(TestGroups.EDGE) + .source("A0") + .dest("A23") + .directed(true) + .matchedVertex(EdgeId.MatchedVertex.DESTINATION) + .build(); + + runTest(GAFFER_1_KEY_STORE, view, IncludeIncomingOutgoingType.INCOMING, expectedEdge); + } + + @Test + void shouldGetIncomingEdgesOnlyByteEntityStore() throws OperationException { + final View view = new View.Builder() + .edge(TestGroups.EDGE, new ViewElementDefinition.Builder() + .properties(Collections.emptySet()) + .groupBy() + .build()) + .build(); + + // Incoming edge should have matched vertex DESTINATION + final Edge expectedEdge = new Edge.Builder() + .group(TestGroups.EDGE) + .source("A0") + .dest("A23") + .directed(true) + .matchedVertex(EdgeId.MatchedVertex.DESTINATION) + .build(); + + runTest(BYTE_ENTITY_STORE, view, IncludeIncomingOutgoingType.INCOMING, expectedEdge); + } + + @Test + void shouldGetEdgesWhenDestAndSourceAreInDifferentBatchesGaffer1Store() throws OperationException { + // Given + // Set batch scanner entries to 20 - so edge A99 -> A1 will have its src in the final batch but its + // dest in the first + GAFFER_1_KEY_STORE.getProperties().setMaxEntriesForBatchScanner("20"); + final Set seedSet = new HashSet<>(); + for (int i = 1; i < 100; i++) { + seedSet.add(new EntitySeed("A" + i)); + } + + // When + final GetElementsWithinSet op = new GetElementsWithinSet.Builder() + .view(new View.Builder() + .edge(TestGroups.EDGE, new ViewElementDefinition.Builder() + .properties(Collections.emptySet()) + .groupBy() + .build()) + .build()) + .input(seedSet) + .build(); + final GetElementsWithinSetHandler handler = new GetElementsWithinSetHandler(); + + final Iterable results = handler.doOperation(op, user, GAFFER_1_KEY_STORE); + + // Then + final Edge expectedEdge = new Edge.Builder() + .group(TestGroups.EDGE) + .source("A99") + .dest("A1") + .directed(true) + .build(); + + assertThat(results) + .asInstanceOf(InstanceOfAssertFactories.iterable(Element.class)) + .contains(expectedEdge); + } + + @Test + void shouldGetEdgesWhenDestAndSourceAreInDifferentBatchesByteEntityStore() throws OperationException { + // Given + // Set batch scanner entries to 20 - so edge A99 -> A1 will have its src in the final batch but its + // dest in the first + BYTE_ENTITY_STORE.getProperties().setMaxEntriesForBatchScanner("20"); + final Set seedSet = new HashSet<>(); + for (int i = 1; i < 100; i++) { + seedSet.add(new EntitySeed("A" + i)); + } + + // When + final GetElementsWithinSet op = new GetElementsWithinSet.Builder() + .view(new View.Builder() + .edge(TestGroups.EDGE, new ViewElementDefinition.Builder() + .properties(Collections.emptySet()) + .groupBy() + .build()) + .build()) + .input(seedSet) + .build(); + final GetElementsWithinSetHandler handler = new GetElementsWithinSetHandler(); + + final Iterable results = handler.doOperation(op, user, GAFFER_1_KEY_STORE); + + // Then + final Edge expectedEdge = new Edge.Builder() + .group(TestGroups.EDGE) + .source("A99") + .dest("A1") + .directed(true) + .build(); + + assertThat(results) + .asInstanceOf(InstanceOfAssertFactories.iterable(Element.class)) + .contains(expectedEdge); + } + + private void runTest(final AccumuloStore store, final View view, final IncludeIncomingOutgoingType type, final Element... expectedElements) throws OperationException { final GetElementsWithinSet operation = new GetElementsWithinSet.Builder().view(view).input(seeds).build(); + operation.setIncludeIncomingOutGoing(type); final GetElementsWithinSetHandler handler = new GetElementsWithinSetHandler(); final Iterable elements = handler.doOperation(operation, user, store); @@ -398,6 +523,14 @@ private static void setupGraph(final AccumuloStore store) throws OperationExcept .property(AccumuloPropertyNames.PROP_4, 0) .build()); + data.add(new Edge.Builder() + .group(TestGroups.EDGE) + .source("A99") + .dest("A1") + .directed(true) + .property(AccumuloPropertyNames.COLUMN_QUALIFIER, 1) + .build()); + data.add(new Entity.Builder() .group(TestGroups.ENTITY) .vertex("A" + i) diff --git a/store-implementation/accumulo-store/src/test/java/uk/gov/gchq/gaffer/accumulostore/operation/impl/GetElementsWithinSetTest.java b/store-implementation/accumulo-store/src/test/java/uk/gov/gchq/gaffer/accumulostore/operation/impl/GetElementsWithinSetTest.java index bfe11a36df4..2e130cfa29d 100644 --- a/store-implementation/accumulo-store/src/test/java/uk/gov/gchq/gaffer/accumulostore/operation/impl/GetElementsWithinSetTest.java +++ b/store-implementation/accumulo-store/src/test/java/uk/gov/gchq/gaffer/accumulostore/operation/impl/GetElementsWithinSetTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2016-2021 Crown Copyright + * Copyright 2016-2024 Crown Copyright * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -25,18 +25,16 @@ import uk.gov.gchq.gaffer.exception.SerialisationException; import uk.gov.gchq.gaffer.jsonserialisation.JSONSerialiser; import uk.gov.gchq.gaffer.operation.OperationTest; +import uk.gov.gchq.gaffer.operation.graph.SeededGraphFilters; import java.util.Iterator; import static org.assertj.core.api.Assertions.assertThat; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertNotNull; -import static org.junit.jupiter.api.Assertions.assertNotSame; -public class GetElementsWithinSetTest extends OperationTest { +class GetElementsWithinSetTest extends OperationTest { @Test - public void shouldJSONSerialiseAndDeserialise() throws SerialisationException { + void shouldJSONSerialiseAndDeserialise() throws SerialisationException { // Given final GetElementsWithinSet op = new GetElementsWithinSet.Builder() .input(AccumuloTestData.SEED_SOURCE_1, @@ -65,15 +63,18 @@ public void builderShouldCreatePopulatedOperation() { final GetElementsWithinSet getElementsWithinSet = new GetElementsWithinSet.Builder() .input(AccumuloTestData.SEED_A) .directedType(DirectedType.DIRECTED) + .inOutType(SeededGraphFilters.IncludeIncomingOutgoingType.INCOMING) .option(AccumuloTestData.TEST_OPTION_PROPERTY_KEY, "true") .view(new View.Builder() .edge("testEdgegroup") .build()) .build(); - assertEquals("true", getElementsWithinSet.getOption(AccumuloTestData.TEST_OPTION_PROPERTY_KEY)); - assertEquals(DirectedType.DIRECTED, getElementsWithinSet.getDirectedType()); + + assertThat(getElementsWithinSet.getOption(AccumuloTestData.TEST_OPTION_PROPERTY_KEY)).isEqualTo("true"); + assertThat(getElementsWithinSet.getDirectedType()).isEqualTo(DirectedType.DIRECTED); + assertThat(getElementsWithinSet.getIncludeIncomingOutGoing()).isEqualTo(SeededGraphFilters.IncludeIncomingOutgoingType.INCOMING); assertThat(getElementsWithinSet.getInput().iterator().next()).isEqualTo(AccumuloTestData.SEED_A); - assertNotNull(getElementsWithinSet.getView()); + assertThat(getElementsWithinSet.getView()).isNotNull(); } @Test @@ -86,6 +87,7 @@ public void shouldShallowCloneOperation() { final GetElementsWithinSet getElementsWithinSet = new GetElementsWithinSet.Builder() .input(AccumuloTestData.SEED_A) .directedType(DirectedType.DIRECTED) + .inOutType(SeededGraphFilters.IncludeIncomingOutgoingType.INCOMING) .option(AccumuloTestData.TEST_OPTION_PROPERTY_KEY, "true") .view(view) .build(); @@ -94,25 +96,22 @@ public void shouldShallowCloneOperation() { final GetElementsWithinSet clone = getElementsWithinSet.shallowClone(); // Then - assertNotSame(getElementsWithinSet, clone); - assertEquals("true", clone.getOption(AccumuloTestData.TEST_OPTION_PROPERTY_KEY)); - assertEquals(DirectedType.DIRECTED, clone.getDirectedType()); + assertThat(clone).isNotSameAs(getElementsWithinSet); + assertThat(clone.getOption(AccumuloTestData.TEST_OPTION_PROPERTY_KEY)).isEqualTo("true"); + assertThat(clone.getIncludeIncomingOutGoing()).isEqualTo(SeededGraphFilters.IncludeIncomingOutgoingType.INCOMING); assertThat(clone.getInput().iterator().next()).isEqualTo(AccumuloTestData.SEED_A); - assertEquals(view, clone.getView()); + assertThat(clone.getView()).isEqualTo(view); } @Test - public void shouldCreateInputFromVertices() { + void shouldCreateInputFromVertices() { // When final GetElementsWithinSet op = new GetElementsWithinSet.Builder() .input(AccumuloTestData.SEED_B, AccumuloTestData.SEED_B1.getVertex()) .build(); // Then - assertEquals( - Lists.newArrayList(AccumuloTestData.SEED_B, AccumuloTestData.SEED_B1), - Lists.newArrayList(op.getInput()) - ); + assertThat(Lists.newArrayList(op.getInput())).isEqualTo(Lists.newArrayList(AccumuloTestData.SEED_B, AccumuloTestData.SEED_B1)); } @Override diff --git a/store-implementation/federated-store/src/test/java/uk/gov/gchq/gaffer/federatedstore/FederatedStoreGetElementsWithinSetTest.java b/store-implementation/federated-store/src/test/java/uk/gov/gchq/gaffer/federatedstore/FederatedStoreGetElementsWithinSetTest.java new file mode 100644 index 00000000000..f0ec586b3db --- /dev/null +++ b/store-implementation/federated-store/src/test/java/uk/gov/gchq/gaffer/federatedstore/FederatedStoreGetElementsWithinSetTest.java @@ -0,0 +1,273 @@ +/* + * Copyright 2024 Crown Copyright + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package uk.gov.gchq.gaffer.federatedstore; + +import org.assertj.core.api.InstanceOfAssertFactories; +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import uk.gov.gchq.gaffer.accumulostore.AccumuloProperties; +import uk.gov.gchq.gaffer.accumulostore.operation.impl.GetElementsWithinSet; +import uk.gov.gchq.gaffer.commonutil.StreamUtil; +import uk.gov.gchq.gaffer.data.element.Edge; +import uk.gov.gchq.gaffer.data.element.Element; +import uk.gov.gchq.gaffer.data.element.Entity; +import uk.gov.gchq.gaffer.data.element.id.EntityId; +import uk.gov.gchq.gaffer.data.elementdefinition.view.View; +import uk.gov.gchq.gaffer.federatedstore.operation.AddGraph; +import uk.gov.gchq.gaffer.federatedstore.operation.FederatedOperation; +import uk.gov.gchq.gaffer.graph.Graph; +import uk.gov.gchq.gaffer.graph.GraphConfig; +import uk.gov.gchq.gaffer.operation.OperationException; +import uk.gov.gchq.gaffer.operation.data.EntitySeed; +import uk.gov.gchq.gaffer.operation.impl.add.AddElements; +import uk.gov.gchq.gaffer.store.schema.Schema; +import uk.gov.gchq.gaffer.store.schema.SchemaEdgeDefinition; +import uk.gov.gchq.gaffer.store.schema.SchemaEntityDefinition; +import uk.gov.gchq.gaffer.user.User; + +import static org.assertj.core.api.Assertions.assertThat; +import static uk.gov.gchq.gaffer.commonutil.TestPropertyNames.STRING; +import static uk.gov.gchq.gaffer.federatedstore.FederatedStoreTestUtil.GRAPH_ID_A; +import static uk.gov.gchq.gaffer.federatedstore.FederatedStoreTestUtil.GRAPH_ID_B; +import static uk.gov.gchq.gaffer.federatedstore.FederatedStoreTestUtil.GRAPH_ID_TEST_FEDERATED_STORE; +import static uk.gov.gchq.gaffer.federatedstore.FederatedStoreTestUtil.GROUP_BASIC_EDGE; +import static uk.gov.gchq.gaffer.federatedstore.FederatedStoreTestUtil.GROUP_BASIC_ENTITY; +import static uk.gov.gchq.gaffer.federatedstore.FederatedStoreTestUtil.getFederatedStorePropertiesWithHashMapCache; +import static uk.gov.gchq.gaffer.federatedstore.FederatedStoreTestUtil.resetForFederatedTests; +import static uk.gov.gchq.gaffer.store.TestTypes.BOOLEAN_TYPE; +import static uk.gov.gchq.gaffer.store.TestTypes.DIRECTED_EITHER; +import static uk.gov.gchq.gaffer.store.TestTypes.STRING_TYPE; + +import java.util.HashSet; +import java.util.LinkedHashSet; +import java.util.Set; + +class FederatedStoreGetElementsWithinSetTest { + private static final AccumuloProperties ACCUMULO_PROPERTIES = AccumuloProperties.loadStoreProperties(StreamUtil.openStream(FederatedStoreGetElementsWithinSetTest.class, "properties/singleUseAccumuloStore.properties")); + private static final User USER = new User(); + private static final Set SEEDS = new LinkedHashSet<>(); + private static final String GRAPH_IDS = String.format("%s,%s", GRAPH_ID_A, GRAPH_ID_B); + private static final View EDGE_VIEW = new View.Builder().edge(GROUP_BASIC_EDGE).build(); + private static final View ENTITY_VIEW = new View.Builder().entity(GROUP_BASIC_ENTITY).build(); + + private Graph federatedGraph; + + @AfterAll + static void tearDownCache() { + resetForFederatedTests(); + } + + @BeforeEach + void setUp() throws Exception { + resetForFederatedTests(); + FederatedStoreProperties federatedStoreProperties = getFederatedStorePropertiesWithHashMapCache(); + for (int i = 0; i < 300; i++) { + SEEDS.add(new EntitySeed("A" + i)); + } + + federatedGraph = new Graph.Builder() + .config(new GraphConfig.Builder() + .graphId(GRAPH_ID_TEST_FEDERATED_STORE) + .build()) + .addStoreProperties(federatedStoreProperties) + .build(); + + federatedGraph.execute(new AddGraph.Builder() + .graphId(GRAPH_ID_A) + .storeProperties(ACCUMULO_PROPERTIES) + .schema(getSchema()) + .build(), USER); + + federatedGraph.execute(new AddGraph.Builder() + .graphId(GRAPH_ID_B) + .storeProperties(ACCUMULO_PROPERTIES) + .schema(getSchema()) + .build(), USER); + + for (int i = 300; i >= 0; i--) { + addEntities("A" + i, GRAPH_ID_A); + addEntities("A" + i, GRAPH_ID_B); + } + + // Add 6 edges total - should all have src and dest in different batches + addEdges("A244", "A87", GRAPH_ID_A); + addEdges("A168", "A110", GRAPH_ID_A); + addEdges("A56", "A299", GRAPH_ID_A); + addEdges("A297", "A193", GRAPH_ID_B); + addEdges("A15", "A285", GRAPH_ID_B); + addEdges("A1", "A52", GRAPH_ID_B); + } + + @Test + void shouldReturnOnlyEdgesWhenViewContainsNoEntities() throws Exception { + // Given/When + final Iterable results = (Iterable) federatedGraph.execute(new FederatedOperation.Builder() + .op(new GetElementsWithinSet.Builder() + .view(EDGE_VIEW) + .input(SEEDS) + .build()) + .graphIdsCSV(GRAPH_IDS) + .build(), USER); + + // Then + assertThat(results) + .asInstanceOf(InstanceOfAssertFactories.iterable(Element.class)) + .containsAll(getExpectedEdges()); + } + + @Test + void shouldReturnOnlyEntitiesWhenViewContainsNoEdges() throws Exception { + // Given/When + final Iterable results = (Iterable) federatedGraph.execute(new FederatedOperation.Builder() + .op(new GetElementsWithinSet.Builder() + .view(ENTITY_VIEW) + .input(SEEDS) + .build()) + .graphIdsCSV(GRAPH_IDS) + .build(), USER); + + // Then + assertThat(results).hasSize(600); + assertThat(results).extracting(r -> r.getGroup()).contains(GROUP_BASIC_ENTITY); + } + + @Test + void shouldGetAllEdgesWithSmallerBatchSizeInAFederatedOperation() throws Exception { + // Given + // Set batch scanner entries to 50 - so some edges will have its src in the final batch but its + // dest in the first - should all still be retrieved + ACCUMULO_PROPERTIES.setMaxEntriesForBatchScanner("50"); + + // When + final Iterable results = (Iterable) federatedGraph.execute(new FederatedOperation.Builder() + .op(new GetElementsWithinSet.Builder() + .view(EDGE_VIEW) + .input(SEEDS) + .build()) + .graphIdsCSV(GRAPH_IDS) + .build(), USER); + + // Then + assertThat(results) + .asInstanceOf(InstanceOfAssertFactories.iterable(Element.class)) + .containsAll(getExpectedEdges()); + } + + @Test + void shouldGetAllEdgesWithSmallerBatchSizeStandardOperation() throws Exception { + // Given + // Set batch scanner entries to 50 - so some edges will have its src in the final batch but its + // dest in the first - should all still be retrieved + ACCUMULO_PROPERTIES.setMaxEntriesForBatchScanner("50"); + + // When + final GetElementsWithinSet op = new GetElementsWithinSet.Builder() + .view(EDGE_VIEW) + .input(SEEDS) + .build(); + final Iterable results = federatedGraph.execute(op, USER); + + // Then + assertThat(results) + .asInstanceOf(InstanceOfAssertFactories.iterable(Element.class)) + .containsAll(getExpectedEdges()); + } + + private void addEntities(final String source, final String graphId) throws OperationException { + federatedGraph.execute(new FederatedOperation.Builder() + .op(new AddElements.Builder() + .input(new Entity.Builder() + .group(GROUP_BASIC_ENTITY) + .vertex(source) + .build()) + .build()) + .graphIdsCSV(graphId) + .build(), USER); + } + + private void addEdges(final String source, final String dest, final String graphId) throws OperationException { + federatedGraph.execute(new FederatedOperation.Builder() + .op(new AddElements.Builder() + .input(new Edge.Builder() + .group(GROUP_BASIC_EDGE) + .source(source) + .dest(dest) + .directed(true) + .build()) + .build()) + .graphIdsCSV(graphId) + .build(), USER); + } + + private Set getExpectedEdges() { + final Set expectedEdges = new HashSet<>(); + expectedEdges.add(new Edge.Builder() + .group(GROUP_BASIC_EDGE) + .source("A244") + .dest("A87") + .directed(true) + .build()); + expectedEdges.add(new Edge.Builder() + .group(GROUP_BASIC_EDGE) + .source("A168") + .dest("A110") + .directed(true) + .build()); + expectedEdges.add(new Edge.Builder() + .group(GROUP_BASIC_EDGE) + .source("A56") + .dest("A299") + .directed(true) + .build()); + expectedEdges.add(new Edge.Builder() + .group(GROUP_BASIC_EDGE) + .source("A297") + .dest("A193") + .directed(true) + .build()); + expectedEdges.add(new Edge.Builder() + .group(GROUP_BASIC_EDGE) + .source("A15") + .dest("A285") + .directed(true) + .build()); + expectedEdges.add(new Edge.Builder() + .group(GROUP_BASIC_EDGE) + .source("A1") + .dest("A52") + .directed(true) + .build()); + return expectedEdges; + } + + private Schema getSchema() { + return new Schema.Builder() + .entity(GROUP_BASIC_ENTITY, new SchemaEntityDefinition.Builder() + .vertex(STRING) + .build()) + .edge(GROUP_BASIC_EDGE, new SchemaEdgeDefinition.Builder() + .source(STRING) + .destination(STRING) + .directed(DIRECTED_EITHER) + .build()) + .type(STRING, STRING_TYPE) + .type(DIRECTED_EITHER, BOOLEAN_TYPE) + .build(); + } +} From f4d373895b8344f4ace6d6f559c610f903787320 Mon Sep 17 00:00:00 2001 From: tb06904 <141412860+tb06904@users.noreply.github.com> Date: Fri, 26 Jul 2024 09:42:47 +0000 Subject: [PATCH 11/16] Gh-3253 Fix custom types in gremlin (#3255) * add conversions so gafferpop edges and vertexes are graphson compliant * update testing * update testing * javadoc * make sure cypher types can be used correctly * typo --- library/tinkerpop/pom.xml | 2 - .../gchq/gaffer/tinkerpop/GafferPopGraph.java | 49 +++--- .../generator/GafferEdgeGenerator.java | 27 ++-- .../generator/GafferEntityGenerator.java | 10 +- .../generator/GafferPopEdgeGenerator.java | 22 +-- .../generator/GafferPopVertexGenerator.java | 20 ++- .../step/util/GafferPopHasContainer.java | 5 +- .../util/GafferCustomTypeFactory.java | 149 ++++++++++++++++++ .../util/GafferPredicateFactory.java | 7 +- .../util/TypeSubTypeValueFactory.java | 66 -------- .../gaffer/tinkerpop/GafferPopGraphTest.java | 3 +- .../GafferPopElementGeneratorTest.java | 17 +- .../traversal/step/GafferPopGraphStepIT.java | 15 +- .../traversal/step/GafferPopHasStepIT.java | 12 +- .../util/GafferCustomTypeFactoryTest.java | 108 +++++++++++++ .../util/TypeSubTypeValueFactoryTest.java | 66 -------- .../util/GafferPopTstvTestUtils.java | 15 +- pom.xml | 2 + rest-api/spring-rest/pom.xml | 5 + .../rest/controller/GremlinController.java | 12 +- .../rest/handler/GremlinWebSocketHandler.java | 6 + .../controller/GremlinControllerTest.java | 35 ++++ .../handler/GremlinWebSocketIT.java | 18 +++ 23 files changed, 449 insertions(+), 222 deletions(-) create mode 100644 library/tinkerpop/src/main/java/uk/gov/gchq/gaffer/tinkerpop/process/traversal/util/GafferCustomTypeFactory.java delete mode 100644 library/tinkerpop/src/main/java/uk/gov/gchq/gaffer/tinkerpop/process/traversal/util/TypeSubTypeValueFactory.java create mode 100644 library/tinkerpop/src/test/java/uk/gov/gchq/gaffer/tinkerpop/process/traversal/util/GafferCustomTypeFactoryTest.java delete mode 100644 library/tinkerpop/src/test/java/uk/gov/gchq/gaffer/tinkerpop/process/traversal/util/TypeSubTypeValueFactoryTest.java diff --git a/library/tinkerpop/pom.xml b/library/tinkerpop/pom.xml index 7612fc4c477..645ec6d4963 100644 --- a/library/tinkerpop/pom.xml +++ b/library/tinkerpop/pom.xml @@ -28,8 +28,6 @@ 4.2.3 7.15.0 - - 1.0.0 !GafferPopGraphStructureStandardTest,!GafferPopFeatureTest,!GafferPopGraphProcessStandardTest diff --git a/library/tinkerpop/src/main/java/uk/gov/gchq/gaffer/tinkerpop/GafferPopGraph.java b/library/tinkerpop/src/main/java/uk/gov/gchq/gaffer/tinkerpop/GafferPopGraph.java index 42f55e88f25..89d4af3397d 100755 --- a/library/tinkerpop/src/main/java/uk/gov/gchq/gaffer/tinkerpop/GafferPopGraph.java +++ b/library/tinkerpop/src/main/java/uk/gov/gchq/gaffer/tinkerpop/GafferPopGraph.java @@ -57,7 +57,7 @@ import uk.gov.gchq.gaffer.tinkerpop.generator.GafferPopElementGenerator; import uk.gov.gchq.gaffer.tinkerpop.process.traversal.strategy.optimisation.GafferPopGraphStepStrategy; import uk.gov.gchq.gaffer.tinkerpop.process.traversal.strategy.optimisation.GafferPopHasStepStrategy; -import uk.gov.gchq.gaffer.tinkerpop.process.traversal.util.TypeSubTypeValueFactory; +import uk.gov.gchq.gaffer.tinkerpop.process.traversal.util.GafferCustomTypeFactory; import uk.gov.gchq.gaffer.tinkerpop.service.GafferPopNamedOperationServiceFactory; import uk.gov.gchq.gaffer.user.User; import uk.gov.gchq.koryphe.iterable.MappedIterable; @@ -728,6 +728,32 @@ public T execute(final OperationChain opChain) { } } + /** + * Sets the {@link GafferPopGraphVariables} to default values for this + * graph + * + * @param variables The variables + */ + public void setDefaultVariables(final GafferPopGraphVariables variables) { + LOGGER.debug("Resetting graph variables to defaults"); + variables.set(GafferPopGraphVariables.OP_OPTIONS, Collections.unmodifiableMap(opOptions)); + variables.set(GafferPopGraphVariables.USER, defaultUser); + variables.set(GafferPopGraphVariables.GET_ALL_ELEMENTS_LIMIT, + configuration().getInteger(GET_ALL_ELEMENTS_LIMIT, DEFAULT_GET_ALL_ELEMENTS_LIMIT)); + variables.set(GafferPopGraphVariables.HAS_STEP_FILTER_STAGE, + configuration().getString(HAS_STEP_FILTER_STAGE, DEFAULT_HAS_STEP_FILTER_STAGE.toString())); + variables.set(GafferPopGraphVariables.LAST_OPERATION_CHAIN, new OperationChain()); + } + + /** + * Get the underlying Gaffer graph this GafferPop graph is connected to. + * + * @return The Gaffer Graph. + */ + public Graph getGafferGraph() { + return graph; + } + private Iterator verticesWithSeedsAndView(final List seeds, final View view) { final boolean getAll = null == seeds || seeds.isEmpty(); final LinkedList idVertices = new LinkedList<>(); @@ -933,9 +959,9 @@ private List getElementSeeds(final Iterable ids) { // Check if contains label in edge ID if (edgeIDMatcher.matches()) { seeds.add(new EdgeSeed(edgeIDMatcher.group("src"), edgeIDMatcher.group("dest"))); + // If not then check if a custom type e.g. TSTV } else { - // If not then check if a TSTV ID - seeds.add(new EntitySeed(TypeSubTypeValueFactory.parseAsTstvIfValid(id))); + seeds.add(new EntitySeed(GafferCustomTypeFactory.parseAsCustomTypeIfValid(id))); } // Assume entity ID as a fallback } else { @@ -988,23 +1014,6 @@ private IncludeIncomingOutgoingType getInOutType(final Direction direction) { return inOutType; } - /** - * Sets the {@link GafferPopGraphVariables} to default values for this - * graph - * - * @param variables The variables - */ - public void setDefaultVariables(final GafferPopGraphVariables variables) { - LOGGER.info("Resetting graph variables to defaults"); - variables.set(GafferPopGraphVariables.OP_OPTIONS, Collections.unmodifiableMap(opOptions)); - variables.set(GafferPopGraphVariables.USER, defaultUser); - variables.set(GafferPopGraphVariables.GET_ALL_ELEMENTS_LIMIT, - configuration().getInteger(GET_ALL_ELEMENTS_LIMIT, DEFAULT_GET_ALL_ELEMENTS_LIMIT)); - variables.set(GafferPopGraphVariables.HAS_STEP_FILTER_STAGE, - configuration().getString(HAS_STEP_FILTER_STAGE, DEFAULT_HAS_STEP_FILTER_STAGE.toString())); - variables.set(GafferPopGraphVariables.LAST_OPERATION_CHAIN, new OperationChain()); - } - /** * Gets the next ID to assign to a supplied vertex based on the currently configured ID manager. * diff --git a/library/tinkerpop/src/main/java/uk/gov/gchq/gaffer/tinkerpop/generator/GafferEdgeGenerator.java b/library/tinkerpop/src/main/java/uk/gov/gchq/gaffer/tinkerpop/generator/GafferEdgeGenerator.java index 4ed6f1bfece..640ffb54f9a 100644 --- a/library/tinkerpop/src/main/java/uk/gov/gchq/gaffer/tinkerpop/generator/GafferEdgeGenerator.java +++ b/library/tinkerpop/src/main/java/uk/gov/gchq/gaffer/tinkerpop/generator/GafferEdgeGenerator.java @@ -1,5 +1,5 @@ /* - * Copyright 2016-2023 Crown Copyright + * Copyright 2016-2024 Crown Copyright * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,26 +16,27 @@ package uk.gov.gchq.gaffer.tinkerpop.generator; -import org.apache.tinkerpop.gremlin.structure.Property; - import uk.gov.gchq.gaffer.data.element.Edge; import uk.gov.gchq.gaffer.data.generator.OneToOneElementGenerator; import uk.gov.gchq.gaffer.tinkerpop.GafferPopEdge; - -import java.util.Iterator; +import uk.gov.gchq.gaffer.tinkerpop.process.traversal.util.GafferCustomTypeFactory; public class GafferEdgeGenerator implements OneToOneElementGenerator { @Override public Edge _apply(final GafferPopEdge gafferPopEdge) { - final Edge edge = new Edge(gafferPopEdge.label(), gafferPopEdge.outVertex().id(), - gafferPopEdge.inVertex().id(), true); - final Iterator> propItr = gafferPopEdge.properties(); - while (propItr.hasNext()) { - final Property prop = propItr.next(); - if (null != prop.key()) { - edge.putProperty(prop.key(), prop.value()); + // Add edge + final Edge edge = new Edge( + gafferPopEdge.label(), + GafferCustomTypeFactory.parseAsCustomTypeIfValid(gafferPopEdge.outVertex().id()), + GafferCustomTypeFactory.parseAsCustomTypeIfValid(gafferPopEdge.inVertex().id()), + true); + + // Add properties + gafferPopEdge.properties().forEachRemaining(prop -> { + if (prop.key() != null) { + edge.putProperty(prop.key(), GafferCustomTypeFactory.parseAsCustomTypeIfValid(prop.value())); } - } + }); return edge; } } diff --git a/library/tinkerpop/src/main/java/uk/gov/gchq/gaffer/tinkerpop/generator/GafferEntityGenerator.java b/library/tinkerpop/src/main/java/uk/gov/gchq/gaffer/tinkerpop/generator/GafferEntityGenerator.java index 550bd60f9d6..b574770744f 100644 --- a/library/tinkerpop/src/main/java/uk/gov/gchq/gaffer/tinkerpop/generator/GafferEntityGenerator.java +++ b/library/tinkerpop/src/main/java/uk/gov/gchq/gaffer/tinkerpop/generator/GafferEntityGenerator.java @@ -1,5 +1,5 @@ /* - * Copyright 2016-2023 Crown Copyright + * Copyright 2016-2024 Crown Copyright * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -19,6 +19,7 @@ import uk.gov.gchq.gaffer.data.element.Entity; import uk.gov.gchq.gaffer.data.generator.OneToOneElementGenerator; import uk.gov.gchq.gaffer.tinkerpop.GafferPopVertex; +import uk.gov.gchq.gaffer.tinkerpop.process.traversal.util.GafferCustomTypeFactory; public class GafferEntityGenerator implements OneToOneElementGenerator { @Override @@ -27,12 +28,13 @@ public Entity _apply(final GafferPopVertex vertex) { throw new IllegalArgumentException("Unable to convert a null GafferPopVertex Object"); } - final Entity entity = new Entity(vertex.label(), vertex.id()); + final Entity entity = new Entity(vertex.label(), GafferCustomTypeFactory.parseAsCustomTypeIfValid(vertex.id())); // Tinkerpop allows nested properties under a key for Gaffer we need to flatten these so only one property per key vertex.properties().forEachRemaining(vertProp -> { - entity.putProperty(vertProp.key(), vertProp.value()); - vertProp.properties().forEachRemaining(prop -> entity.putProperty(prop.key(), prop.value())); + entity.putProperty(vertProp.key(), GafferCustomTypeFactory.parseAsCustomTypeIfValid(vertProp.value())); + vertProp.properties().forEachRemaining( + prop -> entity.putProperty(prop.key(), GafferCustomTypeFactory.parseAsCustomTypeIfValid(prop.value()))); }); return entity; diff --git a/library/tinkerpop/src/main/java/uk/gov/gchq/gaffer/tinkerpop/generator/GafferPopEdgeGenerator.java b/library/tinkerpop/src/main/java/uk/gov/gchq/gaffer/tinkerpop/generator/GafferPopEdgeGenerator.java index efc798ae581..4ca1840fde0 100644 --- a/library/tinkerpop/src/main/java/uk/gov/gchq/gaffer/tinkerpop/generator/GafferPopEdgeGenerator.java +++ b/library/tinkerpop/src/main/java/uk/gov/gchq/gaffer/tinkerpop/generator/GafferPopEdgeGenerator.java @@ -1,5 +1,5 @@ /* - * Copyright 2016-2023 Crown Copyright + * Copyright 2016-2024 Crown Copyright * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -24,8 +24,7 @@ import uk.gov.gchq.gaffer.data.generator.OneToOneObjectGenerator; import uk.gov.gchq.gaffer.tinkerpop.GafferPopEdge; import uk.gov.gchq.gaffer.tinkerpop.GafferPopGraph; - -import java.util.Map.Entry; +import uk.gov.gchq.gaffer.tinkerpop.process.traversal.util.GafferCustomTypeFactory; public class GafferPopEdgeGenerator implements OneToOneObjectGenerator { private final GafferPopGraph graph; @@ -48,14 +47,19 @@ public GafferPopEdge _apply(final Element element) { } final Edge edge = ((Edge) element); - final GafferPopEdge gafferPopEdge = new GafferPopEdge(edge.getGroup(), - edge.getSource(), edge.getDestination(), graph); + final GafferPopEdge gafferPopEdge = new GafferPopEdge( + edge.getGroup(), + GafferCustomTypeFactory.parseForGraphSONv3(edge.getSource()), + GafferCustomTypeFactory.parseForGraphSONv3(edge.getDestination()), + graph); - for (final Entry entry : edge.getProperties().entrySet()) { - if (null != entry.getValue()) { - gafferPopEdge.propertyWithoutUpdate(entry.getKey(), entry.getValue()); + // Add the properties + edge.getProperties().forEach((k, v) -> { + if (v != null) { + gafferPopEdge.propertyWithoutUpdate(k, GafferCustomTypeFactory.parseForGraphSONv3(v)); } - } + }); + if (gafferPopReadOnly) { gafferPopEdge.setReadOnly(); } diff --git a/library/tinkerpop/src/main/java/uk/gov/gchq/gaffer/tinkerpop/generator/GafferPopVertexGenerator.java b/library/tinkerpop/src/main/java/uk/gov/gchq/gaffer/tinkerpop/generator/GafferPopVertexGenerator.java index 18ad7aed0d2..33b5e42c6d3 100644 --- a/library/tinkerpop/src/main/java/uk/gov/gchq/gaffer/tinkerpop/generator/GafferPopVertexGenerator.java +++ b/library/tinkerpop/src/main/java/uk/gov/gchq/gaffer/tinkerpop/generator/GafferPopVertexGenerator.java @@ -1,5 +1,5 @@ /* - * Copyright 2016-2023 Crown Copyright + * Copyright 2016-2024 Crown Copyright * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -25,8 +25,8 @@ import uk.gov.gchq.gaffer.data.generator.OneToOneObjectGenerator; import uk.gov.gchq.gaffer.tinkerpop.GafferPopGraph; import uk.gov.gchq.gaffer.tinkerpop.GafferPopVertex; +import uk.gov.gchq.gaffer.tinkerpop.process.traversal.util.GafferCustomTypeFactory; -import java.util.Map.Entry; public class GafferPopVertexGenerator implements OneToOneObjectGenerator { private final GafferPopGraph graph; @@ -49,12 +49,18 @@ public GafferPopVertex _apply(final Element element) { } final Entity entity = ((Entity) element); - final GafferPopVertex vertex = new GafferPopVertex(entity.getGroup(), entity.getVertex(), graph); - for (final Entry entry : entity.getProperties().entrySet()) { - if (null != entry.getValue()) { - vertex.propertyWithoutUpdate(Cardinality.list, entry.getKey(), entry.getValue()); + final GafferPopVertex vertex = new GafferPopVertex( + entity.getGroup(), + GafferCustomTypeFactory.parseForGraphSONv3(entity.getVertex()), + graph); + + // Add the properties + entity.getProperties().forEach((k, v) -> { + if (v != null) { + vertex.propertyWithoutUpdate(Cardinality.list, k, GafferCustomTypeFactory.parseForGraphSONv3(v)); } - } + }); + if (gafferPopReadOnly) { vertex.setReadOnly(); } diff --git a/library/tinkerpop/src/main/java/uk/gov/gchq/gaffer/tinkerpop/process/traversal/step/util/GafferPopHasContainer.java b/library/tinkerpop/src/main/java/uk/gov/gchq/gaffer/tinkerpop/process/traversal/step/util/GafferPopHasContainer.java index 2d2c088b95b..1b98260cc5e 100644 --- a/library/tinkerpop/src/main/java/uk/gov/gchq/gaffer/tinkerpop/process/traversal/step/util/GafferPopHasContainer.java +++ b/library/tinkerpop/src/main/java/uk/gov/gchq/gaffer/tinkerpop/process/traversal/step/util/GafferPopHasContainer.java @@ -20,6 +20,7 @@ import org.apache.tinkerpop.gremlin.structure.Element; import org.apache.tinkerpop.gremlin.structure.Property; +import uk.gov.gchq.gaffer.tinkerpop.process.traversal.util.GafferCustomTypeFactory; import uk.gov.gchq.gaffer.tinkerpop.process.traversal.util.GafferPredicateFactory; import java.util.function.Predicate; @@ -45,7 +46,7 @@ public Predicate getGafferPredicate() { @Override protected boolean testId(final Element element) { - return gafferPredicate.test(element.id()); + return gafferPredicate.test(GafferCustomTypeFactory.parseAsCustomTypeIfValid(element.id())); } @Override @@ -60,7 +61,7 @@ protected boolean testLabel(final Element element) { @Override protected boolean testValue(final Property property) { - return gafferPredicate.test(property.value()); + return gafferPredicate.test(GafferCustomTypeFactory.parseAsCustomTypeIfValid(property.value())); } @Override diff --git a/library/tinkerpop/src/main/java/uk/gov/gchq/gaffer/tinkerpop/process/traversal/util/GafferCustomTypeFactory.java b/library/tinkerpop/src/main/java/uk/gov/gchq/gaffer/tinkerpop/process/traversal/util/GafferCustomTypeFactory.java new file mode 100644 index 00000000000..e13817615ee --- /dev/null +++ b/library/tinkerpop/src/main/java/uk/gov/gchq/gaffer/tinkerpop/process/traversal/util/GafferCustomTypeFactory.java @@ -0,0 +1,149 @@ +/* + * Copyright 2024 Crown Copyright + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package uk.gov.gchq.gaffer.tinkerpop.process.traversal.util; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import uk.gov.gchq.gaffer.types.TypeSubTypeValue; + +import java.sql.Timestamp; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.Date; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.UUID; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/** + * Class that helps the conversion between Gaffer custom types and + * standard types that Tinkerpop supports. + * + * Tinkerpop only supports a limited number of types so any custom Gaffer + * ones can only be passed as String representations via Gremlin so need + * conversion before using in Gaffer Operation chains. + */ +public final class GafferCustomTypeFactory { + /* + * List of supported standard types that GraphSON v3 can serialise + */ + public static final List> GRAPHSONV3_TYPES = Collections.unmodifiableList( + Arrays.asList( + Boolean.class, + Byte[].class, + Date.class, + Double.class, + Float.class, + Integer.class, + List.class, + Long.class, + Map.class, + Set.class, + String.class, + Timestamp.class, + UUID.class)); + + private static final Logger LOGGER = LoggerFactory.getLogger(GafferCustomTypeFactory.class); + private static final Pattern TSTV_REGEX = Pattern.compile(".*\\[type=(?.*),\\s*subType=(?.*),\\s*value=(?.*)\\]$"); + + private GafferCustomTypeFactory() { + // Utility class + } + + /** + * Returns a the relevant Object e.g. {@link TypeSubTypeValue} from the + * supplied value or ID, usually by parsing a specifically formatted string. + * As a fallback will give back the original value if no relevant type + * was found. + * + *
+     * "TypeSubTypeValue[type=alpha,subType=beta,value=gamma]" // returns TypeSubTypeValue object
+     * "[type=alpha,subType=beta,value=gamma]" // returns TypeSubTypeValue object
+     * "normalvalue" // returns itself
+     * 
+ * + * @param value The value. + * @return The value as its relevant type. + */ + public static Object parseAsCustomTypeIfValid(final Object value) { + if (value instanceof String) { + Matcher tstvMatcher = TSTV_REGEX.matcher((String) value); + if (tstvMatcher.matches()) { + // Split into a TSTV via matcher + LOGGER.debug("Parsing string as a TSTV: {}", value); + return new TypeSubTypeValue( + tstvMatcher.group("type"), + tstvMatcher.group("stype"), + tstvMatcher.group("val")); + } + } + + // If value is collection e.g. list or set then check the values inside it + if (value instanceof Collection) { + List converted = new ArrayList<>(); + ((Collection) value).forEach(v -> converted.add(parseAsCustomTypeIfValid(v))); + // Return a set if needed + if (value instanceof Set) { + return new HashSet<>(converted); + } + return converted; + } + + return value; + } + + /** + * Parses the given value to make sure it can be used with Tinkerpops + * GraphSONv3 types. Will convert the value to String representation + * if type is not compatible or if value is a collection it will convert + * all the values inside it. + * + * @param value The value to parse. + * @return The value in compatible format. + */ + public static Object parseForGraphSONv3(final Object value) { + if (value == null) { + return value; + } + + // If value is collection e.g. list or set then check the values inside it + if (value instanceof Collection) { + List converted = new ArrayList<>(); + ((Collection) value).forEach(v -> converted.add(parseForGraphSONv3(v))); + // Return a set if needed + if (value instanceof Set) { + return new HashSet<>(converted); + } + return converted; + } + + // Check if the value can be used with GraphSON v3 + if (!GRAPHSONV3_TYPES.contains(value.getClass())) { + LOGGER.debug("Converting value to string {}", value); + return value.toString(); + } + + return value; + } + +} diff --git a/library/tinkerpop/src/main/java/uk/gov/gchq/gaffer/tinkerpop/process/traversal/util/GafferPredicateFactory.java b/library/tinkerpop/src/main/java/uk/gov/gchq/gaffer/tinkerpop/process/traversal/util/GafferPredicateFactory.java index a7c73b08e69..af22d5f5359 100644 --- a/library/tinkerpop/src/main/java/uk/gov/gchq/gaffer/tinkerpop/process/traversal/util/GafferPredicateFactory.java +++ b/library/tinkerpop/src/main/java/uk/gov/gchq/gaffer/tinkerpop/process/traversal/util/GafferPredicateFactory.java @@ -42,7 +42,6 @@ import java.util.stream.Collectors; public final class GafferPredicateFactory { - private static final String COULD_NOT_TRANSLATE_ERROR = "Could not translate Gremlin predicate: "; private GafferPredicateFactory() { @@ -60,7 +59,7 @@ private GafferPredicateFactory() { * @param p the Gremlin predicate to convert * @return the equivalent {@link KoryphePredicate} * - * @see TypeSubTypeValueFactory#parseAsTstvIfValid(Object) + * @see GafferCustomTypeFactory#parseAsCustomTypeIfValid(Object) */ public static Predicate convertGremlinPredicate(final P p) { if (p == null) { @@ -76,12 +75,12 @@ public static Predicate convertGremlinPredicate(final P p) { BiPredicate biPredicate = p.getBiPredicate(); if (biPredicate instanceof Compare) { - Object value = TypeSubTypeValueFactory.parseAsTstvIfValid(p.getValue()); + Object value = GafferCustomTypeFactory.parseAsCustomTypeIfValid(p.getValue()); return getComparePredicate((Compare) biPredicate, value); } else if (biPredicate instanceof Contains) { Collection value = (Collection) p.getValue(); Collection mappedValues = value.stream() - .map(v -> TypeSubTypeValueFactory.parseAsTstvIfValid(v)) + .map(GafferCustomTypeFactory::parseAsCustomTypeIfValid) .collect(Collectors.toList()); return getContainsPredicate((Contains) biPredicate, mappedValues); } else if (biPredicate instanceof Text) { diff --git a/library/tinkerpop/src/main/java/uk/gov/gchq/gaffer/tinkerpop/process/traversal/util/TypeSubTypeValueFactory.java b/library/tinkerpop/src/main/java/uk/gov/gchq/gaffer/tinkerpop/process/traversal/util/TypeSubTypeValueFactory.java deleted file mode 100644 index 4a43c13e32e..00000000000 --- a/library/tinkerpop/src/main/java/uk/gov/gchq/gaffer/tinkerpop/process/traversal/util/TypeSubTypeValueFactory.java +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Copyright 2024 Crown Copyright - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package uk.gov.gchq.gaffer.tinkerpop.process.traversal.util; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import uk.gov.gchq.gaffer.types.TypeSubTypeValue; - -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -public final class TypeSubTypeValueFactory { - - private static final Logger LOGGER = LoggerFactory.getLogger(TypeSubTypeValueFactory.class); - private static final Pattern TSTV_REGEX = Pattern.compile("^t:(?.*)\\|st:(?.*)\\|v:(?.*)$"); - - private TypeSubTypeValueFactory() { - // Utility class - } - - /** - * Returns a the relevant Object e.g. {@link TypeSubTypeValue} from the - * supplied value or ID, usually by parsing a specifically formatted string. - * As a fallback will give back the original value if no relevant type - * was found. - * - *
-     * "t:type|st:subtype|v:value" // returns TypeSubTypeValue object
-     * "notATstv" // returns itself
-     * 
- * - * @param value The value. - * @return The value as its relevant type. - */ - public static Object parseAsTstvIfValid(final Object value) { - if (value instanceof String) { - Matcher tstvMatcher = TSTV_REGEX.matcher((String) value); - if (tstvMatcher.matches()) { - // Split into a TSTV via matcher - LOGGER.debug("Parsing string as a TSTV: {}", value); - return new TypeSubTypeValue( - tstvMatcher.group("type"), - tstvMatcher.group("stype"), - tstvMatcher.group("val")); - } - } - - return value; - } - -} diff --git a/library/tinkerpop/src/test/java/uk/gov/gchq/gaffer/tinkerpop/GafferPopGraphTest.java b/library/tinkerpop/src/test/java/uk/gov/gchq/gaffer/tinkerpop/GafferPopGraphTest.java index 25ef6aafc7e..29db09fc4b3 100644 --- a/library/tinkerpop/src/test/java/uk/gov/gchq/gaffer/tinkerpop/GafferPopGraphTest.java +++ b/library/tinkerpop/src/test/java/uk/gov/gchq/gaffer/tinkerpop/GafferPopGraphTest.java @@ -50,7 +50,6 @@ import static uk.gov.gchq.gaffer.tinkerpop.util.GafferPopTestUtil.TEST_CONFIGURATION_2; import static uk.gov.gchq.gaffer.tinkerpop.util.GafferPopTestUtil.TEST_CONFIGURATION_3; import static uk.gov.gchq.gaffer.tinkerpop.util.GafferPopTestUtil.getTestUser; -import static uk.gov.gchq.gaffer.tinkerpop.util.GafferPopTstvTestUtils.TSTV_ID; import static uk.gov.gchq.gaffer.tinkerpop.util.GafferPopTstvTestUtils.TSTV_ID_STRING; import static uk.gov.gchq.gaffer.tinkerpop.util.modern.GafferPopModernTestUtils.CREATED; import static uk.gov.gchq.gaffer.tinkerpop.util.modern.GafferPopModernTestUtils.JOSH; @@ -322,7 +321,7 @@ void shouldGetVerticesWithTSTV() { assertThat(result).toIterable() .hasSize(1) .extracting(r -> r.id()) - .containsExactly(TSTV_ID); + .containsExactly(TSTV_ID_STRING); } @Test diff --git a/library/tinkerpop/src/test/java/uk/gov/gchq/gaffer/tinkerpop/generator/GafferPopElementGeneratorTest.java b/library/tinkerpop/src/test/java/uk/gov/gchq/gaffer/tinkerpop/generator/GafferPopElementGeneratorTest.java index 731060cdf3a..64ee051c2b1 100644 --- a/library/tinkerpop/src/test/java/uk/gov/gchq/gaffer/tinkerpop/generator/GafferPopElementGeneratorTest.java +++ b/library/tinkerpop/src/test/java/uk/gov/gchq/gaffer/tinkerpop/generator/GafferPopElementGeneratorTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2023 Crown Copyright + * Copyright 2023-2024 Crown Copyright * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -30,10 +30,10 @@ import uk.gov.gchq.gaffer.tinkerpop.GafferPopGraph; import uk.gov.gchq.gaffer.tinkerpop.GafferPopVertex; -public class GafferPopElementGeneratorTest { +class GafferPopElementGeneratorTest { @Test - public void shouldReturnAGafferPopVertex() { + void shouldReturnAGafferPopVertex() { // Given final GafferPopGraph graph = mock(GafferPopGraph.class); final Element element = new Entity.Builder().group(TestGroups.ENTITY).build(); @@ -49,10 +49,15 @@ public void shouldReturnAGafferPopVertex() { } @Test - public void shouldReturnAGafferPopEdge() { + void shouldReturnAGafferPopEdge() { // Given final GafferPopGraph graph = mock(GafferPopGraph.class); - final Element element = new Edge.Builder().group(TestGroups.EDGE).build(); + final String source = "source"; + final String dest = "dest"; + final Element element = new Edge.Builder() + .group(TestGroups.EDGE) + .source(source) + .dest(dest).build(); final GafferPopElementGenerator generator = new GafferPopElementGenerator(graph, true); @@ -66,7 +71,7 @@ public void shouldReturnAGafferPopEdge() { } @Test - public void shouldThrowExceptionForInvalidElement() { + void shouldThrowExceptionForInvalidElement() { // Given final GafferPopGraph graph = mock(GafferPopGraph.class); final Element element = mock(Element.class); diff --git a/library/tinkerpop/src/test/java/uk/gov/gchq/gaffer/tinkerpop/process/traversal/step/GafferPopGraphStepIT.java b/library/tinkerpop/src/test/java/uk/gov/gchq/gaffer/tinkerpop/process/traversal/step/GafferPopGraphStepIT.java index 3a74cd1bd2e..c50c213c9f9 100644 --- a/library/tinkerpop/src/test/java/uk/gov/gchq/gaffer/tinkerpop/process/traversal/step/GafferPopGraphStepIT.java +++ b/library/tinkerpop/src/test/java/uk/gov/gchq/gaffer/tinkerpop/process/traversal/step/GafferPopGraphStepIT.java @@ -34,12 +34,9 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatRuntimeException; -import static uk.gov.gchq.gaffer.tinkerpop.util.GafferPopTstvTestUtils.OTHER_TSTV_PROPERTY; import static uk.gov.gchq.gaffer.tinkerpop.util.GafferPopTstvTestUtils.OTHER_TSTV_PROPERTY_STRING; import static uk.gov.gchq.gaffer.tinkerpop.util.GafferPopTstvTestUtils.TSTV; -import static uk.gov.gchq.gaffer.tinkerpop.util.GafferPopTstvTestUtils.TSTV_ID; import static uk.gov.gchq.gaffer.tinkerpop.util.GafferPopTstvTestUtils.TSTV_ID_STRING; -import static uk.gov.gchq.gaffer.tinkerpop.util.GafferPopTstvTestUtils.TSTV_PROPERTY; import static uk.gov.gchq.gaffer.tinkerpop.util.GafferPopTstvTestUtils.TSTV_PROPERTY_STRING; import static uk.gov.gchq.gaffer.tinkerpop.util.modern.GafferPopModernTestUtils.AGE; import static uk.gov.gchq.gaffer.tinkerpop.util.modern.GafferPopModernTestUtils.JOSH; @@ -93,7 +90,7 @@ void shouldGetVertexByTSTVSeed() { assertThat(result) .extracting(r -> r.id()) - .containsExactlyInAnyOrder(TSTV_ID); + .containsExactlyInAnyOrder(TSTV_ID_STRING); } @@ -141,7 +138,7 @@ void shouldFilterVerticesByLabelAndTstvProperty() { assertThat(result) .extracting(r -> r.value(NAME)) - .containsExactlyInAnyOrder(TSTV_PROPERTY); + .containsExactlyInAnyOrder(TSTV_PROPERTY_STRING); } @Test @@ -161,7 +158,7 @@ void shouldFilterVerticesByLabelAndTstvPropertyLessThan() { assertThat(result) .extracting(r -> r.value(NAME)) - .containsExactlyInAnyOrder(TSTV_PROPERTY); + .containsExactlyInAnyOrder(TSTV_PROPERTY_STRING); } @Test @@ -181,7 +178,7 @@ void shouldFilterVerticesByLabelAndTstvPropertyMoreThan() { assertThat(result) .extracting(r -> r.value(NAME)) - .containsExactlyInAnyOrder(OTHER_TSTV_PROPERTY); + .containsExactlyInAnyOrder(OTHER_TSTV_PROPERTY_STRING); } @Test @@ -201,7 +198,7 @@ void shouldFilterVerticesByLabelAndTstvPropertyWithin() { assertThat(result) .extracting(r -> r.value(NAME)) - .containsExactlyInAnyOrder(OTHER_TSTV_PROPERTY, TSTV_PROPERTY); + .containsExactlyInAnyOrder(OTHER_TSTV_PROPERTY_STRING, TSTV_PROPERTY_STRING); } @Test @@ -238,7 +235,7 @@ void shouldFilterVerticesByTstvPropertyWithin() { assertThat(result) .extracting(r -> r.value(NAME)) - .containsExactlyInAnyOrder(OTHER_TSTV_PROPERTY, TSTV_PROPERTY); + .containsExactlyInAnyOrder(OTHER_TSTV_PROPERTY_STRING, TSTV_PROPERTY_STRING); } @Test diff --git a/library/tinkerpop/src/test/java/uk/gov/gchq/gaffer/tinkerpop/process/traversal/step/GafferPopHasStepIT.java b/library/tinkerpop/src/test/java/uk/gov/gchq/gaffer/tinkerpop/process/traversal/step/GafferPopHasStepIT.java index 0b3f0e4e0be..e817be0f64e 100644 --- a/library/tinkerpop/src/test/java/uk/gov/gchq/gaffer/tinkerpop/process/traversal/step/GafferPopHasStepIT.java +++ b/library/tinkerpop/src/test/java/uk/gov/gchq/gaffer/tinkerpop/process/traversal/step/GafferPopHasStepIT.java @@ -31,10 +31,8 @@ import java.util.List; import static org.assertj.core.api.Assertions.assertThat; -import static uk.gov.gchq.gaffer.tinkerpop.util.GafferPopTstvTestUtils.OTHER_TSTV_PROPERTY; import static uk.gov.gchq.gaffer.tinkerpop.util.GafferPopTstvTestUtils.OTHER_TSTV_PROPERTY_STRING; import static uk.gov.gchq.gaffer.tinkerpop.util.GafferPopTstvTestUtils.TSTV; -import static uk.gov.gchq.gaffer.tinkerpop.util.GafferPopTstvTestUtils.TSTV_PROPERTY; import static uk.gov.gchq.gaffer.tinkerpop.util.GafferPopTstvTestUtils.TSTV_PROPERTY_STRING; import static uk.gov.gchq.gaffer.tinkerpop.util.modern.GafferPopModernTestUtils.AGE; import static uk.gov.gchq.gaffer.tinkerpop.util.modern.GafferPopModernTestUtils.JOSH; @@ -80,7 +78,7 @@ void shouldFilterVerticesByLabelAndTstvProperty() { assertThat(result) .extracting(r -> r.value(NAME)) - .containsExactlyInAnyOrder(TSTV_PROPERTY); + .containsExactlyInAnyOrder(TSTV_PROPERTY_STRING); } @Test @@ -100,7 +98,7 @@ void shouldFilterVerticesByLabelAndTstvPropertyLessThan() { assertThat(result) .extracting(r -> r.value(NAME)) - .containsExactlyInAnyOrder(TSTV_PROPERTY); + .containsExactlyInAnyOrder(TSTV_PROPERTY_STRING); } @Test @@ -120,7 +118,7 @@ void shouldFilterVerticesByLabelAndTstvPropertyMoreThan() { assertThat(result) .extracting(r -> r.value(NAME)) - .containsExactlyInAnyOrder(OTHER_TSTV_PROPERTY); + .containsExactlyInAnyOrder(OTHER_TSTV_PROPERTY_STRING); } @Test @@ -141,7 +139,7 @@ void shouldFilterVerticesByLabelAndTstvPropertyWithin() { assertThat(result) .extracting(r -> r.value(NAME)) - .containsExactlyInAnyOrder(OTHER_TSTV_PROPERTY, TSTV_PROPERTY); + .containsExactlyInAnyOrder(OTHER_TSTV_PROPERTY_STRING, TSTV_PROPERTY_STRING); } @Test @@ -179,7 +177,7 @@ void shouldFilterVerticesByTstvPropertyWithin() { assertThat(result) .extracting(r -> r.value(NAME)) - .containsExactlyInAnyOrder(OTHER_TSTV_PROPERTY, TSTV_PROPERTY); + .containsExactlyInAnyOrder(OTHER_TSTV_PROPERTY_STRING, TSTV_PROPERTY_STRING); } @Test diff --git a/library/tinkerpop/src/test/java/uk/gov/gchq/gaffer/tinkerpop/process/traversal/util/GafferCustomTypeFactoryTest.java b/library/tinkerpop/src/test/java/uk/gov/gchq/gaffer/tinkerpop/process/traversal/util/GafferCustomTypeFactoryTest.java new file mode 100644 index 00000000000..1d7ffb808c8 --- /dev/null +++ b/library/tinkerpop/src/test/java/uk/gov/gchq/gaffer/tinkerpop/process/traversal/util/GafferCustomTypeFactoryTest.java @@ -0,0 +1,108 @@ +/* + * Copyright 2024 Crown Copyright + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package uk.gov.gchq.gaffer.tinkerpop.process.traversal.util; + +import org.assertj.core.api.InstanceOfAssertFactories; +import org.junit.jupiter.api.Test; + +import uk.gov.gchq.gaffer.types.TypeSubTypeValue; + +import java.util.Collection; + +import static org.assertj.core.api.Assertions.assertThat; +import static uk.gov.gchq.gaffer.tinkerpop.util.GafferPopTstvTestUtils.COMPLEX_TSTV_ID; +import static uk.gov.gchq.gaffer.tinkerpop.util.GafferPopTstvTestUtils.COMPLEX_TSTV_ID_STRING; +import static uk.gov.gchq.gaffer.tinkerpop.util.GafferPopTstvTestUtils.TSTV_ID; +import static uk.gov.gchq.gaffer.tinkerpop.util.GafferPopTstvTestUtils.TSTV_ID_STRING; +import static uk.gov.gchq.gaffer.tinkerpop.util.GafferPopTstvTestUtils.TSTV_PROPERTY_SET; +import static uk.gov.gchq.gaffer.tinkerpop.util.GafferPopTstvTestUtils.TSTV_PROPERTY_SET_STRING; + +class GafferCustomTypeFactoryTest { + + @Test + void shouldConvertTypeSubTypeValues() { + // When + Object stringParsed = GafferCustomTypeFactory.parseAsCustomTypeIfValid(TSTV_ID_STRING); + Object tstvParsed = GafferCustomTypeFactory.parseForGraphSONv3(TSTV_ID); + + // Then + assertThat(stringParsed) + .isInstanceOf(TypeSubTypeValue.class) + .extracting(r -> (TypeSubTypeValue) r) + .isEqualTo(TSTV_ID); + + assertThat(tstvParsed) + .isInstanceOf(String.class) + .extracting(r -> (String) r) + .isEqualTo(TSTV_ID_STRING); + } + + @Test + void shouldConvertComplexTypeSubTypeValues() { + // When + Object stringParsed = GafferCustomTypeFactory.parseAsCustomTypeIfValid(COMPLEX_TSTV_ID_STRING); + Object tstvParsed = GafferCustomTypeFactory.parseForGraphSONv3(COMPLEX_TSTV_ID); + + // Then + assertThat(stringParsed) + .isInstanceOf(TypeSubTypeValue.class) + .extracting(r -> (TypeSubTypeValue) r) + .isEqualTo(COMPLEX_TSTV_ID); + + assertThat(tstvParsed) + .isInstanceOf(String.class) + .extracting(r -> (String) r) + .isEqualTo(COMPLEX_TSTV_ID_STRING); + } + + @Test + void shouldParseSetOfTypeSubTypeValues() { + Object stringParsed = GafferCustomTypeFactory.parseAsCustomTypeIfValid(TSTV_PROPERTY_SET_STRING); + Object tstvParsed = GafferCustomTypeFactory.parseForGraphSONv3(TSTV_PROPERTY_SET); + + // Then + assertThat(stringParsed) + .isInstanceOf(Collection.class) + .asInstanceOf(InstanceOfAssertFactories.COLLECTION) + .containsExactlyInAnyOrderElementsOf(TSTV_PROPERTY_SET); + + assertThat(tstvParsed) + .isInstanceOf(Collection.class) + .asInstanceOf(InstanceOfAssertFactories.COLLECTION) + .containsExactlyInAnyOrderElementsOf(TSTV_PROPERTY_SET_STRING); + } + + @Test + void shouldNotParseStringAsTstv() { + String notATstv = "not|a|tstv"; + Object result = GafferCustomTypeFactory.parseAsCustomTypeIfValid(notATstv); + assertThat(result) + .isInstanceOf(String.class) + .extracting(r -> (String) r) + .isEqualTo("not|a|tstv"); + } + + @Test + void shouldNotParseObjectAsTstv() { + Object notATstv = 1; + Object result = GafferCustomTypeFactory.parseAsCustomTypeIfValid(notATstv); + assertThat(result) + .isInstanceOf(Integer.class) + .extracting(r -> (Integer) r) + .isEqualTo(1); + } +} diff --git a/library/tinkerpop/src/test/java/uk/gov/gchq/gaffer/tinkerpop/process/traversal/util/TypeSubTypeValueFactoryTest.java b/library/tinkerpop/src/test/java/uk/gov/gchq/gaffer/tinkerpop/process/traversal/util/TypeSubTypeValueFactoryTest.java deleted file mode 100644 index b5b2267ec7a..00000000000 --- a/library/tinkerpop/src/test/java/uk/gov/gchq/gaffer/tinkerpop/process/traversal/util/TypeSubTypeValueFactoryTest.java +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Copyright 2024 Crown Copyright - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package uk.gov.gchq.gaffer.tinkerpop.process.traversal.util; - -import org.junit.jupiter.api.Test; - -import uk.gov.gchq.gaffer.types.TypeSubTypeValue; - -import static org.assertj.core.api.Assertions.assertThat; - -class TypeSubTypeValueFactoryTest { - - @Test - void shouldParseStringAsTstv() { - String tstv = "t:one|st:two|v:three"; - Object result = TypeSubTypeValueFactory.parseAsTstvIfValid(tstv); - assertThat(result) - .isInstanceOf(TypeSubTypeValue.class) - .extracting(r -> (TypeSubTypeValue) r) - .isEqualTo(new TypeSubTypeValue("one", "two", "three")); - } - - @Test - void shouldParseComplexStringAsTstv() { - String tstv = "t:one|one|st:two|two|v:three|three"; - Object result = TypeSubTypeValueFactory.parseAsTstvIfValid(tstv); - assertThat(result) - .isInstanceOf(TypeSubTypeValue.class) - .extracting(r -> (TypeSubTypeValue) r) - .isEqualTo(new TypeSubTypeValue("one|one", "two|two", "three|three")); - } - - @Test - void shouldNotParseStringAsTstv() { - String notATstv = "not|a|tstv"; - Object result = TypeSubTypeValueFactory.parseAsTstvIfValid(notATstv); - assertThat(result) - .isInstanceOf(String.class) - .extracting(r -> (String) r) - .isEqualTo("not|a|tstv"); - } - - @Test - void shouldNotParseObjectAsTstv() { - Object notATstv = 1; - Object result = TypeSubTypeValueFactory.parseAsTstvIfValid(notATstv); - assertThat(result) - .isInstanceOf(Integer.class) - .extracting(r -> (Integer) r) - .isEqualTo(1); - } -} diff --git a/library/tinkerpop/src/test/java/uk/gov/gchq/gaffer/tinkerpop/util/GafferPopTstvTestUtils.java b/library/tinkerpop/src/test/java/uk/gov/gchq/gaffer/tinkerpop/util/GafferPopTstvTestUtils.java index 824741329ed..c3c9e342eb6 100644 --- a/library/tinkerpop/src/test/java/uk/gov/gchq/gaffer/tinkerpop/util/GafferPopTstvTestUtils.java +++ b/library/tinkerpop/src/test/java/uk/gov/gchq/gaffer/tinkerpop/util/GafferPopTstvTestUtils.java @@ -24,18 +24,27 @@ import uk.gov.gchq.gaffer.tinkerpop.GafferPopGraph; import uk.gov.gchq.gaffer.types.TypeSubTypeValue; +import java.util.Arrays; +import java.util.HashSet; +import java.util.Set; + public final class GafferPopTstvTestUtils { public static final String TSTV = "tstv"; public static final String NAME = "name"; public static final String EDGE = "test"; public static final TypeSubTypeValue TSTV_ID = new TypeSubTypeValue("alpha", "beta", "gamma"); - public static final String TSTV_ID_STRING = "t:alpha|st:beta|v:gamma"; public static final TypeSubTypeValue OTHER_TSTV_ID = new TypeSubTypeValue("delta", "epsilon", "zeta"); + public static final TypeSubTypeValue COMPLEX_TSTV_ID = new TypeSubTypeValue("de|lt-a", "eps|i|l|o=n", "zet|09!//a"); public static final TypeSubTypeValue TSTV_PROPERTY = new TypeSubTypeValue("eta", "theta", "iota"); - public static final String TSTV_PROPERTY_STRING = "t:eta|st:theta|v:iota"; public static final TypeSubTypeValue OTHER_TSTV_PROPERTY = new TypeSubTypeValue("kappa", "lambda", "mu"); - public static final String OTHER_TSTV_PROPERTY_STRING = "t:kappa|st:lambda|v:mu"; + public static final String TSTV_ID_STRING = "TypeSubTypeValue[type=alpha,subType=beta,value=gamma]"; + public static final String OTHER_TSTV_ID_STRING = "TypeSubTypeValue[type=delta,subType=epsilon,value=zeta]"; + public static final String COMPLEX_TSTV_ID_STRING = "TypeSubTypeValue[type=de|lt-a,subType=eps|i|l|o=n,value=zet|09!//a]"; + public static final String TSTV_PROPERTY_STRING = "TypeSubTypeValue[type=eta,subType=theta,value=iota]"; + public static final String OTHER_TSTV_PROPERTY_STRING = "TypeSubTypeValue[type=kappa,subType=lambda,value=mu]"; + public static final Set TSTV_PROPERTY_SET = new HashSet<>(Arrays.asList(TSTV_PROPERTY, OTHER_TSTV_PROPERTY)); + public static final Set TSTV_PROPERTY_SET_STRING = new HashSet<>(Arrays.asList(TSTV_PROPERTY_STRING, OTHER_TSTV_PROPERTY_STRING)); public static final Configuration TSTV_CONFIGURATION = new BaseConfiguration() { { diff --git a/pom.xml b/pom.xml index 25626464c92..dca3aecbdfd 100644 --- a/pom.xml +++ b/pom.xml @@ -99,6 +99,8 @@ 5.15.0 1.36.0 3.7.1 + + 1.0.0 2.17 diff --git a/rest-api/spring-rest/pom.xml b/rest-api/spring-rest/pom.xml index 521ab6fb6e3..085e10e198a 100644 --- a/rest-api/spring-rest/pom.xml +++ b/rest-api/spring-rest/pom.xml @@ -121,6 +121,11 @@ springdoc-openapi-ui ${springdoc.version} + + org.opencypher.gremlin + cypher-gremlin-server-plugin + ${cypher-gremlin.version} + diff --git a/rest-api/spring-rest/src/main/java/uk/gov/gchq/gaffer/rest/controller/GremlinController.java b/rest-api/spring-rest/src/main/java/uk/gov/gchq/gaffer/rest/controller/GremlinController.java index af6d5e0c449..ba763b88d22 100644 --- a/rest-api/spring-rest/src/main/java/uk/gov/gchq/gaffer/rest/controller/GremlinController.java +++ b/rest-api/spring-rest/src/main/java/uk/gov/gchq/gaffer/rest/controller/GremlinController.java @@ -23,6 +23,7 @@ import org.apache.tinkerpop.gremlin.structure.Graph; import org.apache.tinkerpop.gremlin.structure.util.empty.EmptyGraph; import org.json.JSONObject; +import org.opencypher.gremlin.server.jsr223.CypherPlugin; import org.opencypher.gremlin.translation.CypherAst; import org.opencypher.gremlin.translation.translator.Translator; import org.springframework.beans.factory.annotation.Autowired; @@ -43,7 +44,9 @@ import uk.gov.gchq.gaffer.tinkerpop.GafferPopGraphVariables; import java.nio.charset.StandardCharsets; +import java.util.HashMap; import java.util.LinkedList; +import java.util.Map; import static org.springframework.http.MediaType.APPLICATION_JSON_VALUE; import static org.springframework.http.MediaType.TEXT_PLAIN_VALUE; @@ -61,12 +64,15 @@ public class GremlinController { private final ConcurrentBindings bindings = new ConcurrentBindings(); private final AbstractUserFactory userFactory; private final Graph graph; + private final Map> plugins = new HashMap<>(); @Autowired public GremlinController(final GraphTraversalSource g, final AbstractUserFactory userFactory) { bindings.putIfAbsent("g", g); graph = g.getGraph(); this.userFactory = userFactory; + // Add cypher plugin so cypher functions can be used in queries + plugins.put(CypherPlugin.class.getName(), new HashMap<>()); } /** @@ -163,13 +169,15 @@ private JSONObject runGremlinAndGetExplain(final String gremlinQuery, final Http } else { gafferPopGraph = (GafferPopGraph) graph; } + gafferPopGraph.setDefaultVariables((GafferPopGraphVariables) gafferPopGraph.variables()); // Hooks for user auth userFactory.setHttpHeaders(httpHeaders); graph.variables().set(GafferPopGraphVariables.USER, userFactory.createUser()); JSONObject explain = new JSONObject(); - try (GremlinExecutor gremlinExecutor = GremlinExecutor.build().globalBindings(bindings).create()) { - gafferPopGraph.setDefaultVariables((GafferPopGraphVariables) gafferPopGraph.variables()); + try (GremlinExecutor gremlinExecutor = GremlinExecutor.build() + .addPlugins("gremlin-groovy", plugins) + .globalBindings(bindings).create()) { // Execute the query note this will actually run the query which we need // as Gremlin will skip steps if there is no input from the previous ones gremlinExecutor.eval(gremlinQuery).join(); diff --git a/rest-api/spring-rest/src/main/java/uk/gov/gchq/gaffer/rest/handler/GremlinWebSocketHandler.java b/rest-api/spring-rest/src/main/java/uk/gov/gchq/gaffer/rest/handler/GremlinWebSocketHandler.java index 1564a5bfd4a..abd2885bf63 100644 --- a/rest-api/spring-rest/src/main/java/uk/gov/gchq/gaffer/rest/handler/GremlinWebSocketHandler.java +++ b/rest-api/spring-rest/src/main/java/uk/gov/gchq/gaffer/rest/handler/GremlinWebSocketHandler.java @@ -40,6 +40,7 @@ import org.apache.tinkerpop.gremlin.util.ser.MessageTextSerializer; import org.apache.tinkerpop.gremlin.util.ser.SerTokens; import org.json.JSONObject; +import org.opencypher.gremlin.server.jsr223.CypherPlugin; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.web.socket.BinaryMessage; @@ -57,6 +58,7 @@ import java.nio.charset.StandardCharsets; import java.util.AbstractMap.SimpleEntry; import java.util.Collections; +import java.util.HashMap; import java.util.Map; import java.util.UUID; import java.util.concurrent.ExecutorService; @@ -88,6 +90,7 @@ public class GremlinWebSocketHandler extends BinaryWebSocketHandler { private final ConcurrentBindings bindings = new ConcurrentBindings(); private final AbstractUserFactory userFactory; private final Graph graph; + private final Map> plugins = new HashMap<>(); /** * Constructor @@ -99,6 +102,8 @@ public GremlinWebSocketHandler(final GraphTraversalSource g, final AbstractUserF bindings.putIfAbsent("g", g); graph = g.getGraph(); this.userFactory = userFactory; + // Add cypher plugin so cypher functions can be used in queries + plugins.put(CypherPlugin.class.getName(), new HashMap<>()); } @Override @@ -143,6 +148,7 @@ private ResponseMessage handleGremlinRequest(final WebSocketSession session, fin try (Scope scope = span.makeCurrent(); GremlinExecutor gremlinExecutor = GremlinExecutor.build() .globalBindings(bindings) + .addPlugins("gremlin-groovy", plugins) .executorService(executorService) .create()) { // Set current headers for potential authorisation then set the user diff --git a/rest-api/spring-rest/src/test/java/uk/gov/gchq/gaffer/rest/controller/GremlinControllerTest.java b/rest-api/spring-rest/src/test/java/uk/gov/gchq/gaffer/rest/controller/GremlinControllerTest.java index d5cd4e79169..92c94f4a980 100644 --- a/rest-api/spring-rest/src/test/java/uk/gov/gchq/gaffer/rest/controller/GremlinControllerTest.java +++ b/rest-api/spring-rest/src/test/java/uk/gov/gchq/gaffer/rest/controller/GremlinControllerTest.java @@ -32,6 +32,8 @@ import org.springframework.test.web.servlet.MvcResult; import org.springframework.test.web.servlet.request.MockMvcRequestBuilders; +import uk.gov.gchq.gaffer.operation.impl.Limit; +import uk.gov.gchq.gaffer.operation.impl.get.GetAllElements; import uk.gov.gchq.gaffer.operation.impl.get.GetElements; import uk.gov.gchq.gaffer.rest.factory.spring.AbstractUserFactory; import uk.gov.gchq.gaffer.rest.factory.spring.UnknownUserFactory; @@ -125,6 +127,7 @@ void shouldRejectMalformedGremlinQuery() throws Exception { void shouldReturnExplainOfValidCypherQuery() throws Exception { // Given String cypherString = "MATCH (p:person) WHERE ID(p) = '" + MARKO.getId() + "' RETURN p"; + List expectedOperations = Arrays.asList(GetElements.class.getName()); // When @@ -152,6 +155,38 @@ void shouldReturnExplainOfValidCypherQuery() throws Exception { .containsExactlyElementsOf(expectedOperations); } + @Test + void shouldReturnExplainOfCypherQueryWithExtensions() throws Exception { + // Given (uses the toInteger custom function) + String cypherString = "MATCH (p:person) WHERE p.age > toInteger(22) RETURN p"; + + List expectedOperations = Arrays.asList(GetAllElements.class.getName(), Limit.class.getName()); + + // When + MvcResult result = mockMvc + .perform(MockMvcRequestBuilders + .post(CYPHER_EXPLAIN_ENDPOINT) + .content(cypherString) + .contentType(TEXT_PLAIN_VALUE)) + .andReturn(); + + // Then + // Ensure OK response + assertThat(result.getResponse().getStatus()).isEqualTo(200); + + // Get and check response + JSONObject jsonResponse = new JSONObject(result.getResponse().getContentAsString()); + assertThat(jsonResponse.has(GremlinController.EXPLAIN_OVERVIEW_KEY)).isTrue(); + assertThat(jsonResponse.has(GremlinController.EXPLAIN_OP_CHAIN_KEY)).isTrue(); + assertThat(jsonResponse.has(GremlinController.EXPLAIN_GREMLIN_KEY)).isTrue(); + + // Check the operations that ran are as expected + JSONArray operations = jsonResponse.getJSONObject("chain").getJSONArray("operations"); + assertThat(operations) + .map(json -> ((JSONObject) json).getString("class")) + .containsExactlyElementsOf(expectedOperations); + } + @Test void shouldRejectMalformedCypherQuery() throws Exception { // Given diff --git a/rest-api/spring-rest/src/test/java/uk/gov/gchq/gaffer/rest/integration/handler/GremlinWebSocketIT.java b/rest-api/spring-rest/src/test/java/uk/gov/gchq/gaffer/rest/integration/handler/GremlinWebSocketIT.java index 2dba6d0a30c..c3f72fff2f6 100644 --- a/rest-api/spring-rest/src/test/java/uk/gov/gchq/gaffer/rest/integration/handler/GremlinWebSocketIT.java +++ b/rest-api/spring-rest/src/test/java/uk/gov/gchq/gaffer/rest/integration/handler/GremlinWebSocketIT.java @@ -145,4 +145,22 @@ void shouldAcceptQueryWithCypher() { .containsExactly(MARKO.getName()); } + @Test + void shouldAcceptGremlinQueryUsingCustomCypherFunctions() { + // Given + String query = "g.V().hasLabel('person').values('age').map(cypherToString()).toList()"; + + // When + List results = client.submit(query).stream().collect(Collectors.toList()); + + // Then + assertThat(results) + .map(result -> result.getObject()) + .containsExactlyInAnyOrder( + String.valueOf(MARKO.getAge()), + String.valueOf(VADAS.getAge()), + String.valueOf(PETER.getAge()), + String.valueOf(JOSH.getAge())); + } + } From dc892f1d9afaf6fd1ac115bdbb1df045a1e091b1 Mon Sep 17 00:00:00 2001 From: cn337131 <141730190+cn337131@users.noreply.github.com> Date: Mon, 5 Aug 2024 09:06:00 +0000 Subject: [PATCH 12/16] Gh-3259: Improve release process (#3260) * update release pipelines * simplify * release notes fix * remove comment * address comments --- .github/release-notes.yml | 20 -- .github/release.yml | 23 +++ .github/workflows/create-release-branch.yaml | 43 ++--- .github/workflows/release.yaml | 181 ++++++++----------- 4 files changed, 116 insertions(+), 151 deletions(-) delete mode 100644 .github/release-notes.yml create mode 100644 .github/release.yml diff --git a/.github/release-notes.yml b/.github/release-notes.yml deleted file mode 100644 index 9b58699c5bc..00000000000 --- a/.github/release-notes.yml +++ /dev/null @@ -1,20 +0,0 @@ -changelog: - sections: - - title: "Headliners" - emoji: ":star:" - labels: [ "headliner" ] - - title: "New Features" - emoji: ":gift:" - labels: [ "feature" ] - - title: "Enhancements" - emoji: ":sparkles:" - labels: [ "enhancement" ] - - title: "Bugs Fixed" - emoji: ":beetle:" - labels: [ "bug" ] - - title: "Documentation" - emoji: ":book:" - labels: "documentation" - - title: "Automation" - emoji: ":robot:" - labels: [ "automation" ] diff --git a/.github/release.yml b/.github/release.yml new file mode 100644 index 00000000000..d30df62ae17 --- /dev/null +++ b/.github/release.yml @@ -0,0 +1,23 @@ +changelog: + categories: + - title: Headliners + labels: + - headliner + - title: New Features + labels: + - feature + - title: Enhancements + labels: + - enhancement + - title: Bugs Fixed + labels: + - bug + - title: Documentation + labels: + - documentation + - title: Automation + labels: + - automation + - title: Other changes + labels: + - "*" diff --git a/.github/workflows/create-release-branch.yaml b/.github/workflows/create-release-branch.yaml index 5117cc4164c..1c2d361ac09 100644 --- a/.github/workflows/create-release-branch.yaml +++ b/.github/workflows/create-release-branch.yaml @@ -1,11 +1,9 @@ name: Create Release Branch on: - workflow_dispatch: - inputs: - version: - description: 'Release Branch Version' - required: false + milestone: + types: + - closed env: artifactId: gaffer2 @@ -23,28 +21,11 @@ jobs: token: ${{ secrets.ADMIN_GITHUB_TOKEN }} fetch-depth: 0 - - name: Set version from input - if: ${{ github.event.inputs.version }} - run: echo "RELEASE_VERSION=$(echo ${{ github.event.inputs.version }} | sed 's/^v//')" >> $GITHUB_ENV - - - name: Get latest tag - if: ${{ !github.event.inputs.version }} - uses: actions-ecosystem/action-get-latest-tag@v1 - id: get-latest-tag - - - name: Format latest tag - if: ${{ !github.event.inputs.version }} - run: echo "CURRENT_VERSION=$(echo ${{ steps.get-latest-tag.outputs.tag }} | sed 's/^gaffer2-//')" >> $GITHUB_ENV - - - name: Bump latest tag variable version - if: ${{ !github.event.inputs.version }} - run: echo "RELEASE_VERSION=$(echo ${{ env.CURRENT_VERSION }} | sed -r 's/([0-9]+)\.([0-9]+)\.([0-9]+)/echo \1.$((\2+1)).0/' | sh)" >> $GITHUB_ENV - - - name: Verify version regex - run: echo ${{ env.RELEASE_VERSION }} | grep -E '^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-((?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\+([0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?$' + - name: Set version from milestone + run: echo "RELEASE_VERSION=$(echo ${{ github.event.milestone.title }})" >> $GITHUB_ENV - name: Set release branch - run: echo "BRANCH_NAME=$(echo release/${{ env.RELEASE_VERSION }} )" >> $GITHUB_ENV + run: echo "BRANCH_NAME=$(echo release/"${{ env.RELEASE_VERSION }}" )" >> $GITHUB_ENV - name: Set up Github credentials run: | @@ -54,10 +35,20 @@ jobs: - name: Update versions run: | mvn versions:set-property -Dproperty=revision -DnewVersion=${RELEASE_VERSION} -DgenerateBackupPoms=false - sed -i'' -e "s/^gaffer.version=.*/gaffer.version=$RELEASE_VERSION/" rest-api/common-rest/src/main/resources/version.properties - name: Push to release branch run: | git checkout -b $BRANCH_NAME git commit -a -m "prepare release $artifactId-$RELEASE_VERSION" git push --set-upstream origin $BRANCH_NAME + + - name: Tag release branch + run: | + git tag gaffer2-$RELEASE_VERSION + git push origin --tags + + - name: Create PR to master + run: | + gh pr create -B master -H $BRANCH_NAME --title 'Merge release into master branch' --body 'Created by GH Action' + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index 37fde540f14..70d464b9882 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -1,21 +1,22 @@ name: Full Release on: - milestone: - types: - - closed + pull_request: + branches: + - master + types: [closed] env: artifactId: gaffer2 MAVEN_OPTS: -Dmaven.wagon.http.retryHandler.count=3 -Dmaven.wagon.httpconnectionManager.ttlSeconds=25 - jobs: - create-release-tag: + deploy-release: + if: ${{ github.event.pull_request.merged }} runs-on: ubuntu-latest outputs: - branch_name: ${{ steps.branch.outputs.branch_name }} + release_version: ${{ steps.release-version.outputs.release_version }} steps: - name: Setup JDK @@ -36,106 +37,15 @@ jobs: git config user.name github-actions[bot] git config user.email 41898282+github-actions[bot]@users.noreply.github.com - - name: Set release version - run: echo "RELEASE_VERSION=$(echo ${{ github.event.milestone.title }} | cut -c 2-)" >> $GITHUB_ENV - - - name: Set branch name - run: echo "BRANCH_NAME=$(git branch -a | grep $RELEASE_VERSION | tail -n 1 | cut -c 18-)" >> $GITHUB_ENV - - - name: Output branch name - id: branch - run: echo "branch_name=$BRANCH_NAME" >> $GITHUB_OUTPUT - - - name: Fail if branch output missing (no branch found) - if: ${{ !steps.branch.outputs.branch_name }} - run: exit 1 - - - name: Merge release into master - run: | - git checkout ${{ env.BRANCH_NAME }} - git checkout master - git merge ${{ env.BRANCH_NAME }} - - - name: Push changes - run: | - git tag $artifactId-$RELEASE_VERSION - git push origin $artifactId-$RELEASE_VERSION - git push - - update-develop: - runs-on: ubuntu-latest - needs: - - create-release-tag - - steps: - - name: Checkout develop - uses: actions/checkout@v4 - with: - ref: develop - token: ${{ secrets.ADMIN_GITHUB_TOKEN }} - fetch-depth: 0 - - - name: Set up Github credentials - run: | - git config user.name github-actions[bot] - git config user.email 41898282+github-actions[bot]@users.noreply.github.com - - - name: Setup JDK - uses: actions/setup-java@v4 - with: - distribution: 'zulu' - java-version: '8' - - - name: Merge release into develop - run: | - git checkout ${{ needs.create-release-tag.outputs.branch_name }} - git checkout develop - git merge ${{ needs.create-release-tag.outputs.branch_name }} --strategy-option theirs - - - name: Update develop branch + - name: Output release version + id: release-version run: | - git checkout develop - mvn versions:set-property -Dproperty=revision -DnewVersion=$(echo ${{ github.event.milestone.title }} | cut -c 2-)-SNAPSHOT - mvn build-helper:parse-version versions:set-property \ - -Dproperty=revision \ - -DnewVersion=\${parsedVersion.majorVersion}.\${parsedVersion.minorVersion}.\${parsedVersion.nextIncrementalVersion}-SNAPSHOT - NEW_GAFFER_VERSION=$(mvn -q help:evaluate -DforceStdout -Dexpression=pom.version) - sed -i'' -e "s/^gaffer.version=.*/gaffer.version=$NEW_GAFFER_VERSION/" rest-api/common-rest/src/main/resources/version.properties - git commit -a -m "prepare for next development iteration" - git push - - update-github-releases: - runs-on: ubuntu-latest - needs: - - create-release-tag - - steps: - - name: Checkout Master - uses: actions/checkout@v4 - with: - ref: master - - - name: Create Release Notes - uses: docker://decathlon/release-notes-generator-action:3.1.5 - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - - - name: Set version - run: echo "RELEASE_VERSION=$(echo ${{ github.event.milestone.title }} | cut -c 2-)" >> $GITHUB_ENV - - - name: Upload notes - uses: softprops/action-gh-release@v2 - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - with: - tag_name: ${{ env.artifactId }}-${{ env.RELEASE_VERSION }} - name: Gaffer ${{ env.RELEASE_VERSION }} - body_path: release_file.md + echo "release_version=$(mvn -q help:evaluate -DforceStdout -Dexpression=pom.version)" >> $GITHUB_OUTPUT generate-javadoc: runs-on: ubuntu-latest needs: - - create-release-tag + - deploy-release steps: - name: Checkout Master @@ -156,7 +66,7 @@ jobs: java-version: '11' - name: Set version - run: echo "RELEASE_VERSION=$(echo ${{ github.event.milestone.title }} | cut -c 2-)" >> $GITHUB_ENV + run: echo "RELEASE_VERSION=$(echo ${{ needs.deploy-release.outputs.release_version }})" >> $GITHUB_ENV - name: Upload Javadoc run: | @@ -176,7 +86,7 @@ jobs: release-to-nexus: runs-on: ubuntu-latest needs: - - create-release-tag + - deploy-release steps: - name: Setup JDK @@ -188,7 +98,7 @@ jobs: - name: Checkout release uses: actions/checkout@v4 with: - ref: ${{ needs.create-release-tag.outputs.branch_name }} + ref: master - name: Decode CodeSigning key env: @@ -205,4 +115,65 @@ jobs: GPG_PASSPHRASE: ${{ secrets.GPG_PASSPHRASE }} OSS_NEXUS_USERNAME: ${{ secrets.OSS_NEXUS_USERNAME }} OSS_NEXUS_PASSWORD: ${{ secrets.OSS_NEXUS_PASSWORD }} - run: mvn deploy -P quick,ossrh-release --settings cd/mvnsettings.xml -B + run: + mvn deploy -P quick,ossrh-release --settings cd/mvnsettings.xml -B + + update-github-releases: + runs-on: ubuntu-latest + needs: + - deploy-release + + steps: + - name: Checkout Master + uses: actions/checkout@v4 + with: + ref: master + + - name: Set version + run: echo "RELEASE_VERSION=$(echo ${{ needs.deploy-release.outputs.release_version }})" >> $GITHUB_ENV + + - name: Create github release + uses: softprops/action-gh-release@v2 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + tag_name: ${{ env.artifactId }}-${{ env.RELEASE_VERSION }} + name: Gaffer ${{ env.RELEASE_VERSION }} + + update-develop: + runs-on: ubuntu-latest + needs: + - deploy-release + + steps: + - name: Checkout develop + uses: actions/checkout@v4 + with: + ref: develop + token: ${{ secrets.ADMIN_GITHUB_TOKEN }} + fetch-depth: 0 + + - name: Set up Github credentials + run: | + git config user.name github-actions[bot] + git config user.email 41898282+github-actions[bot]@users.noreply.github.com + + - name: Setup JDK + uses: actions/setup-java@v4 + with: + distribution: 'zulu' + java-version: '8' + + - name: Merge master into develop + run: | + git merge origin/master + + - name: Update develop branch + run: | + git checkout develop + mvn versions:set-property -Dproperty=revision -DnewVersion=$(echo ${{ needs.deploy-release.outputs.release_version }})-SNAPSHOT + mvn build-helper:parse-version versions:set-property \ + -Dproperty=revision \ + -DnewVersion=\${parsedVersion.majorVersion}.\${parsedVersion.minorVersion}.\${parsedVersion.nextIncrementalVersion}-SNAPSHOT + git commit -a -m "prepare for next development iteration" + git push From b3aaa6493be4cfcd41b495d8a8251c4806b894e5 Mon Sep 17 00:00:00 2001 From: p29876 <165825455+p29876@users.noreply.github.com> Date: Thu, 8 Aug 2024 12:45:49 +0000 Subject: [PATCH 13/16] Make gremlin config message clearer (#3264) --- .../main/java/uk/gov/gchq/gaffer/rest/config/GremlinConfig.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rest-api/spring-rest/src/main/java/uk/gov/gchq/gaffer/rest/config/GremlinConfig.java b/rest-api/spring-rest/src/main/java/uk/gov/gchq/gaffer/rest/config/GremlinConfig.java index a13d12d5c3f..452c37dad96 100644 --- a/rest-api/spring-rest/src/main/java/uk/gov/gchq/gaffer/rest/config/GremlinConfig.java +++ b/rest-api/spring-rest/src/main/java/uk/gov/gchq/gaffer/rest/config/GremlinConfig.java @@ -44,7 +44,7 @@ public GraphTraversalSource graphTraversalSource(final GraphFactory graphFactory // Determine where to look for the GafferPop properties String gafferPopProperties = graphFactory.getGraph().getStoreProperties().get(GafferPopGraph.GAFFERPOP_PROPERTIES); if (gafferPopProperties == null) { - LOGGER.warn("GafferPop properties file was not specified using default location: {}", DEFAULT_PROPERTIES); + LOGGER.warn("GafferPop properties file was not specified. Using default location: {}", DEFAULT_PROPERTIES); gafferPopProperties = DEFAULT_PROPERTIES; } // Obtain the graph traversal From 4a4c4b1f93f075676a1973d49bdf698fca6847e3 Mon Sep 17 00:00:00 2001 From: cn337131 <141730190+cn337131@users.noreply.github.com> Date: Thu, 8 Aug 2024 13:53:51 +0000 Subject: [PATCH 14/16] Gh-3258: Sonarcloud Issues (#3261) * initial improvements * more test tidy up * more fixes * improve coverage * copyright * fix DeleteAllData test * checkstyle * address comments * address comments * checkstyle * checkstyle --------- Co-authored-by: wb36499 <166839644+wb36499@users.noreply.github.com> --- .../gaffer/commonutil/ByteBufferUtilTest.java | 32 ++- .../gaffer/commonutil/CloseableUtilTest.java | 19 +- .../gaffer/commonutil/CollectionUtilTest.java | 94 +++----- .../gchq/gaffer/commonutil/FieldUtilTest.java | 18 +- .../gchq/gaffer/commonutil/GroupUtilTest.java | 8 +- .../gchq/gaffer/commonutil/JsonAssert.java | 23 +- .../gchq/gaffer/commonutil/JsonUtilTest.java | 85 +++---- .../gchq/gaffer/commonutil/LongUtilTest.java | 6 +- .../gaffer/commonutil/PropertiesUtilTest.java | 25 +- .../gaffer/commonutil/StreamUtilTest.java | 11 +- .../gaffer/commonutil/StringUtilTest.java | 26 +-- .../commonutil/ToStringBuilderTest.java | 16 +- .../ArrayByteSequenceTest.java | 44 ++-- .../AuthorisationsTest.java | 59 +++-- .../ElementVisibilityTest.java | 47 ++-- .../VisibilityEvaluatorTest.java | 86 +++---- ...alidTrue.java => AlwaysValidTrueTest.java} | 14 +- .../iterable/CachingIterableTest.java | 16 +- .../iterable/ConsumableBlockingQueueTest.java | 69 +++--- .../iterable/EmptyIterableTest.java | 6 +- .../LimitedInMemorySortedIterableTest.java | 45 +++- .../iterable/RepeatItemIterableTest.java | 8 +- .../iterable/StreamIterableTest.java | 8 +- .../iterable/StreamIteratorTest.java | 6 +- .../iterable/SuppliedIterableTest.java | 8 +- .../iterable/TransformIterableTest.java | 41 +++- .../TransformOneToManyIterableTest.java | 16 +- .../gchq/gaffer/commonutil/pair/PairTest.java | 39 ++-- .../stream/GafferCollectorTest.java | 9 +- .../gaffer/commonutil/stream/StreamsTest.java | 12 +- .../hook/NamedOperationResolverTest.java | 216 +++++++++--------- .../store/operation/DeleteAllDataTest.java | 12 +- .../CustomMapSerialiserTest.java | 75 +++--- .../gchq/gaffer/cache/impl/JcsCacheTest.java | 50 ++-- .../loader/AddElementsFromHdfsLoaderIT.java | 10 +- .../RBMBackedTimestampSetSerialiserTest.java | 84 +++---- 36 files changed, 709 insertions(+), 634 deletions(-) rename core/common-util/src/test/java/uk/gov/gchq/gaffer/commonutil/iterable/{AlwaysValidTrue.java => AlwaysValidTrueTest.java} (78%) diff --git a/core/common-util/src/test/java/uk/gov/gchq/gaffer/commonutil/ByteBufferUtilTest.java b/core/common-util/src/test/java/uk/gov/gchq/gaffer/commonutil/ByteBufferUtilTest.java index 9b474d6bed5..073fdd86762 100644 --- a/core/common-util/src/test/java/uk/gov/gchq/gaffer/commonutil/ByteBufferUtilTest.java +++ b/core/common-util/src/test/java/uk/gov/gchq/gaffer/commonutil/ByteBufferUtilTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2017-2023 Crown Copyright + * Copyright 2017-2024 Crown Copyright * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -30,17 +30,16 @@ import static java.nio.charset.StandardCharsets.UTF_8; import static org.assertj.core.api.Assertions.assertThat; -import static org.junit.jupiter.api.Assertions.assertEquals; /** * This test class is copied from org.apache.accumulo.core.util.ByteByfferUtilTest. */ -public class ByteBufferUtilTest { +class ByteBufferUtilTest { private static final byte[] TEST_DATA_STRING = "0123456789".getBytes(UTF_8); @Test - public void testNonZeroArrayOffset() { + void testNonZeroArrayOffset() { final ByteBuffer bb1 = ByteBuffer.wrap(TEST_DATA_STRING, 3, 4); // create a ByteBuffer with a non-zero array offset @@ -49,9 +48,9 @@ public void testNonZeroArrayOffset() { // The purpose of this test is to ensure ByteBufferUtil code works when arrayOffset is non-zero. The following asserts are not to test ByteBuffer, but // ensure the behaviour of slice() is as expected. - assertEquals(3, bb2.arrayOffset()); - assertEquals(0, bb2.position()); - assertEquals(4, bb2.limit()); + assertThat(bb2.arrayOffset()).isEqualTo(3); + assertThat(bb2.position()).isZero(); + assertThat(bb2.limit()).isEqualTo(4); // start test with non zero arrayOffset assertByteBufferEquals("3456", bb2); @@ -62,21 +61,21 @@ public void testNonZeroArrayOffset() { } @Test - public void testZeroArrayOffsetAndNonZeroPosition() { + void testZeroArrayOffsetAndNonZeroPosition() { final ByteBuffer bb = ByteBuffer.wrap(TEST_DATA_STRING, 3, 4); assertByteBufferEquals("3456", bb); } @Test - public void testZeroArrayOffsetAndPosition() { + void testZeroArrayOffsetAndPosition() { final ByteBuffer bb = ByteBuffer.wrap(TEST_DATA_STRING, 0, 4); assertByteBufferEquals("0123", bb); } @Test - public void testDirectByteBuffer() { + void testDirectByteBuffer() { // allocate direct so it does not have a backing array final ByteBuffer bb = ByteBuffer.allocateDirect(10); bb.put(TEST_DATA_STRING); @@ -90,15 +89,14 @@ public void testDirectByteBuffer() { } private static void assertByteBufferEquals(final String expected, final ByteBuffer bb) { - assertEquals(expected, ByteBufferUtil.toString(bb)); - assertEquals(expected, new String(ByteBufferUtil.toBytes(bb), UTF_8)); - assertEquals(expected, ByteBufferUtil.toString(bb)); + assertThat(ByteBufferUtil.toString(bb)).isEqualTo(expected); + assertThat(new String(ByteBufferUtil.toBytes(bb), UTF_8)).isEqualTo(expected); List bal = ByteBufferUtil.toBytesList(Collections.singletonList(bb)); assertThat(bal).hasSize(1); - assertEquals(expected, new String(bal.get(0), UTF_8)); + assertThat(new String(bal.get(0), UTF_8)).isEqualTo(expected); - assertEquals(new ArrayByteSequence(expected), new ArrayByteSequence(bb)); + assertThat(new ArrayByteSequence(bb)).isEqualTo(new ArrayByteSequence(expected)); ByteArrayOutputStream baos = new ByteArrayOutputStream(); DataOutputStream dos = new DataOutputStream(baos); @@ -109,13 +107,13 @@ private static void assertByteBufferEquals(final String expected, final ByteBuff throw new RuntimeException(e); } - assertEquals(expected, new String(baos.toByteArray(), UTF_8)); + assertThat(new String(baos.toByteArray(), UTF_8)).isEqualTo(expected); ByteArrayInputStream bais = ByteBufferUtil.toByteArrayInputStream(bb); byte[] buffer = new byte[expected.length()]; try { bais.read(buffer); - assertEquals(expected, new String(buffer, UTF_8)); + assertThat(new String(buffer, UTF_8)).isEqualTo(expected); } catch (IOException e) { throw new RuntimeException(e); } diff --git a/core/common-util/src/test/java/uk/gov/gchq/gaffer/commonutil/CloseableUtilTest.java b/core/common-util/src/test/java/uk/gov/gchq/gaffer/commonutil/CloseableUtilTest.java index f444c1aae48..e021379e443 100644 --- a/core/common-util/src/test/java/uk/gov/gchq/gaffer/commonutil/CloseableUtilTest.java +++ b/core/common-util/src/test/java/uk/gov/gchq/gaffer/commonutil/CloseableUtilTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2017-2021 Crown Copyright + * Copyright 2017-2024 Crown Copyright * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -28,10 +28,10 @@ import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; -public class CloseableUtilTest { +class CloseableUtilTest { @Test - public void shouldCloseACloseable() throws IOException { + void shouldCloseACloseable() throws IOException { final Closeable closeable = mock(Closeable.class); CloseableUtil.close(closeable); @@ -40,7 +40,7 @@ public void shouldCloseACloseable() throws IOException { } @Test - public void shouldCloseAllCloseables() throws IOException { + void shouldCloseAllCloseables() throws IOException { final Closeable closeable1 = mock(Closeable.class); final Closeable closeable2 = mock(Closeable.class); final Object nonCloseable = mock(Object.class); @@ -51,10 +51,19 @@ public void shouldCloseAllCloseables() throws IOException { verify(closeable2).close(); } + @Test + void shouldCloseAutoCloseables() throws Exception { + final AutoCloseable autoCloseable = mock(AutoCloseable.class); + + CloseableUtil.close(autoCloseable); + + verify(autoCloseable).close(); + } + @ParameterizedTest @NullSource @ValueSource(strings = {"Some string"}) - public void shouldNotThrowExceptionForNullOrStringObject(Object obj) { + void shouldNotThrowExceptionForNullOrStringObject(Object obj) { assertThatNoException().isThrownBy(() -> CloseableUtil.close(obj)); } } diff --git a/core/common-util/src/test/java/uk/gov/gchq/gaffer/commonutil/CollectionUtilTest.java b/core/common-util/src/test/java/uk/gov/gchq/gaffer/commonutil/CollectionUtilTest.java index 962da073307..9df6e041066 100644 --- a/core/common-util/src/test/java/uk/gov/gchq/gaffer/commonutil/CollectionUtilTest.java +++ b/core/common-util/src/test/java/uk/gov/gchq/gaffer/commonutil/CollectionUtilTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2017-2021 Crown Copyright + * Copyright 2017-2024 Crown Copyright * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -27,14 +27,11 @@ import java.util.TreeSet; import static org.assertj.core.api.Assertions.assertThat; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertFalse; -import static org.junit.jupiter.api.Assertions.assertTrue; -public class CollectionUtilTest { +class CollectionUtilTest { @Test - public void shouldReturnTreeSetWithProvidedItem() { + void shouldReturnTreeSetWithProvidedItem() { final String item = "test item"; final TreeSet treeSet = CollectionUtil.treeSet(item); @@ -44,14 +41,14 @@ public void shouldReturnTreeSetWithProvidedItem() { } @Test - public void shouldReturnTreeSetWithWithOutNullItem() { - final TreeSet treeSet = CollectionUtil.treeSet(null); + void shouldReturnTreeSetWithWithOutNullItem() { + final TreeSet treeSet = CollectionUtil.treeSet((String) null); assertThat(treeSet).isEmpty(); } @Test - public void shouldReturnTreeSetWithProvidedItems() { + void shouldReturnTreeSetWithProvidedItems() { final String[] items = {"test item 1", "test item 2", null}; final TreeSet treeSet = CollectionUtil.treeSet(items); @@ -65,14 +62,7 @@ public void shouldReturnTreeSetWithProvidedItems() { } @Test - public void shouldReturnTreeSetWithNoItemsForNullArray() { - final TreeSet treeSet = CollectionUtil.treeSet(null); - - assertThat(treeSet).isEmpty(); - } - - @Test - public void shouldConvertMapToStringKeys() { + void shouldConvertMapToStringKeys() { // Given final Map, String> map = new HashMap<>(); populateClassKeyMap(map); @@ -83,11 +73,11 @@ public void shouldConvertMapToStringKeys() { // Then final Map expectedResult = new HashMap<>(); populateStringKeyMap(expectedResult); - assertEquals(expectedResult, result); + assertThat(result).isEqualTo(expectedResult); } @Test - public void shouldConvertMapToStringKeysWithProvidedMap() { + void shouldConvertMapToStringKeysWithProvidedMap() { // Given final Map, String> map = new HashMap<>(); populateClassKeyMap(map); @@ -100,11 +90,11 @@ public void shouldConvertMapToStringKeysWithProvidedMap() { // Then final Map expectedResult = new LinkedHashMap<>(); populateStringKeyMap(expectedResult); - assertEquals(expectedResult, result); + assertThat(result).isEqualTo(expectedResult); } @Test - public void shouldConvertMapToClassKeys() throws ClassNotFoundException { + void shouldConvertMapToClassKeys() throws ClassNotFoundException { // Given final Map map = new HashMap<>(); populateStringKeyMap(map); @@ -115,11 +105,11 @@ public void shouldConvertMapToClassKeys() throws ClassNotFoundException { // Then final Map, String> expectedResult = new HashMap<>(); populateClassKeyMap(expectedResult); - assertEquals(expectedResult, result); + assertThat(result).isEqualTo(expectedResult); } @Test - public void shouldConvertMapToClassKeysWithProvidedMap() throws ClassNotFoundException { + void shouldConvertMapToClassKeysWithProvidedMap() throws ClassNotFoundException { // Given final Map map = new HashMap<>(); populateStringKeyMap(map); @@ -132,11 +122,11 @@ public void shouldConvertMapToClassKeysWithProvidedMap() throws ClassNotFoundExc // Then final Map, String> expectedResult = new LinkedHashMap<>(); populateClassKeyMap(expectedResult); - assertEquals(expectedResult, result); + assertThat(result).isEqualTo(expectedResult); } @Test - public void shouldReturnTrueWhenCollectionContainsAProvidedValue() { + void shouldReturnTrueWhenCollectionContainsAProvidedValue() { // Given final Collection collection = Sets.newHashSet(10, 20, 2, 30); final Object[] values = new Object[] {1, 2, 3}; @@ -145,11 +135,11 @@ public void shouldReturnTrueWhenCollectionContainsAProvidedValue() { final boolean result = CollectionUtil.containsAny(collection, values); // Then - assertTrue(result); + assertThat(result).isTrue(); } @Test - public void shouldReturnFalseWhenCollectionDoesNotContainsAProvidedValue() { + void shouldReturnFalseWhenCollectionDoesNotContainsAProvidedValue() { // Given final Collection collection = Sets.newHashSet(10, 20, 30); final Object[] values = new Object[] {1, 2, 3}; @@ -158,11 +148,11 @@ public void shouldReturnFalseWhenCollectionDoesNotContainsAProvidedValue() { final boolean result = CollectionUtil.containsAny(collection, values); // Then - assertFalse(result); + assertThat(result).isFalse(); } @Test - public void shouldReturnFalseWhenContainsAnyCalledWithNullValue() { + void shouldReturnFalseWhenContainsAnyCalledWithNullValue() { // Given final Collection collection = Sets.newHashSet(10, 20, 30); @@ -170,20 +160,20 @@ public void shouldReturnFalseWhenContainsAnyCalledWithNullValue() { final boolean result = CollectionUtil.containsAny(collection, null); // Then - assertFalse(result); + assertThat(result).isFalse(); } @Test - public void shouldReturnFalseWhenContainsAnyCalledWithNullCollection() { + void shouldReturnFalseWhenContainsAnyCalledWithNullCollection() { final Object[] values = new Object[] {1, 2, 3}; final boolean result = CollectionUtil.containsAny(null, values); - assertFalse(result); + assertThat(result).isFalse(); } @Test - public void shouldReturnFalseWhenAnyMissingCalledWhenTheCollectionContainsAllValues() { + void shouldReturnFalseWhenAnyMissingCalledWhenTheCollectionContainsAllValues() { // Given final Collection collection = Sets.newHashSet(10, 20, 30); final Object[] values = new Object[] {10, 20, 30}; @@ -192,11 +182,11 @@ public void shouldReturnFalseWhenAnyMissingCalledWhenTheCollectionContainsAllVal final boolean result = CollectionUtil.anyMissing(collection, values); // Then - assertFalse(result); + assertThat(result).isFalse(); } @Test - public void shouldReturnFalseWhenAnyMissingCalledWhenNullValues() { + void shouldReturnFalseWhenAnyMissingCalledWhenNullValues() { // Given final Collection collection = Sets.newHashSet(10, 20, 30); @@ -204,11 +194,11 @@ public void shouldReturnFalseWhenAnyMissingCalledWhenNullValues() { final boolean result = CollectionUtil.anyMissing(collection, null); // Then - assertFalse(result); + assertThat(result).isFalse(); } @Test - public void shouldReturnTrueWhenAnyMissingCalledWhenTheCollectionDoesNotContainAProvidedValue() { + void shouldReturnTrueWhenAnyMissingCalledWhenTheCollectionDoesNotContainAProvidedValue() { // Given final Collection collection = Sets.newHashSet(10, 20, 30); final Object[] values = new Object[] {1, 2, 3}; @@ -217,23 +207,11 @@ public void shouldReturnTrueWhenAnyMissingCalledWhenTheCollectionDoesNotContainA final boolean result = CollectionUtil.anyMissing(collection, values); // Then - assertTrue(result); - } - - @Test - public void shouldReturnFalseWhenAnyMissingCalledWithNullValue() { - // Given - final Collection collection = Sets.newHashSet(10, 20, 30); - - // When - final boolean result = CollectionUtil.anyMissing(collection, null); - - // Then - assertFalse(result); + assertThat(result).isTrue(); } @Test - public void shouldReturnTrueWhenAnyMissingCalledWithNullCollectionAndSomeValues() { + void shouldReturnTrueWhenAnyMissingCalledWithNullCollectionAndSomeValues() { // Given final Object[] values = new Object[] {1, 2, 3}; @@ -241,20 +219,20 @@ public void shouldReturnTrueWhenAnyMissingCalledWithNullCollectionAndSomeValues( final boolean result = CollectionUtil.anyMissing(null, values); // Then - assertTrue(result); + assertThat(result).isTrue(); } @Test - public void shouldReturnFalseWhenAnyMissingCalledWithNullCollectionAndValues() { + void shouldReturnFalseWhenAnyMissingCalledWithNullCollectionAndValues() { // When final boolean result = CollectionUtil.anyMissing(null, null); // Then - assertFalse(result); + assertThat(result).isFalse(); } @Test - public void shouldReturnTrueWhenDistinctCalledWithCollectionOfUniqueValues() { + void shouldReturnTrueWhenDistinctCalledWithCollectionOfUniqueValues() { // Given final Collection collection = Lists.newArrayList(1, 2, 3, 4, 5); @@ -262,11 +240,11 @@ public void shouldReturnTrueWhenDistinctCalledWithCollectionOfUniqueValues() { final boolean result = CollectionUtil.distinct(collection); // Then - assertTrue(result); + assertThat(result).isTrue(); } @Test - public void shouldReturnFalseWhenDistinctCalledWithCollectionOfNonUniqueValues() { + void shouldReturnFalseWhenDistinctCalledWithCollectionOfNonUniqueValues() { // Given final Collection collection = Lists.newArrayList(1, 2, 3, 1, 2); @@ -274,7 +252,7 @@ public void shouldReturnFalseWhenDistinctCalledWithCollectionOfNonUniqueValues() final boolean result = CollectionUtil.distinct(collection); // Then - assertFalse(result); + assertThat(result).isFalse(); } private void populateClassKeyMap(Map, String> map) { diff --git a/core/common-util/src/test/java/uk/gov/gchq/gaffer/commonutil/FieldUtilTest.java b/core/common-util/src/test/java/uk/gov/gchq/gaffer/commonutil/FieldUtilTest.java index 0d6bfd63fb6..fe7597b0751 100644 --- a/core/common-util/src/test/java/uk/gov/gchq/gaffer/commonutil/FieldUtilTest.java +++ b/core/common-util/src/test/java/uk/gov/gchq/gaffer/commonutil/FieldUtilTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2019-2020 Crown Copyright + * Copyright 2019-2024 Crown Copyright * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -24,28 +24,28 @@ import java.util.LinkedHashSet; import java.util.Set; -import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.assertj.core.api.Assertions.assertThat; -public class FieldUtilTest { +class FieldUtilTest { @Test - public void testNullField() { - final Pair nullPair = new Pair("Test", null); + void testNullField() { + final Pair nullPair = new Pair("Test", null); final ValidationResult validationResult = FieldUtil.validateRequiredFields(nullPair); final Set expected = new LinkedHashSet<>(); expected.add("Test is required."); - assertEquals(expected, validationResult.getErrors()); + assertThat(validationResult.getErrors()).isEqualTo(expected); } @Test - public void testNotNullField() { - final Pair nonNullPair = new Pair("Test", "Test"); + void testNotNullField() { + final Pair nonNullPair = new Pair("Test", "Test"); final ValidationResult validationResult = FieldUtil.validateRequiredFields(nonNullPair); final Set expected = new LinkedHashSet<>(); - assertEquals(expected, validationResult.getErrors()); + assertThat(validationResult.getErrors()).isEqualTo(expected); } } diff --git a/core/common-util/src/test/java/uk/gov/gchq/gaffer/commonutil/GroupUtilTest.java b/core/common-util/src/test/java/uk/gov/gchq/gaffer/commonutil/GroupUtilTest.java index 5599ec7aefa..3eeb7084091 100644 --- a/core/common-util/src/test/java/uk/gov/gchq/gaffer/commonutil/GroupUtilTest.java +++ b/core/common-util/src/test/java/uk/gov/gchq/gaffer/commonutil/GroupUtilTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2017-2021 Crown Copyright + * Copyright 2017-2024 Crown Copyright * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -21,19 +21,19 @@ import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException; import static org.assertj.core.api.Assertions.assertThatNoException; -public class GroupUtilTest { +class GroupUtilTest { private static final String INVALID_STRING = "inv@l1dStr|ng&^"; private static final String VALID_STRING = "vAl1d-Str|ng"; @Test - public void shouldThrowExceptionWithInvalidStringName() { + void shouldThrowExceptionWithInvalidStringName() { assertThatIllegalArgumentException() .isThrownBy(() -> GroupUtil.validateName(INVALID_STRING)) .withMessage("Group is invalid: inv@l1dStr|ng&^, it must match regex: [a-zA-Z0-9|-]*"); } @Test - public void shouldPassValidationWithValidStringName() { + void shouldPassValidationWithValidStringName() { assertThatNoException().isThrownBy(() -> GroupUtil.validateName(VALID_STRING)); } } diff --git a/core/common-util/src/test/java/uk/gov/gchq/gaffer/commonutil/JsonAssert.java b/core/common-util/src/test/java/uk/gov/gchq/gaffer/commonutil/JsonAssert.java index d29353347b7..df55289db70 100644 --- a/core/common-util/src/test/java/uk/gov/gchq/gaffer/commonutil/JsonAssert.java +++ b/core/common-util/src/test/java/uk/gov/gchq/gaffer/commonutil/JsonAssert.java @@ -1,5 +1,5 @@ /* - * Copyright 2016-2020 Crown Copyright + * Copyright 2016-2024 Crown Copyright * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -17,7 +17,8 @@ package uk.gov.gchq.gaffer.commonutil; import com.fasterxml.jackson.databind.ObjectMapper; -import org.junit.jupiter.api.Assertions; + +import static org.assertj.core.api.Assertions.assertThat; import java.io.IOException; import java.util.Collections; @@ -33,18 +34,18 @@ private JsonAssert() { public static void assertEquals(final String expectedJson, final String actualJson) { try { - final Map expectedSchemaMap = null != expectedJson ? OBJECT_MAPPER.readValue(expectedJson, Map.class) : Collections.emptyMap(); - final Map actualSchemaMap = null != actualJson ? OBJECT_MAPPER.readValue(actualJson, Map.class) : Collections.emptyMap(); - Assertions.assertEquals(expectedSchemaMap, actualSchemaMap); + final Map expectedSchemaMap = expectedJson != null ? OBJECT_MAPPER.readValue(expectedJson, Map.class) : Collections.emptyMap(); + final Map actualSchemaMap = actualJson != null ? OBJECT_MAPPER.readValue(actualJson, Map.class) : Collections.emptyMap(); + assertThat(actualSchemaMap).isEqualTo(expectedSchemaMap); return; } catch (final IOException e) { // ignore the error and try using lists instead } try { - final List expectedSchemaMap = null != expectedJson ? OBJECT_MAPPER.readValue(expectedJson, List.class) : Collections.emptyList(); - final List actualSchemaMap = null != actualJson ? OBJECT_MAPPER.readValue(actualJson, List.class) : Collections.emptyList(); - Assertions.assertEquals(expectedSchemaMap, actualSchemaMap); + final List expectedSchemaMap = expectedJson != null ? OBJECT_MAPPER.readValue(expectedJson, List.class) : Collections.emptyList(); + final List actualSchemaMap = actualJson != null ? OBJECT_MAPPER.readValue(actualJson, List.class) : Collections.emptyList(); + assertThat(actualSchemaMap).isEqualTo(expectedSchemaMap); } catch (final IOException e) { throw new AssertionError(expectedJson + " is not equal to " + actualJson, e); } @@ -56,9 +57,9 @@ public static void assertEquals(final byte[] expectedJson, final byte[] actualJs public static void assertNotEqual(final String firstJson, final String secondJson) { try { - final Map firstSchemaMap = null != firstJson ? OBJECT_MAPPER.readValue(firstJson, Map.class) : Collections.emptyMap(); - final Map secondSchemaMap = null != secondJson ? OBJECT_MAPPER.readValue(secondJson, Map.class) : Collections.emptyMap(); - Assertions.assertNotEquals(firstSchemaMap, secondSchemaMap); + final Map firstSchemaMap = firstJson != null ? OBJECT_MAPPER.readValue(firstJson, Map.class) : Collections.emptyMap(); + final Map secondSchemaMap = secondJson != null ? OBJECT_MAPPER.readValue(secondJson, Map.class) : Collections.emptyMap(); + assertThat(firstSchemaMap).isNotEqualTo(secondSchemaMap); } catch (final IOException e) { // ignore } diff --git a/core/common-util/src/test/java/uk/gov/gchq/gaffer/commonutil/JsonUtilTest.java b/core/common-util/src/test/java/uk/gov/gchq/gaffer/commonutil/JsonUtilTest.java index 8ce62ecc67a..1d1c2eacb64 100644 --- a/core/common-util/src/test/java/uk/gov/gchq/gaffer/commonutil/JsonUtilTest.java +++ b/core/common-util/src/test/java/uk/gov/gchq/gaffer/commonutil/JsonUtilTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2017-2020 Crown Copyright + * Copyright 2017-2024 Crown Copyright * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -13,94 +13,69 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + package uk.gov.gchq.gaffer.commonutil; import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; + +import static org.assertj.core.api.Assertions.assertThat; -import static org.junit.jupiter.api.Assertions.assertFalse; -import static org.junit.jupiter.api.Assertions.assertTrue; +import java.util.stream.Stream; -public class JsonUtilTest { +class JsonUtilTest { @Test - public void shouldReturnTrueWhenJsonObjectsAreEqualButInADifferentOrder() { + void shouldReturnTrueWhenJsonObjectsAreEqualButInADifferentOrder() { final String json1 = "{\"a\": 1, \"b\": 2}"; final String json2 = "{\"b\": 2, \"a\": 1}"; - assertTrue(JsonUtil.equals(json1, json2)); - assertTrue(JsonUtil.equals(json1.getBytes(), json2.getBytes())); + assertThat(JsonUtil.equals(json1, json2)).isTrue(); + assertThat(JsonUtil.equals(json1.getBytes(), json2.getBytes())).isTrue(); JsonAssert.assertEquals(json1, json2); JsonAssert.assertEquals(json1.getBytes(), json2.getBytes()); } @Test - public void shouldReturnFalseWhenJsonObjectsAreDifferentSizes() { - final String json1 = "{\"a\": 1, \"b\": 2}"; - final String json2 = "{\"a\": 1, \"b\": 2, \"c\": 3}"; - - assertFalse(JsonUtil.equals(json1, json2)); - assertFalse(JsonUtil.equals(json1.getBytes(), json2.getBytes())); - - JsonAssert.assertNotEqual(json1, json2); - JsonAssert.assertNotEqual(json1.getBytes(), json2.getBytes()); - } - - @Test - public void shouldReturnFalseWhenJsonObjectsAreNotEqual() { - final String json1 = "{\"a\": 1, \"b\": 2}"; - final String json2 = "{\"a\": 1, \"b\": 3}"; - - assertFalse(JsonUtil.equals(json1, json2)); - assertFalse(JsonUtil.equals(json1.getBytes(), json2.getBytes())); - - JsonAssert.assertNotEqual(json1, json2); - JsonAssert.assertNotEqual(json1.getBytes(), json2.getBytes()); - } - - @Test - public void shouldReturnTrueWhenJsonArraysAreEqual() { + void shouldReturnTrueWhenJsonArraysAreEqual() { final String json1 = "[1,2,3]"; final String json2 = "[1,2,3]"; - assertTrue(JsonUtil.equals(json1, json2)); - assertTrue(JsonUtil.equals(json1.getBytes(), json2.getBytes())); + assertThat(JsonUtil.equals(json1, json2)).isTrue(); + assertThat(JsonUtil.equals(json1.getBytes(), json2.getBytes())).isTrue(); JsonAssert.assertEquals(json1, json2); JsonAssert.assertEquals(json1.getBytes(), json2.getBytes()); } - @Test - public void shouldReturnFalseWhenJsonArraysAreNotEqual() { - // Given - final String json1 = "[1,2,3]"; - final String json2 = "[1,2,4]"; - - assertFalse(JsonUtil.equals(json1, json2)); - assertFalse(JsonUtil.equals(json1.getBytes(), json2.getBytes())); + @ParameterizedTest + @MethodSource("provideJSONStrings") + void shouldReturnFalse(String json1, String json2) { + assertThat(JsonUtil.equals(json1, json2)).isFalse(); + assertThat(JsonUtil.equals(json1.getBytes(), json2.getBytes())).isFalse(); JsonAssert.assertNotEqual(json1, json2); JsonAssert.assertNotEqual(json1.getBytes(), json2.getBytes()); } - @Test - public void shouldReturnFalseWhenJsonArraysAreDifferentSizes() { - final String json1 = "[1,2,3]"; - final String json2 = "[1,2,3,4]"; - - assertFalse(JsonUtil.equals(json1, json2)); - assertFalse(JsonUtil.equals(json1.getBytes(), json2.getBytes())); - - JsonAssert.assertNotEqual(json1, json2); - JsonAssert.assertNotEqual(json1.getBytes(), json2.getBytes()); + private static Stream provideJSONStrings() { + return Stream.of( + Arguments.of("{\"a\": 1, \"b\": 2}", "{\"a\": 1, \"b\": 2, \"c\": 3}"), + Arguments.of("{\"a\": 1, \"b\": 2}", "{\"a\": 1, \"b\": 3}"), + Arguments.of("[1,2,3]", "[1,2,4]"), + Arguments.of("[1,2,3]", "[1,2,3,4]") + ); } @Test - public void shouldReturnFalseWhenActualObjectIsNull() { + void shouldReturnFalseWhenActualObjectIsNull() { final String json1 = "{\"a\": 1, \"b\": 2}"; - assertFalse(JsonUtil.equals(json1, null)); - assertFalse(JsonUtil.equals(json1.getBytes(), null)); + assertThat(JsonUtil.equals(json1, null)).isFalse(); + assertThat(JsonUtil.equals(json1.getBytes(), null)).isFalse(); JsonAssert.assertNotEqual(json1, null); JsonAssert.assertNotEqual(json1.getBytes(), null); diff --git a/core/common-util/src/test/java/uk/gov/gchq/gaffer/commonutil/LongUtilTest.java b/core/common-util/src/test/java/uk/gov/gchq/gaffer/commonutil/LongUtilTest.java index e8d803bd5e6..6115ca5c69f 100644 --- a/core/common-util/src/test/java/uk/gov/gchq/gaffer/commonutil/LongUtilTest.java +++ b/core/common-util/src/test/java/uk/gov/gchq/gaffer/commonutil/LongUtilTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2017-2021 Crown Copyright + * Copyright 2017-2024 Crown Copyright * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -23,10 +23,10 @@ import static org.assertj.core.api.Assertions.assertThat; -public class LongUtilTest { +class LongUtilTest { @Test - public void shouldGetDifferentPositiveTimeBasedRandoms() { + void shouldGetDifferentPositiveTimeBasedRandoms() { final int n = 1000; final Set timestamps = new HashSet<>(n); diff --git a/core/common-util/src/test/java/uk/gov/gchq/gaffer/commonutil/PropertiesUtilTest.java b/core/common-util/src/test/java/uk/gov/gchq/gaffer/commonutil/PropertiesUtilTest.java index aef6acbf8ef..a4ffa83ee68 100644 --- a/core/common-util/src/test/java/uk/gov/gchq/gaffer/commonutil/PropertiesUtilTest.java +++ b/core/common-util/src/test/java/uk/gov/gchq/gaffer/commonutil/PropertiesUtilTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2017-2021 Crown Copyright + * Copyright 2017-2024 Crown Copyright * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -18,22 +18,39 @@ import org.junit.jupiter.api.Test; +import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException; import static org.assertj.core.api.Assertions.assertThatNoException; -public class PropertiesUtilTest { +class PropertiesUtilTest { private static final String INVALID_STRING = "inv@l1dStr|ng&^"; private static final String VALID_STRING = "vAl1d-Str|ng"; @Test - public void shouldThrowExceptionWithInvalidStringName() { + void shouldThrowExceptionWithInvalidStringName() { assertThatIllegalArgumentException() .isThrownBy(() -> PropertiesUtil.validateName(INVALID_STRING)) .withMessage("Property is invalid: inv@l1dStr|ng&^, it must match regex: [a-zA-Z0-9|-]*"); } @Test - public void shouldPassValidationWithValidStringName() { + void shouldPassValidationWithValidStringName() { assertThatNoException().isThrownBy(() -> PropertiesUtil.validateName(VALID_STRING)); } + + @Test + void shouldBeFalseWithInvalidStringName() { + assertThat(PropertiesUtil.isValidName(INVALID_STRING)).isFalse(); + } + + @Test + void shouldBeTrueWithValidStringName() { + assertThat(PropertiesUtil.isValidName(VALID_STRING)).isTrue(); + } + + @Test + void shouldStripInvalidCharacters() { + final String expectedString = "invl1dStr|ng"; + assertThat(PropertiesUtil.stripInvalidCharacters(INVALID_STRING)).isEqualTo(expectedString); + } } diff --git a/core/common-util/src/test/java/uk/gov/gchq/gaffer/commonutil/StreamUtilTest.java b/core/common-util/src/test/java/uk/gov/gchq/gaffer/commonutil/StreamUtilTest.java index 420bf7e1275..18ca1e25db6 100644 --- a/core/common-util/src/test/java/uk/gov/gchq/gaffer/commonutil/StreamUtilTest.java +++ b/core/common-util/src/test/java/uk/gov/gchq/gaffer/commonutil/StreamUtilTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2017-2021 Crown Copyright + * Copyright 2017-2024 Crown Copyright * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -13,6 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + package uk.gov.gchq.gaffer.commonutil; import org.junit.jupiter.api.Test; @@ -23,12 +24,12 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.junit.jupiter.api.Assertions.fail; -public class StreamUtilTest { +class StreamUtilTest { public static final String FILE_NAME = "URLSchema.json"; @Test - public void testOpenStreamsURLNotEmpty() throws Exception { + void testOpenStreamsURLNotEmpty() throws Exception { final URI resource = getClass().getClassLoader().getResource(FILE_NAME).toURI(); if (null == resource) { fail("Test json file not found:" + FILE_NAME); @@ -37,8 +38,8 @@ public void testOpenStreamsURLNotEmpty() throws Exception { final InputStream[] inputStreams = StreamUtil.openStreams(resource); assertThat(inputStreams) - .isNotEmpty() - .overridingErrorMessage("InputStreams length is %s", 0); + .overridingErrorMessage("InputStreams length is %s", 0) + .isNotEmpty(); StreamUtil.closeStreams(inputStreams); } diff --git a/core/common-util/src/test/java/uk/gov/gchq/gaffer/commonutil/StringUtilTest.java b/core/common-util/src/test/java/uk/gov/gchq/gaffer/commonutil/StringUtilTest.java index 06cec46c3e8..f02d96edcc9 100644 --- a/core/common-util/src/test/java/uk/gov/gchq/gaffer/commonutil/StringUtilTest.java +++ b/core/common-util/src/test/java/uk/gov/gchq/gaffer/commonutil/StringUtilTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2018-2020 Crown Copyright + * Copyright 2018-2024 Crown Copyright * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -25,64 +25,64 @@ import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNull; -public class StringUtilTest { +class StringUtilTest { @Test - public void unescapeCommaShouldReplaceBackslashesWithComma() { + void unescapeCommaShouldReplaceBackslashesWithComma() { assertEquals("replaceBackslashesWith,Comma", StringUtil.unescapeComma("replaceBackslashesWith\\\\Comma")); } @Test - public void unescapeCommaShouldNotRemoveSemicolon() { + void unescapeCommaShouldNotRemoveSemicolon() { assertEquals("don'tRemove;SemiColon", StringUtil.unescapeComma("don'tRemove;SemiColon")); } @Test - public void unescapeCommaShouldNotRemoveComma() { + void unescapeCommaShouldNotRemoveComma() { assertEquals("don'tRemove,Comma", StringUtil.unescapeComma("don'tRemove,Comma")); } @Test - public void unescapeCommaShouldRemoveBackslash() { + void unescapeCommaShouldRemoveBackslash() { assertEquals("removeBackslash", StringUtil.unescapeComma("remove\\Backslash")); } @Test - public void escapeCommaShouldReplaceBackslashWithSemiColon() { + void escapeCommaShouldReplaceBackslashWithSemiColon() { assertEquals("replaceWith\\;semicolon", StringUtil.escapeComma("replaceWith\\semicolon")); } @Test - public void escapeCommaShouldReplaceCommaWith2Backslashes() { + void escapeCommaShouldReplaceCommaWith2Backslashes() { assertEquals("replaceWith\\\\comma", StringUtil.escapeComma("replaceWith,comma")); } @Test - public void toBytesWhenStringIsValid() { + void toBytesWhenStringIsValid() { assertArrayEquals("isValid".getBytes(), StringUtil.toBytes("isValid")); } @Test - public void toBytesWhenStringIsNull() { + void toBytesWhenStringIsNull() { assertArrayEquals(new byte[0], StringUtil.toBytes(null)); } @Test - public void toStringWhenBytesAreValid() { + void toStringWhenBytesAreValid() { final byte[] validBytes = "isValid".getBytes(); assertEquals("isValid", StringUtil.toString(validBytes)); } @Test - public void ifEmptyStringTestReturnNull() { + void ifEmptyStringTestReturnNull() { assertNull(StringUtil.nullIfEmpty("")); } @ParameterizedTest @NullSource @ValueSource(strings = {" ", "String", " string "}) - public void shouldReturnValueWhenNotEmptyString(String input) { + void shouldReturnValueWhenNotEmptyString(String input) { assertEquals(input, StringUtil.nullIfEmpty(input)); } } diff --git a/core/common-util/src/test/java/uk/gov/gchq/gaffer/commonutil/ToStringBuilderTest.java b/core/common-util/src/test/java/uk/gov/gchq/gaffer/commonutil/ToStringBuilderTest.java index fcfc17c80c0..faf300ce53e 100644 --- a/core/common-util/src/test/java/uk/gov/gchq/gaffer/commonutil/ToStringBuilderTest.java +++ b/core/common-util/src/test/java/uk/gov/gchq/gaffer/commonutil/ToStringBuilderTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2017-2020 Crown Copyright + * Copyright 2017-2024 Crown Copyright * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -20,12 +20,12 @@ import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; -import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.assertj.core.api.Assertions.assertThat; -public class ToStringBuilderTest { +class ToStringBuilderTest { @BeforeEach - public void setUp() throws Exception { + public void setUp() { clearDebugModeProperty(); } @@ -35,19 +35,19 @@ public void after() { } @Test - public void testDebugOffToStringBuilder() { + void testDebugOffToStringBuilder() { setDebugMode("false"); ToStringBuilder toStringBuilder = new ToStringBuilder("Test String"); - assertEquals(ToStringBuilder.SHORT_STYLE, toStringBuilder.getStyle()); + assertThat(toStringBuilder.getStyle()).isEqualTo(ToStringBuilder.SHORT_STYLE); } @Test - public void testDebugOnToStringBuilder() { + void testDebugOnToStringBuilder() { setDebugMode("true"); ToStringBuilder toStringBuilder = new ToStringBuilder("Test String"); - assertEquals(ToStringBuilder.FULL_STYLE, toStringBuilder.getStyle()); + assertThat(toStringBuilder.getStyle()).isEqualTo(ToStringBuilder.FULL_STYLE); } private void setDebugMode(final String value) { diff --git a/core/common-util/src/test/java/uk/gov/gchq/gaffer/commonutil/elementvisibilityutil/ArrayByteSequenceTest.java b/core/common-util/src/test/java/uk/gov/gchq/gaffer/commonutil/elementvisibilityutil/ArrayByteSequenceTest.java index f3f4aa0bdef..996385f7759 100644 --- a/core/common-util/src/test/java/uk/gov/gchq/gaffer/commonutil/elementvisibilityutil/ArrayByteSequenceTest.java +++ b/core/common-util/src/test/java/uk/gov/gchq/gaffer/commonutil/elementvisibilityutil/ArrayByteSequenceTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2017-2021 Crown Copyright + * Copyright 2017-2024 Crown Copyright * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -21,13 +21,13 @@ import java.nio.ByteBuffer; +import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException; -import static org.junit.jupiter.api.Assertions.assertEquals; /** * This test class is copied from org.apache.accumulo.core.data.ArrayByteSequenceTest. */ -public class ArrayByteSequenceTest { +class ArrayByteSequenceTest { ArrayByteSequence abs; byte[] data; @@ -39,74 +39,76 @@ public void setUp() { } @Test - public void testInvalidByteBufferBounds0ShouldThrowIAX() { + void testInvalidByteBufferBounds0ShouldThrowIAX() { assertThatIllegalArgumentException().isThrownBy(() -> abs = new ArrayByteSequence(data, -1, 0)); } @Test - public void testInvalidByteBufferBounds1ShouldThrowIAX() { + void testInvalidByteBufferBounds1ShouldThrowIAX() { assertThatIllegalArgumentException().isThrownBy(() -> abs = new ArrayByteSequence(data, data.length + 1, 0)); } @Test - public void testInvalidByteBufferBounds2ShouldThrowIAX() { + void testInvalidByteBufferBounds2ShouldThrowIAX() { assertThatIllegalArgumentException().isThrownBy(() -> abs = new ArrayByteSequence(data, 0, -1)); } @Test - public void testInvalidByteBufferBounds3ShouldThrowIAX() { + void testInvalidByteBufferBounds3ShouldThrowIAX() { assertThatIllegalArgumentException().isThrownBy(() -> abs = new ArrayByteSequence(data, 6, 2)); } @Test - public void testInvalidByteAt0ShouldThrowIAX() { + void testInvalidByteAt0ShouldThrowIAX() { assertThatIllegalArgumentException().isThrownBy(() -> abs.byteAt(-1)); } @Test - public void testInvalidByteAt1ShouldThrowIAX() { + void testInvalidByteAt1ShouldThrowIAX() { assertThatIllegalArgumentException().isThrownBy(() -> abs.byteAt(data.length)); } @Test - public void testSubSequence() { - assertEquals(0, abs.subSequence(0, 0).length()); - assertEquals("mile", abs.subSequence(1, 5).toString()); + void testSubSequence() { + assertThat(abs.subSequence(0, 0).length()).isZero(); + assertThat(abs.subSequence(1, 5)).hasToString("mile"); } @Test - public void testInvalidSubsequence0ShouldThrowIAX() { + void testInvalidSubsequence0ShouldThrowIAX() { assertThatIllegalArgumentException().isThrownBy(() -> abs.subSequence(5, 1)); } @Test - public void testInvalidSubsequence1ShouldThrowIAX() { + void testInvalidSubsequence1ShouldThrowIAX() { assertThatIllegalArgumentException().isThrownBy(() -> abs.subSequence(-1, 1)); } @Test - public void testInvalidSubsequence3ShouldThrowIAX() { + void testInvalidSubsequence3ShouldThrowIAX() { assertThatIllegalArgumentException().isThrownBy(() -> abs.subSequence(0, 10)); } @Test - public void testFromByteBuffer() { + void testFromByteBuffer() { final ByteBuffer bb = ByteBuffer.wrap(data, 1, 4); abs = new ArrayByteSequence(bb); - assertEquals("mile", abs.toString()); + assertThat(abs).hasToString("mile"); } @Test - public void testFromReadOnlyByteBuffer() { + void testFromReadOnlyByteBuffer() { final ByteBuffer bb = ByteBuffer.wrap(data, 1, 4).asReadOnlyBuffer(); abs = new ArrayByteSequence(bb); - assertEquals("mile", abs.toString()); + assertThat(abs).hasToString("mile"); } @Test - public void testToString() { - assertEquals("", new ArrayByteSequence("").toString(), "String conversion should round trip correctly"); + void testToString() { + assertThat(new ArrayByteSequence("")) + .as("String conversion should round trip correctly") + .hasToString(""); } } diff --git a/core/common-util/src/test/java/uk/gov/gchq/gaffer/commonutil/elementvisibilityutil/AuthorisationsTest.java b/core/common-util/src/test/java/uk/gov/gchq/gaffer/commonutil/elementvisibilityutil/AuthorisationsTest.java index 2b2981311fd..7fc9fefd53e 100644 --- a/core/common-util/src/test/java/uk/gov/gchq/gaffer/commonutil/elementvisibilityutil/AuthorisationsTest.java +++ b/core/common-util/src/test/java/uk/gov/gchq/gaffer/commonutil/elementvisibilityutil/AuthorisationsTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2017-2021 Crown Copyright + * Copyright 2017-2024 Crown Copyright * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -19,54 +19,54 @@ import org.junit.jupiter.api.Test; import java.nio.ByteBuffer; +import java.util.List; +import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatExceptionOfType; -import static org.junit.jupiter.api.Assertions.assertArrayEquals; -import static org.junit.jupiter.api.Assertions.assertEquals; /** * This test class is copied from org.apache.accumulo.core.security.AuthorizationsTest. */ -public class AuthorisationsTest { +class AuthorisationsTest { @Test - public void testEncodeDecode() { + void testEncodeDecode() { final Authorisations a = new Authorisations("a", "abcdefg", "hijklmno", ","); final byte[] array = a.getAuthorisationsArray(); final Authorisations b = new Authorisations(array); - assertEquals(a, b); + assertThat(b).isEqualTo(a); } @Test - public void testEncodeEmptyAuthorisations() { + void testEncodeEmptyAuthorisations() { final Authorisations a = new Authorisations(); final byte[] array = a.getAuthorisationsArray(); final Authorisations b = new Authorisations(array); - assertEquals(a, b); + assertThat(b).isEqualTo(a); } @Test - public void testEncodeMultiByteAuthorisations() { + void testEncodeMultiByteAuthorisations() { final Authorisations a = new Authorisations("五", "b", "c", "九"); final byte[] array = a.getAuthorisationsArray(); final Authorisations b = new Authorisations(array); - assertEquals(a, b); + assertThat(b).isEqualTo(a); } @Test - public void testSerialization() { + void testSerialization() { final Authorisations a1 = new Authorisations("a", "b"); final Authorisations a2 = new Authorisations("b", "a"); - assertEquals(a1, a2); - assertEquals(a1.serialise(), a2.serialise()); + assertThat(a2).isEqualTo(a1); + assertThat(a2.serialise()).isEqualTo(a1.serialise()); } @Test - public void testDefensiveAccess() { + void testDefensiveAccess() { final Authorisations expected = new Authorisations("foo", "a"); final Authorisations actual = new Authorisations("foo", "a"); @@ -74,37 +74,46 @@ public void testDefensiveAccess() { for (byte[] bytes : actual) { bytes[0]++; } - assertArrayEquals(expected.getAuthorisationsArray(), actual.getAuthorisationsArray()); + assertThat(actual.getAuthorisationsArray()).isEqualTo(expected.getAuthorisationsArray()); // test defensive getter and serializer actual.getAuthorisations().get(0)[0]++; - assertArrayEquals(expected.getAuthorisationsArray(), actual.getAuthorisationsArray()); - assertEquals(expected.serialise(), actual.serialise()); + assertThat(actual.getAuthorisationsArray()).isEqualTo(expected.getAuthorisationsArray()); + assertThat(actual.serialise()).isEqualTo(expected.serialise()); } // This should throw ReadOnlyBufferException, but THRIFT-883 requires that the ByteBuffers themselves not be read-only // @Test(expected = ReadOnlyBufferException.class) @Test - public void testReadOnlyByteBuffer() { + void testReadOnlyByteBuffer() { final Authorisations expected = new Authorisations("foo"); final Authorisations actual = new Authorisations("foo"); - assertArrayEquals(expected.getAuthorisationsArray(), actual.getAuthorisationsArray()); + assertThat(actual.getAuthorisationsArray()).isEqualTo(expected.getAuthorisationsArray()); actual.getAuthorisationsBB().get(0).array()[0]++; - assertArrayEquals(expected.getAuthorisationsArray(), actual.getAuthorisationsArray()); + assertThat(actual.getAuthorisationsArray()).isEqualTo(expected.getAuthorisationsArray()); } @Test - public void testUnmodifiableList() { + void testUnmodifiableList() { final Authorisations expected = new Authorisations("foo"); final Authorisations actual = new Authorisations("foo"); - assertArrayEquals(expected.getAuthorisationsArray(), actual.getAuthorisationsArray()); + assertThat(actual.getAuthorisationsArray()).isEqualTo(expected.getAuthorisationsArray()); - assertThatExceptionOfType(UnsupportedOperationException.class).isThrownBy(() -> { - actual.getAuthorisationsBB().add(ByteBuffer.wrap(new byte[] {'a'})); - }); + final ByteBuffer byteBuffer = ByteBuffer.wrap(new byte[] {'a'}); + final List getAuthBB = actual.getAuthorisationsBB(); + + assertThatExceptionOfType(UnsupportedOperationException.class) + .isThrownBy(() -> getAuthBB.add(byteBuffer)); + } + + @Test + void testToString() { + final Authorisations a = new Authorisations("a", "abcdefg", "hijklmno"); + + assertThat(a).hasToString("a,hijklmno,abcdefg"); } } diff --git a/core/common-util/src/test/java/uk/gov/gchq/gaffer/commonutil/elementvisibilityutil/ElementVisibilityTest.java b/core/common-util/src/test/java/uk/gov/gchq/gaffer/commonutil/elementvisibilityutil/ElementVisibilityTest.java index ff2eaf1e856..40422e88ea0 100644 --- a/core/common-util/src/test/java/uk/gov/gchq/gaffer/commonutil/elementvisibilityutil/ElementVisibilityTest.java +++ b/core/common-util/src/test/java/uk/gov/gchq/gaffer/commonutil/elementvisibilityutil/ElementVisibilityTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2017-2021 Crown Copyright + * Copyright 2017-2024 Crown Copyright * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -23,68 +23,67 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException; import static org.assertj.core.api.Assertions.assertThatNoException; -import static org.junit.jupiter.api.Assertions.assertEquals; import static uk.gov.gchq.gaffer.commonutil.elementvisibilityutil.ElementVisibility.quote; /** * This test class is copied from org.apache.accumulo.core.security.ColumnVisibilityTest. */ -public class ElementVisibilityTest { +class ElementVisibilityTest { @Test - public void testEmptyStringIsValid() { + void testEmptyStringIsValid() { final ElementVisibility a = new ElementVisibility(new byte[0]); final ElementVisibility b = new ElementVisibility(""); - assertEquals(a, b); + assertThat(b).isEqualTo(a); } @Test - public void testCharactersOnly() { + void testCharactersOnly() { getBytesShouldNotThrowIAX("test", "words"); } @Test - public void testCompound() { + void testCompound() { getBytesShouldNotThrowIAX("a|b", "a&b", "ab&bc", "_&-&:", "A&B&C&D&E", "A|B|C|D|E", "(A|B|C)", "(A)|B|(C)", "A&(B)&(C)", "A&B&(L)"); } @Test - public void testBadCharacters() { + void testBadCharacters() { getBytesShouldThrowIAX("=", "*", "^", "%", "@", "a*b"); } @Test - public void testComplexCompound() { + void testComplexCompound() { getBytesShouldNotThrowIAX("(a|b)&(x|y)", "a&(x|y)", "(a|b)&(x|y)", "A&(L|M)", "B&(L|M)", "A&B&(L|M)"); getBytesShouldNotThrowIAX("A&FOO&(L|M)", "(A|B)&FOO&(L|M)", "A&B&(L|M|FOO)", "((A|B|C)|foo)&bar"); getBytesShouldNotThrowIAX("(one&two)|(foo&bar)", "(one|foo)&three", "one|foo|bar", "(one|foo)|bar", "((one|foo)|bar)&two"); } @Test - public void testDanglingOperators() { + void testDanglingOperators() { getBytesShouldThrowIAX("a|b&", "(|a)", "|", "a|", "|a", "|", "&"); getBytesShouldThrowIAX("&(five)", "|(five)", "(five)&", "five|", "a|(b)&", "(&five)", "(five|)"); } @Test - public void testMissingSeparators() { + void testMissingSeparators() { getBytesShouldThrowIAX("one(five)", "(five)one", "(one)(two)", "a|(b(c))"); } @Test - public void testMismatchedParentheses() { + void testMismatchedParentheses() { getBytesShouldThrowIAX("(", ")", "(a&b", "b|a)", "A|B)"); } @Test - public void testMixedOperators() { + void testMixedOperators() { getBytesShouldThrowIAX("(A&B)|(C&D)&(E)", "a|b&c", "A&B&C|D", "(A&B)|(C&D)&(E)"); } @Test - public void testQuotes() { + void testQuotes() { getBytesShouldThrowIAX("\"\"", "\"A\"A", "\"A\"\"B\"", "(A)\"B\"", "\"A\"(B)"); getBytesShouldThrowIAX("\"A", "\"", "\"B", "A&\"B", "A&\"B\\'"); @@ -92,21 +91,21 @@ public void testQuotes() { } @Test - public void testToStringSimpleCharacter() { + void testToStringSimpleCharacter() { final ElementVisibility cv = new ElementVisibility(quote("a")); - assertEquals("[a]", cv.toString()); + assertThat(cv).hasToString("[a]"); } @Test - public void testToStringMultiByte() { + void testToStringMultiByte() { final ElementVisibility cv = new ElementVisibility(quote("五")); - assertEquals("[\"五\"]", cv.toString()); + assertThat(cv).hasToString("[\"五\"]"); } @Test - public void testParseTree() { + void testParseTree() { final ElementVisibility.Node node = parse("(W)|(U&V)"); assertNode(node, ElementVisibility.NodeType.OR, 0, 9); @@ -115,14 +114,14 @@ public void testParseTree() { } @Test - public void testParseTreeWithNoChildren() { + void testParseTreeWithNoChildren() { final ElementVisibility.Node node = parse("ABC"); assertNode(node, ElementVisibility.NodeType.TERM, 0, 3); } @Test - public void testParseTreeWithTwoChildren() { + void testParseTreeWithTwoChildren() { final ElementVisibility.Node node = parse("ABC|DEF"); assertNode(node, ElementVisibility.NodeType.OR, 0, 7); @@ -131,7 +130,7 @@ public void testParseTreeWithTwoChildren() { } @Test - public void testParseTreeWithParenthesesAndTwoChildren() { + void testParseTreeWithParenthesesAndTwoChildren() { final ElementVisibility.Node node = parse("(ABC|DEF)"); assertNode(node, ElementVisibility.NodeType.OR, 1, 8); @@ -140,7 +139,7 @@ public void testParseTreeWithParenthesesAndTwoChildren() { } @Test - public void testParseTreeWithParenthesizedChildren() { + void testParseTreeWithParenthesizedChildren() { final ElementVisibility.Node node = parse("ABC|(DEF&GHI)"); assertNode(node, ElementVisibility.NodeType.OR, 0, 13); @@ -151,7 +150,7 @@ public void testParseTreeWithParenthesizedChildren() { } @Test - public void testParseTreeWithMoreParentheses() { + void testParseTreeWithMoreParentheses() { final ElementVisibility.Node node = parse("(W)|(U&V)"); assertNode(node, ElementVisibility.NodeType.OR, 0, 9); diff --git a/core/common-util/src/test/java/uk/gov/gchq/gaffer/commonutil/elementvisibilityutil/VisibilityEvaluatorTest.java b/core/common-util/src/test/java/uk/gov/gchq/gaffer/commonutil/elementvisibilityutil/VisibilityEvaluatorTest.java index 4eec071231d..8c496ac1d16 100644 --- a/core/common-util/src/test/java/uk/gov/gchq/gaffer/commonutil/elementvisibilityutil/VisibilityEvaluatorTest.java +++ b/core/common-util/src/test/java/uk/gov/gchq/gaffer/commonutil/elementvisibilityutil/VisibilityEvaluatorTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2017-2021 Crown Copyright + * Copyright 2017-2024 Crown Copyright * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -24,98 +24,106 @@ import java.util.regex.PatternSyntaxException; +import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatExceptionOfType; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertFalse; -import static org.junit.jupiter.api.Assertions.assertTrue; import static uk.gov.gchq.gaffer.commonutil.elementvisibilityutil.ElementVisibility.quote; /** * This test class is copied from org.apache.accumulo.core.security.VisibilityEvaluatorTest. */ -public class VisibilityEvaluatorTest { +class VisibilityEvaluatorTest { final VisibilityEvaluator ve = new VisibilityEvaluator(new Authorisations("one", "two", "three", "four")); @Test - public void testVisibilityEvaluator() throws VisibilityParseException { + void testVisibilityEvaluator() throws VisibilityParseException { // test for empty vis - assertTrue(ve.evaluate(new ElementVisibility(new byte[0]))); + assertThat(ve.evaluate(new ElementVisibility(new byte[0]))).isTrue(); // test for and - assertTrue(ve.evaluate(new ElementVisibility("one&two")), "'and' test"); + assertThat(ve.evaluate(new ElementVisibility("one&two"))) + .as("'and' test") + .isTrue(); // test for or - assertTrue(ve.evaluate(new ElementVisibility("foor|four")), "'or' test"); + assertThat(ve.evaluate(new ElementVisibility("foor|four"))) + .as("'or' test") + .isTrue(); // test for and and or - assertTrue(ve.evaluate(new ElementVisibility("(one&two)|(foo&bar)")), "'and' and 'or' test"); + assertThat(ve.evaluate(new ElementVisibility("(one&two)|(foo&bar)"))) + .as("'and' and 'or' test") + .isTrue(); } @ParameterizedTest @ValueSource(strings = {"one", "one|five", "five|one", "(one)", "(one&two)|(foo&bar)", "(one|foo)&three", "one|foo|bar", "(one|foo)|bar", "((one|foo)|bar)&two"}) - public void testFalseNegatives(String marking) throws VisibilityParseException { - assertTrue(ve.evaluate(new ElementVisibility(marking)), marking); + void testFalseNegatives(String marking) throws VisibilityParseException { + assertThat(ve.evaluate(new ElementVisibility(marking))) + .as(marking) + .isTrue(); } @ParameterizedTest @ValueSource(strings = {"five", "one&five", "five&one", "((one|foo)|bar)&goober"}) - public void testFalsePositives(String marking) throws VisibilityParseException { - assertFalse(ve.evaluate(new ElementVisibility(marking)), marking); + void testFalsePositives(String marking) throws VisibilityParseException { + assertThat(ve.evaluate(new ElementVisibility(marking))) + .as(marking) + .isFalse(); } @ParameterizedTest @ValueSource(strings = {"one(five)", "(five)one", "(one)(two)", "a|(b(c))"}) - public void testMissingSeparatorsShouldThrowPSX(String marking) { + void testMissingSeparatorsShouldThrowPSX(String marking) { assertThatExceptionOfType(PatternSyntaxException.class).isThrownBy(() -> new ElementVisibility(marking)); } @ParameterizedTest @ValueSource(strings = {"&(five)", "|(five)", "(five)&", "five|", "a|(b)&", "(&five)", "(five|)"}) - public void testUnexpectedSeparatorShouldThrowPSX(String marking) { + void testUnexpectedSeparatorShouldThrowPSX(String marking) { assertThatExceptionOfType(PatternSyntaxException.class).isThrownBy(() -> new ElementVisibility(marking)); } @ParameterizedTest @ValueSource(strings = {"(", ")", "(a&b", "b|a)"}) - public void testMismatchedParenthesisShouldThrowPSX(String marking) { + void testMismatchedParenthesisShouldThrowPSX(String marking) { assertThatExceptionOfType(PatternSyntaxException.class).isThrownBy(() -> new ElementVisibility(marking)); } @Test - public void testQuotedExpressions() throws VisibilityParseException { + void testQuotedExpressions() throws VisibilityParseException { final Authorisations auths = new Authorisations("A#C", "A\"C", "A\\C", "AC"); - final VisibilityEvaluator ve = new VisibilityEvaluator(auths); + final VisibilityEvaluator visEv = new VisibilityEvaluator(auths); - assertTrue(ve.evaluate(new ElementVisibility(quote("A#C") + "|" + quote("A?C")))); + assertThat(visEv.evaluate(new ElementVisibility(quote("A#C") + "|" + quote("A?C")))).isTrue(); - assertFalse(ve.evaluate(new ElementVisibility(quote("A#C") + "&B"))); + assertThat(visEv.evaluate(new ElementVisibility(quote("A#C") + "&B"))).isFalse(); - assertTrue(ve.evaluate(new ElementVisibility(quote("A#C")))); - assertTrue(ve.evaluate(new ElementVisibility("(" + quote("A#C") + ")"))); + assertThat(visEv.evaluate(new ElementVisibility(quote("A#C")))).isTrue(); + assertThat(visEv.evaluate(new ElementVisibility("(" + quote("A#C") + ")"))).isTrue(); } @Test - public void testQuote() { - assertEquals("\"A#C\"", quote("A#C")); - assertEquals("\"A\\\"C\"", quote("A\"C")); - assertEquals("\"A\\\"\\\\C\"", quote("A\"\\C")); - assertEquals("ACS", quote("ACS")); - assertEquals("\"九\"", quote("九")); - assertEquals("\"五十\"", quote("五十")); + void testQuote() { + assertThat(quote("A#C")).isEqualTo("\"A#C\""); + assertThat(quote("A\"C")).isEqualTo("\"A\\\"C\""); + assertThat(quote("A\"\\C")).isEqualTo("\"A\\\"\\\\C\""); + assertThat(quote("ACS")).isEqualTo("ACS"); + assertThat(quote("九")).isEqualTo("\"九\""); + assertThat(quote("五十")).isEqualTo("\"五十\""); } @Test - public void testNonAscii() throws VisibilityParseException { - final VisibilityEvaluator ve = new VisibilityEvaluator(new Authorisations("五", "六", "八", "九", "五十")); - - assertTrue(ve.evaluate(new ElementVisibility(quote("五") + "|" + quote("四")))); - assertFalse(ve.evaluate(new ElementVisibility(quote("五") + "&" + quote("四")))); - assertTrue(ve.evaluate(new ElementVisibility(quote("五") + "&(" + quote("四") + "|" + quote("九") + ")"))); - assertTrue(ve.evaluate(new ElementVisibility("\"五\"&(\"四\"|\"五十\")"))); - assertFalse(ve.evaluate(new ElementVisibility(quote("五") + "&(" + quote("四") + "|" + quote("三") + ")"))); - assertFalse(ve.evaluate(new ElementVisibility("\"五\"&(\"四\"|\"三\")"))); + void testNonAscii() throws VisibilityParseException { + final VisibilityEvaluator visEv = new VisibilityEvaluator(new Authorisations("五", "六", "八", "九", "五十")); + + assertThat(visEv.evaluate(new ElementVisibility(quote("五") + "|" + quote("四")))).isTrue(); + assertThat(visEv.evaluate(new ElementVisibility(quote("五") + "&" + quote("四")))).isFalse(); + assertThat(visEv.evaluate(new ElementVisibility(quote("五") + "&(" + quote("四") + "|" + quote("九") + ")"))).isTrue(); + assertThat(visEv.evaluate(new ElementVisibility("\"五\"&(\"四\"|\"五十\")"))).isTrue(); + assertThat(visEv.evaluate(new ElementVisibility(quote("五") + "&(" + quote("四") + "|" + quote("三") + ")"))).isFalse(); + assertThat(visEv.evaluate(new ElementVisibility("\"五\"&(\"四\"|\"三\")"))).isFalse(); } } diff --git a/core/common-util/src/test/java/uk/gov/gchq/gaffer/commonutil/iterable/AlwaysValidTrue.java b/core/common-util/src/test/java/uk/gov/gchq/gaffer/commonutil/iterable/AlwaysValidTrueTest.java similarity index 78% rename from core/common-util/src/test/java/uk/gov/gchq/gaffer/commonutil/iterable/AlwaysValidTrue.java rename to core/common-util/src/test/java/uk/gov/gchq/gaffer/commonutil/iterable/AlwaysValidTrueTest.java index 128a54c9bdb..97d96e4e348 100644 --- a/core/common-util/src/test/java/uk/gov/gchq/gaffer/commonutil/iterable/AlwaysValidTrue.java +++ b/core/common-util/src/test/java/uk/gov/gchq/gaffer/commonutil/iterable/AlwaysValidTrueTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2016-2020 Crown Copyright + * Copyright 2016-2024 Crown Copyright * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -22,29 +22,29 @@ import uk.gov.gchq.koryphe.ValidationResult; -import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.assertj.core.api.Assertions.assertThat; -public class AlwaysValidTrue { +class AlwaysValidTrueTest { @ParameterizedTest @NullSource @ValueSource(strings = {"test"}) - public void shouldReturnTrueForNullAndString(final String input) { + void shouldReturnTrueForNullAndString(final String input) { final AlwaysValid validator = new AlwaysValid<>(); final boolean result = validator.validate(input); - assertTrue(result); + assertThat(result).isTrue(); } @ParameterizedTest @NullSource @ValueSource(strings = {"test"}) - public void shouldReturnValidationResultForNullAndString(final String input) { + void shouldReturnValidationResultForNullAndString(final String input) { final AlwaysValid validator = new AlwaysValid<>(); final ValidationResult result = validator.validateWithValidationResult(input); - assertTrue(result.isValid()); + assertThat(result.isValid()).isTrue(); } } diff --git a/core/common-util/src/test/java/uk/gov/gchq/gaffer/commonutil/iterable/CachingIterableTest.java b/core/common-util/src/test/java/uk/gov/gchq/gaffer/commonutil/iterable/CachingIterableTest.java index 8f8bbe4386b..76c742463cf 100644 --- a/core/common-util/src/test/java/uk/gov/gchq/gaffer/commonutil/iterable/CachingIterableTest.java +++ b/core/common-util/src/test/java/uk/gov/gchq/gaffer/commonutil/iterable/CachingIterableTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2018-2023 Crown Copyright + * Copyright 2018-2024 Crown Copyright * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -37,13 +37,13 @@ import static org.mockito.Mockito.when; @ExtendWith(MockitoExtension.class) -public class CachingIterableTest { +class CachingIterableTest { private static final List SMALL_LIST = Arrays.asList(0, 1, 2, 3, 4); private static final List LARGE_LIST = Arrays.asList(0, 1, 2, 3, 4, 5, 6, 7, 8, 9); @Test - public void shouldCacheSmallIterable(@Mock final Iterable mockIterable) { + void shouldCacheSmallIterable(@Mock final Iterable mockIterable) { when(mockIterable.iterator()) .thenReturn(SMALL_LIST.iterator()) .thenReturn(SMALL_LIST.iterator()); @@ -57,7 +57,7 @@ public void shouldCacheSmallIterable(@Mock final Iterable mockIterable) } @Test - public void shouldNotCacheALargeIterable(@Mock final Iterable mockIterable) { + void shouldNotCacheALargeIterable(@Mock final Iterable mockIterable) { when(mockIterable.iterator()) .thenReturn(LARGE_LIST.iterator()) .thenReturn(LARGE_LIST.iterator()); @@ -71,14 +71,14 @@ public void shouldNotCacheALargeIterable(@Mock final Iterable mockItera } @Test - public void shouldHandleNullIterable() { + void shouldHandleNullIterable() { Iterable cachingIterable = new CachingIterable<>(null); assertThat(cachingIterable).isEmpty(); } @Test - public void shouldCloseTheIterable() throws IOException { + void shouldCloseTheIterable() throws IOException { @SuppressWarnings("unchecked") final Iterable iterable = Mockito.mock(Iterable.class, Mockito.withSettings().extraInterfaces(Closeable.class)); @@ -90,7 +90,7 @@ public void shouldCloseTheIterable() throws IOException { } @Test - public void shouldCloseTheIterableWhenFullyCached() throws IOException { + void shouldCloseTheIterableWhenFullyCached() throws IOException { @SuppressWarnings("unchecked") final Iterable iterable = Mockito.mock(Iterable.class, Mockito.withSettings().extraInterfaces(Closeable.class)); @@ -104,7 +104,7 @@ public void shouldCloseTheIterableWhenFullyCached() throws IOException { @SuppressWarnings("unchecked") @Test - public void shouldHandleMultipleIterators() throws IOException { + void shouldHandleMultipleIterators() throws IOException { // Given final Iterable iterable = Mockito.mock(Iterable.class, Mockito.withSettings().extraInterfaces(Closeable.class)); diff --git a/core/common-util/src/test/java/uk/gov/gchq/gaffer/commonutil/iterable/ConsumableBlockingQueueTest.java b/core/common-util/src/test/java/uk/gov/gchq/gaffer/commonutil/iterable/ConsumableBlockingQueueTest.java index d7c81a606d1..7a8f6bee7c0 100644 --- a/core/common-util/src/test/java/uk/gov/gchq/gaffer/commonutil/iterable/ConsumableBlockingQueueTest.java +++ b/core/common-util/src/test/java/uk/gov/gchq/gaffer/commonutil/iterable/ConsumableBlockingQueueTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2017-2021 Crown Copyright + * Copyright 2017-2024 Crown Copyright * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -21,28 +21,22 @@ import java.util.ArrayList; import java.util.Iterator; import java.util.List; +import java.util.NoSuchElementException; import java.util.stream.Collectors; -import java.util.stream.IntStream; import static org.assertj.core.api.Assertions.assertThat; -import static org.junit.jupiter.api.Assertions.assertFalse; -import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.assertj.core.api.Assertions.assertThatExceptionOfType; -public class ConsumableBlockingQueueTest { +class ConsumableBlockingQueueTest { @Test - public void shouldConsumeResultsWhenIterating() { + void shouldConsumeResultsWhenIterating() throws InterruptedException { // Given final ConsumableBlockingQueue queue = new ConsumableBlockingQueue<>(5); - IntStream.range(0, 4) - .forEach(i -> { - try { - queue.put(i); - } catch (InterruptedException e) { - throw new RuntimeException(e); - } - }); + for (int i = 0; i < 4; i++) { + queue.put(i); + } // When final List items = queue.stream().collect(Collectors.toList()); @@ -57,26 +51,25 @@ public void shouldConsumeResultsWhenIterating() { } @Test - public void shouldBlockOnAdditionWhenQueueIsFull() throws InterruptedException { + void shouldBlockOnAdditionWhenQueueIsFull() throws InterruptedException { // Given final ConsumableBlockingQueue queue = new ConsumableBlockingQueue<>(5); final boolean[] finishedAdding = new boolean[] {false}; new Thread(() -> { - IntStream.range(0, 10) - .forEach(i -> { - try { - queue.put(i); - } catch (InterruptedException e) { - throw new RuntimeException(e); - } - }); + for (int i = 0; i < 10; i++) { + try { + queue.put(i); + } catch (InterruptedException e) { + throw new RuntimeException(e); + } + } finishedAdding[0] = true; }).start(); // Wait for some items to be added, but there isn't room for all of them Thread.sleep(1000L); - assertFalse(finishedAdding[0]); + assertThat(finishedAdding[0]).isFalse(); // Consume some results final Iterator consumer = queue.iterator(); @@ -88,7 +81,7 @@ public void shouldBlockOnAdditionWhenQueueIsFull() throws InterruptedException { // Now the queue has space some items should be added, but there still isn't room for all of them Thread.sleep(1000L); - assertFalse(finishedAdding[0]); + assertThat(finishedAdding[0]).isFalse(); // Consume some more results for (int i = 0; i < 4; i++) { @@ -98,7 +91,7 @@ public void shouldBlockOnAdditionWhenQueueIsFull() throws InterruptedException { // Now the queue has space some items should be added and this time there is room for the rest of them Thread.sleep(1000L); - assertTrue(finishedAdding[0]); + assertThat(finishedAdding[0]).isTrue(); // Consume some rest of the results while (consumer.hasNext()) { @@ -110,11 +103,33 @@ public void shouldBlockOnAdditionWhenQueueIsFull() throws InterruptedException { } @Test - public void shouldNotBlockWhenConsumingWhenQueueIsEmpty() { + void shouldNotBlockWhenConsumingWhenQueueIsEmpty() { final ConsumableBlockingQueue queue = new ConsumableBlockingQueue<>(5); final Iterator iterator = queue.iterator(); assertThat(iterator).isExhausted(); } + + @Test + void shouldThrowExceptionWhenQueueIsEmpty() { + final ConsumableBlockingQueue queue = new ConsumableBlockingQueue<>(5); + + final Iterator iterator = queue.iterator(); + + assertThatExceptionOfType(NoSuchElementException.class) + .isThrownBy(() -> iterator.next()) + .withMessage("No more items"); + } + + @Test + void shouldReturnToString() throws InterruptedException { + final ConsumableBlockingQueue queue = new ConsumableBlockingQueue<>(5); + + for (int i = 0; i < 4; i++) { + queue.put(i); + } + + assertThat(queue).hasToString("ConsumableBlockingQueue[items={0,1,2,3}]"); + } } diff --git a/core/common-util/src/test/java/uk/gov/gchq/gaffer/commonutil/iterable/EmptyIterableTest.java b/core/common-util/src/test/java/uk/gov/gchq/gaffer/commonutil/iterable/EmptyIterableTest.java index 80f03271365..f38352ff2b7 100644 --- a/core/common-util/src/test/java/uk/gov/gchq/gaffer/commonutil/iterable/EmptyIterableTest.java +++ b/core/common-util/src/test/java/uk/gov/gchq/gaffer/commonutil/iterable/EmptyIterableTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2015-2021 Crown Copyright + * Copyright 2015-2024 Crown Copyright * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -20,10 +20,10 @@ import static org.assertj.core.api.Assertions.assertThat; -public class EmptyIterableTest { +class EmptyIterableTest { @Test - public void shouldBeEmpty() { + void shouldBeEmpty() { final EmptyIterable iterable = new EmptyIterable<>(); assertThat(iterable).isEmpty(); diff --git a/core/common-util/src/test/java/uk/gov/gchq/gaffer/commonutil/iterable/LimitedInMemorySortedIterableTest.java b/core/common-util/src/test/java/uk/gov/gchq/gaffer/commonutil/iterable/LimitedInMemorySortedIterableTest.java index 00cc2fd759c..a5cd7b2c670 100644 --- a/core/common-util/src/test/java/uk/gov/gchq/gaffer/commonutil/iterable/LimitedInMemorySortedIterableTest.java +++ b/core/common-util/src/test/java/uk/gov/gchq/gaffer/commonutil/iterable/LimitedInMemorySortedIterableTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2017-2021 Crown Copyright + * Copyright 2017-2024 Crown Copyright * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -13,6 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + package uk.gov.gchq.gaffer.commonutil.iterable; import com.google.common.collect.Lists; @@ -26,11 +27,12 @@ import java.util.stream.IntStream; import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatExceptionOfType; -public class LimitedInMemorySortedIterableTest { +class LimitedInMemorySortedIterableTest { @Test - public void shouldLimitEntries() { + void shouldLimitEntries() { final LimitedInMemorySortedIterable list = new LimitedInMemorySortedIterable(Comparator.naturalOrder(), 100); final List expectedItems = new ArrayList<>(); IntStream.rangeClosed(1, 100).forEach(expectedItems::add); @@ -43,7 +45,7 @@ public void shouldLimitEntries() { } @Test - public void shouldLimitAndDeduplicateEntries() { + void shouldLimitAndDeduplicateEntries() { final LimitedInMemorySortedIterable list = new LimitedInMemorySortedIterable(Comparator.naturalOrder(), 2, true); list.add(1); @@ -57,7 +59,7 @@ public void shouldLimitAndDeduplicateEntries() { } @Test - public void shouldDeduplicateEntries() { + void shouldDeduplicateEntries() { final LimitedInMemorySortedIterable list = new LimitedInMemorySortedIterable(Comparator.naturalOrder(), 100, true); list.add(1); @@ -67,7 +69,7 @@ public void shouldDeduplicateEntries() { } @Test - public void shouldNotDeduplicateEntries() { + void shouldNotDeduplicateEntries() { final LimitedInMemorySortedIterable list = new LimitedInMemorySortedIterable(Comparator.naturalOrder(), 100, false); list.add(1); @@ -77,7 +79,7 @@ public void shouldNotDeduplicateEntries() { } @Test - public void shouldLimitAndNotDeduplicateEntries() { + void shouldLimitAndNotDeduplicateEntries() { final LimitedInMemorySortedIterable list = new LimitedInMemorySortedIterable(Comparator.naturalOrder(), 4, false); list.add(1); @@ -89,7 +91,7 @@ public void shouldLimitAndNotDeduplicateEntries() { } @Test - public void shouldAddAll() { + void shouldAddAll() { final LimitedInMemorySortedIterable itr = new LimitedInMemorySortedIterable(Comparator.naturalOrder(), 100); // When/Then @@ -122,7 +124,7 @@ public void shouldAddAll() { } @Test - public void shouldLimitEntriesOnAddAll() { + void shouldLimitEntriesOnAddAll() { // Given final LimitedInMemorySortedIterable itr = new LimitedInMemorySortedIterable(Comparator.naturalOrder(), 10); @@ -156,7 +158,7 @@ public void shouldLimitEntriesOnAddAll() { } @Test - public void shouldSortLargeNumberOfItems() { + void shouldSortLargeNumberOfItems() { // Given final int streamSize = 1000000; final int resultLimit = 10000; @@ -177,4 +179,27 @@ public void shouldSortLargeNumberOfItems() { final List expected = Lists.newArrayList(list); assertThat(sortedElements).isEqualTo(expected); } + + @Test + void shouldThrowExceptionWithNoComparator() { + assertThatExceptionOfType(IllegalArgumentException.class) + .isThrownBy(() -> new LimitedInMemorySortedIterable(null, 100)) + .withMessage("Comparator is required"); + } + + @Test + void shouldThrowExceptionWithInvalidLimit() { + assertThatExceptionOfType(IllegalArgumentException.class) + .isThrownBy(() -> new LimitedInMemorySortedIterable(Comparator.naturalOrder(), 0)) + .withMessage("Limit cannot be less than or equal to 0"); + } + + @Test + void shouldReturnToString() { + final LimitedInMemorySortedIterable list = new LimitedInMemorySortedIterable(Comparator.naturalOrder(), 1); + list.add(1); + + assertThat(list) + .hasToString("LimitedInMemorySortedIterable[size=1,limit=1,deduplicate=false,backingMap={1=OneOrMore[deduplicate=false,singleItem=1]}]"); + } } diff --git a/core/common-util/src/test/java/uk/gov/gchq/gaffer/commonutil/iterable/RepeatItemIterableTest.java b/core/common-util/src/test/java/uk/gov/gchq/gaffer/commonutil/iterable/RepeatItemIterableTest.java index b1d782f1436..1d283314947 100644 --- a/core/common-util/src/test/java/uk/gov/gchq/gaffer/commonutil/iterable/RepeatItemIterableTest.java +++ b/core/common-util/src/test/java/uk/gov/gchq/gaffer/commonutil/iterable/RepeatItemIterableTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2017-2021 Crown Copyright + * Copyright 2017-2024 Crown Copyright * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -22,10 +22,10 @@ import static org.assertj.core.api.Assertions.assertThat; -public class RepeatItemIterableTest { +class RepeatItemIterableTest { @Test - public void shouldRepeatItem5Times() { + void shouldRepeatItem5Times() { final String item = "item"; final long repeats = 5; @@ -38,7 +38,7 @@ public void shouldRepeatItem5Times() { @ParameterizedTest @ValueSource(longs = {0, -1, -5}) - public void shouldRepeatItem0TimesWhenRepeatsIsEqualOrLessThanZero(long repeats) { + void shouldRepeatItem0TimesWhenRepeatsIsEqualOrLessThanZero(long repeats) { final String item = "item"; final Iterable itr = new RepeatItemIterable<>(item, repeats); diff --git a/core/common-util/src/test/java/uk/gov/gchq/gaffer/commonutil/iterable/StreamIterableTest.java b/core/common-util/src/test/java/uk/gov/gchq/gaffer/commonutil/iterable/StreamIterableTest.java index 7873fa784ed..aa688034042 100644 --- a/core/common-util/src/test/java/uk/gov/gchq/gaffer/commonutil/iterable/StreamIterableTest.java +++ b/core/common-util/src/test/java/uk/gov/gchq/gaffer/commonutil/iterable/StreamIterableTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2017-2020 Crown Copyright + * Copyright 2017-2024 Crown Copyright * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -32,10 +32,10 @@ import static org.mockito.Mockito.verify; @ExtendWith(MockitoExtension.class) -public class StreamIterableTest { +class StreamIterableTest { @Test - public void shouldDelegateIteratorToIterable(@Mock final StreamSupplier streamSupplier, + void shouldDelegateIteratorToIterable(@Mock final StreamSupplier streamSupplier, @Mock final Stream stream, @Mock final Iterator iterator) { // Given @@ -58,7 +58,7 @@ public void shouldDelegateIteratorToIterable(@Mock final StreamSupplier } @Test - public void shouldDelegateCloseToStreamIterable(@Mock final StreamSupplier streamSupplier) + void shouldDelegateCloseToStreamIterable(@Mock final StreamSupplier streamSupplier) throws IOException { // Given final StreamIterable streamIterable = new StreamIterable<>(streamSupplier); diff --git a/core/common-util/src/test/java/uk/gov/gchq/gaffer/commonutil/iterable/StreamIteratorTest.java b/core/common-util/src/test/java/uk/gov/gchq/gaffer/commonutil/iterable/StreamIteratorTest.java index 757ad787bc5..2461e03d566 100644 --- a/core/common-util/src/test/java/uk/gov/gchq/gaffer/commonutil/iterable/StreamIteratorTest.java +++ b/core/common-util/src/test/java/uk/gov/gchq/gaffer/commonutil/iterable/StreamIteratorTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2017-2020 Crown Copyright + * Copyright 2017-2024 Crown Copyright * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -26,10 +26,10 @@ import static org.mockito.Mockito.verify; @ExtendWith(MockitoExtension.class) -public class StreamIteratorTest { +class StreamIteratorTest { @Test - public void shouldDelegateCloseToWrappedIterator(@Mock final Stream stream) { + void shouldDelegateCloseToWrappedIterator(@Mock final Stream stream) { final StreamIterator streamIterator = new StreamIterator<>(stream); streamIterator.close(); diff --git a/core/common-util/src/test/java/uk/gov/gchq/gaffer/commonutil/iterable/SuppliedIterableTest.java b/core/common-util/src/test/java/uk/gov/gchq/gaffer/commonutil/iterable/SuppliedIterableTest.java index 1abd6b59df8..2a8d729b4de 100644 --- a/core/common-util/src/test/java/uk/gov/gchq/gaffer/commonutil/iterable/SuppliedIterableTest.java +++ b/core/common-util/src/test/java/uk/gov/gchq/gaffer/commonutil/iterable/SuppliedIterableTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2017-2020 Crown Copyright + * Copyright 2017-2024 Crown Copyright * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -37,10 +37,10 @@ import static org.mockito.Mockito.withSettings; @ExtendWith(MockitoExtension.class) -public class SuppliedIterableTest { +class SuppliedIterableTest { @Test - public void shouldRequestNewIterableFromSupplierWhenIteratorInvoked(@Mock final Supplier> supplier) { + void shouldRequestNewIterableFromSupplierWhenIteratorInvoked(@Mock final Supplier> supplier) { // Given final Iterable iterable1 = Arrays.asList(1, 2, 3); final Iterable iterable2 = Arrays.asList(4, 5, 6); @@ -69,7 +69,7 @@ public void shouldRequestNewIterableFromSupplierWhenIteratorInvoked(@Mock final @SuppressWarnings("unchecked") @Test - public void shouldCloseIterables(@Mock final Supplier> supplier) throws IOException { + void shouldCloseIterables(@Mock final Supplier> supplier) throws IOException { // Given final Iterable iterable1 = mock(Iterable.class, withSettings().extraInterfaces(Closeable.class)); final Iterable iterable2 = mock(Iterable.class, withSettings().extraInterfaces(Closeable.class)); diff --git a/core/common-util/src/test/java/uk/gov/gchq/gaffer/commonutil/iterable/TransformIterableTest.java b/core/common-util/src/test/java/uk/gov/gchq/gaffer/commonutil/iterable/TransformIterableTest.java index 608c07323b1..9e3f69c7cc3 100644 --- a/core/common-util/src/test/java/uk/gov/gchq/gaffer/commonutil/iterable/TransformIterableTest.java +++ b/core/common-util/src/test/java/uk/gov/gchq/gaffer/commonutil/iterable/TransformIterableTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2016-2021 Crown Copyright + * Copyright 2016-2024 Crown Copyright * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -41,10 +41,10 @@ import static org.mockito.Mockito.when; @ExtendWith(MockitoExtension.class) -public class TransformIterableTest { +class TransformIterableTest { @Test - public void shouldCreateIteratorThatReturnsOnlyValidStrings(@Mock final Validator validator) { + void shouldCreateIteratorThatReturnsOnlyValidStrings(@Mock final Validator validator) { // Given final String item1 = "valid item 1"; final String item2 = "invalid item 2"; @@ -74,7 +74,7 @@ public void shouldCreateIteratorThatReturnsOnlyValidStrings(@Mock final Validato } @Test - public void shouldThrowIAXExceptionWhenNextItemIsInvalidString(@Mock final Validator validator) { + void shouldThrowIAXExceptionWhenNextItemIsInvalidString(@Mock final Validator validator) { // Given final String item1 = "valid item 1"; final String item2 = "invalid item 2 invalid"; @@ -100,7 +100,7 @@ public void shouldThrowIAXExceptionWhenNextItemIsInvalidString(@Mock final Valid } @Test - public void shouldThrowNoElementExceptionWhenNextCalledWhenNoNextString(@Mock final Validator validator) { + void shouldThrowNoElementExceptionWhenNextCalledWhenNoNextString(@Mock final Validator validator) { // Given final String item1 = "item 1"; final Iterable items = Arrays.asList(item1); @@ -122,7 +122,7 @@ public void shouldThrowNoElementExceptionWhenNextCalledWhenNoNextString(@Mock fi } @Test - public void shouldThrowExceptionIfRemoveCalled(@Mock final Validator validator) { + void shouldThrowExceptionIfRemoveCalled(@Mock final Validator validator) { final String item1 = "item 1"; final String item2 = "item 2"; final Iterable items = Arrays.asList(item1, item2); @@ -139,7 +139,7 @@ public void shouldThrowExceptionIfRemoveCalled(@Mock final Validator val @SuppressWarnings("unchecked") @Test - public void shouldAutoCloseIterator() throws IOException { + void shouldAutoCloseIterator() throws IOException { // Given final boolean autoClose = true; final Iterable items = mock(Iterable.class, Mockito.withSettings().extraInterfaces(Closeable.class)); @@ -164,7 +164,7 @@ public void shouldAutoCloseIterator() throws IOException { @SuppressWarnings("unchecked") @Test - public void shouldNotAutoCloseIterator() throws IOException { + void shouldNotAutoCloseIterator() throws IOException { // Given final boolean autoClose = false; final Iterable items = mock(Iterable.class, Mockito.withSettings().extraInterfaces(Closeable.class)); @@ -188,6 +188,31 @@ public void shouldNotAutoCloseIterator() throws IOException { } } + @Test + void shouldThrowExceptionWithNullInput() { + // Given + final boolean autoClose = true; + final AlwaysValid valid = new AlwaysValid<>(); + + // When/then + assertThatExceptionOfType(IllegalArgumentException.class) + .isThrownBy(() -> new TransformIterableImpl(null, valid, false, autoClose)) + .withMessage("Input iterable is required"); + } + + @SuppressWarnings("unchecked") + @Test + void shouldGetValidator() { + // Given + final boolean autoClose = true; + final Iterable items = mock(Iterable.class, Mockito.withSettings().extraInterfaces(Closeable.class)); + + try (TransformIterable iterable = new TransformIterableImpl(items, new AlwaysValid<>(), false, autoClose)) { + // Then + assertThat(iterable.getValidator()).isInstanceOf(AlwaysValid.class); + } + } + private class TransformIterableImpl extends TransformIterable { TransformIterableImpl(final Iterable input, final Validator validator) { diff --git a/core/common-util/src/test/java/uk/gov/gchq/gaffer/commonutil/iterable/TransformOneToManyIterableTest.java b/core/common-util/src/test/java/uk/gov/gchq/gaffer/commonutil/iterable/TransformOneToManyIterableTest.java index e6bfc2db597..ce8673ce149 100644 --- a/core/common-util/src/test/java/uk/gov/gchq/gaffer/commonutil/iterable/TransformOneToManyIterableTest.java +++ b/core/common-util/src/test/java/uk/gov/gchq/gaffer/commonutil/iterable/TransformOneToManyIterableTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2016-2021 Crown Copyright + * Copyright 2016-2024 Crown Copyright * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -43,10 +43,10 @@ import static org.mockito.Mockito.when; @ExtendWith(MockitoExtension.class) -public class TransformOneToManyIterableTest { +class TransformOneToManyIterableTest { @Test - public void shouldCreateIteratorThatReturnsOnlyValidStrings(@Mock final Validator validator) { + void shouldCreateIteratorThatReturnsOnlyValidStrings(@Mock final Validator validator) { // Given final String nullItem0 = null; final String validItem1 = "item 1"; @@ -79,7 +79,7 @@ public void shouldCreateIteratorThatReturnsOnlyValidStrings(@Mock final Validato } @Test - public void shouldCreateIteratorThatThrowsExceptionOnInvalidString(@Mock final Validator validator) { + void shouldCreateIteratorThatThrowsExceptionOnInvalidString(@Mock final Validator validator) { // Given final String item1 = "item 1"; final String item2 = "item 2a invalid,item 2b"; @@ -106,7 +106,7 @@ public void shouldCreateIteratorThatThrowsExceptionOnInvalidString(@Mock final V } @Test - public void shouldThrowExceptionIfNextCalledWhenNoNextString(@Mock final Validator validator) { + void shouldThrowExceptionIfNextCalledWhenNoNextString(@Mock final Validator validator) { // Given final String item1 = "item 1"; final String items2A_B = "item 2a,item 2b"; @@ -132,7 +132,7 @@ public void shouldThrowExceptionIfNextCalledWhenNoNextString(@Mock final Validat } @Test - public void shouldThrowExceptionIfRemoveCalled(@Mock final Validator validator) { + void shouldThrowExceptionIfRemoveCalled(@Mock final Validator validator) { final String item1 = "item 1"; final String item2 = "item 2"; final Iterable items = Arrays.asList(item1, item2); @@ -151,7 +151,7 @@ public void shouldThrowExceptionIfRemoveCalled(@Mock final Validator val @SuppressWarnings("unchecked") @Test - public void shouldAutoCloseIterator() throws IOException { + void shouldAutoCloseIterator() throws IOException { // Given final boolean autoClose = true; final Iterable items = mock(Iterable.class, Mockito.withSettings().extraInterfaces(Closeable.class)); @@ -176,7 +176,7 @@ public void shouldAutoCloseIterator() throws IOException { @SuppressWarnings("unchecked") @Test - public void shouldNotAutoCloseIterator() throws IOException { + void shouldNotAutoCloseIterator() throws IOException { // Given final boolean autoClose = false; final Iterable items = mock(Iterable.class, Mockito.withSettings().extraInterfaces(Closeable.class)); diff --git a/core/common-util/src/test/java/uk/gov/gchq/gaffer/commonutil/pair/PairTest.java b/core/common-util/src/test/java/uk/gov/gchq/gaffer/commonutil/pair/PairTest.java index 04e87d70ee8..04637ef1d48 100644 --- a/core/common-util/src/test/java/uk/gov/gchq/gaffer/commonutil/pair/PairTest.java +++ b/core/common-util/src/test/java/uk/gov/gchq/gaffer/commonutil/pair/PairTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2017-2020 Crown Copyright + * Copyright 2017-2024 Crown Copyright * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -13,48 +13,55 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + package uk.gov.gchq.gaffer.commonutil.pair; import org.junit.jupiter.api.Test; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertNull; +import static org.assertj.core.api.Assertions.assertThat; -public class PairTest { +class PairTest { @Test - public void shouldCreateMutablePair() { + void shouldCreateMutablePair() { final Pair pair = new Pair<>(0, "foo"); - assertEquals(0, pair.getFirst().intValue()); - assertEquals("foo", pair.getSecond()); + assertThat(pair.getFirst().intValue()).isZero(); + assertThat(pair.getSecond()).isEqualTo("foo"); } @Test - public void shouldCreateMutablePair2() { + void shouldCreateMutablePair2() { final Pair pair = new Pair<>(null, "bar"); - assertNull(pair.getFirst()); - assertEquals("bar", pair.getSecond()); + assertThat(pair.getFirst()).isNull(); + assertThat(pair.getSecond()).isEqualTo("bar"); } @Test - public void shouldBeAbleToMutateFirstInPair() { + void shouldBeAbleToMutateFirstInPair() { final Pair pair = new Pair<>(0); pair.setFirst(1); - assertEquals(1, pair.getFirst().intValue()); - assertNull(pair.getSecond()); + assertThat(pair.getFirst().intValue()).isEqualTo(1); + assertThat(pair.getSecond()).isNull(); } @Test - public void shouldBeAbleToMutateSecondInPair() { + void shouldBeAbleToMutateSecondInPair() { final Pair pair = new Pair<>(); pair.setSecond("2nd"); - assertNull(pair.getFirst()); - assertEquals("2nd", pair.getSecond()); + assertThat(pair.getFirst()).isNull(); + assertThat(pair.getSecond()).isEqualTo("2nd"); + } + + @Test + void shouldReturnToString() { + final Pair pair = new Pair<>("foo", "bar"); + + assertThat(pair).hasToString("Pair[first=foo,second=bar]"); } } diff --git a/core/common-util/src/test/java/uk/gov/gchq/gaffer/commonutil/stream/GafferCollectorTest.java b/core/common-util/src/test/java/uk/gov/gchq/gaffer/commonutil/stream/GafferCollectorTest.java index 1cf3335da98..a0056e75e70 100644 --- a/core/common-util/src/test/java/uk/gov/gchq/gaffer/commonutil/stream/GafferCollectorTest.java +++ b/core/common-util/src/test/java/uk/gov/gchq/gaffer/commonutil/stream/GafferCollectorTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2017-2021 Crown Copyright + * Copyright 2017-2024 Crown Copyright * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -13,6 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + package uk.gov.gchq.gaffer.commonutil.stream; import org.junit.jupiter.api.Test; @@ -26,10 +27,10 @@ import static uk.gov.gchq.gaffer.commonutil.stream.GafferCollectors.toLimitedInMemorySortedIterable; import static uk.gov.gchq.gaffer.commonutil.stream.GafferCollectors.toLinkedHashSet; -public class GafferCollectorTest { +class GafferCollectorTest { @Test - public void shouldCollectToLinkedHashSet() { + void shouldCollectToLinkedHashSet() { final IntStream stream = IntStream.range(0, 100); final Iterable iterable = stream.boxed() @@ -41,7 +42,7 @@ public void shouldCollectToLinkedHashSet() { } @Test - public void shouldCollectToLimitedSortedSet() { + void shouldCollectToLimitedSortedSet() { final IntStream stream = IntStream.range(0, 100); final int limit = 50; final boolean deduplicate = true; diff --git a/core/common-util/src/test/java/uk/gov/gchq/gaffer/commonutil/stream/StreamsTest.java b/core/common-util/src/test/java/uk/gov/gchq/gaffer/commonutil/stream/StreamsTest.java index 1b993cf1199..ac87d0f3424 100644 --- a/core/common-util/src/test/java/uk/gov/gchq/gaffer/commonutil/stream/StreamsTest.java +++ b/core/common-util/src/test/java/uk/gov/gchq/gaffer/commonutil/stream/StreamsTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2016-2020 Crown Copyright + * Copyright 2016-2024 Crown Copyright * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -29,11 +29,11 @@ import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; -public class StreamsTest { +class StreamsTest { @SuppressWarnings("unchecked") @Test - public void shouldCloseIteratorWhenStreamIsClosed() throws Throwable { + void shouldCloseIteratorWhenStreamIsClosed() throws Throwable { // Given final Iterator iterator = mock(Iterator.class, Mockito.withSettings().extraInterfaces(Closeable.class)); given(iterator.hasNext()).willReturn(true, false); @@ -53,7 +53,7 @@ public void shouldCloseIteratorWhenStreamIsClosed() throws Throwable { @SuppressWarnings("unchecked") @Test - public void shouldCloseIterableWhenStreamIsClosed() throws Throwable { + void shouldCloseIterableWhenStreamIsClosed() throws Throwable { // Given final Iterable iterable = mock(Iterable.class, Mockito.withSettings().extraInterfaces(Closeable.class)); final Iterator iterator = mock(Iterator.class, Mockito.withSettings().extraInterfaces(Closeable.class)); @@ -76,7 +76,7 @@ public void shouldCloseIterableWhenStreamIsClosed() throws Throwable { @SuppressWarnings("unchecked") @Test - public void shouldCloseIteratorWhenParallelStreamIsClosed() throws Throwable { + void shouldCloseIteratorWhenParallelStreamIsClosed() throws Throwable { // Given final Iterator iterator = mock(Iterator.class, Mockito.withSettings().extraInterfaces(Closeable.class)); given(iterator.hasNext()).willReturn(true, false); @@ -96,7 +96,7 @@ public void shouldCloseIteratorWhenParallelStreamIsClosed() throws Throwable { @SuppressWarnings("unchecked") @Test - public void shouldCloseIterableWhenParallelStreamIsClosed() throws Throwable { + void shouldCloseIterableWhenParallelStreamIsClosed() throws Throwable { // Given final Iterable iterable = mock(Iterable.class, Mockito.withSettings().extraInterfaces(Closeable.class)); final Iterator iterator = mock(Iterator.class, Mockito.withSettings().extraInterfaces(Closeable.class)); diff --git a/core/graph/src/test/java/uk/gov/gchq/gaffer/graph/hook/NamedOperationResolverTest.java b/core/graph/src/test/java/uk/gov/gchq/gaffer/graph/hook/NamedOperationResolverTest.java index 866e8c945b4..52ab591687a 100644 --- a/core/graph/src/test/java/uk/gov/gchq/gaffer/graph/hook/NamedOperationResolverTest.java +++ b/core/graph/src/test/java/uk/gov/gchq/gaffer/graph/hook/NamedOperationResolverTest.java @@ -16,6 +16,8 @@ package uk.gov.gchq.gaffer.graph.hook; +import org.json.JSONArray; +import org.json.JSONObject; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.Mock; @@ -29,7 +31,6 @@ import uk.gov.gchq.gaffer.named.operation.ParameterDetail; import uk.gov.gchq.gaffer.operation.Operation; import uk.gov.gchq.gaffer.operation.OperationChain; -import uk.gov.gchq.gaffer.operation.OperationException; import uk.gov.gchq.gaffer.operation.impl.Limit; import uk.gov.gchq.gaffer.operation.impl.get.GetAdjacentIds; import uk.gov.gchq.gaffer.operation.impl.get.GetAllElements; @@ -54,6 +55,7 @@ class NamedOperationResolverTest extends GraphHookTest { static final String SUFFIX_CACHE_NAME = "suffix"; + static final String OP_NAME = "opName"; NamedOperationResolverTest() { super(NamedOperationResolver.class); @@ -62,6 +64,7 @@ class NamedOperationResolverTest extends GraphHookTest { @SuppressWarnings({"unchecked", "rawtypes"}) @Test void shouldResolveNamedOperation(@Mock final User user, + @Mock final Context context, @Mock final NamedOperationCache cache, @Mock final NamedOperationDetail namedOpDetail, @Mock final GetAdjacentIds op1, @@ -69,24 +72,24 @@ void shouldResolveNamedOperation(@Mock final User user, @Mock final Iterable input) throws CacheOperationException { // Given - final String opName = "opName"; final NamedOperationResolver resolver = new NamedOperationResolver(cache); final OperationChain testChain = new OperationChain(Arrays.asList(op1, op2)); final List expectedResolvedChain = Arrays.asList(testChain); given(op1.getInput()).willReturn(null); - given(cache.getNamedOperation(opName, user)).willReturn(namedOpDetail); + given(cache.getNamedOperation(OP_NAME, user)).willReturn(namedOpDetail); given(namedOpDetail.getOperationChain(null)).willReturn(testChain); + given(context.getUser()).willReturn(user); final OperationChain opChain = new OperationChain.Builder() .first(new NamedOperation.Builder<>() - .name(opName) + .name(OP_NAME) .input(input) .build()) .build(); // When - resolver.preExecute(opChain, new Context(user)); + resolver.preExecute(opChain, context); // Then assertThat(opChain.getOperations()).isEqualTo(expectedResolvedChain); @@ -98,14 +101,14 @@ void shouldResolveNamedOperation(@Mock final User user, @SuppressWarnings({"unchecked", "rawtypes"}) @Test void shouldResolveNestedNamedOperation(@Mock final User user, + @Mock final Context context, @Mock final NamedOperationCache cache, @Mock final NamedOperationDetail namedOpDetail, @Mock final GetAdjacentIds op1, @Mock final GetElements op2, @Mock final Iterable input) - throws OperationException, CacheOperationException { + throws CacheOperationException { // Given - final String opName = "opName"; final NamedOperationResolver resolver = new NamedOperationResolver(cache); final OperationChain namedOperationOpChain = new OperationChain(Arrays.asList(op1, op2)); @@ -113,20 +116,21 @@ void shouldResolveNestedNamedOperation(@Mock final User user, final Map params = null; given(op1.getInput()).willReturn(null); - given(cache.getNamedOperation(opName, user)).willReturn(namedOpDetail); + given(cache.getNamedOperation(OP_NAME, user)).willReturn(namedOpDetail); given(namedOpDetail.getOperationChain(params)).willReturn(namedOperationOpChain); + given(context.getUser()).willReturn(user); final OperationChain opChain = new OperationChain.Builder() .first(new OperationChain.Builder() .first(new NamedOperation.Builder<>() - .name(opName) + .name(OP_NAME) .input(input) .build()) .build()) .build(); // When - resolver.preExecute(opChain, new Context(user)); + resolver.preExecute(opChain, context); // Then assertThat(opChain.getOperations()).hasSize(1); @@ -141,6 +145,7 @@ void shouldResolveNestedNamedOperation(@Mock final User user, @Test void shouldFailToResolveNestedNamedOperationsOverDefaultLimit( @Mock final User user, + @Mock final Context context, @Mock final NamedOperationCache cache, @Mock final NamedOperationDetail namedOp1Detail, @Mock final NamedOperationDetail namedOp2Detail, @@ -156,6 +161,7 @@ void shouldFailToResolveNestedNamedOperationsOverDefaultLimit( final String namedOp4Name = "namedOp4"; final NamedOperationResolver resolver = new NamedOperationResolver(cache); + given(context.getUser()).willReturn(user); // Setup cache returns (we can ignore named op 4 as it wont be used due to the depth limit) given(cache.getNamedOperation(namedOp1Name, user)).willReturn(namedOp1Detail); given(cache.getNamedOperation(namedOp2Name, user)).willReturn(namedOp2Detail); @@ -201,7 +207,7 @@ void shouldFailToResolveNestedNamedOperationsOverDefaultLimit( .build(); // When assertThatExceptionOfType(GafferRuntimeException.class) - .isThrownBy(() -> resolver.preExecute(opChain, new Context(user))) + .isThrownBy(() -> resolver.preExecute(opChain, context)) .withMessageContaining("NamedOperation Resolver hit nested depth limit"); } @@ -209,6 +215,7 @@ void shouldFailToResolveNestedNamedOperationsOverDefaultLimit( @Test void shouldAllowConfigurableResolverDepthLimit( @Mock final User user, + @Mock final Context context, @Mock final NamedOperationCache cache, @Mock final NamedOperationDetail namedOp1Detail, @Mock final NamedOperationDetail namedOp2Detail, @@ -223,6 +230,7 @@ void shouldAllowConfigurableResolverDepthLimit( final String namedOp3Name = "namedOp3"; // Make a resolver with a stricter depth limit final NamedOperationResolver resolverStrict = new NamedOperationResolver(cache, 2); + given(context.getUser()).willReturn(user); // Setup cache returns given(cache.getNamedOperation(namedOp1Name, user)).willReturn(namedOp1Detail); @@ -261,40 +269,40 @@ void shouldAllowConfigurableResolverDepthLimit( // When resolved using the stricter limit it should fail to resolve the chain assertThatExceptionOfType(GafferRuntimeException.class) - .isThrownBy(() -> resolverStrict.preExecute(opChainStrict, new Context(user))) + .isThrownBy(() -> resolverStrict.preExecute(opChainStrict, context)) .withMessageContaining("NamedOperation Resolver hit nested depth limit"); } - @SuppressWarnings({"unchecked", "rawtypes"}) @Test void shouldExecuteNamedOperationWithoutOverridingInput(@Mock final User user, + @Mock final Context context, @Mock final NamedOperationCache cache, @Mock final NamedOperationDetail namedOpDetail, @Mock final GetAdjacentIds op1, @Mock final GetElements op2, @Mock final Iterable input, @Mock final Iterable mockIterable) - throws OperationException, CacheOperationException { + throws CacheOperationException { // Given - final String opName = "opName"; final NamedOperationResolver resolver = new NamedOperationResolver(cache); final OperationChain namedOpChain = new OperationChain(Arrays.asList(op1, op2)); final Map params = null; given(op1.getInput()).willReturn(mockIterable); - given(cache.getNamedOperation(opName, user)).willReturn(namedOpDetail); + given(cache.getNamedOperation(OP_NAME, user)).willReturn(namedOpDetail); given(namedOpDetail.getOperationChain(params)).willReturn(namedOpChain); + given(context.getUser()).willReturn(user); // When final OperationChain opChain = new OperationChain.Builder() .first(new NamedOperation.Builder<>() - .name(opName) + .name(OP_NAME) .input(input) .build()) .build(); - resolver.preExecute(opChain, new Context(user)); + resolver.preExecute(opChain, context); // Then assertThat(opChain.getOperations().get(0)).isSameAs(namedOpChain); @@ -305,173 +313,128 @@ void shouldExecuteNamedOperationWithoutOverridingInput(@Mock final User user, @SuppressWarnings({ "rawtypes" }) @Test void shouldResolveNamedOperationWithParameter(@Mock final User user, - @Mock final NamedOperationCache cache) - throws OperationException, CacheOperationException { + @Mock final Context context, + @Mock final NamedOperationCache cache) + throws CacheOperationException { // Given - final String opName = "opName"; final NamedOperationResolver resolver = new NamedOperationResolver(cache); final Map paramMap = new HashMap<>(); paramMap.put("param1", 1L); - final ParameterDetail param = new ParameterDetail.Builder() - .defaultValue(1L) - .description("Limit param") - .valueClass(Long.class) - .build(); - final Map paramDetailMap = new HashMap<>(); - paramDetailMap.put("param1", param); - // Make a real NamedOperationDetail with a parameter - final NamedOperationDetail namedOpDetail = new NamedOperationDetail.Builder() - .operationName(opName) - .description("standard operation") - .operationChain("{ \"operations\": [ { \"class\":\"uk.gov.gchq.gaffer.operation.impl.get.GetAllElements\" }, " - + "{ \"class\":\"uk.gov.gchq.gaffer.operation.impl.Limit\", \"resultLimit\": \"${param1}\" } ] }") - .parameters(paramDetailMap) - .build(); + final NamedOperationDetail namedOpDetail = getValidNamedOperation(); - given(cache.getNamedOperation(opName, user)).willReturn(namedOpDetail); + given(cache.getNamedOperation(OP_NAME, user)).willReturn(namedOpDetail); + given(context.getUser()).willReturn(user); final OperationChain opChain = new OperationChain.Builder() .first(new NamedOperation.Builder<>() - .name(opName) + .name(OP_NAME) .parameters(paramMap) .build()) .build(); // When - resolver.preExecute(opChain, new Context(user)); + resolver.preExecute(opChain, context); // Then - assertThat(opChain.getOperations().get(0)) - .isInstanceOf(OperationChain.class); + assertThat(opChain.getOperations().get(0)).isInstanceOf(OperationChain.class); assertThat(((OperationChain) opChain.getOperations().get(0)).getOperations().get(0)).isInstanceOf(GetAllElements.class); assertThat(((OperationChain) opChain.getOperations().get(0)).getOperations().get(1)).isInstanceOf(Limit.class); // Check the parameter has been inserted - assertThat(((Limit) ((OperationChain) opChain.getOperations().get(0)).getOperations().get(1)).getResultLimit()).isEqualTo(1L); + assertThat(((Limit) ((OperationChain) opChain.getOperations().get(0)).getOperations().get(1)).getResultLimit()).isEqualTo(1); } @Test void shouldNotExecuteNamedOperationWithParameterOfWrongType(@Mock final User user, + @Mock final Context context, @Mock final NamedOperationCache cache) - throws OperationException, CacheOperationException { + throws CacheOperationException { // Given - final String opName = "opName"; final NamedOperationResolver resolver = new NamedOperationResolver(cache); + + // Create Named Op with param of wrong type final Map paramMap = new HashMap<>(); - // A parameter of the wrong type paramMap.put("param1", new ArrayList<>()); - final ParameterDetail param = new ParameterDetail.Builder() - .defaultValue(1L) - .description("Limit param") - .valueClass(Long.class) - .build(); - final Map paramDetailMap = new HashMap<>(); - paramDetailMap.put("param1", param); + final OperationChain wrongParamTypeNamedOp = new OperationChain.Builder() + .first(new NamedOperation.Builder<>() + .name(OP_NAME) + .parameters(paramMap) + .build()) + .build(); // Make a real NamedOperationDetail with a parameter - final NamedOperationDetail namedOpDetail = new NamedOperationDetail.Builder() - .operationName(opName) - .description("standard operation") - .operationChain("{ \"operations\": [ { \"class\":\"uk.gov.gchq.gaffer.operation.impl.get.GetAllElements\" }, " - + "{ \"class\":\"uk.gov.gchq.gaffer.operation.impl.Limit\", \"resultLimit\": \"${param1}\" } ] }") - .parameters(paramDetailMap) - .build(); + final NamedOperationDetail namedOpDetail = getValidNamedOperation(); - given(cache.getNamedOperation(opName, user)).willReturn(namedOpDetail); + given(cache.getNamedOperation(OP_NAME, user)).willReturn(namedOpDetail); + given(context.getUser()).willReturn(user); // When assertThatExceptionOfType(IllegalArgumentException.class) - .isThrownBy(() -> resolver.preExecute(new OperationChain.Builder() - .first(new NamedOperation.Builder<>() - .name(opName) - .parameters(paramMap) - .build()) - .build(), new Context(user))) + .isThrownBy(() -> resolver.preExecute(wrongParamTypeNamedOp, context)) .withMessageContaining("Cannot deserialize value of type"); } @Test void shouldNotExecuteNamedOperationWithWrongParameterName(@Mock final User user, + @Mock final Context context, @Mock final NamedOperationCache cache) - throws OperationException, CacheOperationException { + throws CacheOperationException { // Given - final String opName = "opName"; final NamedOperationResolver resolver = new NamedOperationResolver(cache); - final Map paramMap = new HashMap<>(); + // A parameter with the wrong name + final Map paramMap = new HashMap<>(); paramMap.put("param2", 1L); - final ParameterDetail param = new ParameterDetail.Builder() - .defaultValue(1L) - .description("Limit param") - .valueClass(Long.class) - .build(); - final Map paramDetailMap = new HashMap<>(); - paramDetailMap.put("param1", param); + final OperationChain wrongParamNameNamedOp = new OperationChain.Builder() + .first(new NamedOperation.Builder<>() + .name(OP_NAME) + .parameters(paramMap) + .build()) + .build(); // Make a real NamedOperationDetail with a parameter - final NamedOperationDetail namedOpDetail = new NamedOperationDetail.Builder() - .operationName(opName) - .description("standard operation") - .operationChain("{ \"operations\": [ { \"class\":\"uk.gov.gchq.gaffer.operation.impl.get.GetAllElements\" }, " - + "{ \"class\":\"uk.gov.gchq.gaffer.operation.impl.Limit\", \"resultLimit\": \"${param1}\" } ] }") - .parameters(paramDetailMap) - .build(); + final NamedOperationDetail namedOpDetail = getValidNamedOperation(); - given(cache.getNamedOperation(opName, user)).willReturn(namedOpDetail); + given(cache.getNamedOperation(OP_NAME, user)).willReturn(namedOpDetail); + given(context.getUser()).willReturn(user); // When assertThatExceptionOfType(IllegalArgumentException.class) - .isThrownBy(() -> resolver.preExecute(new OperationChain.Builder() - .first(new NamedOperation.Builder<>() - .name(opName) - .parameters(paramMap) - .build()) - .build(), new Context(user))) + .isThrownBy(() -> resolver.preExecute(wrongParamNameNamedOp, context)) .withMessageContaining("Unexpected parameter name in NamedOperation"); } @Test void shouldNotExecuteNamedOperationWithMissingRequiredArg(@Mock final User user, + @Mock final Context context, @Mock final NamedOperationCache cache) - throws OperationException, CacheOperationException { + throws CacheOperationException { // Given - final String opName = "opName"; final NamedOperationResolver resolver = new NamedOperationResolver(cache); // Don't set any parameters final Map paramMap = new HashMap<>(); - final ParameterDetail param = new ParameterDetail.Builder() - .description("Limit param") - .valueClass(Long.class) - .required(true) - .build(); - final Map paramDetailMap = new HashMap<>(); - paramDetailMap.put("param1", param); + final OperationChain badParamNamedOp = new OperationChain.Builder() + .first(new NamedOperation.Builder<>() + .name(OP_NAME) + .parameters(paramMap) + .build()) + .build(); // Make a real NamedOperationDetail with a parameter - final NamedOperationDetail namedOpDetail = new NamedOperationDetail.Builder() - .operationName(opName) - .description("standard operation") - .operationChain("{ \"operations\": [ { \"class\":\"uk.gov.gchq.gaffer.operation.impl.get.GetAllElements\" }, " - + "{ \"class\":\"uk.gov.gchq.gaffer.operation.impl.Limit\", \"resultLimit\": \"${param1}\" } ] }") - .parameters(paramDetailMap) - .build(); + final NamedOperationDetail namedOpDetail = getValidNamedOperation(); - given(cache.getNamedOperation(opName, user)).willReturn(namedOpDetail); + given(cache.getNamedOperation(OP_NAME, user)).willReturn(namedOpDetail); + given(context.getUser()).willReturn(user); // When assertThatExceptionOfType(IllegalArgumentException.class) - .isThrownBy(() -> resolver.preExecute(new OperationChain.Builder() - .first(new NamedOperation.Builder<>() - .name(opName) - .parameters(paramMap) - .build()) - .build(), new Context(user))) + .isThrownBy(() -> resolver.preExecute(badParamNamedOp, context)) .withMessageContaining("Missing parameter param1 with no default"); } @@ -499,4 +462,31 @@ void shouldReturnOperationsInParameters() { public NamedOperationResolver getTestObject() { return new NamedOperationResolver(SUFFIX_CACHE_NAME); } + + private NamedOperationDetail getValidNamedOperation() { + final ParameterDetail param = new ParameterDetail.Builder() + .description("Limit param") + .valueClass(Long.class) + .required(true) + .build(); + final Map paramDetailMap = new HashMap<>(); + paramDetailMap.put("param1", param); + + final String opChainString = new JSONObject() + .put("operations", new JSONArray() + .put(new JSONObject() + .put("class", "uk.gov.gchq.gaffer.operation.impl.get.GetAllElements")) + .put(new JSONObject() + .put("class", "uk.gov.gchq.gaffer.operation.impl.Limit") + .put("resultLimit", "${param1}"))) + .toString(); + + // Make a real NamedOperationDetail with a parameter + return new NamedOperationDetail.Builder() + .operationName(OP_NAME) + .description("standard operation") + .operationChain(opChainString) + .parameters(paramDetailMap) + .build(); + } } diff --git a/core/store/src/test/java/uk/gov/gchq/gaffer/store/operation/DeleteAllDataTest.java b/core/store/src/test/java/uk/gov/gchq/gaffer/store/operation/DeleteAllDataTest.java index 5be04c7ed42..743378afae7 100644 --- a/core/store/src/test/java/uk/gov/gchq/gaffer/store/operation/DeleteAllDataTest.java +++ b/core/store/src/test/java/uk/gov/gchq/gaffer/store/operation/DeleteAllDataTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2022 Crown Copyright + * Copyright 2024 Crown Copyright * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,24 +16,28 @@ package uk.gov.gchq.gaffer.store.operation; +import org.junit.jupiter.api.Test; + import uk.gov.gchq.gaffer.operation.OperationTest; import static org.assertj.core.api.Assertions.assertThat; public class DeleteAllDataTest extends OperationTest { - + @Test @Override public void builderShouldCreatePopulatedOperation() { final DeleteAllData operation = new DeleteAllData.Builder().option("a", "1").build(); - assertThat(operation.getOption("a")).isEqualTo(1); + assertThat(operation.getOption("a")).isEqualTo("1"); } + @Test @Override public void shouldShallowCloneOperation() { final DeleteAllData a = new DeleteAllData(); final DeleteAllData b = a.shallowClone(); - assertThat(a).isNotSameAs(b).isEqualTo(b); + assertThat(a).isNotEqualTo(b); + assertThat(b).isInstanceOf(DeleteAllData.class); } @Override diff --git a/core/type/src/test/java/uk/gov/gchq/gaffer/serialisation/CustomMapSerialiserTest.java b/core/type/src/test/java/uk/gov/gchq/gaffer/serialisation/CustomMapSerialiserTest.java index 5cb1eeefab2..483e904e319 100644 --- a/core/type/src/test/java/uk/gov/gchq/gaffer/serialisation/CustomMapSerialiserTest.java +++ b/core/type/src/test/java/uk/gov/gchq/gaffer/serialisation/CustomMapSerialiserTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2017-2020 Crown Copyright + * Copyright 2017-2024 Crown Copyright * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -25,12 +25,12 @@ import uk.gov.gchq.gaffer.serialisation.implementation.ordered.OrderedIntegerSerialiser; import uk.gov.gchq.gaffer.types.CustomMap; -import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.assertj.core.api.Assertions.assertThat; -public class CustomMapSerialiserTest extends ToBytesSerialisationTest { +class CustomMapSerialiserTest extends ToBytesSerialisationTest { @Test - public void shouldSerialiseStringInt() throws SerialisationException { + void shouldSerialiseStringInt() throws SerialisationException { // Given final CustomMap expected = new CustomMap<>(new StringSerialiser(), new OrderedIntegerSerialiser()); expected.put("one", 111); @@ -40,38 +40,47 @@ public void shouldSerialiseStringInt() throws SerialisationException { final CustomMap deserialise = serialiser.deserialise(serialiser.serialise(expected)); // Then + if (deserialise.equals(expected)) { + return; + } detailedEquals(expected, deserialise, String.class, Integer.class, new StringSerialiser(), new OrderedIntegerSerialiser()); } - private void detailedEquals(final CustomMap expected, final CustomMap actual, final Class expectedKClass, final Class expectedVClass, final ToBytesSerialiser kS, final ToBytesSerialiser vS) { - try { - assertEquals(expected, actual); - } catch (AssertionError e) { - //Serialiser - assertEquals(kS, expected.getKeySerialiser()); - assertEquals(kS, actual.getKeySerialiser()); - assertEquals(vS, expected.getValueSerialiser()); - assertEquals(vS, actual.getValueSerialiser()); - assertEquals(expected.getKeySerialiser(), actual.getKeySerialiser()); - //Key element - assertEquals(expectedKClass, expected.keySet().iterator().next().getClass()); - assertEquals(expectedKClass, actual.keySet().iterator().next().getClass()); - //Value element - assertEquals(expectedVClass, expected.values().iterator().next().getClass()); - assertEquals(expectedVClass, actual.values().iterator().next().getClass()); - //ketSets - assertEquals(expected.keySet(), actual.keySet()); - //values - for (Object k : expected.keySet()) { - final Object expectedV = expected.get(k); - final Object actualV = actual.get(k); - assertEquals(expectedV.getClass(), actualV.getClass()); - assertEquals(expectedVClass, actualV.getClass()); - assertEquals(expectedVClass, expectedV.getClass()); - assertEquals(expectedV, actualV); - } - assertEquals(expected, actual); + private void detailedEquals(final CustomMap expected, + final CustomMap actual, + final Class expectedKClass, + final Class expectedVClass, + final ToBytesSerialiser kS, + final ToBytesSerialiser vS) { + + // Serialiser + assertThat(expected.getKeySerialiser()).isEqualTo(kS); + assertThat(actual.getKeySerialiser()).isEqualTo(kS); + assertThat(expected.getValueSerialiser()).isEqualTo(vS); + assertThat(actual.getValueSerialiser()).isEqualTo(vS); + assertThat(actual.getKeySerialiser()).isEqualTo(expected.getKeySerialiser()); + + // Key element + assertThat(expected.keySet().iterator().next().getClass()).isEqualTo(expectedKClass); + assertThat(actual.keySet().iterator().next().getClass()).isEqualTo(expectedKClass); + + // Value element + assertThat(expected.values().iterator().next().getClass()).isEqualTo(expectedVClass); + assertThat(actual.values().iterator().next().getClass()).isEqualTo(expectedVClass); + + // keySets + assertThat(actual.keySet()).isEqualTo(expected.keySet()); + + //values + for (Object k : expected.keySet()) { + final Object expectedV = expected.get(k); + final Object actualV = actual.get(k); + assertThat(actualV.getClass()).isEqualTo(expectedV.getClass()); + assertThat(actualV.getClass()).isEqualTo(expectedVClass); + assertThat(expectedV.getClass()).isEqualTo(expectedVClass); + assertThat(actualV).isEqualTo(expectedV); } + assertThat(actual).isEqualTo(expected); } @Override @@ -81,7 +90,7 @@ public Serialiser getSerialisation() { @Override public Pair[] getHistoricSerialisationPairs() { - final CustomMap cm1 = new CustomMap(new StringSerialiser(), new OrderedIntegerSerialiser()); + final CustomMap cm1 = new CustomMap<>(new StringSerialiser(), new OrderedIntegerSerialiser()); cm1.put("One", 1); final CustomMap cm2 = new CustomMap<>(new OrderedFloatSerialiser(), new StringSerialiser()); diff --git a/library/cache-library/jcs-cache-service/src/test/java/uk/gov/gchq/gaffer/cache/impl/JcsCacheTest.java b/library/cache-library/jcs-cache-service/src/test/java/uk/gov/gchq/gaffer/cache/impl/JcsCacheTest.java index 11a802991ec..a48b99990c0 100644 --- a/library/cache-library/jcs-cache-service/src/test/java/uk/gov/gchq/gaffer/cache/impl/JcsCacheTest.java +++ b/library/cache-library/jcs-cache-service/src/test/java/uk/gov/gchq/gaffer/cache/impl/JcsCacheTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2017-2021 Crown Copyright + * Copyright 2017-2024 Crown Copyright * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -27,38 +27,36 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatExceptionOfType; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.fail; -public class JcsCacheTest { +class JcsCacheTest { private static JcsCache cache; @BeforeAll - public static void setUp() throws CacheException { + static void setUp() throws CacheException { CompositeCacheManager manager = CompositeCacheManager.getInstance(); cache = new JcsCache<>(manager.getCache("test")); } @BeforeEach - public void before() throws CacheOperationException { + void before() throws CacheOperationException { cache.clear(); } @Test - public void shouldThrowAnExceptionIfEntryAlreadyExistsWhenUsingPutSafe() { - try { - cache.put("test", 1); - cache.putSafe("test", 1); - fail(); - } catch (final OverwritingException | CacheOperationException e) { - assertEquals("Cache entry already exists for key: test", e.getMessage()); - } + void shouldThrowAnExceptionIfEntryAlreadyExistsWhenUsingPutSafe() throws CacheOperationException { + // given + cache.put("test", 1); + + // then + assertThatExceptionOfType(OverwritingException.class) + .isThrownBy(() -> cache.putSafe("test", 1)) + .withMessage("Cache entry already exists for key: test"); } @Test - public void shouldThrowExceptionWhenAddingNullKeyToCache() { + void shouldThrowExceptionWhenAddingNullKeyToCache() { assertThatExceptionOfType(CacheOperationException.class) .isThrownBy(() -> cache.put(null, 2)) .extracting("message") @@ -66,7 +64,7 @@ public void shouldThrowExceptionWhenAddingNullKeyToCache() { } @Test - public void shouldThrowExceptionIfAddingNullValue() { + void shouldThrowExceptionIfAddingNullValue() { assertThatExceptionOfType(CacheOperationException.class) .isThrownBy(() -> cache.put("test", null)) .extracting("message") @@ -74,7 +72,7 @@ public void shouldThrowExceptionIfAddingNullValue() { } @Test - public void shouldAddToCache() throws CacheOperationException { + void shouldAddToCache() throws CacheOperationException { // when cache.put("key", 1); @@ -84,17 +82,17 @@ public void shouldAddToCache() throws CacheOperationException { } @Test - public void shouldReadFromCache() throws CacheOperationException { + void shouldReadFromCache() throws CacheOperationException { // when cache.put("key", 2); // then - assertEquals(new Integer(2), cache.get("key")); + assertThat(cache.get("key")).isEqualTo(2); } @Test - public void shouldDeleteCachedEntries() throws CacheOperationException { + void shouldDeleteCachedEntries() throws CacheOperationException { // given cache.put("key", 3); @@ -107,7 +105,7 @@ public void shouldDeleteCachedEntries() throws CacheOperationException { } @Test - public void shouldUpdateCachedEntries() throws CacheOperationException { + void shouldUpdateCachedEntries() throws CacheOperationException { // given cache.put("key", 4); @@ -117,11 +115,11 @@ public void shouldUpdateCachedEntries() throws CacheOperationException { // then assertThat(cache.size()).isOne(); - assertEquals(new Integer(5), cache.get("key")); + assertThat(cache.get("key")).isEqualTo(5); } @Test - public void shouldRemoveAllEntries() throws CacheOperationException { + void shouldRemoveAllEntries() throws CacheOperationException { // given cache.put("key1", 1); @@ -136,7 +134,7 @@ public void shouldRemoveAllEntries() throws CacheOperationException { } @Test - public void shouldGetAllKeys() throws CacheOperationException { + void shouldGetAllKeys() throws CacheOperationException { cache.put("test1", 1); cache.put("test2", 2); cache.put("test3", 3); @@ -146,14 +144,14 @@ public void shouldGetAllKeys() throws CacheOperationException { } @Test - public void shouldGetAllValues() throws CacheOperationException { + void shouldGetAllValues() throws CacheOperationException { cache.put("test1", 1); cache.put("test2", 2); cache.put("test3", 3); cache.put("duplicate", 3); assertThat(cache.size()).isEqualTo(4); - assertEquals(4, cache.getAllValues().size()); + assertThat(cache.getAllValues()).hasSize(4); assertThat(cache.getAllValues()).contains(1, 2, 3); } diff --git a/library/hdfs-library/src/test/java/uk/gov/gchq/gaffer/hdfs/integration/loader/AddElementsFromHdfsLoaderIT.java b/library/hdfs-library/src/test/java/uk/gov/gchq/gaffer/hdfs/integration/loader/AddElementsFromHdfsLoaderIT.java index 7b287789051..db339935b0d 100644 --- a/library/hdfs-library/src/test/java/uk/gov/gchq/gaffer/hdfs/integration/loader/AddElementsFromHdfsLoaderIT.java +++ b/library/hdfs-library/src/test/java/uk/gov/gchq/gaffer/hdfs/integration/loader/AddElementsFromHdfsLoaderIT.java @@ -1,5 +1,5 @@ /* - * Copyright 2018-2022 Crown Copyright + * Copyright 2018-2024 Crown Copyright * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -89,7 +89,7 @@ public BasicSchemaAddElementsLoaderIT() { } } - private static class AddElementsFromHdfsLoader extends UserLoaderIT { + static class AddElementsFromHdfsLoader extends UserLoaderIT { @TempDir public File testFolder; @@ -133,7 +133,7 @@ public void _setup() throws Exception { } @Test - public void shouldThrowExceptionWhenAddElementsFromHdfsWhenFailureDirectoryContainsFiles(final TestInfo testInfo) throws Exception { + void shouldThrowExceptionWhenAddElementsFromHdfsWhenFailureDirectoryContainsFiles(final TestInfo testInfo) throws Exception { tearDown(); fs.mkdirs(new Path(failureDir)); try (final BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(fs.create(new Path(failureDir + "/someFile.txt"), true)))) { @@ -146,7 +146,7 @@ public void shouldThrowExceptionWhenAddElementsFromHdfsWhenFailureDirectoryConta } @Test - public void shouldAddElementsFromHdfsWhenDirectoriesAlreadyExist(TestInfo testInfo) throws Exception { + void shouldAddElementsFromHdfsWhenDirectoriesAlreadyExist(TestInfo testInfo) throws Exception { // Given tearDown(); fs.mkdirs(new Path(outputDir)); @@ -160,7 +160,7 @@ public void shouldAddElementsFromHdfsWhenDirectoriesAlreadyExist(TestInfo testIn } @Test - public void shouldThrowExceptionWhenAddElementsFromHdfsWhenOutputDirectoryContainsFiles(final TestInfo testInfo) throws Exception { + void shouldThrowExceptionWhenAddElementsFromHdfsWhenOutputDirectoryContainsFiles(final TestInfo testInfo) throws Exception { // Given tearDown(); fs.mkdirs(new Path(outputDir)); diff --git a/library/time-library/src/test/java/uk/gov/gchq/gaffer/time/serialisation/RBMBackedTimestampSetSerialiserTest.java b/library/time-library/src/test/java/uk/gov/gchq/gaffer/time/serialisation/RBMBackedTimestampSetSerialiserTest.java index b5a403c2ab5..c92a7506a83 100644 --- a/library/time-library/src/test/java/uk/gov/gchq/gaffer/time/serialisation/RBMBackedTimestampSetSerialiserTest.java +++ b/library/time-library/src/test/java/uk/gov/gchq/gaffer/time/serialisation/RBMBackedTimestampSetSerialiserTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2017-2023 Crown Copyright + * Copyright 2017-2024 Crown Copyright * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -43,14 +43,13 @@ import java.util.Random; import java.util.stream.IntStream; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertFalse; -import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.catchThrowable; -public class RBMBackedTimestampSetSerialiserTest extends ToBytesSerialisationTest { +class RBMBackedTimestampSetSerialiserTest extends ToBytesSerialisationTest { @Test - public void testSerialiser() throws SerialisationException { + void testSerialiser() throws SerialisationException { // Given final RBMBackedTimestampSet rbmBackedTimestampSet = getExampleValue(); @@ -59,7 +58,7 @@ public void testSerialiser() throws SerialisationException { final RBMBackedTimestampSet deserialised = serialiser.deserialise(serialised); // Then - assertEquals(rbmBackedTimestampSet, deserialised); + assertThat(deserialised).isEqualTo(rbmBackedTimestampSet); } private RBMBackedTimestampSet getExampleValue() { @@ -70,13 +69,13 @@ private RBMBackedTimestampSet getExampleValue() { } @Test - public void testCanHandle() throws SerialisationException { - assertTrue(serialiser.canHandle(RBMBackedTimestampSet.class)); - assertFalse(serialiser.canHandle(String.class)); + void testCanHandle() { + assertThat(serialiser.canHandle(RBMBackedTimestampSet.class)).isTrue(); + assertThat(serialiser.canHandle(String.class)).isFalse(); } @Test - public void testSerialisationSizesQuotedInJavadoc() throws SerialisationException { + void testSerialisationSizesQuotedInJavadoc() throws SerialisationException { // Given final Random random = new Random(123456789L); final Instant instant = ZonedDateTime.of(2017, 1, 1, 1, 1, 1, 0, ZoneId.of("UTC")).toInstant(); @@ -99,13 +98,13 @@ public void testSerialisationSizesQuotedInJavadoc() throws SerialisationExceptio final int lengthSet3 = serialiser.serialise(rbmBackedTimestampSet3).length; // Then - assertTrue(200 < lengthSet1 && lengthSet1 < 220); - assertTrue(72000 < lengthSet2 && lengthSet2 < 74000); - assertTrue(3900000 < lengthSet3 && lengthSet3 < 4100000); + assertThat(lengthSet1).isBetween(200, 220); + assertThat(lengthSet2).isBetween(72000, 74000); + assertThat(lengthSet3).isBetween(3900000, 4100000); } @Test - public void shouldSerialiserStringRBMBackedTimestampSet() throws SerialisationException { + void shouldSerialiserStringRBMBackedTimestampSet() throws SerialisationException { // Given final Serialiser customMapSerialiser = new CustomMapSerialiser(); final RBMBackedTimestampSet timestampSet1 = new RBMBackedTimestampSet.Builder() @@ -126,43 +125,48 @@ public void shouldSerialiserStringRBMBackedTimestampSet() throws SerialisationEx // When final CustomMap deserialise = customMapSerialiser.deserialise(customMapSerialiser.serialise(expected)); + // Then detailedEquals(expected, deserialise, String.class, RBMBackedTimestampSet.class, new StringSerialiser(), new RBMBackedTimestampSetSerialiser()); } private void detailedEquals(final CustomMap expected, final CustomMap actual, final Class expectedKClass, final Class expectedVClass, final ToBytesSerialiser kS, final ToBytesSerialiser vS) { - try { - assertEquals(expected, actual); - } catch (AssertionError e) { - //Serialiser - assertEquals(kS, expected.getKeySerialiser()); - assertEquals(kS, actual.getKeySerialiser()); - assertEquals(vS, expected.getValueSerialiser()); - assertEquals(vS, actual.getValueSerialiser()); - assertEquals(expected.getKeySerialiser(), actual.getKeySerialiser()); - //Key element - assertEquals(expectedKClass, expected.keySet().iterator().next().getClass()); - assertEquals(expectedKClass, actual.keySet().iterator().next().getClass()); - //Value element - assertEquals(expectedVClass, expected.values().iterator().next().getClass()); - assertEquals(expectedVClass, actual.values().iterator().next().getClass()); - //ketSets - assertEquals(expected.keySet(), actual.keySet()); + Throwable thrown = catchThrowable(() -> assertThat(actual).isEqualTo(expected)); + + if (thrown != null) { + // Serialiser + assertThat(expected.getKeySerialiser()).isEqualTo(kS); + assertThat(actual.getKeySerialiser()).isEqualTo(kS); + assertThat(expected.getValueSerialiser()).isEqualTo(vS); + assertThat(actual.getValueSerialiser()).isEqualTo(vS); + assertThat(actual.getKeySerialiser()).isEqualTo(expected.getKeySerialiser()); + + // Key element + assertThat(expected.keySet().iterator().next().getClass()).isEqualTo(expectedKClass); + assertThat(actual.keySet().iterator().next().getClass()).isEqualTo(expectedKClass); + + // Value element + assertThat(expected.values().iterator().next().getClass()).isEqualTo(expectedVClass); + assertThat(actual.values().iterator().next().getClass()).isEqualTo(expectedVClass); + + // keySets + assertThat(actual.keySet()).isEqualTo(expected.keySet()); + //values for (Object k : expected.keySet()) { final Object expectedV = expected.get(k); final Object actualV = actual.get(k); - assertEquals(expectedV.getClass(), actualV.getClass()); - assertEquals(expectedVClass, actualV.getClass()); - assertEquals(expectedVClass, expectedV.getClass()); - assertEquals(expectedV, actualV); + assertThat(actualV.getClass()).isEqualTo(expectedV.getClass()); + assertThat(actualV.getClass()).isEqualTo(expectedVClass); + assertThat(expectedV.getClass()).isEqualTo(expectedVClass); + assertThat(actualV).isEqualTo(expectedV); } - assertEquals(expected, actual); + assertThat(actual).isEqualTo(expected); } } @Test - public void shouldJSONSerialiseFloatRDM() throws IOException { + void shouldJSONSerialiseFloatRDM() throws IOException { //given System.setProperty(JSONSerialiser.JSON_SERIALISER_MODULES, BitmapJsonModules.class.getCanonicalName()); @@ -188,8 +192,8 @@ public void shouldJSONSerialiseFloatRDM() throws IOException { final CustomMap deserialiseMap = JSONSerialiser.deserialise(serialise, CustomMap.class); //then - assertEquals(jsonMap, deserialiseMap, "The expected map from Json doesn't match"); - assertEquals(expectedMap, deserialiseMap, "The expected map doesn't match"); + assertThat(jsonMap).isEqualTo(expectedMap); + assertThat(deserialiseMap).isEqualTo(expectedMap); } protected String jsonFromFile(final String path) throws IOException { From 2b208e63037e3b1be4ec0045d19e909b7ad794e4 Mon Sep 17 00:00:00 2001 From: tb06904 <141412860+tb06904@users.noreply.github.com> Date: Thu, 8 Aug 2024 15:29:22 +0000 Subject: [PATCH 15/16] Gh-3254: Standardise Spring REST user authentication (#3263) * remove unnecessary controller interfaces and add http header setting * test tweaks * Update rest-api/spring-rest/src/main/java/uk/gov/gchq/gaffer/rest/controller/JobController.java Co-authored-by: cn337131 <141730190+cn337131@users.noreply.github.com> --------- Co-authored-by: cn337131 <141730190+cn337131@users.noreply.github.com> Co-authored-by: wb36499 <166839644+wb36499@users.noreply.github.com> --- .../GraphConfigurationController.java | 55 ++++-- .../IGraphConfigurationController.java | 167 ------------------ .../rest/controller/IJobController.java | 80 --------- .../rest/controller/IOperationController.java | 129 -------------- .../controller/IPropertiesController.java | 51 ------ .../rest/controller/IStatusController.java | 40 ----- .../gaffer/rest/controller/JobController.java | 59 +++++-- .../rest/controller/OperationController.java | 55 ++++-- .../rest/controller/PropertiesController.java | 20 ++- .../rest/controller/StatusController.java | 16 +- .../controller/OperationControllerTest.java | 11 +- 11 files changed, 157 insertions(+), 526 deletions(-) delete mode 100644 rest-api/spring-rest/src/main/java/uk/gov/gchq/gaffer/rest/controller/IGraphConfigurationController.java delete mode 100644 rest-api/spring-rest/src/main/java/uk/gov/gchq/gaffer/rest/controller/IJobController.java delete mode 100644 rest-api/spring-rest/src/main/java/uk/gov/gchq/gaffer/rest/controller/IOperationController.java delete mode 100644 rest-api/spring-rest/src/main/java/uk/gov/gchq/gaffer/rest/controller/IPropertiesController.java delete mode 100644 rest-api/spring-rest/src/main/java/uk/gov/gchq/gaffer/rest/controller/IStatusController.java diff --git a/rest-api/spring-rest/src/main/java/uk/gov/gchq/gaffer/rest/controller/GraphConfigurationController.java b/rest-api/spring-rest/src/main/java/uk/gov/gchq/gaffer/rest/controller/GraphConfigurationController.java index eff5bf5b5c1..647abc722f9 100644 --- a/rest-api/spring-rest/src/main/java/uk/gov/gchq/gaffer/rest/controller/GraphConfigurationController.java +++ b/rest-api/spring-rest/src/main/java/uk/gov/gchq/gaffer/rest/controller/GraphConfigurationController.java @@ -1,5 +1,5 @@ /* - * Copyright 2020-2023 Crown Copyright + * Copyright 2020-2024 Crown Copyright * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,11 +16,16 @@ package uk.gov.gchq.gaffer.rest.controller; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; + import org.apache.commons.lang3.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import uk.gov.gchq.gaffer.core.exception.GafferRuntimeException; @@ -44,8 +49,13 @@ import java.util.function.Function; import java.util.function.Predicate; +import static org.springframework.http.MediaType.APPLICATION_JSON_VALUE; +import static org.springframework.http.MediaType.TEXT_PLAIN_VALUE; + @RestController -public class GraphConfigurationController implements IGraphConfigurationController { +@Tag(name = "config") +@RequestMapping("/rest/graph/config") +public class GraphConfigurationController { private static final Logger LOGGER = LoggerFactory.getLogger(GraphConfigurationController.class); @@ -56,32 +66,38 @@ public GraphConfigurationController(final GraphFactory graphFactory) { this.graphFactory = graphFactory; } - @Override + @GetMapping(path = "/schema", produces = APPLICATION_JSON_VALUE) + @Operation(summary = "Gets the schema") public Schema getSchema() { return graphFactory.getGraph().getSchema(); } - @Override + @GetMapping(path = "/description", produces = TEXT_PLAIN_VALUE) + @Operation(summary = "Gets the graph description") public String getDescription() { return graphFactory.getGraph().getDescription(); } - @Override + @GetMapping(path = "/graphId", produces = TEXT_PLAIN_VALUE) + @Operation(summary = "Gets the graph Id") public String getGraphId() { return graphFactory.getGraph().getGraphId(); } - @Override + @GetMapping(path = "/filterFunctions", produces = APPLICATION_JSON_VALUE) + @Operation(summary = "Gets the available filter functions") public Set getFilterFunctions() { return ReflectionUtil.getSubTypes(Predicate.class); } - @Override + @GetMapping(path = "/elementGenerators", produces = APPLICATION_JSON_VALUE) + @Operation(summary = "Gets the available element generators") public Set getElementGenerators() { return ReflectionUtil.getSubTypes(ElementGenerator.class); } - @Override + @GetMapping(path = "/filterFunctions/{inputClass}", produces = APPLICATION_JSON_VALUE) + @Operation(summary = "Gets the available filter functions for a given input class") public Set getFilterFunctions(@PathVariable("inputClass") final String inputClass) { if (StringUtils.isEmpty(inputClass)) { return getFilterFunctions(); @@ -119,29 +135,32 @@ public Set getFilterFunctions(@PathVariable("inputClass") final String in return applicablePredicates; } - @Override + @GetMapping(path = "/objectGenerators", produces = APPLICATION_JSON_VALUE) + @Operation(summary = "Gets the available object generators") public Set getObjectGenerators() { return ReflectionUtil.getSubTypes(ObjectGenerator.class); } - - @Override + @GetMapping(path = "/serialisedFields/{className}", produces = APPLICATION_JSON_VALUE) + @Operation(summary = "Gets the serialised fields for a given class") public Set getSerialisedFields(@PathVariable("className") final String className) { return JsonSerialisationUtil.getSerialisedFieldClasses(className).keySet(); } - - @Override + @GetMapping(path = "/serialisedFields/{className}/classes", produces = APPLICATION_JSON_VALUE) + @Operation(summary = "Gets the serialised fields and their classes for a given class") public Map getSerialisedFieldClasses(@PathVariable("className") final String className) { return JsonSerialisationUtil.getSerialisedFieldClasses(className); } - @Override + @GetMapping(path = "/storeType", produces = TEXT_PLAIN_VALUE) + @Operation(summary = "Gets the store type") public String getStoreType() { return graphFactory.getGraph().getStoreProperties().getStoreClass(); } - @Override + @GetMapping(path = "/storeTraits", produces = APPLICATION_JSON_VALUE) + @Operation(summary = "Gets all store traits supported by this store") public Set getStoreTraits() { try { return graphFactory.getGraph().execute(new GetTraits.Builder().currentTraits(false).build(), new Context()); @@ -150,12 +169,14 @@ public Set getStoreTraits() { } } - @Override + @GetMapping(path = "/transformFunctions", produces = APPLICATION_JSON_VALUE) + @Operation(summary = "Gets the available transform functions") public Set getTransformFunctions() { return ReflectionUtil.getSubTypes(Function.class); } - @Override + @GetMapping(path = "/aggregationFunctions", produces = APPLICATION_JSON_VALUE) + @Operation(summary = "Gets the available aggregation functions") public Set getAggregationFunctions() { return ReflectionUtil.getSubTypes(BinaryOperator.class); } diff --git a/rest-api/spring-rest/src/main/java/uk/gov/gchq/gaffer/rest/controller/IGraphConfigurationController.java b/rest-api/spring-rest/src/main/java/uk/gov/gchq/gaffer/rest/controller/IGraphConfigurationController.java deleted file mode 100644 index ea7732745f8..00000000000 --- a/rest-api/spring-rest/src/main/java/uk/gov/gchq/gaffer/rest/controller/IGraphConfigurationController.java +++ /dev/null @@ -1,167 +0,0 @@ -/* - * Copyright 2020-2024 Crown Copyright - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package uk.gov.gchq.gaffer.rest.controller; - -import io.swagger.v3.oas.annotations.Operation; -import io.swagger.v3.oas.annotations.tags.Tag; - -import org.springframework.web.bind.annotation.RequestMapping; - -import uk.gov.gchq.gaffer.store.StoreTrait; -import uk.gov.gchq.gaffer.store.schema.Schema; - -import java.util.Map; -import java.util.Set; - -import static org.springframework.http.MediaType.APPLICATION_JSON_VALUE; -import static org.springframework.http.MediaType.TEXT_PLAIN_VALUE; -import static org.springframework.web.bind.annotation.RequestMethod.GET; - -@Tag(name = "config") -@RequestMapping("/rest/graph/config") -public interface IGraphConfigurationController { - - @RequestMapping( - path = "/schema", - method = GET, - produces = APPLICATION_JSON_VALUE - ) - @Operation( - summary = "Gets the schema" - ) - Schema getSchema(); - - @RequestMapping( - path = "/description", - method = GET, - produces = TEXT_PLAIN_VALUE - ) - @Operation( - summary = "Gets the graph description" - ) - String getDescription(); - - @RequestMapping( - path = "/graphId", - method = GET, - produces = TEXT_PLAIN_VALUE - ) - @Operation( - summary = "Gets the graph Id" - ) - String getGraphId(); - - @RequestMapping( - path = "/filterFunctions", - method = GET, - produces = APPLICATION_JSON_VALUE - ) - @Operation( - summary = "Gets the available filter functions" - ) - Set getFilterFunctions(); - - @RequestMapping( - path = "/elementGenerators", - method = GET, - produces = APPLICATION_JSON_VALUE - ) - @Operation( - summary = "Gets the available element generators" - ) - Set getElementGenerators(); - - @RequestMapping( - path = "/filterFunctions/{inputClass}", - produces = APPLICATION_JSON_VALUE, - method = GET - ) - @Operation( - summary = "Gets the available filter functions for a given input class" - ) - Set getFilterFunctions(final String inputClass); - - @RequestMapping( - path = "/objectGenerators", - method = GET, - produces = APPLICATION_JSON_VALUE - ) - @Operation( - summary = "Gets the available object generators" - ) - Set getObjectGenerators(); - - @RequestMapping( - path = "/serialisedFields/{className}", - method = GET, - produces = APPLICATION_JSON_VALUE - ) - @Operation( - summary = "Gets the serialised fields for a given class" - ) - Set getSerialisedFields(final String className); - - @RequestMapping( - path = "/serialisedFields/{className}/classes", - method = GET, - produces = APPLICATION_JSON_VALUE - ) - @Operation( - summary = "Gets the serialised fields and their classes for a given class" - ) - Map getSerialisedFieldClasses(final String className); - - @RequestMapping( - path = "/storeType", - method = GET, - produces = TEXT_PLAIN_VALUE - ) - @Operation( - summary = "Gets the store type" - ) - String getStoreType(); - - @RequestMapping( - path = "/storeTraits", - method = GET, - produces = APPLICATION_JSON_VALUE - ) - @Operation( - summary = "Gets all store traits supported by this store" - ) - Set getStoreTraits(); - - @RequestMapping( - path = "/transformFunctions", - method = GET, - produces = APPLICATION_JSON_VALUE - ) - @Operation( - summary = "Gets the available transform functions" - ) - Set getTransformFunctions(); - - @RequestMapping( - path = "/aggregationFunctions", - method = GET, - produces = APPLICATION_JSON_VALUE - ) - @Operation( - summary = "Gets the available aggregation functions" - ) - Set getAggregationFunctions(); -} diff --git a/rest-api/spring-rest/src/main/java/uk/gov/gchq/gaffer/rest/controller/IJobController.java b/rest-api/spring-rest/src/main/java/uk/gov/gchq/gaffer/rest/controller/IJobController.java deleted file mode 100644 index 6d766b6ba76..00000000000 --- a/rest-api/spring-rest/src/main/java/uk/gov/gchq/gaffer/rest/controller/IJobController.java +++ /dev/null @@ -1,80 +0,0 @@ -/* - * Copyright 2020-2024 Crown Copyright - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package uk.gov.gchq.gaffer.rest.controller; - -import io.swagger.v3.oas.annotations.tags.Tag; -import org.springframework.http.ResponseEntity; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.PostMapping; -import org.springframework.web.bind.annotation.RequestMapping; - -import uk.gov.gchq.gaffer.jobtracker.Job; -import uk.gov.gchq.gaffer.jobtracker.JobDetail; -import uk.gov.gchq.gaffer.operation.Operation; -import uk.gov.gchq.gaffer.operation.OperationException; - -import static org.springframework.http.MediaType.APPLICATION_JSON_VALUE; - -@Tag(name = "job") -@RequestMapping("/rest/graph/jobs") -public interface IJobController { - - @PostMapping( - consumes = APPLICATION_JSON_VALUE, - produces = APPLICATION_JSON_VALUE - ) - @io.swagger.v3.oas.annotations.Operation( - summary = "Kicks off an asynchronous job" - ) - ResponseEntity startJob(final Operation operation) throws OperationException; - - @PostMapping( - path = "/schedule", - consumes = APPLICATION_JSON_VALUE, - produces = APPLICATION_JSON_VALUE - ) - @io.swagger.v3.oas.annotations.Operation( - summary = "schedules an asynchronous job" - ) - ResponseEntity scheduleJob(final Job job) throws OperationException; - - @GetMapping( - path = "/{id}", - produces = APPLICATION_JSON_VALUE - ) - @io.swagger.v3.oas.annotations.Operation( - summary = "Retrieves the details of an asynchronous job" - ) - JobDetail getDetails(final String id) throws OperationException; - - @GetMapping( - produces = APPLICATION_JSON_VALUE - ) - @io.swagger.v3.oas.annotations.Operation( - summary = "Retrieves the details of all the asynchronous jobs" - ) - Iterable getAllDetails() throws OperationException; - - @GetMapping( - path = "/{id}/results", - produces = APPLICATION_JSON_VALUE - ) - @io.swagger.v3.oas.annotations.Operation( - summary = "Retrieves the results of an asynchronous job" - ) - Object getResults(final String id) throws OperationException; -} diff --git a/rest-api/spring-rest/src/main/java/uk/gov/gchq/gaffer/rest/controller/IOperationController.java b/rest-api/spring-rest/src/main/java/uk/gov/gchq/gaffer/rest/controller/IOperationController.java deleted file mode 100644 index 669f928cd2a..00000000000 --- a/rest-api/spring-rest/src/main/java/uk/gov/gchq/gaffer/rest/controller/IOperationController.java +++ /dev/null @@ -1,129 +0,0 @@ -/* - * Copyright 2020-2024 Crown Copyright - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package uk.gov.gchq.gaffer.rest.controller; - -import io.swagger.v3.oas.annotations.tags.Tag; -import org.springframework.http.ResponseEntity; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.servlet.mvc.method.annotation.StreamingResponseBody; - -import uk.gov.gchq.gaffer.operation.Operation; -import uk.gov.gchq.gaffer.rest.model.OperationDetail; - -import java.util.Set; - -import static org.springframework.http.MediaType.APPLICATION_JSON_VALUE; -import static org.springframework.web.bind.annotation.RequestMethod.GET; -import static org.springframework.web.bind.annotation.RequestMethod.POST; - -@Tag(name = "operations") -@RequestMapping("/rest/graph/operations") -public interface IOperationController { - - @RequestMapping( - method = GET, - path = "", - produces = APPLICATION_JSON_VALUE - ) - @io.swagger.v3.oas.annotations.Operation( - summary = "Retrieves a list of supported operations" - ) - Set> getOperations(); - - @RequestMapping( - method = GET, - path = "/all", - produces = APPLICATION_JSON_VALUE - ) - @io.swagger.v3.oas.annotations.Operation( - summary = "Retrieves a list of all operations" - ) - Set> getOperationsIncludingUnsupported(); - - @RequestMapping( - method = GET, - path = "/details", - produces = APPLICATION_JSON_VALUE - ) - @io.swagger.v3.oas.annotations.Operation( - summary = "Returns the details of every operation supported by the store" - ) - Set getAllOperationDetails(); - - @RequestMapping( - method = GET, - path = "/details/all", - produces = APPLICATION_JSON_VALUE - ) - @io.swagger.v3.oas.annotations.Operation( - summary = "Returns the details of every operation" - ) - Set getAllOperationDetailsIncludingUnsupported(); - - @RequestMapping( - method = GET, - value = "{className}", - produces = APPLICATION_JSON_VALUE - ) - @io.swagger.v3.oas.annotations.Operation( - summary = "Gets details about the specified operation class" - ) - OperationDetail getOperationDetails(final String className); - - @RequestMapping( - method = GET, - value = "{className}/next", - produces = APPLICATION_JSON_VALUE - ) - @io.swagger.v3.oas.annotations.Operation( - summary = "Gets the operations that can be chained after a given operation" - ) - Set> getNextOperations(final String className); - - @RequestMapping( - method = GET, - value = "{className}/example", - produces = APPLICATION_JSON_VALUE - ) - @io.swagger.v3.oas.annotations.Operation( - summary = "Gets an example of an operation class" - ) - Operation getOperationExample(final String className); - - - @RequestMapping( - method = POST, - path = "/execute", - consumes = APPLICATION_JSON_VALUE, - produces = APPLICATION_JSON_VALUE - ) - @io.swagger.v3.oas.annotations.Operation( - summary = "Executes an operation against a Store" - ) - ResponseEntity execute(final Operation operation); - - @RequestMapping( - method = POST, - path = "/execute/chunked", - consumes = APPLICATION_JSON_VALUE, - produces = APPLICATION_JSON_VALUE - ) - @io.swagger.v3.oas.annotations.Operation( - summary = "Executes an operation against a Store, returning a chunked output" - ) - ResponseEntity executeChunked(final Operation operation); -} diff --git a/rest-api/spring-rest/src/main/java/uk/gov/gchq/gaffer/rest/controller/IPropertiesController.java b/rest-api/spring-rest/src/main/java/uk/gov/gchq/gaffer/rest/controller/IPropertiesController.java deleted file mode 100644 index ed14c810b3f..00000000000 --- a/rest-api/spring-rest/src/main/java/uk/gov/gchq/gaffer/rest/controller/IPropertiesController.java +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright 2020-2024 Crown Copyright - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package uk.gov.gchq.gaffer.rest.controller; - -import io.swagger.v3.oas.annotations.Operation; -import io.swagger.v3.oas.annotations.tags.Tag; -import org.springframework.web.bind.annotation.RequestMapping; - -import java.util.Map; - -import static org.springframework.http.MediaType.APPLICATION_JSON_VALUE; -import static org.springframework.http.MediaType.TEXT_PLAIN_VALUE; -import static org.springframework.web.bind.annotation.RequestMethod.GET; - -@Tag(name = "properties") -@RequestMapping("/rest/properties") -public interface IPropertiesController { - - @RequestMapping( - method = GET, - produces = APPLICATION_JSON_VALUE - ) - @Operation( - summary = "Get all the Gaffer System properties" - ) - Map getProperties(); - - @RequestMapping( - value = "/{property}", - method = GET, - produces = { TEXT_PLAIN_VALUE, APPLICATION_JSON_VALUE } - ) - @Operation( - summary = "Gets the value of a provided property" - ) - String getProperty(final String property); -} diff --git a/rest-api/spring-rest/src/main/java/uk/gov/gchq/gaffer/rest/controller/IStatusController.java b/rest-api/spring-rest/src/main/java/uk/gov/gchq/gaffer/rest/controller/IStatusController.java deleted file mode 100644 index 24b73577f89..00000000000 --- a/rest-api/spring-rest/src/main/java/uk/gov/gchq/gaffer/rest/controller/IStatusController.java +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright 2020-2024 Crown Copyright - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package uk.gov.gchq.gaffer.rest.controller; - -import io.swagger.v3.oas.annotations.Operation; -import io.swagger.v3.oas.annotations.tags.Tag; -import org.springframework.web.bind.annotation.RequestMapping; - -import uk.gov.gchq.gaffer.rest.SystemStatus; - -import static org.springframework.http.MediaType.APPLICATION_JSON_VALUE; -import static org.springframework.web.bind.annotation.RequestMethod.GET; - -@Tag(name = "status") -@RequestMapping("/rest/graph/status") -public interface IStatusController { - - @RequestMapping( - produces = APPLICATION_JSON_VALUE, - method = GET - ) - @Operation( - summary = "Retrieves the status of the graph" - ) - SystemStatus getStatus(); -} diff --git a/rest-api/spring-rest/src/main/java/uk/gov/gchq/gaffer/rest/controller/JobController.java b/rest-api/spring-rest/src/main/java/uk/gov/gchq/gaffer/rest/controller/JobController.java index 6d288e4e854..adc389cb16d 100644 --- a/rest-api/spring-rest/src/main/java/uk/gov/gchq/gaffer/rest/controller/JobController.java +++ b/rest-api/spring-rest/src/main/java/uk/gov/gchq/gaffer/rest/controller/JobController.java @@ -1,5 +1,5 @@ /* - * Copyright 2020-2022 Crown Copyright + * Copyright 2020-2024 Crown Copyright * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -17,10 +17,17 @@ package uk.gov.gchq.gaffer.rest.controller; import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; + import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.HttpHeaders; import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestHeader; +import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import org.springframework.web.servlet.support.ServletUriComponentsBuilder; @@ -33,28 +40,36 @@ import uk.gov.gchq.gaffer.operation.impl.job.GetJobDetails; import uk.gov.gchq.gaffer.operation.impl.job.GetJobResults; import uk.gov.gchq.gaffer.rest.factory.GraphFactory; -import uk.gov.gchq.gaffer.rest.factory.UserFactory; +import uk.gov.gchq.gaffer.rest.factory.spring.AbstractUserFactory; import java.net.URI; +import static org.springframework.http.MediaType.APPLICATION_JSON_VALUE; + import static uk.gov.gchq.gaffer.rest.ServiceConstants.GAFFER_MEDIA_TYPE; import static uk.gov.gchq.gaffer.rest.ServiceConstants.GAFFER_MEDIA_TYPE_HEADER; import static uk.gov.gchq.gaffer.rest.ServiceConstants.JOB_ID_HEADER; @RestController -public class JobController implements IJobController { +@Tag(name = "job") +@RequestMapping("/rest/graph/jobs") +public class JobController { private final GraphFactory graphFactory; - private final UserFactory userFactory; + private final AbstractUserFactory userFactory; @Autowired - public JobController(final GraphFactory graphFactory, final UserFactory userFactory) { + public JobController(final GraphFactory graphFactory, final AbstractUserFactory userFactory) { this.graphFactory = graphFactory; this.userFactory = userFactory; } - @Override - public ResponseEntity startJob(@RequestBody final Operation operation) throws OperationException { + @PostMapping(consumes = APPLICATION_JSON_VALUE, produces = APPLICATION_JSON_VALUE) + @io.swagger.v3.oas.annotations.Operation(summary = "Kicks off an asynchronous job") + public ResponseEntity startJob( + @RequestHeader final HttpHeaders httpHeaders, + @RequestBody final Operation operation) throws OperationException { + userFactory.setHttpHeaders(httpHeaders); final JobDetail jobDetail = graphFactory.getGraph().executeJob(OperationChain.wrap(operation), userFactory.createContext()); final URI jobUri = ServletUriComponentsBuilder.fromCurrentRequest().pathSegment(jobDetail.getJobId()).build().toUri(); return ResponseEntity.created(jobUri) @@ -63,8 +78,12 @@ public ResponseEntity startJob(@RequestBody final Operation operation .body(jobDetail); } - @Override - public ResponseEntity scheduleJob(@RequestBody final Job job) throws OperationException { + @PostMapping(path = "/schedule", consumes = APPLICATION_JSON_VALUE, produces = APPLICATION_JSON_VALUE) + @io.swagger.v3.oas.annotations.Operation(summary = "Schedules an asynchronous job") + public ResponseEntity scheduleJob( + @RequestHeader final HttpHeaders httpHeaders, + @RequestBody final Job job) throws OperationException { + userFactory.setHttpHeaders(httpHeaders); final JobDetail jobDetail = graphFactory.getGraph().executeJob(job, userFactory.createContext()); final URI jobUri = ServletUriComponentsBuilder.fromCurrentRequest().pathSegment(jobDetail.getJobId()).build().toUri(); return ResponseEntity.created(jobUri) @@ -73,8 +92,12 @@ public ResponseEntity scheduleJob(@RequestBody final Job job) throws .body(jobDetail); } - @Override - public JobDetail getDetails(@PathVariable("id") @Parameter(description = "The Job ID") final String id) throws OperationException { + @GetMapping(path = "/{id}", produces = APPLICATION_JSON_VALUE) + @io.swagger.v3.oas.annotations.Operation(summary = "Retrieves the details of an asynchronous job") + public JobDetail getDetails( + @RequestHeader final HttpHeaders httpHeaders, + @PathVariable("id") @Parameter(description = "The Job ID") final String id) throws OperationException { + userFactory.setHttpHeaders(httpHeaders); return graphFactory.getGraph().execute(new GetJobDetails.Builder() .jobId(id) .build(), @@ -82,13 +105,19 @@ public JobDetail getDetails(@PathVariable("id") @Parameter(description = "The Jo ); } - @Override - public Iterable getAllDetails() throws OperationException { + @GetMapping(produces = APPLICATION_JSON_VALUE) + @io.swagger.v3.oas.annotations.Operation(summary = "Retrieves the details of all the asynchronous jobs") + public Iterable getAllDetails(@RequestHeader final HttpHeaders httpHeaders) throws OperationException { + userFactory.setHttpHeaders(httpHeaders); return graphFactory.getGraph().execute(new GetAllJobDetails(), userFactory.createContext()); } - @Override - public Object getResults(@PathVariable("id") @Parameter(description = "The Job ID") final String id) throws OperationException { + @GetMapping(path = "/{id}/results", produces = APPLICATION_JSON_VALUE) + @io.swagger.v3.oas.annotations.Operation(summary = "Retrieves the results of an asynchronous job") + public Object getResults( + @RequestHeader final HttpHeaders httpHeaders, + @PathVariable("id") @Parameter(description = "The Job ID") final String id) throws OperationException { + userFactory.setHttpHeaders(httpHeaders); return graphFactory.getGraph().execute(new GetJobResults.Builder() .jobId(id) .build(), diff --git a/rest-api/spring-rest/src/main/java/uk/gov/gchq/gaffer/rest/controller/OperationController.java b/rest-api/spring-rest/src/main/java/uk/gov/gchq/gaffer/rest/controller/OperationController.java index 2b0e66cbed1..2acbfbc6ad5 100644 --- a/rest-api/spring-rest/src/main/java/uk/gov/gchq/gaffer/rest/controller/OperationController.java +++ b/rest-api/spring-rest/src/main/java/uk/gov/gchq/gaffer/rest/controller/OperationController.java @@ -1,5 +1,5 @@ /* - * Copyright 2020-2023 Crown Copyright + * Copyright 2020-2024 Crown Copyright * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -18,11 +18,18 @@ import com.fasterxml.jackson.databind.ObjectMapper; import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; + import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.HttpHeaders; import org.springframework.http.MediaType; import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestHeader; +import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import org.springframework.web.servlet.mvc.method.annotation.StreamingResponseBody; @@ -34,6 +41,7 @@ import uk.gov.gchq.gaffer.rest.factory.ExamplesFactory; import uk.gov.gchq.gaffer.rest.factory.GraphFactory; import uk.gov.gchq.gaffer.rest.factory.UserFactory; +import uk.gov.gchq.gaffer.rest.factory.spring.AbstractUserFactory; import uk.gov.gchq.gaffer.rest.model.OperationDetail; import uk.gov.gchq.gaffer.rest.service.v2.AbstractOperationService; @@ -41,48 +49,57 @@ import java.nio.charset.StandardCharsets; import java.util.Set; +import static org.springframework.http.MediaType.APPLICATION_JSON_VALUE; + import static uk.gov.gchq.gaffer.jsonserialisation.JSONSerialiser.createDefaultMapper; import static uk.gov.gchq.gaffer.rest.ServiceConstants.GAFFER_MEDIA_TYPE; import static uk.gov.gchq.gaffer.rest.ServiceConstants.GAFFER_MEDIA_TYPE_HEADER; import static uk.gov.gchq.gaffer.rest.ServiceConstants.JOB_ID_HEADER; @RestController -public class OperationController extends AbstractOperationService implements IOperationController { +@Tag(name = "operations") +@RequestMapping("/rest/graph/operations") +public class OperationController extends AbstractOperationService { private final GraphFactory graphFactory; - private final UserFactory userFactory; + private final AbstractUserFactory userFactory; private final ExamplesFactory examplesFactory; public final ObjectMapper mapper = createDefaultMapper(); @Autowired - public OperationController(final GraphFactory graphFactory, final UserFactory userFactory, final ExamplesFactory examplesFactory) { + public OperationController(final GraphFactory graphFactory, final AbstractUserFactory userFactory, final ExamplesFactory examplesFactory) { this.graphFactory = graphFactory; this.userFactory = userFactory; this.examplesFactory = examplesFactory; } - @Override + @GetMapping(produces = APPLICATION_JSON_VALUE) + @io.swagger.v3.oas.annotations.Operation(summary = "Retrieves a list of supported operations") public Set> getOperations() { return getSupportedOperations(); } - @Override + @GetMapping(path = "/all", produces = APPLICATION_JSON_VALUE) + @io.swagger.v3.oas.annotations.Operation(summary = "Retrieves a list of all operations") public Set> getOperationsIncludingUnsupported() { return getSupportedOperations(true); } - @Override + @GetMapping(path = "/details", produces = APPLICATION_JSON_VALUE) + @io.swagger.v3.oas.annotations.Operation(summary = "Returns the details of every operation supported by the store") public Set getAllOperationDetails() { return getSupportedOperationDetails(); } - @Override + @GetMapping(path = "/details/all", produces = APPLICATION_JSON_VALUE) + @io.swagger.v3.oas.annotations.Operation(summary = "Returns the details of every operation") public Set getAllOperationDetailsIncludingUnsupported() { return getSupportedOperationDetails(true); } - @Override + @GetMapping(value = "{className}", produces = APPLICATION_JSON_VALUE) + @io.swagger.v3.oas.annotations.Operation(summary = "Gets details about the specified operation class") public OperationDetail getOperationDetails(@PathVariable("className") @Parameter(name = "className", description = "The Operation class") final String className) { try { final Class operationClass = getOperationClass(className); @@ -101,7 +118,8 @@ public OperationDetail getOperationDetails(@PathVariable("className") @Parameter } } - @Override + @GetMapping(value = "{className}/next", produces = APPLICATION_JSON_VALUE) + @io.swagger.v3.oas.annotations.Operation(summary = "Gets the operations that can be chained after a given operation") public Set> getNextOperations(@PathVariable("className") @Parameter(name = "className", description = "The Operation class") final String className) { Class opClass; try { @@ -115,7 +133,8 @@ public Set> getNextOperations(@PathVariable("classNam return getNextOperations(opClass); } - @Override + @GetMapping(value = "{className}/example", produces = APPLICATION_JSON_VALUE) + @io.swagger.v3.oas.annotations.Operation(summary = "Gets an example of an operation class") public Operation getOperationExample(@PathVariable("className") @Parameter(name = "className", description = "The Operation class") final String className) { Class operationClass; try { @@ -132,8 +151,10 @@ public Operation getOperationExample(@PathVariable("className") @Parameter(name } } - @Override - public ResponseEntity execute(@RequestBody final Operation operation) { + @PostMapping(path = "/execute", consumes = APPLICATION_JSON_VALUE, produces = APPLICATION_JSON_VALUE) + @io.swagger.v3.oas.annotations.Operation(summary = "Executes an operation against a Store") + public ResponseEntity execute(@RequestHeader final HttpHeaders httpHeaders, @RequestBody final Operation operation) { + userFactory.setHttpHeaders(httpHeaders); final Pair resultAndJobId = _execute(operation, userFactory.createContext()); return ResponseEntity.ok() .header(GAFFER_MEDIA_TYPE_HEADER, GAFFER_MEDIA_TYPE) @@ -141,9 +162,13 @@ public ResponseEntity execute(@RequestBody final Operation operation) { .body(resultAndJobId.getFirst()); } - @Override + @PostMapping(path = "/execute/chunked", consumes = APPLICATION_JSON_VALUE, produces = APPLICATION_JSON_VALUE) + @io.swagger.v3.oas.annotations.Operation(summary = "Executes an operation against a Store, returning a chunked output") @SuppressWarnings("PMD.UseTryWithResources") - public ResponseEntity executeChunked(@RequestBody final Operation operation) { + public ResponseEntity executeChunked( + @RequestHeader final HttpHeaders httpHeaders, + @RequestBody final Operation operation) { + userFactory.setHttpHeaders(httpHeaders); final StreamingResponseBody responseBody = response -> { try { final Pair resultAndJobId = _execute(operation, userFactory.createContext()); diff --git a/rest-api/spring-rest/src/main/java/uk/gov/gchq/gaffer/rest/controller/PropertiesController.java b/rest-api/spring-rest/src/main/java/uk/gov/gchq/gaffer/rest/controller/PropertiesController.java index 483c018c961..065191de687 100644 --- a/rest-api/spring-rest/src/main/java/uk/gov/gchq/gaffer/rest/controller/PropertiesController.java +++ b/rest-api/spring-rest/src/main/java/uk/gov/gchq/gaffer/rest/controller/PropertiesController.java @@ -1,5 +1,5 @@ /* - * Copyright 2020 Crown Copyright + * Copyright 2020-2024 Crown Copyright * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,7 +16,12 @@ package uk.gov.gchq.gaffer.rest.controller; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; + +import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import uk.gov.gchq.gaffer.core.exception.GafferRuntimeException; @@ -25,15 +30,22 @@ import java.util.Map; +import static org.springframework.http.MediaType.APPLICATION_JSON_VALUE; +import static org.springframework.http.MediaType.TEXT_PLAIN_VALUE; + @RestController -public class PropertiesController implements IPropertiesController { +@Tag(name = "properties") +@RequestMapping("/rest/properties") +public class PropertiesController { - @Override + @GetMapping(produces = APPLICATION_JSON_VALUE) + @Operation(summary = "Get all the Gaffer System properties") public Map getProperties() { return PropertiesUtil.getProperties(); } - @Override + @GetMapping(value = "/{property}", produces = { TEXT_PLAIN_VALUE, APPLICATION_JSON_VALUE }) + @Operation(summary = "Gets the value of a provided property") public String getProperty(@PathVariable("property") final String property) { final String resolvedPropertyValue = PropertiesUtil.getProperty(property); if (resolvedPropertyValue != null) { diff --git a/rest-api/spring-rest/src/main/java/uk/gov/gchq/gaffer/rest/controller/StatusController.java b/rest-api/spring-rest/src/main/java/uk/gov/gchq/gaffer/rest/controller/StatusController.java index 63b31d02fce..87414faa46b 100644 --- a/rest-api/spring-rest/src/main/java/uk/gov/gchq/gaffer/rest/controller/StatusController.java +++ b/rest-api/spring-rest/src/main/java/uk/gov/gchq/gaffer/rest/controller/StatusController.java @@ -1,5 +1,5 @@ /* - * Copyright 2020 Crown Copyright + * Copyright 2020-2024 Crown Copyright * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,7 +16,12 @@ package uk.gov.gchq.gaffer.rest.controller; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; + import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import uk.gov.gchq.gaffer.core.exception.GafferRuntimeException; @@ -24,8 +29,12 @@ import uk.gov.gchq.gaffer.rest.SystemStatus; import uk.gov.gchq.gaffer.rest.factory.GraphFactory; +import static org.springframework.http.MediaType.APPLICATION_JSON_VALUE; + @RestController -public class StatusController implements IStatusController { +@Tag(name = "status") +@RequestMapping("/rest/graph/status") +public class StatusController { private final GraphFactory graphFactory; @@ -34,7 +43,8 @@ public StatusController(final GraphFactory graphFactory) { this.graphFactory = graphFactory; } - @Override + @GetMapping(produces = APPLICATION_JSON_VALUE) + @Operation(summary = "Retrieves the status of the graph") public SystemStatus getStatus() { try { if (graphFactory.getGraph() != null) { diff --git a/rest-api/spring-rest/src/test/java/uk/gov/gchq/gaffer/rest/controller/OperationControllerTest.java b/rest-api/spring-rest/src/test/java/uk/gov/gchq/gaffer/rest/controller/OperationControllerTest.java index 4ab190f45bf..a3d27e7e05e 100644 --- a/rest-api/spring-rest/src/test/java/uk/gov/gchq/gaffer/rest/controller/OperationControllerTest.java +++ b/rest-api/spring-rest/src/test/java/uk/gov/gchq/gaffer/rest/controller/OperationControllerTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2020-2023 Crown Copyright + * Copyright 2020-2024 Crown Copyright * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -20,6 +20,7 @@ import org.apache.commons.lang3.exception.CloneFailedException; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; +import org.springframework.http.HttpHeaders; import org.springframework.http.ResponseEntity; import org.springframework.web.servlet.mvc.method.annotation.StreamingResponseBody; @@ -36,7 +37,7 @@ import uk.gov.gchq.gaffer.operation.io.Output; import uk.gov.gchq.gaffer.rest.factory.ExamplesFactory; import uk.gov.gchq.gaffer.rest.factory.GraphFactory; -import uk.gov.gchq.gaffer.rest.factory.UserFactory; +import uk.gov.gchq.gaffer.rest.factory.spring.AbstractUserFactory; import uk.gov.gchq.gaffer.rest.model.OperationDetail; import uk.gov.gchq.gaffer.rest.model.OperationField; import uk.gov.gchq.gaffer.store.Context; @@ -68,7 +69,7 @@ public class OperationControllerTest { private Store store; private GraphFactory graphFactory; - private UserFactory userFactory; + private AbstractUserFactory userFactory; private ExamplesFactory examplesFactory; private OperationController operationController; @@ -76,7 +77,7 @@ public class OperationControllerTest { public void setUpController() { store = mock(Store.class); graphFactory = mock(GraphFactory.class); - userFactory = mock(UserFactory.class); + userFactory = mock(AbstractUserFactory.class); examplesFactory = mock(ExamplesFactory.class); operationController = new OperationController(graphFactory, userFactory, examplesFactory); @@ -296,7 +297,7 @@ public void shouldCorrectlyChunkIterables() throws IOException, OperationExcepti when(store.execute(any(Output.class), any(Context.class))).thenReturn(Arrays.asList(1, 2, 3)); // When - final ResponseEntity response = operationController.executeChunked(new GetAllElements()); + final ResponseEntity response = operationController.executeChunked(mock(HttpHeaders.class), new GetAllElements()); try (final OutputStream output = new ByteArrayOutputStream()) { response.getBody().writeTo(output); // Then From a1c1a1f8253c2c1fb7c14c4593fb5a27a392c839 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Tue, 13 Aug 2024 14:49:46 +0000 Subject: [PATCH 16/16] prepare release gaffer2-2.3.0 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index dca3aecbdfd..56f4da83e47 100644 --- a/pom.xml +++ b/pom.xml @@ -38,7 +38,7 @@ - 2.3.0-SNAPSHOT + 2.3.0 false UTF-8