Skip to content

Commit 9908cb7

Browse files
author
derwentx
committed
added more tests cases for 3leg
1 parent 1dea17e commit 9908cb7

File tree

5 files changed

+169
-31
lines changed

5 files changed

+169
-31
lines changed

README.rst

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,10 @@ Roadmap
1717

1818
- [x] Create initial fork
1919
- [x] Implement 3-legged OAuth on Wordpress client
20-
- [x] Better local storage of OAuth creds to stop unnecessary API keys being generated
21-
- [ ] Implement iterator for conveniant access to API items
20+
- [x] Better local storage of OAuth credentials to stop unnecessary API keys being generated
21+
- [ ] Support easy image upload to WC Api
22+
- [ ] Better handling of timeouts with a back-off
23+
- [ ] Implement iterator for convenient access to API items
2224

2325
Requirements
2426
------------
@@ -138,7 +140,8 @@ Setup for the new WP REST API integration (WooCommerce 2.6 or later):
138140
consumer_key="ck_XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
139141
consumer_secret="cs_XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
140142
api="wp-json",
141-
version="wc/v1"
143+
version="wc/v2",
144+
callback='http://127.0.0.1/oauth1_callback'
142145
)
143146
144147
Options
@@ -165,6 +168,8 @@ Options
165168
+-----------------------+-------------+----------+------------------------------------------------------------------------------------------------------------------+
166169
| ``query_string_auth`` | ``bool`` | no | Use query string for Basic Authentication when ``True`` and using HTTPS, default is ``False`` which uses header |
167170
+-----------------------+-------------+----------+------------------------------------------------------------------------------------------------------------------+
171+
| ``oauth1a_3leg`` | ``string`` | no | use oauth1a 3-legged authentication |
172+
+-----------------------+-------------+----------+------------------------------------------------------------------------------------------------------------------+
168173
| ``creds_store`` | ``string`` | no | JSON file where oauth verifier is stored (only used with OAuth_3Leg) |
169174
+-----------------------+-------------+----------+------------------------------------------------------------------------------------------------------------------+
170175

tests.py

Lines changed: 72 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -373,19 +373,21 @@ def setUp(self):
373373
consumer_secret=self.consumer_secret,
374374
basic_auth=True,
375375
api=self.api_name,
376-
version=self.api_ver
376+
version=self.api_ver,
377+
query_string_auth=False,
377378
)
378379

379380
def test_endpoint_url(self):
380-
basic_api_params = dict(**self.api_params)
381381
api = API(
382-
**basic_api_params
382+
**self.api_params
383383
)
384384
endpoint_url = api.requester.endpoint_url(self.endpoint)
385385
endpoint_url = api.auth.get_auth_url(endpoint_url, 'GET')
386386
self.assertEqual(
387387
endpoint_url,
388-
UrlUtils.join_components([self.base_url, self.api_name, self.api_ver, self.endpoint])
388+
UrlUtils.join_components([
389+
self.base_url, self.api_name, self.api_ver, self.endpoint
390+
])
389391
)
390392

391393
def test_query_string_endpoint_url(self):
@@ -590,16 +592,48 @@ def test_get_sign_key(self):
590592
)
591593

592594
def test_flatten_params(self):
593-
flattened_params = UrlUtils.flatten_params(self.twitter_params_raw)
594-
expected_flattened_params = self.twitter_param_string
595-
self.assertEqual(flattened_params, expected_flattened_params)
595+
self.assertEqual(
596+
UrlUtils.flatten_params(self.twitter_params_raw),
597+
self.twitter_param_string
598+
)
599+
600+
def test_sorted_params(self):
601+
# Example given in oauth.net:
602+
oauthnet_example_sorted = [
603+
('a', '1'),
604+
('c', 'hi%%20there'),
605+
('f', '25'),
606+
('f', '50'),
607+
('f', 'a'),
608+
('z', 'p'),
609+
('z', 't')
610+
]
611+
612+
oauthnet_example = copy(oauthnet_example_sorted)
613+
random.shuffle(oauthnet_example)
614+
615+
# oauthnet_example_sorted = [
616+
# ('a', '1'),
617+
# ('c', 'hi%%20there'),
618+
# ('f', '25'),
619+
# ('z', 'p'),
620+
# ]
621+
622+
self.assertEqual(
623+
UrlUtils.sorted_params(oauthnet_example),
624+
oauthnet_example_sorted
625+
)
596626

