Coverage on query

This commit is contained in:
2023-03-21 11:50:54 -05:00
parent 303cd4aec0
commit c6fa22524c
3 changed files with 186 additions and 39 deletions

View File

@ -72,7 +72,6 @@ import com.kingsrook.qqq.backend.core.utils.StringUtils;
import com.kingsrook.qqq.backend.core.utils.ValueUtils; import com.kingsrook.qqq.backend.core.utils.ValueUtils;
import com.kingsrook.qqq.backend.javalin.QJavalinAccessLogger; import com.kingsrook.qqq.backend.javalin.QJavalinAccessLogger;
import com.kingsrook.qqq.backend.javalin.QJavalinImplementation; import com.kingsrook.qqq.backend.javalin.QJavalinImplementation;
import com.kingsrook.qqq.backend.javalin.QJavalinUtils;
import io.javalin.apibuilder.ApiBuilder; import io.javalin.apibuilder.ApiBuilder;
import io.javalin.apibuilder.EndpointGroup; import io.javalin.apibuilder.EndpointGroup;
import io.javalin.http.ContentType; import io.javalin.http.ContentType;
@ -198,16 +197,7 @@ public class QJavalinApiHandler
// todo - make sure table is supported in this version // todo - make sure table is supported in this version
QTableMetaData table = qInstance.getTable(tableName); QTableMetaData table = qInstance.getTable(tableName);
validateTableAndVersion(context, version, table);
if(table == null)
{
throw (new QNotFoundException("Could not find any resources at path " + context.path()));
}
if(!getApiVersionRange(table).includes(new APIVersion(version)))
{
throw (new QNotFoundException("This version of this API does not contain the resource path " + context.path()));
}
GetInput getInput = new GetInput(); GetInput getInput = new GetInput();
@ -270,16 +260,7 @@ public class QJavalinApiHandler
// todo - make sure table is supported in this version // todo - make sure table is supported in this version
QTableMetaData table = qInstance.getTable(tableName); QTableMetaData table = qInstance.getTable(tableName);
validateTableAndVersion(context, version, table);
if(table == null)
{
throw (new QNotFoundException("Could not find any resources at path " + context.path()));
}
if(!getApiVersionRange(table).includes(new APIVersion(version)))
{
throw (new QNotFoundException("This version of this API does not contain the resource path " + context.path()));
}
QueryInput queryInput = new QueryInput(); QueryInput queryInput = new QueryInput();
setupSession(context, queryInput); setupSession(context, queryInput);
@ -308,7 +289,18 @@ public class QJavalinApiHandler
badRequestMessages.add("pageSize must be between 1 and 1000."); badRequestMessages.add("pageSize must be between 1 and 1000.");
} }
Integer pageNo = Objects.requireNonNullElse(QJavalinUtils.integerQueryParam(context, "pageNo"), 1); Integer pageNo = 1;
if(StringUtils.hasContent(context.queryParam("pageNo")))
{
try
{
pageNo = ValueUtils.getValueAsInteger(context.queryParam("pageNo"));
}
catch(Exception e)
{
badRequestMessages.add("Could not parse pageNo as an integer");
}
}
if(pageNo < 1) if(pageNo < 1)
{ {
badRequestMessages.add("pageNo must be greater than 0."); badRequestMessages.add("pageNo must be greater than 0.");
@ -432,7 +424,7 @@ public class QJavalinApiHandler
} }
else else
{ {
throw (new QBadRequestException("Requested failed with " + badRequestMessages.size() + " reasons: " + StringUtils.join(" \n", badRequestMessages))); throw (new QBadRequestException("Request failed with " + badRequestMessages.size() + " reasons: " + StringUtils.join(" \n", badRequestMessages)));
} }
} }
@ -482,6 +474,30 @@ public class QJavalinApiHandler
/*******************************************************************************
**
*******************************************************************************/
private static void validateTableAndVersion(Context context, String version, QTableMetaData table) throws QNotFoundException
{
if(table == null)
{
throw (new QNotFoundException("Could not find any resources at path " + context.path()));
}
APIVersion requestApiVersion = new APIVersion(version);
if(!ApiMiddlewareType.getApiInstanceMetaData(qInstance).getSupportedVersions().contains(requestApiVersion))
{
throw (new QNotFoundException("This version of this API does not contain the resource path " + context.path()));
}
if(!getApiVersionRange(table).includes(requestApiVersion))
{
throw (new QNotFoundException("This version of this API does not contain the resource path " + context.path()));
}
}
/******************************************************************************* /*******************************************************************************
** **
*******************************************************************************/ *******************************************************************************/

