Skip to content

Commit f78f654

Browse files
authored
SRE-371 Refactor application and add tests
* Refactors the application to enable better testing * Implements tests
1 parent 28aaded commit f78f654

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

48 files changed

+3044
-909
lines changed
Lines changed: 25 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,28 @@
1-
name: publish
1+
name: CI/CD
22
on:
33
push:
4-
tags:
5-
- 'v*'
4+
pull_request:
5+
branches:
6+
- 'main'
7+
68
env:
79
REGISTRY: ghcr.io
810
IMAGE_NAME: ${{ github.repository }}
911

1012
jobs:
11-
release:
13+
test:
1214
runs-on: ubuntu-latest
15+
1316
steps:
14-
- name: Create GitHub release
15-
uses: Roang-zero1/github-create-release-action@master
16-
with:
17-
version_regex: ^v[[:digit:]]+\.[[:digit:]]+\.[[:digit:]]+
18-
env:
19-
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
17+
- name: Checkout repository
18+
uses: actions/checkout@v3
19+
20+
- name: Run unit tests and linter
21+
run: docker build --target test .
2022

2123
build-and-push-image:
24+
if: startsWith(github.ref, 'refs/tags/v') || github.event_name == 'pull_request'
25+
needs: test
2226
runs-on: ubuntu-latest
2327
permissions:
2428
contents: read
@@ -48,3 +52,14 @@ jobs:
4852
push: true
4953
tags: ${{ steps.meta.outputs.tags }}
5054
labels: ${{ steps.meta.outputs.labels }}
55+
release:
56+
runs-on: ubuntu-latest
57+
needs: build-and-push-image
58+
if: startsWith(github.ref, 'refs/tags/v')
59+
steps:
60+
- name: Create GitHub release
61+
uses: Roang-zero1/github-create-release-action@master
62+
with:
63+
version_regex: ^v[[:digit:]]+\.[[:digit:]]+\.[[:digit:]]+
64+
env:
65+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

.pre-commit-config.yaml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
default_language_version:
2+
python: python3.11
13
repos:
24
- repo: https://github.com/pre-commit/pre-commit-hooks
35
rev: v3.2.0

Dockerfile

