Skip to content

Commit

Permalink
feat: support trigger multi model instances
Browse files Browse the repository at this point in the history
  • Loading branch information
pinglin committed Jun 24, 2022
1 parent b433398 commit e3d4263
Show file tree
Hide file tree
Showing 8 changed files with 297 additions and 76 deletions.
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ require (
github.com/grpc-ecosystem/go-grpc-middleware v1.3.0
github.com/grpc-ecosystem/grpc-gateway/v2 v2.10.3
github.com/iancoleman/strcase v0.2.0
github.com/instill-ai/protogen-go v0.1.5-alpha.0.20220620010454-ca08bcdfc4dd
github.com/instill-ai/protogen-go v0.2.0-alpha.0.20220624160723-e497dd0238c5
github.com/instill-ai/usage-client v0.0.0-20220607201439-d646c37f5b02
github.com/instill-ai/x v0.1.0-alpha.0.20220604235252-39fcffc82edb
github.com/knadh/koanf v1.4.1
Expand Down
4 changes: 2 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -694,8 +694,8 @@ github.com/imdario/mergo v0.3.10/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH
github.com/imdario/mergo v0.3.11/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA=
github.com/imdario/mergo v0.3.12/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA=
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
github.com/instill-ai/protogen-go v0.1.5-alpha.0.20220620010454-ca08bcdfc4dd h1:m6XdTfydrZwaQHqLIDMn0/hGp2C6e8HxRoO6YclrL+U=
github.com/instill-ai/protogen-go v0.1.5-alpha.0.20220620010454-ca08bcdfc4dd/go.mod h1:d9ebEdwMX2Las4OScym45qbQM+xcBQITqvq/8anTVas=
github.com/instill-ai/protogen-go v0.2.0-alpha.0.20220624160723-e497dd0238c5 h1:te67yngw0YVOt1glwJhDDijbnUoePe8I+3qSGjZVLcc=
github.com/instill-ai/protogen-go v0.2.0-alpha.0.20220624160723-e497dd0238c5/go.mod h1:d9ebEdwMX2Las4OScym45qbQM+xcBQITqvq/8anTVas=
github.com/instill-ai/usage-client v0.0.0-20220607201439-d646c37f5b02 h1:7dhRYHERy+NbvESpaQ0NPOo3CiiDpvLsARR90Ftkiqw=
github.com/instill-ai/usage-client v0.0.0-20220607201439-d646c37f5b02/go.mod h1:saH0H46iHHMxBx+znN3CoE4IOylbTlpQUPj0Do06yKo=
github.com/instill-ai/x v0.1.0-alpha.0.20220604235252-39fcffc82edb h1:70AJVfr463jWkgPQ1w281zsQ1LK/tOW5INTNc+yOBsI=
Expand Down
17 changes: 15 additions & 2 deletions integration-test/const.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,23 @@ export const model_def_name = "model-definitions/local"
export const model_id = "dummy-det"
export const model_instance_id = "latest"

export const detSyncRecipe = {
export const detSyncSingleModelInstRecipe = {
recipe: {
source: "source-connectors/source-http",
model_instances: [`models/${model_id}/instances/${model_instance_id}`],
model_instances: [
`models/${model_id}/instances/${model_instance_id}`,
],
destination: "destination-connectors/destination-http"
},
};

export const detSyncMultiModelInstRecipe = {
recipe: {
source: "source-connectors/source-http",
model_instances: [
`models/${model_id}/instances/${model_instance_id}`,
`models/${model_id}/instances/${model_instance_id}`,
],
destination: "destination-connectors/destination-http"
},
};
Expand Down
14 changes: 7 additions & 7 deletions integration-test/rest-pipeline.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ export function CheckCreate() {
id: randomString(63),
description: randomString(50),
},
constant.detSyncRecipe
constant.detSyncSingleModelInstRecipe
)

// Create a pipeline
Expand Down Expand Up @@ -152,7 +152,7 @@ export function CheckList() {
description: randomString(50),
state: "STATE_ACTIVE",
},
constant.detSyncRecipe
constant.detSyncSingleModelInstRecipe
)
}

Expand Down Expand Up @@ -280,7 +280,7 @@ export function CheckGet() {
id: randomString(10),
description: randomString(50),
},
constant.detSyncRecipe
constant.detSyncSingleModelInstRecipe
)

// Create a pipeline
Expand Down Expand Up @@ -333,7 +333,7 @@ export function CheckUpdate() {
{
id: randomString(10),
},
constant.detSyncRecipe
constant.detSyncSingleModelInstRecipe
)

