Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update CLI with the new SelectedTests using Pydantic #4

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ For JSON respond, add `--json` to the command.

### create-project

Run `./cli.sh create-project --name {project name} --dut_type {dut type}` to create a new project. DUT Type must be one of `Controller, Accessory`.
Run `./cli.sh create-project --name {project name} --config {config file}` to create a new project. Project name is required.

### list-projects

Expand Down
26 changes: 20 additions & 6 deletions app/api_lib_autogen/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,7 @@

class BodyCreateTestRunExecutionApiV1TestRunExecutionsPost(BaseModel):
test_run_execution_in: "TestRunExecutionCreate" = Field(..., alias="test_run_execution_in")
selected_tests: "Optional[Dict[str, Dict[str, Dict[str, int]]]]" = Field(None, alias="selected_tests")


# class BodyUploadFileApiV1TestRunExecutionsFileUploadPost(BaseModel):
# file: "IO[Any]" = Field(..., alias="file")
selected_tests: "SelectedTests" = Field(..., alias="selected_tests")


class DutConfig(BaseModel):
Expand Down Expand Up @@ -169,7 +165,6 @@ class TestRunExecution(BaseModel):

class TestRunExecutionCreate(BaseModel):
title: "str" = Field(..., alias="title")
test_run_config_id: "Optional[int]" = Field(None, alias="test_run_config_id")
project_id: "Optional[int]" = Field(None, alias="project_id")
description: "Optional[str]" = Field(None, alias="description")
operator_id: "Optional[int]" = Field(None, alias="operator_id")
Expand Down Expand Up @@ -311,3 +306,22 @@ class ValidationError(BaseModel):
class WiFiConfig(BaseModel):
ssid: "str" = Field(..., alias="ssid")
password: "str" = Field(..., alias="password")


class SelectedTests(BaseModel):
collections: "list[SelectedCollection]" = Field(..., alias="collections")


class SelectedCollection(BaseModel):
public_id: "str" = Field(..., alias="public_id")
test_suites: "list[SelectedTestSuite]" = Field(..., alias="test_suites")


class SelectedTestSuite(BaseModel):
public_id: "str" = Field(..., alias="public_id")
test_cases: "list[SelectedTestCase]" = Field(..., alias="test_cases")


class SelectedTestCase(BaseModel):
public_id: "str" = Field(..., alias="public_id")
iterations: "int" = Field(..., alias="iterations")
40 changes: 22 additions & 18 deletions app/commands/project.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ def create_project(name: str, config: Optional[str]) -> None:
test_environment_config = TestEnvironmentConfig(**config_dict)
projectCreate = ProjectCreate(name=name, config=test_environment_config)
response = sync_apis.projects_api.create_project_api_v1_projects_post(project_create=projectCreate)
click.echo(f"Project {response.name} created with id {response.id}.")
except json.JSONDecodeError as e:
click.echo(f"Failed to parse JSON parameter: {e.msg}", err=True)
raise Exit(code=1)
Expand All @@ -66,9 +67,8 @@ def create_project(name: str, config: Optional[str]) -> None:
except UnexpectedResponse as e:
click.echo(f"Failed to create project {name}: {e.status_code} {e.content}", err=True)
raise Exit(code=1)

click.echo(f"Project {response.name} created with id {response.id}.")
client.close()
finally:
client.close()


@click.command()
Expand All @@ -82,11 +82,12 @@ def delete_project(id: int) -> None:
"""Delete a project"""
try:
sync_apis.projects_api.delete_project_api_v1_projects_id_delete(id=id)
click.echo(f"Project {id} is deleted.")
except UnexpectedResponse as e:
click.echo(f"Failed to delete project {id}: {e.status_code} {e.content}", err=True)
raise Exit(code=1)
click.echo(f"Project {id} is deleted.")
client.close()
finally:
client.close()


@click.command()
Expand Down Expand Up @@ -172,20 +173,22 @@ def __print_project(project: dict) -> None:
)
)

if id is not None:
projects = __list_project_by_id(id)
else:
projects = __list_project_by_batch(archived, skip, limit)
try:
if id is not None:
projects = __list_project_by_id(id)
else:
projects = __list_project_by_batch(archived, skip, limit)

