summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rwxr-xr-xeffiapi41
-rw-r--r--yarns/000.yarn61
-rw-r--r--yarns/lib.py5
3 files changed, 90 insertions, 17 deletions
diff --git a/effiapi b/effiapi
index 5575a37..f3894fc 100755
--- a/effiapi
+++ b/effiapi
@@ -92,7 +92,19 @@ class FakeHTTPAPI(HTTPAPI):
return FakeResponse(201, headers, copy.deepcopy(body))
def PUT(self, url, headers, body):
- raise NotImplementedError()
+ logging.debug(
+ 'FakeHTTPAPI.PUT url=%r headers=%r body=r',
+ url, headers, body)
+
+ rid = headers.get('Muck-Id')
+ if not rid:
+ return FakeResponse(400, {}, 'No Muck-Id in request')
+
+ self._memb[rid] = copy.deepcopy(body)
+ headers = {
+ 'Muck-Id': rid,
+ }
+ return FakeResponse(200, headers, copy.deepcopy(body))
def GET(self, url, headers=None, body=None):
logging.info(
@@ -183,12 +195,12 @@ class MuckAPI:
raise MuckError('{} {}'.format(r.status_code, r.text))
return r.json()
- def create(self, member):
+ def _write(self, member, func):
url = self.url('/res')
headers = self._get_headers()
headers['Content-Type'] = 'application/json'
- r = self._httpapi.POST(url, headers, json.dumps(member))
- logging.info('Show result: %s %s', r.status_code, r.text)
+ r = func(url, headers, json.dumps(member))
+ logging.info('Write result: %s %s', r.status_code, r.text)
if not r.ok:
raise MuckError('{} {}'.format(r.status_code, r.text))
rid = r.headers.get('Muck-Id')
@@ -196,6 +208,12 @@ class MuckAPI:
raise MuckError('Muck did not return Muck-Id')
return rid, r.json()
+ def create(self, member):
+ return self._write(member, self._httpapi.POST)
+
+ def update(self, member):
+ return self._write(member, self._httpapi.PUT)
+
def search(self, cond):
url = self.url('/search')
headers = self._get_headers()
@@ -235,6 +253,11 @@ class API:
'path': '/memb',
'callback': self._call(self._create),
},
+ {
+ 'method': 'PUT',
+ 'path': '/memb',
+ 'callback': self._call(self._update),
+ },
]
for route in routes:
@@ -302,6 +325,16 @@ class API:
rid, newobj = self._muck.create(obj)
return response(201, rid, newobj)
+ def _update(self):
+ r = bottle.request
+ if r.content_type != 'application/json':
+ return response(400, None, 'wrong content type')
+
+ obj = bottle.request.json
+ logging.info('UPDATE %r', repr(obj))
+ rid, newobj = self._muck.update(obj)
+ return response(200, rid, newobj)
+
def response(status, rid, body):
headers = {
diff --git a/yarns/000.yarn b/yarns/000.yarn
index 9225c70..adff964 100644
--- a/yarns/000.yarn
+++ b/yarns/000.yarn
@@ -42,19 +42,31 @@ member, to update and retrieve it, and to search memberships.
WHEN admin requests GET /status
THEN HTTP status is 200
- AND HTTP body matches { "resources": 0 }
+ AND body matches { "resources": 0 }
WHEN admin requests POST /memb with body { "fullname": "James Bond" }
THEN HTTP status is 201
- AND the member id is ID
+ AND remember header Muck-Id as ID
+ AND remember header Muck-Revision as REV1
WHEN admin requests GET /status
THEN HTTP status is 200
- AND HTTP body matches { "resources": 1 }
+ AND body matches { "resources": 1 }
WHEN admin requests GET /memb with header Muck-Id: ${ID}
THEN HTTP status is 200
- AND HTTP body matches { "fullname": "James Bond" }
+ AND body matches { "fullname": "James Bond" }
+ AND header Muck-Revision is ${REV1}
+
+ WHEN admin requests PUT /memb with id ${ID}, revision ${REV1},
+ ... and body { "fullname": "Alfred Pennyworth" }
+ THEN HTTP status is 200
+ AND remember header Muck-Revision as REV2
+
+ WHEN admin requests GET /memb with header Muck-Id: ${ID}
+ THEN HTTP status is 200
+ AND body matches { "fullname": "Alfred Pennyworth" }
+ AND header Muck-Revision is ${REV2}
FINALLY Effiapi is terminated
@@ -86,6 +98,19 @@ TODO:
IMPLEMENTS WHEN admin requests GET /status
effiapi.GET('/status', {}, None)
+ IMPLEMENTS WHEN admin requests PUT /memb with id (\S+), revision (\S+), and body (.+)
+ rid = get_expanded_match()
+ rev = get_expanded_match()
+ body = get_json_match()
+ print('rid', repr(rid))
+ print('rev', repr(rev))
+ print('body', repr(body))
+ headers = {
+ 'Muck-Id': rid,
+ 'Muck-Revision': rev,
+ }
+ effiapi.PUT('/memb', headers, body)
+
IMPLEMENTS WHEN admin requests GET /memb with header (\S+): (\S+)
header = get_next_match()
print('header', repr(header))
@@ -102,14 +127,6 @@ TODO:
## Inspect HTTP responses
- IMPLEMENTS THEN the member id is (\S+)
- print('member id')
- name = get_next_match()
- print 'name', repr(name), name
- value = effiapi.get_header('Muck-Id')
- print 'value', repr(value)
- save_for_expansion(name, value)
-
IMPLEMENTS THEN HTTP status is (\d+)
expected = int(get_next_match())
actual = effiapi.get_status_code()
@@ -117,7 +134,25 @@ TODO:
print 'expecting:', repr(expected)
assertEqual(effiapi.get_status_code(), expected)
- IMPLEMENTS THEN HTTP body matches (.+)
+ IMPLEMENTS THEN remember header (\S+) as (.+)
+ header = get_next_match()
+ varname = get_next_match()
+ value = effiapi.get_header(header)
+ print 'header:', repr(header)
+ print 'value:', repr(value)
+ print 'varname:', repr(varname)
+ save_for_expansion(varname, value)
+
+ IMPLEMENTS THEN header (\S+) is (.+)
+ header = get_next_match()
+ expected = get_expanded_match()
+ actual = effiapi.get_header(header)
+ print 'header:', repr(header)
+ print 'expected:', repr(expected)
+ print 'actual:', repr(actual)
+ assertEqual(actual, expected)
+
+ IMPLEMENTS THEN body matches (.+)
expected = get_json_match()
actual = effiapi.get_json_body()
print 'expected:', expected
diff --git a/yarns/lib.py b/yarns/lib.py
index a776fda..100511e 100644
--- a/yarns/lib.py
+++ b/yarns/lib.py
@@ -96,6 +96,11 @@ class EffiAPI:
body = json.dumps(body)
self.request(requests.post, path, headers, body)
+ def PUT(self, path, headers, body):
+ headers['Content-Type'] = 'application/json'
+ body = json.dumps(body)
+ self.request(requests.put, path, headers, body)
+
def GET(self, path, headers, body):
self.request(requests.get, path, headers, body)