Skip to content

Commit

Permalink
Add Standard Ensembler with Route Name Path to SDK (#248)
Browse files Browse the repository at this point in the history
* Add route_name_path field to EnsemblerStandardConfig

* Add SDK e2e test for standard ensemblers

* Remove paths-ignore value for sdk files

* Refactor EnsemblerStandardConfig class and tests

* Make route_name_path and experiment_mappings nullable

* Add conditional parsing of experiment mappings

* Remove hanging comment

* Rename e2e tests with standard ensembler
  • Loading branch information
deadlycoconuts committed Sep 27, 2022
1 parent 296251d commit ba721c3
Show file tree
Hide file tree
Showing 13 changed files with 308 additions and 40 deletions.
1 change: 0 additions & 1 deletion .github/workflows/turing.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@ on:
- "docs/**"
- "engines/pyfunc-ensembler-job/**"
- "engines/pyfunc-ensembler-service/**"
- "sdk/**"
- ".github/workflows/pyfunc-ensembler-job.yaml"
- ".github/workflows/pyfunc-ensembler-service.yaml"
- ".github/workflows/sdk.yaml"
Expand Down
2 changes: 2 additions & 0 deletions api/api/openapi.bundle.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2350,8 +2350,10 @@ components:
experiment_mappings:
items:
$ref: '#/components/schemas/EnsemblerStandardConfig_experiment_mappings'
nullable: true
type: array
route_name_path:
nullable: true
type: string
type: object
EnsemblerDockerConfig:
Expand Down
2 changes: 2 additions & 0 deletions api/api/specs/routers.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -797,6 +797,7 @@ components:
properties:
experiment_mappings:
type: "array"
nullable: true
items:
type: "object"
required:
Expand All @@ -818,6 +819,7 @@ components:
example: "route-1"
route_name_path:
type: "string"
nullable: true

EnsemblerDockerConfig:
description: "ensembler config when ensembler type is docker"
Expand Down
4 changes: 2 additions & 2 deletions api/e2e/test/00_all_e2e_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -79,9 +79,9 @@ func TestEndToEnd(t *testing.T) {
t.Parallel()
t.Run("DeployRouter", TestDeployRouterWithTrafficRules)
})
t.Run("TestStandardEnsemblerWithRouteNamePath", func(t *testing.T) {
t.Run("TestStandardEnsembler", func(t *testing.T) {
t.Parallel()
t.Run("DeployRouter", TestDeployRouterWithRouteNamePathInStandardEnsembler)
t.Run("DeployRouter", TestDeployRouterWithStandardEnsembler)
})
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,11 @@ d. Test GET router > config section shows version 1, status "deployed"
e. Test cluster that deployments exist
f. Make a request to the router, validate the response.
*/
func TestDeployRouterWithRouteNamePathInStandardEnsembler(t *testing.T) {
func TestDeployRouterWithStandardEnsembler(t *testing.T) {
// Create router
t.Log("Creating router")
data := makeRouterPayload(
filepath.Join("testdata", "create_router_std_ensembler_route_name_path.json.tmpl"),
filepath.Join("testdata", "create_router_with_std_ensembler.json.tmpl"),
globalTestContext)

withDeployedRouter(t, data,
Expand Down
120 changes: 120 additions & 0 deletions sdk/e2e/09_deploy_router_with_std_ensembler_test.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
import os
import logging

import requests
import turing
import turing.batch
import turing.batch.config
import turing.router.config.router_config

from turing.router.config.route import Route
from turing.router.config.experiment_config import ExperimentConfig
from turing.router.config.resource_request import ResourceRequest
from turing.router.config.log_config import LogConfig, ResultLoggerType
from turing.router.config.router_ensembler_config import StandardRouterEnsemblerConfig
from turing.router.config.router_config import RouterConfig
from turing.router.config.router_version import RouterStatus


def test_deploy_router_with_std_ensembler():
# set up route
routes = [
Route(
id="control",
endpoint=f'{os.getenv("MOCKSERVER_ENDPOINT")}/control',
timeout="5s",
),
Route(
id="treatment-a",
endpoint=f'{os.getenv("MOCKSERVER_ENDPOINT")}/treatment-a',
timeout="5s",
),
]

# set up experiment config
experiment_config = ExperimentConfig(
type="proprietary",
config={
"client": {"id": "1", "username": "test", "passkey": "test"},
"experiments": [{"id": "001", "name": "exp_1"}],
"variables": {
"experiment_variables": {
"001": [{"name": "client_id", "type": "unit", "required": True}]
},
"config": [
{
"name": "client_id",
"required": True,
"field": "client.id",
"field_source": "payload",
}
],
},
},
)

# set up resource request config for the router
resource_request = ResourceRequest(
min_replica=1, max_replica=1, cpu_request="200m", memory_request="250Mi"
)

# set up log config for the router
log_config = LogConfig(result_logger_type=ResultLoggerType.NOP)

# set up standard ensembler
ensembler = StandardRouterEnsemblerConfig(
route_name_path="route_name", fallback_response_route_id="control"
)

# create the RouterConfig instance
router_config = RouterConfig(
environment_name=os.getenv("MODEL_CLUSTER_NAME"),
name=f'e2e-sdk-std-ensembler-test-{os.getenv("TEST_ID")}',
routes=routes,
rules=[],
experiment_engine=experiment_config,
resource_request=resource_request,
timeout="5s",
log_config=log_config,
ensembler=ensembler,
)

# create a router using the RouterConfig object
router = turing.Router.create(router_config)
assert router.status == RouterStatus.PENDING

# wait for the router to get deployed
try:
router.wait_for_status(RouterStatus.DEPLOYED)
except TimeoutError:
raise Exception(
f"Turing API is taking too long for router {router.id} to get deployed."
)
assert router.status == RouterStatus.DEPLOYED

# get router with id 1
retrieved_router = turing.Router.get(router.id)
assert retrieved_router.version == 1
assert retrieved_router.status == RouterStatus.DEPLOYED
assert (
retrieved_router.endpoint
== f'http://{retrieved_router.name}-turing-router.{os.getenv("PROJECT_NAME")}.{os.getenv("KSERVICE_DOMAIN")}/v1/predict'
)

# get router version with id 1
router_version_1 = retrieved_router.get_version(1)
assert router_version_1.status == RouterStatus.DEPLOYED

# post single request to turing router
logging.info("Testing router endpoint...")
response = requests.post(
url=router.endpoint,
headers={
"Content-Type": "application/json",
"X-Mirror-Body": "true",
},
json={"client": {"id": 4}},
)
assert response.status_code == 200
expected_response = {"version": "treatment-a"}
assert response.json() == expected_response
1 change: 1 addition & 0 deletions sdk/e2e/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
"test_deploy_router_valid_config",
"test_delete_router",
"test_deploy_router_with_traffic_rules",
"test_deploy_router_with_std_ensembler",
]


Expand Down
39 changes: 33 additions & 6 deletions sdk/tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ def nop_router_ensembler_config():


@pytest.fixture
def standard_router_ensembler_config():
def standard_router_ensembler_config_with_experiment_mappings():
return EnsemblerStandardConfig(
experiment_mappings=[
turing.generated.models.EnsemblerStandardConfigExperimentMappings(
Expand All @@ -108,6 +108,16 @@ def standard_router_ensembler_config():
experiment="experiment-2", treatment="treatment-2", route="route-2"
),
],
route_name_path=None,
fallback_response_route_id="route-1",
)


@pytest.fixture
def standard_router_ensembler_config_with_route_name_path():
return EnsemblerStandardConfig(
experiment_mappings=None,
route_name_path="route_name",
fallback_response_route_id="route-1",
)

Expand Down Expand Up @@ -376,7 +386,7 @@ def generic_traffic_rule(


@pytest.fixture
def generic_ensembler_standard_config():
def generic_ensembler_standard_config_with_experiment_mappings():
return turing.generated.models.EnsemblerStandardConfig(
experiment_mappings=[
turing.generated.models.EnsemblerStandardConfigExperimentMappings(
Expand All @@ -389,6 +399,11 @@ def generic_ensembler_standard_config():
)


@pytest.fixture
def generic_ensembler_standard_config_with_route_name_path():
return turing.generated.models.EnsemblerStandardConfig(route_name_path="route_name")


@pytest.fixture
def generic_env_var():
return turing.generated.models.EnvVar(name="env_name", value="env_val")
Expand Down Expand Up @@ -427,14 +442,14 @@ def generic_ensembler_pyfunc_config(generic_resource_request, generic_env_var):
@pytest.fixture(params=["standard", "docker", "pyfunc"])
def ensembler(
request,
generic_ensembler_standard_config,
generic_ensembler_standard_config_with_experiment_mappings,
generic_ensembler_docker_config,
generic_ensembler_pyfunc_config,
):
ensembler_type = request.param
return turing.generated.models.RouterEnsemblerConfig(
type=ensembler_type,
standard_config=generic_ensembler_standard_config,
standard_config=generic_ensembler_standard_config_with_experiment_mappings,
docker_config=generic_ensembler_docker_config,
pyfunc_config=generic_ensembler_pyfunc_config,
created_at=datetime.now() + timedelta(seconds=10),
Expand All @@ -443,10 +458,22 @@ def ensembler(


@pytest.fixture
def generic_standard_router_ensembler_config(generic_ensembler_standard_config):
def generic_standard_router_ensembler_config_with_experiment_mappings(
generic_ensembler_standard_config_with_experiment_mappings,
):
return turing.generated.models.RouterEnsemblerConfig(
type="standard",
standard_config=generic_ensembler_standard_config_with_experiment_mappings,
)


@pytest.fixture
def generic_standard_router_ensembler_config_with_route_name_path(
generic_ensembler_standard_config_with_route_name_path,
):
return turing.generated.models.RouterEnsemblerConfig(
type="standard",
standard_config=generic_ensembler_standard_config,
standard_config=generic_ensembler_standard_config_with_route_name_path,
)


Expand Down
11 changes: 10 additions & 1 deletion sdk/tests/router/config/router_config_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,16 @@ def test_remove_router_config_default_route(actual, expected, request):
"generic_router_config",
"standard",
None,
"standard_router_ensembler_config",
"standard_router_ensembler_config_with_experiment_mappings",
None,
None,
StandardRouterEnsemblerConfig,
),
pytest.param(
"generic_router_config",
"standard",
None,
"standard_router_ensembler_config_with_route_name_path",
None,
None,
StandardRouterEnsemblerConfig,
Expand Down
Loading

0 comments on commit ba721c3

Please sign in to comment.