Example #1
0
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()
Example #2
0
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)
Example #3
0
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()
Example #4
0
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()
Example #5
0
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
Example #6
0
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()
Example #7
0
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()
Example #8
0
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
Example #9
0
def test_lexicon_unless_false(logger, story, line):
    story.context = {}
    story.resolve.return_value = False
    assert Lexicon.unless_condition(logger, story, line) == line['enter']
Example #10
0
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']
Example #11
0
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)
Example #12
0
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)