Skip to content

Commit 54c5740

Browse files
ci(NODE-6784): ensure compression is used when compression is configured in CI (#4570)
1 parent c48bbcf commit 54c5740

File tree

10 files changed

+136
-72
lines changed

10 files changed

+136
-72
lines changed

test/integration/collection-management/collection.test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -547,7 +547,7 @@ describe('Collection', function () {
547547
const capped = await collection.isCapped();
548548
expect(capped).to.be.false;
549549
} finally {
550-
client.close();
550+
await client.close();
551551
}
552552
}
553553

test/integration/connection-monitoring-and-pooling/connection.test.ts

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -268,7 +268,15 @@ describe('Connection', function () {
268268
// This test exists to prevent regression of processing many messages inside one chunk.
269269
it(
270270
'processes all of them and emits heartbeats',
271-
{ requires: { topology: 'replicaset', mongodb: '>=4.4' } },
271+
{
272+
requires: {
273+
topology: 'replicaset',
274+
mongodb: '>=4.4',
275+
// When compression is enabled, processing heartbeat events is asynchronous.
276+
predicate: () =>
277+
process.env.COMPRESSOR ? 'test requires that compression is disabled' : true
278+
}
279+
},
272280
async function () {
273281
let hbSuccess = 0;
274282
client.on('serverHeartbeatSucceeded', () => (hbSuccess += 1));
@@ -291,6 +299,7 @@ describe('Connection', function () {
291299

292300
// All of the hb will be emitted synchronously in the next tick as the entire chunk is processed.
293301
await processTick();
302+
294303
expect(hbSuccess).to.be.greaterThan(1000);
295304
}
296305
);

test/integration/crud/insert.test.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1825,7 +1825,7 @@ describe('crud - insert', function () {
18251825
.toArray();
18261826
const doc = docs.pop();
18271827
expect(doc.a._bsontype).to.equal('Long');
1828-
client.close();
1828+
await client.close();
18291829
}
18301830
});
18311831

test/integration/crud/misc_cursors.test.js

Lines changed: 0 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -1887,52 +1887,6 @@ describe('Cursor', function () {
18871887
}
18881888
);
18891889

1890-
it('shouldAwaitData', {
1891-
// Add a tag that our runner can trigger on
1892-
// in this case we are setting that node needs to be higher than 0.10.X to run
1893-
metadata: {
1894-
requires: { topology: ['single', 'replicaset', 'sharded'] }
1895-
},
1896-
1897-
test: function (done) {
1898-
// www.mongodb.com/docs/display/DOCS/Tailable+Cursors
1899-
1900-
const configuration = this.configuration;
1901-
client.connect((err, client) => {
1902-
expect(err).to.not.exist;
1903-
this.defer(() => client.close());
1904-
1905-
const db = client.db(configuration.db);
1906-
const options = { capped: true, size: 8 };
1907-
db.createCollection(
1908-
'should_await_data_retry_tailable_cursor',
1909-
options,
1910-
(err, collection) => {
1911-
expect(err).to.not.exist;
1912-
1913-
collection.insert({ a: 1 }, configuration.writeConcernMax(), err => {
1914-
expect(err).to.not.exist;
1915-
1916-
// Create cursor with awaitData, and timeout after the period specified
1917-
const cursor = collection.find({}, { tailable: true, awaitData: true });
1918-
this.defer(() => cursor.close());
1919-
1920-
// Execute each
1921-
cursor.forEach(
1922-
() => cursor.close(),
1923-
() => {
1924-
// Even though cursor is exhausted, should not close session
1925-
// unless cursor is manually closed, due to awaitData / tailable
1926-
done();
1927-
}
1928-
);
1929-
});
1930-
}
1931-
);
1932-
});
1933-
}
1934-
});
1935-
19361890
it('shouldAwaitDataWithDocumentsAvailable', function (done) {
19371891
// www.mongodb.com/docs/display/DOCS/Tailable+Cursors
19381892

test/integration/mongodb-handshake/mongodb-handshake.test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ describe('MongoDB Handshake', () => {
5555
after(() => sinon.restore());
5656

5757
it('constructs a handshake with the specified compressors', async function () {
58-
client = this.configuration.newClient({ compressors: ['snappy'] });
58+
client = this.configuration.newClient({}, { compressors: ['snappy'] });
5959
// The load-balanced mode doesn’t perform SDAM,
6060
// so `connect` doesn’t do anything unless authentication is enabled.
6161
// Force the driver to send a command to the server in the noauth mode.

test/integration/node-specific/bson-options/utf8_validation.test.ts

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,8 @@ describe('class MongoDBResponse', () => {
7979
describe('parsing of utf8-invalid documents with cursors', function () {
8080
let client: MongoClient;
8181
let collection: Collection;
82+
const compressionPredicate = () =>
83+
process.env.COMPRESSOR ? 'Test requires that compression is disabled' : true;
8284

8385
/**
8486
* Inserts a document with malformed utf8 bytes. This method spies on socket.write, and then waits
@@ -117,6 +119,10 @@ describe('parsing of utf8-invalid documents with cursors', function () {
117119
}
118120

119121
beforeEach(async function () {
122+
if (typeof compressionPredicate() === 'string') {
123+
this.currentTest.skipReason = compressionPredicate() as string;
124+
this.skip();
125+
}
120126
client = this.configuration.newClient();
121127
await client.connect();
122128
const db = client.db('test');
@@ -128,7 +134,7 @@ describe('parsing of utf8-invalid documents with cursors', function () {
128134

129135
afterEach(async function () {
130136
sinon.restore();
131-
await client.close();
137+
await client?.close();
132138
});
133139

134140
context('when utf-8 validation is explicitly disabled', function () {
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
import { expect } from 'chai';
2+
3+
describe('compression configuration tests', function () {
4+
describe('process.env.COMPRESSOR is set', function () {
5+
it(
6+
'enables compression when set in the environment',
7+
{
8+
requires: {
9+
predicate: () => !!process.env.COMPRESSOR || 'compression must be enabled.'
10+
}
11+
},
12+
function () {
13+
const client = this.configuration.newClient();
14+
expect(client.s.options.compressors).to.deep.equal([process.env.COMPRESSOR]);
15+
}
16+
);
17+
18+
it(
19+
'enables compression when set in the environment',
20+
{
21+
requires: {
22+
predicate: () => !!process.env.COMPRESSOR || 'compression must be enabled.'
23+
}
24+
},
25+
function () {
26+
const url = this.configuration.url();
27+
expect(url).to.include(`compressors=${process.env.COMPRESSOR}`);
28+
}
29+
);
30+
});
31+
32+
describe('process.env.COMPRESSOR is unset', function () {
33+
it(
34+
'enables compression when set in the environment',
35+
{
36+
requires: {
37+
predicate: () => !process.env.COMPRESSOR || 'compression cannot be enabled.'
38+
}
39+
},
40+
function () {
41+
const client = this.configuration.newClient();
42+
43+
expect(client.s.options.compressors).to.deep.equal(['none']);
44+
}
45+
);
46+
47+
it(
48+
'enables compression when set in the environment',
49+
{
50+
requires: {
51+
predicate: () => !process.env.COMPRESSOR || 'compression cannot be enabled.'
52+
}
53+
},
54+
function () {
55+
const url = this.configuration.url();
56+
expect(url).to.not.include(`compressors=none`);
57+
}
58+
);
59+
});
60+
});

test/integration/read-write-concern/write_concern.test.ts

Lines changed: 28 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
import { expect } from 'chai';
22
import { on, once } from 'events';
3-
import { gte } from 'semver';
43
import * as sinon from 'sinon';
54

65
import {
@@ -174,6 +173,8 @@ describe('Write Concern', function () {
174173
});
175174

176175
describe('fire-and-forget protocol', function () {
176+
const compressionPredicate = () =>
177+
process.env.COMPRESSOR ? 'Test requires that compression is disabled' : true;
177178
context('when writeConcern = 0 and OP_MSG is used', function () {
178179
const writeOperations: { name: string; command: any; expectedReturnVal: any }[] = [
179180
{
@@ -270,10 +271,6 @@ describe('Write Concern', function () {
270271
let spy;
271272

272273
beforeEach(async function () {
273-
if (gte('3.6.0', this.configuration.version)) {
274-
this.currentTest.skipReason = 'Test requires OP_MSG, needs to be on MongoDB 3.6+';
275-
this.skip();
276-
}
277274
spy = sinon.spy(OpMsgRequest.prototype, 'toBin');
278275
client = this.configuration.newClient({ monitorCommands: true, w: 0 });
279276
await client.connect();
@@ -284,22 +281,34 @@ describe('Write Concern', function () {
284281
client.close();
285282
});
286283

287-
it('the request should have moreToCome bit set', async function () {
288-
await op.command(client);
289-
expect(spy.returnValues[spy.returnValues.length - 1][0][16]).to.equal(2);
290-
});
284+
it(
285+
'the request should have moreToCome bit set',
286+
{ requires: { predicate: compressionPredicate } },
287+
async function () {
288+
await op.command(client);
289+
expect(spy.returnValues[spy.returnValues.length - 1][0][16]).to.equal(2);
290+
}
291+
);
291292

292-
it('the return value of the command should be nullish', async function () {
293-
const result = await op.command(client);
294-
expect(result).to.containSubset(op.expectedReturnVal);
295-
});
293+
it(
294+
'the return value of the command should be nullish',
295+
{ requires: { predicate: compressionPredicate } },
296+
async function () {
297+
const result = await op.command(client);
298+
expect(result).to.containSubset(op.expectedReturnVal);
299+
}
300+
);
296301

297-
it('commandSucceededEvent should have reply with only {ok: 1}', async function () {
298-
const events: CommandSucceededEvent[] = [];
299-
client.on('commandSucceeded', event => events.push(event));
300-
await op.command(client);
301-
expect(events[0]).to.containSubset({ reply: { ok: 1 } });
302-
});
302+
it(
303+
'commandSucceededEvent should have reply with only {ok: 1}',
304+
{ requires: { predicate: compressionPredicate } },
305+
async function () {
306+
const events: CommandSucceededEvent[] = [];
307+
client.on('commandSucceeded', event => events.push(event));
308+
await op.command(client);
309+
expect(events[0]).to.containSubset({ reply: { ok: 1 } });
310+
}
311+
);
303312
});
304313
}
305314
});

test/tools/runner/config.ts

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import * as types from 'node:util/types';
44
import { expect } from 'chai';
55
import { type Context } from 'mocha';
66
import ConnectionString from 'mongodb-connection-string-url';
7+
import { type CompressorName } from 'mongodb-legacy';
78
import * as qs from 'querystring';
89
import * as url from 'url';
910

@@ -64,6 +65,21 @@ function convertToConnStringMap(obj: Record<string, any>) {
6465
return result.join(',');
6566
}
6667

68+
function getCompressor(compressor: string | undefined): CompressorName {
69+
if (!compressor) return null;
70+
71+
switch (compressor) {
72+
case 'zstd':
73+
return 'zstd';
74+
case 'zlib':
75+
return 'zlib';
76+
case 'snappy':
77+
return 'snappy';
78+
default:
79+
throw new Error('unsupported test runner compressor, would default to no compression');
80+
}
81+
}
82+
6783
export class TestConfiguration {
6884
version: string;
6985
clientSideEncryption: {
@@ -94,6 +110,7 @@ export class TestConfiguration {
94110
activeResources: number;
95111
isSrv: boolean;
96112
filters: Record<string, Filter>;
113+
compressor: CompressorName | null;
97114

98115
constructor(
99116
private uri: string,
@@ -111,6 +128,7 @@ export class TestConfiguration {
111128
this.buildInfo = context.buildInfo;
112129
this.serverApi = context.serverApi;
113130
this.isSrv = uri.indexOf('mongodb+srv') > -1;
131+
this.compressor = getCompressor(process.env.COMPRESSOR);
114132
this.options = {
115133
hosts,
116134
hostAddresses,
@@ -200,7 +218,13 @@ export class TestConfiguration {
200218
}
201219

202220
newClient(urlOrQueryOptions?: string | Record<string, any>, serverOptions?: MongoClientOptions) {
203-
serverOptions = Object.assign({}, getEnvironmentalOptions(), serverOptions);
221+
const baseOptions: MongoClientOptions = this.compressor
222+
? {
223+
compressors: this.compressor
224+
}
225+
: {};
226+
227+
serverOptions = Object.assign(baseOptions, getEnvironmentalOptions(), serverOptions);
204228

205229
if (this.loggingEnabled && !Object.hasOwn(serverOptions, 'mongodbLogPath')) {
206230
serverOptions = this.setupLogging(serverOptions);
@@ -399,6 +423,8 @@ export class TestConfiguration {
399423
url.searchParams.append('authSource', 'admin');
400424
}
401425

426+
this.compressor && url.searchParams.append('compressors', this.compressor);
427+
402428
// Secrets setup for OIDC always sets the workload URI as MONGODB_URI_SINGLE.
403429
if (process.env.MONGODB_URI_SINGLE?.includes('MONGODB-OIDC')) {
404430
return process.env.MONGODB_URI_SINGLE;

test/tools/unified-spec-runner/entities.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -212,7 +212,7 @@ export class UnifiedMongoClient extends MongoClient {
212212
...getEnvironmentalOptions(),
213213
...(description.serverApi ? { serverApi: description.serverApi } : {}),
214214
// TODO(NODE-5785): We need to increase the truncation length because signature.hash is a Buffer making hellos too long
215-
mongodbLogMaxDocumentLength: 1250
215+
mongodbLogMaxDocumentLength: 1500
216216
};
217217

218218
let logCollector: { buffer: LogMessage[]; write: (log: Log) => void } | undefined;

0 commit comments

Comments
 (0)