Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,16 @@ Out-of-the-box it supports the following frameworks:

You can use any of them, and you must pull them in via your own test requirements.

-----------
Error Codes
-----------

StackInABox has some specific error codes to help with diagnosing issues:

- 597 - StackInABox - Base URL is correct, but service is unknown
- 596 - StackInABox - Handling StackInABoxService generated an exception
- 595 - StackInABoxService - Route Not handled

Both of these are extremely easy to use as shown in the following examples:

---------
Expand Down
2 changes: 1 addition & 1 deletion setup.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,4 @@ cover-package=stackinabox
cover-erase=1
cover-inclusive=true
cover-branches=true
cover-min-percentage=83
cover-min-percentage=88
14 changes: 12 additions & 2 deletions stackinabox/services/service.py
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ def __call__(self, method, request, uri, headers):
request,
uri,
headers)
else:
elif self.obj is not None:
logger.debug('Service Router ({0} - {1}): Located Subservice {2} '
'on Route {3}. Calling...'
.format(id(self),
Expand All @@ -109,6 +109,16 @@ def __call__(self, method, request, uri, headers):
uri,
headers)

else:
logger.debug('Service Router ({0} - {1}): '
'No Method handler for service'
.format(id(self),
self.service_name))
return (405,
headers,
'{0} not supported. Supported Methods are {1}'.format(
method, self.methods))


class StackInABoxService(object):
DELETE = 'DELETE'
Expand Down Expand Up @@ -236,7 +246,7 @@ def try_handle_route(self, route_uri, method, request, uri, headers):
request,
uri,
headers)
return (500, headers, 'Server Error')
return (595, headers, 'Route ({0}) Not Handled'.format(uri))

