package org.swisspush.reststorage; import com.jayway.awaitility.Duration; import com.jayway.restassured.RestAssured; import io.vertx.ext.unit.Async; import io.vertx.ext.unit.TestContext; import io.vertx.ext.unit.junit.VertxUnitRunner; import org.junit.Test; import org.junit.runner.RunWith; import java.util.List; import static com.jayway.awaitility.Awaitility.await; import static com.jayway.restassured.RestAssured.*; import static org.hamcrest.CoreMatchers.equalTo; import static org.hamcrest.CoreMatchers.hasItems; @RunWith(VertxUnitRunner.class) public class CrudTest extends AbstractTestCase { @Test public void testDoubleSlashesHandling(TestContext context) { Async async = context.async(); // put with double slashes with().urlEncodingEnabled(false).body("{ \"foo\": \"bar\" }").put("resources//myres"); // get with single/double slashes should both work when().get("resources/myres").then().assertThat().body("foo", equalTo("bar")); given().urlEncodingEnabled(false).when().get("resources//myres").then().assertThat().body("foo", equalTo("bar")); // delete with double slashes. after this, the resource should be gone given().urlEncodingEnabled(false).delete("resources//myres").then().assertThat().statusCode(200); given().delete("resources/myres").then().assertThat().statusCode(404); // get again with double slashes when().get("resources/myres").then().assertThat().statusCode(404); given().urlEncodingEnabled(false).when().get("resources//myres").then().assertThat().statusCode(404); async.complete(); } @Test public void testPutGetDelete(TestContext context) { Async async = context.async(); with().body("{ \"foo\": \"bar\" }").put("res"); when().get("res").then().assertThat().body("foo", equalTo("bar")); delete("res"); when().get("res").then().assertThat().statusCode(404); async.complete(); } @Test public void testList(TestContext context) { Async async = context.async(); with().body("{ \"foo\": \"bar\" }").put("resources/res1"); with().body("{ \"foo\": \"bar2\" }").put("resources/res2"); checkGETStatusCodeWithAwait5sec("resources/res1", 200); checkGETStatusCodeWithAwait5sec("resources/res2", 200); when().get("resources").then().assertThat().body("resources", hasItems("res1", "res2")); async.complete(); } @Test public void testMerge(TestContext context) { Async async = context.async(); with().body("{ \"foo\": \"bar\", \"hello\": \"world\" }").put("res"); checkGETStatusCodeWithAwait5sec("res", 200); with(). param("merge", "true"). body("{ \"foo\": \"bar2\" }"). put("res"); checkGETStatusCodeWithAwait5sec("res", 200); get("res").then().assertThat(). statusCode(200). body("foo", equalTo("bar2")). body("hello", equalTo("world")); async.complete(); } @Test public void testTwoBranchesDeleteOnLeafOfOneBranch(TestContext context) { Async async = context.async(); with().body("{ \"foo\": \"bar1\" }").put("branch1/res/leaf"); with().body("{ \"foo\": \"bar2\" }").put("branch2/res/leaf"); checkGETStatusCodeWithAwait5sec("branch1/res/leaf", 200); checkGETStatusCodeWithAwait5sec("branch2/res/leaf", 200); delete("branch2"); checkGETStatusCodeWithAwait5sec("branch2", 404); RestAssured.basePath = ""; when().get("branch1").then().assertThat().statusCode(200); when().get("branch1/res").then().assertThat().statusCode(200); when().get("branch1/res/leaf").then().assertThat().statusCode(200).body("foo", equalTo("bar1")); when().get("branch2").then().assertThat().statusCode(404); when().get("branch2/res").then().assertThat().statusCode(404); when().get("branch2/res/leaf").then().assertThat().statusCode(404); delete("branch2/res/leaf"); async.complete(); } @Test public void testTwoBranchesDeleteOnNodeUnderLeafOfOneBranch(TestContext context) { Async async = context.async(); with().body("{ \"foo\": \"bar1\" }").put("branch1/res/res1/leaf"); with().body("{ \"foo\": \"bar2\" }").put("branch2/res/res2/leaf"); checkGETStatusCodeWithAwait5sec("branch1/res/res1/leaf", 200); checkGETStatusCodeWithAwait5sec("branch2/res/res2/leaf", 200); delete("branch2/res"); checkGETStatusCodeWithAwait5sec("branch2/res", 404); RestAssured.basePath = ""; when().get("branch1").then().assertThat().statusCode(200); when().get("branch1/res").then().assertThat().statusCode(200); when().get("branch1/res/res1/").then().assertThat().statusCode(200); when().get("branch1/res/res1/leaf").then().assertThat().statusCode(200).body("foo", equalTo("bar1")); when().get("branch2").then().assertThat().statusCode(404); when().get("branch2/res").then().assertThat().statusCode(404); when().get("branch2/res/res2").then().assertThat().statusCode(404); when().get("branch2/res/res2/leaf").then().assertThat().statusCode(404); async.complete(); } @Test public void testTwoBranchesDeleteOnNodeAfterBranch(TestContext context) { Async async = context.async(); with().body("{ \"foo\": \"bar1\" }").put("branch1/res/res1/leaf"); with().body("{ \"foo\": \"bar2\" }").put("branch2/res/res2/leaf"); checkGETStatusCodeWithAwait5sec("branch1/res/res1/leaf", 200); checkGETStatusCodeWithAwait5sec("branch2/res/res2/leaf", 200); delete("branch1/res"); checkGETStatusCodeWithAwait5sec("branch1/res", 404); RestAssured.basePath = ""; when().get("branch2").then().assertThat().statusCode(200); when().get("branch2/res").then().assertThat().statusCode(200); when().get("branch2/res/res2/leaf").then().assertThat().statusCode(200).body("foo", equalTo("bar2")); when().get("branch1").then().assertThat().statusCode(404); when().get("branch1/res").then().assertThat().statusCode(404); when().get("branch1/res/leaf").then().assertThat().statusCode(404); when().get("branch1/res/res1/leaf").then().assertThat().statusCode(404); async.complete(); } @Test public void testTwoBranchesDeleteOnRoot(TestContext context) { Async async = context.async(); with().body("{ \"foo\": \"bar\" }").put("node/node/node/branch1/res/res1/leaf"); with().body("{ \"foo\": \"bar\" }").put("node/node/node/branch2/res/res2/leaf"); checkGETStatusCodeWithAwait5sec("node/node/node/branch1/res/res1/leaf", 200); checkGETStatusCodeWithAwait5sec("node/node/node/branch2/res/res2/leaf", 200); RestAssured.basePath = ""; delete("/"); checkGETStatusCodeWithAwait5sec("/", 404); when().get("node").then().assertThat().statusCode(404); when().get("node/node").then().assertThat().statusCode(404); when().get("node/node/node").then().assertThat().statusCode(404); when().get("node/node/node/branch2").then().assertThat().statusCode(404); when().get("node/node/node/branch2/res").then().assertThat().statusCode(404); when().get("node/node/node/branch2/res/res2/leaf").then().assertThat().statusCode(404); when().get("node/node/node/branch1").then().assertThat().statusCode(404); when().get("node/node/node/branch1/res").then().assertThat().statusCode(404); when().get("node/node/node/branch1/res/leaf").then().assertThat().statusCode(404); when().get("node/node/node/branch1/res/res1/leaf").then().assertThat().statusCode(404); async.complete(); } @Test public void testThreeBranchesDeleteOnLeafOfOneBranch(TestContext context) { Async async = context.async(); with().body("{ \"foo\": \"bar1\" }").put("node/branch1/res/leaf"); with().body("{ \"foo\": \"bar2\" }").put("node/branch2/res/leaf"); with().body("{ \"foo\": \"bar3\" }").put("node/branch3/res/leaf"); checkGETStatusCodeWithAwait5sec("node/branch1/res/leaf", 200); checkGETStatusCodeWithAwait5sec("node/branch2/res/leaf", 200); checkGETStatusCodeWithAwait5sec("node/branch3/res/leaf", 200); delete("node/branch3/res/leaf"); checkGETStatusCodeWithAwait5sec("node/branch3/res/leaf", 404); RestAssured.basePath = ""; when().get("node/branch1").then().assertThat().statusCode(200); when().get("node/branch1/res").then().assertThat().statusCode(200); when().get("node/branch1/res/leaf").then().assertThat().statusCode(200).body("foo", equalTo("bar1")); when().get("node/branch2").then().assertThat().statusCode(200); when().get("node/branch2/res").then().assertThat().statusCode(200); when().get("node/branch2/res/leaf").then().assertThat().statusCode(200).body("foo", equalTo("bar2")); when().get("node/branch3").then().assertThat().statusCode(404); when().get("node/branch3/res").then().assertThat().statusCode(404); when().get("node/branch3/res/leaf").then().assertThat().statusCode(404); async.complete(); } @Test public void testThreeBranchesDeleteOnNodeUnderLeafOfOneBranch(TestContext context) { Async async = context.async(); with().body("{ \"foo\": \"bar1\" }").put("branch1/res/res1/leaf"); with().body("{ \"foo\": \"bar2\" }").put("branch2/res/res2/leaf"); with().body("{ \"foo\": \"bar3\" }").put("branch3/res/res3/leaf"); checkGETStatusCodeWithAwait5sec("branch1/res/res1/leaf", 200); checkGETStatusCodeWithAwait5sec("branch2/res/res2/leaf", 200); checkGETStatusCodeWithAwait5sec("branch3/res/res3/leaf", 200); delete("branch1/res"); checkGETStatusCodeWithAwait5sec("branch1/res", 404); RestAssured.basePath = ""; when().get("/branch1").then().assertThat().statusCode(404); when().get("/branch1/res").then().assertThat().statusCode(404); when().get("/branch1/res/res1/").then().assertThat().statusCode(404); when().get("/branch1/res/res1/leaf").then().assertThat().statusCode(404); when().get("/branch2").then().assertThat().statusCode(200); when().get("/branch2/res").then().assertThat().statusCode(200); when().get("/branch2/res/res2").then().assertThat().statusCode(200); when().get("/branch2/res/res2/leaf").then().assertThat().statusCode(200).body("foo", equalTo("bar2")); when().get("/branch3").then().assertThat().statusCode(200); when().get("/branch3/res").then().assertThat().statusCode(200); when().get("/branch3/res/res3").then().assertThat().statusCode(200); when().get("/branch3/res/res3/leaf").then().assertThat().statusCode(200).body("foo", equalTo("bar3")); async.complete(); } @Test public void testThreeBranchesDeleteOnNodeAfterBranch(TestContext context) { Async async = context.async(); with().body("{ \"foo\": \"bar1\" }").put("branch1/res/res1/leaf"); with().body("{ \"foo\": \"bar2\" }").put("branch2/res/res2/leaf"); with().body("{ \"foo\": \"bar3\" }").put("branch3/res/res3/leaf"); checkGETStatusCodeWithAwait5sec("branch1/res/res1/leaf", 200); checkGETStatusCodeWithAwait5sec("branch2/res/res2/leaf", 200); checkGETStatusCodeWithAwait5sec("branch3/res/res3/leaf", 200); delete("branch2/res"); checkGETStatusCodeWithAwait5sec("branch2/res", 404); RestAssured.basePath = ""; when().get("branch1").then().assertThat().statusCode(200); when().get("branch1/res").then().assertThat().statusCode(200); when().get("branch1/res/res1").then().assertThat().statusCode(200); when().get("branch1/res/res1/leaf").then().assertThat().statusCode(200).body("foo", equalTo("bar1")); when().get("branch2").then().assertThat().statusCode(404); when().get("branch2/res").then().assertThat().statusCode(404); when().get("branch2/res/res2").then().assertThat().statusCode(404); when().get("branch2/res/res2/leaf").then().assertThat().statusCode(404); when().get("branch3").then().assertThat().statusCode(200); when().get("branch3/res").then().assertThat().statusCode(200); when().get("branch3/res/res3").then().assertThat().statusCode(200); when().get("branch3/res/res3/leaf").then().assertThat().statusCode(200).body("foo", equalTo("bar3")); async.complete(); } @Test public void testThreeBranchesDeleteOnRoot(TestContext context) { Async async = context.async(); with().body("{ \"foo\": \"bar\" }").put("node/node/node/branch1/res/res1/leaf"); with().body("{ \"foo\": \"bar\" }").put("node/node/node/branch2/res/res2/leaf"); with().body("{ \"foo\": \"bar\" }").put("node/node/node/branch3/res/res3/leaf"); checkGETStatusCodeWithAwait5sec("node/node/node/branch1/res/res1/leaf", 200); checkGETStatusCodeWithAwait5sec("node/node/node/branch2/res/res2/leaf", 200); checkGETStatusCodeWithAwait5sec("node/node/node/branch3/res/res3/leaf", 200); RestAssured.basePath = ""; delete("/"); checkGETStatusCodeWithAwait5sec("/", 404); when().get("node").then().assertThat().statusCode(404); when().get("node/node").then().assertThat().statusCode(404); when().get("node/node/node").then().assertThat().statusCode(404); when().get("node/node/node/branch2").then().assertThat().statusCode(404); when().get("node/node/node/branch2/res").then().assertThat().statusCode(404); when().get("node/node/node/branch2/res/res2/leaf").then().assertThat().statusCode(404); when().get("node/node/node/branch1").then().assertThat().statusCode(404); when().get("node/node/node/branch1/res").then().assertThat().statusCode(404); when().get("node/node/node/branch1/res/leaf").then().assertThat().statusCode(404); when().get("node/node/node/branch1/res/res1/leaf").then().assertThat().statusCode(404); when().get("node/node/node/branch3").then().assertThat().statusCode(404); when().get("node/node/node/branch3/res").then().assertThat().statusCode(404); when().get("node/node/node/branch3/res/leaf").then().assertThat().statusCode(404); when().get("node/node/node/branch3/res/res3/leaf").then().assertThat().statusCode(404); async.complete(); } @Test public void testGetSingleResourceWithColonsAndSemiColonsInName(TestContext context) { Async async = context.async(); with().urlEncodingEnabled(false).body("{ \"foo\": \"bar\" }").put("resources/1_hello-:@$&()*+,;=-._~!'"); checkGETStatusCodeWithAwait5secNoUrlEncoding("resources/1_hello-:@$&()*+,;=-._~!'", 200); async.complete(); } @Test public void testGetAndDeleteResourceWithColonsAndSemiColonsInTheName(TestContext context) { Async async = context.async(); String res1 = "999_hello-:@$&()*+,;=-._~!'"; // PUT resource with().urlEncodingEnabled(false).body("{ \"foo\": \"bar_999\" }").put("resources/"+res1); // GET resource checkGETStatusCodeWithAwait5secNoUrlEncoding("resources/"+res1, 200); context.assertEquals("bar_999", given().urlEncodingEnabled(false).when().get("resources/"+res1).jsonPath().getString("foo")); // DELETE resource given().urlEncodingEnabled(false).when().delete("resources/"+res1).then().assertThat().statusCode(200); // check if deleted given().urlEncodingEnabled(false).when().get("resources/"+res1).then().assertThat().statusCode(404); async.complete(); } @Test public void testGetCollectionHavingResourcesWithColonsAndSemiColonsInTheName(TestContext context) { Async async = context.async(); String res1 = "1_hello-:@$&()*+,;=-._~!'"; String res2 = "2_hello-:@$&()*+,;=-._~!'"; String res3 = "3_hello"; with().urlEncodingEnabled(false).body("{ \"foo\": \"bar\" }").put("resources/"+res1); with().urlEncodingEnabled(false).body("{ \"foo\": \"bar2\" }").put("resources/"+res2); with().urlEncodingEnabled(false).body("{ \"foo\": \"bar3\" }").put("resources/"+res3); checkGETStatusCodeWithAwait5secNoUrlEncoding("resources/"+res1, 200); checkGETStatusCodeWithAwait5secNoUrlEncoding("resources/"+res2, 200); checkGETStatusCodeWithAwait5secNoUrlEncoding("resources/"+res3, 200); when().get("resources").then().assertThat().body("resources", hasItems(res1, res2, res3)); async.complete(); } @Test public void testGetHTMLCollectionHavingResourcesWithColonsAndSemiColonsInTheName(TestContext context) { Async async = context.async(); String res1 = "1_hello-:@$&()*+,;=-._~!'"; String res2 = "2_hello-:@$&()*+,;=-._~!'"; String res3 = "3_hello"; with().urlEncodingEnabled(false).body("{ \"foo\": \"bar\" }").put("resources/"+res1); with().urlEncodingEnabled(false).body("{ \"foo\": \"bar2\" }").put("resources/"+res2); with().urlEncodingEnabled(false).body("{ \"foo\": \"bar3\" }").put("resources/"+res3); checkGETStatusCodeWithAwait5secNoUrlEncoding("resources/"+res1, 200); checkGETStatusCodeWithAwait5secNoUrlEncoding("resources/"+res2, 200); checkGETStatusCodeWithAwait5secNoUrlEncoding("resources/"+res3, 200); String title = given().header("Accept", "text/html").when().get("resources").htmlPath().getString("html.head.title"); context.assertEquals("resources", title); List<String> listItems = given().header("Accept", "text/html").when().get("resources").htmlPath().getList("html.body.ul.li"); context.assertEquals(res1, listItems.get(1)); context.assertEquals(res2, listItems.get(2)); context.assertEquals(res3, listItems.get(3)); async.complete(); } private void checkGETStatusCodeWithAwait5sec(final String request, final Integer statusCode) { await().atMost(Duration.FIVE_SECONDS).until(() -> String.valueOf(when().get(request).getStatusCode()), equalTo(String.valueOf(statusCode))); } private void checkGETStatusCodeWithAwait5secNoUrlEncoding(final String request, final Integer statusCode) { await().atMost(Duration.FIVE_SECONDS).until(() -> String.valueOf(given().urlEncodingEnabled(false).when().get(request).getStatusCode()), equalTo(String.valueOf(statusCode))); } }