Skip to content

Commit

Permalink
Merge pull request #321 from cliveseldon/bin_data
Browse files Browse the repository at this point in the history
Allow further options for binary and tensors in prediction API
  • Loading branch information
ukclivecox authored Dec 3, 2018
2 parents 46c4f07 + 8f66f67 commit 0c4b6ac
Show file tree
Hide file tree
Showing 37 changed files with 1,955 additions and 162 deletions.
1 change: 1 addition & 0 deletions api-frontend/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ update_proto:
cp -v ../proto/prediction.proto src/main/proto/
cp -vr ../proto/k8s/k8s.io src/main/proto
cp -v ../proto/k8s/v1.proto src/main/proto
cp -vr ../proto/tensorflow/tensorflow src/main/proto

port_forward_api_server:
POD_NAME=$$(kubectl --namespace default get pod -l app=seldon-apiserver-container-app -o template --template="{{(index .items 0).metadata.name}}") && \
Expand Down
10 changes: 7 additions & 3 deletions api-frontend/Makefile.ci
Original file line number Diff line number Diff line change
Expand Up @@ -38,14 +38,18 @@ clean:
rm -fvr src/main/proto/k8s.io
rm -fv src/main/proto/v1.proto

download_protos:
download_protos_k8s:
cd ../proto/k8s ; make create_protos

update_proto: download_protos
download_protos_tensorflow:
cd ../proto/tensorflow ; make create_protos

update_proto: download_protos_k8s download_protos_tensorflow
cp -v ../proto/seldon_deployment.proto src/main/proto/
cp -v ../proto/prediction.proto src/main/proto/
cp -vr ../proto/k8s/k8s.io src/main/proto
cp -v ../proto/k8s/v1.proto src/main/proto

cp -vr ../proto/tensorflow/tensorflow src/main/proto

update_swagger:
cp -v ../openapi/apife.oas3.json src/main/resources/static/seldon.json
1 change: 1 addition & 0 deletions engine/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ update_proto:
@cp -v ../proto/prediction.proto src/main/proto/
cp -vr ../proto/k8s/k8s.io src/main/proto
cp -v ../proto/k8s/v1.proto src/main/proto
cp -vr ../proto/tensorflow/tensorflow src/main/proto

update_swagger:
cp -v ../openapi/engine.oas3.json src/main/resources/static/seldon.json
10 changes: 7 additions & 3 deletions engine/Makefile.ci
Original file line number Diff line number Diff line change
Expand Up @@ -38,14 +38,18 @@ clean:
rm -fvr src/main/proto/k8s.io
rm -fv src/main/proto/v1.proto

download_protos:
download_protos_k8s:
cd ../proto/k8s ; make create_protos

update_proto: download_protos
download_protos_tensorflow:
cd ../proto/tensorflow ; make create_protos

update_proto: download_protos_k8s download_protos_tensorflow
cp -v ../proto/seldon_deployment.proto src/main/proto/
cp -v ../proto/prediction.proto src/main/proto/
cp -vr ../proto/k8s/k8s.io src/main/proto
cp -v ../proto/k8s/v1.proto src/main/proto

cp -vr ../proto/tensorflow/tensorflow src/main/proto

