Skip to content

Commit

Permalink
Cruft Update
Browse files Browse the repository at this point in the history
  • Loading branch information
kjaymiller committed Jan 24, 2024
1 parent 2d644d4 commit a01505d
Show file tree
Hide file tree
Showing 14 changed files with 167 additions and 49 deletions.
8 changes: 4 additions & 4 deletions .cruft.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"template": "https://github.com/kjaymiller/cookiecutter-relecloud/",
"commit": "62bc1afd3ca0eb0daf28a7c829761198033a08a6",
"template": "https://github.com/Azure-Samples/Azure-Python-Standardization-Template-Generator",
"commit": "621af12f962b64b1f3458b83fa1af0898d565d80",
"checkout": null,
"context": {
"cookiecutter": {
Expand All @@ -11,7 +11,7 @@
"project_host": "aca",
"web_port": "8000",
"__repo_name": "azure-fastapi-cosmos-postgres-aca",
"__src_folder_name": "azure_fastapi_cosmos_postgres_aca",
"__src_folder_name": "azure-fastapi-cosmos-postgres-aca",
"__project_short_description": "Create a relecloud demo application with fastapi and cosmos-postgres",
"_copy_without_render": [
".github/workflows/azure-dev.yml",
Expand All @@ -26,7 +26,7 @@
"lstrip_blocks": true,
"trim_blocks": true
},
"_template": "https://github.com/kjaymiller/cookiecutter-relecloud/"
"_template": "https://github.com/Azure-Samples/Azure-Python-Standardization-Template-Generator"
}
},
"directory": null
Expand Down
5 changes: 3 additions & 2 deletions .devcontainer/devcontainer.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// For format details, see https://aka.ms/devcontainer.json. For config options, see the
// README at: https://github.com/devcontainers/templates/tree/main/src/docker-existing-docker-compose
{
"name": "azure_fastapi_cosmos_postgres_aca",
"name": "azure-fastapi-cosmos-postgres-aca",

// Update the 'dockerComposeFile' list if you have more compose files or use different names.
// The .devcontainer/docker-compose.yml file contains any overrides you need/want to make.
Expand Down Expand Up @@ -32,7 +32,8 @@
"files.exclude": {
".coverage": true,
".pytest_cache": true,
"__pycache__": true
"__pycache__": true,
".ruff_cache": true
},
"[python]": {
"editor.formatOnSave": true,
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/azure-dev.yml
Original file line number Diff line number Diff line change
Expand Up @@ -103,5 +103,5 @@ jobs:
run: |
python3 -m pip install --upgrade pip
python3 -m pip install -r requirements-dev.txt
python3 -m playwright install --with-deps
python3 -m playwright install chromium --with-deps
python3 -m pytest --exitfirst src/tests/smoke/smoketests.py --live-server-url $URI
81 changes: 50 additions & 31 deletions .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,37 +14,56 @@ jobs:
strategy:
fail-fast: false
matrix:
os: ["ubuntu-20.04"]
os: ["ubuntu-latest", "macos-latest", "macos-latest-xlarge", "windows-latest"]
python_version: ["3.8", "3.9", "3.10", "3.11", "3.12"]
services:
db:
image: postgres:14
env:
POSTGRES_PASSWORD: postgres
ports:
- 5432:5432
# needed because the postgres container does not provide a healthcheck
options: --health-cmd pg_isready --health-interval 10s --health-timeout 5s --health-retries 5
exclude:
- os: macos-latest-xlarge
python_version: 3.8
- os: macos-latest-xlarge
python_version: 3.9
- os: macos-latest-xlarge
python_version: "3.10"
steps:
- uses: actions/checkout@v3
- name: Setup python
uses: actions/setup-python@v2
with:
- name: Checkout
uses: actions/checkout@v3
- name: Check for MacOS Runner
if: matrix.os == 'macos-latest-xlarge'
run: brew install postgresql@14
- name: Setup postgres
uses: ikalnytskyi/action-setup-postgres@v4
- name: Setup python
uses: actions/setup-python@v2
with:

python-version: ${{ matrix.python_version }}
architecture: x64
- name: Install dependencies
run: |
python3 -m pip install --upgrade pip
python3 -m pip install -r requirements-dev.txt
playwright install --with-deps
python3 -m pip install -e src
- name: Seed data and run Pytest tests
run: |
python3 src/fastapi_app/seed_data.py
python3 -m pytest
env:
POSTGRES_HOST: localhost
POSTGRES_USERNAME: postgres
POSTGRES_PASSWORD: postgres
POSTGRES_DATABASE: postgres
python-version: ${{ matrix.python_version }}
architecture: x64
- name: Install dependencies
run: |
python3 -m pip install --upgrade pip
python3 -m pip install -r requirements-dev.txt
playwright install chromium --with-deps
python3 -m pip install -e src
- name: Seed data
run: |
python3 src/fastapi_app/seed_data.py
env:
POSTGRES_HOST: localhost
POSTGRES_USERNAME: postgres
POSTGRES_PASSWORD: postgres
POSTGRES_DATABASE: postgres
- name: Run tests Windows
if: runner.os == 'windows'
run: python3 -m pytest --ignore=src/tests/local/test_gunicorn.py
env:
POSTGRES_HOST: localhost
POSTGRES_USERNAME: postgres
POSTGRES_PASSWORD: postgres
POSTGRES_DATABASE: postgres
- name: Run tests
if: runner.os != 'windows'
run: python3 -m pytest
env:
POSTGRES_HOST: localhost
POSTGRES_USERNAME: postgres
POSTGRES_PASSWORD: postgres
POSTGRES_DATABASE: postgres
11 changes: 10 additions & 1 deletion .vscode/launch.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,15 @@
"fastapi_app:app",
"--reload"
],
},
{
"name": "Python: Debug Tests",
"type": "python",
"request": "launch",
"program": "${file}",
"purpose": ["debug-test"],
"console": "integratedTerminal",
"env": {"PYTEST_ADDOPTS": "--no-cov"}
}
]
}
}
22 changes: 21 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,23 @@
---
page_type: sample
languages:
- azdeveloper
- python
- bicep
- html
- css
- scss
products:
- azure
- azure-container-apps
- azure-postgresql
- azure-cosmos-db
urlFragment: azure-fastapi-cosmos-postgres-aca
name: Deploy FastAPI Application with PostgreSQL on Azure Container Apps (Python)
description: This project deploys a web application for a space travel agency using FastAPI with Python, and is set up for easy deployment with the Azure Developer CLI.
---
<!-- YAML front-matter schema: https://review.learn.microsoft.com/en-us/help/contribute/samples/process/onboarding?branch=main#supported-metadata-fields-for-readmemd -->

