Coverage for tests/test_tutorial/test_bigger_applications/test_main.py: 100%

110 statements  

« prev     ^ index     » next       coverage.py v7.6.1, created at 2025-01-13 13:38 +0000

1import importlib 1abcde

2 

3import pytest 1abcde

4from dirty_equals import IsDict 1abcde

5from fastapi.testclient import TestClient 1abcde

6 

7from ...utils import needs_py39 1abcde

8 

9 

10@pytest.fixture( 1abcde

11 name="client", 

12 params=[ 

13 "app_an.main", 

14 pytest.param("app_an_py39.main", marks=needs_py39), 

15 "app.main", 

16 ], 

17) 

18def get_client(request: pytest.FixtureRequest): 1abcde

19 mod = importlib.import_module(f"docs_src.bigger_applications.{request.param}") 1abcde

20 

21 client = TestClient(mod.app) 1abcde

22 return client 1abcde

23 

24 

25def test_users_token_jessica(client: TestClient): 1abcde

26 response = client.get("/users?token=jessica") 1fghij

27 assert response.status_code == 200 1fghij

28 assert response.json() == [{"username": "Rick"}, {"username": "Morty"}] 1fghij

29 

30 

31def test_users_with_no_token(client: TestClient): 1abcde

32 response = client.get("/users") 1klmno

33 assert response.status_code == 422 1klmno

34 assert response.json() == IsDict( 1klmno

35 { 

36 "detail": [ 

37 { 

38 "type": "missing", 

39 "loc": ["query", "token"], 

40 "msg": "Field required", 

41 "input": None, 

42 } 

43 ] 

44 } 

45 ) | IsDict( 

46 # TODO: remove when deprecating Pydantic v1 

47 { 

48 "detail": [ 

49 { 

50 "loc": ["query", "token"], 

51 "msg": "field required", 

52 "type": "value_error.missing", 

53 }, 

54 ] 

55 } 

56 ) 

57 

58 

59def test_users_foo_token_jessica(client: TestClient): 1abcde

60 response = client.get("/users/foo?token=jessica") 1pqrst

61 assert response.status_code == 200 1pqrst

62 assert response.json() == {"username": "foo"} 1pqrst

63 

64 

65def test_users_foo_with_no_token(client: TestClient): 1abcde

66 response = client.get("/users/foo") 1uvwxy

67 assert response.status_code == 422 1uvwxy

68 assert response.json() == IsDict( 1uvwxy

69 { 

70 "detail": [ 

71 { 

72 "type": "missing", 

73 "loc": ["query", "token"], 

74 "msg": "Field required", 

75 "input": None, 

76 } 

77 ] 

78 } 

79 ) | IsDict( 

80 # TODO: remove when deprecating Pydantic v1 

81 { 

82 "detail": [ 

83 { 

84 "loc": ["query", "token"], 

85 "msg": "field required", 

86 "type": "value_error.missing", 

87 }, 

88 ] 

89 } 

90 ) 

91 

92 

93def test_users_me_token_jessica(client: TestClient): 1abcde

94 response = client.get("/users/me?token=jessica") 1zABCD

95 assert response.status_code == 200 1zABCD

96 assert response.json() == {"username": "fakecurrentuser"} 1zABCD

97 

98 

99def test_users_me_with_no_token(client: TestClient): 1abcde

100 response = client.get("/users/me") 1EFGHI

101 assert response.status_code == 422 1EFGHI

102 assert response.json() == IsDict( 1EFGHI

103 { 

104 "detail": [ 

105 { 

106 "type": "missing", 

107 "loc": ["query", "token"], 

108 "msg": "Field required", 

109 "input": None, 

110 } 

111 ] 

112 } 

113 ) | IsDict( 

114 # TODO: remove when deprecating Pydantic v1 

115 { 

116 "detail": [ 

117 { 

118 "loc": ["query", "token"], 

119 "msg": "field required", 

120 "type": "value_error.missing", 

121 }, 

122 ] 

123 } 

124 ) 

125 

126 

127def test_users_token_monica_with_no_jessica(client: TestClient): 1abcde

128 response = client.get("/users?token=monica") 1JKLMN

129 assert response.status_code == 400 1JKLMN

130 assert response.json() == {"detail": "No Jessica token provided"} 1JKLMN

131 

132 

133def test_items_token_jessica(client: TestClient): 1abcde

134 response = client.get( 1OPQRS

135 "/items?token=jessica", headers={"X-Token": "fake-super-secret-token"} 

136 ) 

137 assert response.status_code == 200 1OPQRS