update_swagger:
cp -v ../openapi/engine.oas3.json src/main/resources/static/seldon.json
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@ public void testModelMetrics() throws Exception
updateMessageBuilderFromJson(PredictorSpecBuilder, jsonStr);
PredictorSpec predictorSpec = PredictorSpecBuilder.build();
final String predictJson = "{" +
"\"request\": {" +
"\"data\": {" +
"\"ndarray\": [[1.0]]}" +
"}";
enginePredictor.setPredictorSpec(predictorSpec);
Expand Down Expand Up @@ -220,7 +220,7 @@ public void testInputTransformInputMetrics() throws Exception
updateMessageBuilderFromJson(PredictorSpecBuilder, jsonStr);
PredictorSpec predictorSpec = PredictorSpecBuilder.build();
final String predictJson = "{" +
"\"request\": {" +
"\"data\": {" +
"\"ndarray\": [[1.0]]}" +
"}";
enginePredictor.setPredictorSpec(predictorSpec);
Expand Down Expand Up @@ -275,7 +275,7 @@ public void testTransformOutputMetrics() throws Exception
updateMessageBuilderFromJson(PredictorSpecBuilder, jsonStr);
PredictorSpec predictorSpec = PredictorSpecBuilder.build();
final String predictJson = "{" +
"\"request\": {" +
"\"data\": {" +
"\"ndarray\": [[1.0]]}" +
"}";
enginePredictor.setPredictorSpec(predictorSpec);
Expand Down Expand Up @@ -331,7 +331,7 @@ public void testRouterMetrics() throws Exception
updateMessageBuilderFromJson(PredictorSpecBuilder, jsonStr);
PredictorSpec predictorSpec = PredictorSpecBuilder.build();
final String predictJson = "{" +
"\"request\": {" +
"\"data\": {" +
"\"ndarray\": [[1.0]]}" +
"}";
enginePredictor.setPredictorSpec(predictorSpec);
Expand Down Expand Up @@ -387,7 +387,7 @@ public void testCombinerMetrics() throws Exception
updateMessageBuilderFromJson(PredictorSpecBuilder, jsonStr);
PredictorSpec predictorSpec = PredictorSpecBuilder.build();
final String predictJson = "{" +
"\"request\": {" +
"\"data\": {" +
"\"ndarray\": [[1.0]]}" +
"}";
enginePredictor.setPredictorSpec(predictorSpec);
Expand Down Expand Up @@ -434,5 +434,205 @@ public void testCombinerMetrics() throws Exception
Assert.assertTrue(response.indexOf("mytimer_seconds_count{deployment_name=\"None\",model_image=\"seldonio/combiner\",model_name=\"combiner\",model_version=\"0.6\",predictor_name=\"fx-market-predictor\",predictor_version=\"unknown\",} 1.0")>-1);

}


