Skip to content

Commit bbf7b87

Browse files
authored
Merge pull request #269 from pablokbs/test
Test
2 parents 4e26013 + fee9a15 commit bbf7b87

File tree

15 files changed

+464
-1
lines changed

15 files changed

+464
-1
lines changed
Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
name: Integration Tests
2+
3+
on:
4+
push:
5+
branches: [ master, test ]
6+
pull_request:
7+
branches: [ master ]
8+
9+
jobs:
10+
integration-test:
11+
runs-on: ubuntu-latest
12+
defaults:
13+
run:
14+
working-directory: varios/21/integration
15+
16+
services:
17+
postgres:
18+
image: postgres:15
19+
env:
20+
POSTGRES_PASSWORD: postgres
21+
POSTGRES_DB: testdb
22+
ports:
23+
- 5432:5432
24+
options: >-
25+
--health-cmd pg_isready
26+
--health-interval 10s
27+
--health-timeout 5s
28+
--health-retries 5
29+
30+
steps:
31+
- uses: actions/checkout@v4
32+
33+
- name: Set up Python
34+
uses: actions/setup-python@v5
35+
with:
36+
python-version: '3.11'
37+
cache: 'pip'
38+
cache-dependency-path: varios/21/integration/requirements.txt
39+
40+
- name: Install dependencies
41+
run: pip install -r requirements.txt
42+
43+
- name: Run integration tests with coverage
44+
run: |
45+
pytest --cov=. --cov-report=xml --cov-report=json --cov-report=term-missing -v
46+
env:
47+
DATABASE_URL: postgresql://postgres:postgres@localhost:5432/testdb
48+
49+
- name: Generate coverage badge
50+
run: |
51+
python generate_badge.py
52+
53+
- name: Create coverage badge
54+
uses: schneegans/[email protected]
55+
with:
56+
auth: ${{ secrets.GIST_SECRET }}
57+
gistID: ${{ secrets.COVERAGE_GIST_ID }}
58+
filename: coverage.json
59+
label: coverage
60+
message: ${{ env.COVERAGE }}
61+
color: ${{ env.COLOR }}
62+
namedLogo: python
63+
64+
- name: Upload coverage reports to Codecov
65+
uses: codecov/codecov-action@v4
66+
with:
67+
file: ./varios/21/integration/coverage.xml
68+
flags: integration
69+
name: integration-tests
70+
fail_ci_if_error: true
71+
token: ${{ secrets.CODECOV_TOKEN }}
72+
73+
- name: Store coverage report
74+
uses: actions/upload-artifact@v4
75+
with:
76+
name: coverage-report
77+
path: |
78+
varios/21/integration/coverage.xml
79+
varios/21/integration/coverage.json
80+
varios/21/integration/coverage-badge.json

.github/workflows/tests.yml

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
name: Node.js CI
2+
3+
on:
4+
push:
5+
branches: [ master, test ]
6+
pull_request:
7+
branches: [ master ]
8+
9+
jobs:
10+
test:
11+
runs-on: ubuntu-latest
12+
defaults:
13+
run:
14+
working-directory: varios/21
15+
16+
steps:
17+
- uses: actions/checkout@v4
18+
19+
- name: Use Node.js 18.x
20+
uses: actions/setup-node@v4
21+
with:
22+
node-version: '18.x'
23+
cache: 'npm'
24+
cache-dependency-path: varios/21/package.json
25+
26+
- name: Generate package-lock.json
27+
run: npm install --package-lock-only
28+
29+
- name: Install dependencies
30+
run: npm ci
31+
32+
- name: Run tests
33+
run: npm test

kubernetes/41/hello-app.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ spec:
1919
- containerPort: 80
2020
resources:
2121
requests:
22-
cpu: 500m
22+
cpu: 50m
2323
---
2424

2525
kind: Service
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
name: Node.js CI
2+
3+
on:
4+
push:
5+
branches: [ main ]
6+
pull_request:
7+
branches: [ main ]
8+
9+
jobs:
10+
test:
11+
runs-on: ubuntu-latest
12+
13+
steps:
14+
- uses: actions/checkout@v4
15+
16+
- name: Use Node.js 18.x
17+
uses: actions/setup-node@v4
18+
with:
19+
node-version: '18.x'
20+
cache: 'npm'
21+
22+
- name: Install dependencies
23+
run: npm ci
24+
25+
- name: Run tests
26+
run: npm test

varios/21/Dockerfile

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
FROM node:18-alpine
2+
3+
WORKDIR /app
4+
5+
COPY package*.json ./
6+
7+
RUN npm install
8+
9+
COPY . .
10+
11+
# The default command will start the application
12+
CMD ["npm", "start"]

