def test_ignore_condition(self): os.environ['CLOUD'] = 'AWS' self.populate_file( 'main.yaml', '''--- ignore: equals: {the: '{{ CLOUD }}', is: 'AWS'} steps: - check: {equals: {the: true, is: false}} ''') runner = Runner(self.test_dir, join(self.test_dir, 'main.yaml'), None, system_environment=dict(os.environ)) self.assertTrue(runner.run_tests()) os.environ['CLOUD'] = 'Marathon' self.populate_file( 'main.yaml', '''--- ignore: equals: {the: '{{ CLOUD }}', is: 'AWS'} steps: - check: {equals: {the: true, is: false}} ''') runner = Runner(self.test_dir, join(self.test_dir, 'main.yaml'), None, system_environment=dict(os.environ)) self.assertFalse(runner.run_tests())
def test_random_int(self): self.populate_file('main.yaml', '''--- steps: - echo: {from: '{{ random_int(1, 10) }}', to: one.output} ''') runner = Runner(self.test_dir, join(self.test_dir, 'main.yaml'), None) random.seed(123) self.assertTrue(runner.run_tests()) self.assertTrue(check_file(join(self.test_dir, 'one.output'), '9')) # no upper limit self.populate_file('main.yaml', '''--- steps: - echo: {from: '{{ random_int(1) }}', to: one.output} ''') runner = Runner(self.test_dir, join(self.test_dir, 'main.yaml'), None) random.seed(123) self.assertTrue(runner.run_tests()) self.assertTrue(check_file(join(self.test_dir, 'one.output'), '5186474716495645053')) # no lower limit self.populate_file('main.yaml', '''--- steps: - echo: {from: '{{ random_int(range_to=1) }}', to: one.output} ''') runner = Runner(self.test_dir, join(self.test_dir, 'main.yaml'), None) random.seed(123) self.assertTrue(runner.run_tests()) self.assertTrue(check_file(join(self.test_dir, 'one.output'), '-2936754363331581815'))
def test_random_int(self): random.seed(123) self.populate_file('main.yaml', '''--- steps: - echo: {from: '{{ random_int(1, 10) }}', to: one.output} ''') runner = Runner(self.test_dir, join(self.test_dir, 'main.yaml'), None) self.assertTrue(runner.run_tests()) self.assertTrue(check_file(join(self.test_dir, 'one.output'), '2')) # no upper limit self.populate_file('main.yaml', '''--- steps: - echo: {from: '{{ random_int(1) }}', to: one.output} ''') runner = Runner(self.test_dir, join(self.test_dir, 'main.yaml'), None) self.assertTrue(runner.run_tests()) self.assertTrue(check_file(join(self.test_dir, 'one.output'), '8312092512683043478')) # no lower limit self.populate_file('main.yaml', '''--- steps: - echo: {from: '{{ random_int(range_to=1) }}', to: one.output} ''') runner = Runner(self.test_dir, join(self.test_dir, 'main.yaml'), None) self.assertTrue(runner.run_tests()) self.assertTrue(check_file(join(self.test_dir, 'one.output'), '-6278120581589537461'))
def test_read_simple_query(self): self.populate_file( 'test_inventory.yml', ''' mssql: dbname: tempdb user: sa password: Test1234 host: localhost port: 1433 ''') self.populate_file( 'main.yaml', '''--- steps: - mssql: request: conf: '{{ mssql }}' query: 'select count(*) from test' register: {documents: '{{ OUTPUT }}'} - check: equals: {the: '{{ documents }}', is: 2} ''') runner = Runner(self.test_dir, join(self.test_dir, 'main.yaml'), join(self.test_dir, 'test_inventory.yml')) self.assertTrue(runner.run_tests())
def test_post_from_file(self, m): m.post('http://test.com', text="loaded ok") self.populate_file( 'answers.json', ''' { "answers":[ {"id": 1,"response": true}, {"id": 2,"response": false}, {"id": 3,"response": true}, {"id": 4,"response": false}, {"id": 5,"response": true} ] } ''') self.populate_file( 'main.yaml', '''--- steps: - http: post: url: 'http://test.com' body_from_file: "''' + join(self.test_dir, 'answers.json') + '''" register: {reply: '{{ OUTPUT }}'} - check: equals: {the: '{{ reply }}', is: 'loaded ok'} ''') runner = Runner(self.test_dir, join(self.test_dir, 'main.yaml'), None) self.assertTrue(runner.run_tests())
def test_insert_many(self): self.populate_file( 'test_inventory.yml', ''' mongo: database: test username: test password: test host: localhost port: 27017 ''') self.populate_file( 'main.yaml', '''--- steps: - mongo: request: conf: '{{ mongo }}' collection: 'test' insert_many: - {'foo': 'baz'} - {'foo': 'bar'} ''') runner = Runner(self.test_dir, join(self.test_dir, 'main.yaml'), join(self.test_dir, 'test_inventory.yml')) self.assertTrue(runner.run_tests()) client = MongoClient(self.conf) db = client.get_database('test') collection = db.test cur = collection.find() docs = list(cur) # 0 index is a document from set_up self.assertEqual('baz', docs[1]['foo']) self.assertEqual('bar', docs[2]['foo'])
def test_read_simple_query(self): self.populate_file( 'test_inventory.yml', ''' mongo: database: test username: test password: test host: localhost port: 27017 ''') self.populate_file( 'main.yaml', '''--- steps: - mongo: request: conf: '{{ mongo }}' collection: 'test' command: 'find_one' register: {document: '{{ OUTPUT }}'} - check: equals: {the: '{{ document["msg"] }}', is: "one"} ''') runner = Runner(self.test_dir, join(self.test_dir, 'main.yaml'), join(self.test_dir, 'test_inventory.yml')) self.assertTrue(runner.run_tests())
def test_cmd_override_all(self): self.populate_file( 'inventory.yml', '''--- foo2: baz ''') self.populate_file( 'main.yaml', '''--- variables: foo: baz steps: - echo: actions: - {from: '{{ foo }}', to: one.output} - {from: '{{ foo2 }}', to: two.output} ''') runner = Runner(self.test_dir, join(self.test_dir, 'main.yaml'), join(self.test_dir, 'inventory.yml'), cmd_env={ 'foo': 'bad', 'foo2': 'bad' }) runner.run_tests() self.assertTrue(check_file(join(self.test_dir, 'one.output'), 'bad')) self.assertTrue(check_file(join(self.test_dir, 'two.output'), 'bad'))
def test_custom_functions_available(self): self.populate_file( 'custom_filter.py', '''def function_my_custom(): return {'key': 'value'} def function_my_other(input): return _not_a_fun(input) def _not_a_fun(arg): return 'to_str=' + str(arg) ''') self.populate_file( 'main.yaml', '''--- steps: - echo: {from: '{{ my_custom() }}', to: one.output} - echo: {from: '{{ my_other("test") }}', to: two.output} ''') runner = Runner(self.test_dir, join(self.test_dir, 'main.yaml'), None, filter_list=[join(self.test_dir, 'custom_filter.py')]) self.assertTrue(runner.run_tests()) self.assertTrue( check_file(join(self.test_dir, 'one.output'), "{'key': 'value'}")) self.assertTrue( check_file(join(self.test_dir, 'two.output'), 'to_str=test'))
def test_run_override_main(self): self.populate_file( 'main.yaml', '''--- variables: id: '{{ RANDOM_STR }}' include: - file: one.yaml as: one steps: - echo: {from: '{{ id }}', to: main.output} - run: include: one ''') self.populate_file( 'one.yaml', '''--- variables: id: 1234 steps: - echo: {from: '{{ id }}', to: one.output} ''') runner = Runner(self.test_dir, join(self.test_dir, 'main.yaml'), None) runner.run_tests() main = read_file(join(self.test_dir, 'main.output')) one = read_file(join(self.test_dir, 'one.output')) self.assertEqual(main, one) self.assertTrue(one)
def test_incr_decr_delete(self): self.populate_file( 'main.yaml', '''--- steps: - redis: actions: - request: set: foo: 11 - request: decr: 'foo' - request: get: 'foo' register: {var: '{{ OUTPUT }}'} - check: equals: {the: '{{ var }}', is: 10} - redis: actions: - request: incrby: foo: 5 - request: get: - foo register: {var: '{{ OUTPUT }}'} - check: equals: {the: '{{ var }}', is: 15} - redis: request: delete: foo ''') runner = Runner(self.test_dir, join(self.test_dir, 'main.yaml'), None) self.assertTrue(runner.run_tests()) r = redis.StrictRedis() self.assertIsNone(r.get('foo'))
def test_compose(self): self.populate_resource( 'docker-compose.yml', ''' version: '3.1' services: mockserver: image: jamesdbloom/mockserver ports: - "8000:1080" ''') self.populate_file( 'main.yaml', '''--- steps: - wait: seconds: 5 for: http: put: url: 'http://localhost:8000/mockserver/expectation' body: httpRequest: {'path': '/some/path'} httpResponse: {'body': 'hello world'} response_code: 201 - http: get: url: 'http://localhost:8000/mockserver/expectation', response_code: 200 ''') runner = Runner(self.test_dir, join(self.test_dir, 'main.yaml'), None, resources=join(test.get_test_dir(self.test_name), 'resources')) self.assertFalse(runner.run_tests())
def test_recursive_render_list(self): self.populate_file( 'main.yaml', '''--- steps: - wait: name: 'Waiting for postgres' seconds: 30 for: - echo: {from: '1', to: foo.output} - echo: {from: '2', to: foo.output} ''') runner = Runner(self.test_dir, join(self.test_dir, 'main.yaml'), None, output_format='json') self.assertTrue(runner.run_tests()) reports = [ f for f in listdir(join(self.test_dir, 'reports')) if isfile(join(self.test_dir, 'reports', f)) and f.startswith('report') ] self.assertEqual(1, len(reports)) with open(join(self.test_dir, 'reports', reports[0]), 'r') as fp: obj = json.load(fp) self.assertEqual(1, len(obj)) output = obj[0]['output'] steps = [o for o in output if 'step' in o] self.assertEqual('wait', list(steps[0]['step'].keys())[0]) self.assertEqual( 'echo', list(steps[0]['step']['wait']['for'][0].keys())[0]) self.assertEqual( 'echo', list(steps[0]['step']['wait']['for'][1].keys())[0])
def test_exec(self): self.populate_file( 'main.yaml', '''--- steps: - docker: start: image: 'postgres:11-alpine' environment: POSTGRES_PASSWORD: test POSTGRES_USER: user POSTGRES_DB: test register: {hash: '{{ OUTPUT }}'} - wait: seconds: 5 for: - docker: exec: hash: '{{ hash }}' cmd: > psql -U user -d test -c \ "CREATE TABLE test(rno integer, name character varying)" register: {create_result: '{{ OUTPUT.strip() }}'} - check: equals: {the: '{{ create_result }}', is: 'CREATE TABLE'} - docker: stop: hash: '{{ hash }}' ''') runner = Runner(self.test_dir, join(self.test_dir, 'main.yaml'), None) self.assertTrue(runner.run_tests())
def test_run_tagged_tagged(self): self.populate_file( 'main.yaml', '''--- include: file: one.yaml as: one steps: - run: 'one.before' ''') self.populate_file( 'one.yaml', '''--- include: file: two.yaml as: two steps: - run: include: two.one tag: before - echo: {from: '{{ bar }}', to: after.output, tag: after} ''') self.populate_file( 'two.yaml', '''--- steps: - echo: {from: '1', to: foo.output, tag: one} - echo: {from: '2', to: baz.output, tag: two} - echo: {from: '3', to: bar.output, tag: three} ''') runner = Runner(self.test_dir, join(self.test_dir, 'main.yaml'), None) runner.run_tests() self.assertTrue(check_file(join(self.test_dir, 'foo.output'), '1')) self.assertTrue(not os.path.exists(join(self.test_dir, 'baz.output'))) self.assertTrue(not os.path.exists(join(self.test_dir, 'bar.output')))
def test_vars_override_manual(self): self.populate_file('main.yaml', '''--- include: - one.yaml - file: two.yaml variables: one: override1 two: override2 ''') self.populate_file('one.yaml', '''--- variables: one: foo steps: - echo: {from: 'hello'} ''') self.populate_file('two.yaml', '''--- variables: two: bar steps: - echo: actions: - {from: '{{ one }}', to: one.output} - {from: '{{ two }}', to: two.output} ''') runner = Runner(self.test_dir, join(self.test_dir, 'main.yaml'), None) runner.run_tests() self.assertTrue(check_file(join(self.test_dir, 'one.output'), 'override1')) self.assertTrue(check_file(join(self.test_dir, 'two.output'), 'override2'))
def test_custom_filters_available(self): self.populate_file( 'custom_filter.py', '''def filter_increment(input): if isinstance(input, int): return input + 1 return 'not an int' def filter_to_string(input, arg='test'): return _not_a_fun(input) + ' ' + arg def _not_a_fun(arg): return 'to_str=' + str(arg) ''') self.populate_file( 'main.yaml', '''--- steps: - echo: {from: '{{ 221 | increment }}', to: one.output} - echo: {from: '{{ 221 | to_string("hello") }}', to: two.output} ''') runner = Runner(self.test_dir, join(self.test_dir, 'main.yaml'), None, filter_list=[join(self.test_dir, 'custom_filter.py')]) self.assertTrue(runner.run_tests()) self.assertTrue(check_file(join(self.test_dir, 'one.output'), '222')) self.assertTrue( check_file(join(self.test_dir, 'two.output'), 'to_str=221 hello'))
def test_register_run_tags_with_dot(self): self.populate_file( 'main.yaml', '''--- include: file: simple_file.yaml as: simple.with_dot steps: - run: include: 'simple.with_dot' tag: one ''') self.populate_file( 'simple_file.yaml', '''--- variables: foo: 1 baz: 2 bar: 3 steps: - echo: {from: '{{ foo }}', to: foo.output, tag: one} - echo: {from: '{{ baz }}', to: baz.output} - echo: {from: '{{ bar }}', to: bar.output, tag: one} ''') runner = Runner(self.test_dir, join(self.test_dir, 'main.yaml'), None) runner.run_tests() self.assertTrue(check_file(join(self.test_dir, 'foo.output'), '1')) self.assertTrue(not os.path.exists(join(self.test_dir, 'baz.output'))) self.assertTrue(check_file(join(self.test_dir, 'bar.output'), '3'))
def test_var_in_run_as_obj(self): self.populate_resource( 'test.csv', "email,id\n" "{%- for user in users %}\n" "{{ user.email }},{{ user.id }}\n" "{%- endfor -%}") self.populate_file( 'main.yaml', '''--- variables: users: - email: '*****@*****.**' id: 1 - email: '*****@*****.**' id: 2 include: file: one.yaml as: one steps: - run: include: 'one' variables: users: '{{ users[:1] }}' ''') self.populate_file( 'one.yaml', '''--- steps: - echo: {from_file: 'test.csv', to: res.output} ''') runner = Runner(self.test_dir, join(self.test_dir, 'main.yaml'), None) runner.run_tests() self.assertTrue( check_file(join(self.test_dir, 'res.output'), 'email,id\[email protected],1'))
def test_run_from_template(self): self.populate_file( 'main.yaml', '''--- include: - file: one.yaml as: one - file: two.yaml as: two - file: determine_include.yaml as: determine_include steps: - run: 'determine_include' - run: '{{ include }}' ''') self.populate_file( 'one.yaml', '''--- steps: - echo: {from: 'bar', to: foo.output} ''') self.populate_file( 'two.yaml', '''--- steps: - echo: {from: 'baz', to: foo.output} ''') self.populate_file( 'determine_include.yaml', '''--- steps: - echo: {from: 'hello', register: {include: one}} ''') runner = Runner(self.test_dir, join(self.test_dir, 'main.yaml'), None) runner.run_tests() self.assertTrue(check_file(join(self.test_dir, 'foo.output'), 'bar')) self.assertTrue(not os.path.exists(join(self.test_dir, 'baz.output')))
def test_chaining(self): self.populate_file( 'test_inventory.yml', ''' mongo: database: test username: test password: test host: localhost port: 27017 ''') self.populate_file( 'main.yaml', '''--- steps: - mongo: actions: - request: conf: '{{ mongo }}' collection: 'test' insert_many: - {'author': 'Mike', 'text': 'post1'} - {'author': 'Bob', 'text': 'post1'} - {'author': 'Mike', 'text': 'post2'} - request: conf: '{{ mongo }}' collection: 'test' find: {'author': 'Mike'} next: 'count' register: {posts_num: '{{ OUTPUT }}'} - check: equals: {the: '{{ posts_num }}', is: 2} ''') runner = Runner(self.test_dir, join(self.test_dir, 'main.yaml'), join(self.test_dir, 'test_inventory.yml')) self.assertTrue(runner.run_tests())
def test_trigger_dag_with_dag_config(self): """ Catcher's Airflow step should be able to trigger dag with a specific execution date """ execution_date = datetime(2020, 3, 18, 0, 59, 59) airflow_url = 'http://127.0.0.1:8080' self.dag_id = 'hello_world' self.populate_file('test_inventory_2.yml', f''' postgres_conf_2: url: 'test:test@localhost:5433/test' type: postgres airflow: url: '{airflow_url}' type: 'http' ''') self.populate_file('main_2.yaml', f'''--- steps: - airflow: run: config: db_conf: '{{{{ postgres_conf_2 }}}}' url: '{{{{ airflow.url }}}}' populate_connections: true fernet_key: zp8kV516l9tKzqq9pJ2Y6cXbM3bgEWIapGwzQs6jio4= dag_config: execution_date: '{str(execution_date)}' dag_id: '{self.dag_id}' sync: true wait_timeout: 50 ''') runner = Runner(self.test_dir, join(self.test_dir, 'main_2.yaml'), join(self.test_dir, 'test_inventory_2.yml')) self.assertTrue(runner.run_tests())
def test_write_simple_query(self): self.populate_file( 'test_inventory.yml', ''' mongo: database: test username: test password: test host: localhost port: 27017 ''') self.populate_file( 'main.yaml', '''--- steps: - mongo: request: conf: '{{ mongo }}' collection: 'test' insert_one: 'author': 'Mike' 'text': 'My first blog post!' 'tags': ['mongodb', 'python', 'pymongo'] 'date': '{{ NOW_DT }}' register: {id: '{{ OUTPUT }}'} ''') runner = Runner(self.test_dir, join(self.test_dir, 'main.yaml'), join(self.test_dir, 'test_inventory.yml')) self.assertTrue(runner.run_tests()) client = MongoClient(self.conf) db = client.get_database('test') collection = db.test d = collection.find_one({'author': 'Mike'}) self.assertEqual('My first blog post!', d['text']) self.assertEqual(['mongodb', 'python', 'pymongo'], d['tags'])
def test_consume_with_filter(self): self.produce_message({ 'id': 'uuid1', 'name': 'foo' }, 'test_consume_with_filter') self.produce_message({ 'id': 'uuid2', 'name': 'baz' }, 'test_consume_with_filter') self.produce_message({ 'id': 'uuid3', 'name': 'bar' }, 'test_consume_with_filter') self.produce_message({ 'id': 'uuid4', 'name': 'baf' }, 'test_consume_with_filter') self.populate_file( 'main.yaml', '''--- steps: - kafka: consume: server: '127.0.0.1:9092' topic: 'test_consume_with_filter' where: equals: {the: '{{ MESSAGE.id }}', is: 'uuid3'} register: {user: '******'} - check: equals: {the: '{{ user.name }}', is: 'bar'} ''') runner = Runner(self.test_dir, join(self.test_dir, 'main.yaml'), None) self.assertTrue(runner.run_tests())
def test_python_module_with_json(self): self.write_module( 'print.py', '''from catcher.steps.external_step import ExternalStep from catcher.steps.step import update_variables class Print(ExternalStep): @update_variables def action(self, includes: dict, variables: dict) -> (dict, str): body = self.simple_input(variables) data = body['the'] return variables, 'data is: {}'.format(data) ''') self.populate_file( 'inventory.yml', '''--- complex_conf: field: 'value' json_field: '{"host": "http://minio:9000","aws_access_key_id":"minio","aws_secret_access_key":"minio123"}' ''') self.populate_file( 'main.yaml', '''--- steps: - print: the: '{{ complex_conf }}' ''') load_external_actions(join(self.test_dir, 'print.py')) runner = Runner(self.test_dir, join(self.test_dir, 'main.yaml'), join(self.test_dir, 'inventory.yml'), modules=[self.test_dir]) self.assertTrue(runner.run_tests())
def test_consume_with_timestamp(self): self.produce_message({ 'id': 'uuid1', 'timestamp': 1234 }, 'test_consume_with_timestamp') self.produce_message({ 'id': 'uuid2', 'timestamp': 1235 }, 'test_consume_with_timestamp') self.populate_file( 'main.yaml', '''--- steps: - kafka: consume: server: '127.0.0.1:9092' topic: 'test_consume_with_timestamp' where: equals: '{{ MESSAGE.timestamp > 1000 }}' register: {uuid: '{{ OUTPUT.id }}'} - check: equals: {the: '{{ uuid }}', is: 'uuid1'} - kafka: consume: server: '127.0.0.1:9092' topic: 'test_consume_with_timestamp' where: equals: '{{ MESSAGE.timestamp > 1000 }}' register: {uuid: '{{ OUTPUT.id }}'} - check: equals: {the: '{{ uuid }}', is: 'uuid2'} ''') runner = Runner(self.test_dir, join(self.test_dir, 'main.yaml'), None) self.assertTrue(runner.run_tests())
def test_populate_int(self): self.populate_file( 'resources/schema.sql', ''' CREATE TABLE foo( user_id integer primary key, email varchar(36) NOT NULL ); ''') self.populate_file( 'resources/foo.csv', "user_id,email\n" "1,[email protected]\n" "2,[email protected]\n") self.populate_file( 'main.yaml', '''--- steps: - prepare: populate: mssql: conf: 'sa:Test1234@localhost:1433/tempdb?driver=ODBC+Driver+17+for+SQL+Server' schema: schema.sql data: foo: foo.csv ''') runner = Runner(self.test_dir, join(self.test_dir, 'main.yaml'), None) self.assertTrue(runner.run_tests()) response = self.get_values('foo') self.assertEqual(2, len(response)) self.assertEqual(1, response[0][0]) self.assertEqual('*****@*****.**', response[0][1]) self.assertEqual(2, response[1][0]) self.assertEqual('*****@*****.**', response[1][1])
def test_different_configurations(self): self.populate_file( 'test_inventory.yml', ''' mongo_object: database: test username: test password: test host: localhost port: 27017 type: mongo mongo_string: 'mongodb://*****:*****@localhost:27017' mongo_object_string: url: 'mongodb://*****:*****@localhost:27017' type: mongo ''') self.populate_file( 'main.yaml', '''--- steps: - loop: foreach: in: '[{{ mongo_object }}, "{{ mongo_string }}", {{ mongo_object_string }}]' do: - mongo: request: conf: '{{ ITEM }}' collection: 'test' command: 'find_one' register: {document: '{{ OUTPUT }}'} - check: equals: {the: '{{ document["msg"] }}', is: "one"} ''') runner = Runner(self.test_dir, join(self.test_dir, 'main.yaml'), join(self.test_dir, 'test_inventory.yml')) self.assertTrue(runner.run_tests())
def run_tests(path: str, arguments: dict): file_or_dir = arguments['<tests>'] inventory = arguments['--inventory'] environment = arguments['--environment'] modules = arguments['--modules'] resources = arguments['--resources'] output_format = arguments['--format'] filters = arguments['--filter'] use_sys_vars = arguments['--system_env'] output = 'full' if not arguments['--q'] else 'limited' if arguments['--qq']: output = 'final' if use_sys_vars: sys_vars = dict(os.environ) else: sys_vars = None __load_modules(modules) runner = Runner(path, file_or_dir, inventory, modules=modules, cmd_env=__env_to_variables(environment), resources=resources, system_environment=sys_vars, output_format=output_format, filter_list=filters) return runner.run_tests(output=output)
def test_template_in_template_resource(self, m): self.populate_file( 'main.yaml', '''--- variables: bar: '{{ RANDOM_STR }}' include: - file: one.yaml as: one steps: - echo: {from: '{{ bar }}', to: main.output} - run: one ''') self.populate_file( 'one.yaml', '''--- variables: foo: '{{ bar }}' steps: - http: post: url: 'http://test.com' files: file: 'foo.json' ''') self.populate_resource('foo.json', "{\"key\":\"{{ foo }}\"}") adapter = m.post('http://test.com') runner = Runner(self.test_dir, join(self.test_dir, 'main.yaml'), None) self.assertTrue(runner.run_tests()) main = read_file(join(self.test_dir, 'main.output')) self.assertTrue("{\"key\":\"" + main + "\"}" in adapter.last_request.text)