forked from inno-devops-labs/S25-core-course-labs
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #4 from VoronM1522/lab3
Lab3
- Loading branch information
Showing
9 changed files
with
310 additions
and
13 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,75 @@ | ||
name: Application CI | ||
|
||
on: | ||
push: | ||
|
||
env: | ||
USERNAME: voronm1522 | ||
DOCKER_IMAGE: voronm1522/devops | ||
DOCKER_TAG: python-app | ||
|
||
jobs: | ||
build-and-test: | ||
runs-on: ubuntu-latest | ||
|
||
steps: | ||
- name: Cache python | ||
uses: actions/cache@v4 | ||
with: | ||
path: ~/.cache/pip | ||
key: ubuntu-python-${{ hashFiles('app_python/requirements.txt') }} | ||
restore-keys: | | ||
ubuntu-python- | ||
- uses: actions/checkout@v3 | ||
|
||
- name: Set up python | ||
uses: actions/setup-python@v3 | ||
with: | ||
python-version: '3.10' | ||
|
||
- name: Install dependencies and linter | ||
run: | | ||
python -m pip install --upgrade pip | ||
pip install flake8 | ||
pip install -r app_python/requirements.txt | ||
- name: Lint with flake8 | ||
run: | | ||
flake8 app_python/app.py | ||
- name: Run tests | ||
run: | | ||
python app_python/unittests.py | ||
- name: Login to Docker Hub | ||
uses: docker/login-action@v2 | ||
with: | ||
username: ${{ env.USERNAME }} | ||
password: ${{ secrets.DOCKERHUB_PASSWORD }} | ||
|
||
- name: Cache Docker layers | ||
uses: actions/cache@v3 | ||
with: | ||
path: /tmp/.buildx-cache | ||
key: ubuntu-docker-${{ hashFiles('app_python/Dockerfile') }} | ||
restore-keys: | | ||
ubuntu-docker- | ||
- name: Build and push Docker image | ||
uses: docker/build-push-action@v4 | ||
with: | ||
context: app_python | ||
push: true | ||
tags: ${{ env.DOCKER_IMAGE }}:${{ env.DOCKER_TAG }} | ||
|
||
- name: Install snyk | ||
run: npm install -g snyk | ||
|
||
- name: Run snyk | ||
run: | | ||
cd app_python | ||
snyk test | ||
env: | ||
SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }} | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,4 @@ | ||
*.md | ||
Dockerfile | ||
.dockerignore | ||
.dockerignore | ||
unittests.py |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,69 @@ | ||
name: Application CI | ||
|
||
on: | ||
push: | ||
|
||
env: | ||
USERNAME: voronm1522 | ||
DOCKER_IMAGE: voronm1522/devops | ||
DOCKER_TAG: python-app | ||
|
||
jobs: | ||
build-and-test: | ||
runs-on: ubuntu-latest | ||
|
||
steps: | ||
- name: Cache python | ||
uses: actions/cache@v4 | ||
with: | ||
path: ~/.cache/pip | ||
key: ubuntu-python-${{ hashFiles('app_python/requirements.txt') }} | ||
restore-keys: | | ||
ubuntu-python- | ||
- uses: actions/checkout@v3 | ||
|
||
- name: Set up python | ||
uses: actions/setup-python@v3 | ||
with: | ||
python-version: '3.10' | ||
|
||
- name: Install dependencies and linter | ||
run: | | ||
python -m pip install --upgrade pip | ||
pip install flake8 | ||
pip install -r app_python/requirements.txt | ||
- name: Lint with flake8 | ||
run: | | ||
flake8 app_python/app.py | ||
- name: Run tests | ||
run: | | ||
python app_python/unittests.py | ||
- name: Login to Docker Hub | ||
uses: docker/login-action@v2 | ||
with: | ||
username: ${{ env.USERNAME }} | ||
password: ${{ secrets.DOCKERHUB_PASSWORD }} | ||
|
||
- name: Cache Docker layers | ||
uses: actions/cache@v3 | ||
with: | ||
path: /tmp/.buildx-cache | ||
key: ubuntu-docker-${{ hashFiles('app_python/Dockerfile') }} | ||
restore-keys: | | ||
ubuntu-docker- | ||
- name: Build and push Docker image | ||
uses: docker/build-push-action@v4 | ||
with: | ||
context: app_python | ||
push: true | ||
tags: ${{ env.DOCKER_IMAGE }}:${{ env.DOCKER_TAG }} | ||
|
||
- name: Run snyk | ||
uses: snyk/actions/python-3.10@master | ||
env: | ||
SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
## CI | ||
|
||
For optimizing CI I used the next best practices: | ||
- Caching | ||
- For python requirements | ||
- For Dockerfile | ||
- Vulnerability checking | ||
- Atomic execution for commands (in one `run:` section) | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Binary file not shown.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,104 @@ | ||
import unittest, pytz, os | ||
from app import app, current_time, get_timezone | ||
from datetime import datetime | ||
|
||
|
||
|
||
CONFIG_FILE = "config.txt" | ||
|
||
|
||
|
||
class TestFlaskApp(unittest.TestCase): | ||
def setUp(self): | ||
"""Client settings""" | ||
|
||
self.app = app.test_client() | ||
self.app.testing = True | ||
|
||
|
||
def test_current_time_endpoint(self): | ||
"""Correctness test for endpoint '/'""" | ||
|
||
response = self.app.get("/") | ||
|
||
self.assertEqual(response.status_code, 200) | ||
response_text = response.data.decode("utf-8") | ||
self.assertIn("Current time in", response_text) | ||
self.assertIn("is", response_text) | ||
|
||
|
||
def test_get_timezone_valid(self): | ||
"""Valid time zone reading test""" | ||
|
||
if os.path.exists("test_get_timezone_valid_config.txt"): | ||
os.remove("test_get_timezone_valid_config.txt") | ||
|
||
with open("test_get_timezone_valid_config.txt", "w+") as file: | ||
file.write("Europe/London\n") | ||
|
||
timezone = get_timezone("test_get_timezone_valid_config.txt") | ||
os.remove("test_get_timezone_valid_config.txt") | ||
self.assertEqual(timezone, pytz.timezone("Europe/London")) | ||
|
||
|
||
def test_get_timezone_invalid(self): | ||
"""Invalid time zone reading test""" | ||
|
||
if os.path.exists("test_get_timezone_invalid_config.txt"): | ||
os.remove("test_get_timezone_invalid_config.txt") | ||
|
||
with open("test_get_timezone_invalid_config.txt", "w+") as file: | ||
file.write("Invalid/Timezone\n") | ||
|
||
timezone = get_timezone("test_get_timezone_invalid_config.txt") | ||
os.remove("test_get_timezone_invalid_config.txt") | ||
self.assertEqual(timezone, pytz.timezone("Europe/Moscow")) | ||
|
||
|
||
def test_get_timezone_empty(self): | ||
"""Empty configure file testing""" | ||
|
||
if os.path.exists("test_get_timezone_empty_config.txt"): | ||
os.remove("test_get_timezone_empty_config.txt") | ||
|
||
with open("test_get_timezone_empty_config.txt", "w+") as file: | ||
file.write("\n") | ||
|
||
timezone = get_timezone("test_get_timezone_empty_config.txt") | ||
os.remove("test_get_timezone_empty_config.txt") | ||
self.assertEqual(timezone, pytz.timezone("Europe/Moscow")) | ||
|
||
|
||
def test_get_timezone_file_not_found(self): | ||
"""No configuration file testing""" | ||
|
||
timezone = get_timezone("") | ||
self.assertEqual(timezone, pytz.timezone("Europe/Moscow")) | ||
|
||
|
||
def test_timezone_format(self): | ||
"""Format testing in response""" | ||
|
||
response = self.app.get("/") | ||
response_text = response.data.decode("utf-8") | ||
|
||
import re | ||
time_pattern = r"\d{2}:\d{2}:\d{2}" | ||
self.assertTrue(re.search(time_pattern, response_text)) | ||
|
||
|
||
def test_full_response(self): | ||
"""Full answer testing""" | ||
|
||
try: | ||
with open(CONFIG_FILE, "r") as config_file: | ||
time_zone = pytz.timezone(config_file.read().strip()) | ||
except Exception: | ||
time_zone = pytz.timezone("Europe/Moscow") | ||
|
||
self.assertEqual(current_time(), f"Current time in {time_zone} is {datetime.now(time_zone).strftime('%H:%M:%S')}") | ||
|
||
|
||
|
||
if __name__ == "__main__": | ||
unittest.main() |