diff --git a/.travis.yml b/.travis.yml index 422cd932..8ca7a88e 100644 --- a/.travis.yml +++ b/.travis.yml @@ -9,8 +9,14 @@ python: - '3.6' install: - - pip install flake8 - pip install -r requirements.txt + - pip install flake8 + - pip install pytest-cov pytest coveralls + - pip install -e . script: + - pytest --cov=pshtt - flake8 . + +after_success: + - coveralls diff --git a/requirements.txt b/requirements.txt index 28ad4e89..2bf5775a 100644 --- a/requirements.txt +++ b/requirements.txt @@ -6,3 +6,5 @@ requests_cache pytablewriter publicsuffix pyopenssl==17.2.0 +tox +pytest diff --git a/tests/test_badssl.py b/tests/test_badssl.py new file mode 100644 index 00000000..7ee00cd1 --- /dev/null +++ b/tests/test_badssl.py @@ -0,0 +1,60 @@ +import unittest + +from pshtt.models import Domain, Endpoint +from pshtt.pshtt import basic_check, hsts_check + + +def inspect(base_domain): + """ + Mostly copied from pshtt.pshtt.inspect() + """ + domain = Domain(base_domain) + domain.http = Endpoint("http", "root", base_domain) + domain.httpwww = Endpoint("http", "www", base_domain) + domain.https = Endpoint("https", "root", base_domain) + domain.httpswww = Endpoint("https", "www", base_domain) + + return domain + + # Analyze HTTP endpoint responsiveness and behavior. + basic_check(domain.http) + basic_check(domain.httpwww) + basic_check(domain.https) + basic_check(domain.httpswww) + + # Analyze HSTS header, if present, on each HTTPS endpoint. + hsts_check(domain.https) + hsts_check(domain.httpswww) + + return domain + + +@unittest.skip('Disable live tests against badssl for now') +class TestCertificate(unittest.TestCase): + def test_https_expired(self): + domain = inspect('expired.badssl.com') + basic_check(domain.https) + + self.assertTrue(domain.https.https_expired_cert) + + def test_https_bad_hostname(self): + domain = inspect('wrong.host.badssl.com') + basic_check(domain.https) + + self.assertTrue(domain.https.https_bad_hostname) + + def test_https_bad_chain(self): + domain = inspect('untrusted-root.badssl.com') + basic_check(domain.https) + + self.assertTrue(domain.https.https_bad_chain) + + def test_https_self_signed_cert(self): + domain = inspect('self-signed.badssl.com') + basic_check(domain.https) + + self.assertTrue(domain.https.https_self_signed_cert) + + +if __name__ == '__main__': + unittest.main() diff --git a/tests/test_definitions.py b/tests/test_definitions.py new file mode 100644 index 00000000..649b23c0 --- /dev/null +++ b/tests/test_definitions.py @@ -0,0 +1,89 @@ +import unittest + +from pshtt.models import Domain, Endpoint +from pshtt import pshtt as api + + +class TestUsesHTTPS(unittest.TestCase): + def setUp(self): + base_domain = 'example.com' + self.domain = Domain(base_domain) + + self.domain.http = Endpoint("http", "root", base_domain) + self.domain.httpwww = Endpoint("http", "www", base_domain) + self.domain.https = Endpoint("https", "root", base_domain) + self.domain.httpswww = Endpoint("https", "www", base_domain) + + @unittest.skip('Still working on definition') + def test_definition(self): + self.domain.https.live = True + self.domain.https.https_valid = True + self.domain.https.https_valid = True + + self.assertTrue(api.is_domain_supports_https(self.domain)) + + +class TestBadChain(unittest.TestCase): + def setUp(self): + base_domain = 'example.com' + self.domain = Domain(base_domain) + + self.domain.http = Endpoint("http", "root", base_domain) + self.domain.httpwww = Endpoint("http", "www", base_domain) + self.domain.https = Endpoint("https", "root", base_domain) + self.domain.httpswww = Endpoint("https", "www", base_domain) + + def test_bad_chain_root(self): + self.domain.https.https_bad_chain = True + self.domain.canonical = self.domain.https + + self.assertTrue(api.is_bad_chain(self.domain)) + + def test_bad_chain_www(self): + self.domain.httpswww.https_bad_chain = True + self.domain.canonical = self.domain.httpswww + + self.assertTrue(api.is_bad_chain(self.domain)) + + def test_bad_chain_both(self): + self.domain.https.https_bad_chain = True + self.domain.httpswww.https_bad_chain = True + + self.domain.canonical = self.domain.https + self.assertTrue(api.is_bad_chain(self.domain)) + + self.domain.canonical = self.domain.httpswww + self.assertTrue(api.is_bad_chain(self.domain)) + + +class TestBadHostname(unittest.TestCase): + def setUp(self): + base_domain = 'example.com' + self.domain = Domain(base_domain) + + self.domain.http = Endpoint("http", "root", base_domain) + self.domain.httpwww = Endpoint("http", "www", base_domain) + self.domain.https = Endpoint("https", "root", base_domain) + self.domain.httpswww = Endpoint("https", "www", base_domain) + + def test_bad_hostname_root(self): + self.domain.https.https_bad_hostname = True + self.domain.canonical = self.domain.https + + self.assertTrue(api.is_bad_hostname(self.domain)) + + def test_bad_hostname_www(self): + self.domain.httpswww.https_bad_hostname = True + self.domain.canonical = self.domain.httpswww + + self.assertTrue(api.is_bad_hostname(self.domain)) + + def test_bad_hostname_both(self): + self.domain.https.https_bad_hostname = True + self.domain.httpswww.https_bad_hostname = True + + self.domain.canonical = self.domain.https + self.assertTrue(api.is_bad_hostname(self.domain)) + + self.domain.canonical = self.domain.httpswww + self.assertTrue(api.is_bad_hostname(self.domain)) diff --git a/tests/test_pshtt.py b/tests/test_pshtt.py new file mode 100644 index 00000000..8e6b2d4b --- /dev/null +++ b/tests/test_pshtt.py @@ -0,0 +1,74 @@ +import unittest + +from pshtt.models import Domain, Endpoint +from pshtt.pshtt import is_live + + +class TestLiveliness(unittest.TestCase): + def setUp(self): + base_domain = 'example.com' + self.domain = Domain(base_domain) + + self.domain.http = Endpoint("http", "root", base_domain) + self.domain.httpwww = Endpoint("http", "www", base_domain) + self.domain.https = Endpoint("https", "root", base_domain) + self.domain.httpswww = Endpoint("https", "www", base_domain) + + def test_none(self): + self.assertFalse(is_live(self.domain)) + + def test_http_only(self): + self.domain.http.live = True + + self.assertTrue(is_live(self.domain)) + + def test_https_only(self): + self.domain.https.live = True + + self.assertTrue(is_live(self.domain)) + + def test_httpwww_only(self): + self.domain.httpwww.live = True + + self.assertTrue(is_live(self.domain)) + + def test_httpswww_only(self): + self.domain.httpswww.live = True + + self.assertTrue(is_live(self.domain)) + + def test_http_both(self): + self.domain.http.live = True + self.domain.httpwww.live = True + + self.assertTrue(is_live(self.domain)) + + def test_https_both(self): + self.domain.https.live = True + self.domain.httpswww.live = True + + self.assertTrue(is_live(self.domain)) + + def test_www_neither(self): + self.domain.http.live = True + self.domain.https.live = True + + self.assertTrue(is_live(self.domain)) + + def test_www_both(self): + self.domain.httpwww.live = True + self.domain.httpswww.live = True + + self.assertTrue(is_live(self.domain)) + + def test_all(self): + self.domain.http.live = True + self.domain.https.live = True + self.domain.httpwww.live = True + self.domain.httpswww.live = True + + self.assertTrue(is_live(self.domain)) + + +if __name__ == '__main__': + unittest.main() diff --git a/tox.ini b/tox.ini new file mode 100644 index 00000000..41cca8ed --- /dev/null +++ b/tox.ini @@ -0,0 +1,15 @@ +[tox] +envlist = py27,py34,py35,py36,flake8 +skip_missing_interpreters = true +; usedevelop = true + +[testenv] +deps = + pytest-cov + pytest + coveralls +commands = pytest --cov=pshtt + +[testenv:flake8] +deps = flake8 +commands = flake8