Skip to content

Commit

Permalink
passwordless api unit tests completed
Browse files Browse the repository at this point in the history
  • Loading branch information
WaciX committed Sep 11, 2023
1 parent 51f1303 commit 0883ee5
Show file tree
Hide file tree
Showing 2 changed files with 263 additions and 18 deletions.
157 changes: 141 additions & 16 deletions src/test/java/com/bitwarden/passwordless/PasswordlessClientImplTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -133,8 +133,7 @@ void getAliases_validUserId_validResponse() throws IOException, PasswordlessApiE

wireMock.stubFor(get(urlPathEqualTo("/alias/list"))
.withQueryParam("userId", equalTo(DataFactory.USER_ID))
.willReturn(WireMock.ok()
.withResponseBody(wireMockUtils.createJsonBody(aliasListResponse))));
.willReturn(WireMock.ok().withResponseBody(wireMockUtils.createJsonBody(aliasListResponse))));

List<Alias> aliases = passwordlessClient.getAliases(DataFactory.USER_ID);

Expand All @@ -157,7 +156,7 @@ void updateAppsFeature_errorResponse_PasswordlessApiException() throws JsonProce
wireMock.stubFor(post(urlEqualTo("/apps/features"))
.willReturn(wireMockUtils.createProblemDetailsResponse(problemDetails)));

UpdateAppsFeature updateAppsFeature = DataFactory.createUpdateAppsFeature();
UpdateAppsFeature updateAppsFeature = DataFactory.updateAppsFeature();

PasswordlessApiException passwordlessApiException = catchThrowableOfType(
() -> passwordlessClient.updateAppsFeature(updateAppsFeature), PasswordlessApiException.class);
Expand All @@ -173,7 +172,7 @@ void updateAppsFeature_validRequest_noError() throws PasswordlessApiException, I
wireMock.stubFor(post(urlEqualTo("/apps/features"))
.willReturn(WireMock.ok()));

UpdateAppsFeature updateAppsFeature = DataFactory.createUpdateAppsFeature();
UpdateAppsFeature updateAppsFeature = DataFactory.updateAppsFeature();

passwordlessClient.updateAppsFeature(updateAppsFeature);

Expand All @@ -194,7 +193,7 @@ void deleteCredentials_errorResponse_PasswordlessApiException() throws JsonProce
wireMock.stubFor(post(urlEqualTo("/credentials/delete"))
.willReturn(wireMockUtils.createProblemDetailsResponse(problemDetails)));

DeleteCredential deleteCredential = DataFactory.createDeleteCredential();
DeleteCredential deleteCredential = DataFactory.deleteCredential();

PasswordlessApiException passwordlessApiException = catchThrowableOfType(
() -> passwordlessClient.deleteCredential(deleteCredential), PasswordlessApiException.class);
Expand All @@ -210,7 +209,7 @@ void deleteCredentials_validRequest_noError() throws PasswordlessApiException, I
wireMock.stubFor(post(urlEqualTo("/credentials/delete"))
.willReturn(WireMock.ok()));

DeleteCredential deleteCredential = DataFactory.createDeleteCredential();
DeleteCredential deleteCredential = DataFactory.deleteCredential();

passwordlessClient.deleteCredential(deleteCredential);

Expand All @@ -225,11 +224,37 @@ void getCredentials_requestNull_NPE() {
}

