Coveralls logob
Coveralls logo
  • Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

praekelt / go-http-api / 212

23 Jun 2016 - 14:26 coverage: 98.411% (-1.0%) from 99.392%
212

Pull #21

travis-ci

9181eb84f9c35729a3bad740fb7f9d93?size=18&default=identiconweb-flow
Fix look-up of faultString from JSON RPC errors.
Pull Request #21: Add support for the JSON-RPC Go API.

174 of 185 new or added lines in 5 files covered. (94.05%)

991 of 1007 relevant lines covered (98.41%)

1.97 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

91.85
/go_http/tests/test_account.py
1
"""
2
Tests for go_http.account
3
"""
4

5
import collections
2×
6
import copy
2×
7
import json
2×
8
from unittest import TestCase
2×
9

10
from requests import HTTPError
2×
11
from requests.adapters import HTTPAdapter
2×
12
from requests_testadapter import TestSession, Resp, TestAdapter
2×
13

14
from go_http.account import AccountApiClient
2×
15
from go_http.exceptions import JsonRpcException
2×
16
from go_http.tests.fixtures import account as fixtures
2×
17

18

19
class FakeAccountApiAdapter(HTTPAdapter):
2×
20
    """
21
    Adapter providing a fake account API.
22

23
    This inherits directly from HTTPAdapter instead of using TestAdapter
24
    because it overrides everything TestAdaptor does.
25
    """
26

27
    def __init__(self, account_api):
2×
28
        self.account_api = account_api
2×
29
        super(FakeAccountApiAdapter, self).__init__()
2×
30

31
    def send(self, request, stream=False, timeout=None,
2×
32
             verify=True, cert=None, proxies=None):
33
        response = self.account_api.handle_request(request)
2×
34
        r = self.build_response(request, response)
2×
35
        if not stream:
2×
36
            # force prefetching content unless streaming in use
37
            r.content
2×
38
        return r
2×
39

40

41
class FakeAccountApi(object):
2×
42
    def __init__(self, api_path, auth_token):
2×
43
        self.api_path = api_path
2×
44
        self.auth_token = auth_token
2×
45
        self.responses = collections.defaultdict(list)
2×
46

47
    def http_error_response(self, http_code, error):
2×
48
        return Resp("403 Forbidden", 403, headers={})
2×
49

50
    def jsonrpc_error_response(self, fault, fault_code, fault_string):
2×
51
        return Resp(json.dumps({
2×
52
            "error": {
53
                "fault": fault, "faultCode": fault_code,
54
                "faultString": fault_string,
55
            },
56
        }), 200, headers={})
57

58
    def jsonrpc_success_response(self, result):
2×
59
        return Resp(json.dumps({
2×
60
            "error": None,
61
            "result": result,
62
        }), 200, headers={})
63

64
    def add_success_response(self, method, params, result):
2×
65
        self.responses[method].append((params, copy.deepcopy(result), None))
2×
66

67
    def add_error_response(self, method, params, **error):
2×
68
        self.responses[method].append((params, None, error))
2×
69

70
    def handle_request(self, request):
2×
71
        if request.headers['Authorization'] != 'Bearer %s' % (
2×
72
                self.auth_token):
73
            return self.http_error_response(403, "403 Forbidden")
2×
74
        if request.headers['Content-Type'] != (
2×
75
                'application/json; charset=utf-8'):
NEW
76
            return self.http_error_response(400, "Invalid Content-Type.")
!
77
        if request.method != "POST":
2×
NEW
78
            return self.jsonrpc_error_response(
!
79
                "Fault", 8000, "Only POST method supported")
80
        data = json.loads(request.body)
2×
81
        params, result, error = self.responses[data['method']].pop()
2×
82
        assert params == data['params']
2×
83
        if error is not None:
2×
84
            return self.jsonrpc_error_response(**error)
2×
85
        return self.jsonrpc_success_response(result)
2×
86

87

88
class TestAccountApiClient(TestCase):
2×
89
    API_URL = "http://example.com/go"
2×
90
    AUTH_TOKEN = "auth_token"
2×
91

92
    def setUp(self):
2×
93
        self.account_backend = FakeAccountApi("go/", self.AUTH_TOKEN)
2×
94
        self.session = TestSession()
2×
95
        self.adapter = FakeAccountApiAdapter(self.account_backend)
2×
96
        self.simulate_api_up()
2×
97

98
    def simulate_api_down(self):
2×
NEW
99
        self.session.mount(self.API_URL, TestAdapter("API is down", 500))
!
100

101
    def simulate_api_up(self):
2×
102
        self.session.mount(self.API_URL, self.adapter)
2×
103

104
    def make_client(self, auth_token=AUTH_TOKEN):
2×
105
        return AccountApiClient(
2×
106
            auth_token, api_url=self.API_URL, session=self.session)
107

108
    def assert_http_error(self, expected_status, func, *args, **kw):
2×
109
        try:
2×
110
            func(*args, **kw)
2×
111
        except HTTPError as err:
2×
112
            self.assertEqual(err.response.status_code, expected_status)
2×
113
        else:
114
            self.fail(
2×
115
                "Expected HTTPError with status %s." % (expected_status,))