597-
twitter_base_string = OAuth.get_signature_base_string(
627+
def test_get_signature_base_string(self):
628+
twitter_param_string = OAuth.get_signature_base_string(
598629
self.twitter_method,
599630
self.twitter_params_raw,
600631
self.twitter_target_url
601632
)
602-
self.assertEqual(twitter_base_string, self.twitter_signature_base_string)
633+
self.assertEqual(
634+
twitter_param_string,
635+
self.twitter_signature_base_string
636+
)
603637

604638
# @unittest.skip("changed order of parms to fit wordpress api")
605639
def test_generate_oauth_signature(self):
@@ -815,8 +849,8 @@ def setUp(self):
815849
'url':'http://localhost:18080/wptest/',
816850
'api':'wc-api',
817851
'version':'v3',
818-
'consumer_key':'ck_0297450a41484f27184d1a8a3275f9bab5b69143',
819-
'consumer_secret':'cs_68ef2cf6a708e1c6b30bfb2a38dc948b16bf46c0',
852+
'consumer_key':'ck_e1dd4a9c85f49b9685f7964a154eecb29af39d5a',
853+
'consumer_secret':'cs_8ef3e5d21f8a0c28cd7bc4643e92111a0326b6b1',
820854
}
821855

822856
def test_APIGet(self):
@@ -873,14 +907,14 @@ def test_APIPutWithSimpleQuery(self):
873907

874908
@unittest.skip("Should only work on my machine")
875909
class WCApiTestCasesNew(unittest.TestCase):
876-
""" Tests for New WC API """
910+
""" Tests for New wp-json/wc/v2 API """
877911
def setUp(self):
878912
self.api_params = {
879913
'url':'http://localhost:18080/wptest/',
880914
'api':'wp-json',
881915
'version':'wc/v2',
882-
'consumer_key':'ck_0297450a41484f27184d1a8a3275f9bab5b69143',
883-
'consumer_secret':'cs_68ef2cf6a708e1c6b30bfb2a38dc948b16bf46c0',
916+
'consumer_key':'ck_e1dd4a9c85f49b9685f7964a154eecb29af39d5a',
917+
'consumer_secret':'cs_8ef3e5d21f8a0c28cd7bc4643e92111a0326b6b1',
884918
'callback':'http://127.0.0.1/oauth1_callback',
885919
}
886920

@@ -903,17 +937,38 @@ def test_APIPutWithSimpleQuery(self):
903937
product_id = first_product['id']
904938

905939
nonce = str(random.random())
906-
response = wcapi.put('products/%s?filter%%5Blimit%%5D=5' % (product_id), {"name":str(nonce)})
940+
response = wcapi.put('products/%s?page=2&per_page=5' % (product_id), {"name":str(nonce)})
907941
request_params = UrlUtils.get_query_dict_singular(response.request.url)
908942
response_obj = response.json()
909943
self.assertEqual(response_obj['name'], str(nonce))
910944
self.assertEqual(request_params['filter[limit]'], str(5))
911945

912946
wcapi.put('products/%s' % (product_id), {"name":original_title})
913947

948+
@unittest.skip("Should only work on my machine")
949+
class WCApiTestCasesNew3Leg(unittest.TestCase):
950+
""" Tests for New wp-json/wc/v2 API with 3-leg """
951+
def setUp(self):
952+
self.api_params = {
953+
'url':'http://localhost:18080/wptest/',
954+
'api':'wp-json',
955+
'version':'wc/v2',
956+
'consumer_key':'ck_e1dd4a9c85f49b9685f7964a154eecb29af39d5a',
957+
'consumer_secret':'cs_8ef3e5d21f8a0c28cd7bc4643e92111a0326b6b1',
958+
'callback':'http://127.0.0.1/oauth1_callback',
959+
'oauth1a_3leg': True,
960+
'wp_user': 'wptest',
961+
'wp_pass':'gZ*gZk#v0t5$j#NQ@9'
962+
}
914963

