diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 5a2d55a00c2..46211efdbf5 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -85,6 +85,8 @@ jobs: run: npm i -g typescript - name: Maven Build run: mvn -T 1C clean install -D maven.test.skip=true -D skipTests -D maven.javadoc.skip=true -D license.skip=true -U + - if: runner.os == 'Windows' + run: Set-DisplayResolution -Width 1920 -Height 1080 -Force - name: Integration tests run: mvn -f tests/pom.xml verify -P integration-tests - name: Upload selenide screenshots @@ -94,3 +96,58 @@ jobs: retention-days: 1 name: selenide-screenshots path: tests/build/reports/tests + + integration-tests-spring-boot: + runs-on: ${{ matrix.os }}-latest + continue-on-error: true + strategy: + matrix: + os: [windows] + steps: + - name: Setup Chrome + uses: browser-actions/setup-chrome@v1.3.0 + with: + chrome-version: stable + - if: runner.os == 'Linux' + run: chrome --version + - if: runner.os == 'macOS' + run: chromium --version + - if: runner.os == 'Windows' + run: (Get-Item (Get-Command chrome).Source).VersionInfo.ProductVersion + - uses: actions/checkout@v3 + with: + fetch-depth: 0 + - name: Cache local Maven repository + uses: actions/cache@v3 + with: + path: ~/.m2/repository + key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }} + restore-keys: ${{ runner.os }}-maven- + - name: Set up JDK Corretto 21 + uses: actions/setup-java@v3 + with: + distribution: 'corretto' + java-version: '21' + architecture: x64 + - name: Install NodeJS + uses: actions/setup-node@v3 + with: + node-version: 18 + - name: Install esbuild + run: npm i -g esbuild + - name: Install TypeScript compiler + run: npm i -g typescript + - name: Maven Build + run: mvn -T 1C clean install -P spring-boot-admin -D maven.test.skip=true -D skipTests -D maven.javadoc.skip=true -D license.skip=true -U + - if: runner.os == 'Windows' + run: Set-DisplayResolution -Width 1920 -Height 1080 -Force + - name: Integration tests + run: mvn -f tests/pom.xml verify -P integration-tests-spring-boot-admin -D spring.profiles.active=spring-boot-admin + - name: Upload selenide screenshots + uses: actions/upload-artifact@v3.1.3 + if: always() + with: + retention-days: 1 + name: selenide-screenshots-spring-boot + path: tests/build/reports/tests + \ No newline at end of file diff --git a/.github/workflows/pull-request.yml b/.github/workflows/pull-request.yml index dcb90ec55a3..7132b605dbe 100644 --- a/.github/workflows/pull-request.yml +++ b/.github/workflows/pull-request.yml @@ -83,6 +83,8 @@ jobs: run: npm i -g typescript - name: Maven Build run: mvn -T 1C clean install -D maven.test.skip=true -D skipTests -D maven.javadoc.skip=true -D license.skip=true -U + - if: runner.os == 'Windows' + run: Set-DisplayResolution -Width 1920 -Height 1080 -Force - name: Integration tests run: mvn -f tests/pom.xml verify -P integration-tests - name: Upload selenide screenshots @@ -92,3 +94,56 @@ jobs: retention-days: 1 name: selenide-screenshots path: tests/build/reports/tests + + integration-tests-spring-boot: + runs-on: ${{ matrix.os }}-latest + continue-on-error: true + strategy: + matrix: + os: [windows] + steps: + - name: Setup Chrome + uses: browser-actions/setup-chrome@v1.3.0 + with: + chrome-version: stable + - if: runner.os == 'Linux' + run: chrome --version + - if: runner.os == 'macOS' + run: chromium --version + - if: runner.os == 'Windows' + run: (Get-Item (Get-Command chrome).Source).VersionInfo.ProductVersion + - uses: actions/checkout@v3 + with: + fetch-depth: 0 + - name: Cache local Maven repository + uses: actions/cache@v3 + with: + path: ~/.m2/repository + key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }} + restore-keys: ${{ runner.os }}-maven- + - name: Set up JDK Corretto 21 + uses: actions/setup-java@v3 + with: + distribution: 'corretto' + java-version: 21 + - name: Install NodeJS + uses: actions/setup-node@v3 + with: + node-version: 18 + - name: Install esbuild + run: npm i -g esbuild + - name: Install TypeScript compiler + run: npm i -g typescript + - name: Maven Build + run: mvn -T 1C clean install -P spring-boot-admin -D maven.test.skip=true -D skipTests -D maven.javadoc.skip=true -D license.skip=true -U + - if: runner.os == 'Windows' + run: Set-DisplayResolution -Width 1920 -Height 1080 -Force + - name: Integration tests + run: mvn -f tests/pom.xml verify -P integration-tests-spring-boot-admin -D spring.profiles.active=spring-boot-admin + - name: Upload selenide screenshots + uses: actions/upload-artifact@v3.1.3 + if: always() + with: + retention-days: 1 + name: selenide-screenshots-spring-boot + path: tests/build/reports/tests diff --git a/README.md b/README.md index e7ae599512f..d87a18402f4 100644 --- a/README.md +++ b/README.md @@ -36,8 +36,9 @@ The project started as an internal SAP initiative to address the extension and a - [Run](#run) - [Standalone](#standalone) - [Docker](#docker) - - [Native image](#native-image) - - [Code formatting](#code-formatting) + - [Native image](#native-image) + - [Code formatting](#code-formatting) + - [Spring Boot Admin](#spring-boot-admin) - [Additional Information](#additional-information) - [License](#license) - [Contributors](#contributors) @@ -258,6 +259,15 @@ To format the code using Maven execute the following in the root dir of the proj mvn formatter:format +### Spring Boot Admin +If you want to enable [Spring Boot Admin](https://docs.spring-boot-admin.com/current/) for the Dirigible project, you need to build the project with maven profile `spring-boot-admin` and then activate spring profile `spring-boot-admin`. +To do this, you have to execute the following commands: +``` +mvn -T 1C clean install -P spring-boot-admin -D maven.test.skip=true -D skipTests -D maven.javadoc.skip=true -D license.skip=true + +java -jar -Dspring.profiles.active=spring-boot-admin build/application/target/dirigible-application-*-executable.jar +``` + ## Additional Information ### License diff --git a/build/application/pom.xml b/build/application/pom.xml index b340b0f6331..79b4aaff8f4 100644 --- a/build/application/pom.xml +++ b/build/application/pom.xml @@ -228,6 +228,12 @@ runtime true + + de.codecentric + spring-boot-admin-starter-server + ${spring.admin.version} + provided + @@ -290,4 +296,28 @@ ../../ - \ No newline at end of file + + + default + + true + + + + spring-boot-admin + + + de.codecentric + spring-boot-admin-starter-server + ${spring.admin.version} + + + de.codecentric + spring-boot-admin-starter-client + ${spring.admin.version} + + + + + + diff --git a/build/application/src/main/java/org/eclipse/dirigible/DirigibleApplication.java b/build/application/src/main/java/org/eclipse/dirigible/DirigibleApplication.java index bea1b5f4c26..967be3d6023 100644 --- a/build/application/src/main/java/org/eclipse/dirigible/DirigibleApplication.java +++ b/build/application/src/main/java/org/eclipse/dirigible/DirigibleApplication.java @@ -23,7 +23,9 @@ import org.springframework.data.jpa.repository.config.EnableJpaRepositories; import org.springframework.scheduling.annotation.EnableScheduling; import org.springframework.web.client.RestTemplate; +import de.codecentric.boot.admin.server.config.EnableAdminServer; +@EnableAdminServer @EnableJpaAuditing @EnableJpaRepositories @SpringBootApplication diff --git a/build/application/src/main/resources/application-spring-boot-admin.properties b/build/application/src/main/resources/application-spring-boot-admin.properties new file mode 100644 index 00000000000..d4f76689673 --- /dev/null +++ b/build/application/src/main/resources/application-spring-boot-admin.properties @@ -0,0 +1,9 @@ +spring.boot.admin.context-path=spring-admin +spring.boot.admin.ui.title=${spring.application.name} Admin +spring.boot.admin.ui.brand=Eclipse Dirigible Admin + +spring.boot.admin.client.url=http://localhost:${server.port}/spring-admin +spring.boot.admin.client.username=${DIRIGIBLE_SPRING_ADMIN_USERNAME:admin} +spring.boot.admin.client.password=${DIRIGIBLE_SPRING_ADMIN_PASSWORD:admin} +spring.boot.admin.client.instance.metadata.user.name=${spring.boot.admin.client.username} +spring.boot.admin.client.instance.metadata.user.password=${spring.boot.admin.client.password} diff --git a/build/application/src/main/resources/application.properties b/build/application/src/main/resources/application.properties index 6cfddf3e49e..b869429f59d 100644 --- a/build/application/src/main/resources/application.properties +++ b/build/application/src/main/resources/application.properties @@ -1,5 +1,9 @@ +spring.application.name=Eclipse Dirigible + spring.main.allow-bean-definition-overriding=true + server.error.include-message=always +server.port=8080 spring.servlet.multipart.enabled=true spring.servlet.multipart.file-size-threshold=2KB @@ -20,4 +24,8 @@ management.metrics.mongo.connectionpool.enabled=false spring.devtools.restart.poll-interval=6s spring.devtools.restart.quiet-period=5s +management.endpoints.web.exposure.include=camelroutes,mappings,caches,configprops,camelroutes,metrics,threaddump,heapdump,loggers,health,quartz,scheduledtasks,env,beans,conditions,info +management.endpoints.health.show-details=always + cxf.path=/odata/v2 + diff --git a/build/application/src/main/resources/dirigible.properties b/build/application/src/main/resources/dirigible.properties index bdb08d8d7f3..41bcd7aa6f4 100644 --- a/build/application/src/main/resources/dirigible.properties +++ b/build/application/src/main/resources/dirigible.properties @@ -19,4 +19,6 @@ DIRIGIBLE_DATABASE_PROVIDER=local DIRIGIBLE_JAVASCRIPT_HANDLER_CLASS_NAME=org.eclipse.dirigible.graalium.handler.GraaliumJavascriptHandler DIRIGIBLE_GRAALIUM_ENABLE_DEBUG=true DIRIGIBLE_HOME_URL=services/web/ide/ -DIRIGIBLE_DATABASE_NAMES_CASE_SENSITIVE=true \ No newline at end of file +DIRIGIBLE_DATABASE_NAMES_CASE_SENSITIVE=true +DIRIGIBLE_SPRING_ADMIN_USERNAME=admin +DIRIGIBLE_SPRING_ADMIN_PASSWORD=admin \ No newline at end of file diff --git a/components/core/core-base/src/main/java/org/eclipse/dirigible/components/base/http/access/DirigibleRole.java b/components/core/core-base/src/main/java/org/eclipse/dirigible/components/base/http/access/DirigibleRole.java new file mode 100644 index 00000000000..2c8ab8398c6 --- /dev/null +++ b/components/core/core-base/src/main/java/org/eclipse/dirigible/components/base/http/access/DirigibleRole.java @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2023 SAP SE or an SAP affiliate company and Eclipse Dirigible contributors + * + * All rights reserved. This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v2.0 which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v20.html + * + * SPDX-FileCopyrightText: 2023 SAP SE or an SAP affiliate company and Eclipse Dirigible + * contributors SPDX-License-Identifier: EPL-2.0 + */ +package org.eclipse.dirigible.components.base.http.access; + +public enum DirigibleRole { + + DEVELOPER(RoleNames.DEVELOPER), OPERATOR(RoleNames.OPERATOR); + + private final String roleName; + + DirigibleRole(String roleName) { + this.roleName = roleName; + } + + public String getName() { + return roleName; + } + + @SuppressWarnings("hiding") + public static class RoleNames { + public static final String OPERATOR = "Operator"; + public static final String DEVELOPER = "Developer"; + + } +} diff --git a/components/core/core-base/src/main/java/org/eclipse/dirigible/components/base/http/access/HttpSecurityURIConfigurator.java b/components/core/core-base/src/main/java/org/eclipse/dirigible/components/base/http/access/HttpSecurityURIConfigurator.java index 268d6e3f273..7bb329c2b7b 100644 --- a/components/core/core-base/src/main/java/org/eclipse/dirigible/components/base/http/access/HttpSecurityURIConfigurator.java +++ b/components/core/core-base/src/main/java/org/eclipse/dirigible/components/base/http/access/HttpSecurityURIConfigurator.java @@ -37,7 +37,7 @@ public class HttpSecurityURIConfigurator { "/services/js/resources-core/**", // "/services/js/resources-core/**", // "/services/integrations/**", // - "/actuator/**"}; + "/actuator/health"}; private static final String[] AUTHENTICATED_PATTERNS = {// "/services/**", // @@ -51,6 +51,10 @@ public class HttpSecurityURIConfigurator { "/services/ide/**", // "/websockets/ide/**"}; + private static final String[] OPERATOR_PATTERNS = {// + "/spring-admin/**", // + "/actuator/**"}; + /** * Configure. * @@ -68,7 +72,11 @@ public static void configure(HttpSecurity http) throws Exception { // "Developer" role required .requestMatchers(DEVELOPER_PATTERNS) - .hasRole("Developer") + .hasRole(DirigibleRole.DEVELOPER.getName()) + + // Spring Boot Admin + .requestMatchers(OPERATOR_PATTERNS) + .hasRole(DirigibleRole.OPERATOR.getName()) // Deny all other requests .anyRequest() diff --git a/components/security/security-basic/src/main/java/org/eclipse/dirigible/components/security/basic/BasicAuthSecurityConfiguration.java b/components/security/security-basic/src/main/java/org/eclipse/dirigible/components/security/basic/BasicAuthSecurityConfiguration.java index 7af63cfd9cc..b9bdd1b2dcd 100644 --- a/components/security/security-basic/src/main/java/org/eclipse/dirigible/components/security/basic/BasicAuthSecurityConfiguration.java +++ b/components/security/security-basic/src/main/java/org/eclipse/dirigible/components/security/basic/BasicAuthSecurityConfiguration.java @@ -13,6 +13,7 @@ import java.nio.charset.StandardCharsets; import java.util.Arrays; import org.apache.commons.codec.binary.Base64; +import org.eclipse.dirigible.components.base.http.access.DirigibleRole; import org.eclipse.dirigible.components.base.http.access.HttpSecurityURIConfigurator; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.context.annotation.Bean; @@ -51,7 +52,7 @@ InMemoryUserDetailsManager userDetailsService() { String password = org.eclipse.dirigible.commons.config.Configuration.get("DIRIGIBLE_BASIC_PASSWORD", "YWRtaW4="); // admin UserDetails user = User.withUsername(new String(new Base64().decode(username.getBytes()), StandardCharsets.UTF_8).trim()) .password("{noop}" + new String(new Base64().decode(password.getBytes()), StandardCharsets.UTF_8).trim()) - .roles("DEVELOPER", "OPERATOR") + .roles(DirigibleRole.DEVELOPER.getName(), DirigibleRole.OPERATOR.getName()) .build(); return new InMemoryUserDetailsManager(user); } diff --git a/pom.xml b/pom.xml index 787b567e8b5..1213e3068f4 100644 --- a/pom.xml +++ b/pom.xml @@ -114,6 +114,8 @@ 4.3 3.2.0 + 3.1.8 + 1.7.0 0.9.5.5 23.1.1 @@ -699,5 +701,4 @@ - - + \ No newline at end of file diff --git a/tests/pom.xml b/tests/pom.xml index 69b94d7a499..22706b5394b 100644 --- a/tests/pom.xml +++ b/tests/pom.xml @@ -43,6 +43,11 @@ ${selenide.version} test + + org.junit.jupiter + junit-jupiter-params + test + @@ -114,6 +119,52 @@ false + + + + org.apache.maven.plugins + maven-failsafe-plugin + + + **/SpringBootAdminIT.java + + + + + + + + integration-tests-spring-boot-admin + + false + + + + de.codecentric + spring-boot-admin-starter-server + ${spring.admin.version} + test + + + de.codecentric + spring-boot-admin-starter-client + ${spring.admin.version} + test + + + + + + org.apache.maven.plugins + maven-failsafe-plugin + + + **/SpringBootAdminIT.java + + + + + Windows 11 diff --git a/tests/src/test/java/org/eclipse/dirigible/integration/tests/IntegrationTest.java b/tests/src/test/java/org/eclipse/dirigible/integration/tests/IntegrationTest.java index 0ef7f2351eb..282aa48242e 100644 --- a/tests/src/test/java/org/eclipse/dirigible/integration/tests/IntegrationTest.java +++ b/tests/src/test/java/org/eclipse/dirigible/integration/tests/IntegrationTest.java @@ -15,11 +15,15 @@ import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.boot.test.context.SpringBootTest.WebEnvironment; +import org.springframework.test.annotation.DirtiesContext; +import org.springframework.test.annotation.DirtiesContext.ClassMode; import org.springframework.test.context.junit4.SpringRunner; + +@AutoConfigureMockMvc @RunWith(SpringRunner.class) +@DirtiesContext(classMode = ClassMode.AFTER_CLASS) @SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT, classes = DirigibleApplication.class) -@AutoConfigureMockMvc public abstract class IntegrationTest { // base class for integration tests } diff --git a/tests/src/test/java/org/eclipse/dirigible/integration/tests/api/SecurityIT.java b/tests/src/test/java/org/eclipse/dirigible/integration/tests/api/SecurityIT.java new file mode 100644 index 00000000000..aff4853881d --- /dev/null +++ b/tests/src/test/java/org/eclipse/dirigible/integration/tests/api/SecurityIT.java @@ -0,0 +1,91 @@ +/* + * Copyright (c) 2023 SAP SE or an SAP affiliate company and Eclipse Dirigible contributors + * + * All rights reserved. This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v2.0 which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v20.html + * + * SPDX-FileCopyrightText: 2023 SAP SE or an SAP affiliate company and Eclipse Dirigible + * contributors SPDX-License-Identifier: EPL-2.0 + */ +package org.eclipse.dirigible.integration.tests.api; + +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; +import java.util.stream.Stream; +import org.eclipse.dirigible.DirigibleApplication; +import org.eclipse.dirigible.components.base.http.access.DirigibleRole.RoleNames; +import org.eclipse.dirigible.integration.tests.IntegrationTest; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; +import org.junit.jupiter.params.provider.ValueSource; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.test.context.SpringBootTest.WebEnvironment; +import org.springframework.http.HttpStatus; +import org.springframework.security.test.context.support.WithMockUser; +import org.springframework.test.web.servlet.MockMvc; + +@SpringBootTest(webEnvironment = WebEnvironment.MOCK, classes = DirigibleApplication.class) +class SecurityIT extends IntegrationTest { + + @Autowired + private MockMvc mvc; + + @ParameterizedTest + @MethodSource("providePublicEndpointsParams") + void testPublicEndpoint(String path, HttpStatus expectedStatusCode) throws Exception { + mvc.perform(get(path)) + .andExpect(status().is(expectedStatusCode.value())); + } + + private static Stream providePublicEndpointsParams() { + return Stream.of(// + Arguments.of("/actuator/health", HttpStatus.OK), // + Arguments.of("/login", HttpStatus.OK), // + Arguments.of("/error.html", HttpStatus.OK)); + } + + @ParameterizedTest + @ValueSource(strings = {"/spring-admin", "/actuator/info"}) + void testProtectedEndpointWithoutUnauthenticatedRequest(String path) throws Exception { + mvc.perform(get(path)) + .andExpect(status().isUnauthorized()); + } + + @ParameterizedTest + @ValueSource(strings = {"/actuator/info"}) + @WithMockUser(username = "user_without_roles", roles = {"SOME_UNUSED_ROLE"}) + void testProtectedEndpointsWithUnauthorizedUser(String path) throws Exception { + mvc.perform(get(path)) + .andExpect(status().isForbidden()); + } + + @ParameterizedTest + @MethodSource("provideOperatorEndpointsParams") + @WithMockUser(username = "operator", roles = {RoleNames.OPERATOR}) + void testOperatorEndpointIsAccessible(String path, HttpStatus expectedStatusCode) throws Exception { + mvc.perform(get(path)) + .andExpect(status().is(expectedStatusCode.value())); + } + + private static Stream provideOperatorEndpointsParams() { + return Stream.of(Arguments.of("/spring-admin", HttpStatus.NOT_FOUND), // + Arguments.of("/actuator/info", HttpStatus.OK)); + } + + @ParameterizedTest + @MethodSource("provideDeveloperEndpointsParams") + @WithMockUser(username = "developer", roles = {RoleNames.DEVELOPER}) + void testDeveloperEndpointIsAccessible(String path, HttpStatus expectedStatusCode) throws Exception { + mvc.perform(get(path)) + .andExpect(status().is(expectedStatusCode.value())); + } + + private static Stream provideDeveloperEndpointsParams() { + return Stream.of(Arguments.of("/services/ide/123", HttpStatus.NOT_FOUND), + Arguments.of("/websockets/ide/123", HttpStatus.NOT_FOUND)); + } + +} diff --git a/tests/src/test/java/org/eclipse/dirigible/integration/tests/api/java/messaging/MessagingFacadeIT.java b/tests/src/test/java/org/eclipse/dirigible/integration/tests/api/java/messaging/MessagingFacadeIT.java index 21b8e6b6bae..c1b78b4a14e 100644 --- a/tests/src/test/java/org/eclipse/dirigible/integration/tests/api/java/messaging/MessagingFacadeIT.java +++ b/tests/src/test/java/org/eclipse/dirigible/integration/tests/api/java/messaging/MessagingFacadeIT.java @@ -18,11 +18,8 @@ import org.eclipse.dirigible.integration.tests.IntegrationTest; import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Test; -import org.springframework.test.annotation.DirtiesContext; -import org.springframework.test.annotation.DirtiesContext.ClassMode; import org.testcontainers.shaded.org.awaitility.Awaitility; -@DirtiesContext(classMode = ClassMode.AFTER_CLASS) class MessagingFacadeIT extends IntegrationTest { private static final String TEST_MESSAGE = "Test message"; diff --git a/tests/src/test/java/org/eclipse/dirigible/integration/tests/api/javascript/DirigibleJavaScriptIT.java b/tests/src/test/java/org/eclipse/dirigible/integration/tests/api/javascript/DirigibleJavaScriptIT.java index db72377c105..987fd1270f2 100644 --- a/tests/src/test/java/org/eclipse/dirigible/integration/tests/api/javascript/DirigibleJavaScriptIT.java +++ b/tests/src/test/java/org/eclipse/dirigible/integration/tests/api/javascript/DirigibleJavaScriptIT.java @@ -18,10 +18,7 @@ import org.junit.jupiter.api.TestFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.mock.mockito.MockBean; -import org.springframework.test.annotation.DirtiesContext; -import org.springframework.test.annotation.DirtiesContext.ClassMode; -@DirtiesContext(classMode = ClassMode.AFTER_CLASS) class DirigibleJavaScriptIT extends IntegrationTest { @Autowired diff --git a/tests/src/test/java/org/eclipse/dirigible/integration/tests/ui/Dirigible.java b/tests/src/test/java/org/eclipse/dirigible/integration/tests/ui/Dirigible.java index 0d14fc8769d..d8f0b086af0 100644 --- a/tests/src/test/java/org/eclipse/dirigible/integration/tests/ui/Dirigible.java +++ b/tests/src/test/java/org/eclipse/dirigible/integration/tests/ui/Dirigible.java @@ -24,6 +24,7 @@ public class Dirigible { private static final String LOGIN_PAGE_TITLE = "Please sign in"; private static final String ROOT_PATH = "/"; + private static final String SPRING_BOOT_PATH = "/spring-admin"; private static final String USERNAME = "admin"; private static final String PASSWORD = "admin"; @@ -57,4 +58,11 @@ private void login() { browser.enterTextInElementByAttributePattern(HtmlElementType.INPUT, HtmlAttribute.ID, PASSWORD_FIELD_ID, PASSWORD); browser.clickElementByAttributePatternAndText(HtmlElementType.BUTTON, HtmlAttribute.TYPE, SUBMIT_TYPE, SIGN_IN_BUTTON_TEXT); } + + public void openSpringBootAdmin() { + browser.openPath(SPRING_BOOT_PATH); + login(); + } + + } diff --git a/tests/src/test/java/org/eclipse/dirigible/integration/tests/ui/framework/BrowserImpl.java b/tests/src/test/java/org/eclipse/dirigible/integration/tests/ui/framework/BrowserImpl.java index d1103cc4bbf..33b0f3e98a3 100644 --- a/tests/src/test/java/org/eclipse/dirigible/integration/tests/ui/framework/BrowserImpl.java +++ b/tests/src/test/java/org/eclipse/dirigible/integration/tests/ui/framework/BrowserImpl.java @@ -88,7 +88,7 @@ private SelenideElement getElementByAttributePatternAndText(HtmlElementType elem } private By constructCssSelectorByTypeAndAttribute(HtmlElementType elementType, HtmlAttribute attribute, String attributePattern) { - String cssSelector = elementType.getType() + "[" + attribute.getAttribute() + "*=" + attributePattern + "]"; + String cssSelector = elementType.getType() + "[" + attribute.getAttribute() + "*='" + attributePattern + "']"; return Selectors.byCssSelector(cssSelector); } @@ -131,5 +131,4 @@ private SelenideElement getElementByType(HtmlElementType elementType) { By cssSelector = Selectors.byCssSelector(elementType.getType()); return Selenide.$(cssSelector); } - } diff --git a/tests/src/test/java/org/eclipse/dirigible/integration/tests/ui/framework/HtmlElementType.java b/tests/src/test/java/org/eclipse/dirigible/integration/tests/ui/framework/HtmlElementType.java index b4ef2870f76..492d53f152e 100644 --- a/tests/src/test/java/org/eclipse/dirigible/integration/tests/ui/framework/HtmlElementType.java +++ b/tests/src/test/java/org/eclipse/dirigible/integration/tests/ui/framework/HtmlElementType.java @@ -14,7 +14,8 @@ public enum HtmlElementType { BUTTON("button"), // INPUT("input"), // HEADER5("h5"), // - TITLE("title"); + TITLE("title"), // + ANCHOR("a"); private final String type; diff --git a/tests/src/test/java/org/eclipse/dirigible/integration/tests/ui/tests/SpringBootAdminIT.java b/tests/src/test/java/org/eclipse/dirigible/integration/tests/ui/tests/SpringBootAdminIT.java new file mode 100644 index 00000000000..865b3ea25e7 --- /dev/null +++ b/tests/src/test/java/org/eclipse/dirigible/integration/tests/ui/tests/SpringBootAdminIT.java @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2023 SAP SE or an SAP affiliate company and Eclipse Dirigible contributors + * + * All rights reserved. This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v2.0 which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v20.html + * + * SPDX-FileCopyrightText: 2023 SAP SE or an SAP affiliate company and Eclipse Dirigible + * contributors SPDX-License-Identifier: EPL-2.0 + */ +package org.eclipse.dirigible.integration.tests.ui.tests; + +import org.eclipse.dirigible.integration.tests.ui.Dirigible; +import org.eclipse.dirigible.integration.tests.ui.framework.HtmlElementType; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.springframework.test.context.ActiveProfiles; + +@ActiveProfiles("spring-boot-admin") +class SpringBootAdminIT extends UserInterfaceIntegrationTest { + + private static final String SPRING_ADMIN_BRAND_TITLE = "Eclipse Dirigible Admin"; + private Dirigible dirigible; + + @BeforeEach + void setUp() { + this.dirigible = new Dirigible(browser); + } + + @Test + void testOpenSpringBootAdminUI() { + dirigible.openSpringBootAdmin(); + browser.assertElementExistsByTypeAndText(HtmlElementType.ANCHOR, SPRING_ADMIN_BRAND_TITLE); + } +}