Skip to content

Commit

Permalink
Adding JSON aliases to blob endpoints, and the Blob and Blobs classes
Browse files Browse the repository at this point in the history
Adding office formats to the FormatsTest, since I forgot them.
Updated blob integration tests and included get all tests
  • Loading branch information
RyanM-RMA committed Jun 6, 2024
1 parent 4ec7599 commit 6f1fd51
Show file tree
Hide file tree
Showing 5 changed files with 124 additions and 69 deletions.
9 changes: 4 additions & 5 deletions cwms-data-api/src/main/java/cwms/cda/api/BlobController.java
Original file line number Diff line number Diff line change
Expand Up @@ -85,8 +85,8 @@ protected DSLContext getDslContext(Context ctx) {
responses = {@OpenApiResponse(status = STATUS_200,
description = "A list of blobs.",
content = {
@OpenApiContent(type = Formats.JSON, from = Blobs.class),
@OpenApiContent(type = Formats.JSONV2, from = Blobs.class),
@OpenApiContent(type = Formats.XMLV2, from = Blobs.class)
})
},
tags = {TAG}
Expand Down Expand Up @@ -115,7 +115,7 @@ public void getAll(@NotNull Context ctx) {
String like = ctx.queryParamAsClass(LIKE, String.class).getOrDefault(".*");

String formatHeader = ctx.header(Header.ACCEPT);
ContentType contentType = Formats.parseHeaderAndQueryParm(formatHeader, "");
ContentType contentType = Formats.parseHeader(formatHeader, Blobs.class);

BlobDao dao = new BlobDao(dsl);
List<Blob> blobList = dao.getAll(office, like);
Expand Down Expand Up @@ -169,8 +169,7 @@ public void getOne(@NotNull Context ctx, @NotNull String blobId) {
description = "Create new Blob",
requestBody = @OpenApiRequestBody(
content = {
@OpenApiContent(from = Blob.class, type = Formats.JSONV2),
@OpenApiContent(from = Blob.class, type = Formats.XMLV2)
@OpenApiContent(from = Blob.class, type = Formats.JSONV2)
},
required = true),
queryParams = {
Expand All @@ -189,7 +188,7 @@ public void create(@NotNull Context ctx) {
String formatHeader = reqContentType != null ? reqContentType : Formats.JSON;

boolean failIfExists = ctx.queryParamAsClass(FAIL_IF_EXISTS, Boolean.class).getOrDefault(true);
ContentType contentType = Formats.parseHeader(formatHeader);
ContentType contentType = Formats.parseHeader(formatHeader, Blob.class);
Blob blob = Formats.parseContent(contentType, ctx.bodyAsInputStream(), Blob.class);

if (blob.getOfficeId() == null) {
Expand Down
3 changes: 2 additions & 1 deletion cwms-data-api/src/main/java/cwms/cda/data/dto/Blob.java
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,10 @@
import cwms.cda.formatters.Formats;
import cwms.cda.formatters.annotations.FormattableWith;
import cwms.cda.formatters.json.JsonV2;
import cwms.cda.formatters.xml.XMLv2;

@JsonNaming(PropertyNamingStrategies.KebabCaseStrategy.class)
@FormattableWith(contentType = Formats.JSONV2, formatter = JsonV2.class)
@FormattableWith(contentType = Formats.JSONV2, formatter = JsonV2.class, aliases = {Formats.DEFAULT, Formats.JSON})
public class Blob extends CwmsDTO
{
@JsonProperty(required=true)
Expand Down
2 changes: 1 addition & 1 deletion cwms-data-api/src/main/java/cwms/cda/data/dto/Blobs.java
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
import java.util.List;

@JsonRootName("blobs")
@FormattableWith(contentType = Formats.JSONV2, formatter = JsonV2.class)
@FormattableWith(contentType = Formats.JSONV2, formatter = JsonV2.class, aliases = {Formats.DEFAULT, Formats.JSON})
public class Blobs extends CwmsDTOPaginated {
@JacksonXmlElementWrapper(localName = "blobs")
@JacksonXmlProperty(localName = "blob")
Expand Down
170 changes: 108 additions & 62 deletions cwms-data-api/src/test/java/cwms/cda/api/BlobControllerTestIT.java
Original file line number Diff line number Diff line change
@@ -1,117 +1,163 @@
package cwms.cda.api;

import static io.restassured.RestAssured.given;
import static org.hamcrest.Matchers.is;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import cwms.cda.data.dto.Blob;
import cwms.cda.formatters.Formats;
import cwms.cda.formatters.json.JsonV2;
import fixtures.TestAccounts;
import io.restassured.filter.log.LogDetail;
import java.io.UnsupportedEncodingException;
import javax.servlet.http.HttpServletResponse;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Tag;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.EnumSource;

import javax.servlet.http.HttpServletResponse;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;

import static io.restassured.RestAssured.given;
import static org.hamcrest.Matchers.is;

@Tag("integration")
public class BlobControllerTestIT extends DataApiTestIT {

public static final String SPK = "SPK";
private static final String EXISTING_BLOB_ID = "TEST_BLOBIT2";
private static final String EXISTING_BLOB_VALUE = "test value";

@BeforeAll
static void createExistingBlob() throws Exception
{
String origDesc = "test description";
byte[] origBytes = EXISTING_BLOB_VALUE.getBytes();

String mediaType = "application/octet-stream";
Blob blob = new Blob(SPK, EXISTING_BLOB_ID, origDesc, mediaType, origBytes);
ObjectMapper om = JsonV2.buildObjectMapper();
String serializedBlob = om.writeValueAsString(blob);
TestAccounts.KeyUser user = TestAccounts.KeyUser.SPK_NORMAL;

given()
.log().ifValidationFails(LogDetail.ALL,true)
.contentType(Formats.JSONV2)
.body(serializedBlob)
.header("Authorization",user.toHeaderValue())
.queryParam("office",SPK)
.queryParam("fail-if-exists",false)
.when()
.redirects().follow(true)
.redirects().max(3)
.post("/blobs/")
.then()
.log().ifValidationFails(LogDetail.ALL,true)
.assertThat()
.statusCode(is(HttpServletResponse.SC_CREATED));
}

@Test
void test_getOne_not_found() throws UnsupportedEncodingException {
String blobId = "TEST";
String urlencoded = java.net.URLEncoder.encode(blobId, "UTF-8");
String urlencoded = URLEncoder.encode(blobId, "UTF-8");

given()
.log().ifValidationFails(LogDetail.ALL,true)
.log().ifValidationFails(LogDetail.ALL,true)
.accept(Formats.JSONV2)
.queryParam(Controllers.OFFICE, SPK)
.when()
.get("/blobs/" + urlencoded)
.then()
.log().ifValidationFails(LogDetail.ALL,true)
.log().ifValidationFails(LogDetail.ALL,true)
.assertThat()
.statusCode(is(HttpServletResponse.SC_NOT_FOUND));
}


@Test
void test_create_getOne() throws JsonProcessingException {
String blobId = "TEST_BLOBIT2";
void test_create_getOne() throws JsonProcessingException
{
// /* There is an issue with how javalin handles / in the path that are actually part
// of the object name (NOTE: good candidate for actually having a GUID or other "code"
// as part of the path and the actual name as a query parameter.
// */

String origDesc = "test description";
String origValue = "test value";
byte[] origBytes = origValue.getBytes();
given()
.log().ifValidationFails(LogDetail.ALL, true)
.accept(Formats.JSONV2)
.queryParam(Controllers.OFFICE, SPK)
.when()
.get("/blobs/" + EXISTING_BLOB_ID)
.then()
.log().ifValidationFails(LogDetail.ALL, true)
.assertThat()
.statusCode(is(HttpServletResponse.SC_OK))
.body(is(EXISTING_BLOB_VALUE));
}

String mediaType = "application/octet-stream";
Blob blob = new Blob(SPK, blobId, origDesc, mediaType, origBytes);
ObjectMapper om = JsonV2.buildObjectMapper();
String serializedBlob = om.writeValueAsString(blob);
TestAccounts.KeyUser user = TestAccounts.KeyUser.SPK_NORMAL;
@Test
void test_blob_get_one_default()
{
given()
.log()
.ifValidationFails(LogDetail.ALL, true)
.queryParam(Controllers.OFFICE, SPK)
.when()
.get("/blobs/" + EXISTING_BLOB_ID)
.then()
.log().ifValidationFails(LogDetail.ALL, true)
.assertThat()
.statusCode(is(HttpServletResponse.SC_OK))
.body(is(EXISTING_BLOB_VALUE));
}

@Test
void test_blob_range()
{
// We can now do Range requests!
given()
.log().ifValidationFails(LogDetail.ALL,true)
.accept(Formats.JSONV2)
.contentType(Formats.JSONV2)
.body(serializedBlob)
.header("Authorization",user.toHeaderValue())
.queryParam("office",SPK)
.queryParam("fail-if-exists",false)
.queryParam(Controllers.OFFICE, SPK)
.header("Range"," bytes=3-")
.when()
.redirects().follow(true)
.redirects().max(3)
.post("/blobs/")
.get("/blobs/" + EXISTING_BLOB_ID)
.then()
.log().ifValidationFails(LogDetail.ALL,true)
.assertThat()
.statusCode(is(HttpServletResponse.SC_CREATED));

// /* There is an issue with how javalin handles / in the path that are actually part
// of the object name (NOTE: good candidate for actually having a GUID or other "code"
// as part of the path and the actual name as a query parameter.
// */
.statusCode(is(HttpServletResponse.SC_PARTIAL_CONTENT))
.body( is("t value"));
}

@ParameterizedTest
@EnumSource(GetAllTest.class)
void test_blob_get_all_default_alias(GetAllTest test)
{
given()
.accept(Formats.JSONV2)
.log().ifValidationFails(LogDetail.ALL,true)
.accept(test._accept)
.queryParam(Controllers.OFFICE, SPK)
.when()
.get("/blobs/" + blobId)
.get("/blobs/")
.then()
.log().ifValidationFails(LogDetail.ALL,true)
.assertThat()
.statusCode(is(HttpServletResponse.SC_OK))
.body( is(origValue));


given()
.log().ifValidationFails(LogDetail.ALL,true)
.queryParam(Controllers.OFFICE, SPK)
.when()
.get("/blobs/" + blobId)
.then()
.log().ifValidationFails(LogDetail.ALL,true)
.assertThat()
.statusCode(is(HttpServletResponse.SC_OK))
.body( is(origValue))
;
.contentType(is(test._expectedContentType));
}

// We can now do Range requests!
given()
.log().ifValidationFails(LogDetail.ALL,true)
.queryParam(Controllers.OFFICE, SPK)
.header("Range"," bytes=3-")
.when()
.get("/blobs/" + blobId)
.then()
.log().ifValidationFails(LogDetail.ALL,true)
.assertThat()
.statusCode(is(HttpServletResponse.SC_PARTIAL_CONTENT))
.body( is("t value"))
enum GetAllTest
{
DEFAULT(Formats.DEFAULT, Formats.JSONV2),
JSON(Formats.JSON, Formats.JSONV2),
JSONV2(Formats.JSONV2, Formats.JSONV2),
;

final String _accept;
final String _expectedContentType;

GetAllTest(String accept, String expectedContentType)
{
_accept = accept;
_expectedContentType = expectedContentType;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import java.util.Arrays;
import java.util.Map;

import cwms.cda.data.dto.Blob;
import cwms.cda.data.dto.County;
import cwms.cda.data.dto.CwmsDTOBase;
import cwms.cda.data.dto.Office;
Expand Down Expand Up @@ -189,6 +190,14 @@ enum ParseHeaderClassAliasTest
STATE_DEFAULT(State.class, Formats.DEFAULT, Formats.JSONV2),
STATE_JSON(State.class, Formats.JSON, Formats.JSONV2),
STATE_JSONV2(State.class, Formats.JSONV2, Formats.JSONV2),
OFFICE_DEFAULT(Office.class, Formats.JSONV2, Formats.JSONV2),
OFFICE_JSON(Office.class, Formats.JSONV2, Formats.JSONV2),
OFFICE_JSONV2(Office.class, Formats.JSONV2, Formats.JSONV2),
OFFICE_XML(Office.class, Formats.XML, Formats.XMLV2),
OFFICE_XMLV2(Office.class, Formats.XMLV2, Formats.XMLV2),
BLOB_DEFAULT(Blob.class, Formats.DEFAULT, Formats.JSONV2),
BLOB_JSON(Blob.class, Formats.JSON, Formats.JSONV2),
BLOB_JSONV2(Blob.class, Formats.JSONV2, Formats.JSONV2),
;

final Class<? extends CwmsDTOBase> _class;
Expand Down

0 comments on commit 6f1fd51

Please sign in to comment.