// Create a pipeline
Expand Down Expand Up @@ -442,7 +442,7 @@ export function CheckUpdateState() {
{
id: randomString(10),
},
constant.detSyncRecipe
constant.detSyncSingleModelInstRecipe
)

check(http.request("POST", `${pipelineHost}/v1alpha/pipelines`, JSON.stringify(reqBodySync), {
Expand Down Expand Up @@ -528,7 +528,7 @@ export function CheckRename() {
{
id: randomString(10),
},
constant.detSyncRecipe
constant.detSyncSingleModelInstRecipe
)

// Create a pipeline
Expand Down Expand Up @@ -575,7 +575,7 @@ export function CheckLookUp() {
{
id: randomString(10),
},
constant.detSyncRecipe
constant.detSyncSingleModelInstRecipe
)

// Create a pipeline
Expand Down
212 changes: 197 additions & 15 deletions integration-test/rest-trigger.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,207 @@ import { randomString } from "https://jslib.k6.io/k6-utils/1.1.0/index.js";

import * as constant from "./const.js"

export function CheckTriggerImageDirect() {
export function CheckTriggerDirectSingleImageSingleModelInst() {

var reqBody = Object.assign(
{
id: randomString(10),
description: randomString(50),
state: "STATE_ACTIVE",
},
constant.detSyncRecipe
constant.detSyncSingleModelInstRecipe
);

group("Pipelines API: Trigger a pipeline for single image and single model instance", () => {

check(http.request("POST", `${pipelineHost}/v1alpha/pipelines`, JSON.stringify(reqBody), {
headers: {
"Content-Type": "application/json",
},
}), {
"POST /v1alpha/pipelines response status is 201": (r) => r.status === 201,
});

var payloadImageURL = {
inputs: [
{
image_url: "https://artifacts.instill.tech/dog.jpg",
}
]
};

check(http.request("POST", `${pipelineHost}/v1alpha/pipelines/${reqBody.id}:trigger`, JSON.stringify(payloadImageURL), {
headers: {
"Content-Type": "application/json",
},
}), {
[`POST /v1alpha/pipelines/${reqBody.id}/outputs (url) response status is 200`]: (r) => r.status === 200,
[`POST /v1alpha/pipelines/${reqBody.id}/outputs (url) response output[0].detection_outputs.length`]: (r) => r.json().output[0].detection_outputs.length === payloadImageURL.inputs.length,
[`POST /v1alpha/pipelines/${reqBody.id}/outputs (url) response output[0].detection_outputs[0].bounding_box_objects.length`]: (r) => r.json().output[0].detection_outputs[0].bounding_box_objects.length === 1,
[`POST /v1alpha/pipelines/${reqBody.id}/outputs (url) response output[0].detection_outputs[0].bounding_box_objects[0].category`]: (r) => r.json().output[0].detection_outputs[0].bounding_box_objects[0].category === "test",
[`POST /v1alpha/pipelines/${reqBody.id}/outputs (url) response output[0].detection_outputs[0].bounding_box_objects[0].score`]: (r) => r.json().output[0].detection_outputs[0].bounding_box_objects[0].score === 1,
[`POST /v1alpha/pipelines/${reqBody.id}/outputs (url) response output[0].detection_outputs[0].bounding_box_objects[0].bounding_box`]: (r) => r.json().output[0].detection_outputs[0].bounding_box_objects[0].bounding_box !== undefined,
});

var payloadImageBase64 = {
inputs: [
{
imageBase64: encoding.b64encode(constant.dogImg, "b"),
}
]
};

check(http.request("POST", `${pipelineHost}/v1alpha/pipelines/${reqBody.id}:trigger`, JSON.stringify(payloadImageBase64), {
headers: {
"Content-Type": "application/json",
},
}), {
[`POST /v1alpha/pipelines/${reqBody.id}/outputs (base64) response status is 200`]: (r) => r.status === 200,
[`POST /v1alpha/pipelines/${reqBody.id}/outputs (base64) response output[0].detection_outputs.length`]: (r) => r.json().output[0].detection_outputs.length === payloadImageBase64.inputs.length,
[`POST /v1alpha/pipelines/${reqBody.id}/outputs (base64) response output[0].detection_outputs[0].bounding_box_objects.length`]: (r) => r.json().output[0].detection_outputs[0].bounding_box_objects.length === 1,
[`POST /v1alpha/pipelines/${reqBody.id}/outputs (base64) response output[0].detection_outputs[0].bounding_box_objects[0].category`]: (r) => r.json().output[0].detection_outputs[0].bounding_box_objects[0].category === "test",
[`POST /v1alpha/pipelines/${reqBody.id}/outputs (base64) response output[0].detection_outputs[0].bounding_box_objects[0].score`]: (r) => r.json().output[0].detection_outputs[0].bounding_box_objects[0].score === 1,
[`POST /v1alpha/pipelines/${reqBody.id}/outputs (base64) response output[0].detection_outputs[0].bounding_box_objects[0].bounding_box`]: (r) => r.json().output[0].detection_outputs[0].bounding_box_objects[0].bounding_box !== undefined,
});

const fd = new FormData();
fd.append("file", http.file(constant.dogImg));
fd.append("file", http.file(constant.dogImg));
fd.append("file", http.file(constant.dogImg));
check(http.request("POST", `${pipelineHost}/v1alpha/pipelines/${reqBody.id}:trigger-multipart`, fd.body(), {
headers: {
"Content-Type": `multipart/form-data; boundary=${fd.boundary}`,
},
}), {
[`POST /v1alpha/pipelines/${reqBody.id}/outputs (multipart) response status is 200`]: (r) => r.status === 200,
[`POST /v1alpha/pipelines/${reqBody.id}/outputs (multipart) response output[0].detection_outputs.length`]: (r) => r.json().output[0].detection_outputs.length === fd.parts.length,
[`POST /v1alpha/pipelines/${reqBody.id}/outputs (multipart) response output[0].detection_outputs[0].bounding_box_objects.length`]: (r) => r.json().output[0].detection_outputs[0].bounding_box_objects.length === 1,
[`POST /v1alpha/pipelines/${reqBody.id}/outputs (multipart) response output[0].detection_outputs[0].bounding_box_objects[0].score`]: (r) => r.json().output[0].detection_outputs[0].bounding_box_objects[0].score === 1,
});

});

// Delete the pipeline
check(http.request("DELETE", `${pipelineHost}/v1alpha/pipelines/${reqBody.id}`, null, {
headers: {
"Content-Type": "application/json",
},
}), {
[`DELETE /v1alpha/pipelines/${reqBody.id} response status 204`]: (r) => r.status === 204,
});
}

export function CheckTriggerDirectMultiImageSingleModelInst() {

var reqBody = Object.assign(
{
id: randomString(10),
description: randomString(50),
state: "STATE_ACTIVE",
},
constant.detSyncSingleModelInstRecipe
);

group("Pipelines API: Trigger a pipeline for multiple images and single model instance", () => {

check(http.request("POST", `${pipelineHost}/v1alpha/pipelines`, JSON.stringify(reqBody), {
headers: {
"Content-Type": "application/json",
},
}), {
"POST /v1alpha/pipelines response status is 201": (r) => r.status === 201,
});

var payloadImageURL = {
inputs: [
{
image_url: "https://artifacts.instill.tech/dog.jpg",
},
{
image_url: "https://artifacts.instill.tech/dog.jpg",
},
{
image_url: "https://artifacts.instill.tech/dog.jpg",
},
{
image_url: "https://artifacts.instill.tech/dog.jpg",
},
],
};

check(http.request("POST", `${pipelineHost}/v1alpha/pipelines/${reqBody.id}:trigger`, JSON.stringify(payloadImageURL), {
headers: {
"Content-Type": "application/json",
},
}), {
[`POST /v1alpha/pipelines/${reqBody.id}/outputs (url) response status is 200`]: (r) => r.status === 200,
[`POST /v1alpha/pipelines/${reqBody.id}/outputs (url) response output[0].detection_outputs.length`]: (r) => r.json().output[0].detection_outputs.length === payloadImageURL.inputs.length,
[`POST /v1alpha/pipelines/${reqBody.id}/outputs (url) response output[0].detection_outputs[0].bounding_box_objects.length`]: (r) => r.json().output[0].detection_outputs[0].bounding_box_objects.length === 1,
[`POST /v1alpha/pipelines/${reqBody.id}/outputs (url) response output[0].detection_outputs[0].bounding_box_objects[0].category`]: (r) => r.json().output[0].detection_outputs[0].bounding_box_objects[0].category === "test",
[`POST /v1alpha/pipelines/${reqBody.id}/outputs (url) response output[0].detection_outputs[0].bounding_box_objects[0].score`]: (r) => r.json().output[0].detection_outputs[0].bounding_box_objects[0].score === 1,
[`POST /v1alpha/pipelines/${reqBody.id}/outputs (url) response output[0].detection_outputs[0].bounding_box_objects[0].bounding_box`]: (r) => r.json().output[0].detection_outputs[0].bounding_box_objects[0].bounding_box !== undefined,
});

var payloadImageBase64 = {
inputs: [
{
imageBase64: encoding.b64encode(constant.dogImg, "b"),
},
{
imageBase64: encoding.b64encode(constant.dogImg, "b"),
},
],
};

check(http.request("POST", `${pipelineHost}/v1alpha/pipelines/${reqBody.id}:trigger`, JSON.stringify(payloadImageBase64), {
headers: {
"Content-Type": "application/json",
},
}), {
[`POST /v1alpha/pipelines/${reqBody.id}/outputs (base64) response status is 200`]: (r) => r.status === 200,
[`POST /v1alpha/pipelines/${reqBody.id}/outputs (base64) response output[0].detection_outputs.length`]: (r) => r.json().output[0].detection_outputs.length === payloadImageBase64.inputs.length,
[`POST /v1alpha/pipelines/${reqBody.id}/outputs (base64) response output[0].detection_outputs[0].bounding_box_objects.length`]: (r) => r.json().output[0].detection_outputs[0].bounding_box_objects.length === 1,
[`POST /v1alpha/pipelines/${reqBody.id}/outputs (base64) response output[0].detection_outputs[0].bounding_box_objects[0].category`]: (r) => r.json().output[0].detection_outputs[0].bounding_box_objects[0].category === "test",
[`POST /v1alpha/pipelines/${reqBody.id}/outputs (base64) response output[0].detection_outputs[0].bounding_box_objects[0].score`]: (r) => r.json().output[0].detection_outputs[0].bounding_box_objects[0].score === 1,
[`POST /v1alpha/pipelines/${reqBody.id}/outputs (base64) response output[0].detection_outputs[0].bounding_box_objects[0].bounding_box`]: (r) => r.json().output[0].detection_outputs[0].bounding_box_objects[0].bounding_box !== undefined,
});

const fd = new FormData();
fd.append("file", http.file(constant.dogImg));
fd.append("file", http.file(constant.dogImg));
fd.append("file", http.file(constant.dogImg));
check(http.request("POST", `${pipelineHost}/v1alpha/pipelines/${reqBody.id}:trigger-multipart`, fd.body(), {
headers: {
"Content-Type": `multipart/form-data; boundary=${fd.boundary}`,
},
}), {
[`POST /v1alpha/pipelines/${reqBody.id}/outputs (multipart) response status is 200`]: (r) => r.status === 200,
[`POST /v1alpha/pipelines/${reqBody.id}/outputs (multipart) response output[0].detection_outputs.length`]: (r) => r.json().output[0].detection_outputs.length === fd.parts.length,
[`POST /v1alpha/pipelines/${reqBody.id}/outputs (multipart) response output[0].detection_outputs[0].bounding_box_objects.length`]: (r) => r.json().output[0].detection_outputs[0].bounding_box_objects.length === 1,
[`POST /v1alpha/pipelines/${reqBody.id}/outputs (multipart) response output[0].detection_outputs[0].bounding_box_objects[0].score`]: (r) => r.json().output[0].detection_outputs[0].bounding_box_objects[0].score === 1,
});

});

// Delete the pipeline
check(http.request("DELETE", `${pipelineHost}/v1alpha/pipelines/${reqBody.id}`, null, {
headers: {
"Content-Type": "application/json",
},
}), {
[`DELETE /v1alpha/pipelines/${reqBody.id} response status 204`]: (r) => r.status === 204,
});
}

export function CheckTriggerDirectMultiImageMultiModelInst() {

var reqBody = Object.assign(
{
id: randomString(10),
description: randomString(50),
state: "STATE_ACTIVE",
},
constant.detSyncMultiModelInstRecipe
);

group("Pipelines API: Trigger a pipeline", () => {
Expand Down Expand Up @@ -51,11 +243,7 @@ export function CheckTriggerImageDirect() {
},
}), {
[`POST /v1alpha/pipelines/${reqBody.id}/outputs (url) response status is 200`]: (r) => r.status === 200,
[`POST /v1alpha/pipelines/${reqBody.id}/outputs (url) response output.detection_outputs.length`]: (r) => r.json().output.detection_outputs.length === payloadImageURL.inputs.length,
[`POST /v1alpha/pipelines/${reqBody.id}/outputs (url) response output.detection_outputs[0].bounding_box_objects.length`]: (r) => r.json().output.detection_outputs[0].bounding_box_objects.length === 1,
[`POST /v1alpha/pipelines/${reqBody.id}/outputs (url) response output.detection_outputs[0].bounding_box_objects[0].category`]: (r) => r.json().output.detection_outputs[0].bounding_box_objects[0].category === "test",
[`POST /v1alpha/pipelines/${reqBody.id}/outputs (url) response output.detection_outputs[0].bounding_box_objects[0].score`]: (r) => r.json().output.detection_outputs[0].bounding_box_objects[0].score === 1,
[`POST /v1alpha/pipelines/${reqBody.id}/outputs (url) response output.detection_outputs[0].bounding_box_objects[0].bounding_box`]: (r) => r.json().output.detection_outputs[0].bounding_box_objects[0].bounding_box !== undefined,
[`POST /v1alpha/pipelines/${reqBody.id}/outputs (url) response output.length == 2`]: (r) => r.json().output.length === 2,
});

var payloadImageBase64 = {
Expand All @@ -75,11 +263,7 @@ export function CheckTriggerImageDirect() {
},
}), {
[`POST /v1alpha/pipelines/${reqBody.id}/outputs (base64) response status is 200`]: (r) => r.status === 200,
[`POST /v1alpha/pipelines/${reqBody.id}/outputs (base64) response output.detection_outputs.length`]: (r) => r.json().output.detection_outputs.length === payloadImageBase64.inputs.length,
[`POST /v1alpha/pipelines/${reqBody.id}/outputs (base64) response output.detection_outputs[0].bounding_box_objects.length`]: (r) => r.json().output.detection_outputs[0].bounding_box_objects.length === 1,
[`POST /v1alpha/pipelines/${reqBody.id}/outputs (base64) response output.detection_outputs[0].bounding_box_objects[0].category`]: (r) => r.json().output.detection_outputs[0].bounding_box_objects[0].category === "test",
[`POST /v1alpha/pipelines/${reqBody.id}/outputs (base64) response output.detection_outputs[0].bounding_box_objects[0].score`]: (r) => r.json().output.detection_outputs[0].bounding_box_objects[0].score === 1,
[`POST /v1alpha/pipelines/${reqBody.id}/outputs (base64) response output.detection_outputs[0].bounding_box_objects[0].bounding_box`]: (r) => r.json().output.detection_outputs[0].bounding_box_objects[0].bounding_box !== undefined,
[`POST /v1alpha/pipelines/${reqBody.id}/outputs (base64) response output.length == 2`]: (r) => r.json().output.length === 2,
});

const fd = new FormData();
Expand All @@ -92,9 +276,7 @@ export function CheckTriggerImageDirect() {
},
}), {
[`POST /v1alpha/pipelines/${reqBody.id}/outputs (multipart) response status is 200`]: (r) => r.status === 200,
[`POST /v1alpha/pipelines/${reqBody.id}/outputs (multipart) response output.detection_outputs.length`]: (r) => r.json().output.detection_outputs.length === fd.parts.length,
[`POST /v1alpha/pipelines/${reqBody.id}/outputs (multipart) response output.detection_outputs[0].bounding_box_objects.length`]: (r) => r.json().output.detection_outputs[0].bounding_box_objects.length === 1,
[`POST /v1alpha/pipelines/${reqBody.id}/outputs (multipart) response output.detection_outputs[0].bounding_box_objects[0].score`]: (r) => r.json().output.detection_outputs[0].bounding_box_objects[0].score === 1,
[`POST /v1alpha/pipelines/${reqBody.id}/outputs (multipart) response output.length == 2`]: (r) => r.json().output.length === 2,
});

});
Expand Down
6 changes: 3 additions & 3 deletions integration-test/rest.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,8 @@ import http from "k6/http";
import { sleep, check, group, fail } from "k6";
import { FormData } from "https://jslib.k6.io/formdata/0.0.2/index.js";
import { randomString } from "https://jslib.k6.io/k6-utils/1.1.0/index.js";
import { URL } from "https://jslib.k6.io/url/1.0.0/index.js";

import * as constant from "./const.js";
import * as helper from "./helper.js";
import * as pipeline from './rest-pipeline.js';
import * as trigger from './rest-trigger.js';

Expand Down Expand Up @@ -135,7 +133,9 @@ export default function (data) {
pipeline.CheckRename()
pipeline.CheckLookUp()

trigger.CheckTriggerImageDirect()
trigger.CheckTriggerDirectSingleImageSingleModelInst()
trigger.CheckTriggerDirectMultiImageSingleModelInst()
trigger.CheckTriggerDirectMultiImageMultiModelInst()
}

export function teardown(data) {
Expand Down
Loading

0 comments on commit e3d4263

Please sign in to comment.