blob: 7a585b59022c42d056c353798e315af2583128bd [file]
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
from __future__ import annotations
import ast
import os
import pytest
from airflow import DAG
from airflow.models import DagBag
from airflow.security import permissions
from tests.test_utils.api_connexion_utils import assert_401, create_user, delete_user
from tests.test_utils.db import clear_db_dag_code, clear_db_dags, clear_db_serialized_dags
ROOT_DIR = os.path.abspath(os.path.join(os.path.dirname(__file__), os.pardir, os.pardir))
EXAMPLE_DAG_FILE = os.path.join("airflow", "example_dags", "example_bash_operator.py")
@pytest.fixture(scope="module")
def configured_app(minimal_app_for_api):
app = minimal_app_for_api
create_user(
app, # type:ignore
username="test",
role_name="Test",
permissions=[(permissions.ACTION_CAN_READ, permissions.RESOURCE_DAG_CODE)], # type: ignore
)
create_user(app, username="test_no_permissions", role_name="TestNoPermissions") # type: ignore
yield app
delete_user(app, username="test") # type: ignore
delete_user(app, username="test_no_permissions") # type: ignore
class TestGetSource:
@pytest.fixture(autouse=True)
def setup_attrs(self, configured_app) -> None:
self.app = configured_app
self.client = self.app.test_client() # type:ignore
self.clear_db()
def teardown_method(self) -> None:
self.clear_db()
@staticmethod
def clear_db():
clear_db_dags()
clear_db_serialized_dags()
clear_db_dag_code()
@staticmethod
def _get_dag_file_docstring(fileloc: str) -> str | None:
with open(fileloc) as f:
file_contents = f.read()
module = ast.parse(file_contents)
docstring = ast.get_docstring(module)
return docstring
def test_should_respond_200_text(self, url_safe_serializer):
dagbag = DagBag(dag_folder=EXAMPLE_DAG_FILE)
dagbag.sync_to_db()
first_dag: DAG = next(iter(dagbag.dags.values()))
dag_docstring = self._get_dag_file_docstring(first_dag.fileloc)
url = f"/api/v1/dagSources/{url_safe_serializer.dumps(first_dag.fileloc)}"
response = self.client.get(
url, headers={"Accept": "text/plain"}, environ_overrides={"REMOTE_USER": "test"}
)
assert 200 == response.status_code
assert dag_docstring in response.data.decode()
assert "text/plain" == response.headers["Content-Type"]
def test_should_respond_200_json(self, url_safe_serializer):
dagbag = DagBag(dag_folder=EXAMPLE_DAG_FILE)
dagbag.sync_to_db()
first_dag: DAG = next(iter(dagbag.dags.values()))
dag_docstring = self._get_dag_file_docstring(first_dag.fileloc)
url = f"/api/v1/dagSources/{url_safe_serializer.dumps(first_dag.fileloc)}"
response = self.client.get(
url, headers={"Accept": "application/json"}, environ_overrides={"REMOTE_USER": "test"}
)
assert 200 == response.status_code
assert dag_docstring in response.json["content"]
assert "application/json" == response.headers["Content-Type"]
def test_should_respond_406(self, url_safe_serializer):
dagbag = DagBag(dag_folder=EXAMPLE_DAG_FILE)
dagbag.sync_to_db()
first_dag: DAG = next(iter(dagbag.dags.values()))
url = f"/api/v1/dagSources/{url_safe_serializer.dumps(first_dag.fileloc)}"
response = self.client.get(
url, headers={"Accept": "image/webp"}, environ_overrides={"REMOTE_USER": "test"}
)
assert 406 == response.status_code
def test_should_respond_404(self):
wrong_fileloc = "abcd1234"
url = f"/api/v1/dagSources/{wrong_fileloc}"
response = self.client.get(
url, headers={"Accept": "application/json"}, environ_overrides={"REMOTE_USER": "test"}
)
assert 404 == response.status_code
def test_should_raises_401_unauthenticated(self, url_safe_serializer):
dagbag = DagBag(dag_folder=EXAMPLE_DAG_FILE)
dagbag.sync_to_db()
first_dag: DAG = next(iter(dagbag.dags.values()))
response = self.client.get(
f"/api/v1/dagSources/{url_safe_serializer.dumps(first_dag.fileloc)}",
headers={"Accept": "text/plain"},
)
assert_401(response)
def test_should_raise_403_forbidden(self, url_safe_serializer):
dagbag = DagBag(dag_folder=EXAMPLE_DAG_FILE)
dagbag.sync_to_db()
first_dag: DAG = next(iter(dagbag.dags.values()))
response = self.client.get(
f"/api/v1/dagSources/{url_safe_serializer.dumps(first_dag.fileloc)}",
headers={"Accept": "text/plain"},
environ_overrides={"REMOTE_USER": "test_no_permissions"},
)
assert response.status_code == 403