Skip to content

Commit 5943dfb

Browse files
committed
test(user): add CRUD tests for auth0 endpoints
Also, improve error handling of Auth0Users.java
1 parent 114fc65 commit 5943dfb

File tree

10 files changed

+454
-34
lines changed

10 files changed

+454
-34
lines changed

src/main/java/com/conveyal/datatools/manager/auth/Auth0Users.java

Lines changed: 46 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
package com.conveyal.datatools.manager.auth;
22

33
import com.conveyal.datatools.manager.DataManager;
4-
import com.fasterxml.jackson.core.type.TypeReference;
54
import com.fasterxml.jackson.databind.JsonNode;
65
import com.fasterxml.jackson.databind.ObjectMapper;
76
import org.apache.http.HttpResponse;
@@ -16,7 +15,6 @@
1615
import java.io.IOException;
1716
import java.net.URI;
1817
import java.net.URISyntaxException;
19-
import java.util.Collection;
2018
import java.util.HashSet;
2119
import java.util.Set;
2220

@@ -43,7 +41,8 @@ private static URI getUrl(String searchQuery, int page, int perPage, boolean inc
4341
// always filter users by datatools client_id
4442
String defaultQuery = "app_metadata.datatools.client_id:" + clientId;
4543
URIBuilder builder = new URIBuilder();
46-
builder.setScheme("https").setHost(AUTH0_DOMAIN).setPath("/api/v2/users");
44+
setSchemePortAndHost(builder);
45+
builder.setPath("/api/v2/users");
4746
builder.setParameter("sort", "email:1");
4847
builder.setParameter("per_page", Integer.toString(perPage));
4948
builder.setParameter("page", Integer.toString(page));
@@ -82,20 +81,40 @@ private static String doRequest(URI uri) {
8281

8382
request.addHeader("Authorization", "Bearer " + AUTH0_API_TOKEN);
8483
request.setHeader("Accept-Charset", charset);
85-
HttpResponse response = null;
84+
HttpResponse response;
85+
86+
LOG.info("Making request: ({})", request.toString());
8687

8788
try {
8889
response = client.execute(request);
8990
} catch (IOException e) {
91+
LOG.error("An exception occurred while making a request to Auth0");
9092
e.printStackTrace();
93+
return null;
9194
}
9295

9396
String result = null;
9497

95-
try {
96-
result = EntityUtils.toString(response.getEntity());
97-
} catch (IOException e) {
98-
e.printStackTrace();
98+
if (response.getEntity() != null) {
99+
try {
100+
result = EntityUtils.toString(response.getEntity());
101+
} catch (IOException e) {
102+
LOG.error("An exception occurred while parsing a response from Auth0");
103+
e.printStackTrace();
104+
}
105+
} else {
106+
LOG.warn("No response body available to parse from Auth0 request");
107+
}
108+
109+
int statusCode = response.getStatusLine().getStatusCode();
110+
if(statusCode >= 300) {
111+
LOG.warn(
112+
"HTTP request to Auth0 returned error code >= 300: ({}). Body: {}",
113+
request.toString(),
114+
result != null ? result : ""
115+
);
116+
} else {
117+
LOG.info("Successfully made request: ({})", request.toString());
99118
}
100119

101120
return result;
@@ -118,35 +137,18 @@ public static String getAuth0Users(String queryString) {
118137
return getAuth0Users(queryString, 0);
119138
}
120139

121-
/**
122-
* Get all users for this application (using the default search).
123-
*/
124-
public static Collection<Auth0UserProfile> getAll () {
125-
Collection<Auth0UserProfile> users = new HashSet<>();
126-
127-
// limited to the first 100
128-
URI uri = getUrl(null, 0, 100, false);
129-
String response = doRequest(uri);
130-
try {
131-
users = mapper.readValue(response, new TypeReference<Collection<Auth0UserProfile>>(){});
132-
} catch (IOException e) {
133-
e.printStackTrace();
134-
}
135-
return users;
136-
}
137-
138140
/**
139141
* Get a single Auth0 user for the specified ID.
140142
*/
141143
public static Auth0UserProfile getUserById(String id) {
142-
143144
URIBuilder builder = new URIBuilder();
144-
builder.setScheme("https").setHost(AUTH0_DOMAIN).setPath("/api/v2/users/" + id);
145+
setSchemePortAndHost(builder);
146+
builder.setPath("/api/v2/users/" + id);
145147
URI uri = null;
146148
try {
147149
uri = builder.build();
148-
149150
} catch (URISyntaxException e) {
151+
LOG.error("Unable to build URI to getUserById");
150152
e.printStackTrace();
151153
return null;
152154
}
@@ -155,23 +157,33 @@ public static Auth0UserProfile getUserById(String id) {
155157
try {
156158
user = mapper.readValue(response, Auth0UserProfile.class);
157159
} catch (IOException e) {
160+
LOG.error("Unable to parse user profile response from Auth0! Response: {}", response);
158161
e.printStackTrace();
159162
}
160163
return user;
161164
}
162165

163166
/**
164-
* Get users subscribed to a given target ID.
167+
* Sets uri builder scheme port and host according to whether a test environment is in effect
165168
*/
166-
public static String getUsersBySubscription(String subscriptionType, String target) {
167-
return getAuth0Users("app_metadata.datatools.subscriptions.type:" + subscriptionType + " AND app_metadata.datatools.subscriptions.target:" + target);
169+
private static void setSchemePortAndHost(URIBuilder builder) {
170+
if (AUTH0_DOMAIN.equals("localhost:8089")) {
171+
// set items for testing purposes assuming use of a Wiremock server
172+
builder.setScheme("http");
173+
builder.setPort(8089);
174+
builder.setHost("localhost");
175+
} else {
176+
// use live Auth0 domain
177+
builder.setScheme("https");
178+
builder.setHost(AUTH0_DOMAIN);
179+
}
168180
}
169181

170182
/**
171-
* Get users belong to a specified organization.
183+
* Get users subscribed to a given target ID.
172184
*/
173-
public static String getUsersForOrganization(String organizationId) {
174-
return getAuth0Users("app_metadata.datatools.organizations.organization_id:" + organizationId);
185+
public static String getUsersBySubscription(String subscriptionType, String target) {
186+
return getAuth0Users("app_metadata.datatools.subscriptions.type:" + subscriptionType + " AND app_metadata.datatools.subscriptions.target:" + target);
175187
}
176188

177189
public static Set<String> getVerifiedEmailsBySubscription(String subscriptionType, String target) {

src/test/java/com/conveyal/datatools/manager/controllers/api/UserControllerTest.java

Lines changed: 151 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,11 @@
1111

1212
import static com.conveyal.datatools.TestUtils.parseJson;
1313
import static com.github.tomakehurst.wiremock.client.WireMock.aResponse;
14+
import static com.github.tomakehurst.wiremock.client.WireMock.delete;
1415
import static com.github.tomakehurst.wiremock.client.WireMock.equalTo;
16+
import static com.github.tomakehurst.wiremock.client.WireMock.get;
1517
import static com.github.tomakehurst.wiremock.client.WireMock.matchingJsonPath;
18+
import static com.github.tomakehurst.wiremock.client.WireMock.patch;
1619
import static com.github.tomakehurst.wiremock.client.WireMock.post;
1720
import static com.github.tomakehurst.wiremock.client.WireMock.stubFor;
1821
import static com.github.tomakehurst.wiremock.client.WireMock.urlPathEqualTo;
@@ -45,6 +48,73 @@ public static void setUp() {
4548
DatatoolsTest.setUp();
4649
}
4750

51+
/**
52+
* Make sure the user endpoint can return a list of users
53+
*/
54+
@Test
55+
public void canListFirstTenUsers() throws IOException {
56+
// create wiremock stub for get users endpoint
57+
stubFor(
58+
get(urlPathEqualTo("/api/v2/users"))
59+
.withQueryParam("page", equalTo("1"))
60+
.willReturn(
61+
aResponse()
62+
.withBodyFile("getFirstTenUsersResponse.json")
63+
)
64+
);
65+
66+
67+
// make request and parse the json response
68+
JsonNode userResponse = parseJson(
69+
given()
70+
.port(4000)
71+
.get("/api/manager/secure/user?page=1")
72+
.then()
73+
.extract()
74+
.response()
75+
.asString()
76+
);
77+
78+
// make sure the response matches the saved snapshot
79+
assertThat(userResponse, matchesSnapshot());
80+
}
81+
82+
/**
83+
* Make sure a user can be created
84+
*/
85+
@Test
86+
public void canCreateUser() throws IOException {
87+
// create wiremock stub for create users endpoint
88+
stubFor(
89+
post(urlPathEqualTo("/api/v2/users"))
90+
.withRequestBody(matchingJsonPath("$.email", equalTo("[email protected]")))
91+
.willReturn(
92+
aResponse()
93+
.withBodyFile("createNewUserResponse.json")
94+
)
95+
);
96+
97+
98+
// make request and parse the json response
99+
JsonNode createUserResponse = parseJson(
100+
given()
101+
.port(4000)
102+
.body("{\n" +
103+
" \"email\" : \"[email protected]\",\n" +
104+
" \"password\" : \"password\",\n" +
105+
" \"permissions\" : {}\n" +
106+
"}")
107+
.post("/api/manager/secure/user")
108+
.then()
109+
.extract()
110+
.response()
111+
.asString()
112+
);
113+
114+
// make sure the response matches the saved snapshot
115+
assertThat(createUserResponse, matchesSnapshot());
116+
}
117+
48118
/**
49119
* Make sure a meaningful Auth0 error can be returned when a duplicate user is being created
50120
*/
@@ -82,4 +152,85 @@ public void canReturnMeaningfulAuth0Error() throws IOException {
82152
// make sure the response matches the saved snapshot
83153
assertThat(createUserResponse, matchesSnapshot());
84154
}
155+
156+
/**
157+
* Make sure a user can be updated
158+
*/
159+
@Test
160+
public void canUpdateUser() throws IOException {
161+
// create wiremock stub for update users endpoint
162+
stubFor(
163+
patch(urlPathEqualTo("/api/v2/users/auth0%7Ctest-existing-user"))
164+
.withRequestBody(
165+
matchingJsonPath(
166+
"$.app_metadata.datatools[0].permissions[0].type",
167+
equalTo("administer-application")
168+
)
169+
)
170+
.willReturn(
171+
aResponse()
172+
.withBodyFile("updateExistingUserResponse.json")
173+
)
174+
);
175+
176+
// create wiremock stub for get user by id endpoint
177+
stubFor(
178+
get(urlPathEqualTo("/api/v2/users/auth0%7Ctest-existing-user"))
179+
.willReturn(
180+
aResponse()
181+
.withBodyFile("getExistingUserResponse.json")
182+
)
183+
);
184+
185+
186+
// make request and parse the json response
187+
JsonNode createUserResponse = parseJson(
188+
given()
189+
.port(4000)
190+
.body("{" +
191+
"\"user_id\": \"auth0|test-existing-user\"" +
192+
",\"data\": [{" +
193+
"\"permissions\": [{\"type\": \"administer-application\"}]," +
194+
"\"projects\": []," +
195+
"\"organizations\": []," +
196+
"\"client_id\":\"testing-client-id\"" +
197+
"}]" +
198+
"}")
199+
.put("/api/manager/secure/user/auth0|test-existing-user")
200+
.then()
201+
.extract()
202+
.response()
203+
.asString()
204+
);
205+
206+
// make sure the response matches the saved snapshot
207+
assertThat(createUserResponse, matchesSnapshot());
208+
}
209+
210+
/**
211+
* Make sure a user can be deleted
212+
*/
213+
@Test
214+
public void canDeleteUser() throws IOException {
215+
// create wiremock stub for the delate users endpoint
216+
stubFor(
217+
delete(urlPathEqualTo("/api/v2/users/auth0%7Ctest-existing-user"))
218+
.willReturn(aResponse())
219+
);
220+
221+
222+
// make request and parse the json response
223+
JsonNode deleteUserResponse = parseJson(
224+
given()
225+
.port(4000)
226+
.delete("/api/manager/secure/user/auth0|test-existing-user")
227+
.then()
228+
.extract()
229+
.response()
230+
.asString()
231+
);
232+
233+
// make sure the response matches the saved snapshot
234+
assertThat(deleteUserResponse, matchesSnapshot());
235+
}
85236
}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
{
2+
"email": "[email protected]",
3+
"email_verified": false,
4+
"updated_at": "2019-02-16T01:27:19.810Z",
5+
"user_id": "auth0|test-new-user",
6+
"name": "[email protected]",
7+
"picture": "https://i0.wp.com/cdn.auth0.com/avatars/tu.png?ssl=1",
8+
"nickname": "test-new-user",
9+
"identities": [{
10+
"connection": "Username-Password-Authentication",
11+
"user_id": "test-new-user",
12+
"provider": "auth0",
13+
"isSocial": false
14+
}],
15+
"created_at": "2019-02-16T01:27:19.810Z",
16+
"app_metadata": {
17+
"datatools": [{
18+
"permissions": [],
19+
"projects": [],
20+
"organizations": [],
21+
"client_id": "testing-client-id"
22+
}]
23+
}
24+
}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
{
2+
"email": "[email protected]",
3+
"email_verified": false,
4+
"updated_at": "2019-02-16T01:27:19.810Z",
5+
"user_id": "auth0|test-existing-user",
6+
"name": "[email protected]",
7+
"picture": "https://i0.wp.com/cdn.auth0.com/avatars/tu.png?ssl=1",
8+
"nickname": "test-existing-user",
9+
"identities": [{
10+
"connection": "Username-Password-Authentication",
11+
"user_id": "test-existing-user",
12+
"provider": "auth0",
13+
"isSocial": false
14+
}],
15+
"created_at": "2019-02-16T01:27:19.810Z",
16+
"app_metadata": {
17+
"datatools": [{
18+
"permissions": [],
19+
"projects": [],
20+
"organizations": [],
21+
"client_id": "testing-client-id"
22+
}]
23+
}
24+
}

0 commit comments

Comments
 (0)