if projects is None or len(projects) == 0:
click.echo("Server did not return any project", err=True)
raise Exit(code=1)
if projects is None or (isinstance(projects, list) and len(projects) == 0):
click.echo("Server did not return any project", err=True)
raise Exit(code=1)

if json:
__print_json(projects)
else:
__print_table(projects)
client.close()
if json:
__print_json(projects)
else:
__print_table(projects)
finally:
client.close()


@click.command()
Expand All @@ -209,7 +212,6 @@ def update_project(id: int, config: str):
projectUpdate = ProjectUpdate(**config_dict)
response = sync_apis.projects_api.update_project_api_v1_projects_id_put(id=id, project_update=projectUpdate)
click.echo(f"Project {response.name} is updated with the new config.")
client.close()
except json.JSONDecodeError as e:
click.echo(f"Failed to parse JSON parameter: {e.msg}", err=True)
raise Exit(code=1)
Expand All @@ -222,3 +224,5 @@ def update_project(id: int, config: str):
except UnexpectedResponse as e:
click.echo(f"Failed to update project {id}: {e.status_code} {e.content}", err=True)
raise Exit(code=1)
finally:
client.close()
20 changes: 12 additions & 8 deletions app/commands/run_tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,14 +56,18 @@ async def run_tests(selected_tests: str, title: str, file: str, project_id: int)

selected_tests_dict = __parse_selected_tests(selected_tests, file)

new_test_run = await __create_new_test_run(selected_tests=selected_tests_dict, title=title, project_id=project_id)
socket = TestRunSocket(new_test_run)
socket_task = asyncio.create_task(socket.connect_websocket())
new_test_run = await __start_test_run(new_test_run)
socket.run = new_test_run
await socket_task
await client.aclose()
click.echo(f"Log output in: '{log_path}'")
try:
new_test_run = await __create_new_test_run(
selected_tests=selected_tests_dict, title=title, project_id=project_id
)
socket = TestRunSocket(new_test_run)
socket_task = asyncio.create_task(socket.connect_websocket())
new_test_run = await __start_test_run(new_test_run)
socket.run = new_test_run
await socket_task
click.echo(f"Log output in: '{log_path}'")
finally:
await client.aclose()


async def __create_new_test_run(selected_tests: dict, title: str, project_id: int) -> None:
Expand Down
16 changes: 9 additions & 7 deletions app/commands/test_run_execution_history.py
Original file line number Diff line number Diff line change
Expand Up @@ -57,13 +57,15 @@ def test_run_execution_history(
id: Optional[int], skip: Optional[int], limit: Optional[int], json: Optional[bool]
) -> None:
"""Read test run execution history"""
if id is not None:
__test_run_execution_by_id(id, json)
elif skip is not None or limit is not None:
__test_run_execution_batch(json, skip, limit)
else:
__test_run_execution_batch(json)
client.close()
try:
if id is not None:
__test_run_execution_by_id(id, json)
elif skip is not None or limit is not None:
__test_run_execution_batch(json, skip, limit)
else:
__test_run_execution_batch(json)
finally:
client.close()


def __test_run_execution_by_id(id: int, json: bool) -> None:
Expand Down
6 changes: 3 additions & 3 deletions app/test_run/socket_schemas.py
Original file line number Diff line number Diff line change
Expand Up @@ -63,15 +63,15 @@ class TestRunUpdate(TestUpdateBase):


class TestSuiteUpdate(TestUpdateBase):
test_suite_execution_id: int
test_suite_execution_index: int


class TestCaseUpdate(TestSuiteUpdate):
test_case_execution_id: int
test_case_execution_index: int


class TestStepUpdate(TestCaseUpdate):
test_step_execution_id: int
test_step_execution_index: int


class TestUpdate(BaseModel):
Expand Down
26 changes: 13 additions & 13 deletions app/test_run/websocket.py
Original file line number Diff line number Diff line change
Expand Up @@ -104,20 +104,20 @@ def __log_test_run_update(self, update: TestRunUpdate) -> None:
click.echo(f"Test Run [{str(update.state.name)}]")

def __log_test_suite_update(self, update: TestSuiteUpdate) -> None:
suite = self.__suite(update.test_suite_execution_id)
suite = self.__suite(update.test_suite_execution_index)
title = suite.test_suite_metadata.title
click.echo(f" - {title} [{str(update.state.name)}]")