@Test
public void testModelStrData() throws Exception
{
String jsonStr = readFile("src/test/resources/model_simple.json",StandardCharsets.UTF_8);
String responseStr = readFile("src/test/resources/response_strdata.json",StandardCharsets.UTF_8);
String responseStr2 = readFile("src/test/resources/response_strdata2.json",StandardCharsets.UTF_8);
PredictorSpec.Builder PredictorSpecBuilder = PredictorSpec.newBuilder();
updateMessageBuilderFromJson(PredictorSpecBuilder, jsonStr);
PredictorSpec predictorSpec = PredictorSpecBuilder.build();
final String predictJson = "{" +
"\"strData\": \"my string data\"" +
"}";
enginePredictor.setPredictorSpec(predictorSpec);

ResponseEntity<String> httpResponse1 = new ResponseEntity<String>(responseStr, null, HttpStatus.OK);
ResponseEntity<String> httpResponse2 = new ResponseEntity<String>(responseStr2, null, HttpStatus.OK);
Mockito.when(restTemplate.postForEntity(Matchers.<URI>any(), Matchers.<HttpEntity<MultiValueMap<String, String>>>any(), Matchers.<Class<String>>any()))
.thenAnswer(new Answer<ResponseEntity<String>>() {
private int count = 0;

public ResponseEntity<String> answer(InvocationOnMock invocation) {
count++;
if (count == 1)
return httpResponse1;

return httpResponse2;
}});
internalPredictionService.setRestTemplate(restTemplate);

MvcResult res = mvc.perform(MockMvcRequestBuilders.post("/api/v0.1/predictions")
.accept(MediaType.APPLICATION_JSON_UTF8)
.content(predictJson)
.contentType(MediaType.APPLICATION_JSON_UTF8)).andReturn();
String response = res.getResponse().getContentAsString();
System.out.println(response);
Assert.assertEquals(200, res.getResponse().getStatus());

SeldonMessage.Builder builder = SeldonMessage.newBuilder();
JsonFormat.parser().ignoringUnknownFields().merge(response, builder);
SeldonMessage seldonMessage = builder.build();

// Check for returned metrics
Assert.assertEquals("COUNTER",seldonMessage.getMeta().getMetrics(0).getType().toString());
Assert.assertEquals(1.0F,seldonMessage.getMeta().getMetrics(0).getValue(),0.0);
Assert.assertEquals("mycounter1",seldonMessage.getMeta().getMetrics(0).getKey());

Assert.assertEquals("GAUGE",seldonMessage.getMeta().getMetrics(1).getType().toString());
Assert.assertEquals(22.0F,seldonMessage.getMeta().getMetrics(1).getValue(),0.0);
Assert.assertEquals("mygauge1",seldonMessage.getMeta().getMetrics(1).getKey());

Assert.assertEquals("TIMER",seldonMessage.getMeta().getMetrics(2).getType().toString());
Assert.assertEquals(1.0F,seldonMessage.getMeta().getMetrics(2).getValue(),0.0);
Assert.assertEquals("mytimer1",seldonMessage.getMeta().getMetrics(2).getKey());

// Check prometheus endpoint for metric
MvcResult res2 = mvc.perform(MockMvcRequestBuilders.get("/prometheus")).andReturn();
Assert.assertEquals(200, res2.getResponse().getStatus());
response = res2.getResponse().getContentAsString();
System.out.println("response is ["+response+"]");
Assert.assertTrue(response.indexOf("mycounter1_total{deployment_name=\"None\",model_image=\"seldonio/mean_classifier\",model_name=\"mean-classifier\",model_version=\"0.6\",mytag1=\"mytagval1\",predictor_name=\"fx-market-predictor\",predictor_version=\"unknown\",} 1.0")>-1);
Assert.assertTrue(response.indexOf("mytimer1_seconds_count{deployment_name=\"None\",model_image=\"seldonio/mean_classifier\",model_name=\"mean-classifier\",model_version=\"0.6\",predictor_name=\"fx-market-predictor\",predictor_version=\"unknown\",} 1.0")>-1);
Assert.assertTrue(response.indexOf("mygauge1{deployment_name=\"None\",model_image=\"seldonio/mean_classifier\",model_name=\"mean-classifier\",model_version=\"0.6\",predictor_name=\"fx-market-predictor\",predictor_version=\"unknown\",} 22.0")>-1);
System.out.println(response);

res = mvc.perform(MockMvcRequestBuilders.post("/api/v0.1/predictions")
.accept(MediaType.APPLICATION_JSON_UTF8)
.content(predictJson)
.contentType(MediaType.APPLICATION_JSON_UTF8)).andReturn();
response = res.getResponse().getContentAsString();
System.out.println(response);
Assert.assertEquals(200, res.getResponse().getStatus());

builder = SeldonMessage.newBuilder();
JsonFormat.parser().ignoringUnknownFields().merge(response, builder);
seldonMessage = builder.build();

// Check for returned metrics
Assert.assertEquals("COUNTER",seldonMessage.getMeta().getMetrics(0).getType().toString());
Assert.assertEquals(1.0F,seldonMessage.getMeta().getMetrics(0).getValue(),0.0);
Assert.assertEquals("mycounter1",seldonMessage.getMeta().getMetrics(0).getKey());

Assert.assertEquals("GAUGE",seldonMessage.getMeta().getMetrics(1).getType().toString());
Assert.assertEquals(100.0F,seldonMessage.getMeta().getMetrics(1).getValue(),0.0);
Assert.assertEquals("mygauge1",seldonMessage.getMeta().getMetrics(1).getKey());

Assert.assertEquals("TIMER",seldonMessage.getMeta().getMetrics(2).getType().toString());
Assert.assertEquals(1.0F,seldonMessage.getMeta().getMetrics(2).getValue(),0.0);
Assert.assertEquals("mytimer1",seldonMessage.getMeta().getMetrics(2).getKey());

// Check prometheus endpoint for metric
res2 = mvc.perform(MockMvcRequestBuilders.get("/prometheus")).andReturn();
Assert.assertEquals(200, res2.getResponse().getStatus());
response = res2.getResponse().getContentAsString();
Assert.assertTrue(response.indexOf("mycounter1_total{deployment_name=\"None\",model_image=\"seldonio/mean_classifier\",model_name=\"mean-classifier\",model_version=\"0.6\",mytag1=\"mytagval1\",predictor_name=\"fx-market-predictor\",predictor_version=\"unknown\",} 2.0")>-1);
Assert.assertTrue(response.indexOf("mytimer1_seconds_count{deployment_name=\"None\",model_image=\"seldonio/mean_classifier\",model_name=\"mean-classifier\",model_version=\"0.6\",predictor_name=\"fx-market-predictor\",predictor_version=\"unknown\",} 2.0")>-1);
Assert.assertTrue(response.indexOf("mygauge1{deployment_name=\"None\",model_image=\"seldonio/mean_classifier\",model_name=\"mean-classifier\",model_version=\"0.6\",predictor_name=\"fx-market-predictor\",predictor_version=\"unknown\",} 100.0")>-1);
System.out.println(response);
}