@Test
void getCredentials_errorResponse_PasswordlessApiException() {
void getCredentials_errorResponse_PasswordlessApiException() throws JsonProcessingException {
PasswordlessProblemDetails problemDetails = DataFactory.passwordlessProblemDetailsInvalidToken();

wireMock.stubFor(get(urlPathEqualTo("/credentials/list"))
.withQueryParam("userId", equalTo(DataFactory.USER_ID))
.willReturn(wireMockUtils.createProblemDetailsResponse(problemDetails)));

PasswordlessApiException passwordlessApiException = catchThrowableOfType(
() -> passwordlessClient.getCredentials(DataFactory.USER_ID), PasswordlessApiException.class);

assertThat(passwordlessApiException).isNotNull();
assertThat(passwordlessApiException.getDetails()).isEqualTo(problemDetails);

wireMockUtils.verifyGet("/credentials/list", Collections.singletonMap("userId", DataFactory.USER_ID));
}

@Test
void getCredentials_validUserId_validResponse() {
void getCredentials_validUserId_validResponse() throws IOException, PasswordlessApiException {
Credential credential1 = DataFactory.credential1();
Credential credential2 = DataFactory.credential2();
ListResponse<Credential> credentialListResponse = new ListResponse<>(Arrays.asList(credential1, credential2));

wireMock.stubFor(get(urlPathEqualTo("/credentials/list"))
.withQueryParam("userId", equalTo(DataFactory.USER_ID))
.willReturn(WireMock.ok().withResponseBody(wireMockUtils.createJsonBody(credentialListResponse))));

List<Credential> credentials = passwordlessClient.getCredentials(DataFactory.USER_ID);

assertThat(credentials).containsExactlyInAnyOrder(credential1, credential2);

wireMockUtils.verifyGet("/credentials/list", Collections.singletonMap("userId", DataFactory.USER_ID));
}

@Test
Expand All @@ -240,11 +265,37 @@ void registerToken_requestNull_NPE() {
}

@Test
void registerToken_errorResponse_PasswordlessApiException() {
void registerToken_errorResponse_PasswordlessApiException() throws JsonProcessingException {
PasswordlessProblemDetails problemDetails = DataFactory.passwordlessProblemDetailsInvalidToken();

wireMock.stubFor(post(urlEqualTo("/register/token"))
.willReturn(wireMockUtils.createProblemDetailsResponse(problemDetails)));

RegisterToken registerToken = DataFactory.registerToken();

PasswordlessApiException passwordlessApiException = catchThrowableOfType(
() -> passwordlessClient.registerToken(registerToken), PasswordlessApiException.class);

assertThat(passwordlessApiException).isNotNull();
assertThat(passwordlessApiException.getDetails()).isEqualTo(problemDetails);

wireMockUtils.verifyPost("/register/token", registerToken);
}

@Test
void registerToken_validRequest_validResponse() {
void registerToken_validRequest_validResponse() throws PasswordlessApiException, IOException {
RegisteredToken expectedRegisteredToken = DataFactory.registeredToken();

wireMock.stubFor(post(urlEqualTo("/register/token"))
.willReturn(WireMock.ok().withResponseBody(wireMockUtils.createJsonBody(expectedRegisteredToken))));

RegisterToken registerToken = DataFactory.registerToken();

RegisteredToken registeredToken = passwordlessClient.registerToken(registerToken);

assertThat(registeredToken).isEqualTo(expectedRegisteredToken);

wireMockUtils.verifyPost("/register/token", registerToken);
}

@Test
Expand All @@ -255,19 +306,71 @@ void signIn_requestNull_NPE() {
}

@Test
void signIn_errorResponse_PasswordlessApiException() {
void signIn_errorResponse_PasswordlessApiException() throws JsonProcessingException {
PasswordlessProblemDetails problemDetails = DataFactory.passwordlessProblemDetailsInvalidToken();

wireMock.stubFor(post(urlEqualTo("/signin/verify"))
.willReturn(wireMockUtils.createProblemDetailsResponse(problemDetails)));

VerifySignIn verifySignIn = DataFactory.verifySignIn();

PasswordlessApiException passwordlessApiException = catchThrowableOfType(
() -> passwordlessClient.signIn(verifySignIn), PasswordlessApiException.class);

assertThat(passwordlessApiException).isNotNull();
assertThat(passwordlessApiException.getDetails()).isEqualTo(problemDetails);

wireMockUtils.verifyPost("/signin/verify", verifySignIn);
}

@Test
void signIn_validRequest_validResponse() {
void signIn_validRequest_validResponse() throws IOException, PasswordlessApiException {
VerifiedUser expectedVerifiedUser = DataFactory.verifiedUser();

wireMock.stubFor(post(urlEqualTo("/signin/verify"))
.willReturn(WireMock.ok().withResponseBody(wireMockUtils.createJsonBody(expectedVerifiedUser))));

VerifySignIn verifySignIn = DataFactory.verifySignIn();

VerifiedUser verifiedUser = passwordlessClient.signIn(verifySignIn);

assertThat(verifiedUser).isEqualTo(expectedVerifiedUser);

wireMockUtils.verifyPost("/signin/verify", verifySignIn);
}

@Test
void getUsers_errorResponse_PasswordlessApiException() {
void getUsers_errorResponse_PasswordlessApiException() throws JsonProcessingException {
PasswordlessProblemDetails problemDetails = DataFactory.passwordlessProblemDetailsInvalidToken();

wireMock.stubFor(get(urlPathEqualTo("/users/list"))
.willReturn(wireMockUtils.createProblemDetailsResponse(problemDetails)));

PasswordlessApiException passwordlessApiException = catchThrowableOfType(
() -> passwordlessClient.getUsers(), PasswordlessApiException.class);

assertThat(passwordlessApiException).isNotNull();
assertThat(passwordlessApiException.getDetails()).isEqualTo(problemDetails);

wireMockUtils.verifyGet("/users/list", null);
}

@Test
void getUsers_valid_validResponse() {
void getUsers_valid_validResponse() throws PasswordlessApiException, IOException {
UserSummary userSummary1 = DataFactory.userSummary1();
UserSummary userSummary2 = DataFactory.userSummary2();
UserSummary userSummary3 = DataFactory.userSummary3();
ListResponse<UserSummary> userSummaryListResponse = new ListResponse<>(Arrays.asList(userSummary1, userSummary2,
userSummary3));

wireMock.stubFor(get(urlPathEqualTo("/users/list"))
.willReturn(WireMock.ok().withResponseBody(wireMockUtils.createJsonBody(userSummaryListResponse))));

List<UserSummary> users = passwordlessClient.getUsers();

assertThat(users).containsExactlyInAnyOrder(userSummary1, userSummary2, userSummary3);

wireMockUtils.verifyGet("/users/list", null);
}

@Test
Expand All @@ -278,11 +381,33 @@ void deleteUser_requestNull_NPE() {
}

@Test
void deleteUser_errorResponse_PasswordlessApiException() {
void deleteUser_errorResponse_PasswordlessApiException() throws JsonProcessingException {
PasswordlessProblemDetails problemDetails = DataFactory.passwordlessProblemDetailsInvalidToken();

wireMock.stubFor(post(urlEqualTo("/users/delete"))
.willReturn(wireMockUtils.createProblemDetailsResponse(problemDetails)));

DeleteUser deleteUser = DataFactory.deleteUser();

PasswordlessApiException passwordlessApiException = catchThrowableOfType(
() -> passwordlessClient.deleteUser(deleteUser), PasswordlessApiException.class);

assertThat(passwordlessApiException).isNotNull();
assertThat(passwordlessApiException.getDetails()).isEqualTo(problemDetails);

wireMockUtils.verifyPost("/users/delete", deleteUser);
}

@Test
void deleteUser_validRequest_validResponse() {
void deleteUser_validRequest_validResponse() throws PasswordlessApiException, IOException {
wireMock.stubFor(post(urlEqualTo("/users/delete"))
.willReturn(WireMock.ok()));

DeleteUser deleteUser = DataFactory.deleteUser();

passwordlessClient.deleteUser(deleteUser);

wireMockUtils.verifyPost("/users/delete", deleteUser);
}

@Test
Expand Down
124 changes: 122 additions & 2 deletions src/test/java/com/bitwarden/passwordless/factory/DataFactory.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,10 @@
import com.bitwarden.passwordless.model.*;
import lombok.experimental.UtilityClass;

import java.time.Instant;
import java.time.LocalDateTime;
import java.util.Arrays;
import java.util.Collections;

@UtilityClass
public class DataFactory {
Expand Down Expand Up @@ -67,15 +70,132 @@ public Alias alias2() {
.build();
}

public UpdateAppsFeature createUpdateAppsFeature() {
public UpdateAppsFeature updateAppsFeature() {
return UpdateAppsFeature.builder()
.auditLoggingRetentionPeriod(12)
.build();
}

public DeleteCredential createDeleteCredential() {
public DeleteCredential deleteCredential() {
return DeleteCredential.builder()
.credentialId("ZtmCjN6tOMM5X_KxfYApAHI-5n6C4KRy9YMeMqfNjj8")
.build();
}

public Credential credential1() {
return Credential.builder()
.userId(USER_ID)
.descriptor(Credential.PublicKeyCredentialDescriptor.builder()
.type("public-key")
.id("ZtmCjN6tOMM5X_KxfYApAHI-5n6C4KRy9YMeMqfNjj8")
.build())
.publicKey("pQECAyYgASFYIOsfC6kHh3pBohSGE6WwwGo8rJYG2lgmSbBfgtIq1gJzIlggr/6DYuFeATzcucHJ2ejCF2qWH7Z43yK4z/UYAV9YrY4=")
.userHandle("ZWI0ZGVlMDctMmQwNS00MDRlLTgwZWQtMGY2NWQwYzRlMzBl")
.signatureCounter(2)
.attestationFmt("none")
.createdAt(LocalDateTime.parse("2023-09-09T20:05:03.6059728"))
.aaGuid("00000000-0000-0000-0000-000000000000")
.lastUsedAt(LocalDateTime.parse("2023-09-09T20:09:59.6593325"))
.origin("http://localhost:8080")
.country("PL")
.device("Chrome, Mac OS X 10")
.build();
}

public Credential credential2() {
return Credential.builder()
.userId(USER_ID)
.descriptor(Credential.PublicKeyCredentialDescriptor.builder()
.type("public-key")
.id("CYdwzAHqmUr85Dpei2kbWHs9xsBp1clzbG09VUcfnS0")
.build())
.publicKey("pQECAyYgASFYIHSn0S/oH/sgZx12v37duci9gDkg0bB4f25h8p+6ecq2Ilgg2RadGaGqyJpNtm9ETrg+Uinf5n8SdPZN0oibSWb6TDc=")
.userHandle("ODU5YTIyZTAtYmVmYS00ZWY0LWFjNDktNTRlZDkwYzFkZWIy")
.signatureCounter(1)
.attestationFmt("none")
.createdAt(LocalDateTime.parse("2023-09-09T21:18:00.1309909"))
.aaGuid("00000000-0000-0000-0000-000000000000")
.lastUsedAt(LocalDateTime.parse("2023-09-09T21:32:50.2848782"))
.origin("http://localhost:8080")
.country("PL")
.device("Chrome, Mac OS X 10")
.build();
}

public RegisterToken registerToken() {
return RegisterToken.builder()
.userId(USER_ID)
.username("TestUser")
.attestation("none")
.authenticatorType("any")
.discoverable(true)
.userVerification("preferred")
.aliases(Collections.emptyList())
.aliasHashing(true)
.expiresAt(Instant.parse("2023-09-09T20:07:02.365573Z"))
.build();
}

public RegisteredToken registeredToken() {
return RegisteredToken.builder()
.token("register_k8QgFOUhu_arMUbfi_93OZFdc6M39tPdmmNbx5xFZlMUS_TEgdwAE9f_VyjOIGT80GbZJDAwMDAwMDAwLTAwMDAtMDAwMC0wMDAwLTAwMDAwMDAwMDAwMMDAwMDAwMDA2SRlYjRkZWUwNy0yZDA1LTQwNGUtODBlZC0wZjY1ZDBjNGUzMGXAqFRlc3RVc2VypG5vbmWjYW55w6lwcmVmZXJyZWSQw84VNwZS")
.build();
}

public VerifySignIn verifySignIn() {
return VerifySignIn.builder()
.token("verify_k8QgiPlgfMVr34FyFipBrkj6jBwKT9QifsFx-DSa1L3Yp_PE1NwAE9f_ppPH0GT80Y_ZJDBlZGQ2NWJjLTliOGQtNGIxYS1iMjA4LTIxYzZjOGYxYWQ5NK5wYXNza2V5X3NpZ25pbsDAwMDAwMDZJGViNGRlZTA3LTJkMDUtNDA0ZS04MGVkLTBmNjVkMGM0ZTMwZdf_ppOx8GT80RepbG9jYWxob3N0tWh0dHA6Ly9sb2NhbGhvc3Q6ODA4MMOzQ2hyb21lLCBNYWMgT1MgWCAxMKJQTMDEIGbZgozerTjDOV_ysX2AKQByPuZ-guCkcvWDHjKnzY4_zhU3BlI")
.build();
}

public VerifiedUser verifiedUser() {
return VerifiedUser.builder()
.success(true)
.userId(USER_ID)
.timestamp(Instant.parse("2023-09-09T20:09:59.698674300Z"))
.origin("http://localhost:8080")
.device("Chrome, Mac OS X 10")
.country("PL")
.credentialId("ZtmCjN6tOMM5X/KxfYApAHI+5n6C4KRy9YMeMqfNjj8=")
.expiresAt(Instant.parse("2023-09-09T20:11:59.698675700Z"))
.tokenId("0edd65bc-9b8d-4b1a-b208-21c6c8f1ad94")
.type("passkey_signin")
.build();
}

public UserSummary userSummary1() {
return UserSummary.builder()
.userId(USER_ID)
.aliasCount(2)
.aliases(Arrays.asList(null, null))
.credentialsCount(1)
.lastUsedAt(LocalDateTime.parse("2023-09-09T20:09:59.6593325"))
.build();
}

public UserSummary userSummary2() {
return UserSummary.builder()
.userId("859a22e0-befa-4ef4-ac49-54ed90c1deb2")
.aliasCount(1)
.aliases(Collections.singletonList("TestUser2"))
.credentialsCount(1)
.lastUsedAt(LocalDateTime.parse("2023-09-09T21:09:59.6593325"))
.build();
}

public UserSummary userSummary3() {
return UserSummary.builder()
.userId("859a22e0-befa-4ef4-ac49-54ed90c1deb2")
.aliasCount(0)
.aliases(null)
.credentialsCount(0)
.lastUsedAt(LocalDateTime.parse("2023-09-09T22:09:59.6593325"))
.build();
}

public DeleteUser deleteUser() {
return DeleteUser.builder()
.userId(USER_ID)
.build();
}
}

0 comments on commit 0883ee5

Please sign in to comment.