116

117
    def assert_jsonrpc_exception(self, f, *args, **kw):
2×
NEW
118
        try:
!
NEW
119
            f(*args, **kw)
!
NEW
120
        except Exception as err:
!
NEW
121
            self.assertTrue(isinstance(err, JsonRpcException))
!
NEW
122
            self.assertTrue(isinstance(err.cursor, unicode))
!
NEW
123
            self.assertTrue(isinstance(err.error, Exception))
!
NEW
124
        return err
!
125

126
    def test_assert_http_error(self):
2×
127
        self.session.mount("http://bad.example.com/", TestAdapter("", 500))
2×
128

129
        def bad_req():
2×
130
            r = self.session.get("http://bad.example.com/")
2×
131
            r.raise_for_status()
2×
132

133
        # Fails when no exception is raised.
134
        self.assertRaises(
2×
135
            self.failureException, self.assert_http_error, 404, lambda: None)
136

137
        # Fails when an HTTPError with the wrong status code is raised.
138
        self.assertRaises(
2×
139
            self.failureException, self.assert_http_error, 404, bad_req)
140

141
        # Passes when an HTTPError with the expected status code is raised.
142
        self.assert_http_error(500, bad_req)
2×
143

144
        # Non-HTTPError exceptions aren't caught.
145
        def raise_error():
2×
146
            raise ValueError()
2×
147

148
        self.assertRaises(ValueError, self.assert_http_error, 404, raise_error)
2×
149

150
    def test_default_session(self):
2×
151
        import requests
2×
152
        client = AccountApiClient(self.AUTH_TOKEN)
2×
153
        self.assertTrue(isinstance(client.session, requests.Session))
2×
154

155
    def test_default_api_url(self):
2×
156
        client = AccountApiClient(self.AUTH_TOKEN)
2×
157
        self.assertEqual(
2×
158
            client.api_url, "https://go.vumi.org/api/v1/go")
159

160
    def test_auth_failure(self):
2×
161
        client = self.make_client(auth_token="bogus_token")
2×
162
        self.assert_http_error(403, client.campaigns)
2×
163

164
    def test_jsonrpc_error_handling(self):
2×
165
        client = self.make_client()
2×
166
        self.account_backend.add_error_response(
2×
167
            "campaigns", [],
168
            fault="Fault", fault_code=8002, fault_string="Meep")
169
        try:
2×
170
            client.campaigns()
2×
171
        except JsonRpcException as err:
2×
172
            self.assertEqual(err.fault, "Fault")
2×
173
            self.assertEqual(err.fault_code, 8002)
2×
174
            self.assertEqual(err.fault_string, "Meep")
2×
175
        else:
NEW
176
            self.fail("Excepcted JsonRpcException exception to be raised")
!
177

178
    def test_campaigns(self):
2×
179
        client = self.make_client()
2×
180
        self.account_backend.add_success_response(
2×
181
            "campaigns", [], fixtures.campaigns)
182
        self.assertEqual(client.campaigns(), fixtures.campaigns)
2×
183

184
    def test_conversations(self):
2×
185
        client = self.make_client()
2×
186
        self.account_backend.add_success_response(
2×
187
            "conversations", ["campaign-1"], fixtures.conversations)
188
        self.assertEqual(
2×
189
            client.conversations("campaign-1"),
190
            fixtures.conversations)
191

192
    def test_channels(self):
2×
193
        client = self.make_client()
2×
194
        self.account_backend.add_success_response(
2×
195
            "channels", ["campaign-1"], fixtures.channels)
196
        self.assertEqual(
2×
197
            client.channels("campaign-1"),
198
            fixtures.channels)
199

200
    def test_routers(self):
2×
201
        client = self.make_client()
2×
202
        self.account_backend.add_success_response(
2×
203
            "routers", ["campaign-1"], fixtures.routers)
204
        self.assertEqual(
2×
205
            client.routers("campaign-1"),
206
            fixtures.routers)
207

208
    def test_routing_entries(self):
2×
209
        client = self.make_client()
2×
210
        self.account_backend.add_success_response(
2×
211
            "routing_entries", ["campaign-1"], fixtures.routing_entries)
212
        self.assertEqual(
2×
213
            client.routing_entries("campaign-1"),
214
            fixtures.routing_entries)
215

216
    def test_routing_table(self):
2×
217
        client = self.make_client()
2×
218
        self.account_backend.add_success_response(
2×
219
            "routing_table", ["campaign-1"], fixtures.routing_table)
220
        self.assertEqual(
2×
221
            client.routing_table("campaign-1"),
222
            fixtures.routing_table)
223

224
    def test_update_routing_tabel(self):
2×
225
        client = self.make_client()
2×
226
        self.account_backend.add_success_response(
2×
227
            "update_routing_table", ["campaign-1", fixtures.routing_table],
228
            None)
229
        self.assertEqual(
2×
230
            client.update_routing_table("campaign-1", fixtures.routing_table),
231
            None)
Troubleshooting · Open an Issue · Sales · Support · ENTERPRISE · CAREERS · STATUS
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2023 Coveralls, Inc