138 assert response.json() == { 1OPQRS

139 "plumbus": {"name": "Plumbus"}, 

140 "gun": {"name": "Portal Gun"}, 

141 } 

142 

143 

144def test_items_with_no_token_jessica(client: TestClient): 1abcde

145 response = client.get("/items", headers={"X-Token": "fake-super-secret-token"}) 1TUVWX

146 assert response.status_code == 422 1TUVWX

147 assert response.json() == IsDict( 1TUVWX

148 { 

149 "detail": [ 

150 { 

151 "type": "missing", 

152 "loc": ["query", "token"], 

153 "msg": "Field required", 

154 "input": None, 

155 } 

156 ] 

157 } 

158 ) | IsDict( 

159 # TODO: remove when deprecating Pydantic v1 

160 { 

161 "detail": [ 

162 { 

163 "loc": ["query", "token"], 

164 "msg": "field required", 

165 "type": "value_error.missing", 

166 }, 

167 ] 

168 } 

169 ) 

170 

171 

172def test_items_plumbus_token_jessica(client: TestClient): 1abcde

173 response = client.get( 1YZ012

174 "/items/plumbus?token=jessica", headers={"X-Token": "fake-super-secret-token"} 

175 ) 

176 assert response.status_code == 200 1YZ012

177 assert response.json() == {"name": "Plumbus", "item_id": "plumbus"} 1YZ012

178 

179 

180def test_items_bar_token_jessica(client: TestClient): 1abcde

181 response = client.get( 134567

182 "/items/bar?token=jessica", headers={"X-Token": "fake-super-secret-token"} 

183 ) 

184 assert response.status_code == 404 134567

185 assert response.json() == {"detail": "Item not found"} 134567

186 

187 

188def test_items_plumbus_with_no_token(client: TestClient): 1abcde

189 response = client.get( 189!#$

190 "/items/plumbus", headers={"X-Token": "fake-super-secret-token"} 

191 ) 

192 assert response.status_code == 422 189!#$

193 assert response.json() == IsDict( 189!#$

194 { 

195 "detail": [ 

196 { 

197 "type": "missing", 

198 "loc": ["query", "token"], 

199 "msg": "Field required", 

200 "input": None, 

201 } 

202 ] 

203 } 

204 ) | IsDict( 

205 # TODO: remove when deprecating Pydantic v1 

206 { 

207 "detail": [ 

208 { 

209 "loc": ["query", "token"], 

210 "msg": "field required", 

211 "type": "value_error.missing", 

212 }, 

213 ] 

214 } 

215 ) 

216 

217 

218def test_items_with_invalid_token(client: TestClient): 1abcde

219 response = client.get("/items?token=jessica", headers={"X-Token": "invalid"}) 1%'()*

220 assert response.status_code == 400 1%'()*

221 assert response.json() == {"detail": "X-Token header invalid"} 1%'()*

222 

223 

224def test_items_bar_with_invalid_token(client: TestClient): 1abcde

225 response = client.get("/items/bar?token=jessica", headers={"X-Token": "invalid"}) 1+,-./

226 assert response.status_code == 400 1+,-./

227 assert response.json() == {"detail": "X-Token header invalid"} 1+,-./

228 

229 

230def test_items_with_missing_x_token_header(client: TestClient): 1abcde

231 response = client.get("/items?token=jessica") 1:;=?@

232 assert response.status_code == 422 1:;=?@

233 assert response.json() == IsDict( 1:;=?@

234 { 

235 "detail": [ 

236 { 

237 "type": "missing", 

238 "loc": ["header", "x-token"], 

239 "msg": "Field required", 

240 "input": None, 

241 } 

242 ] 

243 } 

244 ) | IsDict( 

245 # TODO: remove when deprecating Pydantic v1 

246 { 

247 "detail": [ 

248 { 

249 "loc": ["header", "x-token"], 

250 "msg": "field required", 

251 "type": "value_error.missing", 

252 } 

253 ] 

254 } 

255 ) 

256 

257 

258def test_items_plumbus_with_missing_x_token_header(client: TestClient): 1abcde

259 response = client.get("/items/plumbus?token=jessica") 1[]^_`

260 assert response.status_code == 422 1[]^_`

