Commit 20647618 authored by Esther Vogt's avatar Esther Vogt
Browse files

Merge branch 'development' into 'master'

Deploy final version

See merge request !11
parents d8736029 6e5f73a2
Pipeline #171591 passed with stage
in 30 seconds
backend/secfit/.vscode/ gitbackend/secfit/.vscode/
backend/secfit/*/migrations/__pycache__/ backend/secfit/*/migrations/__pycache__/
backend/secfit/*/__pycache__/ backend/secfit/*/__pycache__/
backend/secfit/db.sqlite3 backend/secfit/db.sqlite3
...@@ -10,4 +10,9 @@ package-lock.json ...@@ -10,4 +10,9 @@ package-lock.json
/backend/secfit/coverage.xml /backend/secfit/coverage.xml
/backend/secfit/report.xml /backend/secfit/report.xml
/backend/secfit/htmlcov/ /backend/secfit/htmlcov/
chromedriver.exe
/tests/.pytest_cache/
/tests/report.xml
/tests/report.html
node_modules node_modules
/tests/.pytest_cache/
...@@ -7,10 +7,9 @@ variables: ...@@ -7,10 +7,9 @@ variables:
stages: stages:
- test-init - test-init
- dpl-dev # deploy a review app - dpl-dev # deploy a review app
# - test-dev # run black box testing against the review app - test-dev # run black box testing against the review app
- dpl-prod # deploy the productive app - dpl-prod # deploy the productive app
integration-test-backend: integration-test-backend:
# generate junit xml report + coverage report -> see backend/secfit/pytest.ini # generate junit xml report + coverage report -> see backend/secfit/pytest.ini
image: python:3.8 image: python:3.8
...@@ -30,40 +29,86 @@ integration-test-backend: ...@@ -30,40 +29,86 @@ integration-test-backend:
cobertura: backend/secfit/coverage.xml cobertura: backend/secfit/coverage.xml
coverage: '/TOTAL.*\s+(\d+\%)/' coverage: '/TOTAL.*\s+(\d+\%)/'
deploy-dev: deploy-dev:
image: ruby image: ruby
stage: dpl-dev stage: dpl-dev
variables:
HEROKU_API_KEY: $HEROKU_STAGING_API_KEY
script: script:
# update the list of available packages - apt-get update
- apt-get update -qy - apt-get install apt-transport-https
# install the Ruby runtime on system - echo "deb https://cli-assets.heroku.com/branches/stable/apt ./" > /etc/apt/sources.list.d/heroku.list
- apt-get install -y ruby-dev - wget -O- https://cli-assets.heroku.com/apt/release.key | apt-key add -
- apt-get update
- apt-get install -y heroku ruby-dev
- gem install dpl - gem install dpl
- dpl --provider=heroku --app=$APP_NAME_FRONTEND_DEV --api-key=$HEROKU_STAGING_API_KEY - dpl --provider=heroku --app=$APP_NAME_FRONTEND_DEV --api-key=$HEROKU_STAGING_API_KEY
- dpl --provider=heroku --app=$APP_NAME_BACKEND_DEV --api-key=$HEROKU_STAGING_API_KEY - dpl --provider=heroku --app=$APP_NAME_BACKEND_DEV --api-key=$HEROKU_STAGING_API_KEY
# - heroku pg:reset --confirm $APP_NAME_BACKEND_DEV --exit-code --app $APP_NAME_BACKEND_DEV
# - heroku run python backend/secfit/manage.py migrate -a $APP_NAME_BACKEND_DEV
- echo "Deployed to DEV server" - echo "Deployed to DEV server"
- heroku pg:reset --confirm $APP_NAME_BACKEND_DEV -a $APP_NAME_BACKEND_DEV
- heroku run python backend/secfit/manage.py migrate -a $APP_NAME_BACKEND_DEV
- heroku run python backend/secfit/manage.py loaddata backend/secfit/seed_test.json -a $APP_NAME_BACKEND_DEV
- echo "Reset DB, ran migrations and uploaded seed data for testing."
only: only:
- add-team - development
#
#bb-test-frontend:chrome: two-way-domain:chrome:
# image: python:3.8 image: python:3.8
# stage: test-dev stage: test-dev
# services: when: manual
# - selenium/standalone-chrome services:
# script: - selenium/standalone-chrome
# - cd tests script:
# - apt-get update -qy - cd tests
# - pip install -r requirements.txt - apt-get update -qy
# - pytest --browser=$BROWSER --local='false' - pip install -r requirements.txt
# artifacts: - pytest test_register_domain.py -rP --perform_setup false --verbose --junitxml=test_register_domain.xml --browser=$BROWSER --local='false'
# when: always # also upload reports if job fails artifacts:
# expire_in: 1 week when: always # also upload reports if job fails
# reports: expire_in: 1 week
# junit: tests/report.xml reports:
# only: junit: tests/test_register_domain.xml
# - bbtesting-ex2-t3 only:
- development
bva-register:chrome:
image: python:3.8
stage: test-dev
when: manual
services:
- selenium/standalone-chrome
script:
- cd tests
- apt-get update -qy
- pip install -r requirements.txt
- pytest test_register_bva.py -rP --perform_setup false --verbose --junitxml=test_register_bva.xml --browser=$BROWSER --local='false'
artifacts:
when: always # also upload reports if job fails
expire_in: 1 week
reports:
junit: tests/test_register_bva.xml
only:
- development
bva-exercises:chrome:
image: python:3.8
stage: test-dev
when: manual
services:
- selenium/standalone-chrome
script:
- cd tests
- apt-get update -qy
- pip install -r requirements.txt
- pytest test_exercises_bva.py -rP --perform_setup false --verbose --junitxml=test_exercises_bva.xml --browser=$BROWSER --local='false'
artifacts:
when: always # also upload reports if job fails
expire_in: 1 week
reports:
junit: tests/test_exercises_bva.xml
only:
- development
deploy-prod: deploy-prod:
image: ruby image: ruby
...@@ -71,12 +116,17 @@ deploy-prod: ...@@ -71,12 +116,17 @@ deploy-prod:
when: manual when: manual
allow_failure: false allow_failure: false
script: script:
- apt-get update -qy - apt-get update
- apt-get install -y ruby-dev - apt-get install apt-transport-https
- echo "deb https://cli-assets.heroku.com/branches/stable/apt ./" > /etc/apt/sources.list.d/heroku.list
- wget -O- https://cli-assets.heroku.com/apt/release.key | apt-key add -
- apt-get update
- apt-get install -y heroku ruby-dev
- gem install dpl - gem install dpl
- dpl --provider=heroku --app=$APP_NAME_FRONTEND_PROD --api-key=$HEROKU_STAGING_API_KEY - dpl --provider=heroku --app=$APP_NAME_FRONTEND_PROD --api-key=$HEROKU_STAGING_API_KEY
- dpl --provider=heroku --app=$APP_NAME_BACKEND_PROD --api-key=$HEROKU_STAGING_API_KEY - dpl --provider=heroku --app=$APP_NAME_BACKEND_PROD --api-key=$HEROKU_STAGING_API_KEY
# - heroku run python backend/secfit/manage.py migrate -a $APP_NAME_BACKEND_PROD
- echo "Deployed to PROD server" - echo "Deployed to PROD server"
- heroku run python backend/secfit/manage.py migrate -a $APP_NAME_BACKEND_PROD
- echo "Ran migrations on PROD backend"
only: only:
- master - master
...@@ -270,6 +270,11 @@ scripts except __init__.py file and re-create migrations ...@@ -270,6 +270,11 @@ scripts except __init__.py file and re-create migrations
### Test-driven development (TDD) / CI/CD ### Test-driven development (TDD) / CI/CD
##
**Q:** What should a typical CI/CD pipeline look like?
- [Gitlab Docu Pipeline Architectures](https://docs.gitlab.com/ee/ci/pipelines/pipeline_architectures.html)
- [Medium intro to Gitlab Jobs, Stages, Pipelines](https://medium.com/@ryzmen/gitlab-fast-pipelines-stages-jobs-c51c829b9aa1)
## ##
**Q:** What is the general concept of CI/CD? How does this look like on Gitlab? **Q:** What is the general concept of CI/CD? How does this look like on Gitlab?
- References: - References:
...@@ -288,8 +293,8 @@ Human intervention is not required. ...@@ -288,8 +293,8 @@ Human intervention is not required.
- **Selenium and WebdriverIO** - **Selenium and WebdriverIO**
- References: - References:
- [Gitlab Docu](https://docs.gitlab.com/ee/ci/examples/end_to_end_testing_webdriverio/) - [Gitlab Docu](https://docs.gitlab.com/ee/ci/examples/end_to_end_testing_webdriverio/)
- for JavaScript-based applications - **Selenium**: Selenium is a piece of software that can control web browsers (=JavaScript-based applications), e.g.,
- **Selenium**: Selenium is a piece of software that can control web browsers, e.g., to make them visit a specific URL to make them visit a specific URL
or interact with elements on the page. It can be programmatically controlled from a variety of programming languages. or interact with elements on the page. It can be programmatically controlled from a variety of programming languages.
- **WebdriverIO**: - **WebdriverIO**:
- functions: - functions:
...@@ -303,8 +308,48 @@ can simply pass CSS selectors to browser.element to get access to elements on th ...@@ -303,8 +308,48 @@ can simply pass CSS selectors to browser.element to get access to elements on th
example, to click on the link back to the home page. example, to click on the link back to the home page.
## ##
**Q:** How to run tests locally with Selenium and WebdriverIO? **Q:** How to run tests on the frontend with Selenium and WebdriverIO?
- [Gitlab Docu - Selenium/WebdriverIO](https://docs.gitlab.com/ee/ci/examples/end_to_end_testing_webdriverio/#running-locally) - [General Gitlab Docu - Selenium/WebdriverIO](https://docs.gitlab.com/ee/ci/examples/end_to_end_testing_webdriverio/#running-locally)
- [Selenium with Docker and Gitlab](https://github.com/esthervogt/python-gitlabci-selenium)
- very helpful!
- [E2E Testing with separate backend/frontend](https://bierus.medium.com/end-2-end-testing-with-separated-fronted-f2a5dc5be12)
- [Strategies for removal of test data](https://bierus.medium.com/end-2-end-testing-with-separated-fronted-f2a5dc5be12)
##
**Q:** How to launch a selenium chrome standalone browser?
- [Stackoverflow Article](https://stackoverflow.com/questions/45323271/how-to-run-selenium-with-chrome-in-docker)
- start container: ```docker run -d -p 4444:4444 selenium/standalone-chrome```
- stop container: ```docker stop <CONTAINER ID>```
- run: ```pytest```
##
**Q:** What is the difference between pytest.ini and conftest.py?
- pytest.ini: This is the primary pytest configuration file that allows you to change default behavior.
- conftest.py: This is a local plugin to allow hook functions and fixtures for the directory where the conftest.py file
exists and all subdirectories.
##
**Q:** How to make two tests depend on each other?
- [Stackoverflow article](https://stackoverflow.com/questions/10464502/how-can-i-skip-a-test-if-another-test-fails-with-py-test)
- use [```pip install pytest-dependency```](https://pypi.org/project/pytest-dependency/)
##
**Q:** What are helpful arguments for pytest?
- ```pytest -rP```: shows the captured output of passed tests
- ```pytest -rx```: shows the captured output of failed tests (default behaviour)
##
**Q:** What criteria is tested by the django EmailValidator?
- [Source Code EmailValidator](max length for domain name labels is 63 characters per RFC 1034)
##
**Q:** How to parameterize the generation of test functions?
- [Stackoverflow Article](https://stackoverflow.com/questions/32999470/parametrize-pytest-fixture/33208377#33208377)
##
**Q:** How to connect to localhost urls when running selenium in standalone container?
- [Stackoverflow Article](https://stackoverflow.com/questions/31324981/how-to-access-host-port-from-docker-container):
use host.docker.internal instead of localhost in the url
## ##
**Q:** What is the difference between unit, integration, functional, E2E and acceptance tests? **Q:** What is the difference between unit, integration, functional, E2E and acceptance tests?
...@@ -411,6 +456,12 @@ need to make sure that the given user account has sufficient privileges to creat ...@@ -411,6 +456,12 @@ need to make sure that the given user account has sufficient privileges to creat
image and a URL that the image points to. Examples for badges can be the pipeline status, test coverage, latest release, image and a URL that the image points to. Examples for badges can be the pipeline status, test coverage, latest release,
or ways to contact the project maintainers. or ways to contact the project maintainers.
##
**Q:** How to get the XPath of an element?
- Right-click "inspect" on the item you are trying to find the XPath.
- Right-click on the highlighted area on the HTML DOM.
- Go to Copy > select 'Copy XPath'.
## SecFit specifics ## SecFit specifics
## ##
**Q:** What are athlete_files? **Q:** What are athlete_files?
......
...@@ -46,7 +46,7 @@ RUN DJANGO_SUPERUSER_USERNAME=${DJANGO_SUPERUSER_USERNAME} \ ...@@ -46,7 +46,7 @@ RUN DJANGO_SUPERUSER_USERNAME=${DJANGO_SUPERUSER_USERNAME} \
&& echo "If you wish to alter the user credentials, then delete the user first." && echo "If you wish to alter the user credentials, then delete the user first."
# Create some exercises from seed data # Create some exercises from seed data
RUN python manage.py loaddata seed.json RUN python manage.py loaddata seed_test.json
#RUN python manage.py loaddata seed_users.json #RUN python manage.py loaddata seed_users.json
# Run wsgi server with gunicorn # Run wsgi server with gunicorn
......
[pytest] [pytest]
DJANGO_SETTINGS_MODULE=secfit.settings DJANGO_SETTINGS_MODULE=secfit.settings
python_files = tests.py test_*.py *_tests.py python_files = tests.py test_*.py *_tests.py
addopts = --junitxml=report.xml --cov-report term-missing --cov=. --cov-report xml:coverage.xml junit_logging = system-out
addopts = --verbose --junitxml=report.xml --cov-report term-missing --cov=. --cov-report xml:coverage.xml
\ No newline at end of file
[ [
{
"model": "workouts.workout",
"pk": 1,
"fields": {
"name": "workout1c1",
"date": "2022-03-23T22:10:00Z",
"notes": "workout1c1",
"owner": 6,
"visibility": "PU"
}
},
{
"model": "workouts.workout",
"pk": 2,
"fields": {
"name": "workout2c1",
"date": "2022-03-23T22:10:00Z",
"notes": "workout2c1",
"owner": 6,
"visibility": "CO"
}
},
{
"model": "workouts.workout",
"pk": 3,
"fields": {
"name": "workout3c1",
"date": "2022-03-23T22:12:00Z",
"notes": "workout3c1",
"owner": 6,
"visibility": "PR"
}
},
{
"model": "workouts.workout",
"pk": 4,
"fields": {
"name": "workout1a1",
"date": "2022-03-23T22:11:00Z",
"notes": "workout1a1",
"owner": 7,
"visibility": "PU"
}
},
{
"model": "workouts.workout",
"pk": 5,
"fields": {
"name": "workout2a1",
"date": "2022-03-23T22:12:00Z",
"notes": "workout2a1",
"owner": 7,
"visibility": "CO"
}
},
{
"model": "workouts.workout",
"pk": 6,
"fields": {
"name": "workout3a1",
"date": "2022-03-24T22:12:00Z",
"notes": "workout3a1",
"owner": 7,
"visibility": "PR"
}
},
{
"model": "workouts.exercise",
"pk": 1,
"fields": {
"name": "Push-up",
"description": "A push-up (or press-up in British English) is a common calisthenics exercise beginning from the prone position.",
"duration": 0,
"calories": 0,
"muscleGroup": "Legs",
"unit": "reps"
}
},
{
"model": "workouts.exercise",
"pk": 2,
"fields": {
"name": "Crunch",
"description": "The crunch is one of the most popular abdominal exercises.",
"duration": 0,
"calories": 0,
"muscleGroup": "Legs",
"unit": "reps"
}
},
{
"model": "workouts.exercise",
"pk": 3,
"fields": {
"name": "Plank",
"description": "The plank is an isometric core strength exercise that involves maintaining a position similar to a push-up for the maximum possible time.",
"duration": 0,
"calories": 0,
"muscleGroup": "Legs",
"unit": "seconds"
}
},
{
"model": "workouts.workoutfile",
"pk": 1,
"fields": {
"workout": 4,
"owner": 7,
"file": "workouts/4/workout-file.jpg"
}
},
{ {
"model": "users.user", "model": "users.user",
"pk": 1, "pk": 1,
"fields": { "fields": {
"password": "pbkdf2_sha256$216000$3BL8IxTEIkzV$Fh79DOZmk6CFrFE7/Glubxk50SzCkzF1P9cLKIqSpWk=", "password": "pbkdf2_sha256$216000$a6UXDemjTOVX$bJ/Y/PCpQj2fFTU/SsdM9Hhhx6KXYixFjMA2bL8XYNw=",
"last_login": "2022-03-02T12:47:32.750Z", "last_login": "2022-03-23T22:03:40.282Z",
"is_superuser": true, "is_superuser": true,
"username": "admin", "username": "admin",
"first_name": "", "first_name": "",
"last_name": "", "last_name": "",
"email": "esther-vogt@gmx.net",
"is_staff": true, "is_staff": true,
"is_active": true, "is_active": true,
"date_joined": "2022-02-23T19:40:47.604Z", "date_joined": "2022-03-21T10:38:29.564Z",
"email": "esther-vogt@gmx.net",
"coach": null, "coach": null,
"phone_number": "", "phone_number": "",
"country": "", "country": "",
"city": "", "city": "",
"street_address": "", "street_address": "",
"role": "Athletes", "role": "Athlete",
"groups": [], "groups": [],
"user_permissions": [] "user_permissions": []
} }
}, },
{ {
"model": "users.user", "model": "users.user",
"pk": 2, "pk": 6,
"fields": { "fields": {
"password": "pbkdf2_sha256$216000$MNqM0ESAfJh2$pE/EqC6q6EmCg0II1aBKGlHGEKhw3lPL6+h2tBswvWA=", "password": "pbkdf2_sha256$216000$leWVb2x2Y3wL$xgiz9vwhNoT1eu0+L20VKf+xhbnv7l/0h/jynJpld78=",
"last_login": null, "last_login": null,
"is_superuser": false, "is_superuser": false,
"username": "Tia-Clair_Toomey", "username": "coach1",
"first_name": "", "first_name": "",
"last_name": "", "last_name": "",
"email": "",
"is_staff": false, "is_staff": false,
"is_active": true, "is_active": true,
"date_joined": "2022-03-02T09:24:49.973Z", "date_joined": "2022-03-23T22:09:55.285Z",
"email": "coach1@domain.com",
"coach": null, "coach": null,
"phone_number": "", "phone_number": "",
"country": "", "country": "",
"city": "", "city": "",
"street_address": "", "street_address": "",
"role": "Athletes", "role": "Coach",
"groups": [ "groups": [
1 2
], ],
"user_permissions": [] "user_permissions": []
} }
}, },
{ {
"model": "users.user", "model": "users.user",
"pk": 3, "pk": 7,
"fields": { "fields": {
"password": "pbkdf2_sha256$216000$CSxiFJQhjEUf$UMcCuCV/9jXQRALtPUtLpeTmJKbhYGvXrfMWSfs5nGw=", "password": "pbkdf2_sha256$216000$1lJ8zIC8Gvzp$zJquv2euj3BmM3zEIwT8mgY+1Qs8jLmeEz0Ho3ACrho=",
"last_login": null, "last_login": null,
"is_superuser": false, "is_superuser": false,
"username": "Shane_Orr", "username": "athlete1",
"first_name": "", "first_name": "",
"last_name": "", "last_name": "",
"email": "",
"is_staff": false, "is_staff": false,
"is_active": true, "is_active": true,
"date_joined": "2022-03-02T09:25:06.583Z", "date_joined": "2022-03-23T22:11:36Z",
"coach": null, "email": "athlete1@domain.com",
"coach": 6,
"phone_number": "", "phone_number": "",
"country": "", "country": "",
"city": "", "city": "",
"street_address": "", "street_address": "",
"role": "Coaches", "role": "Athlete",
"groups": [ "groups": [
2 1
], ],
"user_permissions": [] "user_permissions": []
} }
}, },
{ {
"model": "users.user", "model": "users.user",
"pk": 4, "pk": 8,
"fields": { "fields": {
"password": "pbkdf2_sha256$216000$RBAIDnDJxplK$sfPpGuEVrNyXehX1r7sf7FeG690Lxl8kQQDG+U5XADw=", "password": "pbkdf2_sha256$216000$SOPjFEULUbnw$DbWevm8Na1TtNnSxil68TuTMY/NZLeQFlJ77g4m6xW0=",
"last_login": null, "last_login": null,
"is_superuser": false, "is_superuser": false,
"username": "Mat_Fraser", "username": "athlete2",
"first_name": "", "first_name": "",
"last_name": "", "last_name": "",
"email": "",
"is_staff": false, "is_staff": false,
"is_active": true, "is_active": true,
"date_joined": "2022-03-02T12:49:44.588Z", "date_joined": "2022-03-23T22:13:10Z",
"coach": null, "email": "athlete2@domain.com",
"coach": 6,
"phone_number": "", "phone_number": "",
"country": "", "country": "",
"city": "", "city": "",
"street_address": "", "street_address": "",
"role": "Athletes", "role": "Athlete",
"groups": [ "groups": [
1 1
], ],
"user_permissions": [] "user_permissions": []
} }
},
{
"model": "comments.comment",
"pk": 1,
"fields": {
"owner": 7,
"workout": 4,
"content": "some comment",
"timestamp": "2022-03-23T22:16:35.217Z"
}
} }