From dc57add93cfb1e4104ab94b24ba14f536cdda275 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jos=C3=A9=20Pacheco?= <pachewise@gmail.com>
Date: Mon, 24 Feb 2025 18:04:50 -0500
Subject: [PATCH] add tests; thanks @OverkillGuy for the initial tests

---
 docs/en/docs/advanced/security/api-key.md     |  2 +-
 docs_src/security/tutorial008.py              |  5 +-
 docs_src/security/tutorial009.py              |  6 +-
 docs_src/security/tutorial010.py              |  6 +-
 .../test_security/test_tutorial008.py         | 63 +++++++++++++++++++
 .../test_security/test_tutorial009.py         | 62 ++++++++++++++++++
 .../test_security/test_tutorial010.py         | 61 ++++++++++++++++++
 7 files changed, 201 insertions(+), 4 deletions(-)
 create mode 100644 tests/test_tutorial/test_security/test_tutorial008.py
 create mode 100644 tests/test_tutorial/test_security/test_tutorial009.py
 create mode 100644 tests/test_tutorial/test_security/test_tutorial010.py

diff --git a/docs/en/docs/advanced/security/api-key.md b/docs/en/docs/advanced/security/api-key.md
index 70012c42e..dd1abc31c 100644
--- a/docs/en/docs/advanced/security/api-key.md
+++ b/docs/en/docs/advanced/security/api-key.md
@@ -62,5 +62,5 @@ Again, similar to the approaches above, except we use `APIKeyQuery`:
 The client will then need to pass in the key as part of the query param:
 
 ```http
-GET /secure-data?api_key=mysecretapikey HTTP/1.1
+GET /secure-data?x-api-key=mysecretapikey HTTP/1.1
 ```
diff --git a/docs_src/security/tutorial008.py b/docs_src/security/tutorial008.py
index 282d8675a..9e6c413d2 100644
--- a/docs_src/security/tutorial008.py
+++ b/docs_src/security/tutorial008.py
@@ -6,7 +6,10 @@ from fastapi.security.api_key import APIKeyHeader
 API_KEY = "mysecretapikey"
 
 API_KEY_NAME = "X-API-Key"
-api_key_header = APIKeyHeader(name=API_KEY_NAME)
+api_key_header = APIKeyHeader(
+    name=API_KEY_NAME,
+    description="API Key required to access secure endpoints.",
+)
 
 def verify_api_key(api_key: str = Depends(api_key_header)):
     if api_key != API_KEY:
diff --git a/docs_src/security/tutorial009.py b/docs_src/security/tutorial009.py
index 03297f923..857d6c1c6 100644
--- a/docs_src/security/tutorial009.py
+++ b/docs_src/security/tutorial009.py
@@ -7,7 +7,11 @@ app = FastAPI()
 # or stored in a secure DB.
 API_KEY = "mysecretapikey"
 
-api_key_cookie = APIKeyCookie(name="X-API-KEY") # case-sensitive!
+API_KEY_NAME = "X-API-KEY" # case-sensitive!
+api_key_cookie = APIKeyCookie(
+    name=API_KEY_NAME,
+    description="API Key required to access secure endpoints.",
+)
 
 
 def verify_api_key(api_key: str = Depends(api_key_cookie)):
diff --git a/docs_src/security/tutorial010.py b/docs_src/security/tutorial010.py
index 9b04b2ce6..107a8d6cb 100644
--- a/docs_src/security/tutorial010.py
+++ b/docs_src/security/tutorial010.py
@@ -7,7 +7,11 @@ app = FastAPI()
 # or stored in a secure DB.
 API_KEY = "mysecretapikey"
 
-api_key_query = APIKeyQuery(name="api_key") # Note you have to use underscores
+API_KEY_NAME = "x-api-key"
+api_key_query = APIKeyQuery(
+    name=API_KEY_NAME,
+    description="API Key required to access secure endpoints.",
+)
 
 
 def verify_api_key(api_key: str = Depends(api_key_query)):