915-
# def test_APIPut(self):
916-
964+
@debug_on()
965+
def test_api_get_3leg(self):
966+
wcapi = API(**self.api_params)
967+
per_page = 10
968+
response = wcapi.get('products')
969+
self.assertIn(response.status_code, [200,201])
970+
response_obj = response.json()
971+
self.assertEqual(len(response_obj), per_page)
917972

918973
# @unittest.skipIf(platform.uname()[1] != "Ich.lan", "should only work on my machine")
919974
@unittest.skip("Should only work on my machine")
@@ -941,7 +996,6 @@ def test_APIGet(self):
941996
response_obj = response.json()
942997
self.assertEqual(response_obj[0]['name'], self.api_params['wp_user'])
943998

944-
@debug_on()
945999
def test_APIGetWithSimpleQuery(self):
9461000
response = self.wpapi.get('media?page=2&per_page=2')
9471001
# print UrlUtils.beautify_response(response)

wordpress/api.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
__title__ = "wordpress-api"
88

99
# from requests import request
10+
import logging
1011
from json import dumps as jsonencode
1112
from wordpress.auth import OAuth, OAuth_3Leg, BasicAuth
1213
from wordpress.transport import API_Requests_Wrapper
@@ -16,7 +17,7 @@ class API(object):
1617
""" API Class """
1718

1819
def __init__(self, url, consumer_key, consumer_secret, **kwargs):
19-
20+
self.logger = logging.getLogger(__name__)
2021
self.requester = API_Requests_Wrapper(url=url, **kwargs)
2122

2223
auth_kwargs = dict(
@@ -163,11 +164,12 @@ def __request(self, method, endpoint, data):
163164
data=data
164165
)
165166

166-
if response.status_code not in [200, 201]:
167+
if response.status_code not in [200, 201, 202]:
167168
self.request_post_mortem(response)
168169

169170
return response
170171

172+
# TODO add kwargs option for headers
171173
def get(self, endpoint):
172174
""" Get requests """
173175
return self.__request("GET", endpoint, None)

wordpress/helpers.py

Lines changed: 55 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,8 @@ def filter_true(cls, seq):
5252

5353
class UrlUtils(object):
5454

55+
reg_netloc = r'(?P<hostname>[^:]+)(:(?P<port>\d+))?'
56+
5557
@classmethod
5658
def get_query_list(cls, url):
5759
""" returns the list of queries in the url """
@@ -174,7 +176,7 @@ def beautify_response(response):
174176

175177
@classmethod
176178
def remove_port(cls, url):
177-
""" Remove the port number from a URL """
179+
""" Remove the port number from a URL"""
178180

179181
urlparse_result = urlparse(url)
180182

@@ -187,10 +189,61 @@ def remove_port(cls, url):
187189
fragment=urlparse_result.fragment
188190
))
189191

