Skip to content

Commit

Permalink
Add integration tests reworked
Browse files Browse the repository at this point in the history
Need to finish testing some service-level spring beans + some integration tests
  • Loading branch information
Daniel Villavicencio authored and Daniel Villavicencio committed Feb 10, 2024
1 parent 3248795 commit f4bd3fe
Show file tree
Hide file tree
Showing 22 changed files with 424 additions and 518 deletions.
2 changes: 0 additions & 2 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,6 @@ ext {
set('flywayTestVersion', '10.0.0')
set('tcPostgresVersion', '1.19.4')
set('tcJdbcVersion', '1.19.4')
set('tcR2dbcVersion', '1.19.4')
set('testContainersVersion', '1.19.2')
set('tcJunitVersion', '1.19.3')
set('junitJupiterParamsVersion', '5.10.1')
Expand Down Expand Up @@ -79,7 +78,6 @@ dependencies {
testImplementation 'org.springframework.restdocs:spring-restdocs-mockmvc'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
testImplementation "org.testcontainers:jdbc:${tcJdbcVersion}"
testImplementation "org.testcontainers:r2dbc:${tcR2dbcVersion}"
testImplementation "org.testcontainers:postgresql:${tcPostgresVersion}"
testImplementation "org.testcontainers:junit-jupiter:${tcJunitVersion}"
testImplementation "io.projectreactor:reactor-test:${reactorTestVersion}"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,5 @@ public interface OAuth2Configuration {

String getCallbackUrl();

String getTokenUrl();

String getAuthorizationUrl();
}
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ public ResponseEntity<?> handleCallBackFromDiscord(
public ResponseEntity<?> handleCallBackFromBungie(
@RequestParam(OAuth2Params.CODE) String authorizationCode,
HttpSession httpSession) {
userRegistrationService.saveUserDetails(authorizationCode, httpSession);
userRegistrationService.authenticateBungieUser(authorizationCode, httpSession);
return ResponseEntity.noContent().build();
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,12 @@
import com.danielvm.destiny2bot.dto.destiny.membership.MembershipResponse;
import com.danielvm.destiny2bot.enums.ManifestEntity;
import com.danielvm.destiny2bot.exception.ExternalServiceException;
import com.danielvm.destiny2bot.exception.InternalServerException;
import com.danielvm.destiny2bot.exception.ResourceNotFoundException;
import com.danielvm.destiny2bot.util.MembershipUtil;
import com.danielvm.destiny2bot.util.OAuth2Util;
import java.util.Objects;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Service;
import org.springframework.util.Assert;
import reactor.core.publisher.Mono;
Expand Down Expand Up @@ -66,8 +64,8 @@ public Mono<MembershipResponse> getUserMembershipInformation(String bearerToken)
return reactiveBungieClient.getMembershipInfoForCurrentUser(bearerToken)
.filter(Objects::nonNull)
.filter(membership ->
Objects.nonNull(MembershipUtil.extractMembershipType(membership))
&& Objects.nonNull(MembershipUtil.extractMembershipId(membership)))
MembershipUtil.extractMembershipType(membership) != null
&& MembershipUtil.extractMembershipId(membership) != null)
.switchIfEmpty(Mono.error(
new ResourceNotFoundException("Membership information for the user [%s] is invalid")));
}
Expand All @@ -84,13 +82,11 @@ public ManifestFields getManifestEntity(
ManifestEntity entityType, Long hashIdentifier) {
var response = imperativeBungieClient.getManifestEntity(entityType.getId(), hashIdentifier)
.getBody();
if (Objects.isNull(response) || Objects.isNull(response.getResponse()) || Objects.isNull(
response.getResponse().getDisplayProperties()) || Objects.isNull(
response.getResponse().getDisplayProperties().getName())) {
if (Objects.isNull(response) || Objects.isNull(response.getResponse())) {
String errorMessage = "The manifest entity for activity of type [%s] with hash [%s] returned a null for a required field"
.formatted(entityType, hashIdentifier);
log.error(errorMessage);
throw new InternalServerException(errorMessage, HttpStatus.INTERNAL_SERVER_ERROR);
throw new ExternalServiceException(errorMessage);
}
return response.getResponse();
}
Expand All @@ -106,7 +102,7 @@ public PostGameCarnageReport getPGCR(String accessToken, Long activityInstance)
BungieResponse<PostGameCarnageReport> report = pgcrBungieClient.getPostCarnageReport(
OAuth2Util.formatBearerToken(accessToken), activityInstance
).getBody();
if (Objects.isNull(report) || Objects.isNull(report.getResponse())) {
if (report == null || report.getResponse() == null) {
String errorMessage = "A PGCR for a given raid did not include some required details. Raid instance [%s]"
.formatted(activityInstance);
log.error(errorMessage);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,10 @@ private void indexCharacters(BotUser user, UserIndexing currentUserInfo,
notLastPage = indexCharacter(user, character, pageNumber++, characterIndexing);
} catch (Throwable throwable) {
notLastPage = false;
String characterDescription =
character.getDestinyClass() + " - " + character.getLightLevel();
log.error("Something wrong happened when indexing character [{}] for user [{}]",
characterDescription, user.getDiscordUsername(), throwable);
discordStatusMessageService.updateStatusMessage(character, IndexingStatus.ERROR);
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@
import com.danielvm.destiny2bot.util.MembershipUtil;
import com.danielvm.destiny2bot.util.OAuth2Util;
import jakarta.servlet.http.HttpSession;
import java.util.Objects;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
Expand Down Expand Up @@ -47,18 +46,30 @@ public UserRegistrationService(
}

private static TokenResponse verifyTokenParameters(ResponseEntity<TokenResponse> tokenResponse) {
if (Objects.isNull(tokenResponse) || Objects.isNull(tokenResponse.getBody()) ||
Objects.isNull(tokenResponse.getBody().getAccessToken()) ||
Objects.isNull(tokenResponse.getBody().getRefreshToken()) ||
Objects.isNull(tokenResponse.getBody().getExpiresIn())) {
if (tokenResponse == null || tokenResponse.getBody() == null ||
tokenResponse.getBody().getAccessToken() == null ||
tokenResponse.getBody().getRefreshToken() == null ||
tokenResponse.getBody().getExpiresIn() == null) {
log.error("Token response parameters are null from Discord");
throw new InternalServerException(
"Token response parameters from Discord were returned as null",
"Required Token response parameters from Discord are not present",
HttpStatus.BAD_GATEWAY);
}
return tokenResponse.getBody();
}

private static DiscordUserResponse verifyUserDetails(
ResponseEntity<DiscordUserResponse> userDetails) {
if (userDetails == null || userDetails.getBody() == null ||
userDetails.getBody().getUsername() == null || userDetails.getBody().getId() == null) {
log.error("Required parameters for a Discord user are null or something went wrong");
throw new InternalServerException(
"Required parameters for a Discord user are not valid or not present",
HttpStatus.BAD_GATEWAY);
}
return userDetails.getBody();
}

/**
* Retrieve DiscordUserId from authenticated user and save it to Session
*
Expand All @@ -73,22 +84,12 @@ public void authenticateDiscordUser(String authorizationCode, HttpSession sessio
TokenResponse tokenResponse = verifyTokenParameters(discordClient.getAccessToken(
tokenExchangeParameters));

String bearerToken = tokenResponse.getAccessToken();
String bearerToken = OAuth2Util.formatBearerToken(tokenResponse.getAccessToken());

ResponseEntity<DiscordUserResponse> userDetails = discordClient.getUser(
OAuth2Util.formatBearerToken(bearerToken));

if (Objects.isNull(userDetails) || Objects.isNull(userDetails.getBody()) ||
Objects.isNull(userDetails.getBody().getUsername()) ||
Objects.isNull(userDetails.getBody().getId())) {
log.error("Required parameters for a Discord user are null or something went wrong");
throw new InternalServerException(
"Required parameters for a Discord user are not valid or not present",
HttpStatus.BAD_GATEWAY);
}
DiscordUserResponse userDetails = verifyUserDetails(discordClient.getUser(bearerToken));

session.setAttribute(DISCORD_USER_ID_KEY, userDetails.getBody().getId());
session.setAttribute(DISCORD_USER_ALIAS_KEY, userDetails.getBody().getUsername());
session.setAttribute(DISCORD_USER_ID_KEY, userDetails.getId());
session.setAttribute(DISCORD_USER_ALIAS_KEY, userDetails.getUsername());
}

/**
Expand All @@ -104,7 +105,7 @@ public void authenticateDiscordUser(String authorizationCode, HttpSession sessio
* @param httpSession The HttpSession the user is linked to
*/
@Async
public void saveUserDetails(String authorizationCode, HttpSession httpSession) {
public void authenticateBungieUser(String authorizationCode, HttpSession httpSession) {
MultiValueMap<String, String> tokenExchangeParameters = OAuth2Util.buildTokenExchangeParameters(
authorizationCode, bungieConfiguration.getCallbackUrl(),
bungieConfiguration.getClientSecret(), bungieConfiguration.getClientId()
Expand Down
4 changes: 2 additions & 2 deletions src/main/java/com/danielvm/destiny2bot/util/OAuth2Util.java
Original file line number Diff line number Diff line change
Expand Up @@ -67,8 +67,8 @@ public static MultiValueMap<String, String> buildRefreshTokenExchangeParameters(
/**
* Return the qualified url with all parameters
*
* @param bungieConfiguration The config class containing all necessary information to build the
* authorization URI
* @param authUrl The authorization url
* @param clientId The bungie clientId
* @return The authorization url with all required parameters
*/
public static String bungieAuthorizationUrl(String authUrl, String clientId) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,9 @@
import org.mockito.Mockito;
import org.springframework.core.io.Resource;

public class TestUtils {
public class ResourceUtils {

private TestUtils() {
private ResourceUtils() {
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
import static com.danielvm.destiny2bot.enums.InteractionResponseType.CHANNEL_MESSAGE_WITH_SOURCE;
import static org.assertj.core.api.Assertions.assertThat;

import com.danielvm.destiny2bot.TestUtils;
import com.danielvm.destiny2bot.ResourceUtils;
import com.danielvm.destiny2bot.dto.discord.Attachment;
import com.danielvm.destiny2bot.dto.discord.Choice;
import com.danielvm.destiny2bot.dto.discord.Embedded;
Expand Down Expand Up @@ -89,8 +89,8 @@ public void creatingApplicationCommandResponseWorksCorrectly() throws IOExceptio
.build();

Map<Long, Resource> resourcesMap = Map.of(
1L, TestUtils.createResourceWithName("kalli-action-phase.jpg"),
2L, TestUtils.createResourceWithName("kalli-dps-phase.jpg")
1L, ResourceUtils.createResourceWithName("kalli-action-phase.jpg"),
2L, ResourceUtils.createResourceWithName("kalli-dps-phase.jpg")
);

String raidName = "Last Wish";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
import com.danielvm.destiny2bot.dto.discord.Interaction;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import io.r2dbc.spi.ConnectionFactoryOptions;
import java.nio.charset.StandardCharsets;
import java.security.KeyPair;
import java.security.PublicKey;
Expand All @@ -17,6 +16,7 @@
import org.mockito.junit.jupiter.MockitoExtension;
import org.skyscreamer.jsonassert.JSONAssert;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.web.server.LocalServerPort;
import org.springframework.cloud.contract.wiremock.AutoConfigureWireMock;
Expand All @@ -25,17 +25,18 @@
import org.springframework.test.context.DynamicPropertySource;
import org.springframework.test.web.reactive.server.WebTestClient;
import org.springframework.test.web.reactive.server.WebTestClient.ResponseSpec;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.web.reactive.function.BodyInserters;
import org.testcontainers.containers.GenericContainer;
import org.testcontainers.containers.PostgreSQLContainer;
import org.testcontainers.containers.PostgreSQLR2DBCDatabaseContainer;
import org.testcontainers.junit.jupiter.Container;
import org.testcontainers.junit.jupiter.Testcontainers;
import software.pando.crypto.nacl.Crypto;

@ExtendWith(MockitoExtension.class)
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
@AutoConfigureWireMock(files = "/build/resources/test/__files")
@AutoConfigureMockMvc
@Testcontainers
public abstract class BaseIntegrationTest {

Expand All @@ -56,6 +57,9 @@ public abstract class BaseIntegrationTest {
@LocalServerPort
protected int localServerPort;

@Autowired
MockMvc mockMvc;

@Autowired
WebTestClient webTestClient;

Expand Down
Loading

0 comments on commit f4bd3fe

Please sign in to comment.