Skip to content

Commit d4dd47f

Browse files
authored
Add integration tests for TenantManager operations. (#385)
This adds some integration testing for all of the tenant operations in TenantManager. Several bugs were uncovered after running the tests, so these have been fixed. This is part of the initiative to adding multi-tenancy support (see issue #332).
1 parent 52d6cb5 commit d4dd47f

File tree

6 files changed

+168
-39
lines changed

6 files changed

+168
-39
lines changed

src/main/java/com/google/firebase/auth/FirebaseUserManager.java

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -262,15 +262,15 @@ void deleteTenant(String tenantId) throws FirebaseAuthException {
262262

263263
ListTenantsResponse listTenants(int maxResults, String pageToken)
264264
throws FirebaseAuthException {
265-
ImmutableMap.Builder<String, Object> builder = ImmutableMap.<String, Object>builder()
266-
.put("pageSize", maxResults);
265+
ImmutableMap.Builder<String, Object> builder =
266+
ImmutableMap.<String, Object>builder().put("pageSize", maxResults);
267267
if (pageToken != null) {
268268
checkArgument(!pageToken.equals(
269269
ListTenantsPage.END_OF_LIST), "invalid end of list page token");
270270
builder.put("pageToken", pageToken);
271271
}
272272

273-
GenericUrl url = new GenericUrl(tenantMgtBaseUrl + "/tenants:list");
273+
GenericUrl url = new GenericUrl(tenantMgtBaseUrl + "/tenants");
274274
url.putAll(builder.build());
275275
ListTenantsResponse response = sendRequest("GET", url, null, ListTenantsResponse.class);
276276
if (response == null) {
@@ -329,9 +329,13 @@ private <T> T sendRequest(
329329
HttpResponse response = null;
330330
try {
331331
HttpContent httpContent = content != null ? new JsonHttpContent(jsonFactory, content) : null;
332-
HttpRequest request = requestFactory.buildRequest(method, url, httpContent);
332+
HttpRequest request =
333+
requestFactory.buildRequest(method.equals("PATCH") ? "POST" : method, url, httpContent);
333334
request.setParser(new JsonObjectParser(jsonFactory));
334335
request.getHeaders().set(CLIENT_VERSION_HEADER, clientVersion);
336+
if (method.equals("PATCH")) {
337+
request.getHeaders().set("X-HTTP-Method-Override", "PATCH");
338+
}
335339
request.setResponseInterceptor(interceptor);
336340
response = request.execute();
337341
return response.parseAs(clazz);

src/main/java/com/google/firebase/auth/Tenant.java

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,9 +31,12 @@
3131
*/
3232
public final class Tenant {
3333

34-
@Key("name")
34+
// Lazily initialized from 'resourceName'.
3535
private String tenantId;
3636

37+
@Key("name")
38+
private String resourceName;
39+
3740
@Key("displayName")
3841
private String displayName;
3942

@@ -44,6 +47,9 @@ public final class Tenant {
4447
private boolean emailLinkSignInEnabled;
4548

4649
public String getTenantId() {
50+
if (tenantId == null) {
51+
tenantId = resourceName.substring(resourceName.lastIndexOf("/") + 1);
52+
}
4753
return tenantId;
4854
}
4955

src/main/java/com/google/firebase/auth/TenantManager.java

Lines changed: 13 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -178,6 +178,19 @@ public ApiFuture<Tenant> createTenantAsync(@NonNull CreateRequest request) {
178178
return createTenantOp(request).callAsync(firebaseApp);
179179
}
180180

181+
private CallableOperation<Tenant, FirebaseAuthException> createTenantOp(
182+
final CreateRequest request) {
183+
// TODO(micahstairs): Add a check to make sure the app has not been destroyed yet.
184+
checkNotNull(request, "create request must not be null");
185+
return new CallableOperation<Tenant, FirebaseAuthException>() {
186+
@Override
187+
protected Tenant execute() throws FirebaseAuthException {
188+
return userManager.createTenant(request);
189+
}
190+
};
191+
}
192+
193+
181194
/**
182195
* Updates an existing user account with the attributes contained in the specified {@link
183196
* UpdateRequest}.
@@ -215,18 +228,6 @@ protected Tenant execute() throws FirebaseAuthException {
215228
};
216229
}
217230

218-
private CallableOperation<Tenant, FirebaseAuthException> createTenantOp(
219-
final CreateRequest request) {
220-
// TODO(micahstairs): Add a check to make sure the app has not been destroyed yet.
221-
checkNotNull(request, "create request must not be null");
222-
return new CallableOperation<Tenant, FirebaseAuthException>() {
223-
@Override
224-
protected Tenant execute() throws FirebaseAuthException {
225-
return userManager.createTenant(request);
226-
}
227-
};
228-
}
229-
230231
/**
231232
* Deletes the tenant identified by the specified tenant ID.
232233
*

src/test/java/com/google/firebase/auth/FirebaseAuthIT.java

Lines changed: 130 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -46,8 +46,6 @@
4646
import com.google.firebase.FirebaseApp;
4747
import com.google.firebase.FirebaseOptions;
4848
import com.google.firebase.ImplFirebaseTrampolines;
49-
import com.google.firebase.auth.UserRecord.CreateRequest;
50-
import com.google.firebase.auth.UserRecord.UpdateRequest;
5149
import com.google.firebase.auth.hash.Scrypt;
5250
import com.google.firebase.testing.IntegrationTestUtils;
5351
import java.io.IOException;
@@ -116,7 +114,7 @@ public void testGetNonExistingUserByEmail() throws Exception {
116114
@Test
117115
public void testUpdateNonExistingUser() throws Exception {
118116
try {
119-
auth.updateUserAsync(new UpdateRequest("non.existing")).get();
117+
auth.updateUserAsync(new UserRecord.UpdateRequest("non.existing")).get();
120118
fail("No error thrown for non existing uid");
121119
} catch (ExecutionException e) {
122120
assertTrue(e.getCause() instanceof FirebaseAuthException);
@@ -141,7 +139,7 @@ public void testDeleteNonExistingUser() throws Exception {
141139
public void testCreateUserWithParams() throws Exception {
142140
RandomUser randomUser = RandomUser.create();
143141
String phone = randomPhoneNumber();
144-
CreateRequest user = new CreateRequest()
142+
UserRecord.CreateRequest user = new UserRecord.CreateRequest()
145143
.setUid(randomUser.uid)
146144
.setEmail(randomUser.email)
147145
.setPhoneNumber(phone)
@@ -168,7 +166,7 @@ public void testCreateUserWithParams() throws Exception {
168166
assertTrue(providers.contains("password"));
169167
assertTrue(providers.contains("phone"));
170168

171-
checkRecreate(randomUser.uid);
169+
checkRecreateUser(randomUser.uid);
172170
} finally {
173171
auth.deleteUserAsync(userRecord.getUid()).get();
174172
}
@@ -177,7 +175,7 @@ public void testCreateUserWithParams() throws Exception {
177175
@Test
178176
public void testUserLifecycle() throws Exception {
179177
// Create user
180-
UserRecord userRecord = auth.createUserAsync(new CreateRequest()).get();
178+
UserRecord userRecord = auth.createUserAsync(new UserRecord.CreateRequest()).get();
181179
String uid = userRecord.getUid();
182180

183181
// Get user
@@ -197,7 +195,7 @@ public void testUserLifecycle() throws Exception {
197195
// Update user
198196
RandomUser randomUser = RandomUser.create();
199197
String phone = randomPhoneNumber();
200-
UpdateRequest request = userRecord.updateRequest()
198+
UserRecord.UpdateRequest request = userRecord.updateRequest()
201199
.setDisplayName("Updated Name")
202200
.setEmail(randomUser.email)
203201
.setPhoneNumber(phone)
@@ -240,7 +238,7 @@ public void testUserLifecycle() throws Exception {
240238
auth.deleteUserAsync(userRecord.getUid()).get();
241239
try {
242240
auth.getUserAsync(userRecord.getUid()).get();
243-
fail("No error thrown for deleted user");
241+
fail("No error thrown for getting a deleted user");
244242
} catch (ExecutionException e) {
245243
assertTrue(e.getCause() instanceof FirebaseAuthException);
246244
assertEquals(FirebaseUserManager.USER_NOT_FOUND_ERROR,
@@ -253,9 +251,11 @@ public void testListUsers() throws Exception {
253251
final List<String> uids = new ArrayList<>();
254252

255253
try {
256-
uids.add(auth.createUserAsync(new CreateRequest().setPassword("password")).get().getUid());
257-
uids.add(auth.createUserAsync(new CreateRequest().setPassword("password")).get().getUid());
258-
uids.add(auth.createUserAsync(new CreateRequest().setPassword("password")).get().getUid());
254+
for (int i = 0; i < 3; i++) {
255+
UserRecord.CreateRequest createRequest =
256+
new UserRecord.CreateRequest().setPassword("password");
257+
uids.add(auth.createUserAsync(createRequest).get().getUid());
258+
}
259259

260260
// Test list by batches
261261
final AtomicInteger collected = new AtomicInteger(0);
@@ -320,9 +320,121 @@ public void onSuccess(ListUsersPage result) {
320320
}
321321
}
322322

323+
@Test
324+
public void testTenantLifecycle() throws Exception {
325+
TenantManager tenantManager = auth.getTenantManager();
326+
327+
// Create tenant
328+
Tenant.CreateRequest createRequest = new Tenant.CreateRequest().setDisplayName("DisplayName");
329+
Tenant tenant = tenantManager.createTenantAsync(createRequest).get();
330+
assertEquals("DisplayName", tenant.getDisplayName());
331+
assertFalse(tenant.isPasswordSignInAllowed());
332+
assertFalse(tenant.isEmailLinkSignInEnabled());
333+
String tenantId = tenant.getTenantId();
334+
335+
// Get tenant
336+
tenant = tenantManager.getTenantAsync(tenantId).get();
337+
assertEquals(tenantId, tenant.getTenantId());
338+
assertEquals("DisplayName", tenant.getDisplayName());
339+
assertFalse(tenant.isPasswordSignInAllowed());
340+
assertFalse(tenant.isEmailLinkSignInEnabled());
341+
342+
// Update tenant
343+
Tenant.UpdateRequest updateRequest = tenant.updateRequest()
344+
.setDisplayName("UpdatedName")
345+
.setPasswordSignInAllowed(true)
346+
.setEmailLinkSignInEnabled(true);
347+
tenant = tenantManager.updateTenantAsync(updateRequest).get();
348+
assertEquals(tenantId, tenant.getTenantId());
349+
assertEquals("UpdatedName", tenant.getDisplayName());
350+
assertTrue(tenant.isPasswordSignInAllowed());
351+
assertTrue(tenant.isEmailLinkSignInEnabled());
352+
353+
// Delete tenant
354+
tenantManager.deleteTenantAsync(tenant.getTenantId()).get();
355+
try {
356+
tenantManager.getTenantAsync(tenant.getTenantId()).get();
357+
fail("No error thrown for getting a deleted tenant");
358+
} catch (ExecutionException e) {
359+
assertTrue(e.getCause() instanceof FirebaseAuthException);
360+
assertEquals(FirebaseUserManager.TENANT_NOT_FOUND_ERROR,
361+
((FirebaseAuthException) e.getCause()).getErrorCode());
362+
}
363+
}
364+
365+
@Test
366+
public void testListTenants() throws Exception {
367+
TenantManager tenantManager = auth.getTenantManager();
368+
final List<String> tenantIds = new ArrayList<>();
369+
370+
try {
371+
for (int i = 0; i < 3; i++) {
372+
Tenant.CreateRequest createRequest =
373+
new Tenant.CreateRequest().setDisplayName("DisplayName" + i);
374+
tenantIds.add(tenantManager.createTenantAsync(createRequest).get().getTenantId());
375+
}
376+
377+
// Test list by batches
378+
final AtomicInteger collected = new AtomicInteger(0);
379+
ListTenantsPage page = tenantManager.listTenantsAsync(null).get();
380+
while (page != null) {
381+
for (Tenant tenant : page.getValues()) {
382+
if (tenantIds.contains(tenant.getTenantId())) {
383+
collected.incrementAndGet();
384+
assertNotNull(tenant.getDisplayName());
385+
}
386+
}
387+
page = page.getNextPage();
388+
}
389+
assertEquals(tenantIds.size(), collected.get());
390+
391+
// Test iterate all
392+
collected.set(0);
393+
page = tenantManager.listTenantsAsync(null).get();
394+
for (Tenant tenant : page.iterateAll()) {
395+
if (tenantIds.contains(tenant.getTenantId())) {
396+
collected.incrementAndGet();
397+
assertNotNull(tenant.getDisplayName());
398+
}
399+
}
400+
assertEquals(tenantIds.size(), collected.get());
401+
402+
// Test iterate async
403+
collected.set(0);
404+
final Semaphore semaphore = new Semaphore(0);
405+
final AtomicReference<Throwable> error = new AtomicReference<>();
406+
ApiFuture<ListTenantsPage> pageFuture = tenantManager.listTenantsAsync(null);
407+
ApiFutures.addCallback(pageFuture, new ApiFutureCallback<ListTenantsPage>() {
408+
@Override
409+
public void onFailure(Throwable t) {
410+
error.set(t);
411+
semaphore.release();
412+
}
413+
414+
@Override
415+
public void onSuccess(ListTenantsPage result) {
416+
for (Tenant tenant : result.iterateAll()) {
417+
if (tenantIds.contains(tenant.getTenantId())) {
418+
collected.incrementAndGet();
419+
assertNotNull(tenant.getDisplayName());
420+
}
421+
}
422+
semaphore.release();
423+
}
424+
}, MoreExecutors.directExecutor());
425+
semaphore.acquire();
426+
assertEquals(tenantIds.size(), collected.get());
427+
assertNull(error.get());
428+
} finally {
429+
for (String tenantId : tenantIds) {
430+
tenantManager.deleteTenantAsync(tenantId).get();
431+
}
432+
}
433+
}
434+
323435
@Test
324436
public void testCustomClaims() throws Exception {
325-
UserRecord userRecord = auth.createUserAsync(new CreateRequest()).get();
437+
UserRecord userRecord = auth.createUserAsync(new UserRecord.CreateRequest()).get();
326438
String uid = userRecord.getUid();
327439

328440
try {
@@ -413,7 +525,7 @@ public void testVerifyIdToken() throws Exception {
413525
}
414526
idToken = signInWithCustomToken(customToken);
415527
decoded = auth.verifyIdTokenAsync(idToken, true).get();
416-
assertEquals("user2", decoded.getUid());
528+
assertEquals("user2", decoded.getUid());
417529
auth.deleteUserAsync("user2");
418530
}
419531

@@ -524,7 +636,7 @@ public void testImportUsersWithPassword() throws Exception {
524636
@Test
525637
public void testGeneratePasswordResetLink() throws Exception {
526638
RandomUser user = RandomUser.create();
527-
auth.createUser(new CreateRequest()
639+
auth.createUser(new UserRecord.CreateRequest()
528640
.setUid(user.uid)
529641
.setEmail(user.email)
530642
.setEmailVerified(false)
@@ -549,7 +661,7 @@ public void testGeneratePasswordResetLink() throws Exception {
549661
@Test
550662
public void testGenerateEmailVerificationResetLink() throws Exception {
551663
RandomUser user = RandomUser.create();
552-
auth.createUser(new CreateRequest()
664+
auth.createUser(new UserRecord.CreateRequest()
553665
.setUid(user.uid)
554666
.setEmail(user.email)
555667
.setEmailVerified(false)
@@ -572,7 +684,7 @@ public void testGenerateEmailVerificationResetLink() throws Exception {
572684
@Test
573685
public void testGenerateSignInWithEmailLink() throws Exception {
574686
RandomUser user = RandomUser.create();
575-
auth.createUser(new CreateRequest()
687+
auth.createUser(new UserRecord.CreateRequest()
576688
.setUid(user.uid)
577689
.setEmail(user.email)
578690
.setEmailVerified(false)
@@ -686,9 +798,9 @@ private String signInWithEmailLink(
686798
}
687799
}
688800

689-
private void checkRecreate(String uid) throws Exception {
801+
private void checkRecreateUser(String uid) throws Exception {
690802
try {
691-
auth.createUserAsync(new CreateRequest().setUid(uid)).get();
803+
auth.createUserAsync(new UserRecord.CreateRequest().setUid(uid)).get();
692804
fail("No error thrown for creating user with existing ID");
693805
} catch (ExecutionException e) {
694806
assertTrue(e.getCause() instanceof FirebaseAuthException);

src/test/java/com/google/firebase/auth/FirebaseUserManagerTest.java

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -458,7 +458,7 @@ public void testListTenants() throws Exception {
458458
checkTenant(tenants.get(1), "TENANT_2");
459459
assertEquals("", page.getNextPageToken());
460460
checkRequestHeaders(interceptor);
461-
checkUrl(interceptor, "GET", TENANTS_BASE_URL + ":list");
461+
checkUrl(interceptor, "GET", TENANTS_BASE_URL);
462462
GenericUrl url = interceptor.getResponse().getRequest().getUrl();
463463
assertEquals(999, url.getFirst("pageSize"));
464464
assertNull(url.getFirst("pageToken"));
@@ -477,7 +477,7 @@ public void testListTenantsWithPageToken() throws Exception {
477477
checkTenant(tenants.get(1), "TENANT_2");
478478
assertEquals("", page.getNextPageToken());
479479
checkRequestHeaders(interceptor);
480-
checkUrl(interceptor, "GET", TENANTS_BASE_URL + ":list");
480+
checkUrl(interceptor, "GET", TENANTS_BASE_URL);
481481
GenericUrl url = interceptor.getResponse().getRequest().getUrl();
482482
assertEquals(999, url.getFirst("pageSize"));
483483
assertEquals("token", url.getFirst("pageToken"));
@@ -1469,7 +1469,13 @@ private static void checkRequestHeaders(TestResponseInterceptor interceptor) {
14691469

14701470
private static void checkUrl(TestResponseInterceptor interceptor, String method, String url) {
14711471
HttpRequest request = interceptor.getResponse().getRequest();
1472-
assertEquals(method, request.getRequestMethod());
1472+
if (method.equals("PATCH")) {
1473+
assertEquals("PATCH",
1474+
request.getHeaders().getFirstHeaderStringValue("X-HTTP-Method-Override"));
1475+
assertEquals("POST", request.getRequestMethod());
1476+
} else {
1477+
assertEquals(method, request.getRequestMethod());
1478+
}
14731479
assertEquals(url, request.getUrl().toString().split("\\?")[0]);
14741480
}
14751481

src/test/java/com/google/firebase/auth/TenantTest.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ public class TenantTest {
3434

3535
private static final String TENANT_JSON_STRING =
3636
"{"
37-
+ "\"name\":\"TENANT_ID\","
37+
+ "\"name\":\"projects/project-id/resource/TENANT_ID\","
3838
+ "\"displayName\":\"DISPLAY_NAME\","
3939
+ "\"allowPasswordSignup\":true,"
4040
+ "\"enableEmailLinkSignin\":false"

0 commit comments

Comments
 (0)