kezhenxu94
3 years ago
committed by
GitHub
21 changed files with 963 additions and 76 deletions
@ -0,0 +1,98 @@
|
||||
# DolphinScheduler End-to-End Test |
||||
|
||||
## Page Object Model |
||||
|
||||
DolphinScheduler End-to-End test respects |
||||
the [Page Object Model (POM)](https://www.selenium.dev/documentation/guidelines/page_object_models/) design pattern. |
||||
Every page of DolphinScheduler is abstracted into a class for better maintainability. |
||||
|
||||
### Example |
||||
|
||||
The login page is abstracted |
||||
as [`LoginPage`](dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/pages/LoginPage.java), with the |
||||
following fields, |
||||
|
||||
```java |
||||
public final class LoginPage { |
||||
@FindBy(id = "input-username") |
||||
private WebElement inputUsername; |
||||
|
||||
@FindBy(id = "input-password") |
||||
private WebElement inputPassword; |
||||
|
||||
@FindBy(id = "button-login") |
||||
private WebElement buttonLogin; |
||||
} |
||||
``` |
||||
|
||||
where `inputUsername`, `inputPassword` and `buttonLogin` are the main elements on UI that we are interested in. They are |
||||
annotated with `FindBy` so that the test framework knows how to locate the elements on UI. You can locate the elements |
||||
by `id`, `className`, `css` selector, `tagName`, or even `xpath`, please refer |
||||
to [the JavaDoc](https://www.selenium.dev/selenium/docs/api/java/org/openqa/selenium/support/FindBy.html). |
||||
|
||||
**Note:** for better maintainability, it's essential to add some convenient `id` or `class` on UI for the wanted |
||||
elements if needed, avoid using too complex `xpath` selector or `css` selector that is not maintainable when UI have |
||||
styles changes. |
||||
|
||||
With those fields declared, we should also initialize them with a web driver. Here we pass the web driver into the |
||||
constructor and invoke `PageFactory.initElements` to initialize those fields, |
||||
|
||||
```java |
||||
public final class LoginPage { |
||||
// ... |
||||
public LoginPage(RemoteWebDriver driver) { |
||||
this.driver = driver; |
||||
|
||||
PageFactory.initElements(driver, this); |
||||
} |
||||
} |
||||
``` |
||||
|
||||
then, all those UI elements are properly filled in. |
||||
|
||||
## Test Environment Setup |
||||
|
||||
DolphinScheduler End-to-End test uses [testcontainers](https://www.testcontainers.org) to set up the testing |
||||
environment, with docker compose. |
||||
|
||||
Typically, every test case needs one or more `docker-compose.yaml` files to set up all needed components, and expose the |
||||
DolphinScheduler UI port for testing. You can use `@DolphinScheduler(composeFiles = "")` and pass |
||||
the `docker-compose.yaml` files to automatically set up the environment in the test class. |
||||
|
||||
```java |
||||
|
||||
@DolphinScheduler(composeFiles = "docker/tenant/docker-compose.yaml") |
||||
class TenantE2ETest { |
||||
} |
||||
``` |
||||
|
||||
You can get the web driver that is ready for testing in the class by adding a field of type `RemoteWebDriver`, which |
||||
will be automatically injected via the testing framework. |
||||
|
||||
```java |
||||
|
||||
@DolphinScheduler(composeFiles = "docker/tenant/docker-compose.yaml") |
||||
class TenantE2ETest { |
||||
private RemoteWebDriver browser; |
||||
} |
||||
``` |
||||
|
||||
Then the field `browser` can be used in the test methods. |
||||
|
||||
```java |
||||
|
||||
@DolphinScheduler(composeFiles = "docker/tenant/docker-compose.yaml") |
||||
class TenantE2ETest { |
||||
private RemoteWebDriver browser; |
||||
|
||||
@Test |
||||
void testLogin() { |
||||
final LoginPage page = new LoginPage(browser); // <<-- use the browser injected |
||||
} |
||||
} |
||||
``` |
||||
|
||||
## Notes |
||||
|
||||
- For UI tests, it's common that the pages might need some time to load, or the operations might need some time to |
||||
complete, we can use `await().untilAsserted(() -> {})` to wait for the assertions. |
@ -0,0 +1,40 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?> |
||||
<!-- |
||||
~ Licensed to 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. Apache Software Foundation (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. |
||||
--> |
||||
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" |
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" |
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> |
||||
<parent> |
||||
<artifactId>dolphinscheduler-e2e</artifactId> |
||||
<groupId>org.apache.dolphinscheduler</groupId> |
||||
<version>1.0-SNAPSHOT</version> |
||||
</parent> |
||||
<modelVersion>4.0.0</modelVersion> |
||||
|
||||
<artifactId>dolphinscheduler-e2e-case</artifactId> |
||||
|
||||
<dependencies> |
||||
<dependency> |
||||
<groupId>org.apache.dolphinscheduler</groupId> |
||||
<artifactId>dolphinscheduler-e2e-core</artifactId> |
||||
<version>${project.version}</version> |
||||
</dependency> |
||||
</dependencies> |
||||
</project> |
@ -0,0 +1,98 @@
|
||||
/* |
||||
* Licensed to 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. Apache Software Foundation (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.dolphinscheduler.e2e.cases.security; |
||||
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat; |
||||
import static org.awaitility.Awaitility.await; |
||||
|
||||
import org.apache.dolphinscheduler.e2e.core.DolphinScheduler; |
||||
import org.apache.dolphinscheduler.e2e.pages.LoginPage; |
||||
import org.apache.dolphinscheduler.e2e.pages.TenantPage; |
||||
|
||||
import org.junit.jupiter.api.Order; |
||||
import org.junit.jupiter.api.Test; |
||||
import org.openqa.selenium.By; |
||||
import org.openqa.selenium.WebElement; |
||||
import org.openqa.selenium.remote.RemoteWebDriver; |
||||
|
||||
@DolphinScheduler(composeFiles = "docker/tenant/docker-compose.yaml") |
||||
class TenantE2ETest { |
||||
private RemoteWebDriver browser; |
||||
|
||||
@Test |
||||
@Order(1) |
||||
void testLogin() { |
||||
final LoginPage page = new LoginPage(browser); |
||||
page.inputUsername().sendKeys("admin"); |
||||
page.inputPassword().sendKeys("dolphinscheduler123"); |
||||
page.buttonLogin().click(); |
||||
} |
||||
|
||||
@Test |
||||
@Order(10) |
||||
void testCreateTenant() { |
||||
final TenantPage page = new TenantPage(browser); |
||||
final String tenant = System.getProperty("user.name"); |
||||
|
||||
page.buttonCreateTenant().click(); |
||||
page.createTenantForm().inputTenantCode().sendKeys(tenant); |
||||
page.createTenantForm().inputDescription().sendKeys("Test"); |
||||
page.createTenantForm().buttonSubmit().click(); |
||||
|
||||
await().untilAsserted(() -> assertThat(page.tenantList()) |
||||
.as("Tenant list should contain newly-created tenant") |
||||
.extracting(WebElement::getText) |
||||
.anyMatch(it -> it.contains(tenant))); |
||||
} |
||||
|
||||
@Test |
||||
@Order(20) |
||||
void testCreateDuplicateTenant() { |
||||
final String tenant = System.getProperty("user.name"); |
||||
final TenantPage page = new TenantPage(browser); |
||||
page.buttonCreateTenant().click(); |
||||
page.createTenantForm().inputTenantCode().sendKeys(tenant); |
||||
page.createTenantForm().inputDescription().sendKeys("Test"); |
||||
page.createTenantForm().buttonSubmit().click(); |
||||
|
||||
await().untilAsserted(() -> assertThat(browser.findElementByTagName("body") |
||||
.getText().contains("already exists")) |
||||
.as("Should fail when creating a duplicate tenant") |
||||
.isTrue()); |
||||
|
||||
page.createTenantForm().buttonCancel().click(); |
||||
} |
||||
|
||||
@Test |
||||
@Order(30) |
||||
void testDeleteTenant() { |
||||
final String tenant = System.getProperty("user.name"); |
||||
final TenantPage page = new TenantPage(browser); |
||||
|
||||
page.tenantList() |
||||
.stream() |
||||
.filter(it -> it.getText().contains(tenant)) |
||||
.findFirst() |
||||
.ifPresent(it -> it.findElement(By.className("delete")).click()); |
||||
|
||||
page.buttonConfirm().click(); |
||||
} |
||||
} |
@ -0,0 +1,47 @@
|
||||
/* |
||||
* Licensed to 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. Apache Software Foundation (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.dolphinscheduler.e2e.pages; |
||||
|
||||
import org.openqa.selenium.WebElement; |
||||
import org.openqa.selenium.remote.RemoteWebDriver; |
||||
import org.openqa.selenium.support.FindBy; |
||||
import org.openqa.selenium.support.PageFactory; |
||||
|
||||
import lombok.Getter; |
||||
|
||||
@Getter |
||||
public final class LoginPage { |
||||
private final RemoteWebDriver driver; |
||||
|
||||
@FindBy(id = "input-username") |
||||
private WebElement inputUsername; |
||||
|
||||
@FindBy(id = "input-password") |
||||
private WebElement inputPassword; |
||||
|
||||
@FindBy(id = "button-login") |
||||
private WebElement buttonLogin; |
||||
|
||||
public LoginPage(RemoteWebDriver driver) { |
||||
this.driver = driver; |
||||
|
||||
PageFactory.initElements(driver, this); |
||||
} |
||||
} |
@ -0,0 +1,78 @@
|
||||
/* |
||||
* Licensed to 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. Apache Software Foundation (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.dolphinscheduler.e2e.pages; |
||||
|
||||
import java.util.List; |
||||
|
||||
import org.openqa.selenium.WebDriver; |
||||
import org.openqa.selenium.WebElement; |
||||
import org.openqa.selenium.support.FindBy; |
||||
import org.openqa.selenium.support.FindBys; |
||||
import org.openqa.selenium.support.PageFactory; |
||||
|
||||
import lombok.Getter; |
||||
|
||||
@Getter |
||||
public final class TenantPage { |
||||
private final WebDriver driver; |
||||
|
||||
@FindBy(id = "button-create-tenant") |
||||
private WebElement buttonCreateTenant; |
||||
|
||||
@FindBy(className = "rows-tenant") |
||||
private List<WebElement> tenantList; |
||||
|
||||
@FindBys({ |
||||
@FindBy(className = "el-popconfirm"), |
||||
@FindBy(className = "el-button--primary"), |
||||
}) |
||||
private WebElement buttonConfirm; |
||||
|
||||
private final CreateTenantForm createTenantForm; |
||||
|
||||
public TenantPage(WebDriver driver) { |
||||
this.driver = driver; |
||||
this.createTenantForm = new CreateTenantForm(); |
||||
|
||||
PageFactory.initElements(driver, this); |
||||
} |
||||
|
||||
@Getter |
||||
public class CreateTenantForm { |
||||
CreateTenantForm() { |
||||
PageFactory.initElements(driver, this); |
||||
} |
||||
|
||||
@FindBy(id = "input-tenant-code") |
||||
private WebElement inputTenantCode; |
||||
|
||||
@FindBy(id = "select-queue") |
||||
private WebElement selectQueue; |
||||
|
||||
@FindBy(id = "input-description") |
||||
private WebElement inputDescription; |
||||
|
||||
@FindBy(id = "button-submit") |
||||
private WebElement buttonSubmit; |
||||
|
||||
@FindBy(id = "button-cancel") |
||||
private WebElement buttonCancel; |
||||
} |
||||
} |
@ -0,0 +1,35 @@
|
||||
# |
||||
# 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. |
||||
# |
||||
|
||||
version: "2.1" |
||||
|
||||
services: |
||||
dolphinscheduler: |
||||
image: apache/dolphinscheduler:ci |
||||
command: [ standalone-server ] |
||||
expose: |
||||
- 12345 |
||||
networks: |
||||
- e2e |
||||
healthcheck: |
||||
test: [ "CMD", "bash", "-c", "cat < /dev/null > /dev/tcp/127.0.0.1/12345" ] |
||||
interval: 5s |
||||
timeout: 60s |
||||
retries: 120 |
||||
|
||||
networks: |
||||
e2e: |
@ -0,0 +1,32 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?> |
||||
<!-- |
||||
~ Licensed to 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. Apache Software Foundation (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. |
||||
--> |
||||
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" |
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" |
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> |
||||
<parent> |
||||
<artifactId>dolphinscheduler-e2e</artifactId> |
||||
<groupId>org.apache.dolphinscheduler</groupId> |
||||
<version>1.0-SNAPSHOT</version> |
||||
</parent> |
||||
<modelVersion>4.0.0</modelVersion> |
||||
|
||||
<artifactId>dolphinscheduler-e2e-core</artifactId> |
||||
</project> |
@ -0,0 +1,41 @@
|
||||
/* |
||||
* Licensed to 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. Apache Software Foundation (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.dolphinscheduler.e2e.core; |
||||
|
||||
import java.lang.annotation.ElementType; |
||||
import java.lang.annotation.Inherited; |
||||
import java.lang.annotation.Retention; |
||||
import java.lang.annotation.RetentionPolicy; |
||||
import java.lang.annotation.Target; |
||||
|
||||
import org.junit.jupiter.api.MethodOrderer.OrderAnnotation; |
||||
import org.junit.jupiter.api.TestMethodOrder; |
||||
import org.junit.jupiter.api.extension.ExtendWith; |
||||
import org.testcontainers.junit.jupiter.Testcontainers; |
||||
|
||||
@Inherited |
||||
@Testcontainers |
||||
@Target(ElementType.TYPE) |
||||
@Retention(RetentionPolicy.RUNTIME) |
||||
@TestMethodOrder(OrderAnnotation.class) |
||||
@ExtendWith(DolphinSchedulerExtension.class) |
||||
public @interface DolphinScheduler { |
||||
String[] composeFiles(); |
||||
} |
@ -0,0 +1,187 @@
|
||||
/* |
||||
* Licensed to 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. Apache Software Foundation (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.dolphinscheduler.e2e.core; |
||||
|
||||
import static org.testcontainers.containers.BrowserWebDriverContainer.VncRecordingMode.RECORD_ALL; |
||||
import static org.testcontainers.containers.VncRecordingContainer.VncRecordingFormat.MP4; |
||||
|
||||
import java.io.File; |
||||
import java.io.IOException; |
||||
import java.net.URL; |
||||
import java.nio.file.Files; |
||||
import java.nio.file.Path; |
||||
import java.nio.file.Paths; |
||||
import java.time.Duration; |
||||
import java.util.List; |
||||
import java.util.Objects; |
||||
import java.util.Optional; |
||||
import java.util.concurrent.TimeUnit; |
||||
import java.util.stream.Collectors; |
||||
import java.util.stream.Stream; |
||||
|
||||
import org.junit.jupiter.api.extension.AfterAllCallback; |
||||
import org.junit.jupiter.api.extension.BeforeAllCallback; |
||||
import org.junit.jupiter.api.extension.BeforeEachCallback; |
||||
import org.junit.jupiter.api.extension.ExtensionContext; |
||||
import org.junit.runner.Description; |
||||
import org.junit.runners.model.Statement; |
||||
import org.openqa.selenium.WebDriver; |
||||
import org.openqa.selenium.chrome.ChromeOptions; |
||||
import org.openqa.selenium.remote.RemoteWebDriver; |
||||
import org.testcontainers.containers.BrowserWebDriverContainer; |
||||
import org.testcontainers.containers.ContainerState; |
||||
import org.testcontainers.containers.DockerComposeContainer; |
||||
import org.testcontainers.containers.Network; |
||||
import org.testcontainers.containers.wait.strategy.Wait; |
||||
import org.testcontainers.shaded.org.apache.commons.lang.SystemUtils; |
||||
import org.testcontainers.shaded.org.awaitility.Awaitility; |
||||
|
||||
import com.google.common.base.Strings; |
||||
import com.google.common.net.HostAndPort; |
||||
|
||||
import lombok.extern.slf4j.Slf4j; |
||||
|
||||
@Slf4j |
||||
final class DolphinSchedulerExtension |
||||
implements BeforeAllCallback, AfterAllCallback, |
||||
BeforeEachCallback { |
||||
private final boolean LOCAL_MODE = Objects.equals(System.getProperty("local"), "true"); |
||||
|
||||
private RemoteWebDriver driver; |
||||
private DockerComposeContainer<?> compose; |
||||
private BrowserWebDriverContainer<?> browser; |
||||
|
||||
@Override |
||||
@SuppressWarnings("UnstableApiUsage") |
||||
public void beforeAll(ExtensionContext context) throws IOException { |
||||
Awaitility.setDefaultTimeout(Duration.ofSeconds(5)); |
||||
Awaitility.setDefaultPollInterval(Duration.ofSeconds(1)); |
||||
|
||||
Network network = null; |
||||
HostAndPort address = null; |
||||
String rootPath = "/"; |
||||
if (!LOCAL_MODE) { |
||||
compose = createDockerCompose(context); |
||||
compose.start(); |
||||
|
||||
final ContainerState dsContainer = compose.getContainerByServiceName("dolphinscheduler_1") |
||||
.orElseThrow(() -> new RuntimeException("Failed to find a container named 'dolphinscheduler'")); |
||||
final String networkId = dsContainer.getContainerInfo().getNetworkSettings().getNetworks().keySet().iterator().next(); |
||||
network = new Network() { |
||||
@Override |
||||
public String getId() { |
||||
return networkId; |
||||
} |
||||
|
||||
@Override |
||||
public void close() { |
||||
} |
||||
|
||||
@Override |
||||
public Statement apply(Statement base, Description description) { |
||||
return null; |
||||
} |
||||
}; |
||||
address = HostAndPort.fromParts("dolphinscheduler", 12345); |
||||
rootPath = "/dolphinscheduler"; |
||||
} |
||||
|
||||
final Path record; |
||||
if (!Strings.isNullOrEmpty(System.getenv("RECORDING_PATH"))) { |
||||
record = Paths.get(System.getenv("RECORDING_PATH")); |
||||
if (!record.toFile().exists()) { |
||||
if (!record.toFile().mkdir()) { |
||||
throw new IOException("Failed to create recording directory: " + record.toAbsolutePath()); |
||||
} |
||||
} |
||||
} else { |
||||
record = Files.createTempDirectory("record-"); |
||||
} |
||||
browser = new BrowserWebDriverContainer<>() |
||||
.withCapabilities(new ChromeOptions()) |
||||
.withRecordingMode(RECORD_ALL, record.toFile(), MP4); |
||||
if (network != null) { |
||||
browser.withNetwork(network); |
||||
} |
||||
browser.start(); |
||||
|
||||
driver = browser.getWebDriver(); |
||||
|
||||
driver.manage().timeouts() |
||||
.implicitlyWait(5, TimeUnit.SECONDS) |
||||
.pageLoadTimeout(5, TimeUnit.SECONDS); |
||||
if (address == null) { |
||||
try { |
||||
address = HostAndPort.fromParts(browser.getTestHostIpAddress(), 8888); |
||||
} catch (UnsupportedOperationException ignored) { |
||||
if (SystemUtils.IS_OS_MAC || SystemUtils.IS_OS_MAC_OSX) { |
||||
address = HostAndPort.fromParts("host.docker.internal", 8888); |
||||
} |
||||
} |
||||
} |
||||
if (address == null) { |
||||
throw new UnsupportedOperationException("Unsupported operation system"); |
||||
} |
||||
driver.get(new URL("http", address.getHost(), address.getPort(), rootPath).toString()); |
||||
|
||||
browser.beforeTest(new TestDescription(context)); |
||||
} |
||||
|
||||
@Override |
||||
public void afterAll(ExtensionContext context) { |
||||
browser.afterTest(new TestDescription(context), Optional.empty()); |
||||
browser.stop(); |
||||
if (compose != null) { |
||||
compose.stop(); |
||||
} |
||||
} |
||||
|
||||
@Override |
||||
public void beforeEach(ExtensionContext context) { |
||||
final Object instance = context.getRequiredTestInstance(); |
||||
Stream.of(instance.getClass().getDeclaredFields()) |
||||
.filter(f -> WebDriver.class.isAssignableFrom(f.getType())) |
||||
.forEach(it -> { |
||||
try { |
||||
it.setAccessible(true); |
||||
it.set(instance, driver); |
||||
} catch (IllegalAccessException e) { |
||||
LOGGER.error("Failed to inject web driver to field: {}", it.getName(), e); |
||||
} |
||||
}); |
||||
} |
||||
|
||||
private DockerComposeContainer<?> createDockerCompose(ExtensionContext context) { |
||||
final Class<?> clazz = context.getRequiredTestClass(); |
||||
final DolphinScheduler annotation = clazz.getAnnotation(DolphinScheduler.class); |
||||
final List<File> files = Stream.of(annotation.composeFiles()) |
||||
.map(it -> DolphinScheduler.class.getClassLoader().getResource(it)) |
||||
.filter(Objects::nonNull) |
||||
.map(URL::getPath) |
||||
.map(File::new) |
||||
.collect(Collectors.toList()); |
||||
compose = new DockerComposeContainer<>(files) |
||||
.withPull(true) |
||||
.withTailChildContainers(true) |
||||
.waitingFor("dolphinscheduler_1", Wait.forHealthcheck()); |
||||
|
||||
return compose; |
||||
} |
||||
} |
@ -0,0 +1,55 @@
|
||||
/* |
||||
* Licensed to 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. Apache Software Foundation (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.dolphinscheduler.e2e.core; |
||||
|
||||
import static java.nio.charset.StandardCharsets.UTF_8; |
||||
|
||||
import static org.junit.platform.commons.util.StringUtils.isBlank; |
||||
|
||||
import java.io.UnsupportedEncodingException; |
||||
import java.net.URLEncoder; |
||||
|
||||
import org.junit.jupiter.api.extension.ExtensionContext; |
||||
|
||||
import lombok.RequiredArgsConstructor; |
||||
|
||||
@RequiredArgsConstructor |
||||
final class TestDescription implements org.testcontainers.lifecycle.TestDescription { |
||||
private static final String UNKNOWN_NAME = "unknown"; |
||||
|
||||
private final ExtensionContext context; |
||||
|
||||
@Override |
||||
public String getTestId() { |
||||
return context.getUniqueId(); |
||||
} |
||||
|
||||
@Override |
||||
public String getFilesystemFriendlyName() { |
||||
final String contextId = context.getUniqueId(); |
||||
try { |
||||
return (isBlank(contextId)) |
||||
? UNKNOWN_NAME |
||||
: URLEncoder.encode(contextId, UTF_8.toString()); |
||||
} catch (UnsupportedEncodingException e) { |
||||
return UNKNOWN_NAME; |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,31 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?> |
||||
<!-- |
||||
~ 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. |
||||
~ |
||||
--> |
||||
|
||||
<Configuration status="DEBUG"> |
||||
<Appenders> |
||||
<Console name="Console" target="SYSTEM_OUT"> |
||||
<PatternLayout charset="UTF-8" pattern="%d %c %L [%t] %-5p %x - %m%n"/> |
||||
</Console> |
||||
</Appenders> |
||||
<Loggers> |
||||
<Root level="INFO"> |
||||
<AppenderRef ref="Console"/> |
||||
</Root> |
||||
</Loggers> |
||||
</Configuration> |
@ -0,0 +1,20 @@
|
||||
# |
||||
# 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. |
||||
# |
||||
|
||||
lombok.accessors.fluent=true |
||||
lombok.log.fieldname=LOGGER |
||||
lombok.accessors.fluent=true |
@ -0,0 +1,138 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?> |
||||
<!-- |
||||
~ 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. |
||||
--> |
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" |
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" |
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> |
||||
<modelVersion>4.0.0</modelVersion> |
||||
|
||||
<groupId>org.apache.dolphinscheduler</groupId> |
||||
<artifactId>dolphinscheduler-e2e</artifactId> |
||||
<packaging>pom</packaging> |
||||
<version>1.0-SNAPSHOT</version> |
||||
|
||||
<modules> |
||||
<module>dolphinscheduler-e2e-core</module> |
||||
<module>dolphinscheduler-e2e-case</module> |
||||
</modules> |
||||
|
||||
<properties> |
||||
<maven.compiler.source>8</maven.compiler.source> |
||||
<maven.compiler.target>8</maven.compiler.target> |
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> |
||||
|
||||
<junit.version>5.7.2</junit.version> |
||||
<selenium.version>3.141.59</selenium.version> |
||||
<lombok.version>1.18.20</lombok.version> |
||||
<assertj-core.version>3.20.2</assertj-core.version> |
||||
<awaitility.version>4.1.0</awaitility.version> |
||||
<kotlin.version>1.5.30</kotlin.version> |
||||
</properties> |
||||
|
||||
<dependencies> |
||||
<dependency> |
||||
<groupId>org.slf4j</groupId> |
||||
<artifactId>slf4j-api</artifactId> |
||||
<version>1.7.30</version> |
||||
</dependency> |
||||
<dependency> |
||||
<groupId>org.apache.logging.log4j</groupId> |
||||
<artifactId>log4j-slf4j-impl</artifactId> |
||||
<version>2.14.1</version> |
||||
</dependency> |
||||
|
||||
<dependency> |
||||
<groupId>org.junit.jupiter</groupId> |
||||
<artifactId>junit-jupiter</artifactId> |
||||
</dependency> |
||||
|
||||
<dependency> |
||||
<groupId>org.testcontainers</groupId> |
||||
<artifactId>testcontainers</artifactId> |
||||
</dependency> |
||||
<dependency> |
||||
<groupId>org.testcontainers</groupId> |
||||
<artifactId>junit-jupiter</artifactId> |
||||
</dependency> |
||||
|
||||
<dependency> |
||||
<groupId>org.testcontainers</groupId> |
||||
<artifactId>selenium</artifactId> |
||||
</dependency> |
||||
|
||||
<dependency> |
||||
<groupId>org.seleniumhq.selenium</groupId> |
||||
<artifactId>selenium-chrome-driver</artifactId> |
||||
<version>${selenium.version}</version> |
||||
</dependency> |
||||
<dependency> |
||||
<groupId>org.seleniumhq.selenium</groupId> |
||||
<artifactId>selenium-support</artifactId> |
||||
<version>${selenium.version}</version> |
||||
</dependency> |
||||
|
||||
<dependency> |
||||
<groupId>org.assertj</groupId> |
||||
<artifactId>assertj-core</artifactId> |
||||
<version>${assertj-core.version}</version> |
||||
<scope>test</scope> |
||||
</dependency> |
||||
|
||||
<dependency> |
||||
<groupId>org.awaitility</groupId> |
||||
<artifactId>awaitility</artifactId> |
||||
<version>${awaitility.version}</version> |
||||
<scope>test</scope> |
||||
</dependency> |
||||
|
||||
<dependency> |
||||
<groupId>org.projectlombok</groupId> |
||||
<artifactId>lombok</artifactId> |
||||
<version>${lombok.version}</version> |
||||
<scope>provided</scope> |
||||
</dependency> |
||||
</dependencies> |
||||
|
||||
<dependencyManagement> |
||||
<dependencies> |
||||
<dependency> |
||||
<groupId>org.junit</groupId> |
||||
<artifactId>junit-bom</artifactId> |
||||
<version>${junit.version}</version> |
||||
<scope>import</scope> |
||||
<type>pom</type> |
||||
</dependency> |
||||
<dependency> |
||||
<groupId>org.testcontainers</groupId> |
||||
<artifactId>testcontainers-bom</artifactId> |
||||
<version>1.16.0</version> |
||||
<scope>import</scope> |
||||
<type>pom</type> |
||||
</dependency> |
||||
</dependencies> |
||||
</dependencyManagement> |
||||
|
||||
<build> |
||||
<plugins> |
||||
<plugin> |
||||
<groupId>org.apache.maven.plugins</groupId> |
||||
<artifactId>maven-surefire-plugin</artifactId> |
||||
<version>2.22.2</version> |
||||
</plugin> |
||||
</plugins> |
||||
</build> |
||||
</project> |
Loading…
Reference in new issue