blob: 10dd6be265cc6ff40f37e3ca66f96dec00cc2f45 [file]
# Copyright 2015 The LUCI Authors. All rights reserved.
# Use of this source code is governed under the Apache License, Version 2.0
# that can be found in the LICENSE file.
from __future__ import annotations
import datetime
from recipe_engine import recipe_api
from recipe_engine.post_process import StepSuccess, StepFailure, StepException, StepCanceled
DEPS = [
'context',
'step',
]
def RunSteps(api):
# Nest all steps below this.
with api.step.nest('complicated thing'):
with api.step.nest('first part'):
api.step('wait a bit', ['sleep', '1'])
# Outer nested step's status gets the worst child's status by default.
with api.step.nest('inherit status'):
with api.step.nest('inner step') as inner_step_presentation:
inner_step_presentation.step_text += 'Hey!'
inner_step_presentation.status = api.step.EXCEPTION
# But, you could also pick the last status.
with api.step.nest('last status', status='last'):
with api.step.nest('failpants') as failpants_presentation:
failpants_presentation.status = api.step.EXCEPTION
api.step('everything OK', ['echo', 'hi'])
# Exceptions bubbling out take precedence.
try:
with api.step.nest('exception status'):
api.step('I am fine', ['echo', 'the chillest'])
raise Exception('Whoa! Bang!')
except Exception:
pass
try:
with api.step.nest('failure status'):
api.step('I fail', ['echo', 'fail'])
except api.step.StepFailure:
pass
try:
with api.step.nest('infra failure status'):
with api.context(infra_steps=True):
api.step('I infra-fail', ['echo', 'fail'])
except api.step.InfraFailure:
pass
try:
with api.step.nest('timeout status'):
api.step(
'I fail', ['echo', 'fail'], timeout=datetime.timedelta(seconds=1))
except api.step.StepFailure as ex:
assert ex.had_timeout
try:
with api.step.nest('warning status'):
api.step('I am fine', ['echo', 'the chillest'])
raise api.step.StepWarning("warning!")
except Exception:
pass
try:
with api.step.nest('canceled status'):
api.step('I get canceled', ['echo', 'cancel'])
except api.step.StepFailure:
pass
# Duplicate nesting names with unique child steps
for i in range(3):
with api.step.nest('Do Iteration'):
api.step('Iterate %d' % i, ['echo', 'lerpy'])
api.step('simple thing', ['sleep', '1'])
# Note that "|" is a reserved character:
try:
api.step('cool|step', ['echo', 'hi'])
assert False # pragma: no cover
except ValueError:
pass
# OK to have a nest parent without any children
with api.step.nest('lonely parent'):
pass
# funcall successfully produces five
out = api.step.funcall("five", (lambda: 5))
assert out == 5, f'out must be 5 not {out}'
def fail():
raise ValueError("failed exception")
try:
api.step.funcall(None, fail)
except ValueError as e:
pass
else: # pragma: nocover
assert "we expected an exception here, but there was none"
def GenTests(api):
yield (
api.test('basic')
+ api.post_process(StepException, 'inherit status')
+ api.post_process(StepSuccess, 'last status')
+ api.post_process(StepException, 'exception status')
# TODO(iannucci): switch to build.proto so these can actually be
# differentiated: annotator protocol only has a subset of the possible
# statuses.
+ api.step_data('failure status.I fail', retcode=1)
+ api.post_process(StepFailure, 'failure status')
# TODO(iannucci): switch to build.proto so these can actually be
# differentiated: annotator protocol only has a subset of the possible
# statuses.
+ api.step_data('infra failure status.I infra-fail', retcode=1)
+ api.post_process(StepException, 'infra failure status')
# TODO(iannucci): switch to build.proto so these can actually be
# differentiated: annotator protocol only has a subset of the possible
# statuses.
+ api.step_data('timeout status.I fail', times_out_after=20)
+ api.post_process(StepFailure, 'timeout status')
+ api.step_data('canceled status.I get canceled', cancel=True)
+ api.post_process(StepCanceled, 'canceled status')
)