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

AJ-1234: Add WsmPactTest #372

Merged
merged 1 commit into from
Nov 2, 2023
Merged
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
Original file line number Diff line number Diff line change
@@ -0,0 +1,184 @@
package org.databiosphere.workspacedataservice.pact;

import static au.com.dius.pact.consumer.dsl.LambdaDsl.newJsonBody;
import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
import static org.junit.jupiter.api.Assertions.assertThrows;

import au.com.dius.pact.consumer.MockServer;
import au.com.dius.pact.consumer.dsl.DslPart;
import au.com.dius.pact.consumer.dsl.PactDslWithProvider;
import au.com.dius.pact.consumer.junit5.PactConsumerTestExt;
import au.com.dius.pact.consumer.junit5.PactTestFor;
import au.com.dius.pact.core.model.PactSpecVersion;
import au.com.dius.pact.core.model.RequestResponsePact;
import au.com.dius.pact.core.model.annotations.Pact;
import bio.terra.datarepo.model.SnapshotModel;
import bio.terra.workspace.model.CloningInstructionsEnum;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
import org.databiosphere.workspacedataservice.workspacemanager.HttpWorkspaceManagerClientFactory;
import org.databiosphere.workspacedataservice.workspacemanager.WorkspaceManagerClientFactory;
import org.databiosphere.workspacedataservice.workspacemanager.WorkspaceManagerDao;
import org.databiosphere.workspacedataservice.workspacemanager.WorkspaceManagerException;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Tag;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.springframework.mock.web.MockHttpServletRequest;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

@Tag("pact-test")
@ExtendWith(PactConsumerTestExt.class)
public class WsmPactTest {
// copied from DslPart.UUID_REGEX, used to configure Pact to accept a wildcard UUID as the
// workspaceId path param
private static final String UUID_REGEX_PATTERN =
"[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}";

// the two UUIDs are hardcoded to prevent churn in pactfiles, and intended to be human memorable
private static final UUID WORKSPACE_UUID =
UUID.fromString("facade00-0000-4000-a000-000000000000");
private static final UUID SNAPSHOT_UUID = UUID.fromString("decade00-0000-4000-a000-000000000000");
private static final String SNAPSHOT_NAME = "hardcodedSnapshotName";
private static final String SNAPSHOT_CREATOR_EMAIL = "[email protected]";

@BeforeEach
void setUp() {
// Without this setup, the HttpClient throws a "No thread-bound request found" error
RequestContextHolder.setRequestAttributes(
new ServletRequestAttributes(new MockHttpServletRequest()));
}

private String snapshotPath(String workspaceIdPart) {
return String.format(
"/api/workspaces/v1/%s/resources/referenced/datarepo/snapshots", workspaceIdPart);
}

@Pact(consumer = "wds", provider = "workspacemanager")
RequestResponsePact linkSnapshotForPolicySuccess(PactDslWithProvider builder) {
return builder
.given("a workspace with the given id exists", Map.of("id", WORKSPACE_UUID.toString()))
.given("authenticated with the given email", Map.of("email", SNAPSHOT_CREATOR_EMAIL))
.given("policies allowing snapshot reference creation")
.uponReceiving("a request to create a snapshot reference")
.matchPath(snapshotPath(UUID_REGEX_PATTERN), snapshotPath(WORKSPACE_UUID.toString()))
.method("POST")
.headers(contentTypeJson())
.body(createSnapshotReferenceBody(SNAPSHOT_NAME))
.willRespondWith()
.status(200) // ok
.headers(contentTypeJson())
.body(
newJsonBody(
body -> {
// put expectations here if we ever start reading fields in the code under
// test
})
.build())
.toPact();
}

private String conditions(String... conditions) {
return String.join(" and ", conditions);
}

@Pact(consumer = "wds", provider = "workspacemanager")
RequestResponsePact linkSnapshotForPolicyConflict(PactDslWithProvider builder) {
return builder
.given("a workspace with the given id exists", Map.of("id", WORKSPACE_UUID.toString()))
.given("authenticated with the given email", Map.of("email", SNAPSHOT_CREATOR_EMAIL))
.given("policies preventing snapshot reference creation")
.uponReceiving("a request to create a snapshot reference")
.matchPath(snapshotPath(UUID_REGEX_PATTERN), snapshotPath(WORKSPACE_UUID.toString()))
.method("POST")
.headers(contentTypeJson())
.body(createSnapshotReferenceBody(SNAPSHOT_NAME))
.willRespondWith()
.status(409) // conflict
.headers(contentTypeJson())
.body(
newJsonBody(
body ->
body.stringMatcher(
"message", "^(.*)policy conflict(.*)$", "unexpected policy conflict"))
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Trailmarker comment for crosslinking from @calypsomatic 's other PR.

.build())
.toPact();
}

@Test
@PactTestFor(
pactMethod = "linkSnapshotForPolicySuccess",
providerName = "workspacemanager",
pactVersion = PactSpecVersion.V3)
void testLinkSnapshotForPolicySuccess(MockServer mockServer) {
var wsmDao = buildWsmDao(mockServer);
var snapshotModel = buildSnapshotModel();

assertDoesNotThrow(() -> wsmDao.linkSnapshotForPolicy(snapshotModel));
}

@Test
@PactTestFor(
pactMethod = "linkSnapshotForPolicyConflict",
providerName = "workspacemanager",
pactVersion = PactSpecVersion.V3)
void testLinkSnapshotForPolicyConflict(MockServer mockServer) {
var wsmDao = buildWsmDao(mockServer);
var snapshotModel = buildSnapshotModel();

assertThrows(
WorkspaceManagerException.class, () -> wsmDao.linkSnapshotForPolicy(snapshotModel));
}

private SnapshotModel buildSnapshotModel() {
return new SnapshotModel().id(SNAPSHOT_UUID).name(SNAPSHOT_NAME);
}

private WorkspaceManagerDao buildWsmDao(MockServer mockServer) {
WorkspaceManagerClientFactory clientFactory =
new HttpWorkspaceManagerClientFactory(mockServer.getUrl());
return new WorkspaceManagerDao(clientFactory, WORKSPACE_UUID.toString());
}

private DslPart createSnapshotReferenceBody(String snapshotName) {
// metadata.name is a composite of <snapshotName>_<timestamp>
String nameFormatString = String.format("'%s'_yyyyMMddHHmmss", snapshotName);

return newJsonBody(
body -> {
body.object(
"snapshot",
snapshot -> {
snapshot.stringValue("instanceName", "terra");
snapshot.uuid("snapshot");
});
body.object(
"metadata",
metadata -> {
metadata.stringValue(
"cloningInstructions", CloningInstructionsEnum.REFERENCE.toString());
metadata.datetime("name", nameFormatString);
// expect exactly one property, declaring the snapshot as being for policy only
metadata.minMaxArrayLike(
"properties",
/* minSize= */ 1,
/* maxSize= */ 1,
p -> {
p.stringValue("key", "purpose");
p.stringValue("value", "policy");
});
});
})
.build();
}

private Map<String, String> contentTypeJson() {
Map<String, String> headers = new HashMap<>();
// pact will automatically assume an expected Content-Type of "application/json; charset=UTF-8"
// unless we explicitly tell it otherwise
headers.put("Content-Type", "application/json");
return headers;
}
}