package org.swisspush.reststorage; import com.jayway.restassured.specification.RequestSpecification; 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 static com.jayway.restassured.RestAssured.*; import static org.hamcrest.CoreMatchers.containsString; import static org.hamcrest.CoreMatchers.equalTo; @RunWith(VertxUnitRunner.class) public class ResourceCompressionTest extends AbstractTestCase { private final String COMPRESS_HEADER = "x-stored-compressed"; private final String IF_NONE_MATCH_HEADER = "if-none-match"; @Test public void testPutGetWithCompression(TestContext context) { Async async = context.async(); putResource("{ \"foo\": \"bar\" }", true, 200); getResource("res", 200, "foo", "bar"); async.complete(); } /** * The resource has always to be overwritten, if the compression state differs between the sent resource * and the stored resource. This behaviour is, to prevent unexpected behaviour considering the etag mechanism. */ @Test public void testStoreCompressedAndUnCompressed() { String originalContent = "{\"content\": \"originalContent\"}"; String modifiedContent = "{\"content\": \"modifiedContent\"}"; // Scenario 1: PUT 1 = {uncompressed, etag1}, PUT 2 = {compressed, etag1} putResource(originalContent, false, 200); putResource(modifiedContent, true, 200); getResource("res", 200, "content", "modifiedContent"); // Scenario 2: PUT 1 = {compressed, etag1}, PUT 2 = {uncompressed, etag1} jedis.flushAll(); putResource(originalContent, true, 200); putResource(modifiedContent, false, 200); getResource("res", 200, "content", "modifiedContent"); // Scenario 3: PUT 1 = {compressed, etag1}, PUT 2 = {compressed, etag1} jedis.flushAll(); putResource(originalContent, true, 200); putResource(modifiedContent, true, 304); getResource("res", 200, "content", "originalContent"); // Scenario 4: PUT 1 = {uncompressed, etag1}, PUT 2 = {uncompressed, etag1} jedis.flushAll(); putResource(originalContent, false, 200); putResource(modifiedContent, false, 304); getResource("res", 200, "content", "originalContent"); } @Test public void testCompressAndMerge(TestContext context) { Async async = context.async(); with() .header(COMPRESS_HEADER, "true") .param("merge", "true") .body("{ \"foo\": \"bar2\" }") .put("res") .then().assertThat() .statusCode(400) .body(containsString("Invalid parameter/header combination: merge parameter and " + COMPRESS_HEADER + " header cannot be used concurrently")); async.complete(); } @Test public void testGetFailHandlingForCorruptCompressedData(TestContext context) { Async async = context.async(); putResource("{ \"foo\": \"bar\" }", true, 200); // cripple compressed data to make it impossible to decompress jedis.hset("rest-storage:resources:res", "resource", "xxx"); when() .get("res") .then().assertThat() .statusCode(500) .body(containsString("Error during decompression of resource: Not in GZIP format")); async.complete(); } private void putResource(String body, boolean storeCompressed, int statusCode){ RequestSpecification spec = given().header(IF_NONE_MATCH_HEADER, "etag1"); if(storeCompressed){ spec = spec.header(COMPRESS_HEADER, "true"); } spec.body(body).put("res").then().assertThat().statusCode(statusCode); } private void getResource(String path, int statusCode, String bodyProperty, String equalToValue){ when() .get(path) .then().assertThat() .statusCode(statusCode) .body(bodyProperty, equalTo(equalToValue)); } }