Skip to content

Commit f86d820

Browse files
authored
Merge pull request #6 from erik-sn/master
Added .env file and filtering tests
2 parents d64db37 + 6570f6c commit f86d820

File tree

9 files changed

+143
-33
lines changed

9 files changed

+143
-33
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ var/
2020
*.egg-info/
2121
.installed.cfg
2222
*.egg
23+
.env
2324

2425
# PyInstaller
2526
# Usually these files are written by a python script from a template

Dockerfile

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,5 @@
11
FROM python:3.6
2-
ENV PYTHONUNBUFFERED 1
3-
ENV DJANGO_SETTINGS_MODULE api.config.settings
4-
ENV SECRET_KEY r#lkao5gtpp@me&4532%!q%sj9yzg)xb-_*mlousmi&=#2r7&w
5-
ENV DEBUG True
6-
ENV DATABASE_URL postgres://postgres@db/postgres
7-
ENV DOCKER_HOST True
2+
ENV DOCKER_HOST=True
83
RUN mkdir /project
94
WORKDIR /project
105
RUN apt-get update

README.rst

Lines changed: 32 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,15 +6,31 @@ A `RESTful <https://en.wikipedia.org/wiki/Representational_state_transfer>`_ API
66
Getting Started
77
---------------
88

9-
To run this project, you will need to install `Docker <https://docs.docker.com/>`_ on your machine.
109

11-
Once Docker is installed and running, enter the following command from within the project folder to start the web and database servers:
10+
11+
First create a `.env` file in the root directory that contains necessary environment variables:
12+
13+
.. code::
14+
15+
# python/django
16+
PYTHONUNBUFFERED=1
17+
DJANGO_SETTINGS_MODULE=api.config.settings
18+
SECRET_KEY=**Django Secret Key**
19+
DEBUG=True
20+
21+
# database
22+
DATABASE_URL=postgres://postgres@db/postgres
23+
24+
25+
To run this project, you will need to install `Docker <https://docs.docker.com/>`_ on your machine. Once Docker is installed and running and your `.env` file is defined, enter the following command from within the
26+
project folder to start the web and database servers:
1227

1328
.. code::
1429
1530
docker-compose up
1631
17-
This will take several minutes the first time you run it as it needs to download and install all the necessary components into a docker container.
32+
This will take several minutes the first time you run it as it needs to download and install all the necessary
33+
components into a docker container.
1834

1935
If successful, you should see the following messages at the end of the installation and configuration:
2036

@@ -32,4 +48,16 @@ On OS X, you may need to use the IP address of your docker virtual machine rathe
3248
3349
docker-machine ip default
3450
35-
If you installed the Kitematic tool, you should also see your new containers in its list and you can start and stop them from there rather than the command line from now on.
51+
If you installed the Kitematic tool, you should also see your new containers in its list and you can start and stop them
52+
from there rather than the command line from now on.
53+
54+
55+
Running Tests
56+
-------------
57+
58+
Make sure you have created a .env file as above. To run all tests:
59+
60+
.. code::
61+
62+
python manage.py test --settings=api.config.test_settings
63+

api/config/settings.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
import os
2-
import subprocess
32
import dj_database_url
43

54
# Environment specific settings from environment variables or local .env file
@@ -15,6 +14,7 @@
1514

1615
ALLOWED_HOSTS = ['*']
1716

17+
1818
def show_debug_toolbar(request):
1919
return DOCKER and DEBUG
2020

api/config/test_settings.py

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
"""
2+
import all default settings and then over write any settings
3+
that are specific to testing
4+
5+
"""
6+
import sys
7+
8+
from api.config.settings import *
9+
10+
11+
if 'test' in sys.argv or 'test_coverage' in sys.argv:
12+
# use an in memory sqlite3 backend for performance
13+
DATABASES = {
14+
'default': {
15+
'ENGINE': 'django.db.backends.sqlite3',
16+
'NAME': 'default',
17+
},
18+
}

api/core/tests/test_filters.py

Lines changed: 46 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
1-
import unittest
2-
from api.core.filters import passes_filterset, passes_boolean_filter
1+
from unittest import TestCase, mock
2+
from rest_framework.test import APIRequestFactory
3+
4+
5+
from api.core.views import filter_strategies
36

47

58
class TestStrategy(object):
@@ -8,24 +11,49 @@ class TestStrategy(object):
811
'stochastic': True
912
}
1013

