Skip to content

Commit 4f09dbc

Browse files
committedNov 17, 2016
Update README to include docker, start check script
1 parent 77236ca commit 4f09dbc

File tree

5 files changed

+200
-3
lines changed

5 files changed

+200
-3
lines changed
 

‎.gitignore

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
exercise/venv/*

‎README.md

+117-3
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,121 @@ Below are two sections:
2323

2424
# Instructions
2525

26-
There is a problem. You need to solve it.
26+
## Problem
27+
28+
We're starting a new application and we need to store students! We'd like to be
29+
able to do the following with the students:
30+
31+
* Create a student
32+
* Retrieve a particular student by unique identifier
33+
* Search students in the system
34+
35+
__0.__ Format -- the application should accept and produce JSON.
36+
37+
__1.__ Data -- the student record has the following fields:
38+
39+
* Either an `email` or a `username` must be non-blank, and whichever (or both)
40+
are defined they must be unique for that field.
41+
* A `first_name` and `last_name`; the `last_name` is required to be non-blank.
42+
* A `display_name`, which if not defined at creation should be the first name
43+
and last names joined with a space.
44+
* The `created_at` datetime when the student was added to the system, which
45+
should be assigned by the system when the student is created.
46+
* The `started_at` of the student started at an institution; if not specified
47+
it should be the date the student was added to the system.
48+
49+
__2.__ Search -- the students may be searched by the following fields:
50+
51+
* `name` (which is a partial match against any of the first name, last name, or
52+
display name)
53+
* `username` (partial match)
54+
* `email` (partial match)
55+
* `started_after` (date formatted `YYYY-MM-DD` that will return students
56+
who started on or after a particular date)
57+
58+
If multiple fields provided any returned records must match all of them, so
59+
treat them as an `AND`.
60+
61+
__3.__ Routes -- the routes you should use are:
62+
63+
* Create a student: `POST /students`
64+
* Search students: `GET /students`
65+
* Retrieve a student: `GET /students/{identifier}`
66+
* Health check: `GET /` should return a successful HTTP status
67+
68+
## Languages and Environment
69+
70+
__1.__ You may use any of the following languages to solve this problem:
71+
72+
* Python
73+
* JavaScript
74+
* Ruby
75+
* Go
76+
* Java
77+
78+
__2.__ If you use external libraries you should use standard dependency
79+
management tools to declare them -- for example, `requirements.txt` for Python
80+
projects, `Gemfile` for Ruby projects, etc.
81+
82+
__3.__ If you use a relational database please use Postgres.
83+
84+
__4.__ Using Docker (with a `Dockerfile`) is also just fine. We use Docker for
85+
development, testing, and production here, but you're not required to know it
86+
when you start.
87+
88+
__5.__ Unit tests are strongly encouraged.
89+
90+
__6.__ Please include with your solution instructions on what we need to do to
91+
run it.
92+
93+
## Checking your work
94+
95+
There is a directory in this repo `exercise/` with a script that you can use to
96+
exercise your solution. You can run it in two ways:
97+
98+
__1.__ Run without Docker
99+
100+
It requires python to be installed and a particular module to be installed.
101+
[Virtualenv](http://docs.python-guide.org/en/latest/dev/virtualenvs/) is a
102+
great way to manage and isolate dependencies, and you can do so with the
103+
exercise like this, assuming you're using some sort of Unix-y command-line:
104+
105+
```
106+
$ cd exercise
107+
$ virtualenv venv
108+
$ source venv/bin/activate
109+
$ pip install -r requirements.txt
110+
```
111+
112+
If you don't have `virtualenv` you can install with
113+
114+
```
115+
$ sudo pip install virtualenv
116+
```
117+
118+
Once you've got the environment setup you can run it like this:
119+
120+
```
121+
$ python check.py http://myhost:8888
122+
```
123+
124+
where `http://myhost:8888` is the URL where your solution is running.
125+
126+
It uses the same data every time to run its checks so you'll need to have a
127+
clean datastore before you run it.
128+
129+
__2.__ Run with Docker
130+
131+
If you already have Docker installed you can build a container and
132+
point it at your solution. Note that mapping the host on which your solution is
133+
running (`myhost`, below) to the host known by the docker container may be
134+
tricky.
135+
136+
```
137+
$ cd exercise
138+
$ docker build -t turnitin-check .
139+
$ docker run --rm turnitin-check http://myhost:8888
140+
```
27141

28142
# Logistics
29143

@@ -34,7 +148,7 @@ a whole weekend to work on it.
34148
__2.__ You will need to use git for this exercise. To get these instructions
35149
and a repo with test scripts do the following:
36150

37-
A: (Create a bitbucket account)[https://bitbucket.org/account/signup/] if you
151+
A: [Create a bitbucket account](https://bitbucket.org/account/signup/) if you
38152
don't already have one. For the examples below we assume a user `pusheen`.
39153

40154
B: Clone our repository:
@@ -51,7 +165,7 @@ __3.__ Once you are done you can put your solution in your own repository by
51165
adding it as a remote and pushing to it.
52166

53167
A: Create a new repo via the bitbucket UI, let's assume you call it
54-
`backend-coding-exercise` to mirror ours.
168+
`backend-code-exercise` to mirror ours.
55169

56170
B: Please make the repository *private*, we'd like to make sure that every
57171
candidate's work is his or her own.

‎exercise/Dockerfile

+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
FROM python:alpine
2+
3+
RUN mkdir /app
4+
WORKDIR /app
5+
ADD requirements.txt /app/
6+
RUN pip install -r requirements.txt
7+
ADD . /app
8+
9+
ENTRYPOINT ["python", "check.py"]

‎exercise/check.py

+71
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
import sys
2+
import unittest
3+
4+
import requests
5+
6+
BASE = None
7+
8+
9+
class VerifyStudents(unittest.TestCase):
10+
def get(self, query_args={}):
11+
return requests.get(self.url(), params=query_args)
12+
13+
def post(self, body_dict={}):
14+
return requests.post(self.url(), json=body_dict)
15+
16+
def url(self):
17+
return BASE + self.path()
18+
19+
def assert_post_not_ok(self, body_dict, msg):
20+
self.assert_response_not_between(self.post(body_dict), 200, 300, msg)
21+
22+
def assert_response_between(self, response, low, high, msg):
23+
status = response.status_code
24+
if status not in range(low, high):
25+
self.fail(msg + ', expected status between {} and {}, got {}'.format(low, high, status))
26+
27+
def assert_response_not_between(self, response, low, high, msg):
28+
status = response.status_code
29+
if status in range(low, high):
30+
self.fail(msg + ', expected status NOT between {} and {}, got {}'.format(low, high, status))
31+
32+
33+
class VerifyCreate(VerifyStudents):
34+
def path(self):
35+
return '/students'
36+
37+
def valid_student(self, updates={}):
38+
student = {
39+
'email': 'pusheen@example.com',
40+
'first_name': 'Push',
41+
'last_name': 'Een',
42+
}
43+
student.update(updates)
44+
return student
45+
46+
def test_fail_missing_last_name(self):
47+
doc = self.valid_student({'last_name': None})
48+
self.assert_post_not_ok(doc, 'Expected error with no last name')
49+
50+
51+
if __name__ == '__main__':
52+
if len(sys.argv) == 1:
53+
print("Usage: python {} url-of-solution".format(sys.argv[0]))
54+
sys.exit(1)
55+
56+
BASE = sys.argv[1].rstrip('/')
57+
58+
# lop this off so unittest doesn't try to do something with it
59+
del(sys.argv[1])
60+
61+
try:
62+
response = requests.get(BASE + '/')
63+
if response.status_code >= 400:
64+
print("FAIL: Health check got bad status ({}), not continuing".format(response.status_code))
65+
sys.exit(1)
66+
except requests.RequestException as e:
67+
print("FAIL: Caught exception with health check -- {}".format(e))
68+
sys.exit(1)
69+
70+
print("OK: Health check")
71+
unittest.main(verbosity=2)

‎exercise/requirements.txt

+2
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
requests==2.12.0
2+

0 commit comments

Comments
 (0)
Please sign in to comment.