Repository: ocadotechnology/aimmo

Issue:
Score_cells use tuples. That might be too slow!
`Score_cells()` function in `world_map.py` uses a tuple. If I recall correctly this will be very slow and can be improved.

New starter issue perhaps?


Discussion:

Resolving patch:
diff --git a/example_project/example_project/settings.py b/example_project/example_project/settings.py
--- a/example_project/example_project/settings.py
+++ b/example_project/example_project/settings.py
@@ -45,8 +45,10 @@
 
 DATABASES = {
     'default': {
-        'ENGINE': 'django.db.backends.sqlite3',  # Add 'postgresql_psycopg2', 'mysql', 'sqlite3' or 'oracle'.
-        'NAME': os.path.join(os.path.abspath(os.path.dirname(__file__)), 'db.sqlite3'),  # Or path to database file if using sqlite3.
+        'ENGINE': 'django.db.backends.sqlite3',  # Add 'postgresql_psycopg2', 'mysql',
+                                                 # 'sqlite3' or 'oracle'.
+        'NAME': os.path.join(os.path.abspath(os.path.dirname(__file__)), 'db.sqlite3'),
+        # Or path to database file if using sqlite3.
     }
 }
 
@@ -106,12 +108,15 @@
    'django.contrib.messages.middleware.MessageMiddleware',
 ]
 
+
 def get_url(game):
     if os.environ.get('AIMMO_MODE', '') == 'minikube':
-        output = subprocess.check_output([os.environ['MINIKUBE_PATH'], 'service', 'game-%s' % game, '--url'])
-        return (output.strip(), '/game/%s/socket.io' % game)
+        output = subprocess.check_output([os.environ['MINIKUBE_PATH'], 'service',
+                                          'game-%s' % game, '--url'])
+        return output.strip(), '/game/%s/socket.io' % game
     else:
-        return ('http://localhost:%d' % (6001 + int(game) * 1000), '/socket.io')
+        return 'http://localhost:%d' % (6001 + int(game) * 1000), '/socket.io'
+
 
 AIMMO_GAME_SERVER_LOCATION_FUNCTION = get_url
 
diff --git a/integration-tests/setup.py b/integration-tests/setup.py
new file mode 100644
--- /dev/null
+++ b/integration-tests/setup.py
@@ -0,0 +1,17 @@
+# -*- coding: utf-8 -*-
+from setuptools import find_packages, setup
+
+
+setup(
+    name='integration-tests',
+    packages=find_packages(),
+    include_package_data=True,
+    install_requires=[
+        'requests',
+    ],
+    tests_require=[
+        'requests',
+    ],
+    test_suite='tests',
+    zip_safe=False,
+)
diff --git a/run.py b/run.py
--- a/run.py
+++ b/run.py
@@ -13,12 +13,6 @@
 _SERVICE_PY = os.path.join(_SCRIPT_LOCATION, 'aimmo-game-creator', 'service.py')
 
 
-if __name__ == '__main__':
-    logging.basicConfig()
-    sys.path.append(os.path.join(_SCRIPT_LOCATION, 'example_project'))
-    os.environ.setdefault("DJANGO_SETTINGS_MODULE", "example_project.settings")
-
-
 def log(message):
     print >> sys.stderr, message
 
@@ -49,10 +43,14 @@ def create_superuser_if_missing(username, password):
         User.objects.get_by_natural_key(username)
     except User.DoesNotExist:
         log('Creating superuser %s with password %s' % (username, password))
-        User.objects.create_superuser(username=username, email='admin@admin.com', password=password)
+        User.objects.create_superuser(username=username, email='admin@admin.com',
+                                      password=password)
 
 
 def main(use_minikube):
+    logging.basicConfig()
+    sys.path.append(os.path.join(_SCRIPT_LOCATION, 'example_project'))
+    os.environ.setdefault("DJANGO_SETTINGS_MODULE", "example_project.settings")
 
     run_command(['pip', 'install', '-e', _SCRIPT_LOCATION])
     run_command(['python', _MANAGE_PY, 'migrate', '--noinput'])
@@ -63,7 +61,8 @@ def main(use_minikube):
     server_args = []
     if use_minikube:
         # Import minikube here, so we can install the deps first
-        run_command(['pip', 'install', '-r', os.path.join(_SCRIPT_LOCATION, 'minikube_requirements.txt')])
+        run_command(['pip', 'install', '-r', os.path.join(_SCRIPT_LOCATION,
+                                                          'minikube_requirements.txt')])
         import minikube
 
         minikube.start()


Test patch:
diff --git a/all_tests.py b/all_tests.py
--- a/all_tests.py
+++ b/all_tests.py
@@ -13,7 +13,8 @@
 import sys
 
 BASE_DIR = os.path.abspath(os.path.dirname(__file__))
-APPS = ('', 'aimmo-game/', 'aimmo-game-worker/', 'aimmo-game-creator/')
+APPS = ('', 'aimmo-game/', 'aimmo-game-worker/', 'aimmo-game-creator/',
+        'integration-tests/')
 
 
 def print_help():