261 assert response.json() == IsDict( 1[]^_`

262 { 

263 "detail": [ 

264 { 

265 "type": "missing", 

266 "loc": ["header", "x-token"], 

267 "msg": "Field required", 

268 "input": None, 

269 } 

270 ] 

271 } 

272 ) | IsDict( 

273 # TODO: remove when deprecating Pydantic v1 

274 { 

275 "detail": [ 

276 { 

277 "loc": ["header", "x-token"], 

278 "msg": "field required", 

279 "type": "value_error.missing", 

280 } 

281 ] 

282 } 

283 ) 

284 

285 

286def test_root_token_jessica(client: TestClient): 1abcde

287 response = client.get("/?token=jessica") 2{ | } ~ ab

288 assert response.status_code == 200 2{ | } ~ ab

289 assert response.json() == {"message": "Hello Bigger Applications!"} 2{ | } ~ ab

290 

291 

292def test_root_with_no_token(client: TestClient): 1abcde

293 response = client.get("/") 2bbcbdbebfb

294 assert response.status_code == 422 2bbcbdbebfb

295 assert response.json() == IsDict( 2bbcbdbebfb

296 { 

297 "detail": [ 

298 { 

299 "type": "missing", 

300 "loc": ["query", "token"], 

301 "msg": "Field required", 

302 "input": None, 

303 } 

304 ] 

305 } 

306 ) | IsDict( 

307 # TODO: remove when deprecating Pydantic v1 

308 { 

309 "detail": [ 

310 { 

311 "loc": ["query", "token"], 

312 "msg": "field required", 

313 "type": "value_error.missing", 

314 }, 

315 ] 

316 } 

317 ) 

318 

319 

320def test_put_no_header(client: TestClient): 1abcde

321 response = client.put("/items/foo") 2gbhbibjbkb

322 assert response.status_code == 422, response.text 2gbhbibjbkb

323 assert response.json() == IsDict( 2gbhbibjbkb

324 { 

325 "detail": [ 

326 { 

327 "type": "missing", 

328 "loc": ["query", "token"], 

329 "msg": "Field required", 

330 "input": None, 

331 }, 

332 { 

333 "type": "missing", 

334 "loc": ["header", "x-token"], 

335 "msg": "Field required", 

336 "input": None, 

337 }, 

338 ] 

339 } 

340 ) | IsDict( 

341 # TODO: remove when deprecating Pydantic v1 

342 { 

343 "detail": [ 

344 { 

345 "loc": ["query", "token"], 

346 "msg": "field required", 

347 "type": "value_error.missing", 

348 }, 

349 { 

350 "loc": ["header", "x-token"], 

351 "msg": "field required", 

352 "type": "value_error.missing", 

353 }, 

354 ] 

355 } 

356 ) 

357 

358 

359def test_put_invalid_header(client: TestClient): 1abcde

360 response = client.put("/items/foo", headers={"X-Token": "invalid"}) 2lbmbnbobpb

361 assert response.status_code == 400, response.text 2lbmbnbobpb

362 assert response.json() == {"detail": "X-Token header invalid"} 2lbmbnbobpb

363 

364 

365def test_put(client: TestClient): 1abcde

366 response = client.put( 2qbrbsbtbub

367 "/items/plumbus?token=jessica", headers={"X-Token": "fake-super-secret-token"} 

368 ) 

369 assert response.status_code == 200, response.text 2qbrbsbtbub

370 assert response.json() == {"item_id": "plumbus", "name": "The great Plumbus"} 2qbrbsbtbub

371 

372 

373def test_put_forbidden(client: TestClient): 1abcde

374 response = client.put( 2vbwbxbybzb

375 "/items/bar?token=jessica", headers={"X-Token": "fake-super-secret-token"} 

376 ) 

377 assert response.status_code == 403, response.text 2vbwbxbybzb

378 assert response.json() == {"detail": "You can only update the item: plumbus"} 2vbwbxbybzb

379 

380 

381def test_admin(client: TestClient): 1abcde

382 response = client.post( 2AbBbCbDbEb

383 "/admin/?token=jessica", headers={"X-Token": "fake-super-secret-token"} 

384 ) 

385 assert response.status_code == 200, response.text 2AbBbCbDbEb

386 assert response.json() == {"message": "Admin getting schwifty"} 2AbBbCbDbEb

387 

388 

389def test_admin_invalid_header(client: TestClient): 1abcde

390 response = client.post("/admin/", headers={"X-Token": "invalid"}) 2FbGbHbIbJb

391 assert response.status_code == 400, response.text 2FbGbHbIbJb

392 assert response.json() == {"detail": "X-Token header invalid"} 2FbGbHbIbJb

393 

394 

395def test_openapi_schema(client: TestClient): 1abcde

396 response = client.get("/openapi.json") 2KbLbMbNbOb

397 assert response.status_code == 200, response.text 2KbLbMbNbOb

398 assert response.json() == { 2KbLbMbNbOb

399 "openapi": "3.1.0", 

400 "info": {"title": "FastAPI", "version": "0.1.0"}, 

401 "paths": { 

402 "/users/": { 

403 "get": { 

404 "tags": ["users"], 

405 "summary": "Read Users", 

406 "operationId": "read_users_users__get", 

407 "parameters": [ 

408 { 

409 "required": True, 

410 "schema": {"title": "Token", "type": "string"}, 

411 "name": "token", 

412 "in": "query", 

413 } 

414 ], 

415 "responses": { 

416 "200": { 

417 "description": "Successful Response", 

418 "content": {"application/json": {"schema": {}}}, 

419 }, 

420 "422": { 

421 "description": "Validation Error", 

422 "content": { 

423 "application/json": { 

424 "schema": { 

425 "$ref": "#/components/schemas/HTTPValidationError" 

426 } 

427 } 

428 }, 

429 }, 

430 }, 

431 } 

432 }, 

433 "/users/me": { 

434 "get": { 

435 "tags": ["users"], 

436 "summary": "Read User Me", 

437 "operationId": "read_user_me_users_me_get", 

438 "parameters": [ 

439 { 

440 "required": True, 

441 "schema": {"title": "Token", "type": "string"}, 

442 "name": "token", 

443 "in": "query", 

444 } 

445 ], 

446 "responses": { 

447 "200": { 

448 "description": "Successful Response", 

449 "content": {"application/json": {"schema": {}}}, 

450 }, 

451 "422": { 

452 "description": "Validation Error", 

453 "content": { 

454 "application/json": { 

455 "schema": { 

456 "$ref": "#/components/schemas/HTTPValidationError" 

457 } 

458 } 

459 }, 

460 }, 

461 }, 

462 } 

463 }, 

464 "/users/{username}": { 

465 "get": { 

466 "tags": ["users"], 

467 "summary": "Read User", 

468 "operationId": "read_user_users__username__get", 

469 "parameters": [ 

470 { 

471 "required": True, 

472 "schema": {"title": "Username", "type": "string"}, 

473 "name": "username", 

474 "in": "path", 

475 }, 

476 { 

477 "required": True, 

478 "schema": {"title": "Token", "type": "string"}, 

479 "name": "token", 

480 "in": "query", 

481 }, 

482 ], 

483 "responses": { 

484 "200": { 

485 "description": "Successful Response", 

486 "content": {"application/json": {"schema": {}}}, 

487 }, 

488 "422": { 

489 "description": "Validation Error", 

490 "content": { 

491 "application/json": { 

492 "schema": { 

493 "$ref": "#/components/schemas/HTTPValidationError" 

494 } 

495 } 

496 }, 

497 }, 

498 }, 

499 } 

500 }, 

501 "/items/": { 

502 "get": { 

503 "tags": ["items"], 

504 "summary": "Read Items", 

505 "operationId": "read_items_items__get", 

506 "parameters": [ 

507 { 

508 "required": True, 

509 "schema": {"title": "Token", "type": "string"}, 

510 "name": "token", 

511 "in": "query", 

512 }, 

513 { 

514 "required": True, 

515 "schema": {"title": "X-Token", "type": "string"}, 

516 "name": "x-token", 

517 "in": "header", 

518 }, 

519 ], 

520 "responses": { 

521 "200": { 

522 "description": "Successful Response", 

523 "content": {"application/json": {"schema": {}}}, 

524 }, 

525 "404": {"description": "Not found"}, 

526 "422": { 

527 "description": "Validation Error", 

528 "content": { 

529 "application/json": { 

530 "schema": { 

531 "$ref": "#/components/schemas/HTTPValidationError" 

532 } 

533 } 

534 }, 

535 }, 

536 }, 

537 } 

538 }, 

539 "/items/{item_id}": { 

540 "get": { 

541 "tags": ["items"], 

542 "summary": "Read Item", 

543 "operationId": "read_item_items__item_id__get", 

544 "parameters": [ 

545 { 

546 "required": True, 

547 "schema": {"title": "Item Id", "type": "string"}, 

548 "name": "item_id", 

549 "in": "path", 

550 }, 

551 { 

552 "required": True, 

553 "schema": {"title": "Token", "type": "string"}, 

554 "name": "token", 

555 "in": "query", 

556 }, 

557 { 

558 "required": True, 

559 "schema": {"title": "X-Token", "type": "string"}, 

560 "name": "x-token", 

561 "in": "header", 

562 }, 

563 ], 

564 "responses": { 

565 "200": { 

566 "description": "Successful Response", 

567 "content": {"application/json": {"schema": {}}}, 

568 }, 

569 "404": {"description": "Not found"}, 

570 "422": { 

571 "description": "Validation Error", 

572 "content": { 

573 "application/json": { 

574 "schema": { 

575 "$ref": "#/components/schemas/HTTPValidationError" 

576 } 

577 } 

578 }, 

579 }, 

580 }, 

581 }, 

582 "put": { 

583 "tags": ["items", "custom"], 

584 "summary": "Update Item", 

585 "operationId": "update_item_items__item_id__put", 

586 "parameters": [ 

587 { 

588 "required": True, 

589 "schema": {"title": "Item Id", "type": "string"}, 

590 "name": "item_id", 

591 "in": "path", 

592 }, 

593 { 

594 "required": True, 

595 "schema": {"title": "Token", "type": "string"}, 

596 "name": "token", 

597 "in": "query", 

598 }, 

599 { 

600 "required": True, 

601 "schema": {"title": "X-Token", "type": "string"}, 

602 "name": "x-token", 

603 "in": "header", 

604 }, 

605 ], 

606 "responses": { 

607 "200": { 

608 "description": "Successful Response", 

609 "content": {"application/json": {"schema": {}}}, 

610 }, 

611 "404": {"description": "Not found"}, 

612 "403": {"description": "Operation forbidden"}, 

613 "422": { 

614 "description": "Validation Error", 

615 "content": { 

616 "application/json": { 

617 "schema": { 

618 "$ref": "#/components/schemas/HTTPValidationError" 

619 } 

620 } 

621 }, 

622 }, 

623 }, 

624 }, 

625 }, 

626 "/admin/": { 

627 "post": { 

628 "tags": ["admin"], 

629 "summary": "Update Admin", 

630 "operationId": "update_admin_admin__post", 

631 "parameters": [ 

632 { 

633 "required": True, 

634 "schema": {"title": "Token", "type": "string"}, 

635 "name": "token", 

636 "in": "query", 

637 }, 

638 { 

639 "required": True, 

640 "schema": {"title": "X-Token", "type": "string"}, 

641 "name": "x-token", 

642 "in": "header", 

643 }, 

644 ], 

645 "responses": { 

646 "200": { 

647 "description": "Successful Response", 

648 "content": {"application/json": {"schema": {}}}, 

649 }, 

650 "418": {"description": "I'm a teapot"}, 

651 "422": { 

652 "description": "Validation Error", 

653 "content": { 

654 "application/json": { 

655 "schema": { 

656 "$ref": "#/components/schemas/HTTPValidationError" 

657 } 

658 } 

659 }, 

660 }, 

661 }, 

662 } 

663 }, 

664 "/": { 

665 "get": { 

666 "summary": "Root", 

667 "operationId": "root__get", 

668 "parameters": [ 

669 { 

670 "required": True, 

671 "schema": {"title": "Token", "type": "string"}, 

672 "name": "token", 

673 "in": "query", 

674 } 

675 ], 

676 "responses": { 

677 "200": { 

678 "description": "Successful Response", 

679 "content": {"application/json": {"schema": {}}}, 

680 }, 

681 "422": { 

682 "description": "Validation Error", 

683 "content": { 

684 "application/json": { 

685 "schema": { 

686 "$ref": "#/components/schemas/HTTPValidationError" 

687 } 

688 } 

689 }, 

690 }, 

691 }, 

692 } 

693 }, 

694 }, 

695 "components": { 

696 "schemas": { 

697 "HTTPValidationError": { 

698 "title": "HTTPValidationError", 

699 "type": "object", 

700 "properties": { 

701 "detail": { 

702 "title": "Detail", 

703 "type": "array", 

704 "items": {"$ref": "#/components/schemas/ValidationError"}, 

705 } 

706 }, 

707 }, 

708 "ValidationError": { 

709 "title": "ValidationError", 

710 "required": ["loc", "msg", "type"], 

711 "type": "object", 

712 "properties": { 

713 "loc": { 

714 "title": "Location", 

715 "type": "array", 

716 "items": { 

717 "anyOf": [{"type": "string"}, {"type": "integer"}] 

718 }, 

719 }, 

720 "msg": {"title": "Message", "type": "string"}, 

721 "type": {"title": "Error Type", "type": "string"}, 

722 }, 

723 }, 

724 } 

725 }, 

726 }