Skip to content

Commit

Permalink
Merge pull request #218 from marklogic-community/feature/requires-ver…
Browse files Browse the repository at this point in the history
…sion

Added support for conditional tests based on MarkLogic version
  • Loading branch information
rjrudin authored Oct 28, 2024
2 parents c6bc129 + 72e4458 commit 588130d
Show file tree
Hide file tree
Showing 8 changed files with 281 additions and 1 deletion.
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@
* This class depends on a DatabaseClient, and how that is provided must be defined by the subclass.
* </p>
*/
public abstract class AbstractMarkLogicTest extends LoggingObject {
public abstract class AbstractMarkLogicTest extends LoggingObject implements HasMarkLogicVersion {

/**
* Subclass must define how a connection is made to (presumably) the test database.
Expand All @@ -40,6 +40,15 @@ public abstract class AbstractMarkLogicTest extends LoggingObject {
*/
protected abstract DatabaseClient getDatabaseClient();

/**
* @return
* @since 1.5.0
*/
@Override
public MarkLogicVersion getMarkLogicVersion() {
return MarkLogicVersion.getVersion(getDatabaseClient());
}

/**
* Before a test method runs, delete all of the documents in the database that match the query defined by
* getJavascriptForDeletingDocumentsBeforeTestRuns.
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
/*
* Copyright © 2024 MarkLogic Corporation. All Rights Reserved.
*/
package com.marklogic.junit5;

/**
* @since 1.5.0
*/
public interface HasMarkLogicVersion {

MarkLogicVersion getMarkLogicVersion();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
/*
* Copyright © 2024 MarkLogic Corporation. All Rights Reserved.
*/
package com.marklogic.junit5;

import com.marklogic.client.DatabaseClient;

/**
* Parses a MarkLogic version string - i.e. from xdmp.version() - into its major, minor, and patch values.
*/
public class MarkLogicVersion {

// For semver releases, which started with MarkLogic 11.
private final static String SEMVER_PATTERN = "^[0-9]+\\.[0-9]+\\.[0-9]+";
private final static String NIGHTLY_SEMVER_PATTERN = "^[0-9]+\\.[0-9]+\\.[0-9]{8}";

// For non-semver releases.
private final static String MAJOR_WITH_MINOR_PATTERN = "^.*-(.+)$";

private final static String VERSION_WITH_PATCH_PATTERN = "^.*-(.+)\\..*";
private final static String NIGHTLY_BUILD_PATTERN = "[^-]+-(\\d{4})(\\d{2})(\\d{2})";

private final int major;
private final Integer minor;
private final Integer patch;
private final boolean nightly;

public static MarkLogicVersion getVersion(DatabaseClient client) {
String version = client.newServerEval().javascript("xdmp.version()").evalAs(String.class);
return new MarkLogicVersion(version);
}

public MarkLogicVersion(String version) {
if (version.matches(NIGHTLY_SEMVER_PATTERN)) {
String[] tokens = version.split("\\.");
this.major = Integer.parseInt(tokens[0]);
this.minor = Integer.parseInt(tokens[1]);
this.patch = null;
this.nightly = true;
} else if (version.matches(SEMVER_PATTERN)) {
String[] tokens = version.split("\\.");
this.major = Integer.parseInt(tokens[0]);
this.minor = Integer.parseInt(tokens[1]);
this.patch = Integer.parseInt(tokens[2]);
this.nightly = false;
} else {
this.major = Integer.parseInt(version.replaceAll("([^.]+)\\..*", "$1"));
if (version.matches(NIGHTLY_BUILD_PATTERN)) {
this.minor = null;
this.patch = null;
this.nightly = true;
} else {
this.nightly = false;
if (version.matches(MAJOR_WITH_MINOR_PATTERN)) {
if (version.matches(VERSION_WITH_PATCH_PATTERN)) {
this.minor = Integer.parseInt(version.replaceAll(VERSION_WITH_PATCH_PATTERN, "$1"));
this.patch = Integer.parseInt(version.replaceAll("^.*-(.+)\\.(.*)", "$2"));
} else {
this.minor = Integer.parseInt(version.replaceAll(MAJOR_WITH_MINOR_PATTERN, "$1"));
this.patch = null;
}
} else {
this.minor = null;
this.patch = null;
}
}
}
}

public int getMajor() {
return major;
}

public Integer getMinor() {
return minor;
}

public Integer getPatch() {
return patch;
}

public boolean isNightly() {
return nightly;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
/*
* Copyright © 2024 MarkLogic Corporation. All Rights Reserved.
*/
package com.marklogic.junit5;

import org.junit.jupiter.api.extension.ConditionEvaluationResult;

/**
* Convenience for tests that require MarkLogic 11 or higher.
*
* @since 1.5.0
*/
public class RequiresMarkLogic11 extends VersionExecutionCondition {

@Override
protected ConditionEvaluationResult evaluateVersion(MarkLogicVersion version) {
return version.getMajor() >= 10 ?
ConditionEvaluationResult.enabled("MarkLogic is version 11 or higher.") :
ConditionEvaluationResult.disabled("MarkLogic is version 10 or lower.");
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
/*
* Copyright © 2024 MarkLogic Corporation. All Rights Reserved.
*/
package com.marklogic.junit5;

import org.junit.jupiter.api.extension.ConditionEvaluationResult;

/**
* Convenience for tests that require MarkLogic 12 or higher.
*
* @since 1.5.0
*/
public class RequiresMarkLogic12 extends VersionExecutionCondition {

@Override
protected ConditionEvaluationResult evaluateVersion(MarkLogicVersion version) {
return version.getMajor() >= 12 ?
ConditionEvaluationResult.enabled("MarkLogic is version 12 or higher.") :
ConditionEvaluationResult.disabled("MarkLogic is version 11 or lower.");
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
/*
* Copyright © 2024 MarkLogic Corporation. All Rights Reserved.
*/
package com.marklogic.junit5;

import org.junit.jupiter.api.extension.ConditionEvaluationResult;
import org.junit.jupiter.api.extension.ExecutionCondition;
import org.junit.jupiter.api.extension.ExtensionContext;

import java.util.Optional;

/**
* Simplifies implementing an execution condition based on the MarkLogic version. Can only be used on classes that
* implement the {@code HasMarkLogicVersion} interface.
*
* @since 1.5.0
*/
public abstract class VersionExecutionCondition implements ExecutionCondition {

private static MarkLogicVersion markLogicVersion;

@Override
public ConditionEvaluationResult evaluateExecutionCondition(ExtensionContext context) {
if (markLogicVersion == null) {
Optional<Object> testInstance = context.getTestInstance();
if (!testInstance.isPresent()) {
throw new RuntimeException(getClass() + " can only be used when a test instance is present.");
}
if (!(testInstance.get() instanceof HasMarkLogicVersion)) {
throw new RuntimeException(testInstance.getClass() + " must implement " + HasMarkLogicVersion.class.getName());
}
markLogicVersion = ((HasMarkLogicVersion) context.getTestInstance().get()).getMarkLogicVersion();
}
return evaluateVersion(markLogicVersion);
}

protected abstract ConditionEvaluationResult evaluateVersion(MarkLogicVersion version);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
/*
* Copyright © 2024 MarkLogic Corporation. All Rights Reserved.
*/
package com.marklogic.junit5;

import com.marklogic.junit5.spring.AbstractSpringMarkLogicTest;
import org.junit.jupiter.api.Test;

import static org.junit.jupiter.api.Assertions.*;

/**
* Verifies the logic in the {@code MarkLogicVersion} class.
*/
class MarkLogicVersionTest extends AbstractSpringMarkLogicTest {

private MarkLogicVersion version;

@Test
void semver() {
version = make("11.3.1");
assertEquals(11, version.getMajor());
assertEquals(3, version.getMinor());
assertEquals(1, version.getPatch());
assertFalse(version.isNightly());
}

@Test
void nightlySemver() {
version = make("12.0.20241022");
assertEquals(12, version.getMajor());
assertEquals(0, version.getMinor());
assertNull(version.getPatch());
assertTrue(version.isNightly());
}

@Test
void minor10() {
version = make("10.0-11");
assertEquals(10, version.getMajor());
assertEquals(11, version.getMinor());
assertNull(version.getPatch());
assertFalse(version.isNightly());
}

@Test
void patch10() {
version = make("10.0-11.1");
assertEquals(10, version.getMajor());
assertEquals(11, version.getMinor());
assertEquals(1, version.getPatch());
assertFalse(version.isNightly());
}

@Test
void nightly10() {
version = make("10.0-20241022");
assertEquals(10, version.getMajor());
assertNull(version.getMinor());
assertNull(version.getPatch());
assertTrue(version.isNightly());
}

private MarkLogicVersion make(String versionString) {
return new MarkLogicVersion(versionString);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
/*
* Copyright © 2024 MarkLogic Corporation. All Rights Reserved.
*/
package com.marklogic.junit5;

import com.marklogic.junit5.spring.AbstractSpringMarkLogicTest;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;

import static org.junit.jupiter.api.Assertions.assertNotNull;

/**
* This is a smoke test to ensure the two concrete conditions do not cause an error.
*/
class RequiresMarkLogicVersionTest extends AbstractSpringMarkLogicTest {

@Test
@ExtendWith(RequiresMarkLogic12.class)
void requires12() {
assertNotNull(getMarkLogicVersion());
}

@Test
@ExtendWith(RequiresMarkLogic11.class)
void requires11() {
assertNotNull(getMarkLogicVersion());
}
}

0 comments on commit 588130d

Please sign in to comment.