async def test_lexicon_set_mutation(patch, logger, story): story.context = {} patch.object(Lexicon, 'line_number_or_none') patch.object(Mutations, 'mutate') line = { 'ln': '1', 'name': ['out'], 'args': ['values', { '$OBJECT': 'mutation' }], 'next': '2' } Mutations.mutate.return_value = 'mutated_result' result = await Lexicon.set(logger, story, line) story.resolve.assert_called_with(line['args'][0]) story.end_line.assert_called_with(line['ln'], assign={ 'paths': ['out'], '$OBJECT': 'path' }, output='mutated_result') story.line.assert_called_with(line['next']) Mutations.mutate.assert_called_with(line['args'][1], story.resolve(), story, line) assert result == Lexicon.line_number_or_none()
def test__is_if_condition_true(patch, story): line = { 'args': ['my_condition'] } patch.object(story, 'resolve', return_value='condition_result') assert Lexicon._is_if_condition_true(story, line) == 'condition_result' story.resolve.assert_called_with('my_condition', encode=False)
async def test_if_condition_elif_else(patch, logger, story, line, method): line['method'] = method patch.object(Lexicon, 'line_number_or_none') patch.object(story, 'next_block') ret = await Lexicon.if_condition(logger, story, line) story.next_block.assert_called_with(line) Lexicon.line_number_or_none.assert_called_with(story.next_block()) assert ret == Lexicon.line_number_or_none()
async def test_lexicon_set(patch, logger, story): story.context = {} patch.object(Lexicon, 'next_line_or_none') line = {'ln': '1', 'name': ['out'], 'args': ['values'], 'next': '2'} story.resolve.return_value = 'resolved' result = await Lexicon.set(logger, story, line) story.resolve.assert_called_with(line['args'][0]) story.end_line.assert_called_with( line['ln'], assign={'paths': ['out'], '$OBJECT': 'path'}, output='resolved') story.line.assert_called_with(line['next']) assert result == Lexicon.next_line_or_none()
async def test_lexicon_for_loop(patch, logger, story, line, async_mock, execute_block_return): iterated_over_items = [] async def execute_block(our_logger, our_story, our_line): iterated_over_items.append(story.context['element']) assert our_logger == logger assert our_story == story assert our_line == line return execute_block_return patch.object(Lexicon, 'execute', new=async_mock()) patch.object(Lexicon, 'line_number_or_none') patch.object(Story, 'execute_block', side_effect=execute_block) patch.object(story, 'next_block') line['args'] = [ {'$OBJECT': 'path', 'paths': ['elements']} ] line['output'] = ['element'] story.context = {'elements': ['one', 'two', 'three']} story.resolve.return_value = ['one', 'two', 'three'] story.environment = {} result = await Lexicon.for_loop(logger, story, line) if execute_block_return == LineSentinels.BREAK: assert iterated_over_items == ['one'] assert result == Lexicon.line_number_or_none(story.next_block(line)) elif LineSentinels.is_sentinel(execute_block_return): assert iterated_over_items == ['one'] assert result == execute_block_return else: assert iterated_over_items == story.context['elements'] assert result == Lexicon.line_number_or_none(story.next_block(line)) # Ensure no leakage of the element assert story.context.get('element') is None
async def test_lexicon_execute(patch, logger, story, line, async_mock, name): line['enter'] = None if name is not None: line['name'] = [name] output = MagicMock() patch.object(Services, 'execute', new=async_mock(return_value=output)) patch.object(Lexicon, 'line_number_or_none') result = await Lexicon.execute(logger, story, line) Services.execute.mock.assert_called_with(story, line) if name is not None: story.end_line.assert_called_with(line['ln'], output=output, assign={'paths': [name]}) else: story.end_line.assert_called_with(line['ln'], output=output, assign=None) story.line.assert_called_with(line['next']) assert result == Lexicon.line_number_or_none()
async def test_lexicon_execute_streaming_container(patch, story, async_mock): line = { 'enter': '10', 'ln': '9', LineConstants.service: 'foo', 'output': 'output', 'next': '11' } patch.object(Services, 'start_container', new=async_mock()) patch.object(Lexicon, 'next_line_or_none') patch.many(story, ['end_line', 'line']) Metrics.container_start_seconds_total = Mock() ret = await Lexicon.execute(story.logger, story, line) Services.start_container.mock.assert_called_with(story, line) story.end_line.assert_called_with( line['ln'], output=Services.start_container.mock.return_value, assign={'paths': line.get('output')}) Metrics.container_start_seconds_total.labels().observe.assert_called_once() story.line.assert_called_with(line['next']) Lexicon.next_line_or_none.assert_called_with(story.line()) assert ret == Lexicon.next_line_or_none()
def test_next_line_or_none(): line = {'ln': '10'} assert Lexicon.line_number_or_none(line) == '10' assert Lexicon.line_number_or_none(None) is None
def test_lexicon_unless_false(logger, story, line): story.context = {} story.resolve.return_value = False assert Lexicon.unless_condition(logger, story, line) == line['enter']
def test_lexicon_unless(logger, story, line): story.context = {} result = Lexicon.unless_condition(logger, story, line) logger.log.assert_called_with('lexicon-unless', line, story.context) story.resolve.assert_called_with(line['args'][0], encode=False) assert result == line['exit']
def test__is_if_condition_true_complex(patch, story): line = {'args': ['my_condition', 'my_condition_2']} with pytest.raises(StoryscriptError): Lexicon._is_if_condition_true(story, line)
async def test_lexicon_when(patch, story, async_mock, service_name): line = { 'ln': '10', LineConstants.service: service_name, LineConstants.command: 'updates', 'args': [ { '$OBJECT': 'argument', 'name': 'foo', 'argument': { '$OBJECT': 'string', 'string': 'bar' } } ] } story.context = { service_name: StreamingService(service_name, 'time-server', 'asyncy--foo-1', 'foo.com') } story.app.services = { service_name: { ServiceConstants.config: { 'actions': { 'time-server': { 'events': { 'updates': { 'http': { 'port': 2000, 'subscribe': { 'method': 'post', 'path': '/sub' } }, 'arguments': { 'foo': 'bar' } } } } } } } } story.name = 'my_event_driven_story.story' story.app.config.ENGINE_HOST = 'localhost' story.app.config.ENGINE_PORT = 8000 story.app.app_id = 'my_fav_app' story.app.app_dns = 'my_apps_hostname' expected_url = 'http://foo.com:2000/sub' expected_body = { 'endpoint': f'http://localhost:8000/story/event?' f'story={story.name}&block={line["ln"]}&app=my_fav_app', 'data': { 'foo': 'bar' }, 'event': 'updates', 'id': 'my_guid_here' } if service_name == 'http': expected_body['data']['host'] = story.app.app_dns patch.object(uuid, 'uuid4', return_value='my_guid_here') expected_kwargs = { 'method': 'POST', 'body': json.dumps(expected_body), 'headers': {'Content-Type': 'application/json; charset=utf-8'} } patch.init(AsyncHTTPClient) patch.object(Lexicon, 'next_line_or_none') patch.object(story, 'next_block') patch.object(story.app, 'add_subscription') patch.object(story, 'argument_by_name', return_value='bar') http_res = Mock() http_res.code = 204 patch.object(HttpUtils, 'fetch_with_retry', new=async_mock(return_value=http_res)) ret = await Lexicon.when(story.logger, story, line) client = AsyncHTTPClient() HttpUtils.fetch_with_retry.mock.assert_called_with( 3, story.logger, expected_url, client, expected_kwargs) story.app.add_subscription.assert_called_with( 'my_guid_here', story.context[service_name], 'updates', expected_body) assert ret == Lexicon.next_line_or_none() story.next_block.assert_called_with(line) http_res.code = 400 with pytest.raises(AsyncyError): await Lexicon.when(story.logger, story, line)