Coverage for tests / test_tutorial / test_security / test_tutorial003.py: 100%
49 statements
« prev ^ index » next coverage.py v7.13.3, created at 2026-02-12 18:15 +0000
« prev ^ index » next coverage.py v7.13.3, created at 2026-02-12 18:15 +0000
1import importlib 1abdc
3import pytest 1abdc
4from fastapi.testclient import TestClient 1abdc
5from inline_snapshot import snapshot 1abdc
7from ...utils import needs_py310 1abdc
10@pytest.fixture( 1abdc
11 name="client",
12 params=[
13 pytest.param("tutorial003_py310", marks=needs_py310),
14 pytest.param("tutorial003_an_py310", marks=needs_py310),
15 ],
16)
17def get_client(request: pytest.FixtureRequest): 1abdc
18 mod = importlib.import_module(f"docs_src.security.{request.param}") 1abc
20 client = TestClient(mod.app) 1abc
21 return client 1abc
24def test_login(client: TestClient): 1abdc
25 response = client.post("/token", data={"username": "johndoe", "password": "secret"}) 1nop
26 assert response.status_code == 200, response.text 1nop
27 assert response.json() == {"access_token": "johndoe", "token_type": "bearer"} 1nop
30def test_login_incorrect_password(client: TestClient): 1abdc
31 response = client.post( 1qrs
32 "/token", data={"username": "johndoe", "password": "incorrect"}
33 )
34 assert response.status_code == 400, response.text 1qrs
35 assert response.json() == {"detail": "Incorrect username or password"} 1qrs
38def test_login_incorrect_username(client: TestClient): 1abdc
39 response = client.post("/token", data={"username": "foo", "password": "secret"}) 1tuv
40 assert response.status_code == 400, response.text 1tuv
41 assert response.json() == {"detail": "Incorrect username or password"} 1tuv
44def test_no_token(client: TestClient): 1abdc
45 response = client.get("/users/me") 1efg
46 assert response.status_code == 401, response.text 1efg
47 assert response.json() == {"detail": "Not authenticated"} 1efg
48 assert response.headers["WWW-Authenticate"] == "Bearer" 1efg
51def test_token(client: TestClient): 1abdc
52 response = client.get("/users/me", headers={"Authorization": "Bearer johndoe"}) 1wxy
53 assert response.status_code == 200, response.text 1wxy
54 assert response.json() == { 1wxy
55 "username": "johndoe",
56 "full_name": "John Doe",
57 "email": "johndoe@example.com",
58 "hashed_password": "fakehashedsecret",
59 "disabled": False,
60 }
63def test_incorrect_token(client: TestClient): 1abdc
64 response = client.get("/users/me", headers={"Authorization": "Bearer nonexistent"}) 1hij
65 assert response.status_code == 401, response.text 1hij
66 assert response.json() == {"detail": "Not authenticated"} 1hij
67 assert response.headers["WWW-Authenticate"] == "Bearer" 1hij
70def test_incorrect_token_type(client: TestClient): 1abdc
71 response = client.get( 1klm
72 "/users/me", headers={"Authorization": "Notexistent testtoken"}
73 )
74 assert response.status_code == 401, response.text 1klm
75 assert response.json() == {"detail": "Not authenticated"} 1klm
76 assert response.headers["WWW-Authenticate"] == "Bearer" 1klm
79def test_inactive_user(client: TestClient): 1abdc
80 response = client.get("/users/me", headers={"Authorization": "Bearer alice"}) 1zAB
81 assert response.status_code == 400, response.text 1zAB
82 assert response.json() == {"detail": "Inactive user"} 1zAB
85def test_openapi_schema(client: TestClient): 1abdc
86 response = client.get("/openapi.json") 1CDE
87 assert response.status_code == 200, response.text 1CDE
88 assert response.json() == snapshot( 1CDE
89 {
90 "openapi": "3.1.0",
91 "info": {"title": "FastAPI", "version": "0.1.0"},
92 "paths": {
93 "/token": {
94 "post": {
95 "responses": {
96 "200": {
97 "description": "Successful Response",
98 "content": {"application/json": {"schema": {}}},
99 },
100 "422": {
101 "description": "Validation Error",
102 "content": {
103 "application/json": {
104 "schema": {
105 "$ref": "#/components/schemas/HTTPValidationError"
106 }
107 }
108 },
109 },
110 },
111 "summary": "Login",
112 "operationId": "login_token_post",
113 "requestBody": {
114 "content": {
115 "application/x-www-form-urlencoded": {
116 "schema": {
117 "$ref": "#/components/schemas/Body_login_token_post"
118 }
119 }
120 },
121 "required": True,
122 },
123 }
124 },
125 "/users/me": {
126 "get": {
127 "responses": {
128 "200": {
129 "description": "Successful Response",
130 "content": {"application/json": {"schema": {}}},
131 }
132 },
133 "summary": "Read Users Me",
134 "operationId": "read_users_me_users_me_get",
135 "security": [{"OAuth2PasswordBearer": []}],
136 }
137 },
138 },
139 "components": {
140 "schemas": {
141 "Body_login_token_post": {
142 "title": "Body_login_token_post",
143 "required": ["username", "password"],
144 "type": "object",
145 "properties": {
146 "grant_type": {
147 "title": "Grant Type",
148 "anyOf": [
149 {"pattern": "^password$", "type": "string"},
150 {"type": "null"},
151 ],
152 },
153 "username": {"title": "Username", "type": "string"},
154 "password": {
155 "title": "Password",
156 "type": "string",
157 "format": "password",
158 },
159 "scope": {
160 "title": "Scope",
161 "type": "string",
162 "default": "",
163 },
164 "client_id": {
165 "title": "Client Id",
166 "anyOf": [{"type": "string"}, {"type": "null"}],
167 },
168 "client_secret": {
169 "title": "Client Secret",
170 "anyOf": [{"type": "string"}, {"type": "null"}],
171 "format": "password",
172 },
173 },
174 },
175 "ValidationError": {
176 "title": "ValidationError",
177 "required": ["loc", "msg", "type"],
178 "type": "object",
179 "properties": {
180 "loc": {
181 "title": "Location",
182 "type": "array",
183 "items": {
184 "anyOf": [{"type": "string"}, {"type": "integer"}]
185 },
186 },
187 "msg": {"title": "Message", "type": "string"},
188 "type": {"title": "Error Type", "type": "string"},
189 "input": {"title": "Input"},
190 "ctx": {"title": "Context", "type": "object"},
191 },
192 },
193 "HTTPValidationError": {
194 "title": "HTTPValidationError",
195 "type": "object",
196 "properties": {
197 "detail": {
198 "title": "Detail",
199 "type": "array",
200 "items": {
201 "$ref": "#/components/schemas/ValidationError"
202 },
203 }
204 },
205 },
206 },
207 "securitySchemes": {
208 "OAuth2PasswordBearer": {
209 "type": "oauth2",
210 "flows": {"password": {"scopes": {}, "tokenUrl": "token"}},
211 }
212 },
213 },
214 }
215 )