192+
@classmethod
193+
def remove_default_port(cls, url, defaults=None):
194+
""" Remove the port number from a URL if it is a default port. """
195+
if defaults is None:
196+
defaults = {
197+
'http':80,
198+
'https':443
199+
}
200+
201+
urlparse_result = urlparse(url)
202+
match = re.match(
203+
cls.reg_netloc,
204+
urlparse_result.netloc
205+
)
206+
assert match, "netloc %s should match regex %s"
207+
if match.groupdict().get('port'):
208+
hostname = match.groupdict()['hostname']
209+
port = int(match.groupdict()['port'])
210+
scheme = urlparse_result.scheme.lower()
211+
212+
if defaults[scheme] == port:
213+
return urlunparse(URLParseResult(
214+
scheme=urlparse_result.scheme,
215+
netloc=hostname,
216+
path=urlparse_result.path,
217+
params=urlparse_result.params,
218+
query=urlparse_result.query,
219+
fragment=urlparse_result.fragment
220+
))
221+
return urlunparse(URLParseResult(
222+
scheme=urlparse_result.scheme,
223+
netloc=urlparse_result.netloc,
224+
path=urlparse_result.path,
225+
params=urlparse_result.params,
226+
query=urlparse_result.query,
227+
fragment=urlparse_result.fragment
228+
))
229+
230+
@classmethod
231+
def lower_scheme(cls, url):
232+
""" ensure the scheme of the url is lowercase. """
233+
urlparse_result = urlparse(url)
234+
return urlunparse(URLParseResult(
235+
scheme=urlparse_result.scheme.lower(),
236+
netloc=urlparse_result.netloc,
237+
path=urlparse_result.path,
238+
params=urlparse_result.params,
239+
query=urlparse_result.query,
240+
fragment=urlparse_result.fragment
241+
))
242+
190243
@classmethod
191244
def normalize_str(cls, string):
192245
""" Normalize string for the purposes of url query parameters. """
193-
return quote(string, '')
246+
return quote(string, '~')
194247

195248
@classmethod
196249
def normalize_params(cls, params):

wordpress/transport.py

Lines changed: 30 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,13 @@
66

77
__title__ = "wordpress-requests"
88

9-
from requests import Request, Session
9+
import logging
1010
from json import dumps as jsonencode
11+
from pprint import pformat
12+
13+
from requests import Request, Session
14+
from wordpress import __default_api__, __default_api_version__, __version__
15+
from wordpress.helpers import SeqUtils, StrUtils, UrlUtils
1116

1217
try:
1318
from urllib.parse import urlencode, quote, unquote, parse_qsl, urlparse, urlunparse
@@ -17,14 +22,11 @@
1722
from urlparse import parse_qsl, urlparse, urlunparse
1823
from urlparse import ParseResult as URLParseResult
1924

20-
from wordpress import __version__
21-
from wordpress import __default_api_version__
22-
from wordpress import __default_api__
23-
from wordpress.helpers import SeqUtils, UrlUtils, StrUtils
2425

2526
class API_Requests_Wrapper(object):
2627
""" provides a wrapper for making requests that handles session info """
2728
def __init__(self, url, **kwargs):
29+
self.logger = logging.getLogger(__name__)
2830
self.url = url
2931
self.api = kwargs.get("api", __default_api__)
3032
self.api_version = kwargs.get("version", __default_api_version__)
@@ -88,9 +90,31 @@ def request(self, method, url, auth=None, params=None, data=None, **kwargs):
8890
request_kwargs['params'] = params
8991
if data is not None:
9092
request_kwargs['data'] = data
91-
return self.session.request(
93+
self.logger.debug("request_kwargs:\n%s" % pformat(request_kwargs))
94+
response = self.session.request(
9295
**request_kwargs
9396
)
97+
self.logger.debug("response_code:\n%s" % pformat(response.status_code))
98+
try:
99+
response_json = response.json()
100+
self.logger.debug("response_json:\n%s" % (pformat(response_json)[:1000]))
101+
except ValueError:
102+
response_text = response.text
103+
self.logger.debug("response_text:\n%s" % (response_text[:1000]))
104+
response_headers = {}
105+
if hasattr(response, 'headers'):
106+
response_headers = response.headers
107+
self.logger.debug("response_headers:\n%s" % pformat(response_headers))
108+
response_links = {}
109+
if hasattr(response, 'links') and response.links:
110+
response_links = response.links
111+
self.logger.debug("response_links:\n%s" % pformat(response_links))
112+
113+
114+
115+
116+
117+
return response
94118

95119
def get(self, *args, **kwargs):
96120
return self.request("GET", *args, **kwargs)

0 commit comments

Comments
 (0)