diff --git a/.github/workflows/build-mariadb.yml b/.github/workflows/build-mariadb.yml index ba7408890..21e4d5b5c 100644 --- a/.github/workflows/build-mariadb.yml +++ b/.github/workflows/build-mariadb.yml @@ -58,13 +58,10 @@ jobs: sudo apt-get install ghostscript graphviz -y - name: Basic Auth Build & Test - run: ./gradlew --no-daemon -q --console=plain build test --fail-fast doc -x :twofactor-tests:test -x :oauth2-test:test -x :instancemode-tests:test + run: ./gradlew --no-daemon -q --console=plain build test --fail-fast doc -x :twofactor-tests:test -x :oauth2-test:test - name: 2FA Build & Test run: ./gradlew --no-daemon -q --console=plain :twofactor-tests:test --fail-fast - name: OAuth2 Build & Test run: ./gradlew --no-daemon -q --console=plain :oauth2-tests:test --fail-fast - - - name: Instance Mode & Test - run: ./gradlew --no-daemon -q --console=plain :instancemode-tests:test --fail-fast diff --git a/.github/workflows/build-mysql.yml b/.github/workflows/build-mysql.yml index 44fbcc1e0..609133bfd 100644 --- a/.github/workflows/build-mysql.yml +++ b/.github/workflows/build-mysql.yml @@ -58,13 +58,10 @@ jobs: sudo apt-get install ghostscript graphviz -y - name: Basic Auth Build & Test - run: ./gradlew --no-daemon -q --console=plain build test --fail-fast doc -x :twofactor-tests:test -x :oauth2-test:test -x :instancemode-tests:test -PdbType=mysql + run: ./gradlew --no-daemon -q --console=plain build test --fail-fast doc -x :twofactor-tests:test -x :oauth2-test:test -PdbType=mysql - name: 2FA Build & Test run: ./gradlew --no-daemon -q --console=plain :twofactor-tests:test --fail-fast -PdbType=mysql - name: OAuth2 Build & Test run: ./gradlew --no-daemon -q --console=plain :oauth2-tests:test --fail-fast -PdbType=mysql - - - name: Instance Mode & Test - run: ./gradlew --no-daemon -q --console=plain :instancemode-tests:test --fail-fast -PdbType=mysql diff --git a/.github/workflows/build-postgresql.yml b/.github/workflows/build-postgresql.yml index 153896d92..f3f2f44e5 100644 --- a/.github/workflows/build-postgresql.yml +++ b/.github/workflows/build-postgresql.yml @@ -59,13 +59,10 @@ jobs: sudo apt-get install ghostscript graphviz -y - name: Basic Auth Build & Test - run: ./gradlew --no-daemon -q --console=plain build test --fail-fast doc -x :twofactor-tests:test -x :oauth2-test:test -x :instancemode-tests:test -PdbType=postgresql + run: ./gradlew --no-daemon -q --console=plain build test --fail-fast doc -x :twofactor-tests:test -x :oauth2-test:test -PdbType=postgresql - name: 2FA Build & Test run: ./gradlew --no-daemon -q --console=plain :twofactor-tests:test --fail-fast -PdbType=postgresql - name: OAuth2 Build & Test run: ./gradlew --no-daemon -q --console=plain :oauth2-tests:test --fail-fast -PdbType=postgresql - - - name: Instance Mode & Test - run: ./gradlew --no-daemon -q --console=plain :instancemode-tests:test --fail-fast -PdbType=postgresql diff --git a/build.gradle b/build.gradle index 901cff148..409e723c2 100644 --- a/build.gradle +++ b/build.gradle @@ -30,7 +30,6 @@ buildscript { 'integration-tests', 'twofactor-tests', 'oauth2-tests', - 'instancemode-tests', 'fineract-client', 'core', 'service', diff --git a/fineract-provider/dependencies.gradle b/fineract-provider/dependencies.gradle index d7c7fc6b6..0d0d99e74 100644 --- a/fineract-provider/dependencies.gradle +++ b/fineract-provider/dependencies.gradle @@ -31,6 +31,7 @@ dependencies { 'org.springframework.boot:spring-boot-starter-security', 'org.springframework.boot:spring-boot-starter-cache', 'org.springframework.boot:spring-boot-starter-oauth2-resource-server', + 'org.springframework.boot:spring-boot-starter-actuator', 'org.glassfish.jersey.media:jersey-media-multipart:2.35', @@ -135,7 +136,6 @@ dependencies { // runtimeOnly dependencies are things that Fineract code has no direct compile time dependency on, but which must be present at run-time runtimeOnly( 'org.apache.bval:org.apache.bval.bundle', - 'org.springframework.boot:spring-boot-starter-actuator', // Although fineract (at the time of writing) doesn't have any compile time dep. on httpclient, // it's useful to have this for the Spring Boot TestRestTemplate http://docs.spring.io/spring-boot/docs/current-SNAPSHOT/reference/htmlsingle/#boot-features-rest-templates-test-utility diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/core/config/FineractProperties.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/core/config/FineractProperties.java index ecc2beb1a..76acae42e 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/core/config/FineractProperties.java +++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/core/config/FineractProperties.java @@ -68,17 +68,5 @@ public class FineractProperties { public boolean isBatchOnlyMode() { return !readEnabled && !writeEnabled && batchEnabled; } - - public boolean isReadInstance() { - return isReadOnlyMode() || readEnabled; - } - - public boolean isWriteInstance() { - return isWriteOnlyMode() || writeEnabled; - } - - public boolean isBatchInstance() { - return isBatchOnlyMode() || batchEnabled; - } } } diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/core/config/SecurityConfig.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/core/config/SecurityConfig.java index b976a36a6..eb3005199 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/core/config/SecurityConfig.java +++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/core/config/SecurityConfig.java @@ -19,7 +19,7 @@ package org.apache.fineract.infrastructure.core.config; -import org.apache.fineract.infrastructure.security.filter.FineractInstanceModeApiFilter; +import org.apache.fineract.infrastructure.instancemode.filter.FineractInstanceModeApiFilter; import org.apache.fineract.infrastructure.security.filter.TenantAwareBasicAuthenticationFilter; import org.apache.fineract.infrastructure.security.filter.TwoFactorAuthenticationFilter; import org.apache.fineract.infrastructure.security.service.TenantAwareJpaPlatformUserDetailsService; @@ -65,7 +65,6 @@ public class SecurityConfig extends WebSecurityConfigurerAdapter { @Override protected void configure(HttpSecurity http) throws Exception { - http // .csrf().disable() // NOSONAR only creating a service that is used by non-browser clients .antMatcher("/api/**").authorizeRequests() // @@ -75,6 +74,7 @@ public class SecurityConfig extends WebSecurityConfigurerAdapter { .antMatchers(HttpMethod.POST, "/api/*/self/authentication").permitAll() // .antMatchers(HttpMethod.POST, "/api/*/self/registration").permitAll() // .antMatchers(HttpMethod.POST, "/api/*/self/registration/user").permitAll() // + .antMatchers(HttpMethod.PUT, "/api/*/instance-mode").permitAll() // .antMatchers(HttpMethod.POST, "/api/*/twofactor/validate").fullyAuthenticated() // .antMatchers("/api/*/twofactor").fullyAuthenticated() // .antMatchers("/api/**").access("isFullyAuthenticated() and hasAuthority('TWOFACTOR_AUTHENTICATED')").and() // diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/instancemode/api/InstanceModeApiResource.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/instancemode/api/InstanceModeApiResource.java new file mode 100644 index 000000000..08a82b9a1 --- /dev/null +++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/instancemode/api/InstanceModeApiResource.java @@ -0,0 +1,77 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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. + */ +package org.apache.fineract.infrastructure.instancemode.api; + +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.media.Content; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.parameters.RequestBody; +import io.swagger.v3.oas.annotations.responses.ApiResponse; +import io.swagger.v3.oas.annotations.responses.ApiResponses; +import io.swagger.v3.oas.annotations.tags.Tag; +import javax.ws.rs.Consumes; +import javax.ws.rs.PUT; +import javax.ws.rs.Path; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.apache.fineract.infrastructure.core.config.FineractProperties; +import org.springframework.beans.factory.InitializingBean; +import org.springframework.context.annotation.Profile; +import org.springframework.stereotype.Component; + +@Profile("test") +@Component +@Path("/instance-mode") +@Tag(name = "Instance Mode", description = "Instance mode changing API") +@RequiredArgsConstructor +@Slf4j +public class InstanceModeApiResource implements InitializingBean { + + private final FineractProperties fineractProperties; + + @Override + public void afterPropertiesSet() throws Exception { + log.warn("------------------------------------------------------------"); + log.warn(" "); + log.warn("DO NOT USE THIS IN PRODUCTION!"); + log.warn("Instance type changing feature is enabled"); + log.warn("DO NOT USE THIS IN PRODUCTION!"); + log.warn(" "); + log.warn("------------------------------------------------------------"); + } + + @PUT + @Consumes({ MediaType.APPLICATION_JSON }) + @Operation(summary = "Changes the Fineract instance mode", description = "") + @RequestBody(required = true, content = @Content(schema = @Schema(implementation = InstanceModeApiResourceSwagger.ChangeInstanceModeRequest.class))) + @ApiResponses({ @ApiResponse(responseCode = "200", description = "OK") }) + public Response changeMode(InstanceModeApiResourceSwagger.ChangeInstanceModeRequest request) { + log.warn("------------------------------------------------------------"); + log.warn(" "); + log.warn("Changing instance mode according to the request parameters {}", request); + log.warn(" "); + log.warn("------------------------------------------------------------"); + fineractProperties.getMode().setReadEnabled(request.isReadEnabled()); + fineractProperties.getMode().setWriteEnabled(request.isWriteEnabled()); + fineractProperties.getMode().setBatchEnabled(request.isBatchEnabled()); + return Response.ok().build(); + } +} diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/instancemode/api/InstanceModeApiResourceSwagger.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/instancemode/api/InstanceModeApiResourceSwagger.java new file mode 100644 index 000000000..eda10c894 --- /dev/null +++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/instancemode/api/InstanceModeApiResourceSwagger.java @@ -0,0 +1,39 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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. + */ +package org.apache.fineract.infrastructure.instancemode.api; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Getter; +import lombok.ToString; + +public class InstanceModeApiResourceSwagger { + + @ToString + @Schema(description = "ChangeInstanceModeRequest") + @Getter + public static final class ChangeInstanceModeRequest { + + @Schema(required = true, example = "true") + public boolean readEnabled; + @Schema(required = true, example = "true") + public boolean writeEnabled; + @Schema(required = true, example = "true") + public boolean batchEnabled; + } +} diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/instancemode/filter/FineractInstanceModeApiFilter.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/instancemode/filter/FineractInstanceModeApiFilter.java new file mode 100644 index 000000000..d0f3307dc --- /dev/null +++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/instancemode/filter/FineractInstanceModeApiFilter.java @@ -0,0 +1,121 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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. + */ +package org.apache.fineract.infrastructure.instancemode.filter; + +import static org.apache.commons.lang3.StringUtils.isBlank; +import static org.apache.fineract.infrastructure.instancemode.filter.FineractInstanceModeApiFilter.ExceptionListItem.item; + +import java.io.IOException; +import java.util.List; +import java.util.function.Function; +import javax.servlet.FilterChain; +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import javax.ws.rs.HttpMethod; +import javax.ws.rs.ext.Provider; +import lombok.Getter; +import lombok.RequiredArgsConstructor; +import org.apache.fineract.infrastructure.core.config.FineractProperties; +import org.apache.fineract.infrastructure.core.data.ApiGlobalErrorResponse; +import org.apache.http.HttpStatus; +import org.springframework.stereotype.Component; +import org.springframework.web.filter.OncePerRequestFilter; + +@Provider +@Component +@RequiredArgsConstructor +public class FineractInstanceModeApiFilter extends OncePerRequestFilter { + + private static final List EXCEPTION_LIST = List.of( + item(FineractProperties.FineractModeProperties::isBatchEnabled, pi -> pi.startsWith("/jobs")), + item(p -> true, pi -> pi.startsWith("/instance-mode"))); + + private final FineractProperties fineractProperties; + + @Override + protected void doFilterInternal(final HttpServletRequest request, final HttpServletResponse response, final FilterChain filterChain) + throws ServletException, IOException { + if (isOnExceptionList(request) || isActuatorApi(request)) { + proceed(filterChain, request, response); + } else { + if (isPathOnExceptionList(request)) { + reject(request, response); + } else { + if (fineractProperties.getMode().isReadEnabled() && isReadMethod(request)) { + proceed(filterChain, request, response); + } else if (fineractProperties.getMode().isWriteEnabled()) { + proceed(filterChain, request, response); + } else { + reject(request, response); + } + } + } + } + + private boolean isActuatorApi(HttpServletRequest request) { + if (isBlank(request.getServletPath())) { + return false; + } + return request.getServletPath().startsWith("/actuator"); + } + + private void proceed(FilterChain filterChain, HttpServletRequest request, HttpServletResponse response) + throws IOException, ServletException { + filterChain.doFilter(request, response); + } + + private void reject(HttpServletRequest request, HttpServletResponse response) throws IOException { + response.setStatus(HttpStatus.SC_METHOD_NOT_ALLOWED); + ApiGlobalErrorResponse errorResponse = ApiGlobalErrorResponse.invalidInstanceTypeMethod(request.getMethod()); + response.getWriter().write(errorResponse.toJson()); + } + + private boolean isPathOnExceptionList(HttpServletRequest request) { + if (isBlank(request.getPathInfo())) { + return false; + } + return EXCEPTION_LIST.stream().anyMatch(item -> item.getPathFunction().apply(request.getPathInfo())); + } + + private boolean isOnExceptionList(HttpServletRequest request) { + if (isBlank(request.getPathInfo())) { + return false; + } + return EXCEPTION_LIST.stream().anyMatch( + item -> item.getModeFunction().apply(fineractProperties.getMode()) && item.getPathFunction().apply(request.getPathInfo())); + } + + private boolean isReadMethod(HttpServletRequest request) { + return HttpMethod.GET.equals(request.getMethod()); + } + + @RequiredArgsConstructor + @Getter + static class ExceptionListItem { + + private final Function modeFunction; + private final Function pathFunction; + + public static ExceptionListItem item(Function modeFunction, + Function pathFunction) { + return new ExceptionListItem(modeFunction, pathFunction); + } + } +} diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/jobs/api/SchedulerJobApiResource.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/jobs/api/SchedulerJobApiResource.java index 972e15fef..6f42b6494 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/jobs/api/SchedulerJobApiResource.java +++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/jobs/api/SchedulerJobApiResource.java @@ -133,7 +133,7 @@ public class SchedulerJobApiResource { @QueryParam(SchedulerJobApiConstants.COMMAND) @Parameter(description = "command") final String commandParam) { // check the logged in user have permissions to execute scheduler jobs Response response; - if (fineractProperties.getMode().isBatchInstance()) { + if (fineractProperties.getMode().isBatchEnabled()) { final boolean hasNotPermission = this.context.authenticatedUser().hasNotPermissionForAnyOf("ALL_FUNCTIONS", "EXECUTEJOB_SCHEDULER"); if (hasNotPermission) { diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/security/filter/FineractInstanceModeApiFilter.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/security/filter/FineractInstanceModeApiFilter.java deleted file mode 100644 index c334a66bd..000000000 --- a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/security/filter/FineractInstanceModeApiFilter.java +++ /dev/null @@ -1,62 +0,0 @@ -/** - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you 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. - */ -package org.apache.fineract.infrastructure.security.filter; - -import java.io.IOException; -import javax.servlet.FilterChain; -import javax.servlet.ServletException; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; -import javax.ws.rs.HttpMethod; -import javax.ws.rs.ext.Provider; -import lombok.RequiredArgsConstructor; -import org.apache.fineract.infrastructure.core.config.FineractProperties; -import org.apache.fineract.infrastructure.core.data.ApiGlobalErrorResponse; -import org.apache.http.HttpStatus; -import org.springframework.stereotype.Component; -import org.springframework.web.filter.OncePerRequestFilter; - -@Provider -@Component -@RequiredArgsConstructor -public class FineractInstanceModeApiFilter extends OncePerRequestFilter { - - private final FineractProperties fineractProperties; - - @Override - protected void doFilterInternal(final HttpServletRequest request, final HttpServletResponse response, final FilterChain filterChain) - throws ServletException, IOException { - - if (fineractProperties.getMode().isReadInstance() && isReadMethod(request)) { - filterChain.doFilter(request, response); - } else if (fineractProperties.getMode().isWriteInstance()) { - filterChain.doFilter(request, response); - } else if (fineractProperties.getMode().isBatchInstance() && request.getPathInfo().startsWith("/jobs")) { - filterChain.doFilter(request, response); - } else { - response.setStatus(HttpStatus.SC_METHOD_NOT_ALLOWED); - ApiGlobalErrorResponse errorResponse = ApiGlobalErrorResponse.invalidInstanceTypeMethod(request.getMethod()); - response.getWriter().write(errorResponse.toJson()); - } - } - - private boolean isReadMethod(HttpServletRequest request) { - return HttpMethod.GET.equals(request.getMethod()); - } -} diff --git a/fineract-provider/src/test/java/org/apache/fineract/infrastructure/instancemode/filter/FineractInstanceModeApiFilterTest.java b/fineract-provider/src/test/java/org/apache/fineract/infrastructure/instancemode/filter/FineractInstanceModeApiFilterTest.java new file mode 100644 index 000000000..a6715d6d9 --- /dev/null +++ b/fineract-provider/src/test/java/org/apache/fineract/infrastructure/instancemode/filter/FineractInstanceModeApiFilterTest.java @@ -0,0 +1,254 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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. + */ +package org.apache.fineract.infrastructure.instancemode.filter; + +import static org.mockito.BDDMockito.given; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.verifyNoInteractions; + +import java.io.IOException; +import java.io.PrintWriter; +import javax.servlet.FilterChain; +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import org.apache.fineract.infrastructure.core.config.FineractProperties; +import org.apache.hc.core5.http.HttpStatus; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; +import org.mockito.junit.jupiter.MockitoSettings; +import org.mockito.quality.Strictness; +import org.springframework.http.HttpMethod; + +@ExtendWith(MockitoExtension.class) +@MockitoSettings(strictness = Strictness.LENIENT) +class FineractInstanceModeApiFilterTest { + + @Mock + private FineractProperties fineractProperties; + + @Mock + private HttpServletRequest request; + + @Mock + private HttpServletResponse response; + + @Mock + private FilterChain filterChain; + + @Mock + private PrintWriter outputWriter; + + @InjectMocks + private FineractInstanceModeApiFilter underTest; + + @BeforeEach + void setUp() throws IOException { + given(response.getWriter()).willReturn(outputWriter); + } + + @Test + void testDoFilterInternal_ShouldLetReadApisThrough_WhenFineractIsInAllModeAndIsGetApi() throws ServletException, IOException { + // given + FineractProperties.FineractModeProperties modeProperties = createModeProps(true, true, true); + given(fineractProperties.getMode()).willReturn(modeProperties); + given(request.getMethod()).willReturn(HttpMethod.GET.name()); + given(request.getPathInfo()).willReturn("/loans"); + // when + underTest.doFilterInternal(request, response, filterChain); + // then + verify(filterChain).doFilter(request, response); + } + + @Test + void testDoFilterInternal_ShouldLetReadApisThrough_WhenFineractIsInReadOnlyModeAndIsGetApi() throws ServletException, IOException { + // given + FineractProperties.FineractModeProperties modeProperties = createModeProps(true, false, false); + given(fineractProperties.getMode()).willReturn(modeProperties); + given(request.getMethod()).willReturn(HttpMethod.GET.name()); + given(request.getPathInfo()).willReturn("/loans"); + // when + underTest.doFilterInternal(request, response, filterChain); + // then + verify(filterChain).doFilter(request, response); + } + + @Test + void testDoFilterInternal_ShouldLetActuatorApisThrough_WhenFineractIsInReadOnlyModeAndIsHealthApi() + throws ServletException, IOException { + // given + FineractProperties.FineractModeProperties modeProperties = createModeProps(true, false, false); + given(fineractProperties.getMode()).willReturn(modeProperties); + given(request.getMethod()).willReturn(HttpMethod.GET.name()); + given(request.getServletPath()).willReturn("/actuator/health"); + given(request.getPathInfo()).willReturn(null); + // when + underTest.doFilterInternal(request, response, filterChain); + // then + verify(filterChain).doFilter(request, response); + } + + @Test + void testDoFilterInternal_ShouldNotLetWriteApisThrough_WhenFineractIsInReadOnlyModeAndIsPostApi() throws ServletException, IOException { + // given + FineractProperties.FineractModeProperties modeProperties = createModeProps(true, false, false); + given(fineractProperties.getMode()).willReturn(modeProperties); + given(request.getMethod()).willReturn(HttpMethod.POST.name()); + given(request.getPathInfo()).willReturn("/loans"); + // when + underTest.doFilterInternal(request, response, filterChain); + // then + verifyNoInteractions(filterChain); + verify(response).setStatus(HttpStatus.SC_METHOD_NOT_ALLOWED); + } + + @Test + void testDoFilterInternal_ShouldNotLetBatchApisThrough_WhenFineractIsInReadOnlyModeAndIsJobsApi() throws ServletException, IOException { + // given + FineractProperties.FineractModeProperties modeProperties = createModeProps(true, false, false); + given(fineractProperties.getMode()).willReturn(modeProperties); + given(request.getMethod()).willReturn(HttpMethod.POST.name()); + given(request.getPathInfo()).willReturn("/jobs/1"); + // when + underTest.doFilterInternal(request, response, filterChain); + // then + verifyNoInteractions(filterChain); + verify(response).setStatus(HttpStatus.SC_METHOD_NOT_ALLOWED); + } + + @Test + void testDoFilterInternal_ShouldLetReadApisThrough_WhenFineractIsInWriteModeAndIsGetApi() throws ServletException, IOException { + // given + FineractProperties.FineractModeProperties modeProperties = createModeProps(false, true, false); + given(fineractProperties.getMode()).willReturn(modeProperties); + given(request.getMethod()).willReturn(HttpMethod.GET.name()); + given(request.getPathInfo()).willReturn("/loans"); + // when + underTest.doFilterInternal(request, response, filterChain); + // then + verify(filterChain).doFilter(request, response); + } + + @Test + void testDoFilterInternal_ShouldLetWriteApisThrough_WhenFineractIsInWriteModeAndIsPostApi() throws ServletException, IOException { + // given + FineractProperties.FineractModeProperties modeProperties = createModeProps(false, true, false); + given(fineractProperties.getMode()).willReturn(modeProperties); + given(request.getMethod()).willReturn(HttpMethod.POST.name()); + given(request.getPathInfo()).willReturn("/loans"); + // when + underTest.doFilterInternal(request, response, filterChain); + // then + verify(filterChain).doFilter(request, response); + } + + @Test + void testDoFilterInternal_ShouldLetWriteApisThrough_WhenFineractIsInWriteModeAndIsPutApi() throws ServletException, IOException { + // given + FineractProperties.FineractModeProperties modeProperties = createModeProps(false, true, false); + given(fineractProperties.getMode()).willReturn(modeProperties); + given(request.getMethod()).willReturn(HttpMethod.PUT.name()); + given(request.getPathInfo()).willReturn("/loans/1"); + // when + underTest.doFilterInternal(request, response, filterChain); + // then + verify(filterChain).doFilter(request, response); + } + + @Test + void testDoFilterInternal_ShouldLetActuatorApisThrough_WhenFineractIsInWriteModeAndIsHelathApi() throws ServletException, IOException { + // given + FineractProperties.FineractModeProperties modeProperties = createModeProps(false, true, false); + given(fineractProperties.getMode()).willReturn(modeProperties); + given(request.getMethod()).willReturn(HttpMethod.GET.name()); + given(request.getServletPath()).willReturn("/actuator/health"); + given(request.getPathInfo()).willReturn(null); + // when + underTest.doFilterInternal(request, response, filterChain); + // then + verify(filterChain).doFilter(request, response); + } + + @Test + void testDoFilterInternal_ShouldNotLetBatchApisThrough_WhenFineractIsInWriteModeAndIsJobsApi() throws ServletException, IOException { + // given + FineractProperties.FineractModeProperties modeProperties = createModeProps(false, true, false); + given(fineractProperties.getMode()).willReturn(modeProperties); + given(request.getMethod()).willReturn(HttpMethod.POST.name()); + given(request.getPathInfo()).willReturn("/jobs/1"); + // when + underTest.doFilterInternal(request, response, filterChain); + // then + verifyNoInteractions(filterChain); + verify(response).setStatus(HttpStatus.SC_METHOD_NOT_ALLOWED); + } + + @Test + void testDoFilterInternal_ShouldLetBatchApisThrough_WhenFineractIsInBatchModeAndIsJobsApi() throws ServletException, IOException { + // given + FineractProperties.FineractModeProperties modeProperties = createModeProps(false, false, true); + given(fineractProperties.getMode()).willReturn(modeProperties); + given(request.getMethod()).willReturn(HttpMethod.POST.name()); + given(request.getPathInfo()).willReturn("/jobs/1"); + // when + underTest.doFilterInternal(request, response, filterChain); + // then + verify(filterChain).doFilter(request, response); + } + + @Test + void testDoFilterInternal_ShouldLetBatchApisThrough_WhenFineractIsInBatchModeAndIsListingJobsApi() + throws ServletException, IOException { + // given + FineractProperties.FineractModeProperties modeProperties = createModeProps(false, false, true); + given(fineractProperties.getMode()).willReturn(modeProperties); + given(request.getMethod()).willReturn(HttpMethod.GET.name()); + given(request.getPathInfo()).willReturn("/jobs"); + // when + underTest.doFilterInternal(request, response, filterChain); + // then + verify(filterChain).doFilter(request, response); + } + + @Test + void testDoFilterInternal_ShouldLetActuatorApisThrough_WhenFineractIsInBatchModeAndIsHealthApi() throws ServletException, IOException { + // given + FineractProperties.FineractModeProperties modeProperties = createModeProps(false, false, true); + given(fineractProperties.getMode()).willReturn(modeProperties); + given(request.getMethod()).willReturn(HttpMethod.GET.name()); + given(request.getServletPath()).willReturn("/actuator/health"); + given(request.getPathInfo()).willReturn(null); + // when + underTest.doFilterInternal(request, response, filterChain); + // then + verify(filterChain).doFilter(request, response); + } + + private FineractProperties.FineractModeProperties createModeProps(boolean readEnabled, boolean writeEnabled, boolean batchEnabled) { + FineractProperties.FineractModeProperties modeProperties = new FineractProperties.FineractModeProperties(); + modeProperties.setReadEnabled(readEnabled); + modeProperties.setWriteEnabled(writeEnabled); + modeProperties.setBatchEnabled(batchEnabled); + return modeProperties; + } +} diff --git a/integration-tests/build.gradle b/integration-tests/build.gradle index 486299f29..060d317e7 100644 --- a/integration-tests/build.gradle +++ b/integration-tests/build.gradle @@ -75,6 +75,7 @@ cargo { } else { jvmArgs += '-Dspring.datasource.hikari.driverClassName=org.mariadb.jdbc.Driver -Dspring.datasource.hikari.jdbcUrl=jdbc:mariadb://localhost:3306/fineract_tenants -Dspring.datasource.hikari.username=root -Dspring.datasource.hikari.password=mysql -Dfineract.tenant.host=localhost -Dfineract.tenant.port=3306 -Dfineract.tenant.username=root -Dfineract.tenant.password=mysql' } + jvmArgs += ' -Dspring.profiles.active=test' property 'cargo.start.jvmargs', jvmArgs property 'cargo.tomcat.connector.keystoreFile', file("$rootDir/fineract-provider/src/main/resources/keystore.jks") property 'cargo.tomcat.connector.keystorePass', 'openmf' diff --git a/integration-tests/src/test/java/org/apache/fineract/integrationtests/InstanceModeIntegrationTest.java b/integration-tests/src/test/java/org/apache/fineract/integrationtests/InstanceModeIntegrationTest.java new file mode 100644 index 000000000..471e0e32e --- /dev/null +++ b/integration-tests/src/test/java/org/apache/fineract/integrationtests/InstanceModeIntegrationTest.java @@ -0,0 +1,149 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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. + */ +package org.apache.fineract.integrationtests; + +import static org.junit.jupiter.api.Assertions.assertNotNull; + +import io.restassured.builder.RequestSpecBuilder; +import io.restassured.builder.ResponseSpecBuilder; +import io.restassured.http.ContentType; +import io.restassured.specification.RequestSpecification; +import io.restassured.specification.ResponseSpecification; +import org.apache.fineract.client.models.GetOfficesResponse; +import org.apache.fineract.client.models.PostClientsRequest; +import org.apache.fineract.integrationtests.common.ClientHelper; +import org.apache.fineract.integrationtests.common.OfficeHelper; +import org.apache.fineract.integrationtests.common.SchedulerJobHelper; +import org.apache.fineract.integrationtests.common.Utils; +import org.apache.fineract.integrationtests.support.instancemode.ConfigureInstanceMode; +import org.apache.fineract.integrationtests.support.instancemode.InstanceModeSupportExtension; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; + +@ExtendWith(InstanceModeSupportExtension.class) +public class InstanceModeIntegrationTest { + + private ResponseSpecification responseSpec200; + private ResponseSpecification responseSpec405; + private RequestSpecification requestSpec; + private SchedulerJobHelper schedulerJobHelper; + private int jobId; + + @BeforeEach + public void setup() throws InterruptedException { + Utils.initializeRESTAssured(); + + requestSpec = new RequestSpecBuilder().setContentType(ContentType.JSON).build(); + requestSpec.header("Authorization", "Basic " + Utils.loginIntoServerAndGetBase64EncodedAuthenticationKey()); + responseSpec200 = new ResponseSpecBuilder().expectStatusCode(200).build(); + responseSpec405 = new ResponseSpecBuilder().expectStatusCode(405).build(); + + schedulerJobHelper = new SchedulerJobHelper(requestSpec); + String jobName = "Apply Annual Fee For Savings"; + jobId = schedulerJobHelper.getSchedulerJobIdByName(jobName); + } + + @ConfigureInstanceMode(readEnabled = true, writeEnabled = false, batchEnabled = false) + @Test + public void testGetHeadOfficeWorks_WhenInstanceModeIsReadOnly() { + // given + // when + GetOfficesResponse result = OfficeHelper.getHeadOffice(requestSpec, responseSpec200); + // then + assertNotNull(result); + } + + @ConfigureInstanceMode(readEnabled = false, writeEnabled = true, batchEnabled = false) + @Test + public void testGetHeadOfficeWorks_WhenInstanceModeIsWriteOnly() { + // given + // when + GetOfficesResponse result = OfficeHelper.getHeadOffice(requestSpec, responseSpec200); + // then + assertNotNull(result); + } + + @ConfigureInstanceMode(readEnabled = false, writeEnabled = false, batchEnabled = true) + @Test + public void testGetHeadOfficeDoesntWork_WhenInstanceModeIsBatchOnly() { + // given + // when + OfficeHelper.getHeadOffice(requestSpec, responseSpec405); + // then no exception is thrown + } + + @ConfigureInstanceMode(readEnabled = true, writeEnabled = false, batchEnabled = false) + @Test + public void testCreateClientDoesntWork_WhenReadOnly() { + // given + PostClientsRequest request = ClientHelper.defaultClientCreationRequest(); + // when + ClientHelper.createClient(requestSpec, responseSpec405, request); + // then no exception thrown + } + + @ConfigureInstanceMode(readEnabled = false, writeEnabled = true, batchEnabled = false) + @Test + public void testCreateClientWorks_WhenWriteOnly() { + // given + PostClientsRequest request = ClientHelper.defaultClientCreationRequest(); + // when + Integer result = ClientHelper.createClient(requestSpec, responseSpec200, request); + // then + assertNotNull(result); + } + + @ConfigureInstanceMode(readEnabled = false, writeEnabled = false, batchEnabled = true) + @Test + public void testCreateClientDoesntWork_WhenBatchOnly() { + // given + PostClientsRequest request = ClientHelper.defaultClientCreationRequest(); + // when + ClientHelper.createClient(requestSpec, responseSpec405, request); + // then no exception thrown + } + + @ConfigureInstanceMode(readEnabled = true, writeEnabled = false, batchEnabled = false) + @Test + public void testRunSchedulerJobDoesntWork_WhenReadOnly() { + // given + // when + schedulerJobHelper.runSchedulerJob(jobId, responseSpec405); + // then no exception thrown + } + + @ConfigureInstanceMode(readEnabled = false, writeEnabled = true, batchEnabled = false) + @Test + public void testRunSchedulerJobDoesntWork_WhenWriteOnly() { + // given + // when + schedulerJobHelper.runSchedulerJob(jobId, responseSpec405); + // then no exception thrown + } + + @ConfigureInstanceMode(readEnabled = false, writeEnabled = false, batchEnabled = true) + @Test + public void testRunSchedulerJobWorks_WhenBatchOnly() { + // given + // when + schedulerJobHelper.runSchedulerJob(jobId); + // then no exception thrown + } +} diff --git a/integration-tests/src/test/java/org/apache/fineract/integrationtests/common/SchedulerJobHelper.java b/integration-tests/src/test/java/org/apache/fineract/integrationtests/common/SchedulerJobHelper.java index 3e929a696..6d6155afc 100644 --- a/integration-tests/src/test/java/org/apache/fineract/integrationtests/common/SchedulerJobHelper.java +++ b/integration-tests/src/test/java/org/apache/fineract/integrationtests/common/SchedulerJobHelper.java @@ -113,8 +113,12 @@ public class SchedulerJobHelper { return new Gson().toJson(map); } - private void runSchedulerJob(int jobId) { + public void runSchedulerJob(int jobId) { final ResponseSpecification responseSpec = new ResponseSpecBuilder().expectStatusCode(202).build(); + runSchedulerJob(jobId, responseSpec); + } + + public void runSchedulerJob(int jobId, ResponseSpecification responseSpec) { final String RUN_SCHEDULER_JOB_URL = "/fineract-provider/api/v1/jobs/" + jobId + "?command=executeJob&" + Utils.TENANT_IDENTIFIER; LOG.info("------------------------ RUN SCHEDULER JOB -------------------------"); Utils.performServerPost(requestSpec, responseSpec, RUN_SCHEDULER_JOB_URL, runSchedulerJobAsJSON(), null); @@ -127,7 +131,7 @@ public class SchedulerJobHelper { return runSchedulerJob; } - private int getSchedulerJobIdByName(String jobName) { + public int getSchedulerJobIdByName(String jobName) { List> allSchedulerJobsData = getAllSchedulerJobs(); for (Integer jobIndex = 0; jobIndex < allSchedulerJobsData.size(); jobIndex++) { if (allSchedulerJobsData.get(jobIndex).get("displayName").equals(jobName)) { diff --git a/integration-tests/src/test/java/org/apache/fineract/integrationtests/common/Utils.java b/integration-tests/src/test/java/org/apache/fineract/integrationtests/common/Utils.java index 69f841105..32b1d1caf 100644 --- a/integration-tests/src/test/java/org/apache/fineract/integrationtests/common/Utils.java +++ b/integration-tests/src/test/java/org/apache/fineract/integrationtests/common/Utils.java @@ -204,10 +204,18 @@ public final class Utils { return (T) JsonPath.from(json).get(jsonAttributeToGetBack); } + public static String performServerPut(final RequestSpecification requestSpec, final ResponseSpecification responseSpec, + final String putURL, final String jsonBodyToSend) { + return performServerPut(requestSpec, responseSpec, putURL, jsonBodyToSend, null); + } + public static T performServerPut(final RequestSpecification requestSpec, final ResponseSpecification responseSpec, final String putURL, final String jsonBodyToSend, final String jsonAttributeToGetBack) { final String json = given().spec(requestSpec).body(jsonBodyToSend).expect().spec(responseSpec).log().ifError().when().put(putURL) .andReturn().asString(); + if (jsonAttributeToGetBack == null) { + return (T) json; + } return (T) JsonPath.from(json).get(jsonAttributeToGetBack); } diff --git a/integration-tests/src/test/java/org/apache/fineract/integrationtests/support/instancemode/ConfigureInstanceMode.java b/integration-tests/src/test/java/org/apache/fineract/integrationtests/support/instancemode/ConfigureInstanceMode.java new file mode 100644 index 000000000..23bea907f --- /dev/null +++ b/integration-tests/src/test/java/org/apache/fineract/integrationtests/support/instancemode/ConfigureInstanceMode.java @@ -0,0 +1,36 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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. + */ +package org.apache.fineract.integrationtests.support.instancemode; + +import static java.lang.annotation.ElementType.METHOD; +import static java.lang.annotation.RetentionPolicy.RUNTIME; + +import java.lang.annotation.Retention; +import java.lang.annotation.Target; + +@Retention(RUNTIME) +@Target({ METHOD }) +public @interface ConfigureInstanceMode { + + boolean readEnabled(); + + boolean writeEnabled(); + + boolean batchEnabled(); +} diff --git a/integration-tests/src/test/java/org/apache/fineract/integrationtests/support/instancemode/InstanceModeHelper.java b/integration-tests/src/test/java/org/apache/fineract/integrationtests/support/instancemode/InstanceModeHelper.java new file mode 100644 index 000000000..e628f1780 --- /dev/null +++ b/integration-tests/src/test/java/org/apache/fineract/integrationtests/support/instancemode/InstanceModeHelper.java @@ -0,0 +1,40 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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. + */ +package org.apache.fineract.integrationtests.support.instancemode; + +import com.google.gson.Gson; +import io.restassured.specification.RequestSpecification; +import io.restassured.specification.ResponseSpecification; +import org.apache.fineract.client.models.ChangeInstanceModeRequest; +import org.apache.fineract.client.util.JSON; +import org.apache.fineract.integrationtests.common.Utils; + +@SuppressWarnings({ "HideUtilityClassConstructor" }) +public class InstanceModeHelper { + + private static final Gson GSON = new JSON().getGson(); + + public static void changeMode(RequestSpecification requestSpec, ResponseSpecification responseSpec, boolean readEnabled, + boolean writeEnabled, boolean batchEnabled) { + ChangeInstanceModeRequest request = new ChangeInstanceModeRequest().readEnabled(readEnabled).writeEnabled(writeEnabled) + .batchEnabled(batchEnabled); + String requestStr = GSON.toJson(request); + Utils.performServerPut(requestSpec, responseSpec, "/fineract-provider/api/v1/instance-mode?" + Utils.TENANT_IDENTIFIER, requestStr); + } +} diff --git a/integration-tests/src/test/java/org/apache/fineract/integrationtests/support/instancemode/InstanceModeSupportExtension.java b/integration-tests/src/test/java/org/apache/fineract/integrationtests/support/instancemode/InstanceModeSupportExtension.java new file mode 100644 index 000000000..c8f50d80a --- /dev/null +++ b/integration-tests/src/test/java/org/apache/fineract/integrationtests/support/instancemode/InstanceModeSupportExtension.java @@ -0,0 +1,71 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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. + */ +package org.apache.fineract.integrationtests.support.instancemode; + +import io.restassured.builder.RequestSpecBuilder; +import io.restassured.builder.ResponseSpecBuilder; +import io.restassured.http.ContentType; +import io.restassured.specification.RequestSpecification; +import io.restassured.specification.ResponseSpecification; +import org.apache.fineract.integrationtests.common.Utils; +import org.junit.jupiter.api.extension.AfterTestExecutionCallback; +import org.junit.jupiter.api.extension.BeforeTestExecutionCallback; +import org.junit.jupiter.api.extension.ExtensionContext; +import org.junit.jupiter.api.extension.ExtensionContext.Namespace; +import org.junit.jupiter.api.extension.ExtensionContext.Store; + +public class InstanceModeSupportExtension implements BeforeTestExecutionCallback, AfterTestExecutionCallback { + + private static final Namespace INSTANCE_MODE_NAMESPACE = Namespace.create(InstanceModeSupportExtension.class); + private static final String AUTH_KEY = "AUTH_KEY"; + + @Override + public void beforeTestExecution(ExtensionContext context) throws Exception { + context.getTestMethod().ifPresent(m -> { + ConfigureInstanceMode annotation = m.getAnnotation(ConfigureInstanceMode.class); + if (annotation != null) { + boolean readEnabled = annotation.readEnabled(); + boolean writeEnabled = annotation.writeEnabled(); + boolean batchEnabled = annotation.batchEnabled(); + changeInstanceMode(context, readEnabled, writeEnabled, batchEnabled); + } + }); + } + + @Override + public void afterTestExecution(ExtensionContext context) throws Exception { + context.getTestMethod().ifPresent(m -> { + ConfigureInstanceMode annotation = m.getAnnotation(ConfigureInstanceMode.class); + if (annotation != null) { + changeInstanceMode(context, true, true, true); + } + }); + } + + private void changeInstanceMode(ExtensionContext extensionContext, boolean readEnabled, boolean writeEnabled, boolean batchEnabled) { + Store store = extensionContext.getStore(INSTANCE_MODE_NAMESPACE); + String authKey = store.getOrComputeIfAbsent(AUTH_KEY, k -> Utils.loginIntoServerAndGetBase64EncodedAuthenticationKey(), + String.class); + RequestSpecification requestSpec = new RequestSpecBuilder().setContentType(ContentType.JSON).build(); + ResponseSpecification responseSpec = new ResponseSpecBuilder().expectStatusCode(200).build(); + requestSpec.header("Authorization", "Basic " + authKey); + + InstanceModeHelper.changeMode(requestSpec, responseSpec, readEnabled, writeEnabled, batchEnabled); + } +} diff --git a/settings.gradle b/settings.gradle index f187c6b21..4fb8b3b67 100644 --- a/settings.gradle +++ b/settings.gradle @@ -25,7 +25,6 @@ include ':fineract-provider' include ':fineract-war' include ':integration-tests' include ':twofactor-tests' -include ':instancemode-tests' include ':oauth2-tests' include ':fineract-client' include ':fineract-doc'