def request(self, method, request, uri, headers):
logger.debug('StackInABoxService ({0}:{1}): Request Received {2} - {3}'
Expand Down
11 changes: 6 additions & 5 deletions stackinabox/stack.py
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ def __get_service_url(base_url, service_name):
return '{0}/{1}'.format(base_url, service_name)

@staticmethod
def __get_services_url(url, base_url):
def get_services_url(url, base_url):
length = len(base_url)
checks = ['http://', 'https://']
for check in checks:
Expand Down Expand Up @@ -117,7 +117,7 @@ def register(self, service):
if service.name not in self.services.keys():
logger.debug('StackInABox({0}): Registering Service {1}'
.format(self.__id, service.name))
regex = '^/{0}'.format(service.name)
regex = '^/{0}/'.format(service.name)
self.services[service.name] = [
re.compile(regex),
service
Expand All @@ -133,7 +133,8 @@ def register(self, service):
def call(self, method, request, uri, headers):
logger.debug('StackInABox({0}): Received call to {1} - {2}'
.format(self.__id, method, uri))
service_uri = StackInABox.__get_services_url(uri, self.base_url)
service_uri = StackInABox.get_services_url(uri, self.base_url)

for k, v in six.iteritems(self.services):
matcher, service = v
logger.debug('StackInABox({0}): Checking if Service {1} handles...'
Expand All @@ -155,10 +156,10 @@ def call(self, method, request, uri, headers):
logger.exception('StackInABox({0}): Service {1} - '
'Internal Failure'
.format(self.__id, service.name))
return (500,
return (596,
headers,
'Service Handler had an error: {0}'.format(ex))
return (500, headers, 'Unknown service')
return (597, headers, 'Unknown service - {0}'.format(service_uri))

def into_hold(self, name, obj):
logger.debug('StackInABox({0}): Holding onto {1} of type {2} '
Expand Down
7 changes: 5 additions & 2 deletions stackinabox/tests/test_httpretty.py
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,10 @@ def test_basic(self):
self.assertEqual(res.text, 'okay')

res = requests.get('http://localhost/advanced/_234567890')
self.assertEqual(res.status_code, 500)
self.assertEqual(res.status_code, 595)

res = requests.put('http://localhost/advanced/h')
self.assertEqual(res.status_code, 500)
self.assertEqual(res.status_code, 405)

res = requests.put('http://localhost/advanced2/i')
self.assertEqual(res.status_code, 597)
7 changes: 5 additions & 2 deletions stackinabox/tests/test_requests_mock.py
Original file line number Diff line number Diff line change
Expand Up @@ -87,10 +87,13 @@ def test_basic(self):
self.assertEqual(res.text, 'okay')

res = self.session.get('http://localhost/advanced/_234567890')
self.assertEqual(res.status_code, 500)
self.assertEqual(res.status_code, 595)

res = self.session.put('http://localhost/advanced/h')
self.assertEqual(res.status_code, 500)
self.assertEqual(res.status_code, 405)

res = self.session.put('http://localhost/advanced2/i')
self.assertEqual(res.status_code, 597)

def test_context_requests_mock(self):
with stackinabox.util_requests_mock.activate():
Expand Down
9 changes: 5 additions & 4 deletions stackinabox/tests/test_responses.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@
logger = logging.getLogger(__name__)


@unittest.skipIf(six.PY3, 'Responses fails on PY3')
def test_basic_responses():

@responses.activate
Expand All @@ -34,7 +33,6 @@ def run():
run()


@unittest.skipIf(six.PY3, 'Responses fails on PY3')
def test_advanced_responses():

def run():
Expand Down Expand Up @@ -65,10 +63,13 @@ def run():
assert res.text == 'okay'

res = requests.get('http://localhost/advanced/_234567890')
assert res.status_code == 500
assert res.status_code == 595

res = requests.put('http://localhost/advanced/h')
assert res.status_code == 500
assert res.status_code == 405

res = requests.put('http://localhost/advanced2/i')
assert res.status_code == 597

StackInABox.reset_services()

Expand Down
63 changes: 63 additions & 0 deletions stackinabox/tests/test_stack.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
import re
import unittest

import ddt
import httpretty
import requests

import stackinabox.util_httpretty
from stackinabox.stack import (
StackInABox, ServiceAlreadyRegisteredError)
from stackinabox.services.service import *
from stackinabox.services.hello import HelloService


class ExceptionalServices(StackInABoxService):

def __init__(self):
super(ExceptionalServices, self).__init__('except')
self.register(StackInABoxService.GET,
'/',
ExceptionalServices.handler)

def handler(self, request, uri, headers):
raise Exception('Exceptional Service Failure')


@ddt.ddt
class TestStack(unittest.TestCase):

def setUp(self):
super(TestStack, self).setUp()

def tearDown(self):
super(TestStack, self).tearDown()
StackInABox.reset_services()

def test_double_service_registration(self):
service1 = HelloService()
service2 = HelloService()

StackInABox.register_service(service1)
with self.assertRaises(ServiceAlreadyRegisteredError):
StackInABox.register_service(service2)

@ddt.data(
('http://honeymoon/', 'honeymoon', '/'),
('https://honeymoon/', 'honeymoon', '/'),
('honeymoon/', 'honeymoon', '/')
)
@ddt.unpack
def test_get_services_url(self, url, base, value):
result = StackInABox.get_services_url(url, base)
self.assertEqual(result, value)

@httpretty.activate
def test_service_exception(self):
exceptional = ExceptionalServices()
StackInABox.register_service(exceptional)

stackinabox.util_httpretty.httpretty_registration('localhost')

res = requests.get('http://localhost/except/')
self.assertEqual(res.status_code, 596)
3 changes: 3 additions & 0 deletions stackinabox/tests/utils/services.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@
from stackinabox.services.service import StackInABoxService


logger = logging.getLogger(__name__)


class AdvancedService(StackInABoxService):

def __init__(self):
Expand Down
12 changes: 12 additions & 0 deletions stackinabox/util_httpretty.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@

from httpretty import register_uri
from httpretty.http import HttpBaseClass
import httpretty.http
import six

from stackinabox.stack import StackInABox
from stackinabox.utils import CaseInsensitiveDict
Expand All @@ -28,6 +30,16 @@ def httpretty_callback(request, uri, headers):


def httpretty_registration(uri):

status_data = {
595: 'StackInABoxService - Unknown Route',
596: 'StackInABox - Exception in Service Handler',
597: 'StackInABox - Unknown Service'
}
for k, v in six.iteritems(status_data):
if k not in httpretty.http.STATUSES:
httpretty.http.STATUSES[k] = v

logger.debug('Registering Stack-In-A-Box at {0} under Python HTTPretty'
.format(uri))
StackInABox.update_uri(uri)
Expand Down
3 changes: 2 additions & 1 deletion tools/test-requirements.txt
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
coverage
ddt
httpretty==0.8.6
nose
nose-exclude
pep8
requests
requests-mock
responses
responses>=0.4.0
six