Skip to content

Commit

Permalink
Merge pull request #10 from prefeitura-rio/development
Browse files Browse the repository at this point in the history
Implementação de Testes Automatizados
  • Loading branch information
TanookiVerde authored Jan 8, 2024
2 parents 0b5f68b + a778963 commit b31e1bb
Show file tree
Hide file tree
Showing 21 changed files with 845 additions and 273 deletions.
140 changes: 140 additions & 0 deletions .github/workflows/api.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
name: API

on:
push:
paths:
- ".github/workflows/api*"
- "api/**/*"

jobs:
lint:
name: Lint
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v3

- name: Set up Python
uses: actions/setup-python@v2
with:
python-version: "3.11.x"

- name: Set up dependencies
run: |
cd api/
pip install -U pip poetry
poetry config virtualenvs.create false
poetry install --with dev
- name: Run linters
run: |
cd api/
task lint
tests:
name: Tests
runs-on: ubuntu-latest
container: python:3.11-slim
env:
INFISICAL_ADDRESS: ${{ secrets.INFISICAL_ADDRESS }}
INFISICAL_TOKEN: ${{ secrets.INFISICAL_TOKEN }}
services:
db:
image: postgres:15
env:
POSTGRES_PASSWORD: postgres
ports:
- 5432:5432
options: >-
--health-cmd pg_isready
--health-interval 10s
--health-timeout 5s
--health-retries 5
steps:
- name: Checkout
uses: actions/checkout@v3

- name: Set up dependencies
run: |
cd api/
pip install -U pip poetry
poetry config virtualenvs.create false
poetry install --with dev
- name: Set up database
run: |
cd api/
aerich init-db || true
aerich upgrade || true
- name: Run tests
run: |
cd api/
task test
deploy:
name: Build and Deploy
if: github.ref == 'refs/heads/main' || github.ref == 'refs/heads/development'
needs: [lint, tests]
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v3

- name: Login to GitHub Container Registry
uses: docker/login-action@v1
with:
registry: ghcr.io
username: ${{ github.repository_owner }}
password: ${{ secrets.GITHUB_TOKEN }}

- name: Build and push image
uses: docker/build-push-action@v2
with:
context: api/
file: api/Dockerfile
push: true
tags: |
ghcr.io/${{ github.repository_owner }}/${{ github.event.repository.name }}:${{ github.sha }}
ghcr.io/${{ github.repository_owner }}/${{ github.event.repository.name }}:${{ github.ref == 'refs/heads/main' && 'latest' || github.ref == 'refs/heads/development' && 'latest-dev' || github.sha }}
labels: |
org.opencontainers.image.source=${{ github.event.repository.html_url }}
org.opencontainers.image.revision=${{ github.sha }}
build-args: |
BUILDKIT_INLINE_CACHE=1
- name: Setup Google Cloud CLI
uses: google-github-actions/[email protected]
with:
service_account_key: ${{ secrets.GCP_SA_KEY }}
project_id: ${{ secrets.GCP_PROJECT_ID }}
export_default_credentials: true

- name: Get GKE credentials
uses: google-github-actions/[email protected]
with:
cluster_name: ${{ secrets.GKE_CLUSTER }}
location: ${{ secrets.GKE_ZONE }}
credentials: ${{ secrets.GCP_SA_KEY }}

- name: Set up Kustomize
run: |-
curl -sfLo kustomize https://github.com/kubernetes-sigs/kustomize/releases/download/v3.1.0/kustomize_3.1.0_linux_amd64
chmod u+x ./kustomize
mv ./kustomize api/
- name: Deploy (main)
if: github.ref == 'refs/heads/main'
run: |-
cd api/
./kustomize edit set image gcr.io/PROJECT_ID/IMAGE_NAME:TAG=ghcr.io/${{ github.repository_owner }}/${{ github.event.repository.name }}:${{ github.sha }}
./kustomize build . | kubectl apply -n unificacao-prontuarios-prod -f -
kubectl rollout status -w -n unificacao-prontuarios-prod deployment/unificacao-prontuarios
- name: Deploy (development)
if: github.ref == 'refs/heads/development'
run: |-
cd api/
./kustomize edit set image gcr.io/PROJECT_ID/IMAGE_NAME:TAG=ghcr.io/${{ github.repository_owner }}/${{ github.event.repository.name }}:${{ github.sha }}
./kustomize build . | kubectl apply -n unificacao-prontuarios-dev -f -
kubectl rollout status -w -n unificacao-prontuarios-dev deployment/unificacao-prontuarios
2 changes: 1 addition & 1 deletion .github/workflows/lib-docs.yaml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
name: Deploy docs
name: Lib - Docs