# Deploy FastAPI Application with PostgreSQL via Azure Container Apps

This project deploys a web application for a space travel agency using FastAPI. The application can be deployed to Azure with Azure Container Apps using the [Azure Developer CLI](https://learn.microsoft.com/azure/developer/azure-developer-cli/overview).
Expand Down Expand Up @@ -55,7 +75,7 @@ python3 -m uvicorn fastapi_app:app --reload --port=8000
```sh
python3 -m pip install -r requirements-dev.txt
python3 -m playwright install --with-deps
python3 -m playwright install chromium --with-deps
```
3. Run the tests:
Expand Down
3 changes: 3 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,6 @@ known-first-party = ["fastapi_app"]

[tool.pytest.ini_options]
addopts = "-ra -vv"

[tool.coverage.report]
show_missing = true
3 changes: 3 additions & 0 deletions requirements-dev.txt
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@ pip-tools
pytest
ephemeral-port-reserve
pytest-playwright
coverage
pytest-cov
axe-playwright-python

# Linters
ruff
2 changes: 1 addition & 1 deletion src/fastapi_app/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
if POSTGRES_SSL:
sql_url = f"{sql_url}?sslmode={POSTGRES_SSL}"

engine = create_engine(sql_url, echo=True)
engine = create_engine(sql_url)


def create_db_and_tables():
Expand Down
30 changes: 30 additions & 0 deletions src/static/manifest.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
{
"name": "ReleCloud Space Tourism",
"short_name": "ReleCloud",
"start_url": ".",
"display": "standalone",
"background_color": "#fff",
"description": "ReleCloud Space Tourism",
"icons": [
{
"src": "/static/res/img/favicon.ico",
"sizes": "32x32",
"type": "image/x-icon"
},
{
"src": "/static/res/img/favicon-120-precomposed.png",
"sizes": "120x120",
"type": "image/png"
},
{
"src": "/static/res/img/favicon-152-precomposed.png",
"sizes": "152x152",
"type": "image/png"
},
{
"src": "/static/res/img/favicon-192.png",
"sizes": "192x192",
"type": "image/png"
}
]
}
17 changes: 11 additions & 6 deletions src/templates/base.html
Original file line number Diff line number Diff line change
Expand Up @@ -4,21 +4,26 @@
{% if prod %}
<meta http-equiv="Content-Security-Policy" content="upgrade-insecure-requests">
{% endif %}

<!--main CSS theme file -->
<link rel="stylesheet" href="{{ url_for('static', path='res/css/theme.css') }}" />

<style>
/* Accessibility overrides */
.btn-primary {
background-color: #006ee5;
}
</style>
<!-- For new browsers - multisize ico -->
<link rel="icon" type="image/x-icon" sizes="16x16 32x32" href="{{ url_for('static', path='res/img/favicon.ico') }}">

<!-- For iPad with high-resolution Retina display running iOS ≥ 7: -->
<link rel="apple-touch-icon" sizes="152x152" href="{{ url_for('static', path='res/img/favicon-152-precomposed.png') }}">

<!-- For iPhone with high-resolution Retina display running iOS ≥ 7: -->
<link rel="apple-touch-icon" sizes="120x120" href="{{ url_for('static', path='res/img/favicon-120-precomposed.png') }}">

<!-- Chrome for Android -->
<link rel="manifest" href="manifest.json">
<link rel="manifest" href="{{ url_for('static', path='manifest.json') }}}}">
<link rel="icon" sizes="192x192" href="{{ url_for('static', path='res/img/favicon-192.png') }}">

<title>
Expand Down
4 changes: 2 additions & 2 deletions src/templates/info_request_create.html
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,13 @@ <h1 id="page-title">Request information</h2>
<p>Fill out the form below to request information about our cruises</p>

<form method="post">
<form method="post" action="/info_request/">
<form method="post" action="/info_request">
<label for="name">Name:</label>
<input type="text" id="name" name="name" required><br><br>
<label for="email">Email:</label>
<input type="email" id="email" name="email" required><br><br>
<label for="cruise_id">Cruise:</label>
<select name="cruise_id">
<select name="cruise_id" id="cruise_id">
{% for cruise in cruises %}
<option value="{{ cruise.id }}">{{ cruise.name }}</option>
{% endfor %}
Expand Down
15 changes: 15 additions & 0 deletions src/tests/local/test_gunicorn.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import sys
from unittest import mock

import pytest
from gunicorn.app.wsgiapp import run


def test_config_imports():
argv = ["gunicorn", "--check-config", "fastapi_app.app:app", "-c", "src/gunicorn.conf.py"]

with mock.patch.object(sys, "argv", argv):
with pytest.raises(SystemExit) as excinfo:
run()

assert excinfo.value.args[0] == 0
13 changes: 13 additions & 0 deletions src/tests/local/test_playwright.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,20 @@
import re

import pytest
from axe_playwright_python.sync_playwright import Axe
from playwright.sync_api import Page, expect


def check_for_violations(page: Page):
results = Axe().run(page)
assert results.violations_count == 0, results.generate_report()


def test_home(page: Page, live_server_url: str):
"""Test that the home page loads"""
page.goto(live_server_url)
expect(page).to_have_title("ReleCloud - Expand your horizons")
check_for_violations(page)


@pytest.mark.parametrize(
Expand All @@ -26,19 +33,22 @@ def test_header_has_request_info(page: Page, live_server_url: str, page_title, p
# Request Info
request_info = header.get_by_role("link", name=page_title)
expect(request_info).to_have_attribute("href", re.compile(rf".*{page_url}.*"))
check_for_violations(page)


def test_request_information(page: Page, live_server_url: str):
"""Test that the request info form page loads"""
page.goto(live_server_url)
page.get_by_role("link", name="Request Information").click()
expect(page).to_have_title("ReleCloud - Request information")
check_for_violations(page)


def test_destinations(page: Page, live_server_url: str):
page.goto(live_server_url)
page.get_by_role("link", name="Destinations").click()
expect(page).to_have_title("ReleCloud - Destinations")
check_for_violations(page)


destinations = (
Expand Down Expand Up @@ -80,6 +90,7 @@ def test_destination_options(
page.get_by_role("link", name="Destinations").click()
expect(page).to_have_title("ReleCloud - Destinations")
expect(page.get_by_text(destination)).to_be_visible()
check_for_violations(page)


@pytest.mark.parametrize(
Expand All @@ -97,10 +108,12 @@ def test_destination_options_have_cruises(page: Page, live_server_url: str, dest

for page_cruise in page_cruises:
assert page_cruise.text_content() in cruises
check_for_violations(page)


def test_about(page: Page, live_server_url: str):
"""Test that the request info form page loads"""
page.goto(live_server_url)
page.get_by_role("link", name="About").click()
expect(page.locator("#page-title")).to_have_text(re.compile(r".*about.*", re.IGNORECASE))
check_for_violations(page)

0 comments on commit a01505d

Please sign in to comment.