@ -12,9 +12,6 @@
|
||||
expire_in: "30 days"
|
||||
when: always
|
||||
reports:
|
||||
coverage_report:
|
||||
coverage_format: cobertura
|
||||
path: artifacts/coverage.xml
|
||||
junit:
|
||||
- artifacts/*.JUnit.xml
|
||||
paths:
|
||||
@ -39,6 +36,46 @@ Unit:
|
||||
script:
|
||||
- pytest --cov --cov-report term --cov-report xml:../artifacts/coverage.xml --cov-report html:../artifacts/coverage/ --junit-xml=../artifacts/unit.JUnit.xml **/tests/unit
|
||||
coverage: '/(?i)total.*? (100(?:\.0+)?\%|[1-9]?\d(?:\.\d+)?\%)$/'
|
||||
artifacts:
|
||||
expire_in: "30 days"
|
||||
when: always
|
||||
reports:
|
||||
coverage_report:
|
||||
coverage_format: cobertura
|
||||
path: artifacts/coverage.xml
|
||||
junit:
|
||||
- artifacts/*.JUnit.xml
|
||||
paths:
|
||||
- artifacts/
|
||||
environment:
|
||||
name: Unit Test Coverage Report
|
||||
url: https://nofusscomputing.gitlab.io/-/projects/django_template/-/jobs/${CI_JOB_ID}/artifacts/artifacts/coverage/index.html
|
||||
|
||||
|
||||
UI:
|
||||
extends: .pytest
|
||||
script:
|
||||
- apk update
|
||||
- apk add chromium-chromedriver
|
||||
- pytest --junit-xml=../artifacts/ui.JUnit.xml **/tests/ui
|
||||
artifacts:
|
||||
expire_in: "30 days"
|
||||
when: always
|
||||
reports:
|
||||
junit:
|
||||
- artifacts/*.JUnit.xml
|
||||
paths:
|
||||
- artifacts/
|
||||
rules:
|
||||
- if: # Occur on merge
|
||||
$CI_COMMIT_BRANCH
|
||||
&&
|
||||
(
|
||||
$CI_PIPELINE_SOURCE == "push"
|
||||
||
|
||||
$CI_PIPELINE_SOURCE == "web"
|
||||
)
|
||||
allow_failure: true
|
||||
when: always
|
||||
|
||||
- when: never
|
||||
|
86
app/app/tests/ui/conftest.py
Normal file
86
app/app/tests/ui/conftest.py
Normal file
@ -0,0 +1,86 @@
|
||||
from app.urls import urlpatterns
|
||||
|
||||
class Data:
|
||||
|
||||
|
||||
def parse_urls(self, patterns, parent_route = None) -> list:
|
||||
|
||||
urls = []
|
||||
|
||||
root_paths = [
|
||||
'access',
|
||||
# 'account',
|
||||
# 'api',
|
||||
'config_management',
|
||||
'history',
|
||||
'itam',
|
||||
'organization',
|
||||
'settings'
|
||||
]
|
||||
|
||||
for url in patterns:
|
||||
|
||||
if hasattr(url, 'pattern'):
|
||||
|
||||
route = None
|
||||
|
||||
if hasattr(url.pattern, '_route'):
|
||||
|
||||
if parent_route:
|
||||
|
||||
route = parent_route + url.pattern._route
|
||||
|
||||
route = str(route).replace('<int:device_id>', '1')
|
||||
route = str(route).replace('<int:group_id>', '1')
|
||||
route = str(route).replace('<int:operating_system_id>', '1')
|
||||
route = str(route).replace('<int:organization_id>', '1')
|
||||
route = str(route).replace('<int:pk>', '1')
|
||||
route = str(route).replace('<int:software_id>', '1')
|
||||
route = str(route).replace('<int:team_id>', '1')
|
||||
|
||||
if route != '' and route not in urls:
|
||||
|
||||
urls += [ route ]
|
||||
|
||||
else:
|
||||
|
||||
route = url.pattern._route
|
||||
|
||||
route = str(route).replace('<int:device_id>', '1')
|
||||
route = str(route).replace('<int:group_id>', '1')
|
||||
route = str(route).replace('<int:operating_system_id>', '1')
|
||||
route = str(route).replace('<int:organization_id>', '1')
|
||||
route = str(route).replace('<int:pk>', '1')
|
||||
route = str(route).replace('<int:software_id>', '1')
|
||||
route = str(route).replace('<int:team_id>', '1')
|
||||
|
||||
if str(url.pattern._route).replace('/', '') in root_paths:
|
||||
|
||||
if route != '' and route not in urls:
|
||||
|
||||
urls += [ route ]
|
||||
|
||||
if hasattr(url, 'url_patterns'):
|
||||
|
||||
if str(url.pattern._route).replace('/', '') in root_paths:
|
||||
|
||||
urls += self.parse_urls(patterns=url.url_patterns, parent_route=url.pattern._route)
|
||||
|
||||
return urls
|
||||
|
||||
|
||||
def __init__(self):
|
||||
|
||||
urls = []
|
||||
|
||||
patterns = urlpatterns
|
||||
|
||||
urls_found = self.parse_urls(patterns=patterns)
|
||||
|
||||
for url in urls_found:
|
||||
|
||||
if url not in urls:
|
||||
|
||||
urls += [ url ]
|
||||
|
||||
self.urls = urls
|
141
app/app/tests/ui/test_page_links.py
Normal file
141
app/app/tests/ui/test_page_links.py
Normal file
@ -0,0 +1,141 @@
|
||||
import pytest
|
||||
import re
|
||||
import requests
|
||||
import unittest
|
||||
|
||||
from django.test import LiveServerTestCase
|
||||
|
||||
from app.urls import urlpatterns
|
||||
|
||||
from conftest import Data
|
||||
|
||||
@pytest.mark.skip(reason="test server required to be setup so tests work.")
|
||||
class TestRenderedTemplateLinks:
|
||||
"""UI Links tests """
|
||||
|
||||
server_host: str = '127.0.0.1'
|
||||
# server_host: str = '192.168.1.172'
|
||||
server_url: str = 'http://' + server_host + ':8002/'
|
||||
|
||||
|
||||
data = Data()
|
||||
|
||||
driver = None
|
||||
""" Chrome webdriver """
|
||||
|
||||
session = None
|
||||
""" Client session that is logged into the dejango site """
|
||||
|
||||
|
||||
def setup_class(self):
|
||||
""" Set up the test
|
||||
|
||||
1. fetch session cookie
|
||||
2. login to site
|
||||
3. save session for use in tests
|
||||
"""
|
||||
|
||||
self.session = requests.Session()
|
||||
|
||||
# fetch the csrf token
|
||||
self.session.get(
|
||||
url = self.server_url + 'account/login/',
|
||||
)
|
||||
|
||||
# login
|
||||
self.client = self.session.post(
|
||||
url = self.server_url + 'account/login/',
|
||||
data = {
|
||||
'username': 'admin',
|
||||
'password': 'admin',
|
||||
'csrfmiddlewaretoken': self.session.cookies._cookies[self.server_host]['/']['csrftoken'].value
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
argnames='url',
|
||||
argvalues=[link for link in data.urls],
|
||||
ids=[link for link in data.urls]
|
||||
)
|
||||
def test_ui_no_http_forbidden(self, url):
|
||||
""" Test Page Links
|
||||
|
||||
Scrape the page for links and ensure none return HTTP/403.
|
||||
|
||||
Test failure denotes a link on a page that should have been filtered out by testing for user
|
||||
permissions within the template.
|
||||
|
||||
Args:
|
||||
url (str): Page to test
|
||||
"""
|
||||
|
||||
response = self.session.get(
|
||||
url = str(self.server_url + url)
|
||||
)
|
||||
|
||||
# Failsafe to ensure no redirection and that page exists
|
||||
assert len(response.history) == 0
|
||||
assert response.status_code == 200
|
||||
|
||||
page_urls = []
|
||||
|
||||
page = str(response.content)
|
||||
|
||||
links = re.findall('href=\"([a-z\/0-9]+)\"', page)
|
||||
|
||||
for link in links:
|
||||
|
||||
page_link_response = self.session.get(
|
||||
url = str(self.server_url + link)
|
||||
)
|
||||
|
||||
# Failsafe to ensure no redirection
|
||||
assert len(response.history) == 0
|
||||
|
||||
assert page_link_response.status_code != 403
|
||||
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
argnames='url',
|
||||
argvalues=[link for link in data.urls],
|
||||
ids=[link for link in data.urls]
|
||||
)
|
||||
def test_ui_no_http_not_found(self, url):
|
||||
""" Test Page Links
|
||||
|
||||
Scrape the page for links and ensure none return HTTP/404.
|
||||
|
||||
Test failure denotes a link on a page that should not exist within the template.
|
||||
|
||||
Args:
|
||||
url (str): Page to test
|
||||
"""
|
||||
|
||||
response = self.session.get(
|
||||
url = str(self.server_url + url)
|
||||
)
|
||||
|
||||
# Failsafe to ensure no redirection and that page exists
|
||||
assert len(response.history) == 0
|
||||
assert response.status_code == 200
|
||||
|
||||
page_urls = []
|
||||
|
||||
page = str(response.content)
|
||||
|
||||
links = re.findall('href=\"([a-z\/0-9]+)\"', page)
|
||||
|
||||
for link in links:
|
||||
|
||||
page_link_response = self.session.get(
|
||||
url = str(self.server_url + link)
|
||||
)
|
||||
|
||||
# Failsafe to ensure no redirection
|
||||
assert len(response.history) == 0
|
||||
|
||||
assert page_link_response.status_code != 404
|
||||
|
@ -8,6 +8,8 @@ about: https://gitlab.com/nofusscomputing/infrastructure/configuration-managemen
|
||||
|
||||
Unit tests are written to aid in application stability and to assist in preventing regression bugs. As part of development the developer working on a Merge/Pull request is to ensure that tests are written. Failing to do so will more likely than not ensure that your Merge/Pull request is not merged.
|
||||
|
||||
User Interface (UI) test are written to test the user interface to ensure that it functions as it should. Changes to the UI will need to be tested.
|
||||
|
||||
|
||||
## Writing Tests
|
||||
|
||||
|
@ -1,4 +1,6 @@
|
||||
pytest==8.2.0
|
||||
pytest-django==4.8.0
|
||||
coverage==7.5.1
|
||||
pytest-cov==5.0.0
|
||||
pytest-cov==5.0.0
|
||||
|
||||
# selenium==4.21.0
|
Reference in New Issue
Block a user