def __log_test_case_update(self, update: TestCaseUpdate) -> None:
case = self.__case(id=update.test_case_execution_id, suite_id=update.test_suite_execution_id)
case = self.__case(index=update.test_case_execution_index, suite_index=update.test_suite_execution_index)
title = case.test_case_metadata.title
click.echo(f" - {title} [{str(update.state.name)}]")

def __log_test_step_update(self, update: TestStepUpdate) -> None:
step = self.__step(
id=update.test_step_execution_id,
case_id=update.test_case_execution_id,
suite_id=update.test_suite_execution_id,
index=update.test_step_execution_index,
case_index=update.test_case_execution_index,
suite_index=update.test_suite_execution_index,
)
if step is not None:
title = step.title
Expand All @@ -127,13 +127,13 @@ def __handle_log_record(self, records: List[TestLogRecord]) -> None:
for record in records:
logger.log(record.level, record.message)

def __suite(self, id: int) -> TestSuiteExecution:
return next((s for s in self.run.test_suite_executions if s.id == id))
def __suite(self, index: int) -> TestSuiteExecution:
return self.run.test_suite_executions[index]

def __case(self, id: int, suite_id: int) -> TestCaseExecution:
suite = self.__suite(suite_id)
return next((c for c in suite.test_case_executions if c.id == id))
def __case(self, index: int, suite_index: int) -> TestCaseExecution:
suite = self.__suite(index=suite_index)
return suite.test_case_executions[index]

def __step(self, id: int, case_id: int, suite_id: int) -> Optional[TestStepExecution]:
case = self.__case(id=case_id, suite_id=suite_id)
return next((s for s in case.test_step_executions if s.id == id), None)
def __step(self, index: int, case_index: int, suite_index: int) -> Optional[TestStepExecution]:
case = self.__case(index=case_index, suite_index=suite_index)
return case.test_step_executions[index]
78 changes: 63 additions & 15 deletions openapi.json
Original file line number Diff line number Diff line change
Expand Up @@ -1399,28 +1399,80 @@
"Body_create_test_run_execution_api_v1_test_run_executions__post": {
"title": "Body_create_test_run_execution_api_v1_test_run_executions__post",
"required": [
"test_run_execution_in"
"test_run_execution_in",
"selected_tests"
],
"type": "object",
"properties": {
"test_run_execution_in": {
"$ref": "#/components/schemas/TestRunExecutionCreate"
},
"selected_tests": {
"title": "Selected Tests",
"type": "object",
"additionalProperties": {
"type": "object",
"additionalProperties": {
"type": "object",
"additionalProperties": {
"type": "integer"
}
}
"$ref": "#/components/schemas/SelectedTests"
}
}
},
"SelectedTests": {
"title": "Selected Tests",
"type": "object",
"properties":{
"collections": {
"title": "Collections",
"type": "array",
"items": {
"$ref": "#/components/schemas/SelectedCollection"
}
}
}
},
"SelectedCollection": {
"title": "Selected Test Collection",
"type": "object",
"properties": {
"public_id": {
"title": "Collection Public ID",
"type": "string"
},
"test_suites": {
"title": "Collection Test Suites",
"type": "array",
"items": {
"$ref": "#/components/schemas/SelectedSuite"
}
}
}
},
"SelectedSuite": {
"title": "Selected Test Suite",
"type": "object",
"properties": {
"public_id": {
"title": "Test Suite Public ID",
"type": "string"
},
"test_cases": {
"title": "Suite Test Cases",
"type": "array",
"items": {
"$ref": "#/components/schemas/SelectedCase"
}
}
}
},
"SelectedCase": {
"title": "Selected Test Case",
"type": "object",
"properties": {
"public_id": {
"title": "Test Case Public ID",
"type": "string"
},
"iterations": {
"title": "Iterations",
"type": "integer"
}
}
},
"Body_upload_file_api_v1_test_run_executions_file_upload__post": {
"title": "Body_upload_file_api_v1_test_run_executions_file_upload__post",
"required": [
Expand Down Expand Up @@ -1979,10 +2031,6 @@
"title": "Title",
"type": "string"
},
"test_run_config_id": {
"title": "Test Run Config Id",
"type": "integer"
},
"project_id": {
"title": "Project Id",
"type": "integer"
Expand Down