varios/21/README.md

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
# Demo GitHub Actions con Tests
2+
3+
[![Node.js CI](https://github.com/pablokbs/peladonerd/actions/workflows/tests.yml/badge.svg)](https://github.com/pablokbs/peladonerd/actions/workflows/tests.yml)
4+
[![Integration Tests](https://github.com/pablokbs/peladonerd/actions/workflows/integration-tests.yml/badge.svg)](https://github.com/pablokbs/peladonerd/actions/workflows/integration-tests.yml)
5+
![Coverage](https://img.shields.io/endpoint?url=https://gist.githubusercontent.com/pablokbs/04afb0f414aa2cc4dd88a133454c7947/raw/coverage.json)
6+
7+
Este proyecto es una demostración de GitHub Actions que incluye:
8+
9+
- Tests unitarios en Node.js
10+
- Tests de integración en Python con PostgreSQL
11+
- Reporte de cobertura de código
12+
13+
## Estructura
14+
15+
- `src/` - Aplicación Node.js con tests unitarios
16+
- `integration/` - Tests de integración con PostgreSQL
17+
18+
## Tests Unitarios (Node.js)
19+
20+
```bash
21+
cd src
22+
npm install
23+
npm test
24+
```
25+
26+
## Tests de Integración (Python)
27+
28+
```bash
29+
cd integration
30+
pip install -r requirements.txt
31+
pytest -v
32+
```
33+
34+
## Cobertura de Código
35+
36+
Los tests de integración incluyen reporte de cobertura que se puede ver:
37+
- En los Pull Requests como comentario
38+
- En el badge del README
39+
- En detalle en los artifacts de GitHub Actions

varios/21/integration/app.py

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
import os
2+
import psycopg2
3+
from psycopg2.extras import RealDictCursor
4+
5+
class UserDB:
6+
def __init__(self, connection_string=None):
7+
if connection_string is None:
8+
connection_string = os.getenv('DATABASE_URL', 'postgresql://postgres:postgres@localhost:5432/testdb')
9+
self.connection_string = connection_string
10+
11+
def connect(self):
12+
return psycopg2.connect(self.connection_string)
13+
14+
def setup_database(self):
15+
with self.connect() as conn:
16+
with conn.cursor() as cur:
17+
cur.execute("""
18+
CREATE TABLE IF NOT EXISTS users (
19+
id SERIAL PRIMARY KEY,
20+
username VARCHAR(100) UNIQUE NOT NULL,
21+
email VARCHAR(255) UNIQUE NOT NULL,
22+
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
23+
)
24+
""")
25+
conn.commit()
26+
27+
def add_user(self, username, email):
28+
with self.connect() as conn:
29+
with conn.cursor(cursor_factory=RealDictCursor) as cur:
30+
cur.execute("""
31+
INSERT INTO users (username, email)
32+
VALUES (%s, %s)
33+
RETURNING id, username, email, created_at
34+
""", (username, email))
35+
conn.commit()
36+
return cur.fetchone()
37+
38+
def get_user(self, username):
39+
with self.connect() as conn:
40+
with conn.cursor(cursor_factory=RealDictCursor) as cur:
41+
cur.execute("SELECT * FROM users WHERE username = %s", (username,))
42+
return cur.fetchone()
43+
44+
def delete_user(self, username):
45+
with self.connect() as conn:
46+
with conn.cursor() as cur:
47+
cur.execute("DELETE FROM users WHERE username = %s", (username,))
48+
conn.commit()
49+
return cur.rowcount > 0
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
import json
2+
import sys
3+
4+
def generate_badge(coverage_pct):
5+
color = "red"
6+
if coverage_pct >= 90:
7+
color = "brightgreen"
8+
elif coverage_pct >= 80:
9+
color = "green"
10+
elif coverage_pct >= 70:
11+
color = "yellow"
12+
elif coverage_pct >= 60:
13+
color = "orange"
14+
15+
badge_json = {
16+
"schemaVersion": 1,
17+
"label": "coverage",
18+
"message": f"{coverage_pct}%",
19+
"color": color
20+
}
21+
22+
return json.dumps(badge_json, indent=2)
23+
24+
def main():
25+
with open('coverage.json') as f:
26+
data = json.load(f)
27+
total = data['totals']['percent_covered_display']
28+
coverage_pct = float(total)
29+
30+
badge_json = generate_badge(coverage_pct)
31+
32+
with open('coverage-badge.json', 'w') as f:
33+
f.write(badge_json)
34+
35+
if __name__ == '__main__':
36+
main()
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
psycopg2-binary==2.9.9
2+
pytest==8.0.0
3+
pytest-cov==4.1.0
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
import pytest
2+
import os
3+
from app import UserDB
4+
5+
@pytest.fixture(scope="session")
6+
def db():
7+
# Configuramos la conexión para los tests
8+
db = UserDB(os.getenv('DATABASE_URL', 'postgresql://postgres:postgres@localhost:5432/testdb'))
9+
db.setup_database()
10+
return db
11+
12+
def test_user_creation(db):
13+
# Limpiamos cualquier usuario previo
14+
db.delete_user("testuser")
15+
16+
# Creamos un nuevo usuario
17+
user = db.add_user("testuser", "[email protected]")
18+
19+
assert user["username"] == "testuser"
20+
assert user["email"] == "[email protected]"
21+
assert "id" in user
22+
assert "created_at" in user
23+
24+
def test_user_retrieval(db):
25+
# Primero creamos un usuario
26+
db.add_user("retrievaltest", "[email protected]")
27+
28+
# Luego lo recuperamos
29+
user = db.get_user("retrievaltest")
30+
31+
assert user is not None
32+
assert user["username"] == "retrievaltest"
33+
assert user["email"] == "[email protected]"
34+
35+
def test_user_deletion(db):
36+
# Primero creamos un usuario
37+
db.add_user("deletetest", "[email protected]")
38+
39+
# Verificamos que existe
40+
assert db.get_user("deletetest") is not None
41+
42+
# Lo eliminamos
43+
assert db.delete_user("deletetest") is True
44+
45+
# Verificamos que ya no existe
46+
assert db.get_user("deletetest") is None

0 commit comments

Comments
 (0)