Skip to content

Commit

Permalink
Merge pull request #546 from launchableinc/feature-test_session_name
Browse files Browse the repository at this point in the history
Support --session-name option to `record session` and `record tests` commands
  • Loading branch information
Konboi authored Mar 1, 2023
2 parents 14c6cad + 4ba3dc9 commit db2e31e
Show file tree
Hide file tree
Showing 4 changed files with 159 additions and 3 deletions.
84 changes: 81 additions & 3 deletions launchable/commands/record/session.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import os
import re
import sys
from http import HTTPStatus
from typing import List
from typing import List, Optional

import click

Expand All @@ -16,6 +17,18 @@

LAUNCHABLE_SESSION_DIR_KEY = 'LAUNCHABLE_SESSION_DIR'

TEST_SESSION_NAME_RULE = re.compile("^[a-zA-Z0-9][a-zA-Z0-9_-]*$")


def _validate_session_name(ctx, param, value):
if value is None:
return ""

if TEST_SESSION_NAME_RULE.match(value):
return value
else:
raise click.BadParameter("--session-name option supports only alphabet(a-z, A-Z), number(0-9), '-', and '_'")


@click.command()
@click.option(
Expand Down Expand Up @@ -61,6 +74,16 @@
is_flag=True,
hidden=True,
)
@click.option(
'--session-name',
'session_name',
help='test session name',
required=False,
hidden=True,
type=str,
metavar='SESSION_NAME',
callback=_validate_session_name,
)
@click.pass_context
def session(
ctx: click.core.Context,
Expand All @@ -71,6 +94,7 @@ def session(
is_observation: bool = False,
links: List[str] = [],
is_no_build: bool = False,
session_name: Optional[str] = None,
):
"""
print_session is for barckward compatibility.
Expand All @@ -90,9 +114,18 @@ def session(
raise click.UsageError(
'The cli already created `.launchable file`. If you want to use `--no-build option`, please remove `.launchable` file before executing.') # noqa: E501

if is_no_build:
build_name = NO_BUILD_BUILD_NAME

client = LaunchableClient(dry_run=ctx.obj.dry_run)

if session_name:
sub_path = "builds/{}/test_session_names/{}".format(build_name, session_name)
res = client.request("get", sub_path)

if res.status_code != 404:
raise click.UsageError(
'This session name ({}) is already used. Please set another name.'.format(session_name))

flavor_dict = {}
for f in normalize_key_value_types(flavor):
flavor_dict[f[0]] = f[1]
Expand All @@ -113,7 +146,6 @@ def session(
})
payload["links"] = _links

client = LaunchableClient(dry_run=ctx.obj.dry_run)
try:
sub_path = "builds/{}/test_sessions".format(build_name)
res = client.request("post", sub_path, payload=payload)
Expand Down Expand Up @@ -149,3 +181,49 @@ def session(
raise e
else:
click.echo(e, err=True)

if session_name:
try:
add_session_name(
client=client,
build_name=build_name,
session_id=session_id,
session_name=session_name,
)
except Exception as e:
if os.getenv(REPORT_ERROR_KEY):
raise e
else:
click.echo(e, err=True)


def add_session_name(
client: LaunchableClient,
build_name: str,
session_id: str,
session_name: str,
):
sub_path = "builds/{}/test_sessions/{}".format(build_name, session_id)
payload = {
"name": session_name
}
res = client.request("patch", sub_path, payload=payload)

if res.status_code == HTTPStatus.NOT_FOUND:
click.echo(
click.style(
"Test session {} was not found. Record session may have failed.".format(session_id),
'yellow'),
err=True,
)
sys.exit(1)
if res.status_code == HTTPStatus.BAD_REQUEST:
click.echo(
click.style(
"You cannot use test session name {} since it is already used by other test session in your workspace. The record session is completed successfully without session name." # noqa: E501
.format(session_name),
'yellow'),
err=True,)
sys.exit(1)

res.raise_for_status()
21 changes: 21 additions & 0 deletions launchable/commands/record/tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,15 @@ def _validate_group(ctx, param, value):
is_flag=True,
hidden=True,
)
@click.option(
'--session-name',
'session_name',
help='test session name',
required=False,
hidden=True,
type=str,
metavar='SESSION_NAME',
)
@click.pass_context
def tests(
context: click.core.Context,
Expand All @@ -151,6 +160,7 @@ def tests(
is_allow_test_before_build: bool,
links: List[str] = [],
is_no_build: bool = False,
session_name: Optional[str] = None
):
logger = Logger()

Expand All @@ -174,6 +184,17 @@ def tests(
result = get_session_and_record_start_at_from_subsetting_id(subsetting_id, client)
session_id = result["session"]
record_start_at = result["start_at"]
elif session_name:
if not build_name:
raise click.UsageError(
'--build-name is required when you uses a --session-name option ')

sub_path = "builds/{}/test_session_names/{}".format(build_name, session_name)
res = client.request("get", sub_path)
res.raise_for_status()

session_id = "builds/{}/test_sessions/{}".format(build_name, res.json().get("id"))
record_start_at = get_record_start_at(session_id, client)
else:
# The session_id must be back, so cast to str
session_id = str(find_or_create_session(
Expand Down
24 changes: 24 additions & 0 deletions tests/cli_test_case.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ class CliTestCase(unittest.TestCase):
launchable_token = "v1:{}/{}:auth-token-sample".format(organization, workspace)
session_id = 16
build_name = "123"
session_name = "test_session_name"
subsetting_id = 456
session = "builds/{}/test_sessions/{}".format(build_name, session_id)

Expand Down Expand Up @@ -109,6 +110,29 @@ def setUp(self):
'isObservation': False,
},
status=200)
responses.add(
responses.GET,
"{}/intake/organizations/{}/workspaces/{}/builds/{}/test_session_names/{}".format(
get_base_url(),
self.organization,
self.workspace,
self.build_name,
self.session_name),
json={
'id': self.session_id,
'isObservation': False,
},
status=200)
responses.add(
responses.PATCH,
"{}/intake/organizations/{}/workspaces/{}/builds/{}/test_sessions/{}".format(
get_base_url(),
self.organization,
self.workspace,
self.build_name,
self.session_id),
json={'name': self.session_name},
status=200)
responses.add(
responses.PATCH,
"{}/intake/organizations/{}/workspaces/{}/builds/{}/test_sessions/{}/close".format(
Expand Down
33 changes: 33 additions & 0 deletions tests/commands/record/test_session.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

import responses # type: ignore

from launchable.utils.http_client import get_base_url
from tests.cli_test_case import CliTestCase


Expand Down Expand Up @@ -66,4 +67,36 @@ def test_run_session_with_observation(self):
self.assertEqual(result.exit_code, 0)

payload = json.loads(responses.calls[0].request.body.decode())

self.assert_json_orderless_equal({"flavors": {}, "isObservation": True, "links": [], "noBuild": False}, payload)

@responses.activate
@mock.patch.dict(os.environ, {
"LAUNCHABLE_TOKEN": CliTestCase.launchable_token,
'LANG': 'C.UTF-8',
}, clear=True)
def test_run_session_with_session_name(self):
# session name is already exist
result = self.cli("record", "session", "--build", self.build_name, "--session-name", self.session_name)
self.assertEqual(result.exit_code, 2)

responses.replace(
responses.GET,
"{}/intake/organizations/{}/workspaces/{}/builds/{}/test_session_names/{}".format(
get_base_url(),
self.organization,
self.workspace,
self.build_name,
self.session_name,
),
status=404,
)
# invalid session name
result = self.cli("record", "session", "--build", self.build_name, "--session-name", "invalid/name")
self.assertEqual(result.exit_code, 2)

result = self.cli("record", "session", "--build", self.build_name, "--session-name", self.session_name)
self.assertEqual(result.exit_code, 0)

payload = json.loads(responses.calls[2].request.body.decode())
self.assert_json_orderless_equal({"flavors": {}, "isObservation": False, "links": [], "noBuild": False}, payload)

0 comments on commit db2e31e

Please sign in to comment.