on:
push:
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/lib-lint.yaml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
name: CI - Lint
name: Lib - Lint

on:
push:
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/lib-tests.yaml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
name: CI - Tests
name: Lib - Tests

on:
push:
Expand Down
103 changes: 34 additions & 69 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,27 +1,51 @@
# FHIR
# Prontuários Integrados API

## Preparação de Ambiente

- Rode `pre-commit install`
- O projeto está na pasta `api/`
- Para rodar o banco de dados é obrigatório utilizar um ambiente virtual docker
- Para rodar a API você pode optar pelo docker ou pelo ambiente

### Utilizando Docker (BD e API)
*Ideal para deploy e subir o banco de dados localmente*

- Esteja na pasta `./api/`
- Garanta instalação de Docker e Docker Compose
- Configure em `docker-compose.yaml` a variável `ENVIRONMENT` para `dev` ou `prod`
- `dev`: Ambiente de Desenvolvimento
- `prod`: Ambiente de Produção
- Rode `docker compose up --build` na raiz do projeto
- Os serviços estão disponíveis em:
- Para subir a API e o banco de dados, rode `docker compose up --build`
- Se quiser subir apenas o banco de dados: `docker compose up db --build`
- Os serviços ficam disponíveis em:

|Serviço|URL|Porta|Usuário|Senha|
|--|--|--|--|--|
|Banco de Dados (Postgres) |localhost|5432|postgres|postgres|
|API (Fast API) | localhost|**8000**|-|-|

### Utilizando Poetry (Apenas API)
*Ideal para debugging da API e execução de testes localmente*
- Na pasta `./api/` rode `poetry shell` e depois `poetry install`
- Para inicializar a API rode: `uvicorn app.main:app --host 0.0.0.0 --port 8001`
- PS.: Recomendado seguir o tutorial de Debugging e executar por lá.
- O serviço estará disponivel em:

|Serviço|URL|Porta|Usuário|Senha|
|--|--|--|--|--|
|Banco de Dados (Postgres) |localhost|8001|postgres|postgres|
|API (Fast API) | localhost|8000|-|-|
|API (Fast API) | localhost|**8001**|-|-|


## Dados Iniciais
- Dois scripts que populam o banco com dados iniciais:
- Crie um usuário próprio: `python scripts/create_user.py --username <USUARIO> --password <SENHA>`
- Crie dados iniciais: `python scripts/database_initial_data.py`
- **Atenção**: Caso precise limpar todos os dados do banco: `python scripts/database_cleanup.py`

## Testes Automatizados

- Os testes estão definidos na pasta `api/tests/`
- Para rodar os testes basta executar no terminal `pytest --disable-warnings`

## Debugging
- Para fazer o debugging da API você vai rodá-la fora do container docker. Dessa forma a configuração é simples.
- Arquivos de configuração disponíveis em `.vscode/launch.json`.
Expand All @@ -36,67 +60,8 @@

### Uso
- **Inicie a depuração**: o VSCode detecta automaticamente o arquivo que configura a depuração. Basta dar "play" na aba de depuração
- O serviço fica disponível em:

## Payloads para Testes

### Entidade `Patient` (Campos Obrigatórios)

```json
{
"active": true,
"birth_date": "1999-12-20",
"gender": "male",
"cpf": "11111111111",
"name": "MANUEL GOMES",
"telecom": [{
"value": "5521123456789"
}]
}
```

### Entidade `Patient` (Todos os Campos)