diff --git a/tests/test_tutorial/test_security/test_tutorial008.py b/tests/test_tutorial/test_security/test_tutorial008.py
new file mode 100644
index 000000000..dd2a0b4d4
--- /dev/null
+++ b/tests/test_tutorial/test_security/test_tutorial008.py
@@ -0,0 +1,63 @@
+from fastapi.testclient import TestClient
+
+from docs_src.security.tutorial008 import app
+
+client = TestClient(app)
+
+openapi_schema = {
+    "openapi": "3.1.0",
+    "info": {"title": "FastAPI", "version": "0.1.0"},
+    "paths": {
+        "/secure-data": {
+            "get": {
+                "summary": "Secure Endpoint",
+                "operationId": "secure_endpoint_secure_data_get",
+                "responses": {
+                    "200": {
+                        "description": "Successful Response",
+                        "content": {"application/json": {"schema": {}}},
+                    }
+                },
+                "security": [{"APIKeyHeader": []}],
+            }
+        }
+    },
+    "components": {
+        "securitySchemes": {
+            "APIKeyHeader": {
+                "type": "apiKey",
+                "description": "API Key required to access secure endpoints.",
+                "in": "header",
+                "name": "X-API-Key",
+            }
+        }
+    },
+}
+
+
+def test_openapi_schema():
+    response = client.get("/openapi.json")
+    assert response.status_code == 200, response.text
+    assert response.json() == openapi_schema
+
+
+def test_apikey_header():
+    auth = {"X-API-KEY": "mysecretapikey"}
+    response = client.get("/secure-data", headers=auth)
+    assert response.status_code == 200, response.text
+    assert response.json() == {"message": "You have access to secure data"}
+
+
+def test_apikey_header_no_credentials():
+    response = client.get("/secure-data", headers={})
+    # TODO: this should be 401 in the implementation! discuss with @tiangolo et al
+    assert response.status_code == 403, response.text
+    assert response.json() == {"detail": "Not authenticated"}
+
+
+
+def test_apikey_header_invalid_credentials():
+    auth = {"X-API-KEY": "totally-wrong-api-key"}
+    response = client.get("/secure-data", headers=auth)
+    assert response.status_code == 401, response.text
+    assert response.json() == {"detail": "Invalid API Key"}
diff --git a/tests/test_tutorial/test_security/test_tutorial009.py b/tests/test_tutorial/test_security/test_tutorial009.py
new file mode 100644
index 000000000..0c429338e
--- /dev/null
+++ b/tests/test_tutorial/test_security/test_tutorial009.py
@@ -0,0 +1,62 @@
+from fastapi.testclient import TestClient
+
+from docs_src.security.tutorial009 import app
+
+
+openapi_schema = {
+    "openapi": "3.1.0",
+    "info": {"title": "FastAPI", "version": "0.1.0"},
+    "paths": {
+        "/secure-data": {
+            "get": {
+                "summary": "Secure Endpoint",
+                "operationId": "secure_endpoint_secure_data_get",
+                "responses": {
+                    "200": {
+                        "description": "Successful Response",
+                        "content": {"application/json": {"schema": {}}},
+                    }
+                },
+                "security": [{"APIKeyCookie": []}],
+            },
+        },
+    },
+    "components": {
+        "securitySchemes": {
+            "APIKeyCookie": {
+                "type": "apiKey",
+                "name": "X-API-KEY",
+                "description": "API Key required to access secure endpoints.",
+                "in": "cookie",
+            },
+        },
+    },
+}
+
+
+def test_openapi_schema():
+    client = TestClient(app, cookies={"X-API-KEY": "mysecretapikey"})
+    response = client.get("/openapi.json")
+    assert response.status_code == 200, response.text
+    assert response.json() == openapi_schema
+
+
+def test_apikey_cookie():
+    client = TestClient(app, cookies={"X-API-KEY": "mysecretapikey"})
+    response = client.get("/secure-data")
+    assert response.status_code == 200, response.text
+    assert response.json() == {"message": "You have access to secure data"}
+
+
+def test_apikey_cookie_no_key():
+    client = TestClient(app)
+    response = client.get("/secure-data")
+    # TODO: this should be 401 in the implementation! discuss with @tiangolo et al
+    assert response.status_code == 403, response.text
+    assert response.json() == {"detail": "Not authenticated"}
+
+def test_apikey_cookie_invalid_key():
+    client = TestClient(app, cookies={"X-API-KEY": "wrongkey"})
+    response = client.get("/secure-data")
+    assert response.status_code == 401, response.text
+    assert response.json() == {"detail": "Invalid API Key"}
diff --git a/tests/test_tutorial/test_security/test_tutorial010.py b/tests/test_tutorial/test_security/test_tutorial010.py
new file mode 100644
index 000000000..cb519a5fd
--- /dev/null
+++ b/tests/test_tutorial/test_security/test_tutorial010.py
@@ -0,0 +1,61 @@
+from fastapi.testclient import TestClient
+
+from docs_src.security.tutorial010 import app
+
+
+client = TestClient(app)
+
+openapi_schema = {
+    "openapi": "3.1.0",
+    "info": {"title": "FastAPI", "version": "0.1.0"},
+    "paths": {
+        "/secure-data": {
+            "get": {
+                "summary": "Secure Endpoint",
+                "operationId": "secure_endpoint_secure_data_get",
+                "responses": {
+                    "200": {
+                        "description": "Successful Response",
+                        "content": {"application/json": {"schema": {}}},
+                    }
+                },
+                "security": [{"APIKeyQuery": []}],
+            },
+        },
+    },
+    "components": {
+        "securitySchemes": {
+            "APIKeyQuery": {
+                "type": "apiKey",
+                "name": "x-api-key",
+                "description": "API Key required to access secure endpoints.",
+                "in": "query",
+            },
+        },
+    },
+}
+
+
+def test_openapi_schema():
+    response = client.get("/openapi.json")
+    assert response.status_code == 200, response.text
+    assert response.json() == openapi_schema
+
+
+def test_security_api_key():
+    response = client.get("/secure-data?x-api-key=mysecretapikey")
+    assert response.status_code == 200, response.text
+    assert response.json() == {"message": "You have access to secure data"}
+
+
+def test_security_api_key_no_key():
+    response = client.get("/secure-data")
+    # TODO: this should be 401 in the implementation! discuss with @tiangolo et al
+    assert response.status_code == 403, response.text
+    assert response.json() == {"detail": "Not authenticated"}
+
+
+def test_security_api_key_invalid_key():
+    response = client.get("/secure-data?x-api-key=wrongkey")
+    assert response.status_code == 401, response.text
+    assert response.json() == {"detail": "Invalid API Key"}