@@ -39,7 +40,8 @@ def app_name(app):
 
         dir = os.path.join(BASE_DIR, app)
         if compute_coverage and app != '':
-            result = subprocess.call(['coverage', 'run', '--concurrency=eventlet', '--source=.', 'setup.py', 'test'], cwd=dir)
+            result = subprocess.call(['coverage', 'run', '--concurrency=eventlet',
+                                      '--source=.', 'setup.py', 'test'], cwd=dir)
         else:
             result = subprocess.call([sys.executable, 'setup.py', 'test'], cwd=dir)
         if result != 0:
diff --git a/integration-tests/tests/__init__.py b/integration-tests/tests/__init__.py
new file mode 100644
diff --git a/integration-tests/tests/connection_set_up.py b/integration-tests/tests/connection_set_up.py
new file mode 100644
--- /dev/null
+++ b/integration-tests/tests/connection_set_up.py
@@ -0,0 +1,101 @@
+import time
+import requests
+import os
+import logging
+
+
+logging.basicConfig(level=logging.WARNING)
+
+
+def delete_old_database():
+    try:
+        os.remove("../example_project/example_project/db.sqlite3")
+        logging.debug("Database file in example_project DELETED!")
+    except OSError:
+        logging.debug("No database file found.")
+        pass
+
+
+def obtain_csrftoken(session):
+    """
+    A CSRF cookie token is required in order to not get a 403 Forbidden response by
+    the post to the inputs.
+    :return: String representing the token.
+    """
+
+    return session.cookies['csrftoken']
+
+
+def create_session():
+    """
+    A integration test utility to create a browser session request for a single test.
+    :return: A session object for requests.
+    """
+
+    return requests.Session()
+
+
+def send_get_request(session, url):
+    """
+    Attempts to send a GET to the url. Server is already up as the test should
+    be calling the `is_server_healthy()` function before calling this.
+
+    :param session: Object representing the browser session.
+    :param url: String, containing 'http://', with the URL of the target URL.
+    :return: Response of GET.
+    """
+    response = None
+
+    logging.debug("Attempting a GET request for the provided URL...")
+    try:
+        response = session.get(url)
+        response.raise_for_status()
+    except requests.exceptions.RequestException as e:
+        logging.debug(e)
+
+    return response
+
+
+def send_post_request(session, url, data):
+    """
+    Attempts to send a POST to the url. Server is already up as the test should
+    be calling the `is_server_healthy()` function before calling this.
+
+    :return: Response of POST.
+    """
+    response = None
+
+    logging.debug("Attempting a POST request for the provided URL...")
+
+    try:
+        response = session.post(url, data=data)
+        response.raise_for_status()
+    except requests.exceptions.RequestException as e:
+        logging.debug(e)
+
+    return response
+
+
+def is_server_healthy(url):
+    """
+    Function will only return True when the param URL returns a 2xx code. After
+    45 seconds, the check assumes a timeout.
+    :param url: http URL for the address to poll.
+    :return: boolean value to indicate result.
+    """
+
+    attempts = 0
+
+    logging.debug("Checking if the server is healthy...")
+    while attempts <= 45:
+        try:
+            status_code = requests.get(url).status_code
+            if int(str(status_code)[0]) == 2:
+                return True
+        except requests.exceptions.RequestException as e:
+            pass
+
+        attempts += 1
+        time.sleep(1)
+
+    return False
diff --git a/integration-tests/tests/test_integration.py b/integration-tests/tests/test_integration.py
new file mode 100644
--- /dev/null
+++ b/integration-tests/tests/test_integration.py
@@ -0,0 +1,50 @@
+import os
+import signal
+import time
+import subprocess
+import logging
+from unittest import TestCase
+
+from connection_set_up import (create_session, send_get_request, send_post_request,
+                               obtain_csrftoken, delete_old_database, is_server_healthy)
+
+logging.basicConfig(level=logging.WARNING)
+
+
+class TestIntegration(TestCase):
+    def test_superuser_authentication(self):
+        """
+        A test that will run on a clean & empty database, create all migrations, new
+        browser session and passes a CSRF token with the POST input request.
+        
+        Server gets killed at the end of the test.
+        """
+        url = 'http://localhost:8000/players/accounts/login/'
+
+        delete_old_database()
+
+        p = subprocess.Popen(["python",  "../run.py"], stdout=subprocess.PIPE,
+                             stderr=subprocess.PIPE)
+
+        self.assertTrue(is_server_healthy(url))
+
+        logging.debug("Creating session...")
+        session = create_session()
+
+        send_get_request(session, url)
+
+        logging.debug("Obtaining CSRF Token...")
+        csrftoken = obtain_csrftoken(session)
+
+        login_info = {
+            'username': 'admin',
+            'password': 'admin',
+            'csrfmiddlewaretoken': csrftoken,
+        }
+
+        logging.debug("Sending post response...")
+
+        response = send_post_request(session, url, login_info)
+        self.assertEquals(response.status_code, 200)
+
+        os.kill(int(p.pid), signal.SIGTERM)