diff --git a/.gitignore b/.gitignore index 20665b3..a402ace 100644 --- a/.gitignore +++ b/.gitignore @@ -76,3 +76,6 @@ target/ # sftp configuration file sftp-config.json + +### pyCraft ### +credentials diff --git a/tests/__init__.py b/tests/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/tests/compat.py b/tests/compat.py new file mode 100644 index 0000000..ffaa534 --- /dev/null +++ b/tests/compat.py @@ -0,0 +1,7 @@ +import platform +from distutils.version import StrictVersion + +if StrictVersion(platform.python_version()) < StrictVersion("3.3.0"): + import mock # noqa +else: + from unittest import mock # noqa diff --git a/tests/test_authentication.py b/tests/test_authentication.py new file mode 100644 index 0000000..98cff12 --- /dev/null +++ b/tests/test_authentication.py @@ -0,0 +1,189 @@ +from minecraft.authentication import _raise_from_request +from minecraft.authentication import _make_request +from minecraft.authentication import AuthenticationToken +from minecraft.exceptions import YggdrasilError +import requests +import json +import unittest +from .compat import mock + +FAKE_DATA = { + "access_token": "9c771b61cef241808e129e33d51ea745", + "client_token": "74076db55d8b4087a607fdeace60a94a", + "username": "TheBadassMCrafter" +} + +CREDENTIALS_LOCATION = "credentials" +AUTHSERVER = "https://authserver.mojang.com" + + +def get_mc_credentials(): + """ + Loads username and password from the credentials file. + + The credentials file should be stored in `credentials` in the root of the + project folder. + + The credentials file should have the following format: + ` + username + password + ` + """ + try: + with open(CREDENTIALS_LOCATION, "r") as f: + username = f.readline().lstrip().rstrip() + password = f.readline().lstrip().rstrip() + + return (username, password) + except IOError: + return (None, None) + +username, password = get_mc_credentials() + + +def should_skip_cred_test(): + """ + Returns `True` if a test requiring credentials should be skipped. + Otherwise returns `False` + """ + if username is None or password is None: + return True + return False + + +class Yggdrasil(unittest.TestCase): + def test_init_no_values(self): + a = AuthenticationToken() # noqa + + def test_init_access_token(self): + a = AuthenticationToken(access_token=FAKE_DATA["access_token"]) # noqa + + def test_init_client_token(self): + a = AuthenticationToken(client_token=FAKE_DATA["client_token"]) # noqa + + def test_init_username(self): + a = AuthenticationToken(client_token=FAKE_DATA["username"]) # noqa + + def test_init_positional(self): + a = AuthenticationToken(FAKE_DATA["username"], + FAKE_DATA["access_token"], + FAKE_DATA["client_token"]) + + self.assertEqual(a.username, FAKE_DATA["username"]) + self.assertEqual(a.access_token, FAKE_DATA["access_token"]) + self.assertEqual(a.client_token, FAKE_DATA["client_token"]) + + +class MakeRequest(unittest.TestCase): + def test_make_request_http_method(self): + req = _make_request(AUTHSERVER, "authenticate", {"Billy": "Bob"}) + self.assertEqual(req.request.method, "POST") + + def test_make_request_json_dump(self): + data = {"Marie": "McGee", + "George": 1, + "Nestly": { + "Nestling": "Nestling's tail" + }, + "Listly": ["listling1", 2, "listling 3"] + } + + req = _make_request(AUTHSERVER, "authenticate", data) + self.assertEqual(req.request.body, json.dumps(data)) + + def test_make_request_url(self): + URL = "https://authserver.mojang.com/authenticate" + req = _make_request(AUTHSERVER, "authenticate", {"Darling": "Diary"}) + self.assertEqual(req.request.url, URL) + + +class RaiseFromRequest(unittest.TestCase): + def test_raise_from_erroneous_request(self): + err_req = requests.Request() + err_req.status_code = 401 + err_req.json = mock.MagicMock( + return_value={"error": "ThisIsAnException", + "errorMessage": "Went wrong."}) + + with self.assertRaises(YggdrasilError) as e: + _raise_from_request(err_req) + self.assertEqual(e, "[401]) ThisIsAnException: Went Wrong.") + + def test_raise_from_erroneous_request_without_error(self): + err_req = requests.Request() + err_req.status_code = 401 + err_req.json = mock.MagicMock(return_value={"goldfish": "are pretty."}) + + with self.assertRaises(YggdrasilError) as e: + _raise_from_request(err_req) + + self.assertEqual(e, "Malformed error message.") + + def test_raise_from_healthy_request(self): + req = requests.Request() + req.status_code = 200 + req.json = mock.MagicMock(return_value={"vegetables": "are healthy."}) + + self.assertIs(_raise_from_request(req), None) + + +class AuthenticatedAuthenticationToken(unittest.TestCase): + pass + + +class AuthenticateAuthenticationToken(unittest.TestCase): + def test_authenticate_no_username(self): + a = AuthenticationToken() + + with self.assertRaises(TypeError): + a.authenticate() + + def test_authenticate_no_password(self): + a = AuthenticationToken() + + with self.assertRaises(TypeError): + a.authenticate("username") + + def test_authenticate_wrong_credentials(self): + a = AuthenticationToken() + + # We assume these aren't actual, valid credentials. + with self.assertRaises(YggdrasilError) as e: + a.authenticate("Billy", "The Goat") + + err = "Invalid Credentials. Invalid username or password." + self.assertEqual(e.error, err) + + @unittest.skipIf(should_skip_cred_test(), + "Need credentials to perform test.") + def test_authenticate_good_credentials(self): + a = AuthenticationToken() + + resp = a.authenticate(username, password) + self.assertTrue(resp) + + +class RefreshAuthenticationToken(unittest.TestCase): + # TODO: Make me! + pass + + +class ValidateAuthenticationToken(unittest.TestCase): + # TODO: Make me! + pass + + +class SignOutAuthenticationToken(unittest.TestCase): + # TODO: Make me! + pass + + +class InvalidateAuthenticationToken(unittest.TestCase): + # TODO: Make me! + pass + + +class JoinAuthenticationToken(unittest.TestCase): + # TODO: Make me! + pass diff --git a/tox.ini b/tox.ini index 7f37254..93d2e76 100644 --- a/tox.ini +++ b/tox.ini @@ -11,15 +11,18 @@ commands = nosetests deps = nose + requests [testenv:py27] deps = {[testenv]deps} + mock [testenv:pypy] deps = {[testenv]deps} - + mock + [testenv:cover] basepython = python3.4 commands =