Lines changed: 22 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,27 @@
1-
FROM python:3.9.10 AS build
1+
FROM python:3.11-slim AS base
2+
3+
WORKDIR /opt/brpc
24
COPY requirements.txt .
3-
RUN pip install -r ./requirements.txt
5+
RUN pip install --no-cache-dir -r requirements.txt
6+
7+
8+
FROM base AS test
9+
10+
COPY requirements-dev.txt .
11+
RUN pip install --no-cache-dir -r requirements-dev.txt
12+
13+
COPY src/*.py ./
14+
COPY src/tests tests
15+
16+
RUN coverage run --branch -m pytest
17+
RUN coverage report --fail-under 90
18+
RUN pylint *.py
419

5-
FROM gcr.io/distroless/python3:nonroot
20+
FROM base AS prod
621

7-
COPY --from=build /usr/local/lib/python3.9/site-packages/ \
8-
/usr/lib/python3.9/.
22+
COPY src/*.py ./
923

10-
ENV LC_ALL C.UTF-8
11-
WORKDIR /usr/src/app
12-
COPY src/*.py .
13-
COPY src/collectors/* collectors/
14-
# https://github.com/GoogleContainerTools/distroless/blob/main/experimental/python3/BUILD#L77
24+
RUN useradd -r -s /sbin/nologin nonroot
1525
USER nonroot
16-
CMD ["exporter.py"]
26+
EXPOSE 8080
27+
CMD [ "python", "exporter.py" ]

README.md

Lines changed: 31 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,21 +17,22 @@ Please note that this tool is in the early development stage and should not be u
1717
The project in its current form suits our short-term needs and will receive limited support. We encourage you to fork the project and extend it with additional functionality you might need.
1818

1919
## Development
20-
You should install [pre-commit](https://pre-commit.com/) so that automated linting and formatting checks are performed before each commit.
20+
You should install [pre-commit](https://pre-commit.com/) so that automated linting and formatting checks are performed before each commit.
2121

2222
Run:
2323
```bash
2424
pip install pre-commit
2525
pre-commit install
2626
```
2727
### Running locally
28-
1. Make sure you have python3 installed (>3.9.10)
28+
1. Make sure you have python3 installed (>3.11)
2929
2. Set up your python environment
3030
```bash
3131
pip3 install virtualenv
3232
virtualenv venv
3333
source venv/bin/activate
3434
pip install -r requirements.txt
35+
pip install -r requirements-dev.txt
3536
```
3637
1. Generate valid exporter config and validation file. For example see [config example](config/exporter_example/config.yml) and [validation example](config/exporter_example/validation.yml).
3738
2. Export paths of generated configuration files relative to `src/exporter.py`:
@@ -53,8 +54,35 @@ export CONFIG_FILE_PATH="src/config.yml" # For example if we saved config file
5354
3. Execute
5455
```bash
5556
docker-compose build
56-
docker-compose-up
57+
docker-compose up
5758
curl localhost:8000/metrics # Exporter
5859
curl localhost:3000 # Grafana
5960
curl localhost:9090 # Prometheus
6061
```
62+
63+
### Testing
64+
Testing is performed using [pytest](https://docs.pytest.org/) run by [coverage.py](https://coverage.readthedocs.io/) to generate test coverage reporting.
65+
[pylint](https://pylint.readthedocs.io/) is used to lint the pyhton code.
66+
These dependencies can be found in the [requirements-dev.txt](requirements-dev.txt) file. Unit testing and linting is performed on every commit push to the repository. 90% test coverage and no linter errors/warnings are a requirement for the tests to pass.
67+
68+
#### Testing Locally (venv)
69+
Tests can be run locally in the virtual environment.
70+
1. Run the unit tests with coverage.py from within the `src` directory.
71+
```bash
72+
coverage run --branch -m pytest
73+
```
74+
2. Generate the coverage report. To view the report open the generated `index.html` file in a browser.
75+
```bash
76+
coverage html
77+
```
78+
3. Run the linter to find any errors/warnings.
79+
```bash
80+
pylint src/*py
81+
```
82+
83+
#### Testing Locally (docker)
84+
The tests and linter can be run using docker by building the `test` docker stage.
85+
1. Build the `test` stage in the `Dockerfile`.
86+
```bash
87+
docker build --target test .
88+
```

docker-compose.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ services:
1818
- monitoring
1919
volumes:
2020
- type: bind
21-
source: ${PWD}/${CONFIGURATION_FILE_PATH}
21+
source: ${PWD}/${CONFIG_FILE_PATH}
2222
target: /config/config.yml
2323
- type: bind
2424
source: ${PWD}/${VALIDATION_FILE_PATH}

requirements-dev.txt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
pytest==7.2.1
2+
pylint==2.16.2
3+
coverage==7.1.0
4+
requests==2.28.2
5+
requests_mock==1.10.0

requirements.txt

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
prometheus-client==0.13.1
33
pyyaml==6.0
44
schema==0.7.5
5-
websockets==10.3
5+
websockets==10.4
66
structlog==22.1.0
7-
requests==2.28.1
7+
requests==2.28.1
8+
jsonrpcclient==4.0.2

src/cache.py

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
"""Module for providing in-memory cache"""
2+
3+
4+
class Cache():
5+
"""A rudimentary in-memory cache implementation."""
6+
7+
def __init__(self):
8+
self._cache = {}
9+
10+
def is_cached(self, key: str):
11+
"""Check if key is cached."""
12+
if key in self._cache:
13+
return True
14+
return False
15+
16+
def store_key_value(self, key: str, value):
17+
"""Stores key-value in cache dict."""
18+
self._cache[key] = value
19+
20+
def retrieve_key_value(self, key: str):
21+
"""Retrieves key value from cache."""
22+
if self.is_cached(key):
23+
return self._cache.get(key)
24+
return None
25+
26+
def remove_key_from_cache(self, key: str):
27+
"""Deletes a key from cache."""
28+
if self.is_cached(key):
29+
del self._cache[key]
30+
31+
def clear_cache(self):
32+
"""Clears the entire cache"""
33+
self._cache.clear()

0 commit comments

Comments
 (0)