Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

DEVEXP-530: Conversation e2e tests (Apps) #135

Merged
merged 4 commits into from
Sep 2, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
69 changes: 69 additions & 0 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
name: Building Java SDK

on: [push]

jobs:
build:

runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v3
- name: Set up JDK
uses: actions/setup-java@v3
with:
java-version: '21'
distribution: 'temurin'
cache: maven
- name: Build with Maven
run: mvn -B -DskipITs clean package javadoc:javadoc --file pom.xml

# Optional: Uploads the full dependency graph to GitHub to improve the quality of Dependabot alerts this repository can receive
- name: Update dependency graph
uses: advanced-security/maven-dependency-submission-action@571e99aab1055c2e71a1e2309b9691de18d6b7d6

e2e-tests:
needs: build
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Set up JDK
uses: actions/setup-java@v3
with:
java-version: '21'
distribution: 'temurin'
cache: maven
- name: Checkout sinch-sdk-mockserver repository
uses: actions/checkout@v3
with:
repository: sinch/sinch-sdk-mockserver
token: ${{ secrets.MOCKSERVER_REPO_PAT_CI }}
fetch-depth: 0
path: sinch-sdk-mockserver

- name: Build custom Docker image
run: |
cd sinch-sdk-mockserver
docker build -t sinch-sdk-mockserver -f Dockerfile .

- name: Install Docker Compose
run: |
sudo apt-get update
sudo apt-get install -y docker-compose

- name: Start mock servers with Docker Compose
run: |
cd sinch-sdk-mockserver
docker-compose up -d

- name: Wait for the mock servers to be healthy
run: |
cd sinch-sdk-mockserver
. ./scripts/healthcheck.sh

- name: Link to feature files
run: |
ln -s ${{ github.workspace }}/sinch-sdk-mockserver/features client/src/test/resources

- name: Run e2e tests
run: mvn -B -DskipUTs -Dspotless.check.skip=true verify --file pom.xml
23 changes: 0 additions & 23 deletions .github/workflows/maven.yml

This file was deleted.

2 changes: 1 addition & 1 deletion .github/workflows/samples-compilation.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ jobs:
cache: maven
- name: Building
run: |
mvn clean verify install -DskipTests=true -Dspotless.apply.skip=true
mvn clean install -DskipTests=true -Dspotless.apply.skip=true
cd sample-app
mvn -B clean package
mvn -B -f pom-webhooks.xml clean package
Expand Down
44 changes: 44 additions & 0 deletions client/src/test/java/com/sinch/sdk/e2e/Config.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
package com.sinch.sdk.e2e;

import com.sinch.sdk.SinchClient;
import com.sinch.sdk.models.Configuration;
import com.sinch.sdk.models.ConversationContext;
import com.sinch.sdk.models.ConversationRegion;