14+
def __init__(self, classifier):
15+
self.classifier = classifier
16+
17+
18+
class TestFilterStrategies(TestCase):
19+
20+
@classmethod
21+
def setUpClass(cls):
22+
cls.factory = APIRequestFactory()
23+
24+
@mock.patch('api.core.views.axl.filtered_strategies')
25+
def test_string_word_to_boolean(self, filtered_strategies_mock):
26+
filtered_strategies_mock.return_value = mock.MagicMock()
27+
28+
request = self.factory.get('/articles/?stochastic=true')
29+
request.query_params = request.GET # factory doesn't support query_params
30+
filter_strategies(request)
31+
filtered_strategies_mock.assert_called_with({'stochastic': 1})
32+
33+
@mock.patch('api.core.views.axl.filtered_strategies')
34+
def test_string_number_to_boolean(self, filtered_strategies_mock):
35+
mock.return_value = mock.MagicMock()
36+
37+
request = self.factory.get('/articles/?stochastic=1')
38+
request.query_params = request.GET # factory doesn't support query_params
39+
filter_strategies(request)
40+
filtered_strategies_mock.assert_called_with({'stochastic': 1})
1141

12-
class TestFilters(unittest.TestCase):
42+
@mock.patch('api.core.views.axl.filtered_strategies')
43+
def test_string_to_int(self, filtered_strategies_mock):
44+
filtered_strategies_mock.return_value = mock.MagicMock()
1345

14-
def test_passes_boolean_filter(self):
15-
test_strategy = TestStrategy()
46+
request = self.factory.get('/articles/?memory_depth=3')
47+
request.query_params = request.GET # factory doesn't support query_params
48+
filter_strategies(request)
49+
filtered_strategies_mock.assert_called_with({'memory_depth': 3})
1650

17-
# test that filter works with a string value
18-
test_filterset = {'stochastic': 'True'}
19-
self.assertTrue(passes_boolean_filter(
20-
test_strategy, test_filterset, 'stochastic'))
51+
@mock.patch('api.core.views.axl.filtered_strategies')
52+
def test_makes_use_of(self, filtered_strategies_mock):
53+
filtered_strategies_mock.return_value = mock.MagicMock()
2154

22-
# test that filter works with a boolean value
23-
test_filterset = {'stochastic': True}
24-
self.assertTrue(passes_boolean_filter(
25-
test_strategy, test_filterset, 'stochastic'))
55+
request = self.factory.get('/articles/?makes_use_of=game')
56+
request.query_params = request.GET # factory doesn't support query_params
57+
filter_strategies(request)
58+
filtered_strategies_mock.assert_called_with({'makes_use_of': ['game']})
2659

27-
def test_passes_filterset(self):
28-
test_strategy = TestStrategy()
29-
test_filterset = {'stochastic': 'True'}
30-
self.assertTrue(passes_filterset(test_strategy, test_filterset))
31-
self.assertTrue(passes_filterset(test_strategy, {}))

api/core/views.py

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
from api.core.serializers import StrategySerializer, strategy_id
66

77

8-
def strategies(request):
8+
def filter_strategies(request):
99
"""
1010
Take the incoming request object, convert the strings in its
1111
query_params dictionary into the types required by the axelrod
@@ -38,7 +38,6 @@ def strategies(request):
3838

3939
if 'makes_use_of' in params:
4040
filterset['makes_use_of'] = params.getlist('makes_use_of')
41-
4241
return axl.filtered_strategies(filterset)
4342

4443

@@ -48,7 +47,7 @@ class StrategyViewSet(viewsets.ViewSet):
4847

4948
def list(self, request):
5049
serializer = StrategySerializer(
51-
strategies(request), many=True, context={'request': request})
50+
filter_strategies(request), many=True, context={'request': request})
5251
return Response(serializer.data)
5352

5453
def retrieve(self, request, pk=None):

docker-compose.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@ services:
44
image: postgres
55
web:
66
build: .
7+
env_file:
8+
- .env
79
command: python run_server.py
810
volumes:
911
- .:/project

manage.py

Lines changed: 40 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,45 @@
1-
#!/usr/bin/env python
1+
"""
2+
Source:
3+
https://gist.github.com/bennylope/2999704
4+
5+
Declare all environment files in a .env file and use this manage.py
6+
to run items that reads this file. This allows us to separate development
7+
and production environments
8+
"""
9+
10+
import os
211
import sys
12+
import re
13+
14+
15+
def read_env():
16+
"""Pulled from Honcho code with minor updates, reads local default
17+
environment variables from a .env file located in the project root
18+
directory.
19+
"""
20+
try:
21+
with open('.env') as f:
22+
content = f.read()
23+
except IOError:
24+
content = ''
25+
26+
for line in content.splitlines():
27+
m1 = re.match(r'\A([A-Za-z_0-9]+)=(.*)\Z', line)
28+
if m1:
29+
key, val = m1.group(1), m1.group(2)
30+
m2 = re.match(r"\A'(.*)'\Z", val)
31+
if m2:
32+
val = m2.group(1)
33+
m3 = re.match(r'\A"(.*)"\Z', val)
34+
if m3:
35+
val = re.sub(r'\\(.)', r'\1', m3.group(1))
36+
os.environ.setdefault(key, val)
37+
338

439
if __name__ == "__main__":
40+
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "core.settings")
41+
542
from django.core.management import execute_from_command_line
43+
44+
read_env()
645
execute_from_command_line(sys.argv)

0 commit comments

Comments
 (0)