From 020236207c6afc9c543a423aa2e1dcb43a2db157 Mon Sep 17 00:00:00 2001 From: Ivan Senic Date: Wed, 29 Mar 2023 17:00:03 +0200 Subject: [PATCH 1/2] closes #293: allow empty options object in all commands --- .../ObjectMapperConfiguration.java | 7 +++ .../jsonapi/api/v1/InsertIntegrationTest.java | 62 +++++++++++++++++++ 2 files changed, 69 insertions(+) diff --git a/src/main/java/io/stargate/sgv2/jsonapi/api/configuration/ObjectMapperConfiguration.java b/src/main/java/io/stargate/sgv2/jsonapi/api/configuration/ObjectMapperConfiguration.java index 6064424c4d..93bdb8bb32 100644 --- a/src/main/java/io/stargate/sgv2/jsonapi/api/configuration/ObjectMapperConfiguration.java +++ b/src/main/java/io/stargate/sgv2/jsonapi/api/configuration/ObjectMapperConfiguration.java @@ -30,14 +30,21 @@ ObjectMapper objectMapper(Instance customizers) { private ObjectMapper createMapper() { return JsonMapper.builder() + // important for retaining number accuracy! .enable(DeserializationFeature.USE_BIG_DECIMAL_FOR_FLOATS) + // case insensitive enums, so "before" will match to "BEFORE" in an enum .enable(MapperFeature.ACCEPT_CASE_INSENSITIVE_ENUMS) + // Verify uniqueness of JSON Object properties .enable(StreamReadFeature.STRICT_DUPLICATE_DETECTION) + // Prevent use of Engineering Notation with trailing zeroes: .enable(StreamWriteFeature.WRITE_BIGDECIMAL_AS_PLAIN) + + // don't fail on unknown props, mainly for empty options object in commands + .configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false) .build(); } } diff --git a/src/test/java/io/stargate/sgv2/jsonapi/api/v1/InsertIntegrationTest.java b/src/test/java/io/stargate/sgv2/jsonapi/api/v1/InsertIntegrationTest.java index a1c0d7e536..511833ad54 100644 --- a/src/test/java/io/stargate/sgv2/jsonapi/api/v1/InsertIntegrationTest.java +++ b/src/test/java/io/stargate/sgv2/jsonapi/api/v1/InsertIntegrationTest.java @@ -145,6 +145,34 @@ public void insertDocumentWithNumberId() { .body("errors", is(nullValue())); } + @Test + public void emptyOptionsAllowed() { + String json = + """ + { + "insertOne": { + "document": { + "_id": "doc3", + "username": "user3" + }, + "options": {} + } + } + """; + + given() + .header(HttpConstants.AUTHENTICATION_TOKEN_HEADER_NAME, getAuthToken()) + .contentType(ContentType.JSON) + .body(json) + .when() + .post(CollectionResource.BASE_PATH, keyspaceId.asInternal(), collectionName) + .then() + .statusCode(200) + .body("status.insertedIds[0]", is("doc3")) + .body("data", is(nullValue())) + .body("errors", is(nullValue())); + } + @Test public void insertDuplicateDocument() { String json = @@ -686,6 +714,40 @@ public void withDifferentTypes() { .body("data.docs[0]", jsonEquals(expected)); } + @Test + public void emptyOptionsAllowed() { + String json = + """ + { + "insertMany": { + "documents": [ + { + "_id": "doc4", + "username": "user4" + }, + { + "_id": "doc5", + "username": "user5" + } + ], + "options": {} + } + } + """; + + given() + .header(HttpConstants.AUTHENTICATION_TOKEN_HEADER_NAME, getAuthToken()) + .contentType(ContentType.JSON) + .body(json) + .when() + .post(CollectionResource.BASE_PATH, keyspaceId.asInternal(), collectionName) + .then() + .statusCode(200) + .body("status.insertedIds", contains("doc4", "doc5")) + .body("data", is(nullValue())) + .body("errors", is(nullValue())); + } + @Test public void emptyDocuments() { String json = From 226475fa389aa26bcad6bf03781ee41f0efbda4d Mon Sep 17 00:00:00 2001 From: Ivan Senic Date: Wed, 29 Mar 2023 17:34:12 +0200 Subject: [PATCH 2/2] added test in all int tests, new round of refactoring of int tests --- .../jsonapi/api/v1/CountIntegrationTest.java | 95 ++-- .../api/v1/DeleteManyIntegrationTest.java | 41 +- .../api/v1/DeleteOneIntegrationTest.java | 81 ++- .../jsonapi/api/v1/FindIntegrationTest.java | 8 + .../v1/FindOneAndUpdateIntegrationTest.java | 108 ++-- .../api/v1/FindOneIntegrationTest.java | 57 +- .../api/v1/LwtRetryIntegrationTest.java | 8 +- .../api/v1/UpdateManyIntegrationTest.java | 63 ++- .../api/v1/UpdateOneIntegrationTest.java | 519 ++++++++++-------- 9 files changed, 573 insertions(+), 407 deletions(-) diff --git a/src/test/java/io/stargate/sgv2/jsonapi/api/v1/CountIntegrationTest.java b/src/test/java/io/stargate/sgv2/jsonapi/api/v1/CountIntegrationTest.java index e20e6c9fb0..e2809dabc3 100644 --- a/src/test/java/io/stargate/sgv2/jsonapi/api/v1/CountIntegrationTest.java +++ b/src/test/java/io/stargate/sgv2/jsonapi/api/v1/CountIntegrationTest.java @@ -116,8 +116,7 @@ private void insert(String json) { } @Test - @Order(2) - public void countNoFilter() { + public void noFilter() { String json = """ { @@ -139,8 +138,30 @@ public void countNoFilter() { } @Test - @Order(2) - public void countByColumn() { + public void emptyOptionsAllowed() { + String json = + """ + { + "countDocuments": { + "options": {} + } + } + """; + + given() + .header(HttpConstants.AUTHENTICATION_TOKEN_HEADER_NAME, getAuthToken()) + .contentType(ContentType.JSON) + .body(json) + .when() + .post(CollectionResource.BASE_PATH, keyspaceId.asInternal(), collectionName) + .then() + .statusCode(200) + .body("status.count", is(5)) + .body("errors", is(nullValue())); + } + + @Test + public void byColumn() { String json = """ { @@ -164,8 +185,7 @@ public void countByColumn() { } @Test - @Order(2) - public void countWithEqComparisonOperator() { + public void withEqComparisonOperator() { String json = """ { @@ -189,8 +209,7 @@ public void countWithEqComparisonOperator() { } @Test - @Order(2) - public void countWithEqSubDoc() { + public void withEqSubDoc() { String json = """ { @@ -214,8 +233,7 @@ public void countWithEqSubDoc() { } @Test - @Order(2) - public void countWithEqSubDocWithIndex() { + public void withEqSubDocWithIndex() { String json = """ { @@ -239,8 +257,7 @@ public void countWithEqSubDocWithIndex() { } @Test - @Order(2) - public void countWithEqArrayElement() { + public void withEqArrayElement() { String json = """ { @@ -264,8 +281,7 @@ public void countWithEqArrayElement() { } @Test - @Order(2) - public void countWithExistFalseOperator() { + public void withExistFalseOperator() { String json = """ { @@ -287,8 +303,7 @@ public void countWithExistFalseOperator() { } @Test - @Order(2) - public void countWithExistOperator() { + public void withExistOperator() { String json = """ { @@ -312,8 +327,7 @@ public void countWithExistOperator() { } @Test - @Order(2) - public void countWithAllOperator() { + public void withAllOperator() { String json = """ { @@ -337,8 +351,7 @@ public void countWithAllOperator() { } @Test - @Order(2) - public void countWithAllOperatorLongerString() { + public void withAllOperatorLongerString() { String json = """ { @@ -362,8 +375,7 @@ public void countWithAllOperatorLongerString() { } @Test - @Order(2) - public void countWithAllOperatorMixedAFormatArray() { + public void withAllOperatorMixedAFormatArray() { String json = """ { @@ -387,8 +399,7 @@ public void countWithAllOperatorMixedAFormatArray() { } @Test - @Order(2) - public void countWithAllOperatorNoMatch() { + public void withAllOperatorNoMatch() { String json = """ { @@ -412,8 +423,7 @@ public void countWithAllOperatorNoMatch() { } @Test - @Order(2) - public void countWithEqSubDocumentShortcut() { + public void withEqSubDocumentShortcut() { String json = """ { @@ -437,8 +447,7 @@ public void countWithEqSubDocumentShortcut() { } @Test - @Order(2) - public void countWithEqSubDocument() { + public void withEqSubDocument() { String json = """ { @@ -462,8 +471,7 @@ public void countWithEqSubDocument() { } @Test - @Order(2) - public void countWithEqSubDocumentOrderChangeNoMatch() { + public void withEqSubDocumentOrderChangeNoMatch() { String json = """ { @@ -487,8 +495,7 @@ public void countWithEqSubDocumentOrderChangeNoMatch() { } @Test - @Order(2) - public void countWithEqSubDocumentNoMatch() { + public void withEqSubDocumentNoMatch() { String json = """ { @@ -512,8 +519,7 @@ public void countWithEqSubDocumentNoMatch() { } @Test - @Order(2) - public void countWithSizeOperator() { + public void withSizeOperator() { String json = """ { @@ -537,8 +543,7 @@ public void countWithSizeOperator() { } @Test - @Order(2) - public void countWithSizeOperatorNoMatch() { + public void withSizeOperatorNoMatch() { String json = """ { @@ -562,8 +567,7 @@ public void countWithSizeOperatorNoMatch() { } @Test - @Order(2) - public void countWithEqOperatorArray() { + public void withEqOperatorArray() { String json = """ { @@ -587,8 +591,7 @@ public void countWithEqOperatorArray() { } @Test - @Order(2) - public void countWithEqOperatorNestedArray() { + public void withEqOperatorNestedArray() { String json = """ { @@ -612,8 +615,7 @@ public void countWithEqOperatorNestedArray() { } @Test - @Order(2) - public void countWithEqOperatorArrayNoMatch() { + public void withEqOperatorArrayNoMatch() { String json = """ { @@ -637,8 +639,7 @@ public void countWithEqOperatorArrayNoMatch() { } @Test - @Order(2) - public void countWithEqOperatorNestedArrayNoMatch() { + public void withEqOperatorNestedArrayNoMatch() { String json = """ { @@ -662,8 +663,7 @@ public void countWithEqOperatorNestedArrayNoMatch() { } @Test - @Order(2) - public void countWithNEComparisonOperator() { + public void withNEComparisonOperator() { String json = """ { @@ -685,8 +685,7 @@ public void countWithNEComparisonOperator() { } @Test - @Order(2) - public void countByBooleanColumn() { + public void byBooleanColumn() { String json = """ { diff --git a/src/test/java/io/stargate/sgv2/jsonapi/api/v1/DeleteManyIntegrationTest.java b/src/test/java/io/stargate/sgv2/jsonapi/api/v1/DeleteManyIntegrationTest.java index 3113107ba3..0ae1fb9b4a 100644 --- a/src/test/java/io/stargate/sgv2/jsonapi/api/v1/DeleteManyIntegrationTest.java +++ b/src/test/java/io/stargate/sgv2/jsonapi/api/v1/DeleteManyIntegrationTest.java @@ -59,7 +59,7 @@ private void insert(int countOfDocument) { } @Test - public void deleteManyById() { + public void byId() { insert(2); String json = """ @@ -129,7 +129,34 @@ public void deleteManyById() { } @Test - public void deleteManyByColumn() { + public void emptyOptionsAllowed() { + insert(2); + String json = + """ + { + "deleteMany": { + "filter" : {"_id" : "doc1"}, + "options": {} + } + } + """; + + given() + .header(HttpConstants.AUTHENTICATION_TOKEN_HEADER_NAME, getAuthToken()) + .contentType(ContentType.JSON) + .body(json) + .when() + .post(CollectionResource.BASE_PATH, keyspaceId.asInternal(), collectionName) + .then() + .statusCode(200) + .body("status.deletedCount", is(1)) + .body("status.moreData", is(nullValue())) + .body("data", is(nullValue())) + .body("errors", is(nullValue())); + } + + @Test + public void byColumn() { insert(5); String json = """ @@ -177,7 +204,7 @@ public void deleteManyByColumn() { } @Test - public void deleteManyNoFilter() { + public void noFilter() { insert(20); String json = """ @@ -222,7 +249,7 @@ public void deleteManyNoFilter() { } @Test - public void deleteManyNoFilterMoreDataFlag() { + public void noFilterMoreDataFlag() { insert(25); String json = """ @@ -278,9 +305,9 @@ public void concurrentDeletes() throws Exception { String document = """ { - "_id": "concurrent-%s" - } - """; + "_id": "concurrent-%s" + } + """; for (int i = 0; i < totalDocuments; i++) { insertDoc(document.formatted(i)); } diff --git a/src/test/java/io/stargate/sgv2/jsonapi/api/v1/DeleteOneIntegrationTest.java b/src/test/java/io/stargate/sgv2/jsonapi/api/v1/DeleteOneIntegrationTest.java index d1f6e34988..39ec1179c8 100644 --- a/src/test/java/io/stargate/sgv2/jsonapi/api/v1/DeleteOneIntegrationTest.java +++ b/src/test/java/io/stargate/sgv2/jsonapi/api/v1/DeleteOneIntegrationTest.java @@ -27,7 +27,7 @@ public class DeleteOneIntegrationTest extends CollectionResourceBaseIntegrationT @Nested class DeleteOne { @Test - public void deleteOneById() { + public void byId() { String json = """ { @@ -95,7 +95,32 @@ public void deleteOneById() { } @Test - public void deleteOneByColumn() { + public void emptyOptionsAllowed() { + String json = + """ + { + "deleteOne": { + "filter" : {"_id" : "doc3"}, + "options": {} + } + } + """; + + given() + .header(HttpConstants.AUTHENTICATION_TOKEN_HEADER_NAME, getAuthToken()) + .contentType(ContentType.JSON) + .body(json) + .when() + .post(CollectionResource.BASE_PATH, keyspaceId.asInternal(), collectionName) + .then() + .statusCode(200) + .body("status.deletedCount", is(0)) + .body("data", is(nullValue())) + .body("errors", is(nullValue())); + } + + @Test + public void byColumn() { String json = """ { @@ -142,12 +167,12 @@ public void deleteOneByColumn() { // ensure find does not find the document json = """ - { - "findOne": { - "filter" : {"_id" : "doc4"} - } - } - """; + { + "findOne": { + "filter" : {"_id" : "doc4"} + } + } + """; given() .header(HttpConstants.AUTHENTICATION_TOKEN_HEADER_NAME, getAuthToken()) @@ -163,7 +188,7 @@ public void deleteOneByColumn() { } @Test - public void deleteOneNoFilter() { + public void noFilter() { String json = """ { @@ -190,8 +215,7 @@ public void deleteOneNoFilter() { """ { "deleteOne": { - "filter": { - } + "filter": {} } } """; @@ -211,12 +235,12 @@ public void deleteOneNoFilter() { // ensure find does not find the document json = """ - { - "findOne": { - "filter" : {"_id" : "doc3"} - } - } - """; + { + "findOne": { + "filter" : {"_id" : "doc3"} + } + } + """; given() .header(HttpConstants.AUTHENTICATION_TOKEN_HEADER_NAME, getAuthToken()) @@ -232,7 +256,7 @@ public void deleteOneNoFilter() { } @Test - public void deleteOneNoMatch() { + public void noMatch() { String json = """ { @@ -279,12 +303,12 @@ public void deleteOneNoMatch() { // ensure find does find the document json = """ - { - "findOne": { - "filter" : {"_id" : "doc5"} - } - } - """; + { + "findOne": { + "filter" : {"_id" : "doc5"} + } + } + """; given() .header(HttpConstants.AUTHENTICATION_TOKEN_HEADER_NAME, getAuthToken()) @@ -305,12 +329,11 @@ class Concurrency { @RepeatedTest(10) public void concurrentDeletes() throws Exception { - String document = - """ + String document = """ { - "_id": "concurrent" - } - """; + "_id": "concurrent" + } + """; insertDoc(document); // we can hit with more threads, max 1 retry per thread diff --git a/src/test/java/io/stargate/sgv2/jsonapi/api/v1/FindIntegrationTest.java b/src/test/java/io/stargate/sgv2/jsonapi/api/v1/FindIntegrationTest.java index 706dbfdeb5..7271add5f3 100644 --- a/src/test/java/io/stargate/sgv2/jsonapi/api/v1/FindIntegrationTest.java +++ b/src/test/java/io/stargate/sgv2/jsonapi/api/v1/FindIntegrationTest.java @@ -20,6 +20,14 @@ @QuarkusIntegrationTest @QuarkusTestResource(DseTestResource.class) public class FindIntegrationTest extends CollectionResourceBaseIntegrationTest { + + // TODO refactor in https://github.com/stargate/jsonapi/issues/174 + // - test names + // - order annotations + // - format json + // - errors field check + // - empty options test + @Nested @TestMethodOrder(MethodOrderer.OrderAnnotation.class) class Find { diff --git a/src/test/java/io/stargate/sgv2/jsonapi/api/v1/FindOneAndUpdateIntegrationTest.java b/src/test/java/io/stargate/sgv2/jsonapi/api/v1/FindOneAndUpdateIntegrationTest.java index fc5b1da476..6a6bea6a8c 100644 --- a/src/test/java/io/stargate/sgv2/jsonapi/api/v1/FindOneAndUpdateIntegrationTest.java +++ b/src/test/java/io/stargate/sgv2/jsonapi/api/v1/FindOneAndUpdateIntegrationTest.java @@ -25,7 +25,7 @@ public class FindOneAndUpdateIntegrationTest extends CollectionResourceBaseInteg class FindOneAndUpdate { @Test - public void findByIdAndSet() { + public void byIdAndSet() { String document = """ { @@ -88,7 +88,7 @@ public void findByIdAndSet() { } @Test - public void findByIdAndSetNotFound() { + public void byIdAndSetNotFound() { String json = """ { @@ -113,7 +113,33 @@ public void findByIdAndSetNotFound() { } @Test - public void findByIdReturnDocumentAfter() { + public void emptyOptionsAllowed() { + String json = + """ + { + "findOneAndUpdate": { + "filter" : {"_id" : "doc3"}, + "update" : {"$set" : {"active_user": false}}, + "options": {} + } + } + """; + given() + .header(HttpConstants.AUTHENTICATION_TOKEN_HEADER_NAME, getAuthToken()) + .contentType(ContentType.JSON) + .body(json) + .when() + .post(CollectionResource.BASE_PATH, keyspaceId.asInternal(), collectionName) + .then() + .statusCode(200) + .body("data.docs", is(empty())) + .body("status.matchedCount", is(0)) + .body("status.modifiedCount", is(0)) + .body("errors", is(nullValue())); + } + + @Test + public void byIdReturnDocumentAfter() { String document = """ { @@ -176,7 +202,7 @@ public void findByIdReturnDocumentAfter() { } @Test - public void findByColumnUpsert() { + public void byColumnUpsert() { String json = """ { @@ -223,24 +249,24 @@ public void findByColumnUpsert() { } @Test - public void findByIdUpsert() { + public void byIdUpsert() { String json = """ - { - "findOneAndUpdate": { - "filter" : {"_id" : "afterDoc4"}, - "update" : {"$set" : {"active_user": false}}, - "options" : {"returnDocument" : "after", "upsert" : true} - } - } - """; + { + "findOneAndUpdate": { + "filter" : {"_id" : "afterDoc4"}, + "update" : {"$set" : {"active_user": false}}, + "options" : {"returnDocument" : "after", "upsert" : true} + } + } + """; String expected = """ - { - "_id":"afterDoc4", - "active_user":false - } - """; + { + "_id":"afterDoc4", + "active_user":false + } + """; given() .header(HttpConstants.AUTHENTICATION_TOKEN_HEADER_NAME, getAuthToken()) @@ -259,12 +285,12 @@ public void findByIdUpsert() { // assert state after update json = """ - { - "find": { - "filter" : {"_id" : "afterDoc4"} - } - } - """; + { + "find": { + "filter" : {"_id" : "afterDoc4"} + } + } + """; given() .header(HttpConstants.AUTHENTICATION_TOKEN_HEADER_NAME, getAuthToken()) .contentType(ContentType.JSON) @@ -277,7 +303,7 @@ public void findByIdUpsert() { } @Test - public void findByColumnAndSet() { + public void byColumnAndSet() { String document = """ { @@ -312,12 +338,12 @@ public void findByColumnAndSet() { // assert state after update String expected = """ - { - "_id":"doc4", - "username":"user4", - "new_col": "new_val" - } - """; + { + "_id":"doc4", + "username":"user4", + "new_col": "new_val" + } + """; json = """ { @@ -338,7 +364,7 @@ public void findByColumnAndSet() { } @Test - public void findByIdAndUnset() { + public void byIdAndUnset() { String document = """ { @@ -402,7 +428,7 @@ public void findByIdAndUnset() { class FindOneAndUpdateFailures { @Test - public void findByIdTryUnsetId() { + public void byIdTryUnsetId() { final String inputDoc = """ { @@ -455,14 +481,14 @@ public void findByIdTryUnsetId() { } @Test - public void findByIdTrySetId() { + public void byIdTrySetId() { final String inputDoc = """ { "_id": "update_doc_set_id", "username": "update_user" } - """; + """; insertDoc(inputDoc); String json = @@ -508,7 +534,7 @@ public void findByIdTrySetId() { } @Test - public void findByIdTrySetPropertyOnArray() { + public void byIdTrySetPropertyOnArray() { final String inputDoc = """ { @@ -565,7 +591,7 @@ public void findByIdTrySetPropertyOnArray() { } @Test - public void findByIdTryPopNonArray() { + public void byIdTryPopNonArray() { final String inputDoc = """ { @@ -623,7 +649,7 @@ public void findByIdTryPopNonArray() { } @Test - public void findByIdTryIncNonNumber() { + public void byIdTryIncNonNumber() { final String inputDoc = """ { @@ -684,7 +710,7 @@ public void findByIdTryIncNonNumber() { class FindOneAndUpdateNested { @Test - public void findByIdAndUnsetNested() { + public void byIdAndUnsetNested() { String document = """ { @@ -773,7 +799,7 @@ public void findByIdAndUnsetNested() { } @Test - public void findByIdAndSetNested() { + public void byIdAndSetNested() { String document = """ { @@ -861,7 +887,7 @@ public void findByIdAndSetNested() { class FindOneAndUpdateWithSetOnInsert { @Test - public void findByIdUpsertAndAddOnInsert() { + public void byIdUpsertAndAddOnInsert() { String json = """ { diff --git a/src/test/java/io/stargate/sgv2/jsonapi/api/v1/FindOneIntegrationTest.java b/src/test/java/io/stargate/sgv2/jsonapi/api/v1/FindOneIntegrationTest.java index 2e2aab6c7c..2c4950b635 100644 --- a/src/test/java/io/stargate/sgv2/jsonapi/api/v1/FindOneIntegrationTest.java +++ b/src/test/java/io/stargate/sgv2/jsonapi/api/v1/FindOneIntegrationTest.java @@ -85,7 +85,7 @@ public void setUp() { @Test @Order(-1) // executed before insert - public void findOneNoFilterNoDocuments() { + public void noFilterNoDocuments() { String json = """ { @@ -109,7 +109,7 @@ public void findOneNoFilterNoDocuments() { } @Test - public void findOneNoFilter() { + public void noFilter() { String json = """ { @@ -133,7 +133,32 @@ public void findOneNoFilter() { } @Test - public void findOneById() { + public void emptyOptionsAllowed() { + String json = + """ + { + "findOne": { + "options": {} + } + } + """; + + given() + .header(HttpConstants.AUTHENTICATION_TOKEN_HEADER_NAME, getAuthToken()) + .contentType(ContentType.JSON) + .body(json) + .when() + .post(CollectionResource.BASE_PATH, keyspaceId.asInternal(), collectionName) + .then() + .statusCode(200) + .body("data.count", is(1)) + .body("data.docs", hasSize(1)) + .body("status", is(nullValue())) + .body("errors", is(nullValue())); + } + + @Test + public void byId() { String json = """ { @@ -159,7 +184,7 @@ public void findOneById() { } @Test - public void findOneByIdNotFound() { + public void byIdNotFound() { String json = """ { @@ -184,7 +209,7 @@ public void findOneByIdNotFound() { } @Test - public void findOneByColumn() { + public void byColumn() { String json = """ { @@ -210,7 +235,7 @@ public void findOneByColumn() { } @Test - public void findOneByColumnMissing() { + public void byColumnMissing() { String json = """ { @@ -235,7 +260,7 @@ public void findOneByColumnMissing() { } @Test - public void findOneByColumnNotMatching() { + public void byColumnNotMatching() { String json = """ { @@ -260,7 +285,7 @@ public void findOneByColumnNotMatching() { } @Test - public void findOneWithExistsOperator() { + public void withExistsOperator() { String json = """ { @@ -286,7 +311,7 @@ public void findOneWithExistsOperator() { } @Test - public void findOneWithExistsOperatorFalse() { + public void withExistsOperatorFalse() { String json = """ { @@ -311,7 +336,7 @@ public void findOneWithExistsOperatorFalse() { } @Test - public void findOneWithExistsNotMatching() { + public void withExistsNotMatching() { String json = """ { @@ -336,7 +361,7 @@ public void findOneWithExistsNotMatching() { } @Test - public void findOneWithAllOperatorMissing() { + public void withAllOperatorMissing() { String json = """ { @@ -361,7 +386,7 @@ public void findOneWithAllOperatorMissing() { } @Test - public void findOneWithAllOperatorNotMatching() { + public void withAllOperatorNotMatching() { String json = """ { @@ -386,7 +411,7 @@ public void findOneWithAllOperatorNotMatching() { } @Test - public void findOneWithAllOperatorNotArray() { + public void withAllOperatorNotArray() { String json = """ { @@ -413,7 +438,7 @@ public void findOneWithAllOperatorNotArray() { } @Test - public void findOneWithSizeOperator() { + public void withSizeOperator() { String json = """ { @@ -439,7 +464,7 @@ public void findOneWithSizeOperator() { } @Test - public void findOneWithSizeOperatorNotMatching() { + public void withSizeOperatorNotMatching() { String json = """ { @@ -464,7 +489,7 @@ public void findOneWithSizeOperatorNotMatching() { } @Test - public void findOneWithSizeOperatorNotNumber() { + public void withSizeOperatorNotNumber() { String json = """ { diff --git a/src/test/java/io/stargate/sgv2/jsonapi/api/v1/LwtRetryIntegrationTest.java b/src/test/java/io/stargate/sgv2/jsonapi/api/v1/LwtRetryIntegrationTest.java index 8a4f28f846..7086c55dbf 100644 --- a/src/test/java/io/stargate/sgv2/jsonapi/api/v1/LwtRetryIntegrationTest.java +++ b/src/test/java/io/stargate/sgv2/jsonapi/api/v1/LwtRetryIntegrationTest.java @@ -25,10 +25,10 @@ public void mixedOperations() throws Exception { String document = """ { - "_id": "doc1", - "count": 0 - } - """; + "_id": "doc1", + "count": 0 + } + """; insertDoc(document); String delete = diff --git a/src/test/java/io/stargate/sgv2/jsonapi/api/v1/UpdateManyIntegrationTest.java b/src/test/java/io/stargate/sgv2/jsonapi/api/v1/UpdateManyIntegrationTest.java index 9061926a14..9f55ae6bb1 100644 --- a/src/test/java/io/stargate/sgv2/jsonapi/api/v1/UpdateManyIntegrationTest.java +++ b/src/test/java/io/stargate/sgv2/jsonapi/api/v1/UpdateManyIntegrationTest.java @@ -41,7 +41,7 @@ private void insert(int countOfDocument) { } @Test - public void updateManyById() { + public void byId() { insert(2); String json = """ @@ -121,7 +121,34 @@ public void updateManyById() { } @Test - public void updateManyByColumn() { + public void emptyOptionsAllowed() { + String json = + """ + { + "updateMany": { + "filter" : {"_id" : "doc1"}, + "update" : {"$set" : {"active_user": false}}, + "options": {} + } + } + """; + + given() + .header(HttpConstants.AUTHENTICATION_TOKEN_HEADER_NAME, getAuthToken()) + .contentType(ContentType.JSON) + .body(json) + .when() + .post(CollectionResource.BASE_PATH, keyspaceId.asInternal(), collectionName) + .then() + .statusCode(200) + .body("status.matchedCount", is(0)) + .body("status.modifiedCount", is(0)) + .body("status.moreData", nullValue()) + .body("errors", is(nullValue())); + } + + @Test + public void byColumn() { insert(5); String json = """ @@ -164,7 +191,7 @@ public void updateManyByColumn() { } @Test - public void updateManyLimit() { + public void limit() { insert(20); String json = """ @@ -210,7 +237,7 @@ public void updateManyLimit() { } @Test - public void updateManyLimitMoreDataFlag() { + public void limitMoreDataFlag() { insert(25); String json = """ @@ -255,7 +282,7 @@ public void updateManyLimitMoreDataFlag() { } @Test - public void updateManyUpsert() { + public void upsert() { insert(5); String json = """ @@ -309,7 +336,7 @@ public void updateManyUpsert() { } @Test - public void updateManyByIdNoChange() { + public void byIdNoChange() { insert(2); String json = """ @@ -409,7 +436,7 @@ public void upsertManyByColumnUpsert() { } @Test - public void updateManyUpsertAddFilterColumn() { + public void upsertAddFilterColumn() { insert(5); String json = """ @@ -473,10 +500,10 @@ public void concurrentUpdates() throws Exception { String document = """ { - "_id": "concurrent-%s", - "count": 0 - } - """; + "_id": "concurrent-%s", + "count": 0 + } + """; for (int i = 0; i < 5; i++) { insertDoc(document.formatted(i)); } @@ -488,14 +515,14 @@ public void concurrentUpdates() throws Exception { // find all docs String updateJson = """ - { - "updateMany": { - "update" : { - "$inc" : {"count": 1} - } - } + { + "updateMany": { + "update" : { + "$inc" : {"count": 1} } - """; + } + } + """; // start all threads AtomicReferenceArray exceptions = new AtomicReferenceArray<>(threads); for (int i = 0; i < threads; i++) { diff --git a/src/test/java/io/stargate/sgv2/jsonapi/api/v1/UpdateOneIntegrationTest.java b/src/test/java/io/stargate/sgv2/jsonapi/api/v1/UpdateOneIntegrationTest.java index 2eb3f18343..0d2e4bb0e1 100644 --- a/src/test/java/io/stargate/sgv2/jsonapi/api/v1/UpdateOneIntegrationTest.java +++ b/src/test/java/io/stargate/sgv2/jsonapi/api/v1/UpdateOneIntegrationTest.java @@ -26,7 +26,7 @@ public class UpdateOneIntegrationTest extends CollectionResourceBaseIntegrationT @Nested class UpdateOneWithSet { @Test - public void findByIdAndSet() { + public void byIdAndSet() { String json = """ { @@ -99,7 +99,33 @@ public void findByIdAndSet() { } @Test - public void findByIdUpsert() { + public void emptyOptionsAllowed() { + String json = + """ + { + "updateOne": { + "filter" : {"_id" : "update_doc1"}, + "update" : {"$set" : {"active_user": false}}, + "options": {} + } + } + """; + + given() + .header(HttpConstants.AUTHENTICATION_TOKEN_HEADER_NAME, getAuthToken()) + .contentType(ContentType.JSON) + .body(json) + .when() + .post(CollectionResource.BASE_PATH, keyspaceId.asInternal(), collectionName) + .then() + .statusCode(200) + .body("status.matchedCount", is(0)) + .body("status.modifiedCount", is(0)) + .body("errors", is(nullValue())); + } + + @Test + public void byIdUpsert() { String json = """ { @@ -152,7 +178,7 @@ public void findByIdUpsert() { } @Test - public void findByColumnUpsert() { + public void byColumnUpsert() { String json = """ { @@ -199,7 +225,7 @@ public void findByColumnUpsert() { } @Test - public void findByIdAndColumnUpsert() { + public void byIdAndColumnUpsert() { String json = """ { @@ -254,7 +280,7 @@ public void findByIdAndColumnUpsert() { } @Test - public void findByColumnAndSet() { + public void byColumnAndSet() { String json = """ { @@ -346,7 +372,7 @@ public void findByColumnAndSet() { } @Test - public void findByColumnAndSetArray() { + public void byColumnAndSetArray() { String json = """ { @@ -416,7 +442,7 @@ public void findByColumnAndSetArray() { } @Test - public void findByColumnAndSetSubDoc() { + public void byColumnAndSetSubDoc() { String json = """ { @@ -491,7 +517,7 @@ public void findByColumnAndSetSubDoc() { @Nested class UpdateOneWithUnset { @Test - public void findByIdAndUnset() { + public void byIdAndUnset() { String document = """ { @@ -555,7 +581,7 @@ public void findByIdAndUnset() { class UpdateOneWithPop { @Test - public void findByColumnAndPop() { + public void byColumnAndPop() { String document = """ { @@ -639,7 +665,7 @@ public void findByColumnAndPop() { class UpdateOneWithPush { @Test - public void findByColumnAndPush() { + public void byColumnAndPush() { String document = """ { @@ -699,7 +725,7 @@ public void findByColumnAndPush() { } @Test - public void findByColumnAndPushWithEach() { + public void byColumnAndPushWithEach() { String document = """ { @@ -764,7 +790,7 @@ public void findByColumnAndPushWithEach() { } @Test - public void findByColumnAndPushWithEachAndPosition() { + public void byColumnAndPushWithEachAndPosition() { String document = """ { @@ -834,7 +860,7 @@ public void findByColumnAndPushWithEachAndPosition() { class UpdateOneWithInc { @Test - public void findByColumnAndInc() { + public void byColumnAndInc() { String document = """ { @@ -878,7 +904,8 @@ public void findByColumnAndInc() { // assert state after update String expectedDoc = """ - { "_id":"update_doc_inc", + { + "_id":"update_doc_inc", "number": 119, "newProp": 0.25, "numbers": { @@ -909,32 +936,35 @@ public void findByColumnAndInc() { @Nested class UpdateOneWithMul { @Test - public void findByColumnAndMultiply() { - insertDoc( + public void byColumnAndMultiply() { + String document = """ - { - "_id": "update_doc_mul", - "number": 12, - "numbers": { - "values": [ 2 ] - } - } - """); + { + "_id": "update_doc_mul", + "number": 12, + "numbers": { + "values": [ 2 ] + } + } + """; + insertDoc(document); + String updateJson = """ - { - "updateOne": { - "filter" : {"_id" : "update_doc_mul"}, - "update" : {"$mul" : { - "number": -4, - "newProp" : 0.25, - "numbers.values.0" : 0.25, - "numbers.values.1" : 5 - } - } - } - } - """; + { + "updateOne": { + "filter" : {"_id" : "update_doc_mul"}, + "update" : { + "$mul" : { + "number": -4, + "newProp" : 0.25, + "numbers.values.0" : 0.25, + "numbers.values.1" : 5 + } + } + } + } + """; given() .header(HttpConstants.AUTHENTICATION_TOKEN_HEADER_NAME, getAuthToken()) .contentType(ContentType.JSON) @@ -948,22 +978,23 @@ public void findByColumnAndMultiply() { String expectedDoc = """ - { "_id":"update_doc_mul", - "number": -48, - "newProp": 0, - "numbers": { - "values" : [ 0.5, 0 ] - } - } - """; + { + "_id":"update_doc_mul", + "number": -48, + "newProp": 0, + "numbers": { + "values" : [ 0.5, 0 ] + } + } + """; String findJson = """ - { - "find": { - "filter" : {"_id" : "update_doc_mul"} - } - } - """; + { + "find": { + "filter" : {"_id" : "update_doc_mul"} + } + } + """; given() .header(HttpConstants.AUTHENTICATION_TOKEN_HEADER_NAME, getAuthToken()) .contentType(ContentType.JSON) @@ -980,7 +1011,7 @@ public void findByColumnAndMultiply() { class UpdateOneWithAddToSet { @Test - public void findByColumnAndAddToSet() { + public void byColumnAndAddToSet() { String document = """ { @@ -1041,7 +1072,7 @@ public void findByColumnAndAddToSet() { // Test for case where nothing is actually added @Test - public void findByColumnAndAddToSetNoChange() { + public void byColumnAndAddToSetNoChange() { final String originalDoc = """ { @@ -1090,7 +1121,7 @@ public void findByColumnAndAddToSetNoChange() { } @Test - public void findByColumnAndAddToSetWithEach() { + public void byColumnAndAddToSetWithEach() { String document = """ { @@ -1159,18 +1190,18 @@ public void findByColumnAndAddToSetWithEach() { class UpdateOneWithMin { @Test - public void findByColumnAndMin() { + public void byColumnAndMin() { String document = """ { - "_id": "update_doc_min", - "min": 1, - "max": 99, - "numbers": { - "values": [ 1 ] - } - } - """; + "_id": "update_doc_min", + "min": 1, + "max": 99, + "numbers": { + "values": [ 1 ] + } + } + """; insertDoc(document); String updateJson = @@ -1232,29 +1263,29 @@ public void findByColumnAndMin() { } @Test - public void findByColumnMinNonNumeric() { + public void byColumnMinNonNumeric() { insertDoc( """ { - "_id": "update_doc_min_text", - "start": "abc", - "end": "xyz" - } - """); + "_id": "update_doc_min_text", + "start": "abc", + "end": "xyz" + } + """); String updateJson = """ - { - "updateOne": { - "filter" : {"_id" : "update_doc_min_text"}, - "update" : { - "$min" : { - "start": "fff", - "end" : "fff" - } - } + { + "updateOne": { + "filter" : {"_id" : "update_doc_min_text"}, + "update" : { + "$min" : { + "start": "fff", + "end" : "fff" } } - """; + } + } + """; given() .header(HttpConstants.AUTHENTICATION_TOKEN_HEADER_NAME, getAuthToken()) .contentType(ContentType.JSON) @@ -1270,20 +1301,20 @@ public void findByColumnMinNonNumeric() { // assert state after update: only "end" changed String expectedDoc = """ - { - "_id": "update_doc_min_text", - "start": "abc", - "end": "fff" - } - """; + { + "_id": "update_doc_min_text", + "start": "abc", + "end": "fff" + } + """; String findJson = """ - { - "find": { - "filter" : {"_id" : "update_doc_min_text"} - } - } - """; + { + "find": { + "filter" : {"_id" : "update_doc_min_text"} + } + } + """; given() .header(HttpConstants.AUTHENTICATION_TOKEN_HEADER_NAME, getAuthToken()) .contentType(ContentType.JSON) @@ -1296,29 +1327,29 @@ public void findByColumnMinNonNumeric() { } @Test - public void findByColumnMinMixedTypes() { + public void byColumnMinMixedTypes() { insertDoc( """ { - "_id": "update_doc_min_mixed", - "start": "abc", - "end": "xyz" - } - """); + "_id": "update_doc_min_mixed", + "start": "abc", + "end": "xyz" + } + """); String updateJson = """ - { - "updateOne": { - "filter" : {"_id" : "update_doc_min_mixed"}, - "update" : { - "$min" : { - "start": 123, - "end" : true - } - } + { + "updateOne": { + "filter" : {"_id" : "update_doc_min_mixed"}, + "update" : { + "$min" : { + "start": 123, + "end" : true } } - """; + } + } + """; given() .header(HttpConstants.AUTHENTICATION_TOKEN_HEADER_NAME, getAuthToken()) .contentType(ContentType.JSON) @@ -1335,20 +1366,20 @@ public void findByColumnMinMixedTypes() { // "end" (boolean after strings) String expectedDoc = """ - { - "_id": "update_doc_min_mixed", - "start": 123, - "end": "xyz" - } - """; + { + "_id": "update_doc_min_mixed", + "start": 123, + "end": "xyz" + } + """; String findJson = """ - { - "find": { - "filter" : {"_id" : "update_doc_min_mixed"} - } - } - """; + { + "find": { + "filter" : {"_id" : "update_doc_min_mixed"} + } + } + """; given() .header(HttpConstants.AUTHENTICATION_TOKEN_HEADER_NAME, getAuthToken()) .contentType(ContentType.JSON) @@ -1365,18 +1396,18 @@ public void findByColumnMinMixedTypes() { class UpdateOneWithMax { @Test - public void findByColumnAndMax() { + public void byColumnAndMax() { String document = """ { - "_id": "update_doc_max", - "min": 1, - "max": 99, - "numbers": { - "values": { "x":1, "y":2 } - } - } - """; + "_id": "update_doc_max", + "min": 1, + "max": 99, + "numbers": { + "values": { "x":1, "y":2 } + } + } + """; insertDoc(document); String updateJson = @@ -1438,7 +1469,7 @@ public void findByColumnAndMax() { } @Test - public void findByColumnMaxNonNumeric() { + public void byColumnMaxNonNumeric() { insertDoc( """ { @@ -1449,18 +1480,18 @@ public void findByColumnMaxNonNumeric() { """); String updateJson = """ - { - "updateOne": { - "filter" : {"_id" : "update_doc_max_text"}, - "update" : { - "$max" : { - "start": "fff", - "end" : "fff" - } - } - } - } - """; + { + "updateOne": { + "filter" : {"_id" : "update_doc_max_text"}, + "update" : { + "$max" : { + "start": "fff", + "end" : "fff" + } + } + } + } + """; given() .header(HttpConstants.AUTHENTICATION_TOKEN_HEADER_NAME, getAuthToken()) .contentType(ContentType.JSON) @@ -1476,20 +1507,20 @@ public void findByColumnMaxNonNumeric() { // assert state after update: only "start" changed String expectedDoc = """ - { - "_id": "update_doc_max_text", - "start": "fff", - "end": "xyz" - } - """; + { + "_id": "update_doc_max_text", + "start": "fff", + "end": "xyz" + } + """; String findJson = """ - { - "find": { - "filter" : {"_id" : "update_doc_max_text"} - } - } - """; + { + "find": { + "filter" : {"_id" : "update_doc_max_text"} + } + } + """; given() .header(HttpConstants.AUTHENTICATION_TOKEN_HEADER_NAME, getAuthToken()) .contentType(ContentType.JSON) @@ -1502,29 +1533,29 @@ public void findByColumnMaxNonNumeric() { } @Test - public void findByColumnMaxMixedTypes() { + public void byColumnMaxMixedTypes() { insertDoc( """ { - "_id": "update_doc_max_mixed", - "start": "abc", - "end": "xyz" + "_id": "update_doc_max_mixed", + "start": "abc", + "end": "xyz" } """); String updateJson = """ - { - "updateOne": { - "filter" : {"_id" : "update_doc_max_mixed"}, - "update" : { - "$max" : { - "start": 123, - "end" : true - } - } - } - } - """; + { + "updateOne": { + "filter" : {"_id" : "update_doc_max_mixed"}, + "update" : { + "$max" : { + "start": 123, + "end" : true + } + } + } + } + """; given() .header(HttpConstants.AUTHENTICATION_TOKEN_HEADER_NAME, getAuthToken()) .contentType(ContentType.JSON) @@ -1541,20 +1572,20 @@ public void findByColumnMaxMixedTypes() { // "start" (numbers before Strings) String expectedDoc = """ - { - "_id": "update_doc_max_mixed", - "start": "abc", - "end": true - } - """; + { + "_id": "update_doc_max_mixed", + "start": "abc", + "end": true + } + """; String findJson = """ - { - "find": { - "filter" : {"_id" : "update_doc_max_mixed"} - } - } - """; + { + "find": { + "filter" : {"_id" : "update_doc_max_mixed"} + } + } + """; given() .header(HttpConstants.AUTHENTICATION_TOKEN_HEADER_NAME, getAuthToken()) .contentType(ContentType.JSON) @@ -1571,36 +1602,36 @@ public void findByColumnMaxMixedTypes() { class UpdateOneWithRename { @Test - public void findByColumnAndRename() { + public void byColumnAndRename() { String document = """ - { - "_id": "update_doc_rename", - "total": 1, - "nested": { - "x": true - } - } - """; + { + "_id": "update_doc_rename", + "total": 1, + "nested": { + "x": true + } + } + """; insertDoc(document); // 4 things to try to rename (2 root, 2 nested) of which only 2 exist String updateJson = """ - { - "updateOne": { - "filter" : {"_id" : "update_doc_rename"}, - "update" : { - "$rename" : { - "total": "sum", - "x" : "y", - "nested.x" : "nested.x0", - "nested.z" : "nested.z2" - } - } - } - } - """; + { + "updateOne": { + "filter" : {"_id" : "update_doc_rename"}, + "update" : { + "$rename" : { + "total": "sum", + "x" : "y", + "nested.x" : "nested.x0", + "nested.z" : "nested.z2" + } + } + } + } + """; given() .header(HttpConstants.AUTHENTICATION_TOKEN_HEADER_NAME, getAuthToken()) .contentType(ContentType.JSON) @@ -1616,25 +1647,25 @@ public void findByColumnAndRename() { // assert state after update String expectedDoc = """ - { - "_id": "update_doc_rename", - "sum": 1, - "nested": { - "x0": true - } - } - """; + { + "_id": "update_doc_rename", + "sum": 1, + "nested": { + "x0": true + } + } + """; given() .header(HttpConstants.AUTHENTICATION_TOKEN_HEADER_NAME, getAuthToken()) .contentType(ContentType.JSON) .body( """ - { - "find": { - "filter" : {"_id" : "update_doc_rename"} - } - } - """) + { + "find": { + "filter" : {"_id" : "update_doc_rename"} + } + } + """) .when() .post(CollectionResource.BASE_PATH, keyspaceId.asInternal(), collectionName) .then() @@ -1647,7 +1678,7 @@ public void findByColumnAndRename() { @Nested class UpdateOneMultipleOperationTypes { @Test - public void findByColumnUseSetAndUnset() { + public void byColumnUseSetAndUnset() { insertDoc( """ { @@ -1659,20 +1690,20 @@ public void findByColumnUseSetAndUnset() { """); String updateJson = """ - { - "updateOne": { - "filter" : {"_id" : "update_doc_mixed_set_unset"}, - "update" : { - "$set" : { - "nested.new": "b" - }, - "$unset" : { - "nested.old": 1 - } - } - } - } - """; + { + "updateOne": { + "filter" : {"_id" : "update_doc_mixed_set_unset"}, + "update" : { + "$set" : { + "nested.new": "b" + }, + "$unset" : { + "nested.old": 1 + } + } + } + } + """; given() .header(HttpConstants.AUTHENTICATION_TOKEN_HEADER_NAME, getAuthToken()) .contentType(ContentType.JSON) @@ -1689,13 +1720,13 @@ public void findByColumnUseSetAndUnset() { // "start" (numbers before Strings) String expectedDoc = """ - { - "_id": "update_doc_mixed_set_unset", - "nested": { + { + "_id": "update_doc_mixed_set_unset", + "nested": { "new": "b" - } - } - """; + } + } + """; given() .header(HttpConstants.AUTHENTICATION_TOKEN_HEADER_NAME, getAuthToken()) .contentType(ContentType.JSON) @@ -1706,7 +1737,7 @@ public void findByColumnUseSetAndUnset() { "filter" : {"_id": "update_doc_mixed_set_unset"} } } - """) + """) .when() .post(CollectionResource.BASE_PATH, keyspaceId.asInternal(), collectionName) .then() @@ -1723,10 +1754,10 @@ public void concurrentUpdates() throws Exception { String document = """ { - "_id": "concurrent", - "count": 0 - } - """; + "_id": "concurrent", + "count": 0 + } + """; insertDoc(document); // three threads ensures no retries exhausted