public class Config {

public static final String PROJECT_ID = "tinyfrog-jump-high-over-lilypadbasin";
public static final String KEY_ID = "'keyId";
public static final String KEY_SECRET = "keySecret";
public static final String AUTH_URL = "http://localhost:3011/oauth2/token";
public static final String CONVERSATION_HOST_NAME = "http://localhost:3014";
public static final ConversationRegion CONVERSATION_REGION = ConversationRegion.US;

private final SinchClient client;

private Config() {

Configuration configuration =
Configuration.builder()
.setOAuthUrl(Config.AUTH_URL)
.setProjectId(Config.PROJECT_ID)
.setKeyId(Config.KEY_ID)
.setKeySecret(Config.KEY_SECRET)
.setConversationContext(
ConversationContext.builder()
.setUrl(Config.CONVERSATION_HOST_NAME)
.setRegion(Config.CONVERSATION_REGION)
.build())
.build();

client = new SinchClient(configuration);
}

private static class LazyHolder {
private static final Config INSTANCE = new Config();
}

public static SinchClient getSinchClient() {
return LazyHolder.INSTANCE.client;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
package com.sinch.sdk.e2e.domains.conversation;

import com.sinch.sdk.domains.conversation.api.v1.AppService;
import com.sinch.sdk.domains.conversation.models.v1.ProcessingMode;
import com.sinch.sdk.domains.conversation.models.v1.app.ConversationMetadataReportView;
import com.sinch.sdk.domains.conversation.models.v1.app.request.AppCreateRequest;
import com.sinch.sdk.domains.conversation.models.v1.app.request.AppUpdateRequest;
import com.sinch.sdk.domains.conversation.models.v1.app.request.ConversationChannelCredentialRequest;
import com.sinch.sdk.domains.conversation.models.v1.app.request.ConversationChannelCredentialsRequestBuilderFactory;
import com.sinch.sdk.domains.conversation.models.v1.app.response.AppResponse;
import com.sinch.sdk.domains.conversation.models.v1.credentials.ChannelIntegrationStatus;
import com.sinch.sdk.domains.conversation.models.v1.credentials.StaticBearerCredentials;
import com.sinch.sdk.e2e.Config;
import io.cucumber.java.en.Given;
import io.cucumber.java.en.Then;
import io.cucumber.java.en.When;
import java.util.Arrays;
import java.util.Collection;
import org.junit.jupiter.api.Assertions;

public class AppsSteps {

AppService service;
AppResponse createResponse;
Collection<AppResponse> listResponse;
AppResponse getResponse;
AppResponse updateResponse;
boolean deletePassed;

@Given("^the Conversation service \"Apps\" is available$")
public void serviceAvailable() {
service = Config.getSinchClient().conversation().v1().app();
}

@When("^I send a request to create an app$")
public void create() {

String identity = "SpaceMonkeySquadron";
String token = "00112233445566778899aabbccddeeff";
String displayName = "E2E Conversation App";

ConversationChannelCredentialRequest credentials =
ConversationChannelCredentialsRequestBuilderFactory.sms(
StaticBearerCredentials.builder()
.setClaimedIdentity(identity)
.setToken(token)
.build())
.build();

AppCreateRequest request =
AppCreateRequest.builder()
.setChannelCredentials(Arrays.asList(credentials))
.setDisplayName(displayName)
.build();

createResponse = service.create(request);
}

@When("^I send a request to list all the apps$")
public void list() {

listResponse = service.list();
}

@When("^I send a request to retrieve an app$")
public void get() {

getResponse = service.get("foo");
}

@When("^I send a request to update an app$")
public void update() {

AppUpdateRequest request =
AppUpdateRequest.builder().setDisplayName(" a new display name").build();
updateResponse = service.update("foo", request);
}

@When("^I send a request to delete an app$")
public void delete() {

service.delete("foo");
deletePassed = true;

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here you are just checking that the request completed without exception right?
Note that if we decide to move to static values instead of regexp for parameter matching, this test will fail as foo is certainly not a value corresponding to an appId. You may reuse the one tou are already checking in the common fields

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

According to our discussion: we agree to update tests accordingly in case of future change

}

@Then("the conversation app is created")
public void createResult() {
checkExpectedAppResponseCommonFields(createResponse);
Assertions.assertEquals(
createResponse.getChannelCredentials().get(0).getState().getStatus(),
ChannelIntegrationStatus.PENDING);
}

@Then("the apps list contains {int} apps")
public void listResult(int size) {

Assertions.assertEquals(listResponse.size(), size);
AppResponse item = listResponse.stream().findFirst().orElse(null);

checkExpectedAppResponseCommonFields(item);
Assertions.assertEquals(item.getDisplayName(), "E2E Conversation App");
Assertions.assertEquals(
item.getChannelCredentials().get(0).getState().getStatus(),
ChannelIntegrationStatus.ACTIVE);
item = listResponse.stream().reduce((first, second) -> second).orElse(null);
Assertions.assertEquals(item.getId(), "01W4FFL35P4NC4K35CONVAPP002");
}

@Then("the response contains the app details")
public void getResult() {
checkExpectedAppResponseCommonFields(getResponse);
Assertions.assertEquals(getResponse.getDisplayName(), "E2E Conversation App");
Assertions.assertEquals(
getResponse.getChannelCredentials().get(0).getState().getStatus(),
ChannelIntegrationStatus.ACTIVE);
}

@Then("the response contains the app details with updated properties")
public void updateResult() {
checkExpectedAppResponseCommonFields(updateResponse);
Assertions.assertEquals(updateResponse.getDisplayName(), "Updated name");
Assertions.assertEquals(
updateResponse.getChannelCredentials().get(0).getState().getStatus(),
ChannelIntegrationStatus.ACTIVE);
}

@Then("the delete app response contains no data")
public void deleteResult() {

Assertions.assertTrue(deletePassed);
}

void checkExpectedAppResponseCommonFields(AppResponse appResponse) {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a nice idea to factorize the check on common fields. But some tests can break if we change some data in the mockserver expectations. I've tried to create some consistency when I wrote them. Let's agree together to keep it like this!

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

According to our discussion: we agree to update tests accordingly in case of future change

Assertions.assertEquals(appResponse.getId(), "01W4FFL35P4NC4K35CONVAPP001");
Assertions.assertEquals(appResponse.getChannelCredentials().size(), 1);
Assertions.assertEquals(
appResponse.getConversationMetadataReportView(), ConversationMetadataReportView.NONE);
Assertions.assertEquals(appResponse.getProcessingMode(), ProcessingMode.CONVERSATION);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package com.sinch.sdk.e2e.domains.conversation;

import org.junit.platform.suite.api.IncludeEngines;
import org.junit.platform.suite.api.SelectClasspathResource;
import org.junit.platform.suite.api.Suite;

@Suite
@IncludeEngines("cucumber")
@SelectClasspathResource("features/conversation/apps.feature")
public class ConversationIT {}
42 changes: 39 additions & 3 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -72,8 +72,9 @@

<!-- tests -->
<mockito.version>5.8.0</mockito.version>
<maven.failsafe.plugin.version>3.2.1</maven.failsafe.plugin.version>
<maven-surefire-plugin.version>3.2.1</maven-surefire-plugin.version>
<maven.failsafe.plugin.version>3.4.0</maven.failsafe.plugin.version>
<maven-surefire-plugin.version>3.4.0</maven-surefire-plugin.version>
<cucumber.version>7.18.1</cucumber.version>

<!-- releasing -->
<maven.source.plugin.version>3.2.1</maven.source.plugin.version>
Expand Down Expand Up @@ -292,6 +293,10 @@
<plugin>
<artifactId>maven-failsafe-plugin</artifactId>
<version>${maven.failsafe.plugin.version}</version>
<configuration>
<parallel>all</parallel>
<useUnlimitedThreads>true</useUnlimitedThreads>
</configuration>
<executions>
<execution>
<goals>
Expand All @@ -306,6 +311,9 @@
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>${maven-surefire-plugin.version}</version>
<configuration>
<skipTests>${skipUTs}</skipTests>
</configuration>
</plugin>

<!-- deployment/releasing-->
Expand Down Expand Up @@ -357,7 +365,7 @@

<executions>
<execution>
<phase>verify</phase>
<phase>package</phase>
<goals>
<goal>check</goal>
</goals>
Expand Down Expand Up @@ -399,6 +407,20 @@
<scope>test</scope>
</dependency>

<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-engine</artifactId>
<version>5.10.0</version>
<scope>test</scope>
</dependency>

<dependency>
<groupId>org.junit.platform</groupId>
<artifactId>junit-platform-suite-engine</artifactId>
<version>1.11.0</version>
<scope>test</scope>
</dependency>

<dependency>
<groupId>org.assertj</groupId>
<artifactId>assertj-core</artifactId>
Expand Down Expand Up @@ -455,6 +477,20 @@
<scope>test</scope>
</dependency>

<dependency>
<groupId>io.cucumber</groupId>
<artifactId>cucumber-junit-platform-engine</artifactId>
<version>${cucumber.version}</version>
<scope>test</scope>
</dependency>

<dependency>
<groupId>io.cucumber</groupId>
<artifactId>cucumber-java</artifactId>
<version>${cucumber.version}</version>
<scope>test</scope>
</dependency>

<dependency>
<groupId>org.apache.maven</groupId>
<artifactId>maven-model</artifactId>
Expand Down
Loading