Skip to content

Commit 3ea9eef

Browse files
authored
refactor(NODE-3717): test reorg part 3 - sessions and transactions (#3083)
1 parent 30f2a2d commit 3ea9eef

File tree

5 files changed

+235
-222
lines changed

5 files changed

+235
-222
lines changed

.evergreen/run-serverless-tests.sh

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,12 @@ if [ -z ${SERVERLESS_ATLAS_PASSWORD+omitted} ]; then echo "SERVERLESS_ATLAS_PASS
1313

1414
npx mocha --file test/tools/runner/index.js \
1515
test/integration/crud/crud.spec.test.js \
16+
test/integration/crud/crud.prose.test.js \
1617
test/integration/retryable-reads/retryable_reads.spec.test.js \
1718
test/integration/retryable-writes/retryable_writes.spec.test.js \
18-
test/functional/sessions.test.js \
19-
test/functional/transactions.test.js \
19+
test/integration/sessions/sessions.spec.test.js \
20+
test/integration/sessions/sessions.test.js \
21+
test/integration/transactions/transactions.spec.test.js \
22+
test/integration/transactions/transactions.test.js \
2023
test/integration/versioned-api/versioned_api.spec.test.js \
2124
test/integration/load-balancers/load_balancers.spec.test.js
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
'use strict';
2+
3+
const path = require('path');
4+
const { expect } = require('chai');
5+
const { TestRunnerContext, generateTopologyTests } = require('../../tools/spec-runner');
6+
const { runUnifiedTest } = require('../../tools/unified-spec-runner/runner');
7+
const { loadSpecTests } = require('../../spec');
8+
9+
describe('Sessions', function () {
10+
describe('legacy spec tests', function () {
11+
class SessionSpecTestContext extends TestRunnerContext {
12+
assertSessionNotDirty(options) {
13+
const session = options.session;
14+
expect(session.serverSession.isDirty).to.be.false;
15+
}
16+
17+
assertSessionDirty(options) {
18+
const session = options.session;
19+
expect(session.serverSession.isDirty).to.be.true;
20+
}
21+
22+
assertSameLsidOnLastTwoCommands() {
23+
expect(this.commandEvents).to.have.length.of.at.least(2);
24+
const lastTwoCommands = this.commandEvents.slice(-2).map(c => c.command);
25+
lastTwoCommands.forEach(command => expect(command).to.have.property('lsid'));
26+
expect(lastTwoCommands[0].lsid).to.eql(lastTwoCommands[1].lsid);
27+
}
28+
29+
assertDifferentLsidOnLastTwoCommands() {
30+
expect(this.commandEvents).to.have.length.of.at.least(2);
31+
const lastTwoCommands = this.commandEvents.slice(-2).map(c => c.command);
32+
lastTwoCommands.forEach(command => expect(command).to.have.property('lsid'));
33+
expect(lastTwoCommands[0].lsid).to.not.eql(lastTwoCommands[1].lsid);
34+
}
35+
}
36+
37+
const testContext = new SessionSpecTestContext();
38+
const testSuites = loadSpecTests(path.join('sessions', 'legacy'));
39+
40+
after(() => testContext.teardown());
41+
before(function () {
42+
return testContext.setup(this.configuration);
43+
});
44+
45+
function testFilter(spec) {
46+
const SKIP_TESTS = [
47+
// These two tests need to run against multiple mongoses
48+
'Dirty explicit session is discarded',
49+
'Dirty implicit session is discarded (write)'
50+
];
51+
52+
return SKIP_TESTS.indexOf(spec.description) === -1;
53+
}
54+
55+
generateTopologyTests(testSuites, testContext, testFilter);
56+
});
57+
58+
describe('unified spec tests', function () {
59+
for (const sessionTests of loadSpecTests(path.join('sessions', 'unified'))) {
60+
expect(sessionTests).to.be.an('object');
61+
context(String(sessionTests.description), function () {
62+
for (const test of sessionTests.tests) {
63+
it(String(test.description), {
64+
metadata: { sessions: { skipLeakTests: true } },
65+
test: async function () {
66+
await runUnifiedTest(this, sessionTests, test);
67+
}
68+
});
69+
}
70+
});
71+
}
72+
});
73+
});

test/functional/sessions.test.js renamed to test/integration/sessions/sessions.test.js

Lines changed: 4 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,8 @@
11
'use strict';
22

3-
const path = require('path');
4-
const expect = require('chai').expect;
5-
const { MongoServerError } = require('../../src');
6-
const { setupDatabase, withMonitoredClient } = require('./shared');
7-
const { TestRunnerContext, generateTopologyTests } = require('./spec-runner');
8-
const { loadSpecTests } = require('../spec');
9-
const { runUnifiedTest } = require('../tools/unified-spec-runner/runner');
3+
const { expect } = require('chai');
4+
const { MongoServerError } = require('../../../src');
5+
const { setupDatabase, withMonitoredClient } = require('../shared');
106

117
const ignoredCommands = ['ismaster'];
128
const test = {
@@ -31,7 +27,7 @@ const test = {
3127
}
3228
};
3329

34-
describe('Sessions', function () {
30+
describe('Sessions Spec', function () {
3531
describe('Sessions - functional - old format', function () {
3632
before(function () {
3733
return setupDatabase(this.configuration);
@@ -154,70 +150,6 @@ describe('Sessions', function () {
154150
}
155151
});
156152

157-
describe('legacy spec tests', function () {
158-
class SessionSpecTestContext extends TestRunnerContext {
159-
assertSessionNotDirty(options) {
160-
const session = options.session;
161-
expect(session.serverSession.isDirty).to.be.false;
162-
}
163-
164-
assertSessionDirty(options) {
165-
const session = options.session;
166-
expect(session.serverSession.isDirty).to.be.true;
167-
}
168-
169-
assertSameLsidOnLastTwoCommands() {
170-
expect(this.commandEvents).to.have.length.of.at.least(2);
171-
const lastTwoCommands = this.commandEvents.slice(-2).map(c => c.command);
172-
lastTwoCommands.forEach(command => expect(command).to.have.property('lsid'));
173-
expect(lastTwoCommands[0].lsid).to.eql(lastTwoCommands[1].lsid);
174-
}
175-
176-
assertDifferentLsidOnLastTwoCommands() {
177-
expect(this.commandEvents).to.have.length.of.at.least(2);
178-
const lastTwoCommands = this.commandEvents.slice(-2).map(c => c.command);
179-
lastTwoCommands.forEach(command => expect(command).to.have.property('lsid'));
180-
expect(lastTwoCommands[0].lsid).to.not.eql(lastTwoCommands[1].lsid);
181-
}
182-
}
183-
184-
const testContext = new SessionSpecTestContext();
185-
const testSuites = loadSpecTests(path.join('sessions', 'legacy'));
186-
187-
after(() => testContext.teardown());
188-
before(function () {
189-
return testContext.setup(this.configuration);
190-
});
191-
192-
function testFilter(spec) {
193-
const SKIP_TESTS = [
194-
// These two tests need to run against multiple mongoses
195-
'Dirty explicit session is discarded',
196-
'Dirty implicit session is discarded (write)'
197-
];
198-
199-
return SKIP_TESTS.indexOf(spec.description) === -1;
200-
}
201-
202-
generateTopologyTests(testSuites, testContext, testFilter);
203-
});
204-
205-
describe('unified spec tests', function () {
206-
for (const sessionTests of loadSpecTests(path.join('sessions', 'unified'))) {
207-
expect(sessionTests).to.be.an('object');
208-
context(String(sessionTests.description), function () {
209-
for (const test of sessionTests.tests) {
210-
it(String(test.description), {
211-
metadata: { sessions: { skipLeakTests: true } },
212-
test: async function () {
213-
await runUnifiedTest(this, sessionTests, test);
214-
}
215-
});
216-
}
217-
});
218-
}
219-
});
220-
221153
context('unacknowledged writes', () => {
222154
it('should not include session for unacknowledged writes', {
223155
metadata: { requires: { topology: 'single', mongodb: '>=3.6.0' } },
Lines changed: 149 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,149 @@
1+
'use strict';
2+
3+
const path = require('path');
4+
const { expect } = require('chai');
5+
const { TestRunnerContext, generateTopologyTests } = require('../../tools/spec-runner');
6+
const { runUnifiedTest } = require('../../tools/unified-spec-runner/runner');
7+
const { loadSpecTests } = require('../../spec');
8+
9+
function ignoreNsNotFoundForListIndexes(err) {
10+
if (err.code !== 26) {
11+
throw err;
12+
}
13+
14+
return [];
15+
}
16+
17+
class TransactionsRunnerContext extends TestRunnerContext {
18+
assertCollectionExists(options) {
19+
const client = this.sharedClient;
20+
const db = client.db(options.database);
21+
const collectionName = options.collection;
22+
23+
return db
24+
.listCollections()
25+
.toArray()
26+
.then(collections => expect(collections.some(coll => coll.name === collectionName)).to.be.ok);
27+
}
28+
29+
assertCollectionNotExists(options) {
30+
const client = this.sharedClient;
31+
const db = client.db(options.database);
32+
const collectionName = options.collection;
33+
34+
return db
35+
.listCollections()
36+
.toArray()
37+
.then(
38+
collections => expect(collections.every(coll => coll.name !== collectionName)).to.be.ok
39+
);
40+
}
41+
42+
assertIndexExists(options) {
43+
const client = this.sharedClient;
44+
const collection = client.db(options.database).collection(options.collection);
45+
const indexName = options.index;
46+
47+
return collection
48+
.listIndexes()
49+
.toArray()
50+
.catch(ignoreNsNotFoundForListIndexes)
51+
.then(indexes => expect(indexes.some(idx => idx.name === indexName)).to.be.ok);
52+
}
53+
54+
assertIndexNotExists(options) {
55+
const client = this.sharedClient;
56+
const collection = client.db(options.database).collection(options.collection);
57+
const indexName = options.index;
58+
59+
return collection
60+
.listIndexes()
61+
.toArray()
62+
.catch(ignoreNsNotFoundForListIndexes)
63+
.then(indexes => expect(indexes.every(idx => idx.name !== indexName)).to.be.ok);
64+
}
65+
66+
assertSessionPinned(options) {
67+
expect(options).to.have.property('session');
68+
69+
const session = options.session;
70+
expect(session.isPinned).to.be.true;
71+
}
72+
73+
assertSessionUnpinned(options) {
74+
expect(options).to.have.property('session');
75+
76+
const session = options.session;
77+
expect(session.isPinned).to.be.false;
78+
}
79+
}
80+
81+
describe('Transactions Spec Unified Tests', function () {
82+
for (const transactionTest of loadSpecTests(path.join('transactions', 'unified'))) {
83+
expect(transactionTest).to.exist;
84+
context(String(transactionTest.description), function () {
85+
for (const test of transactionTest.tests) {
86+
it(String(test.description), {
87+
metadata: { sessions: { skipLeakTests: true } },
88+
test: async function () {
89+
await runUnifiedTest(this, transactionTest, test);
90+
}
91+
});
92+
}
93+
});
94+
}
95+
});
96+
97+
const SKIP_TESTS = [
98+
// commitTransaction retry seems to be swallowed by mongos in these three cases
99+
'commitTransaction retry succeeds on new mongos',
100+
'commitTransaction retry fails on new mongos',
101+
'unpin after transient error within a transaction and commit',
102+
// FIXME(NODE-3074): unskip count tests when spec tests have been updated
103+
'count',
104+
// This test needs there to be multiple mongoses
105+
// 'increment txnNumber',
106+
// Skipping this until SPEC-1320 is resolved
107+
// 'remain pinned after non-transient error on commit',
108+
109+
// Will be implemented as part of NODE-2034
110+
'Client side error in command starting transaction',
111+
'Client side error when transaction is in progress'
112+
];
113+
114+
describe('Transactions Spec Legacy Tests', function () {
115+
const testContext = new TransactionsRunnerContext();
116+
const suitesToRun = [{ name: 'spec tests', specPath: path.join('transactions', 'legacy') }];
117+
// Note: convenient-api tests are skipped for serverless
118+
if (!process.env.SERVERLESS) {
119+
suitesToRun.push({
120+
name: 'withTransaction spec tests',
121+
specPath: path.join('transactions', 'convenient-api')
122+
});
123+
} else {
124+
// FIXME(NODE-3550): these tests should pass on serverless but currently fail
125+
SKIP_TESTS.push(
126+
'abortTransaction only performs a single retry',
127+
'abortTransaction does not retry after Interrupted',
128+
'abortTransaction does not retry after WriteConcernError Interrupted',
129+
'commitTransaction does not retry error without RetryableWriteError label',
130+
'commitTransaction is not retried after UnsatisfiableWriteConcern error',
131+
'commitTransaction fails after Interrupted'
132+
);
133+
}
134+
suitesToRun.forEach(suiteSpec => {
135+
describe(suiteSpec.name, function () {
136+
const testSuites = loadSpecTests(suiteSpec.specPath);
137+
after(() => testContext.teardown());
138+
before(function () {
139+
return testContext.setup(this.configuration);
140+
});
141+
142+
function testFilter(spec) {
143+
return SKIP_TESTS.indexOf(spec.description) === -1;
144+
}
145+
146+
generateTopologyTests(testSuites, testContext, testFilter);
147+
});
148+
});
149+
});

0 commit comments

Comments
 (0)