Skip to content

Commit 201ad23

Browse files
committed
Re-add all the legacy behavior. This fixes #15, gets us to a2. Need to fix the docs.
It was surprisingly easy to do. Main issue was to be clever about waiting for the first UMAPI call in order to find the organization ID before creating the connection. Moved all the legacy stuff to a separate module called legacy so that users have to explicitly ask for it as umapi_client.legacy. Also had to make connection.make_call return the result, so that it could be available to the UMAPI client. This turned out to be a better idea all around, since now errors all have the result in them for inspection by the caller.
1 parent a1cdfe0 commit 201ad23

File tree

10 files changed

+445
-71
lines changed

10 files changed

+445
-71
lines changed

setup.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
2222

2323

2424
setup(name='umapi-client',
25-
version='2.0a1',
25+
version='2.0a2',
2626
description='Client for the User Management API (UMAPI) from Adobe - see https://adobe.ly/2h1pHgV',
2727
long_description=('The User Management API (aka the UMAPI) is an Adobe-hosted network service '
2828
'which provides Adobe Enterprise customers the ability to manage their users. This '

tests/conftest.py

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -27,14 +27,9 @@
2727
from six import StringIO
2828

2929
mock_connection_params = {
30-
"mock_auth": "N/A",
3130
"org_id": "N/A",
32-
"tech_acct_id": "N/A",
33-
"api_key": "N/A",
34-
"client_secret": "N/A",
35-
"private_key_file": "N/A",
36-
"user_management_endpoint": 'https://test/umapi',
37-
"test_mode": False,
31+
"auth": "N/A",
32+
"user_management_endpoint": 'https://test/',
3833
"logger": None,
3934
"retry_max_attempts": 3,
4035
"retry_first_delay": 1,

tests/test_actions.py

Lines changed: 19 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -33,25 +33,25 @@ def test_action_create():
3333

3434

3535
def test_action_create_one():
36-
action = Action(z1="z1 text").do(com1={"com1k": "com1v"})
36+
action = Action(z1="z1 text").append(com1={"com1k": "com1v"})
3737
assert json.dumps(action.wire_dict(), sort_keys=True) == \
3838
'{"do": [{"com1": {"com1k": "com1v"}}], "z1": "z1 text"}'
3939

4040

4141
def test_action_create_one_dofirst():
42-
action = Action(z1="z1 text").do_first(com1={"com1k": "com1v"})
42+
action = Action(z1="z1 text").insert(com1={"com1k": "com1v"})
4343
assert json.dumps(action.wire_dict(), sort_keys=True) == \
4444
'{"do": [{"com1": {"com1k": "com1v"}}], "z1": "z1 text"}'
4545

4646

4747
def test_action_create_two():
48-
action = Action(a1="a1 text", z1="z1 text").do(com1={"com1k": "com1v"}).do(com2={"com2k": "com2v"})
48+
action = Action(a1="a1 text", z1="z1 text").append(com1={"com1k": "com1v"}).append(com2={"com2k": "com2v"})
4949
assert json.dumps(action.wire_dict(), sort_keys=True) == \
5050
'{"a1": "a1 text", "do": [{"com1": {"com1k": "com1v"}}, {"com2": {"com2k": "com2v"}}], "z1": "z1 text"}'
5151

5252

5353
def test_action_create_two_dofirst():
54-
action = Action(a1="a1 text", z1="z1 text").do(com1={"com1k": "com1v"}).do_first(com2={"com2k": "com2v"})
54+
action = Action(a1="a1 text", z1="z1 text").append(com1={"com1k": "com1v"}).insert(com2={"com2k": "com2v"})
5555
assert json.dumps(action.wire_dict(), sort_keys=True) == \
5656
'{"a1": "a1 text", "do": [{"com2": {"com2k": "com2v"}}, {"com1": {"com1k": "com1v"}}], "z1": "z1 text"}'
5757

@@ -60,33 +60,33 @@ def test_execute_single_success():
6060
with mock.patch("umapi_client.connection.requests.post") as mock_post:
6161
mock_post.return_value = MockResponse(200, {"result": "success"})
6262
conn = Connection(**mock_connection_params)
63-
action = Action(top="top").do(a="a")
63+
action = Action(top="top").append(a="a")
6464
assert conn.execute_single(action) is True
6565

6666

6767
def test_execute_single_dofirst_success():
6868
with mock.patch("umapi_client.connection.requests.post") as mock_post:
6969
mock_post.return_value = MockResponse(200, {"result": "success"})
7070
conn = Connection(**mock_connection_params)
71-
action = Action(top="top").do_first(a="a")
71+
action = Action(top="top").insert(a="a")
7272
assert conn.execute_single(action) is True
7373

7474

7575
def test_execute_multiple_success():
7676
with mock.patch("umapi_client.connection.requests.post") as mock_post:
7777
mock_post.return_value = MockResponse(200, {"result": "success"})
7878
conn = Connection(**mock_connection_params)
79-
action0 = Action(top="top0").do(a="a0").do(b="b")
80-
action1 = Action(top="top1").do(a="a1")
79+
action0 = Action(top="top0").append(a="a0").append(b="b")
80+
action1 = Action(top="top1").append(a="a1")
8181
assert conn.execute_multiple([action0, action1]) == 2
8282

8383

8484
def test_execute_multiple_dofirst_success():
8585
with mock.patch("umapi_client.connection.requests.post") as mock_post:
8686
mock_post.return_value = MockResponse(200, {"result": "success"})
8787
conn = Connection(**mock_connection_params)
88-
action0 = Action(top="top0").do(a="a0").do_first(b="b")
89-
action1 = Action(top="top1").do(a="a1")
88+
action0 = Action(top="top0").append(a="a0").insert(b="b")
89+
action1 = Action(top="top1").append(a="a1")
9090
assert conn.execute_multiple([action0, action1]) == 2
9191

9292

@@ -97,7 +97,7 @@ def test_execute_single_error():
9797
"errorCode": "test.error",
9898
"message": "Test error message"}]})
9999
conn = Connection(**mock_connection_params)
100-
action = Action(top="top").do(a="a")
100+
action = Action(top="top").append(a="a")
101101
assert conn.execute_single(action) is False
102102
assert action.execution_errors() == [{"command": {"a": "a"},
103103
"step": 0,
@@ -115,7 +115,7 @@ def test_execute_single_multi_error():
115115
"errorCode": "error2",
116116
"message": "message2"}]})
117117
conn = Connection(**mock_connection_params)
118-
action = Action(top="top").do(a="a")
118+
action = Action(top="top").append(a="a")
119119
assert conn.execute_single(action) is False
120120
assert action.execution_errors() == [{"command": {"a": "a"},
121121
"step": 0,
@@ -134,7 +134,7 @@ def test_execute_single_dofirst_error():
134134
"errorCode": "test.error",
135135
"message": "Test error message"}]})
136136
conn = Connection(**mock_connection_params)
137-
action = Action(top="top").do_first(a="a")
137+
action = Action(top="top").insert(a="a")
138138
assert conn.execute_single(action) is False
139139
assert action.execution_errors() == [{"command": {"a": "a"},
140140
"step": 0,
@@ -151,8 +151,8 @@ def test_execute_multiple_error():
151151
"errorCode": "test.error",
152152
"message": "Test error message"}]})
153153
conn = Connection(**mock_connection_params)
154-
action0 = Action(top="top0").do(a="a0")
155-
action1 = Action(top="top1").do(a="a1").do(b="b")
154+
action0 = Action(top="top0").append(a="a0")
155+
action1 = Action(top="top1").append(a="a1").append(b="b")
156156
assert conn.execute_multiple([action0, action1]) == 1
157157
assert action0.execution_errors() == []
158158
assert action1.execution_errors() == [{"command": {"b": "b"},
@@ -173,8 +173,8 @@ def test_execute_multiple_multi_error():
173173
"errorCode": "error2",
174174
"message": "message2"}]})
175175
conn = Connection(**mock_connection_params)
176-
action0 = Action(top="top0").do(a="a0")
177-
action1 = Action(top="top1").do(a="a1").do(b="b")
176+
action0 = Action(top="top0").append(a="a0")
177+
action1 = Action(top="top1").append(a="a1").append(b="b")
178178
assert conn.execute_multiple([action0, action1]) == 1
179179
assert action0.execution_errors() == []
180180
assert action1.execution_errors() == [{"command": {"b": "b"},
@@ -196,8 +196,8 @@ def test_execute_multiple_dofirst_error():
196196
"errorCode": "test.error",
197197
"message": "Test error message"}]})
198198
conn = Connection(**mock_connection_params)
199-
action0 = Action(top="top0").do(a="a0")
200-
action1 = Action(top="top1").do(a="a1").do_first(b="b")
199+
action0 = Action(top="top0").append(a="a0")
200+
action1 = Action(top="top1").append(a="a1").insert(b="b")
201201
assert conn.execute_multiple([action0, action1]) == 1
202202
assert action0.execution_errors() == []
203203
assert action1.execution_errors() == [{"command": {"a": "a1"},

tests/test_connections.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,14 +32,14 @@ def test_get_success():
3232
with mock.patch("umapi_client.connection.requests.get") as mock_get:
3333
mock_get.return_value = MockResponse(200, body=["test", "body"])
3434
conn = Connection(**mock_connection_params)
35-
assert conn.make_call("") == ["test", "body"]
35+
assert conn.make_call("").json() == ["test", "body"]
3636

3737

3838
def test_post_success():
3939
with mock.patch("umapi_client.connection.requests.post") as mock_post:
4040
mock_post.return_value = MockResponse(200, body=["test", "body"])
4141
conn = Connection(**mock_connection_params)
42-
assert conn.make_call("", [3, 5]) == ["test", "body"]
42+
assert conn.make_call("", [3, 5]).json() == ["test", "body"]
4343

4444

4545
def test_get_retry_header_1():

tests/test_legacy.py

Lines changed: 182 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,182 @@
1+
# Copyright (c) 2016 Adobe Systems Incorporated. All rights reserved.
2+
#
3+
# Permission is hereby granted, free of charge, to any person obtaining a copy
4+
# of this software and associated documentation files (the "Software"), to deal
5+
# in the Software without restriction, including without limitation the rights
6+
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7+
# copies of the Software, and to permit persons to whom the Software is
8+
# furnished to do so, subject to the following conditions:
9+
#
10+
# The above copyright notice and this permission notice shall be included in all
11+
# copies or substantial portions of the Software.
12+
#
13+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14+
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15+
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16+
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17+
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18+
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19+
# SOFTWARE.
20+
21+
import mock
22+
import json
23+
import pytest
24+
25+
from conftest import MockResponse
26+
from umapi_client.legacy import UMAPI, Action
27+
from umapi_client.legacy import UMAPIError, UMAPIRetryError, UMAPIRequestError, ActionFormatError
28+
29+
30+
# These values will be returned in the various cases by get/post
31+
success_response = MockResponse(200, {"result": "success"})
32+
error_response = MockResponse(200, {"result": "error", "errors": [{"errorCode": "test.error"}]})
33+
retry_response = MockResponse(429, headers={"Retry-After": "1"})
34+
not_found_response = MockResponse(404, text="404 Object Not Found")
35+
36+
@mock.patch('umapi_client.legacy.requests.get', return_value=success_response)
37+
def test_list_users_success(_):
38+
"""Test Users List - SUCCESS"""
39+
api = UMAPI('http://example.com/success', "N/A", retry_max_attempts=1)
40+
assert api.users(None) == {"result": "success"}
41+
42+
43+
@mock.patch('umapi_client.legacy.requests.get', return_value=error_response)
44+
def test_list_users_error(_):
45+
"""Test Users List - ERROR"""
46+
api = UMAPI('http://example.com/error', "N/A", retry_max_attempts=1)
47+
pytest.raises(UMAPIRequestError, api.users, None)
48+
49+
50+
@mock.patch('umapi_client.legacy.requests.get', return_value=not_found_response)
51+
def test_list_users_failure(patch):
52+
"""Test Users List - FAILURE"""
53+
api = UMAPI('http://example.com/failure', "N/A", retry_max_attempts=1)
54+
pytest.raises(UMAPIError, api.users, None)
55+
patch.return_value = retry_response
56+
api = UMAPI('http://example.com/retry', "N/A", retry_max_attempts=1)
57+
pytest.raises(UMAPIRetryError, api.users, None)
58+
59+
60+
@mock.patch('umapi_client.legacy.requests.get', return_value=success_response)
61+
def test_list_groups_success(_):
62+
"""Test Groups List - SUCCESS"""
63+
api = UMAPI('http://example.com/success', "N/A", retry_max_attempts=1)
64+
assert api.groups(None) == {"result": "success"}
65+
66+
67+
@mock.patch('umapi_client.legacy.requests.post', return_value=success_response)
68+
def test_user_create_success(_):
69+
"""Test User Creation - SUCCESS"""
70+
api = UMAPI('http://example.com/success', "N/A", retry_max_attempts=1)
71+
72+
action = Action(user_key="[email protected]").do(
73+
addAdobeID={"email": "[email protected]"}
74+
)
75+
76+
assert api.action(None, action) == {"result": "success"}
77+
78+
79+
@mock.patch('umapi_client.legacy.requests.post', return_value=error_response)
80+
def test_user_create_error(_):
81+
"""Test User Creation - ERROR"""
82+
api = UMAPI('http://example.com/error', "N/A", retry_max_attempts=1)
83+
84+
action = Action(user_key="[email protected]").do(
85+
addAdobeID={"email": "[email protected]"}
86+
)
87+
pytest.raises(UMAPIRequestError, api.action, None, action)
88+
89+
90+
@mock.patch('umapi_client.legacy.requests.post', return_value=not_found_response)
91+
def test_user_create_failure(patch):
92+
"""Test User Creation - FAILURE"""
93+
action = Action(user_key="[email protected]").do(
94+
addAdobeID={"email": "[email protected]"}
95+
)
96+
api = UMAPI('http://example.com/failure', "N/A", retry_max_attempts=1)
97+
pytest.raises(UMAPIError, api.action, None, action)
98+
patch.return_value = retry_response
99+
api = UMAPI('http://example.com/retry', "N/A", retry_max_attempts=1)
100+
pytest.raises(UMAPIRetryError, api.action, None, action)
101+
102+
103+
@mock.patch('umapi_client.legacy.requests.post', return_value=success_response)
104+
def test_product_add(_):
105+
"""Test Product Add - SUCCESS"""
106+
api = UMAPI('http://example.com/success', "N/A", retry_max_attempts=1)
107+
108+
action = Action(user_key="[email protected]").do(
109+
add=["product1", "product2"]
110+
)
111+
112+
assert api.action(None, action) == {"result": "success"}
113+
114+
115+
@mock.patch('umapi_client.legacy.requests.post', return_value=success_response)
116+
def test_action_format_error(_):
117+
"""Test Action Format Error"""
118+
api = UMAPI('http://example.com/success', "N/A", retry_max_attempts=1)
119+
action = ''
120+
pytest.raises(ActionFormatError, api.action, None, action)
121+
122+
123+
def test_action_obj_create():
124+
""""Create a user creation action object and make sure that we can serialize it in the expected format"""
125+
action = Action(user="[email protected]").do(
126+
addAdobeID={"email": "[email protected]"}
127+
)
128+
assert json.dumps(action.wire_dict(), sort_keys=True) == \
129+
'{"do": [{"addAdobeID": {"email": "[email protected]"}}], "user": "[email protected]"}'
130+
action = Action(user_key="[email protected]").do(
131+
addAdobeID={"email": "[email protected]"}
132+
)
133+
assert json.dumps(action.wire_dict(), sort_keys=True) == \
134+
'{"do": [{"addAdobeID": {"email": "[email protected]"}}], "user": "[email protected]"}'
135+
136+
137+
def test_action_obj_remove():
138+
""""Create a user removal action object"""
139+
action = Action(user="[email protected]").do(
140+
removeFromOrg={}
141+
)
142+
assert json.dumps(action.wire_dict(), sort_keys=True) == \
143+
'{"do": [{"removeFromOrg": {}}], "user": "[email protected]"}'
144+
action = Action(user_key="[email protected]").do(
145+
removeFromOrg={}
146+
)
147+
assert json.dumps(action.wire_dict(), sort_keys=True) == \
148+
'{"do": [{"removeFromOrg": {}}], "user": "[email protected]"}'
149+
150+
151+
def test_action_obj_update():
152+
"""Create a user update action object"""
153+
action = Action(user="[email protected]").do(
154+
update={"firstname": "example", "lastname": "user"}
155+
)
156+
assert json.dumps(action.wire_dict(), sort_keys=True) == \
157+
'{"do": [{"update": {"firstname": "example", "lastname": "user"}}], "user": "[email protected]"}'
158+
action = Action(user_key="[email protected]").do(
159+
update={"firstname": "example", "lastname": "user"}
160+
)
161+
assert json.dumps(action.wire_dict(), sort_keys=True) == \
162+
'{"do": [{"update": {"firstname": "example", "lastname": "user"}}], "user": "[email protected]"}'
163+
164+
165+
def test_action_obj_multi():
166+
"""Create a multi-action action object"""
167+
action = Action(user="[email protected]").do(
168+
addAdobeID={"email": "[email protected]"},
169+
add=["product1", "product2"],
170+
remove=["product3"]
171+
)
172+
assert json.dumps(action.wire_dict(), sort_keys=True) == \
173+
'{"do": [{"addAdobeID": {"email": "[email protected]"}}, {"add": {"product": ["product1", "product2"]}}, {"remove": {"product": ["product3"]}}], "user": "[email protected]"}'
174+
175+
176+
def test_action_obj_requestid():
177+
"""Include a request ID in action object"""
178+
action = Action(user="[email protected]", requestID="abc123").do(
179+
add=["product1"]
180+
)
181+
assert json.dumps(action.wire_dict(), sort_keys=True) == \
182+
'{"do": [{"add": {"product": ["product1"]}}], "requestID": "abc123", "user": "[email protected]"}'

umapi_client/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,4 +20,4 @@
2020

2121
from .connection import Connection
2222
from .api import Action, UserAction, QueryMultiple
23-
from .error import ClientError, UnavailableError, RequestError, ServerError
23+
from .error import ClientError, RequestError, ServerError, UnavailableError

0 commit comments

Comments
 (0)