def test_roles_edit_unauthorized(app, viewer_client, non_exist_role_name, exist_role_name, exist_role): resp = viewer_client.post( f"roles/edit/{exist_role.id}", data={'name': non_exist_role_name}, follow_redirects=True ) check_content_in_response('Access is Denied', resp) assert app.appbuilder.sm.find_role(exist_role_name) assert app.appbuilder.sm.find_role(non_exist_role_name) is None
def test_get_logs_with_metadata_success(request, client): resp = request.getfixturevalue(client).get( GET_LOGS_WITH_METADATA_URL, follow_redirects=True, ) check_content_in_response('"message":', resp) check_content_in_response('"metadata":', resp)
def test_trigger_dag_params_conf(admin_client, request_conf, expected_conf): """ Test that textarea in Trigger DAG UI is pre-populated with json config when the conf URL parameter is passed, or if a params dict is passed in the DAG 1. Conf is not included in URL parameters -> DAG.conf is in textarea 2. Conf is passed as a URL parameter -> passed conf json is in textarea """ test_dag_id = "example_bash_operator" doc_md = "Example Bash Operator" if not request_conf: resp = admin_client.get(f'trigger?dag_id={test_dag_id}') else: test_request_conf = json.dumps(request_conf, indent=4) resp = admin_client.get( f'trigger?dag_id={test_dag_id}&conf={test_request_conf}&doc_md={doc_md}' ) expected_dag_conf = json.dumps(expected_conf, indent=4).replace("\"", """) check_content_in_response( f'<textarea class="form-control" name="conf" id="json">{expected_dag_conf}</textarea>', resp, )
def test_code_from_db(admin_client): dag = DagBag(include_examples=True).get_dag("example_bash_operator") DagCode(dag.fileloc, DagCode._get_code_from_file(dag.fileloc)).sync_to_db() url = 'code?dag_id=example_bash_operator' resp = admin_client.get(url) check_content_not_in_response('Failed to load file', resp) check_content_in_response('example_bash_operator', resp)
def test_odd_name(session, admin_client, pool): pool['pool'] = 'test-pool<script></script>' session.add(Pool(**pool)) session.commit() resp = admin_client.get('/pool/list/') check_content_in_response('test-pool<script>', resp) check_content_not_in_response('test-pool<script>', resp)
def test_run_with_not_runnable_states(_, admin_client, session, state): assert state not in RUNNABLE_STATES task_id = 'runme_0' session.query(TaskInstance).filter(TaskInstance.task_id == task_id).update( { 'state': state, 'end_date': timezone.utcnow() }) session.commit() form = dict( task_id=task_id, dag_id="example_bash_operator", ignore_all_deps="false", ignore_ti_state="false", execution_date=DEFAULT_DATE, origin='/home', ) resp = admin_client.post('run', data=form, follow_redirects=True) check_content_in_response('', resp) msg = ( f"Task is in the '{state}' state which is not a valid state for " f"execution. The task must be cleared in order to be run") assert re.search(msg, resp.get_data(as_text=True))
def test_page_instance_name_xss_prevention(admin_client): xss_string = "<script>alert('Give me your credit card number')</script>" with conf_vars({('webserver', 'instance_name'): xss_string}): resp = admin_client.get('home', follow_redirects=True) escaped_xss_string = "<script>alert('Give me your credit card number')</script>" check_content_in_response(escaped_xss_string, resp) check_content_not_in_response(xss_string, resp)
def test_delete_user(app, admin_client, exist_username): user = app.appbuilder.sm.find_user(exist_username) resp = admin_client.post( f"users/delete/{user.id}", follow_redirects=True, ) check_content_in_response("Deleted Row", resp)
def test_edit_myuserinfo(admin_client): resp = admin_client.post( "userinfoeditview/form", data={'first_name': 'new_first_name', 'last_name': 'new_last_name'}, follow_redirects=True, ) check_content_in_response("User information changed", resp)
def test_dag_autocomplete_success(client_all_dags): resp = client_all_dags.get( 'dagmodel/autocomplete?query=example_bash', follow_redirects=False, ) check_content_in_response('example_bash_operator', resp) check_content_not_in_response('example_subdag_operator', resp)
def test_configuration_expose_config(admin_client): # make sure config is initialized (without unit test mote) initialize_config() with conf_vars({('webserver', 'expose_config'): 'True'}): resp = admin_client.get('configuration', follow_redirects=True) check_content_in_response( ['Airflow Configuration', 'Running Configuration'], resp)
def test_redoc_should_render_template(capture_templates, admin_client): with capture_templates() as templates: resp = admin_client.get('redoc') check_content_in_response('Redoc', resp) assert len(templates) == 1 assert templates[0].name == 'airflow/redoc.html' assert templates[0].local_context == {'openapi_spec_url': '/api/v1/openapi.yaml'}
def test_create_pool_with_same_name(admin_client, pool): # create test pool resp = admin_client.post('/pool/add', data=pool, follow_redirects=True) check_content_in_response('Added Row', resp) # create pool with the same name resp = admin_client.post('/pool/add', data=pool, follow_redirects=True) check_content_in_response('Already exists.', resp)
def test_trigger_endpoint_uses_existing_dagbag(admin_client): """ Test that Trigger Endpoint uses the DagBag already created in views.py instead of creating a new one. """ url = 'trigger?dag_id=example_bash_operator' resp = admin_client.post(url, data={}, follow_redirects=True) check_content_in_response('example_bash_operator', resp)
def test_edit_user(app, admin_client, exist_username): user = app.appbuilder.sm.find_user(exist_username) resp = admin_client.post( f"users/edit/{user.id}", data={"first_name": "new_first_name"}, follow_redirects=True, ) check_content_in_response("new_first_name", resp)
def test_create_pool_with_empty_name(admin_client): resp = admin_client.post( '/pool/add', data={ **POOL, "pool": "" }, follow_redirects=True, ) check_content_in_response('This field is required.', resp)
def test_calendar(admin_client, dagruns): url = 'calendar?dag_id=example_bash_operator' resp = admin_client.get(url, follow_redirects=True) bash_dagrun, _, _ = dagruns datestr = bash_dagrun.execution_date.date().isoformat() expected = rf'{{\"date\":\"{datestr}\",\"state\":\"running\",\"count\":1}}' check_content_in_response(expected, resp)
def test_delete_dag_button_for_dag_on_scheduler_only( admin_client, new_id_example_bash_operator): # Test for JIRA AIRFLOW-3233 (PR 4069): # The delete-dag URL should be generated correctly for DAGs # that exist on the scheduler (DB) but not the webserver DagBag test_dag_id = new_id_example_bash_operator resp = admin_client.get('/', follow_redirects=True) check_content_in_response(f'/delete?dag_id={test_dag_id}', resp) check_content_in_response( f"return confirmDeleteDag(this, '{test_dag_id}')", resp)
def test_import_variables_success(session, admin_client): assert session.query(Variable).count() == 0 content = '{"str_key": "str_value", "int_key": 60, "list_key": [1, 2], "dict_key": {"k_a": 2, "k_b": 3}}' bytes_content = io.BytesIO(bytes(content, encoding='utf-8')) resp = admin_client.post('/variable/varimport', data={'file': (bytes_content, 'test.json')}, follow_redirects=True) check_content_in_response('4 variable(s) successfully updated.', resp)
def test_set_dag_runs_action_fails(admin_client, action, expected_message): resp = admin_client.post( "/dagrun/action_post", data={ "action": action, "rowid": ["0"] }, follow_redirects=True, ) check_content_in_response(expected_message, resp)
def test_doc_urls(admin_client): resp = admin_client.get('/', follow_redirects=True) if "dev" in version.version: airflow_doc_site = ( "http://apache-airflow-docs.s3-website.eu-central-1.amazonaws.com/docs/apache-airflow/" ) else: airflow_doc_site = f'https://airflow.apache.org/docs/apache-airflow/{version.version}' check_content_in_response(airflow_doc_site, resp) check_content_in_response("/api/v1/ui", resp)
def test_trigger_dag_form_origin_url(admin_client, test_origin, expected_origin): test_dag_id = "example_bash_operator" resp = admin_client.get( f'trigger?dag_id={test_dag_id}&origin={test_origin}') check_content_in_response( '<button type="button" class="btn" onclick="location.href = \'{}\'; return false">' .format(expected_origin), resp, )
def test_code_no_file(admin_client): url = 'code?dag_id=example_bash_operator' mock_open_patch = unittest.mock.mock_open(read_data='') mock_open_patch.side_effect = FileNotFoundError with unittest.mock.patch('builtins.open', mock_open_patch), unittest.mock.patch( "airflow.models.dagcode.STORE_DAG_CODE", False): resp = admin_client.get(url, follow_redirects=True) check_content_in_response('Failed to load file', resp) check_content_in_response('example_bash_operator', resp)
def test_trigger_dag_conf_malformed(admin_client): test_dag_id = "example_bash_operator" response = admin_client.post(f'trigger?dag_id={test_dag_id}', data={'conf': '{"a": "b"'}) check_content_in_response('Invalid JSON configuration', response) with create_session() as session: run = session.query(DagRun).filter( DagRun.dag_id == test_dag_id).first() assert run is None
def test_configuration_do_not_expose_config(admin_client): with conf_vars({('webserver', 'expose_config'): 'False'}): resp = admin_client.get('configuration', follow_redirects=True) check_content_in_response( [ 'Airflow Configuration', '# Your Airflow administrator chose not to expose the configuration, ' 'most likely for security reasons.', ], resp, )
def test_task_instance_set_state_failure(admin_client, action): rowid = '["12345"]' # F.A.B. crashes if the rowid is *too* invalid. resp = admin_client.post( "/taskinstance/action_post", data={ "action": action, "rowid": rowid }, follow_redirects=True, ) assert resp.status_code == 200 check_content_in_response("Failed to set state", resp)
def test_escape_in_tree_view(app, admin_client, test_str, expected_text): app.dag_bag.get_dag('test_tree_view').create_dagrun( execution_date=DEFAULT_DATE, start_date=timezone.utcnow(), run_type=DagRunType.MANUAL, state=State.RUNNING, conf={"abc": test_str}, ) url = 'tree?dag_id=test_tree_view' resp = admin_client.get(url, follow_redirects=True) check_content_in_response(expected_text, resp)
def test_failed_success(client_all_dags_edit_tis): form = dict( task_id="run_this_last", dag_id="example_bash_operator", execution_date=DEFAULT_DATE, upstream="false", downstream="false", future="false", past="false", ) resp = client_all_dags_edit_tis.post('failed', data=form) check_content_in_response('example_bash_operator', resp)
def test_import_variables_failed(session, admin_client): content = '{"str_key": "str_value"}' with mock.patch('airflow.models.Variable.set') as set_mock: set_mock.side_effect = UnicodeEncodeError assert session.query(Variable).count() == 0 bytes_content = io.BytesIO(bytes(content, encoding='utf-8')) resp = admin_client.post('/variable/varimport', data={'file': (bytes_content, 'test.json')}, follow_redirects=True) check_content_in_response('1 variable(s) failed to be updated.', resp)
def test_pool_muldelete_default(session, admin_client, pool_factory): pool = pool_factory(pool="default_pool") resp = admin_client.post( "/pool/action_post", data={ "action": "muldelete", "rowid": [pool.id] }, follow_redirects=True, ) check_content_in_response("default_pool cannot be deleted", resp) assert session.query(Pool).filter(Pool.id == pool.id).count() == 1