View File

@ -104,4 +104,37 @@ public class APIVersion implements Comparable<APIVersion>
{ {
return (version); return (version);
} }
/*******************************************************************************
**
*******************************************************************************/
@Override
public boolean equals(Object o)
{
if(this == o)
{
return true;
}
if(o == null || getClass() != o.getClass())
{
return false;
}
APIVersion that = (APIVersion) o;
return Objects.equals(version, that.version);
}
/*******************************************************************************
**
*******************************************************************************/
@Override
public int hashCode()
{
return Objects.hash(version);
}
} }

View File

@ -29,12 +29,12 @@ import com.kingsrook.qqq.backend.core.actions.tables.InsertAction;
import com.kingsrook.qqq.backend.core.exceptions.QException; import com.kingsrook.qqq.backend.core.exceptions.QException;
import com.kingsrook.qqq.backend.core.exceptions.QInstanceValidationException; import com.kingsrook.qqq.backend.core.exceptions.QInstanceValidationException;
import com.kingsrook.qqq.backend.core.model.actions.tables.insert.InsertInput; import com.kingsrook.qqq.backend.core.model.actions.tables.insert.InsertInput;
import com.kingsrook.qqq.backend.core.model.actions.tables.insert.InsertOutput;
import com.kingsrook.qqq.backend.core.model.data.QRecord; import com.kingsrook.qqq.backend.core.model.data.QRecord;
import com.kingsrook.qqq.backend.core.model.metadata.QInstance; import com.kingsrook.qqq.backend.core.model.metadata.QInstance;
import com.kingsrook.qqq.backend.javalin.QJavalinImplementation; import com.kingsrook.qqq.backend.javalin.QJavalinImplementation;
import kong.unirest.HttpResponse; import kong.unirest.HttpResponse;
import kong.unirest.Unirest; import kong.unirest.Unirest;
import org.json.JSONArray;
import org.json.JSONObject; import org.json.JSONObject;
import org.junit.jupiter.api.AfterAll; import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.BeforeAll;
@ -123,10 +123,7 @@ class QJavalinApiHandlerTest extends BaseTest
@Test @Test
void testGet200() throws QException void testGet200() throws QException
{ {
InsertInput insertInput = new InsertInput(); insertTestRecord();
insertInput.setTableName(TestUtils.TABLE_NAME_PERSON);
insertInput.setRecords(List.of(new QRecord().withValue("id", 1).withValue("firstName", "Darin").withValue("lastName", "Kelkhoff")));
InsertOutput insertOutput = new InsertAction().execute(insertInput);
HttpResponse<String> response = Unirest.get(BASE_URL + "/api/" + VERSION + "/person/1").asString(); HttpResponse<String> response = Unirest.get(BASE_URL + "/api/" + VERSION + "/person/1").asString();
assertEquals(200, response.getStatus()); assertEquals(200, response.getStatus());
@ -141,16 +138,12 @@ class QJavalinApiHandlerTest extends BaseTest
/******************************************************************************* /*******************************************************************************
** **
*******************************************************************************/ *******************************************************************************/
@Test private static void insertTestRecord() throws QException
void testQuery400()
{ {
HttpResponse<String> response = Unirest.get(BASE_URL + "/api/" + VERSION + "/person/query?asdf=Darin&orderBy=asdf asdf").asString(); InsertInput insertInput = new InsertInput();
assertEquals(400, response.getStatus()); insertInput.setTableName(TestUtils.TABLE_NAME_PERSON);
JSONObject jsonObject = new JSONObject(response.getBody()); insertInput.setRecords(List.of(new QRecord().withValue("id", 1).withValue("firstName", "Darin").withValue("lastName", "Kelkhoff")));
String error = jsonObject.getString("error"); new InsertAction().execute(insertInput);
assertThat(error).contains("orderBy direction for field asdf must be either ASC or DESC");
assertThat(error).contains("Unrecognized orderBy field name: asdf");
assertThat(error).contains("Unrecognized filter criteria field: asdf");
} }
@ -159,9 +152,49 @@ class QJavalinApiHandlerTest extends BaseTest
** **
*******************************************************************************/ *******************************************************************************/
@Test @Test
void testQuery() void testQuery404()
{ {
HttpResponse<String> response = Unirest.get(BASE_URL + "/api/" + VERSION + "/person/query?firstName=Darin&orderBy=firstName desc").asString(); assertError(404, BASE_URL + "/api/" + VERSION + "/notATable/query?");
assertError(404, BASE_URL + "/api/notAVersion/person/query?");
}
/*******************************************************************************
**
*******************************************************************************/
@Test
void testQuery400()
{
String base = BASE_URL + "/api/" + VERSION + "/person/query?";
assertError("Could not parse pageNo as an integer", base + "pageNo=foo");
assertError("pageNo must be greater than 0", base + "pageNo=0");
assertError("Could not parse pageSize as an integer", base + "pageSize=foo");
assertError("pageSize must be between 1 and 1000.", base + "pageSize=0");
assertError("pageSize must be between 1 and 1000.", base + "pageSize=1001");
assertError("booleanOperator must be either AND or OR", base + "booleanOperator=not");
assertError("includeCount must be either true or false", base + "includeCount=maybe");
assertError("orderBy direction for field firstName must be either ASC or DESC", base + "orderBy=firstName foo");
assertError("Unrecognized format for orderBy clause: firstName asc foo", base + "orderBy=firstName asc foo");
assertError("Unrecognized orderBy field name: foo", base + "orderBy=foo");
assertError("Unrecognized filter criteria field: foo", base + "foo=bar");
assertError("Request failed with 2 reasons", base + "foo=bar&bar=baz");
}
/*******************************************************************************
**
*******************************************************************************/
@Test
void testQuery200NoParams()
{
HttpResponse<String> response = Unirest.get(BASE_URL + "/api/" + VERSION + "/person/query").asString();
assertEquals(200, response.getStatus()); assertEquals(200, response.getStatus());
JSONObject jsonObject = new JSONObject(response.getBody()); JSONObject jsonObject = new JSONObject(response.getBody());
assertEquals(0, jsonObject.getInt("count")); assertEquals(0, jsonObject.getInt("count"));
@ -169,4 +202,69 @@ class QJavalinApiHandlerTest extends BaseTest
assertEquals(50, jsonObject.getInt("pageSize")); assertEquals(50, jsonObject.getInt("pageSize"));
} }
/*******************************************************************************
**
*******************************************************************************/
@Test
void testQuery200SomethingFound() throws QException
{
insertTestRecord();
HttpResponse<String> response = Unirest.get(BASE_URL + "/api/" + VERSION + "/person/query").asString();
assertEquals(200, response.getStatus());
JSONObject jsonObject = new JSONObject(response.getBody());
assertEquals(1, jsonObject.getInt("count"));
assertEquals(1, jsonObject.getInt("pageNo"));
assertEquals(50, jsonObject.getInt("pageSize"));
JSONArray jsonArray = jsonObject.getJSONArray("records");
jsonObject = jsonArray.getJSONObject(0);
assertEquals(1, jsonObject.getInt("id"));
assertEquals("Darin", jsonObject.getString("firstName"));
assertEquals("Kelkhoff", jsonObject.getString("lastName"));
}
/*******************************************************************************
**
*******************************************************************************/
@Test
void testQuery200ManyParams()
{
HttpResponse<String> response = Unirest.get(BASE_URL + "/api/" + VERSION + "/person/query?pageSize=49&pageNo=2&includeCount=true&booleanOperator=AND&firstName=Darin&orderBy=firstName desc").asString();
assertEquals(200, response.getStatus());
JSONObject jsonObject = new JSONObject(response.getBody());
assertEquals(0, jsonObject.getInt("count"));
assertEquals(2, jsonObject.getInt("pageNo"));
assertEquals(49, jsonObject.getInt("pageSize"));
}
/*******************************************************************************
**
*******************************************************************************/
private void assertError(Integer statusCode, String url)
{
HttpResponse<String> response = Unirest.get(url).asString();
assertEquals(statusCode, response.getStatus());
}
/*******************************************************************************
**
*******************************************************************************/
private void assertError(String expectedErrorMessage, String url)
{
HttpResponse<String> response = Unirest.get(url).asString();
assertEquals(400, response.getStatus());
JSONObject jsonObject = new JSONObject(response.getBody());
String error = jsonObject.getString("error");
assertThat(error).contains(expectedErrorMessage);
}
} }