Skip to content

st2client - elapsed time in a more user-friendly format #4963

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

Draft
wants to merge 19 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
43c80be
Change the presentation of elapsed time on st2 execution get to a mor…
winem Jun 7, 2020
0e76b0c
drop space between days and hours if the elapsed time is > 86400 seconds
winem Jun 7, 2020
dc5b830
Remove space between days and hours from changelog (more user-friendl…
winem Jun 8, 2020
a265346
remove repeating spaces before operator to pass lint checks
winem Jun 8, 2020
aafca8b
add unit test to parse the elapsed time for the expected format
winem Jun 13, 2020
724c68a
Merge branch 'master' into issue-4944-stcli-elapsed-time-more-readable
winem Jun 13, 2020
d4e6bba
Add unit test for st2client with hours in elapsed time
winem Jun 13, 2020
e99819f
Revert "add unit test to parse the elapsed time for the expected format"
winem Jun 13, 2020
3d2af58
try to fix unexpected duration reported
winem Jun 14, 2020
98ffc97
test with a duration >1 day
winem Jun 14, 2020
7135b76
troubleshooting failing unit test (elapsed time)
winem Jun 14, 2020
befa79a
Revert "troubleshooting failing unit test (elapsed time)"
winem Jun 14, 2020
7430732
change end timestamp for another test
winem Jun 14, 2020
c5d8e63
use mock.path.object to create DURATION_HOURS response object
winem Jun 19, 2020
52bc3d3
Revert "use mock.path.object to create DURATION_HOURS response object"
winem Jun 19, 2020
41874c7
revert the DURATION_HOURS tests and go back to the initial one
winem Jun 19, 2020
15a4b64
reduce the duration back from 1d2h0m1s ot 2h0m1s
winem Jun 20, 2020
25f91d8
break line to fix lint issue
winem Jun 20, 2020
3765c1f
Merge branch 'master' into issue-4944-stcli-elapsed-time-more-readable
winem Jun 20, 2020
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
8 changes: 8 additions & 0 deletions CHANGELOG.rst
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,14 @@ Added
* Add make command to autogen JSON schema from the models of action, rule, etc. Add check
to ensure update to the models require schema to be regenerated. (new feature)

Changed
~~~~~~~
* Changed the output of elapsed time on `st2 execution get` to a more user-friendly format.
The new format is ``<days>d <hours>h<minutes>m<seconds>s``. Units without a value are omitted.
Old: ``status: succeeded (92342s elapsed)``, ``status: succeeded (113s elapsed)``
New: ``stauts: succeeded (1d1h39m2s elapsed)``, ``status: succeeded (1m53s elapsed)``
This was requested by Sheshagiri (@Sheshagiri) and contributed by Marcel Weinber (@winem). #4944

Fixed
~~~~~
* Fixed a bug where `type` attribute was missing for netstat action in linux pack. Fixes #4946
Expand Down
29 changes: 25 additions & 4 deletions st2client/st2client/commands/action.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@
import six
import sys

from dateutil.relativedelta import relativedelta

from os.path import join as pjoin

from six.moves import range
Expand Down Expand Up @@ -167,20 +169,39 @@ def format_execution_status(instance):
start_timestamp = parse_isotime(start_timestamp)
start_timestamp = calendar.timegm(start_timestamp.timetuple())
now = int(time.time())
elapsed_seconds = (now - start_timestamp)
instance.status = '%s (%ss elapsed)' % (instance.status, elapsed_seconds)
elapsed_time_string = format_elapsed_time(now - start_timestamp)
instance.status = '%s (%s elapsed)' % (instance.status, elapsed_time_string)
elif status in LIVEACTION_COMPLETED_STATES and start_timestamp and end_timestamp:
start_timestamp = parse_isotime(start_timestamp)
start_timestamp = calendar.timegm(start_timestamp.timetuple())
end_timestamp = parse_isotime(end_timestamp)
end_timestamp = calendar.timegm(end_timestamp.timetuple())

elapsed_seconds = (end_timestamp - start_timestamp)
instance.status = '%s (%ss elapsed)' % (instance.status, elapsed_seconds)
elapsed_time_string = format_elapsed_time(end_timestamp - start_timestamp)
instance.status = '%s (%s elapsed)' % (instance.status, elapsed_time_string)

return instance


def format_elapsed_time(delta_in_seconds):
delta = relativedelta(seconds=delta_in_seconds)
days = delta.days
hours = delta.hours
minutes = delta.minutes
seconds = delta.seconds

if days > 0:
elapsed_time_string = '%sd%sh%sm%ss' % (days, hours, minutes, seconds)
elif hours > 0:
elapsed_time_string = '%sh%sm%ss' % (hours, minutes, seconds)
elif minutes > 0:
elapsed_time_string = '%sm%ss' % (minutes, seconds)
else:
elapsed_time_string = '%ss' % (seconds)

return elapsed_time_string


class ActionBranch(resource.ResourceBranch):

def __init__(self, description, app, subparsers, parent_parser=None):
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
status: succeeded (2h0m1s elapsed)
29 changes: 29 additions & 0 deletions st2client/tests/fixtures/execution_with_hours_in_elapsed_time.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
{
"id": "547e19561e2e2417d3dde398",
"parameters": {
"cmd": "127.0.0.1 3"
},
"callback": {},
"context": {
"user": "stanley"
},
"result": {
"localhost": {
"failed": false,
"stderr": "",
"return_code": 0,
"succeeded": true,
"stdout": "PING 127.0.0.1 (127.0.0.1) 56(84) bytes of data.\n64 bytes from 127.0.0.1: icmp_seq=1 ttl=64 time=0.015 ms\n64 bytes from 127.0.0.1: icmp_seq=2 ttl=64 time=0.024 ms\n64 bytes from 127.0.0.1: icmp_seq=3 ttl=64 time=0.030 ms\n\n--- 127.0.0.1 ping statistics ---\n3 packets transmitted, 3 received, 0% packet loss, time 1998ms\nrtt min/avg/max/mdev = 0.015/0.023/0.030/0.006 ms"
}
},
"status": "succeeded",
"start_timestamp": "2014-12-02T19:56:06.900000Z",
"end_timestamp": "2014-12-02T21:56:07.000000Z",
"action": {
"ref": "core.ping"
},
"liveaction": {
"callback": {},
"id": "1"
}
}
9 changes: 9 additions & 0 deletions st2client/tests/unit/test_formatters.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@
'execution_result_has_carriage_return.json',
'execution_unicode.json',
'execution_double_backslash.json',
'execution_with_hours_in_elapsed_time.json',
'execution_with_stack_trace.json',
'execution_with_schema.json'],
'results': ['execution_get_default.txt',
Expand All @@ -50,6 +51,7 @@
'execution_result_has_carriage_return.txt',
'execution_result_has_carriage_return_py3.txt',
'execution_get_attributes.txt',
'execution_get_attribute_with_hours_in_elapsed_time.txt',
'execution_list_attr_start_timestamp.txt',
'execution_list_empty_response_start_timestamp_attr.txt',
'execution_unescape_newline.txt',
Expand All @@ -66,6 +68,7 @@
OUTPUT_SCHEMA = FIXTURES['executions']['execution_with_schema.json']
NEWLINE = FIXTURES['executions']['execution_with_stack_trace.json']
HAS_CARRIAGE_RETURN = FIXTURES['executions']['execution_result_has_carriage_return.json']
DURATION_HOURS = FIXTURES['executions']['execution_with_hours_in_elapsed_time.json']


class TestExecutionResultFormatter(unittest2.TestCase):
Expand Down Expand Up @@ -112,6 +115,12 @@ def test_execution_get_attributes(self):
content = self._get_execution(argv)
self.assertEqual(content, FIXTURES['results']['execution_get_attributes.txt'])

def test_execution_get_attribute_with_hours_in_elapsed_time(self):
argv = ['execution', 'get', DURATION_HOURS['id'], '--attr', 'status']
content = self._get_execution(argv)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think using self._get_execution() is the source of the error because _get_execution() has a mock so it always returns the json from EXECUTION, but you need it to return DURATION_HOURS.

Here's _get_execution with the mocked EXECUTION response:

    @mock.patch.object(
        httpclient.HTTPClient,
        "get",
        mock.MagicMock(
            return_value=base.FakeResponse(json.dumps(EXECUTION), 200, "OK", {})
        ),
    )
    def _get_execution(self, argv):
        self.assertEqual(self.shell.run(argv), 0)
        self._undo_console_redirect()
        with open(self.path, "r") as fd:
            content = fd.read()

        return content

That's why your example unit test that uses mock.MagicMock worked better than self._get_execution().

self.assertEqual(
content, FIXTURES['results']['execution_get_attribute_with_hours_in_elapsed_time.txt'])

def test_execution_get_default_in_json(self):
argv = ['execution', 'get', EXECUTION['id'], '-j']
content = self._get_execution(argv)
Expand Down