Skip to content

Clean up unified tests via skipping API #1551

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

Merged
merged 5 commits into from
Nov 1, 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
Original file line number Diff line number Diff line change
Expand Up @@ -28,13 +28,14 @@
import java.util.Collection;

import static com.mongodb.client.unified.UnifiedRetryableReadsTest.doSkips;
import static com.mongodb.client.unified.UnifiedTestSkips.testDef;
import static com.mongodb.reactivestreams.client.syncadapter.SyncMongoClient.disableWaitForBatchCursorCreation;
import static com.mongodb.reactivestreams.client.syncadapter.SyncMongoClient.enableWaitForBatchCursorCreation;

final class UnifiedRetryableReadsTest extends UnifiedReactiveStreamsTest {
@Override
protected void skips(final String fileDescription, final String testDescription) {
doSkips(fileDescription, testDescription);
doSkips(testDef("unified-test-format/retryable-reads", fileDescription, testDescription));
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,12 @@
import java.util.Collection;

import static com.mongodb.client.unified.UnifiedRetryableWritesTest.doSkips;
import static com.mongodb.client.unified.UnifiedTestSkips.testDef;

final class UnifiedRetryableWritesTest extends UnifiedReactiveStreamsTest {
@Override
protected void skips(final String fileDescription, final String testDescription) {
doSkips(testDescription);
doSkips(testDef("unified-test-format/retryable-writes", fileDescription, testDescription));
}

private static Collection<Arguments> data() throws URISyntaxException, IOException {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,13 +22,16 @@
import java.net.URISyntaxException;
import java.util.Collection;

import static com.mongodb.client.unified.UnifiedTestSkips.testDef;

final class UnifiedServerDiscoveryAndMonitoringTest extends UnifiedReactiveStreamsTest {
private static Collection<Arguments> data() throws URISyntaxException, IOException {
return getTestData("unified-test-format/server-discovery-and-monitoring");
}

@Override
protected void skips(final String fileDescription, final String testDescription) {
com.mongodb.client.unified.UnifiedServerDiscoveryAndMonitoringTest.doSkips(fileDescription, testDescription);
com.mongodb.client.unified.UnifiedServerDiscoveryAndMonitoringTest.doSkips(
testDef("unified-test-format/server-discovery-and-monitoring", fileDescription, testDescription));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,28 +22,28 @@
import java.net.URISyntaxException;
import java.util.Collection;

import static org.junit.jupiter.api.Assumptions.assumeFalse;
import static com.mongodb.client.unified.UnifiedTestSkips.TestDef;
import static com.mongodb.client.unified.UnifiedTestSkips.testDef;

public final class UnifiedRetryableReadsTest extends UnifiedSyncTest {
@Override
protected void skips(final String fileDescription, final String testDescription) {
doSkips(fileDescription, testDescription);
doSkips(testDef("unified-test-format/retryable-reads", fileDescription, testDescription));
}

public static void doSkips(final String fileDescription, @SuppressWarnings("unused") final String testDescription) {
// Skipped because driver removed the deprecated count methods
assumeFalse(fileDescription.equals("count"));
assumeFalse(fileDescription.equals("count-serverErrors"));
// Skipped because the driver never had these methods
assumeFalse(fileDescription.equals("listDatabaseObjects"));
assumeFalse(fileDescription.equals("listDatabaseObjects-serverErrors"));
assumeFalse(fileDescription.equals("listCollectionObjects"));
assumeFalse(fileDescription.equals("listCollectionObjects-serverErrors"));

// JAVA-5224
assumeFalse(fileDescription.equals("ReadConcernMajorityNotAvailableYet is a retryable read")
&& testDescription.equals("Find succeeds on second attempt after ReadConcernMajorityNotAvailableYet"),
"JAVA-5224");
public static void doSkips(final TestDef def) {
def.skipDeprecated("Deprecated feature removed")
.file("retryable-reads", "count")
.file("retryable-reads", "count-serverErrors");

def.skipDeprecated("Deprecated feature never implemented")
.file("retryable-reads", "listDatabaseObjects")
.file("retryable-reads", "listDatabaseObjects-serverErrors")
.file("retryable-reads", "listCollectionObjects")
.file("retryable-reads", "listCollectionObjects-serverErrors");

def.skipJira("https://jira.mongodb.org/browse/JAVA-5224")
.test("retryable-reads", "ReadConcernMajorityNotAvailableYet is a retryable read", "Find succeeds on second attempt after ReadConcernMajorityNotAvailableYet");
}

private static Collection<Arguments> data() throws URISyntaxException, IOException {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@

package com.mongodb.client.unified;

import com.mongodb.client.unified.UnifiedTestSkips.TestDef;
import org.junit.jupiter.params.provider.Arguments;

import java.io.IOException;
Expand All @@ -25,24 +26,27 @@
import static com.mongodb.ClusterFixture.isDiscoverableReplicaSet;
import static com.mongodb.ClusterFixture.isSharded;
import static com.mongodb.ClusterFixture.serverVersionLessThan;
import static org.junit.jupiter.api.Assumptions.assumeFalse;
import static com.mongodb.client.unified.UnifiedTestSkips.testDef;

public final class UnifiedRetryableWritesTest extends UnifiedSyncTest {
@Override
protected void skips(final String fileDescription, final String testDescription) {
doSkips(testDescription);
doSkips(testDef("unified-test-format/retryable-writes", fileDescription, testDescription));
}

public static void doSkips(final String description) {
public static void doSkips(final TestDef def) {
if (isSharded() && serverVersionLessThan(5, 0)) {
assumeFalse(description.contains("succeeds after WriteConcernError"));
assumeFalse(description.contains("succeeds after retryable writeConcernError"));
def.skipJira("https://jira.mongodb.org/browse/JAVA-5125")
.testContains("retryable-writes", "succeeds after WriteConcernError")
.testContains("retryable-writes", "succeeds after retryable writeConcernError");
}
if (isDiscoverableReplicaSet() && serverVersionLessThan(4, 4)) {
assumeFalse(description.equals("RetryableWriteError label is added based on writeConcernError in pre-4.4 mongod response"));
def.skipJira("https://jira.mongodb.org/browse/JAVA-5341")
.test("retryable-writes", "retryable-writes insertOne serverErrors", "RetryableWriteError label is added based on writeConcernError in pre-4.4 mongod response");
}
assumeFalse(description.contains("client bulkWrite"), "JAVA-4586");
assumeFalse(description.contains("client.clientBulkWrite"), "JAVA-4586");
def.skipJira("https://jira.mongodb.org/browse/JAVA-4586")
.testContains("retryable-writes", "client bulkWrite")
.testContains("retryable-writes", "client.clientBulkWrite");
}

private static Collection<Arguments> data() throws URISyntaxException, IOException {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,8 @@
import java.net.URISyntaxException;
import java.util.Collection;

import static org.junit.jupiter.api.Assumptions.assumeFalse;
import static com.mongodb.client.unified.UnifiedTestSkips.TestDef;
import static com.mongodb.client.unified.UnifiedTestSkips.testDef;

public final class UnifiedServerDiscoveryAndMonitoringTest extends UnifiedSyncTest {
private static Collection<Arguments> data() throws URISyntaxException, IOException {
Expand All @@ -31,30 +32,26 @@ private static Collection<Arguments> data() throws URISyntaxException, IOExcepti

@Override
protected void skips(final String fileDescription, final String testDescription) {
doSkips(fileDescription, testDescription);
doSkips(testDef("unified-test-format/server-discovery-and-monitoring", fileDescription, testDescription));
}

public static void doSkips(final String fileDescription, final String testDescription) {
assumeFalse(testDescription.equals("connect with serverMonitoringMode=auto >=4.4"),
"Skipping because our server monitoring events behave differently for now");
assumeFalse(testDescription.equals("connect with serverMonitoringMode=stream >=4.4"),
"Skipping because our server monitoring events behave differently for now");

assumeFalse(fileDescription.equals("standalone-logging"), "Skipping until JAVA-4770 is implemented");
assumeFalse(fileDescription.equals("replicaset-logging"), "Skipping until JAVA-4770 is implemented");
assumeFalse(fileDescription.equals("sharded-logging"), "Skipping until JAVA-4770 is implemented");
assumeFalse(fileDescription.equals("loadbalanced-logging"), "Skipping until JAVA-4770 is implemented");

assumeFalse(fileDescription.equals("standalone-emit-topology-description-changed-before-close"),
"Skipping until JAVA-5229 is implemented");
assumeFalse(fileDescription.equals("replicaset-emit-topology-description-changed-before-close"),
"Skipping until JAVA-5229 is implemented");
assumeFalse(fileDescription.equals("sharded-emit-topology-description-changed-before-close"),
"Skipping until JAVA-5229 is implemented");
assumeFalse(fileDescription.equals("loadbalanced-emit-topology-description-changed-before-close"),
"Skipping until JAVA-5229 is implemented");

assumeFalse(testDescription.equals("poll waits after successful heartbeat"), "Skipping until JAVA-5564 is implemented");
assumeFalse(fileDescription.equals("interruptInUse"), "Skipping until JAVA-4536 is implemented");
public static void doSkips(final TestDef def) {
def.skipJira("https://jira.mongodb.org/browse/JAVA-5230")
.test("server-discovery-and-monitoring", "serverMonitoringMode", "connect with serverMonitoringMode=auto >=4.4")
.test("server-discovery-and-monitoring", "serverMonitoringMode", "connect with serverMonitoringMode=stream >=4.4");
def.skipJira("https://jira.mongodb.org/browse/JAVA-4770")
.file("server-discovery-and-monitoring", "standalone-logging")
Copy link
Contributor

@nhachicha nhachicha Oct 31, 2024

Choose a reason for hiding this comment

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

The standalone-logging here is the description of the test(s) https://github.com/mongodb/specifications/blob/master/source/server-discovery-and-monitoring/tests/unified/logging-standalone.json#L2 and not the JSON file name. The method defines the second parameter as the file https://github.com/mongodb/mongo-java-driver/pull/1551/files#diff-c703183de18b785f0df010e4d1dc57464f07946ae7e350533c507d4232801374R85

I was under the impression that If one wants to exclude all tests under logging-standalone.json I could call

def.skipJira("https://jira.mongodb.org/browse/JAVA-4770")
                .file("server-discovery-and-monitoring", "logging-standalone") 
// logging-standalone is the name of JSON file 
// standalone-logging is the top description of all tests under  logging-standalone.json 

In contrary in https://github.com/mongodb/mongo-java-driver/pull/1551/files#diff-20c83c94232058f9e9a6b35b2c2825e600f5dba0cbc5a4c64bfd0aa78053cd28R46
serverMonitoringMode is the actual JSON file name (which also matches its description)

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Having the description used as an identifier is unfortunate. Probably tests should have an id field that matches their file name.

Added param docs.

.file("server-discovery-and-monitoring", "replicaset-logging")
.file("server-discovery-and-monitoring", "sharded-logging")
.file("server-discovery-and-monitoring", "loadbalanced-logging");
def.skipJira("https://jira.mongodb.org/browse/JAVA-5229")
.file("server-discovery-and-monitoring", "standalone-emit-topology-description-changed-before-close")
.file("server-discovery-and-monitoring", "replicaset-emit-topology-description-changed-before-close")
.file("server-discovery-and-monitoring", "sharded-emit-topology-description-changed-before-close")
.file("server-discovery-and-monitoring", "loadbalanced-emit-topology-description-changed-before-close");
def.skipJira("https://jira.mongodb.org/browse/JAVA-5564")
.test("server-discovery-and-monitoring", "serverMonitoringMode", "poll waits after successful heartbeat");
def.skipJira("https://jira.mongodb.org/browse/JAVA-4536")
.file("server-discovery-and-monitoring", "interruptInUse");
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
/*
* Copyright 2008-present MongoDB, Inc.
*
* Licensed 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 com.mongodb.client.unified;

import com.mongodb.assertions.Assertions;

import static org.junit.jupiter.api.Assumptions.assumeFalse;

public final class UnifiedTestSkips {

private UnifiedTestSkips() {}

public static TestDef testDef(final String dir, final String file, final String test) {
return new TestDef(dir, file, test);
}

public static final class TestDef {
private final String dir;
private final String file;
private final String test;

private TestDef(final String dir, final String file, final String test) {
this.dir = dir;
this.file = file;
this.test = test;
}

/**
* Test is skipped because it is pending implementation, and there is
* a Jira ticket tracking this which has more information.
*
* @param skip reason for skipping the test; must start with a Jira URL
*/
public Skip skipJira(final String skip) {
Assertions.assertTrue(skip.startsWith("https://jira.mongodb.org/browse/JAVA-"));
Copy link
Contributor

Choose a reason for hiding this comment

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

Can the skip be due to a DRIVER-XXX ticket? I think checking against https://jira.mongodb.org/browse/ is enough to make sure a valid JIRA link is provided

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I considered this, but I think we need to have something our team is tracking. If a good counterexample comes up, we can remove the constraint at the time?

return new Skip(this, skip);
}

/**
* Test is skipped because the feature under test was deprecated, and
* was removed in the Java driver.
*
* @param skip reason for skipping the test
*/
public Skip skipDeprecated(final String skip) {
return new Skip(this, skip);
}

/**
* Test is skipped because the Java driver cannot comply with the spec.
*
* @param skip reason for skipping the test
*/
public Skip skipNoncompliant(final String skip) {
return new Skip(this, skip);
}
}

public static final class Skip {
private final TestDef testDef;
private final String reason;

private Skip(final TestDef testDef, final String reason) {
this.testDef = testDef;
this.reason = reason;
}

/**
* All tests in file under dir skipped.
* @param dir the directory name
* @param file the test file's "description" field
* @return this
*/
public Skip file(final String dir, final String file) {
boolean match = ("unified-test-format/" + dir).equals(testDef.dir)
&& file.equals(testDef.file);
assumeFalse(match, reason);
return this;
}

/**
* Test skipped if dir, file, and test match.
* @param dir the directory name
* @param file the test file's "description" field
* @param test the individual test's "description" field
* @return this
*/
public Skip test(final String dir, final String file, final String test) {
boolean match = ("unified-test-format/" + dir).equals(testDef.dir)
&& file.equals(testDef.file)
&& test.equals(testDef.test);
assumeFalse(match, reason);
return this;
}

/**
* Test skipped if the test description contains the fragment as a substring
* Avoid using this, except during development.
* @param dir the directory name
* @param fragment the substring to check in the test "description" field
* @return this
*/
public Skip testContains(final String dir, final String fragment) {
Copy link
Contributor

Choose a reason for hiding this comment

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

This should be used carefully as it has the potential risk of skipping new tests matching the fragment...
I accidentally used updateOne with sort option with contains which matched also BulkWrite updateOne with sort option

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I will add a note.

I think we should stop it from being used in non-dev, but this will be more work, since existing tests use this pattern.

Copy link
Contributor

Choose a reason for hiding this comment

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

Is there a use case where we want to filter by dir and test description as well? Thinking whether we should add an optional testDef.file parameter to the method?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Let's add it if we run into it (hopefully we don't, since as you say the contains methods seem risky).

boolean match = ("unified-test-format/" + dir).equals(testDef.dir)
&& testDef.test.contains(fragment);
assumeFalse(match, reason);
return this;
}
}
}