```json
{
"active": true,
"address": [{
"use": "home",
"type": "physical",
"line": "AV SQN BLOCO M 604 APARTAMENTO ASA NORTE",
"city": "Rio de Janeiro",
"state": "Rio de Janeiro",
"country": "Brasil",
"postal_code": "70752130",
"period": {
"start": "2020-10-01 00:00:00",
"end": "2020-10-02 00:00:00"
}
}],
"birth_city": "Rio de Janeiro",
"birth_country": "Brasil",
"birth_state": "Rio de Janeiro",
"birth_date": "1999-12-20 00:00:00",
"deceased": false,
"gender": "male",
"cpf": "12345678901",
"cns": "1234567890000000",
"name": "GABRIELA INACIO ALVES",
"nationality": "B",
"naturalization": "",
"mother": "MARILIA FARES DA ROCHA ALVES",
"father": "JURACY ALVES",
"protected_person": false,
"race": "Parda",
"ethnicity": "PATAXO",
"telecom": [{
"system": "phone",
"use": "home",
"value": "5521123456789",
"rank": "1",
"period": {
"start": "2020-10-01 00:00:00",
"end": "2020-10-02 00:00:00"
}
}]
}
```
|Serviço|URL|Porta|Usuário|Senha|
|--|--|--|--|--|
|API (Fast API) | localhost|**8001**|-|-|
66 changes: 66 additions & 0 deletions api/.kubernetes.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
---
# Deployment
apiVersion: apps/v1
kind: Deployment
metadata:
name: unificacao-prontuarios
spec:
replicas: 1
strategy:
type: RollingUpdate
rollingUpdate:
maxSurge: 1
maxUnavailable: 0
selector:
matchLabels:
app: unificacao-prontuarios
minReadySeconds: 5
template:
metadata:
labels:
app: unificacao-prontuarios
spec:
containers:
- name: unificacao-prontuarios
image: gcr.io/PROJECT_ID/IMAGE_NAME:TAG
ports:
- containerPort: 80
envFrom:
- secretRef:
name: unificacao-prontuarios-secrets
readinessProbe:
httpGet:
path: /docs
port: 80
initialDelaySeconds: 5
periodSeconds: 10
livenessProbe:
httpGet:
path: /docs
port: 80
initialDelaySeconds: 5
periodSeconds: 10
resources:
requests:
memory: "512Mi"
cpu: "250m"
limits:
memory: "1024Mi"
cpu: "500m"
restartPolicy: Always

---
# Service
apiVersion: v1
kind: Service
metadata:
labels:
app: unificacao-prontuarios
name: unificacao-prontuarios
spec:
ports:
- name: "80"
port: 80
targetPort: 80
selector:
app: unificacao-prontuarios
21 changes: 19 additions & 2 deletions api/app/config/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
from os import getenv
from typing import List

from infisical import InfisicalClient
from loguru import logger


Expand Down Expand Up @@ -64,9 +65,25 @@ def getenv_list_or_action(
return []


def inject_environment_variables(environment: str):
"""Inject environment variables from Infisical."""
site_url = getenv_or_action("INFISICAL_ADDRESS", action="raise")
token = getenv_or_action("INFISICAL_TOKEN", action="raise")
infisical_client = InfisicalClient(
token=token,
site_url=site_url,
)
secrets = infisical_client.get_all_secrets(environment=environment, attach_to_os_environ=True)
logger.info(f"Injecting {len(secrets)} environment variables from Infisical:")
for secret in secrets:
logger.info(f" - {secret.secret_name}: {'*' * len(secret.secret_value)}")


environment = getenv_or_action("ENVIRONMENT", action="warn", default="dev")
if environment not in ["dev", "prod"]:
raise ValueError("ENVIRONMENT must be one of 'dev' or 'prod'")
if environment not in ["dev", "staging", "prod"]:
raise ValueError("ENVIRONMENT must be one of 'dev', 'staging' or 'prod'")

inject_environment_variables(environment=environment)

if environment == "dev":
from app.config.dev import * # noqa: F401, F403
Expand Down
Loading

0 comments on commit b31e1bb

Please sign in to comment.