Skip to content

Commit

Permalink
Merge pull request #175 from launchableinc/ST-830-support-absolute-ti…
Browse files Browse the repository at this point in the history
…me-subsetting

[ST-830] add time option for absolute time-based subsetting
  • Loading branch information
Konboi authored Mar 26, 2021
2 parents 0f17332 + 67282e7 commit 971bcde
Show file tree
Hide file tree
Showing 5 changed files with 112 additions and 13 deletions.
39 changes: 28 additions & 11 deletions launchable/commands/subset.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
import glob
import gzip
from typing import Callable, Union, Optional
from ..utils.click import PERCENTAGE
from ..utils.click import PERCENTAGE, DURATION
from ..utils.env_keys import REPORT_ERROR_KEY
from ..utils.http_client import LaunchableClient
from ..utils.token import parse_token
Expand All @@ -22,9 +22,14 @@
'--target',
'target',
help='subsetting target from 0% to 100%',
required=True,
type=PERCENTAGE,
)
@click.option(
'--time',
'duration',
help='subsetting by absolute time, in seconds e.g) 300, 5m',
type=DURATION,
)
@click.option(
'--session',
'session_id',
Expand Down Expand Up @@ -52,7 +57,7 @@
type=str,
)
@click.pass_context
def subset(context, target, session_id, base_path: str, build_name: str, rest: str):
def subset(context, target, session_id, base_path: str, build_name: str, rest: str, duration):
token, org, workspace = parse_token()

if session_id and build_name:
Expand Down Expand Up @@ -170,6 +175,25 @@ def default_path_builder(file_name):
if path:
self.test_paths.append(self.to_test_path(path))

def get_payload(self, session_id, target, duration):
payload = {
"testPaths": self.test_paths,
"session": {
# expecting just the last component, not the whole path
"id": os.path.basename(session_id)
}
}

if target is not None:
payload["target"] = target
elif duration is not None:
payload["goal"] = {
"type": "subset-by-absolute-time",
"duration": duration,
}

return payload

def run(self):
"""called after tests are scanned to compute the optimized order"""

Expand All @@ -186,14 +210,7 @@ def run(self):
"Content-Encoding": "gzip",
}

payload = {
"testPaths": self.test_paths,
"target": target,
"session": {
# expecting just the last component, not the whole path
"id": os.path.basename(session_id)
}
}
payload = self.get_payload(session_id, target, duration)

path = "/intake/organizations/{}/workspaces/{}/subset".format(
org, workspace)
Expand Down
43 changes: 42 additions & 1 deletion launchable/utils/click.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import click, sys
import click
import sys
import re

# click.Group has the notion of hidden commands but it doesn't allow us to easily add
# the same command under multiple names and hide all but one.
Expand Down Expand Up @@ -32,7 +34,22 @@ def convert(self, value: str, param, ctx):
value), param, ctx)


class DurationType(click.ParamType):
name = "duration"

def convert(self, value: str, param, ctx):
try:
return convert_to_seconds(value)

except ValueError:
pass

self.fail("Expected duration like 3600, 30m, 1h15m but got '{}'".format(
value), param, ctx)


PERCENTAGE = PercentageType()
DURATION = DurationType()

# Can the output deal with Unicode emojis?
try:
Expand All @@ -51,3 +68,27 @@ def emoji(s: str, fallback: str = ''):
Returns 's' in an environment where stdout can deal with emojis, but 'fallback' otherwise.
"""
return s if EMOJI else fallback


def convert_to_seconds(s: str):
units = {'s': 1, 'm': 60,
'h': 60*60, 'd': 60*60*24, 'w': 60*60*24*7}

if s.isdigit():
return float(s)

duration = 0
for m in re.finditer(r'(?P<val>\d+)(?P<unit>[smhdw]?)', s, flags=re.I):
val = m.group('val')
unit = m.group('unit')

if val is None or unit is None:
raise ValueError("unable to parse: {}".format(s))

u = units.get(unit)
if u is None:
raise ValueError("unable to parse: {}".format(s))

duration += int(val) * u

return float(duration)
13 changes: 13 additions & 0 deletions tests/data/maven/subset_by_absolute_time_result.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
{
"testPaths": [
[
{"type": "class", "name": "com.launchableinc.rocket_car_maven.App2Test"}
],
[
{ "type": "class", "name": "com.launchableinc.rocket_car_maven.AppTest"}
]],
"session": {
"id": "16"
},
"goal": {"type": "subset-by-absolute-time", "duration": 5400}
}
16 changes: 15 additions & 1 deletion tests/test_runners/test_maven.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
from pathlib import Path
from unittest import mock
import responses # type: ignore
import responses # type: ignore
import json
import gzip
from tests.cli_test_case import CliTestCase
Expand All @@ -25,6 +25,20 @@ def test_subset(self):

self.assert_json_orderless_equal(expected, payload)

@responses.activate
def test_subset_by_absolute_time(self):
result = self.cli('subset', '--time', '1h30m', '--session',
self.session, 'maven', str(self.test_files_dir.joinpath('java/test/src/java/').resolve()))
self.assertEqual(result.exit_code, 0)

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

expected = self.load_json_from_file(
self.test_files_dir.joinpath('subset_by_absolute_time_result.json'))

self.assert_json_orderless_equal(expected, payload)

@ responses.activate
def test_record_test_maven(self):
result = self.cli('record', 'tests', '--session', self.session,
Expand Down
14 changes: 14 additions & 0 deletions tests/utils/test_click.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
from unittest import TestCase
from launchable.utils.click import convert_to_seconds


class DurationTypeTest(TestCase):
def test_convert_to_seconds(self):
self.assertEqual(convert_to_seconds('30s'), 30)
self.assertEqual(convert_to_seconds('5m'), 300)
self.assertEqual(convert_to_seconds('1h30m'), 5400)
self.assertEqual(convert_to_seconds('1d10h15m'), 123300)
self.assertEqual(convert_to_seconds('15m 1d 10h'), 123300)

with self.assertRaises(ValueError):
convert_to_seconds('1h30k')

0 comments on commit 971bcde

Please sign in to comment.