@Test
public void testModelBinData() throws Exception
{
String jsonStr = readFile("src/test/resources/model_simple.json",StandardCharsets.UTF_8);
String responseStr = readFile("src/test/resources/response_bindata.json",StandardCharsets.UTF_8);
String responseStr2 = readFile("src/test/resources/response_bindata2.json",StandardCharsets.UTF_8);
PredictorSpec.Builder PredictorSpecBuilder = PredictorSpec.newBuilder();
updateMessageBuilderFromJson(PredictorSpecBuilder, jsonStr);
PredictorSpec predictorSpec = PredictorSpecBuilder.build();
final String predictJson = "{" +
"\"binData\": \"MTIz\"" +
"}";
enginePredictor.setPredictorSpec(predictorSpec);

ResponseEntity<String> httpResponse1 = new ResponseEntity<String>(responseStr, null, HttpStatus.OK);
ResponseEntity<String> httpResponse2 = new ResponseEntity<String>(responseStr2, null, HttpStatus.OK);
Mockito.when(restTemplate.postForEntity(Matchers.<URI>any(), Matchers.<HttpEntity<MultiValueMap<String, String>>>any(), Matchers.<Class<String>>any()))
.thenAnswer(new Answer<ResponseEntity<String>>() {
private int count = 0;

public ResponseEntity<String> answer(InvocationOnMock invocation) {
count++;
if (count == 1)
return httpResponse1;

return httpResponse2;
}});
internalPredictionService.setRestTemplate(restTemplate);

MvcResult res = mvc.perform(MockMvcRequestBuilders.post("/api/v0.1/predictions")
.accept(MediaType.APPLICATION_JSON_UTF8)
.content(predictJson)
.contentType(MediaType.APPLICATION_JSON_UTF8)).andReturn();
String response = res.getResponse().getContentAsString();
System.out.println(response);
Assert.assertEquals(200, res.getResponse().getStatus());

SeldonMessage.Builder builder = SeldonMessage.newBuilder();
JsonFormat.parser().ignoringUnknownFields().merge(response, builder);
SeldonMessage seldonMessage = builder.build();

// Check for returned metrics
Assert.assertEquals("COUNTER",seldonMessage.getMeta().getMetrics(0).getType().toString());
Assert.assertEquals(1.0F,seldonMessage.getMeta().getMetrics(0).getValue(),0.0);
Assert.assertEquals("mycounter2",seldonMessage.getMeta().getMetrics(0).getKey());

Assert.assertEquals("GAUGE",seldonMessage.getMeta().getMetrics(1).getType().toString());
Assert.assertEquals(22.0F,seldonMessage.getMeta().getMetrics(1).getValue(),0.0);
Assert.assertEquals("mygauge2",seldonMessage.getMeta().getMetrics(1).getKey());

Assert.assertEquals("TIMER",seldonMessage.getMeta().getMetrics(2).getType().toString());
Assert.assertEquals(1.0F,seldonMessage.getMeta().getMetrics(2).getValue(),0.0);
Assert.assertEquals("mytimer2",seldonMessage.getMeta().getMetrics(2).getKey());

// Check prometheus endpoint for metric
MvcResult res2 = mvc.perform(MockMvcRequestBuilders.get("/prometheus")).andReturn();
Assert.assertEquals(200, res2.getResponse().getStatus());
response = res2.getResponse().getContentAsString();
System.out.println("response is ["+response+"]");
Assert.assertTrue(response.indexOf("mycounter2_total{deployment_name=\"None\",model_image=\"seldonio/mean_classifier\",model_name=\"mean-classifier\",model_version=\"0.6\",mytag1=\"mytagval1\",predictor_name=\"fx-market-predictor\",predictor_version=\"unknown\",} 1.0")>-1);
Assert.assertTrue(response.indexOf("mytimer2_seconds_count{deployment_name=\"None\",model_image=\"seldonio/mean_classifier\",model_name=\"mean-classifier\",model_version=\"0.6\",predictor_name=\"fx-market-predictor\",predictor_version=\"unknown\",} 1.0")>-1);
Assert.assertTrue(response.indexOf("mygauge2{deployment_name=\"None\",model_image=\"seldonio/mean_classifier\",model_name=\"mean-classifier\",model_version=\"0.6\",predictor_name=\"fx-market-predictor\",predictor_version=\"unknown\",} 22.0")>-1);
System.out.println(response);

res = mvc.perform(MockMvcRequestBuilders.post("/api/v0.1/predictions")
.accept(MediaType.APPLICATION_JSON_UTF8)
.content(predictJson)
.contentType(MediaType.APPLICATION_JSON_UTF8)).andReturn();
response = res.getResponse().getContentAsString();
System.out.println(response);
Assert.assertEquals(200, res.getResponse().getStatus());

builder = SeldonMessage.newBuilder();
JsonFormat.parser().ignoringUnknownFields().merge(response, builder);
seldonMessage = builder.build();

// Check for returned metrics
Assert.assertEquals("COUNTER",seldonMessage.getMeta().getMetrics(0).getType().toString());
Assert.assertEquals(1.0F,seldonMessage.getMeta().getMetrics(0).getValue(),0.0);
Assert.assertEquals("mycounter2",seldonMessage.getMeta().getMetrics(0).getKey());

Assert.assertEquals("GAUGE",seldonMessage.getMeta().getMetrics(1).getType().toString());
Assert.assertEquals(100.0F,seldonMessage.getMeta().getMetrics(1).getValue(),0.0);
Assert.assertEquals("mygauge2",seldonMessage.getMeta().getMetrics(1).getKey());

Assert.assertEquals("TIMER",seldonMessage.getMeta().getMetrics(2).getType().toString());
Assert.assertEquals(1.0F,seldonMessage.getMeta().getMetrics(2).getValue(),0.0);
Assert.assertEquals("mytimer2",seldonMessage.getMeta().getMetrics(2).getKey());

// Check prometheus endpoint for metric
res2 = mvc.perform(MockMvcRequestBuilders.get("/prometheus")).andReturn();
Assert.assertEquals(200, res2.getResponse().getStatus());
response = res2.getResponse().getContentAsString();
Assert.assertTrue(response.indexOf("mycounter2_total{deployment_name=\"None\",model_image=\"seldonio/mean_classifier\",model_name=\"mean-classifier\",model_version=\"0.6\",mytag1=\"mytagval1\",predictor_name=\"fx-market-predictor\",predictor_version=\"unknown\",} 2.0")>-1);
Assert.assertTrue(response.indexOf("mytimer2_seconds_count{deployment_name=\"None\",model_image=\"seldonio/mean_classifier\",model_name=\"mean-classifier\",model_version=\"0.6\",predictor_name=\"fx-market-predictor\",predictor_version=\"unknown\",} 2.0")>-1);
Assert.assertTrue(response.indexOf("mygauge2{deployment_name=\"None\",model_image=\"seldonio/mean_classifier\",model_name=\"mean-classifier\",model_version=\"0.6\",predictor_name=\"fx-market-predictor\",predictor_version=\"unknown\",} 100.0")>-1);
System.out.println(response);
}

}
23 changes: 23 additions & 0 deletions engine/src/test/resources/response_bindata.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
{
"meta": {
"metrics": [
{
"type": "COUNTER",
"key": "mycounter2",
"value": 1.0,
"tags": {"mytag1":"mytagval1"}
},
{
"type": "GAUGE",
"key": "mygauge2",
"value": 22.0
},
{
"type": "TIMER",
"key": "mytimer2",
"value": 1.0
}
]
},
"binData": "MTIz"
}
23 changes: 23 additions & 0 deletions engine/src/test/resources/response_bindata2.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
{
"meta": {
"metrics": [
{
"type": "COUNTER",
"key": "mycounter2",
"value": 1.0,
"tags": {"mytag1":"mytagval1"}
},
{
"type": "GAUGE",
"key": "mygauge2",
"value": 100.0
},
{
"type": "TIMER",
"key": "mytimer2",
"value": 1.0
}
]
},
"binData": "MTIz"
}
23 changes: 23 additions & 0 deletions engine/src/test/resources/response_strdata.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
{
"meta": {
"metrics": [
{
"type": "COUNTER",
"key": "mycounter1",
"value": 1.0,
"tags": {"mytag1":"mytagval1"}
},
{
"type": "GAUGE",
"key": "mygauge1",
"value": 22.0
},
{
"type": "TIMER",
"key": "mytimer1",
"value": 1.0
}
]
},
"strData": "some reply"
}
Loading

0 comments on commit 0c4b6ac

Please sign in to comment.