aboutsummaryrefslogtreecommitdiffstats
path: root/app/src/test/java
diff options
context:
space:
mode:
Diffstat (limited to 'app/src/test/java')
-rw-r--r--app/src/test/java/org/onap/portal/history/BaseIntegrationTest.java180
-rw-r--r--app/src/test/java/org/onap/portal/history/TokenGenerator.java129
-rw-r--r--app/src/test/java/org/onap/portal/history/actions/ActionDto.java39
-rw-r--r--app/src/test/java/org/onap/portal/history/actions/ActionFixtures.java126
-rw-r--r--app/src/test/java/org/onap/portal/history/actions/ActionsControllerIntegrationTest.java571
5 files changed, 1045 insertions, 0 deletions
diff --git a/app/src/test/java/org/onap/portal/history/BaseIntegrationTest.java b/app/src/test/java/org/onap/portal/history/BaseIntegrationTest.java
new file mode 100644
index 0000000..e00b770
--- /dev/null
+++ b/app/src/test/java/org/onap/portal/history/BaseIntegrationTest.java
@@ -0,0 +1,180 @@
+/*
+ *
+ * Copyright (c) 2022. Deutsche Telekom AG
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ *
+ */
+
+package org.onap.portal.history;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.github.tomakehurst.wiremock.client.WireMock;
+import com.nimbusds.jose.jwk.JWKSet;
+import org.onap.portal.history.util.IdTokenExchange;
+import io.restassured.RestAssured;
+import io.restassured.filter.log.RequestLoggingFilter;
+import io.restassured.filter.log.ResponseLoggingFilter;
+import io.restassured.specification.RequestSpecification;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.BeforeEach;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.boot.web.server.LocalServerPort;
+import org.springframework.cloud.contract.wiremock.AutoConfigureWireMock;
+import org.springframework.http.MediaType;
+
+import java.util.List;
+import java.util.UUID;
+
+/** Base class for all tests that has the common config including port, realm, logging and auth. */
+@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
+@AutoConfigureWireMock(port = 0)
+public abstract class BaseIntegrationTest {
+
+// @TestConfiguration
+// public static class Config {
+// @Bean
+// WireMockConfigurationCustomizer optionsCustomizer() {
+// return options -> options.extensions(new ResponseTemplateTransformer(true));
+// }
+// }
+
+ @LocalServerPort protected int port;
+ @Value("${portal-history.realm}")
+ protected String realm;
+
+ @Value("${portal-history.delete-interval}")
+ protected String deleteInterval;
+
+ @Autowired protected ObjectMapper objectMapper;
+ @Autowired private TokenGenerator tokenGenerator;
+
+ @BeforeAll
+ public static void setup() {
+ RestAssured.filters(new RequestLoggingFilter(), new ResponseLoggingFilter());
+ }
+
+ /** Mocks the OIDC auth flow. */
+ @BeforeEach
+ public void mockAuth() {
+ WireMock.reset();
+
+ WireMock.stubFor(
+ WireMock.get(
+ WireMock.urlMatching(
+ String.format("/auth/realms/%s/protocol/openid-connect/certs", realm)))
+ .willReturn(
+ WireMock.aResponse()
+ .withHeader("Content-Type", JWKSet.MIME_TYPE)
+ .withBody(tokenGenerator.getJwkSet().toString())));
+
+ final TokenGenerator.TokenGeneratorConfig config =
+ TokenGenerator.TokenGeneratorConfig.builder().port(port).realm(realm).sub("test-user").build();
+
+ WireMock.stubFor(
+ WireMock.post(
+ WireMock.urlMatching(
+ String.format("/auth/realms/%s/protocol/openid-connect/token", realm)))
+ .withBasicAuth("test", "test")
+ .withRequestBody(WireMock.containing("grant_type=client_credentials"))
+ .willReturn(
+ WireMock.aResponse()
+ .withHeader("Content-Type", MediaType.APPLICATION_JSON_VALUE)
+ .withBody(
+ objectMapper
+ .createObjectNode()
+ .put("token_type", "bearer")
+ .put("access_token", tokenGenerator.generateToken(config))
+ .put("expires_in", config.getExpireIn().getSeconds())
+ .put("refresh_token", tokenGenerator.generateToken(config))
+ .put("refresh_expires_in", config.getExpireIn().getSeconds())
+ .put("not-before-policy", 0)
+ .put("session_state", UUID.randomUUID().toString())
+ .put("scope", "email profile")
+ .toString())));
+ }
+
+ /**
+ * Builds an OAuth2 configuration including the roles, port and realm. This config can be used to
+ * generate OAuth2 access tokens.
+ *
+ * @param sub the userId
+ * @param roles the roles used for RBAC
+ * @return the OAuth2 configuration
+ */
+ protected TokenGenerator.TokenGeneratorConfig getTokenGeneratorConfig(String sub, List<String> roles) {
+ return TokenGenerator.TokenGeneratorConfig.builder()
+ .port(port)
+ .sub(sub)
+ .realm(realm)
+ .roles(roles)
+ .build();
+ }
+
+ /** Get a RequestSpecification that does not have an Identity header. */
+ protected RequestSpecification unauthenticatedRequestSpecification() {
+ return RestAssured.given().port(port);
+ }
+
+ /**
+ * Object to store common attributes of requests that are going to be made. Adds an Identity
+ * header for the <code>onap_admin</code> role to the request.
+ * @return the definition of the incoming request (northbound)
+ */
+ protected RequestSpecification requestSpecification() {
+ final String idToken = tokenGenerator.generateToken(getTokenGeneratorConfig("test-user", List.of("foo")));
+
+ return unauthenticatedRequestSpecification()
+ .auth()
+ .preemptive()
+ .oauth2(idToken)
+ .header(IdTokenExchange.X_AUTH_IDENTITY_HEADER, "Bearer " + idToken);
+ }
+
+ /**
+ * Object to store common attributes of requests that are going to be made. Adds an Identity
+ * header for the <code>onap_admin</code> role to the request.
+ * @param userId the userId that should be contained in the incoming request
+ * @return the definition of the incoming request (northbound)
+ */
+ protected RequestSpecification requestSpecification(String userId) {
+ final String idToken = tokenGenerator.generateToken(getTokenGeneratorConfig(userId, List.of("foo")));
+
+ return unauthenticatedRequestSpecification()
+ .auth()
+ .preemptive()
+ .oauth2(idToken)
+ .header(IdTokenExchange.X_AUTH_IDENTITY_HEADER, "Bearer " + idToken);
+ }
+
+ /**
+ * Object to store common attributes of requests that are going to be made. Adds an Identity
+ * header for the <code>onap_admin</code> role to the request.
+ * @param userId the userId that should be contained in the incoming request
+ * @return the definition of the incoming request (northbound)
+ */
+ protected RequestSpecification wrongHeaderRequestSpecification(String userId) {
+ final String idToken = tokenGenerator.generateToken(getTokenGeneratorConfig(userId, List.of("foo")));
+
+ return unauthenticatedRequestSpecification()
+ .auth()
+ .preemptive()
+ .oauth2(idToken)
+ .header("X-WRONG-HEADER", "Bearer " + idToken);
+ }
+}
diff --git a/app/src/test/java/org/onap/portal/history/TokenGenerator.java b/app/src/test/java/org/onap/portal/history/TokenGenerator.java
new file mode 100644
index 0000000..986507c
--- /dev/null
+++ b/app/src/test/java/org/onap/portal/history/TokenGenerator.java
@@ -0,0 +1,129 @@
+/*
+ *
+ * Copyright (c) 2022. Deutsche Telekom AG
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ *
+ */
+
+package org.onap.portal.history;
+
+import com.nimbusds.jose.JOSEObjectType;
+import com.nimbusds.jose.JWSAlgorithm;
+import com.nimbusds.jose.JWSHeader;
+import com.nimbusds.jose.JWSSigner;
+import com.nimbusds.jose.crypto.RSASSASigner;
+import com.nimbusds.jose.jwk.JWKSet;
+import com.nimbusds.jose.jwk.KeyUse;
+import com.nimbusds.jose.jwk.RSAKey;
+import com.nimbusds.jose.jwk.gen.RSAKeyGenerator;
+import com.nimbusds.jwt.JWTClaimsSet;
+import com.nimbusds.jwt.SignedJWT;
+import lombok.Builder;
+import lombok.Getter;
+import lombok.NonNull;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+import java.time.Clock;
+import java.time.Duration;
+import java.time.Instant;
+import java.util.Collections;
+import java.util.Date;
+import java.util.List;
+import java.util.UUID;
+
+@Component
+public class TokenGenerator {
+
+ private static final String ROLES_CLAIM = "roles";
+ private static final String USERID_CLAIM = "sub";
+
+ private final Clock clock;
+ private final RSAKey jwk;
+ private final JWKSet jwkSet;
+ private final JWSSigner signer;
+
+ @Autowired
+ public TokenGenerator(Clock clock) {
+ try {
+ this.clock = clock;
+ jwk =
+ new RSAKeyGenerator(2048)
+ .keyUse(KeyUse.SIGNATURE)
+ .keyID(UUID.randomUUID().toString())
+ .generate();
+ jwkSet = new JWKSet(jwk);
+ signer = new RSASSASigner(jwk);
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ public JWKSet getJwkSet() {
+ return jwkSet;
+ }
+
+ public String generateToken(TokenGeneratorConfig config) {
+ final Instant iat = clock.instant();
+ final Instant exp = iat.plus(config.expireIn);
+
+ final JWTClaimsSet claims =
+ new JWTClaimsSet.Builder()
+ .jwtID(UUID.randomUUID().toString())
+ .subject(UUID.randomUUID().toString())
+ .issuer(config.issuer())
+ .issueTime(Date.from(iat))
+ .expirationTime(Date.from(exp))
+ .claim(ROLES_CLAIM, config.getRoles())
+ .claim(USERID_CLAIM, config.getSub())
+ .build();
+
+ final SignedJWT jwt =
+ new SignedJWT(
+ new JWSHeader.Builder(JWSAlgorithm.RS256)
+ .keyID(jwk.getKeyID())
+ .type(JOSEObjectType.JWT)
+ .build(),
+ claims);
+
+ try {
+ jwt.sign(signer);
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+
+ return jwt.serialize();
+ }
+
+ @Getter
+ @Builder
+ public static class TokenGeneratorConfig {
+ private final int port;
+
+ @NonNull private final String sub;
+
+ @NonNull private final String realm;
+
+ @NonNull @Builder.Default private final Duration expireIn = Duration.ofMinutes(5);
+
+ @Builder.Default private final List<String> roles = Collections.emptyList();
+
+ public String issuer() {
+ return String.format("http://localhost:%d/auth/realms/%s", port, realm);
+ }
+ }
+}
diff --git a/app/src/test/java/org/onap/portal/history/actions/ActionDto.java b/app/src/test/java/org/onap/portal/history/actions/ActionDto.java
new file mode 100644
index 0000000..2deec8e
--- /dev/null
+++ b/app/src/test/java/org/onap/portal/history/actions/ActionDto.java
@@ -0,0 +1,39 @@
+/*
+ *
+ * Copyright (c) 2022. Deutsche Telekom AG
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ *
+ */
+
+package org.onap.portal.history.actions;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+import lombok.Setter;
+
+@Getter
+@Setter
+@AllArgsConstructor
+@NoArgsConstructor
+public class ActionDto {
+ String type;
+ String action;
+ String message;
+ String downStreamSystem;
+ String downStreamId;
+}
diff --git a/app/src/test/java/org/onap/portal/history/actions/ActionFixtures.java b/app/src/test/java/org/onap/portal/history/actions/ActionFixtures.java
new file mode 100644
index 0000000..efab59a
--- /dev/null
+++ b/app/src/test/java/org/onap/portal/history/actions/ActionFixtures.java
@@ -0,0 +1,126 @@
+/*
+ *
+ * Copyright (c) 2022. Deutsche Telekom AG
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ *
+ */
+
+package org.onap.portal.history.actions;
+
+import java.time.OffsetDateTime;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
+
+import org.onap.portal.history.entities.ActionsDao;
+import org.onap.portal.history.openapi.model.CreateActionRequest;
+
+public class ActionFixtures {
+
+ public static List<CreateActionRequest> createActionRequestList(
+ Integer numberOfActions, String userId, OffsetDateTime createdAt){
+ List<CreateActionRequest> createActionRequestList = new ArrayList<>();
+ for (Integer i = 1; i <= numberOfActions; i++) {
+ createActionRequestList.add(
+ generateActionRequest(
+ "Instantiation", "create", "action" + i, i.toString(), "SO", i, i, i, userId, createdAt));
+ }
+ return createActionRequestList;
+ }
+
+ public static List<CreateActionRequest> createActionRequestListHourOffsetOnly(
+ Integer numberOfActions, String userId, OffsetDateTime createdAt){
+ List<CreateActionRequest> createActionRequestList = new ArrayList<>();
+ for (Integer i = 1; i <= numberOfActions; i++) {
+ createActionRequestList.add(
+ generateActionRequest(
+ "Instantiation", "create", "action" + i, i.toString(), "SO", i, 0, 0, userId, createdAt));
+ }
+ return createActionRequestList;
+ }
+
+ public static CreateActionRequest generateActionRequest(
+ String type,
+ String action,
+ String message,
+ String id,
+ String downStreamSystem,
+ Integer deltaHours,
+ Integer deltaMinutes,
+ Integer deltaSeconds,
+ String userId,
+ OffsetDateTime createdAt) {
+ ActionDto actionDto = new ActionDto();
+ actionDto.setType(type);
+ actionDto.setAction(action);
+ actionDto.setMessage(message);
+ actionDto.setDownStreamSystem(downStreamSystem);
+ actionDto.setDownStreamId(id);
+
+ return new CreateActionRequest()
+ .userId(userId)
+ .action(actionDto)
+ .actionCreatedAt(createdAt.minusHours(deltaHours).minusMinutes(deltaMinutes).minusSeconds(deltaSeconds));
+ }
+
+ public static List<ActionsDao> actionsDaoList(
+ Integer numberOfActions, String userId, OffsetDateTime createdAt){
+ List<ActionsDao> actionsDaoList = new ArrayList<>();
+ for (Integer i = 1; i <= numberOfActions; i++) {
+ actionsDaoList.add(
+ generateActionsDao(
+ "Instantiation", "create", "action" + i, i.toString(), "SO", i, i, i, userId, createdAt));
+ }
+ return actionsDaoList;
+ }
+
+ public static ActionsDao generateActionsDao(
+ String type,
+ String action,
+ String message,
+ String id,
+ String downStreamSystem,
+ Integer deltaHours,
+ Integer deltaMinutes,
+ Integer deltaSeconds,
+ String userId,
+ OffsetDateTime createdAt) {
+ ActionDto actionDto = new ActionDto();
+ actionDto.setType(type);
+ actionDto.setAction(action);
+ actionDto.setMessage(message);
+ actionDto.setDownStreamSystem(downStreamSystem);
+ actionDto.setDownStreamId(id);
+
+ ActionsDao actionsDao = new ActionsDao();
+ actionsDao.setUserId(userId);
+ actionsDao.setAction(actionDto);
+ actionsDao.setActionCreatedAt(new Date(createdAt.minusHours(deltaHours).minusMinutes(deltaMinutes).minusSeconds(deltaSeconds).toEpochSecond()*1000));
+ return actionsDao;
+ }
+
+ public static List<ActionsDao> actionsDaoListHourOffsetOnly(
+ Integer numberOfActions, String userId, OffsetDateTime createdAt){
+ List<ActionsDao> actionsDaoList = new ArrayList<>();
+ for (Integer i = 1; i <= numberOfActions; i++) {
+ actionsDaoList.add(
+ generateActionsDao(
+ "Instantiation", "create", "action" + i, i.toString(), "SO", i, 0, 0, userId, createdAt));
+ }
+ return actionsDaoList;
+ }
+}
diff --git a/app/src/test/java/org/onap/portal/history/actions/ActionsControllerIntegrationTest.java b/app/src/test/java/org/onap/portal/history/actions/ActionsControllerIntegrationTest.java
new file mode 100644
index 0000000..c5fa17b
--- /dev/null
+++ b/app/src/test/java/org/onap/portal/history/actions/ActionsControllerIntegrationTest.java
@@ -0,0 +1,571 @@
+/*
+ *
+ * Copyright (c) 2022. Deutsche Telekom AG
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ *
+ */
+
+package org.onap.portal.history.actions;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+
+import java.time.LocalDateTime;
+import java.time.OffsetDateTime;
+import java.time.ZoneOffset;
+import java.time.format.DateTimeFormatter;
+import java.time.temporal.ChronoUnit;
+import java.util.List;
+
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.onap.portal.history.BaseIntegrationTest;
+import org.onap.portal.history.entities.ActionsDao;
+import org.onap.portal.history.openapi.model.ActionResponse;
+import org.onap.portal.history.openapi.model.ActionsListResponse;
+import org.onap.portal.history.openapi.model.CreateActionRequest;
+import org.onap.portal.history.openapi.model.Problem;
+import org.onap.portal.history.repository.ActionsRepository;
+import org.onap.portal.history.services.ActionsService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.MediaType;
+
+import com.fasterxml.jackson.core.JsonProcessingException;
+
+import io.restassured.http.Header;
+
+class ActionsControllerIntegrationTest extends BaseIntegrationTest {
+
+ protected static final String X_REQUEST_ID = "addf6005-3075-4c80-b7bc-2c70b7d42b57";
+ protected static final String X_REQUEST_ID2 = "addf6005-3075-4c80-b7bc-2c70b7d42b22";
+
+ @Autowired
+ ActionsService actionsService;
+
+ @Autowired
+ private ActionsRepository repository;
+
+ // @Value("${portal-history.save-interval}")
+ protected Integer saveInterval = 72;
+
+ @BeforeEach
+ void deleteMongoDataBase(){
+ repository.deleteAll().block();
+ }
+
+ @Test
+ void thatUserCanHaveNoHistoryYet() throws JsonProcessingException {
+ ActionsListResponse response = requestSpecification()
+ .given()
+ .accept(MediaType.APPLICATION_JSON_VALUE)
+ .contentType(MediaType.APPLICATION_JSON_VALUE)
+ .header(new Header("X-Request-Id", X_REQUEST_ID ))
+ .when()
+ .get( "/v1/actions/test-user")
+ .then()
+ .header("X-Request-Id", X_REQUEST_ID)
+ .statusCode(HttpStatus.OK.value())
+ .extract()
+ .body()
+ .as(ActionsListResponse.class);
+
+ assertNotNull(response);
+ assertThat(response.getTotalCount()).isEqualTo(0);
+ }
+
+ @Test
+ void thatActionCanBeSaved() throws Exception{
+ ActionDto actionDto = new ActionDto();
+ actionDto.setType("instantiation");
+ actionDto.setAction("create");
+ actionDto.setDownStreamId("1234");
+ actionDto.setDownStreamSystem("SO");
+ actionDto.setMessage("no details");
+
+ CreateActionRequest actionRequest = new CreateActionRequest()
+ .actionCreatedAt(OffsetDateTime.of(LocalDateTime.now(), ZoneOffset.UTC).truncatedTo(ChronoUnit.SECONDS))
+ .userId("test-user")
+ .action(actionDto);
+
+ ActionResponse response = requestSpecification()
+ .given()
+ .accept(MediaType.APPLICATION_JSON_VALUE)
+ .contentType(MediaType.APPLICATION_JSON_VALUE)
+ .header(new Header("X-Request-Id", X_REQUEST_ID ))
+ .body(actionRequest)
+ .when()
+ .post( "/v1/actions/test-user")
+ .then()
+ .header("X-Request-Id", X_REQUEST_ID)
+ .statusCode(HttpStatus.OK.value())
+ .extract()
+ .body()
+ .as(ActionResponse.class);
+
+ assertThat(response.getActionCreatedAt()).isEqualTo(actionRequest.getActionCreatedAt().truncatedTo(ChronoUnit.SECONDS).format(DateTimeFormatter.ISO_DATE_TIME));
+ assertThat(response.getSaveInterval()).isEqualTo(saveInterval);
+ assertThat(objectMapper.writeValueAsString(response.getAction())).isEqualTo(objectMapper.writeValueAsString(actionRequest.getAction()));
+ }
+
+ @Test
+ void thatActionsCanBeListedWithoutParameter() throws JsonProcessingException {
+ List<ActionsDao> actionsDaoList = ActionFixtures.actionsDaoList(500, "test-user", OffsetDateTime.of(LocalDateTime.now(), ZoneOffset.UTC).truncatedTo(ChronoUnit.SECONDS));
+ repository
+ .saveAll(actionsDaoList)
+ .blockLast();
+ ActionsListResponse response = requestSpecification()
+ .given()
+ .accept(MediaType.APPLICATION_JSON_VALUE)
+ .contentType(MediaType.APPLICATION_JSON_VALUE)
+ .header(new Header("X-Request-Id", X_REQUEST_ID ))
+ .when()
+ .get( "/v1/actions")
+ .then()
+ .header("X-Request-Id", X_REQUEST_ID)
+ .statusCode(HttpStatus.OK.value())
+ .extract()
+ .body()
+ .as(ActionsListResponse.class);
+
+ assertThat(response.getTotalCount()).isEqualTo(10);
+ assertThat(response.getActionsList().get(0).getSaveInterval()).isEqualTo(saveInterval);
+ assertThat(response.getActionsList().get(9).getSaveInterval()).isEqualTo(saveInterval);
+ assertThat(objectMapper.writeValueAsString(response.getActionsList().get(0).getAction())).isEqualTo(objectMapper.writeValueAsString(actionsDaoList.get(0).getAction()));
+ assertThat(objectMapper.writeValueAsString(response.getActionsList().get(9).getAction())).isEqualTo(objectMapper.writeValueAsString(actionsDaoList.get(9).getAction()));
+ }
+
+ @Test
+ void thatActionsCanBeListedWithParameter() throws JsonProcessingException {
+ List<ActionsDao> actionsDaoList = ActionFixtures.actionsDaoList(20, "test-user", OffsetDateTime.of(LocalDateTime.now(), ZoneOffset.UTC).truncatedTo(ChronoUnit.SECONDS));
+ repository
+ .saveAll(actionsDaoList)
+ .blockLast();
+ ActionsListResponse response = requestSpecification()
+ .given()
+ .accept(MediaType.APPLICATION_JSON_VALUE)
+ .contentType(MediaType.APPLICATION_JSON_VALUE)
+ .header(new Header("X-Request-Id", X_REQUEST_ID ))
+ .when()
+ .get( "/v1/actions?page=1&pageSize=5")
+ .then()
+ .header("X-Request-Id", X_REQUEST_ID)
+ .statusCode(HttpStatus.OK.value())
+ .extract()
+ .body()
+ .as(ActionsListResponse.class);
+
+ assertThat(response.getTotalCount()).isEqualTo(5);
+ assertThat(response.getActionsList().get(0).getSaveInterval()).isEqualTo(saveInterval);
+ assertThat(response.getActionsList().get(4).getSaveInterval()).isEqualTo(saveInterval);
+ assertThat(objectMapper.writeValueAsString(response.getActionsList().get(0).getAction())).isEqualTo(objectMapper.writeValueAsString(actionsDaoList.get(0).getAction()));
+ assertThat(objectMapper.writeValueAsString(response.getActionsList().get(4).getAction())).isEqualTo(objectMapper.writeValueAsString(actionsDaoList.get(4).getAction()));
+ }
+
+ @Test
+ void thatActionsCanBeListedWithParameterInOrderByActionCreatedAt() {
+ List<ActionsDao> actionsDaoList = ActionFixtures.actionsDaoList(5, "test-user", OffsetDateTime.of(LocalDateTime.now().minusDays(2), ZoneOffset.UTC).truncatedTo(ChronoUnit.SECONDS));
+ actionsDaoList.addAll(ActionFixtures.actionsDaoList(5, "test-user", OffsetDateTime.of(LocalDateTime.now(), ZoneOffset.UTC).truncatedTo(ChronoUnit.SECONDS)));
+ actionsDaoList.addAll(ActionFixtures.actionsDaoList(5, "test-user", OffsetDateTime.of(LocalDateTime.now().minusHours(6), ZoneOffset.UTC).truncatedTo(ChronoUnit.SECONDS)));
+ actionsDaoList.addAll(ActionFixtures.actionsDaoList(5, "test-user", OffsetDateTime.of(LocalDateTime.now().minusHours(12), ZoneOffset.UTC).truncatedTo(ChronoUnit.SECONDS)));
+ repository
+ .saveAll(actionsDaoList)
+ .blockLast();
+
+ ActionsListResponse response = requestSpecification()
+ .given()
+ .accept(MediaType.APPLICATION_JSON_VALUE)
+ .contentType(MediaType.APPLICATION_JSON_VALUE)
+ .header(new Header("X-Request-Id", X_REQUEST_ID ))
+ .when()
+ .get( "/v1/actions?page=1&pageSize=5")
+ .then()
+ .header("X-Request-Id", X_REQUEST_ID)
+ .statusCode(HttpStatus.OK.value())
+ .extract()
+ .body()
+ .as(ActionsListResponse.class);
+
+ assertThat(response.getTotalCount()).isEqualTo(5);
+ assertThat(response.getActionsList().get(0).getSaveInterval()).isEqualTo(saveInterval);
+ assertThat(response.getActionsList().get(4).getSaveInterval()).isEqualTo(saveInterval);
+ assertThat(response.getActionsList().get(0).getActionCreatedAt()).isEqualTo(actionsDaoList.get(5).getActionCreatedAt().toInstant().atOffset(ZoneOffset.UTC));
+ assertThat(response.getActionsList().get(4).getActionCreatedAt()).isEqualTo(actionsDaoList.get(9).getActionCreatedAt().toInstant().atOffset(ZoneOffset.UTC));
+ }
+
+ @Test
+ void thatActionsCanBeListedWithShowLastHours() throws JsonProcessingException {
+ List<ActionsDao> actionsDaoList = ActionFixtures.actionsDaoListHourOffsetOnly(20, "test-user", OffsetDateTime.now().plusMinutes(30).truncatedTo(ChronoUnit.SECONDS));
+ repository
+ .saveAll(actionsDaoList)
+ .blockLast();
+
+ ActionsListResponse response = requestSpecification()
+ .given()
+ .accept(MediaType.APPLICATION_JSON_VALUE)
+ .contentType(MediaType.APPLICATION_JSON_VALUE)
+ .header(new Header("X-Request-Id", X_REQUEST_ID ))
+ .when()
+ .get( "/v1/actions?page=1&pageSize=20&showLastHours=12")
+ .then()
+ .header("X-Request-Id", X_REQUEST_ID)
+ .statusCode(HttpStatus.OK.value())
+ .extract()
+ .body()
+ .as(ActionsListResponse.class);
+
+ assertThat(response.getTotalCount()).isEqualTo(12);
+ assertThat(response.getActionsList().get(0).getSaveInterval()).isEqualTo(saveInterval);
+ assertThat(objectMapper.writeValueAsString(response.getActionsList().get(0).getAction())).isEqualTo(objectMapper.writeValueAsString(actionsDaoList.get(0).getAction()));
+ assertThat(objectMapper.writeValueAsString(response.getActionsList().get(11).getAction())).isEqualTo(objectMapper.writeValueAsString(actionsDaoList.get(11).getAction()));
+ }
+
+ @Test
+ void thatActionsCanNotBeListedWithWrongPageParameter() {
+ List<ActionsDao> actionsDaoList = ActionFixtures.actionsDaoList(5, "test-user", OffsetDateTime.of(LocalDateTime.now().minusDays(2), ZoneOffset.UTC).truncatedTo(ChronoUnit.SECONDS));
+ repository
+ .saveAll(actionsDaoList)
+ .blockLast();
+
+ Problem response = requestSpecification()
+ .given()
+ .accept(MediaType.APPLICATION_JSON_VALUE)
+ .contentType(MediaType.APPLICATION_JSON_VALUE)
+ .header(new Header("X-Request-Id", X_REQUEST_ID ))
+ .when()
+ .get( "/v1/actions?page=0&pageSize=5")
+ .then()
+ .header("X-Request-Id", X_REQUEST_ID)
+ .statusCode(HttpStatus.BAD_REQUEST.value())
+ .extract()
+ .body()
+ .as(Problem.class);
+
+ assertThat(response.getStatus()).isEqualTo(500);
+ }
+
+ @Test
+ void thatActionsCanBeGetForUserWithShowLastHours(){
+ // First mixed user actions for different users
+ List<ActionsDao> actionsDaoList = ActionFixtures.actionsDaoListHourOffsetOnly(10, "test-user", OffsetDateTime.now().plusMinutes(30).truncatedTo(ChronoUnit.SECONDS));
+ List<ActionsDao> actionsDaoList2 = ActionFixtures.actionsDaoList(10, "test2-user", OffsetDateTime.now().truncatedTo(ChronoUnit.SECONDS));
+ List<ActionsDao> actionsDaoList3 = ActionFixtures.actionsDaoList(10, "test3-user", OffsetDateTime.now().truncatedTo(ChronoUnit.SECONDS));
+
+ actionsDaoList.addAll(actionsDaoList2);
+ actionsDaoList.addAll(actionsDaoList3);
+
+ repository
+ .saveAll(actionsDaoList)
+ .blockLast();
+
+ ActionsListResponse response = requestSpecification()
+ .given()
+ .accept(MediaType.APPLICATION_JSON_VALUE)
+ .contentType(MediaType.APPLICATION_JSON_VALUE)
+ .header(new Header("X-Request-Id", X_REQUEST_ID ))
+ .when()
+ .get( "/v1/actions/test-user?page=1&pageSize=20&showLastHours=2")
+ .then()
+ .header("X-Request-Id", X_REQUEST_ID)
+ .statusCode(HttpStatus.OK.value())
+ .extract()
+ .body()
+ .as(ActionsListResponse.class);
+
+ assertThat(response.getTotalCount()).isEqualTo(2);
+ assertThat(response.getActionsList().get(0).getSaveInterval()).isEqualTo(saveInterval);
+ }
+
+ @Test
+ void thatActionsCanBeGottenForUserWithShowLastHoursWithMinusValue(){
+ // First mixed user actions for different users
+ List<ActionsDao> actionsDaoList = ActionFixtures.actionsDaoListHourOffsetOnly(10, "test-user", OffsetDateTime.of(LocalDateTime.now(), ZoneOffset.UTC).truncatedTo(ChronoUnit.SECONDS));
+ List<ActionsDao> actionsDaoList2 = ActionFixtures.actionsDaoList(10, "test2-user", OffsetDateTime.of(LocalDateTime.now(), ZoneOffset.UTC).truncatedTo(ChronoUnit.SECONDS));
+ List<ActionsDao> actionsDaoList3 = ActionFixtures.actionsDaoList(10, "test3-user", OffsetDateTime.of(LocalDateTime.now(), ZoneOffset.UTC).truncatedTo(ChronoUnit.SECONDS));
+ List<ActionsDao> actionsDaoList4 = ActionFixtures.actionsDaoListHourOffsetOnly(10, "test-user", OffsetDateTime.of(LocalDateTime.now().plusHours(48), ZoneOffset.UTC).truncatedTo(ChronoUnit.SECONDS));
+ actionsDaoList.addAll(actionsDaoList2);
+ actionsDaoList.addAll(actionsDaoList3);
+ actionsDaoList.addAll(actionsDaoList4);
+
+ repository
+ .saveAll(actionsDaoList)
+ .blockLast();
+
+ ActionsListResponse response = requestSpecification()
+ .given()
+ .accept(MediaType.APPLICATION_JSON_VALUE)
+ .contentType(MediaType.APPLICATION_JSON_VALUE)
+ .header(new Header("X-Request-Id", X_REQUEST_ID ))
+ .when()
+ .get( "/v1/actions/test-user?page=1&pageSize=20&showLastHours=-2")
+ .then()
+ .header("X-Request-Id", X_REQUEST_ID)
+ .statusCode(HttpStatus.OK.value())
+ .extract()
+ .body()
+ .as(ActionsListResponse.class);
+
+ assertThat(response.getTotalCount()).isEqualTo(10);
+ }
+
+ @Test
+ void thatActionsCanBeGottenForUserWithoutParameter(){
+ // First mixed user actions for different users
+ List<ActionsDao> actionsDaoList = ActionFixtures.actionsDaoListHourOffsetOnly(10, "test-user", OffsetDateTime.of(LocalDateTime.now(), ZoneOffset.UTC).truncatedTo(ChronoUnit.SECONDS));
+ List<ActionsDao> actionsDaoList2 = ActionFixtures.actionsDaoList(10, "test2-user", OffsetDateTime.of(LocalDateTime.now(), ZoneOffset.UTC).truncatedTo(ChronoUnit.SECONDS));
+ List<ActionsDao> actionsDaoList3 = ActionFixtures.actionsDaoList(10, "test3-user", OffsetDateTime.of(LocalDateTime.now(), ZoneOffset.UTC).truncatedTo(ChronoUnit.SECONDS));
+ List<ActionsDao> actionsDaoList4 = ActionFixtures.actionsDaoListHourOffsetOnly(10, "test-user", OffsetDateTime.of(LocalDateTime.now(), ZoneOffset.UTC).truncatedTo(ChronoUnit.SECONDS));
+ actionsDaoList.addAll(actionsDaoList2);
+ actionsDaoList.addAll(actionsDaoList3);
+ actionsDaoList.addAll(actionsDaoList4);
+ repository
+ .saveAll(actionsDaoList)
+ .blockLast();
+
+ ActionsListResponse response = requestSpecification()
+ .given()
+ .accept(MediaType.APPLICATION_JSON_VALUE)
+ .contentType(MediaType.APPLICATION_JSON_VALUE)
+ .header(new Header("X-Request-Id", X_REQUEST_ID ))
+ .when()
+ .get( "/v1/actions/test-user")
+ .then()
+ .header("X-Request-Id", X_REQUEST_ID)
+ .statusCode(HttpStatus.OK.value())
+ .extract()
+ .body()
+ .as(ActionsListResponse.class);
+
+ assertThat(response.getTotalCount()).isEqualTo(10);
+ assertThat(response.getActionsList().get(0).getSaveInterval()).isEqualTo(saveInterval);
+ }
+
+ @Test
+ void thatActionsCanBeGottenForUserWithShowLastHoursWithEmptyList() {
+ // First mixed user actions for different users
+ List<ActionsDao> actionsDaoList = ActionFixtures.actionsDaoListHourOffsetOnly(10, "test-user", OffsetDateTime.of(LocalDateTime.now(), ZoneOffset.UTC).truncatedTo(ChronoUnit.SECONDS));
+ List<ActionsDao> actionsDaoList2 = ActionFixtures.actionsDaoList(10, "test2-user", OffsetDateTime.of(LocalDateTime.now(), ZoneOffset.UTC).truncatedTo(ChronoUnit.SECONDS));
+ List<ActionsDao> actionsDaoList3 = ActionFixtures.actionsDaoList(10, "test3-user", OffsetDateTime.of(LocalDateTime.now(), ZoneOffset.UTC).truncatedTo(ChronoUnit.SECONDS));
+ List<ActionsDao> actionsDaoList4 = ActionFixtures.actionsDaoListHourOffsetOnly(10, "test-user", OffsetDateTime.of(LocalDateTime.now(), ZoneOffset.UTC).truncatedTo(ChronoUnit.SECONDS));
+ actionsDaoList.addAll(actionsDaoList2);
+ actionsDaoList.addAll(actionsDaoList3);
+ actionsDaoList.addAll(actionsDaoList4);
+ repository
+ .saveAll(actionsDaoList)
+ .blockLast();
+
+ ActionsListResponse response = requestSpecification("test4-user")
+ .given()
+ .accept(MediaType.APPLICATION_JSON_VALUE)
+ .contentType(MediaType.APPLICATION_JSON_VALUE)
+ .header(new Header("X-Request-Id", X_REQUEST_ID ))
+ .when()
+ .get( "/v1/actions/test4-user?page=1&pageSize=20&showLastHours=2")
+ .then()
+ .header("X-Request-Id", X_REQUEST_ID)
+ .statusCode(HttpStatus.OK.value())
+ .extract()
+ .body()
+ .as(ActionsListResponse.class);
+
+ assertThat(response.getTotalCount()).isZero();
+ }
+
+ @Test
+ void thatActionsCanBeDeleted(){
+ // First mixed user actions for different users
+ List<ActionsDao> actionsDaoList = ActionFixtures.actionsDaoListHourOffsetOnly(10, "test-user", OffsetDateTime.now().plusMinutes(30).truncatedTo(ChronoUnit.SECONDS));
+ List<ActionsDao> actionsDaoList2 = ActionFixtures.actionsDaoList(5, "test2-user", OffsetDateTime.now().truncatedTo(ChronoUnit.SECONDS));
+ List<ActionsDao> actionsDaoList3 = ActionFixtures.actionsDaoList(3, "test3-user", OffsetDateTime.now().truncatedTo(ChronoUnit.SECONDS));
+ actionsDaoList.addAll(actionsDaoList2);
+ actionsDaoList.addAll(actionsDaoList3);
+ repository
+ .saveAll(actionsDaoList)
+ .blockLast();
+
+ requestSpecification()
+ .given()
+ .accept(MediaType.APPLICATION_JSON_VALUE)
+ .contentType(MediaType.APPLICATION_JSON_VALUE)
+ .header(new Header("X-Request-Id", X_REQUEST_ID ))
+ .when()
+ .delete( "/v1/actions/test-user?deleteAfterHours=2")
+ .then()
+ .header("X-Request-Id", X_REQUEST_ID)
+ .statusCode(HttpStatus.OK.value())
+ .extract()
+ .body()
+ .as(ActionsListResponse.class);
+
+ ActionsListResponse responseGetUser = requestSpecification()
+ .given()
+ .accept(MediaType.APPLICATION_JSON_VALUE)
+ .contentType(MediaType.APPLICATION_JSON_VALUE)
+ .header(new Header("X-Request-Id", X_REQUEST_ID2 ))
+ .when()
+ .get( "/v1/actions/test-user?page=1&pageSize=20")
+ .then()
+ .header("X-Request-Id", X_REQUEST_ID2)
+ .statusCode(HttpStatus.OK.value())
+ .extract()
+ .body()
+ .as(ActionsListResponse.class);
+
+ ActionsListResponse responseGetUser2 = requestSpecification("test2-user")
+ .given()
+ .accept(MediaType.APPLICATION_JSON_VALUE)
+ .contentType(MediaType.APPLICATION_JSON_VALUE)
+ .header(new Header("X-Request-Id", X_REQUEST_ID2 ))
+ .when()
+ .get( "/v1/actions/test2-user")
+ .then()
+ .header("X-Request-Id", X_REQUEST_ID2)
+ .statusCode(HttpStatus.OK.value())
+ .extract()
+ .body()
+ .as(ActionsListResponse.class);
+
+ ActionsListResponse responseGetUser3 = requestSpecification("test3-user")
+ .given()
+ .accept(MediaType.APPLICATION_JSON_VALUE)
+ .contentType(MediaType.APPLICATION_JSON_VALUE)
+ .header(new Header("X-Request-Id", X_REQUEST_ID2 ))
+ .when()
+ .get( "/v1/actions/test3-user")
+ .then()
+ .header("X-Request-Id", X_REQUEST_ID2)
+ .statusCode(HttpStatus.OK.value())
+ .extract()
+ .body()
+ .as(ActionsListResponse.class);
+
+ assertThat(responseGetUser.getTotalCount()).isEqualTo(2);
+ assertThat(responseGetUser2.getTotalCount()).isEqualTo(5);
+ assertThat(responseGetUser3.getTotalCount()).isEqualTo(3);
+ }
+
+ @Test
+ void thatActionsCanNotBeGetForUserBecauseOfWrongUserIdInToken(){
+ // First mixed user actions for different users
+ List<ActionsDao> actionsDaoList = ActionFixtures.actionsDaoListHourOffsetOnly(10, "test-user", OffsetDateTime.of(LocalDateTime.now(), ZoneOffset.UTC).truncatedTo(ChronoUnit.SECONDS));
+ repository
+ .saveAll(actionsDaoList)
+ .blockLast();
+
+ Problem response = requestSpecification("wrong-userId")
+ .given()
+ .accept(MediaType.APPLICATION_PROBLEM_JSON_VALUE)
+ .header(new Header("X-Request-Id", X_REQUEST_ID ))
+ .when()
+ .get( "/v1/actions/test-user")
+ .then()
+ .header("X-Request-Id", X_REQUEST_ID)
+ .statusCode(HttpStatus.BAD_REQUEST.value())
+ .extract()
+ .body()
+ .as(Problem.class);
+
+ assertThat(response).isNotNull();
+ assertThat(response.getStatus()).isEqualTo(HttpStatus.FORBIDDEN.value());
+ }
+
+ @Test
+ void thatActionsCanNotBeGetForUserBecauseOfWrongHeader(){
+ // First mixed user actions for different users
+ List<ActionsDao> actionsDaoList = ActionFixtures.actionsDaoListHourOffsetOnly(10, "test-user", OffsetDateTime.of(LocalDateTime.now(), ZoneOffset.UTC).truncatedTo(ChronoUnit.SECONDS));
+ repository
+ .saveAll(actionsDaoList)
+ .blockLast();
+
+ Problem response = wrongHeaderRequestSpecification("test-user")
+ .given()
+ .accept(MediaType.APPLICATION_PROBLEM_JSON_VALUE)
+ .header(new Header("X-Request-Id", X_REQUEST_ID ))
+ .when()
+ .get( "/v1/actions/test-user")
+ .then()
+ .header("X-Request-Id", X_REQUEST_ID)
+ .statusCode(HttpStatus.BAD_REQUEST.value())
+ .extract()
+ .body()
+ .as(Problem.class);
+
+ assertThat(response).isNotNull();
+ assertThat(response.getStatus()).isEqualTo(HttpStatus.FORBIDDEN.value());
+ }
+
+ @Test
+ void thatActionsCanBeDeletedForAllUsers(){
+ // First mixed user actions for different users
+ List<ActionsDao> actionsDaoList = ActionFixtures.actionsDaoListHourOffsetOnly(10, "test-user", OffsetDateTime.of(LocalDateTime.now().minusHours(96), ZoneOffset.UTC).truncatedTo(ChronoUnit.SECONDS));
+ List<ActionsDao> actionsDaoList2 = ActionFixtures.actionsDaoList(8, "test2-user", OffsetDateTime.of(LocalDateTime.now().minusHours(24), ZoneOffset.UTC).truncatedTo(ChronoUnit.SECONDS));
+ List<ActionsDao> actionsDaoList3 = ActionFixtures.actionsDaoList(5, "test3-user", OffsetDateTime.of(LocalDateTime.now(), ZoneOffset.UTC).truncatedTo(ChronoUnit.SECONDS));
+ List<ActionsDao> actionsDaoList4 = ActionFixtures.actionsDaoListHourOffsetOnly(10, "test-user", OffsetDateTime.of(LocalDateTime.now().minusHours(48), ZoneOffset.UTC).truncatedTo(ChronoUnit.SECONDS));
+
+ actionsDaoList.addAll(actionsDaoList2);
+ actionsDaoList.addAll(actionsDaoList3);
+ actionsDaoList.addAll(actionsDaoList4);
+ repository
+ .saveAll(actionsDaoList)
+ .blockLast();
+
+ actionsService.deleteActions(72).block();
+
+ ActionsListResponse responseGetUser = requestSpecification()
+ .given()
+ .accept(MediaType.APPLICATION_JSON_VALUE)
+ .contentType(MediaType.APPLICATION_JSON_VALUE)
+ .header(new Header("X-Request-Id", X_REQUEST_ID2 ))
+ .when()
+ .get( "/v1/actions/test-user?page=1&pageSize=20")
+ .then()
+ .statusCode(HttpStatus.OK.value())
+ .extract()
+ .body()
+ .as(ActionsListResponse.class);
+
+ ActionsListResponse responseGetUser2 = requestSpecification("test2-user")
+ .given()
+ .accept(MediaType.APPLICATION_JSON_VALUE)
+ .contentType(MediaType.APPLICATION_JSON_VALUE)
+ .header(new Header("X-Request-Id", X_REQUEST_ID2 ))
+ .when()
+ .get( "/v1/actions/test2-user")
+ .then()
+ .statusCode(HttpStatus.OK.value())
+ .extract()
+ .body()
+ .as(ActionsListResponse.class);
+
+ ActionsListResponse responseGetUser3 = requestSpecification("test3-user")
+ .given()
+ .accept(MediaType.APPLICATION_JSON_VALUE)
+ .contentType(MediaType.APPLICATION_JSON_VALUE)
+ .header(new Header("X-Request-Id", X_REQUEST_ID2 ))
+ .when()
+ .get( "/v1/actions/test3-user")
+ .then()
+ .statusCode(HttpStatus.OK.value())
+ .extract()
+ .body()
+ .as(ActionsListResponse.class);
+
+ assertThat(responseGetUser.getTotalCount()).isEqualTo(10);
+ assertThat(responseGetUser2.getTotalCount()).isEqualTo(8);
+ assertThat(responseGetUser3.getTotalCount()).isEqualTo(5);
+ }
+}