Skip to content

Commit

Permalink
Allow custom api writers to mock the http environment
Browse files Browse the repository at this point in the history
  • Loading branch information
javiertuya committed Jul 3, 2024
1 parent 13b8292 commit 196a830
Show file tree
Hide file tree
Showing 5 changed files with 117 additions and 1 deletion.
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,11 @@ public class ApiWriter {
// Headers to sent (in addition to Content-type: application/json)
private List<String[]> headers = new ArrayList<>();

public ApiWriter reset() {
headers = new ArrayList<>();
return this;
}

public ApiWriter addHeader(String key, String value) {
headers.add(new String[] { key, value });
return this;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,17 @@ public interface IPathResolver {
* Sets the url (without path) of the service
*/
IPathResolver setServerUrl(String url);

/**
* Sets an alternative ApiWriter used to send requests
*/
IPathResolver setApiWriter(ApiWriter writer);

/**
* Geths the ApiWriter used to send requests
* (this is the default ApiWriter if none has been set)
*/
ApiWriter getApiWriter();

/**
* Determines the url where a POST to create an object must be sent.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ public void endWrite() {
boolean usePut = resolver.usePut(this.currentEntity);
log.trace("endWrite: {} to url {}", usePut ? "PUT" : "POST", url);

ApiWriter writer = new ApiWriter();
ApiWriter writer = resolver.getApiWriter().reset();
if (authStore != null) // Store or set credentials, if applicable
authStore.processAuthentication(this.currentEntity, json, writer);
ApiResponse response = writer.post(url, json, usePut);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,12 +23,26 @@ public class OaPathResolver implements IPathResolver {

private String url = "";
private TdSchema model = null;
// To send api requests, uses this default ApiWriter to send requests to a server,
// unless another is set
private ApiWriter writer = new ApiWriter();

@Override
public IPathResolver setServerUrl(String url) {
this.url = url;
return this;
}

@Override
public IPathResolver setApiWriter(ApiWriter writer) {
this.writer = writer;
return this;
}

@Override
public ApiWriter getApiWriter() {
return this.writer;
}

@Override
public String getEndpointPath(String entityName) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
package test4giis.tdrules.store.loader.oa;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertThrows;

import org.junit.Test;

import giis.tdrules.model.ModelException;
import giis.tdrules.openapi.model.TdAttribute;
import giis.tdrules.openapi.model.TdEntity;
import giis.tdrules.openapi.model.TdSchema;
import giis.tdrules.store.loader.DataLoader;
import giis.tdrules.store.loader.IDataAdapter;
import giis.tdrules.store.loader.oa.ApiResponse;
import giis.tdrules.store.loader.oa.ApiWriter;
import giis.tdrules.store.loader.oa.IPathResolver;
import giis.tdrules.store.loader.oa.OaLiveAdapter;
import giis.tdrules.store.loader.oa.OaLiveUidGen;
import giis.tdrules.store.loader.oa.OaPathResolver;

/**
* Test a custom ApiClient to mock the servlet environment. This is used to test
* the HTTP controller endpoints without the need to launch a servlet container
*/
public class TestApiClientMock {

protected TdSchema getModel() {
TdEntity master = new TdEntity().name("Master")
.addAttributesItem(new TdAttribute().name("pk1").datatype("integer").uid("true"))
.addAttributesItem(new TdAttribute().name("i1").datatype("int32"));
TdEntity detail = new TdEntity().name("Detail")
.addAttributesItem(new TdAttribute().name("pk1").datatype("integer").uid("true"))
.addAttributesItem(new TdAttribute().name("fk1").datatype("integer").rid("Master.pk1"));
return new TdSchema().storetype("openapi").addEntitiesItem(master).addEntitiesItem(detail);
}

// Data generator with a path resolver that uses a custom api writer
protected DataLoader getLiveGenerator() {
ApiWriter writer = new CustomApiWriter(); // this mocks the servlet environment and the server
IPathResolver resolver = new OaPathResolver().setServerUrl("").setApiWriter(writer);
IDataAdapter dataAdapter = new OaLiveAdapter(resolver);
return new DataLoader(getModel(), dataAdapter).setUidGen(new OaLiveUidGen());
}

// This custom api writer returns the content of the body request
// and simulates a server generated uid by adding it to the response
public class CustomApiWriter extends ApiWriter {
public ApiResponse post(String url, String requestBody, boolean usePut) {
if ("/master".equals(url) && "{\"i1\":2}".equals(requestBody))
return new ApiResponse(200, "OK", "{\"pk1\":99,\"i1\":2}");
else if ("/detail".equals(url))
return new ApiResponse(200, "OK", requestBody);
else
return new ApiResponse(404, "NotFound", "");
}
}

// Checks that the custom api writer works fine integrated with the data loading
// - request sent
// - response received
// - a symbolic generated key for master that is recovered and sent to the detail
@Test
public void testGenerateMockOk() {
DataLoader dtg = getLiveGenerator();
String json1 = dtg.load("master", "pk1=@generatedpk");
assertEquals("{\"i1\":2}", json1);
assertEquals("{\"pk1\":99,\"i1\":2}", dtg.getDataAdapter().getLastResponse());

String json2 = dtg.load("detail", "fk1=@generatedpk");
assertEquals("{\"pk1\":101,\"fk1\":99}", json2);
assertEquals("{\"pk1\":101,\"fk1\":99}", dtg.getDataAdapter().getLastResponse());

assertEquals("\"master\":{\"i1\":2}\n" + "\"detail\":{\"pk1\":101,\"fk1\":99}",
dtg.getDataAdapter().getAllAsString());
}

@Test
public void testGenerateMockError() {
DataLoader dtg = getLiveGenerator();
ModelException exception = assertThrows(ModelException.class, () -> {
dtg.load("notexists", "");
});
assertEquals("Can't find any entity in the schema with name notexists", exception.getMessage());
}

}

0 comments on commit 196a830

Please sign in to comment.