Skip to content

Commit b19344a

Browse files
authored
[2.x backport] Replace re2 with RegExp in timeline and add unit tests (#4203)
Remove re2 usage and replace it with JavaScript built-in RegExp object. Also add more unit tests to make sure that using RegExp has same expressions as using re2 library. Issue Resolve #3901 Backport PR #3908 Signed-off-by: Anan Zhuang <ananzh@amazon.com>
1 parent ec07e4b commit b19344a

File tree

7 files changed

+125
-137
lines changed

7 files changed

+125
-137
lines changed

CHANGELOG.md

+1
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,7 @@ Inspired from [Keep a Changelog](https://keepachangelog.com/en/1.0.0/)
126126
- Add disablePrototypePoisoningProtection configuration to prevent JS client from erroring when cluster utilizes JS reserved words ([#2992](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/2992))
127127
- [Multiple DataSource] Add support for SigV4 authentication ([#3058](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/3058))
128128
- [Multiple DataSource] Refactor test connection to support SigV4 auth type ([#3456](https://github.com/opensearch-project/OpenSearch-Dashboards/issues/3456))
129+
- Replace re2 with RegExp in timeline and add unit tests ([#3908](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/3908))
129130

130131
### 🐛 Bug Fixes
131132

package.json

-1
Original file line numberDiff line numberDiff line change
@@ -204,7 +204,6 @@
204204
"pegjs": "0.10.0",
205205
"proxy-from-env": "1.0.0",
206206
"query-string": "^6.13.2",
207-
"re2": "1.17.4",
208207
"react": "^16.14.0",
209208
"react-dom": "^16.12.0",
210209
"react-input-range": "^1.3.0",

src/dev/build/tasks/patch_native_modules_task.test.ts

+78-38
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,8 @@ import {
99
createAnyInstanceSerializer,
1010
createAbsolutePathSerializer,
1111
} from '@osd/dev-utils';
12-
import { Build, Config } from '../lib';
13-
import { PatchNativeModules } from './patch_native_modules_task';
12+
import { Build, Config, read, download, untar, gunzip } from '../lib';
13+
import { createPatchNativeModulesTask } from './patch_native_modules_task';
1414

1515
const log = new ToolingLog();
1616
const testWriter = new ToolingLogCollectingWriter();
@@ -19,16 +19,16 @@ expect.addSnapshotSerializer(createAnyInstanceSerializer(Config));
1919
expect.addSnapshotSerializer(createAnyInstanceSerializer(ToolingLog));
2020
expect.addSnapshotSerializer(createAbsolutePathSerializer());
2121

22-
jest.mock('../lib/download');
23-
jest.mock('../lib/fs', () => ({
24-
...jest.requireActual('../lib/fs'),
25-
untar: jest.fn(),
26-
gunzip: jest.fn(),
27-
}));
28-
29-
const { untar } = jest.requireMock('../lib/fs');
30-
const { gunzip } = jest.requireMock('../lib/fs');
31-
const { download } = jest.requireMock('../lib/download');
22+
jest.mock('../lib', () => {
23+
const originalModule = jest.requireActual('../lib');
24+
return {
25+
...originalModule,
26+
download: jest.fn(),
27+
gunzip: jest.fn(),
28+
untar: jest.fn(),
29+
read: jest.fn(),
30+
};
31+
});
3232

3333
async function setup() {
3434
const config = await Config.create({
@@ -38,14 +38,15 @@ async function setup() {
3838
linux: false,
3939
linuxArm: false,
4040
darwin: false,
41+
windows: false,
4142
},
4243
});
4344

4445
const build = new Build(config);
4546

46-
download.mockImplementation(() => {});
47-
untar.mockImplementation(() => {});
48-
gunzip.mockImplementation(() => {});
47+
(read as jest.MockedFunction<typeof read>).mockImplementation(async () => {
48+
return JSON.stringify({ version: mockPackage.version });
49+
});
4950

5051
return { config, build };
5152
}
@@ -55,38 +56,77 @@ beforeEach(() => {
5556
jest.clearAllMocks();
5657
});
5758

58-
it('patch native modules task downloads the correct platform package', async () => {
59-
const { config, build } = await setup();
60-
config.targetPlatforms.linuxArm = true;
61-
await PatchNativeModules.run(config, log, build);
62-
expect(download.mock.calls.length).toBe(1);
63-
expect(download.mock.calls).toMatchInlineSnapshot(`
59+
const mockPackage = {
60+
name: 'mock-native-module',
61+
version: '1.0.0',
62+
destinationPath: 'path/to/destination',
63+
extractMethod: 'untar',
64+
archives: {
65+
'linux-arm64': {
66+
url: 'https://example.com/mock-native-module/linux-arm64.tar.gz',
67+
sha256: 'mock-sha256',
68+
},
69+
'linux-x64': {
70+
url: 'https://example.com/mock-native-module/linux-x64.gz',
71+
sha256: 'mock-sha256',
72+
},
73+
},
74+
};
75+
76+
describe('patch native modules task', () => {
77+
it('patch native modules task downloads the correct platform package', async () => {
78+
const { config, build } = await setup();
79+
config.targetPlatforms.linuxArm = true;
80+
const PatchNativeModulesWithMock = createPatchNativeModulesTask([mockPackage]);
81+
await PatchNativeModulesWithMock.run(config, log, build);
82+
expect((download as jest.MockedFunction<typeof download>).mock.calls.length).toBe(1);
83+
expect((download as jest.MockedFunction<typeof download>).mock.calls).toMatchInlineSnapshot(`
6484
Array [
6585
Array [
6686
Object {
67-
"destination": <absolute path>/.native_modules/re2/linux-arm64-83.tar.gz,
87+
"destination": <absolute path>/.native_modules/mock-native-module/linux-arm64.tar.gz,
6888
"log": <ToolingLog>,
6989
"retries": 3,
70-
"sha256": "d86ced75b794fbf518b90908847b3c09a50f3ff5a2815aa30f53080f926a2873",
71-
"url": "https://d1v1sj258etie.cloudfront.net/node-re2/releases/download/1.17.4/linux-arm64-83.tar.gz",
90+
"sha256": "mock-sha256",
91+
"url": "https://example.com/mock-native-module/linux-arm64.tar.gz",
7292
},
7393
],
7494
]
7595
`);
76-
});
96+
});
7797

78-
it('for .tar.gz artifact, patch native modules task unzip it via untar', async () => {
79-
const { config, build } = await setup();
80-
config.targetPlatforms.linuxArm = true;
81-
await PatchNativeModules.run(config, log, build);
82-
expect(untar.mock.calls.length).toBe(1);
83-
expect(gunzip.mock.calls.length).toBe(0);
84-
});
98+
it('for .tar.gz artifact, patch native modules task unzip it via untar', async () => {
99+
const { config, build } = await setup();
100+
config.targetPlatforms.linuxArm = true;
101+
const PatchNativeModulesWithMock = createPatchNativeModulesTask([mockPackage]);
102+
await PatchNativeModulesWithMock.run(config, log, build);
103+
expect(untar).toHaveBeenCalled();
104+
expect(gunzip).not.toHaveBeenCalled();
105+
});
85106

86-
it('for .gz artifact, patch native modules task unzip it via gunzip', async () => {
87-
const { config, build } = await setup();
88-
config.targetPlatforms.linux = true;
89-
await PatchNativeModules.run(config, log, build);
90-
expect(untar.mock.calls.length).toBe(0);
91-
expect(gunzip.mock.calls.length).toBe(1);
107+
it('for .gz artifact, patch native modules task unzip it via gunzip', async () => {
108+
const mockPackageGZ = {
109+
...mockPackage,
110+
extractMethod: 'gunzip',
111+
};
112+
const { config, build } = await setup();
113+
config.targetPlatforms.linux = true;
114+
const PatchNativeModulesWithMock = createPatchNativeModulesTask([mockPackageGZ]);
115+
await PatchNativeModulesWithMock.run(config, log, build);
116+
expect(gunzip).toHaveBeenCalled();
117+
expect(untar).not.toHaveBeenCalled();
118+
});
119+
120+
it('throws error for unsupported extract methods', async () => {
121+
const mockPackageUnsupported = {
122+
...mockPackage,
123+
extractMethod: 'unsupported',
124+
};
125+
const { config, build } = await setup();
126+
config.targetPlatforms.linux = true;
127+
const PatchNativeModulesWithMock = createPatchNativeModulesTask([mockPackageUnsupported]);
128+
await expect(PatchNativeModulesWithMock.run(config, log, build)).rejects.toThrow(
129+
'Extract method of unsupported is not supported'
130+
);
131+
});
92132
});

src/dev/build/tasks/patch_native_modules_task.ts

+18-51
Original file line numberDiff line numberDiff line change
@@ -52,45 +52,7 @@ interface Package {
5252
>;
5353
}
5454

55-
/* Process for updating URLs and checksums after bumping the version of `re2` or NodeJS:
56-
* 1. Match the `version` with the version in the yarn.lock file.
57-
* 2. Match the module version, the digits at the end of the filename, with the output of
58-
* `node -p process.versions.modules`.
59-
* 3. Confirm that the URLs exist for each platform-architecture combo on
60-
* https://github.com/uhop/node-re2/releases/tag/[VERSION]; reach out to maintainers for ARM
61-
* releases of `re2` as they currently don't have an official ARM release.
62-
* 4. Generate new checksums for each artifact by downloading each one and calling
63-
* `shasum -a 256` or `sha256sum` on the downloaded file.
64-
*/
65-
const packages: Package[] = [
66-
{
67-
name: 're2',
68-
version: '1.17.4',
69-
destinationPath: 'node_modules/re2/build/Release/re2.node',
70-
extractMethod: 'gunzip',
71-
archives: {
72-
'darwin-x64': {
73-
url: 'https://github.com/uhop/node-re2/releases/download/1.17.4/darwin-x64-83.gz',
74-
sha256: '9112ed93c1544ecc6397f7ff20bd2b28f3b04c7fbb54024e10f9a376a132a87d',
75-
},
76-
'linux-x64': {
77-
url: 'https://github.com/uhop/node-re2/releases/download/1.17.4/linux-x64-83.gz',
78-
sha256: '86e03540783a18c41f81df0aec320b1f64aca6cbd3a87fc1b7a9b4109c5f5986',
79-
},
80-
'linux-arm64': {
81-
url:
82-
'https://d1v1sj258etie.cloudfront.net/node-re2/releases/download/1.17.4/linux-arm64-83.tar.gz',
83-
sha256: 'd86ced75b794fbf518b90908847b3c09a50f3ff5a2815aa30f53080f926a2873',
84-
overriddenExtractMethod: 'untar',
85-
overriddenDestinationPath: 'node_modules/re2/build/Release',
86-
},
87-
'win32-x64': {
88-
url: 'https://github.com/uhop/node-re2/releases/download/1.17.4/win32-x64-83.gz',
89-
sha256: '2f842d9757288afd4bd5dec0e7b370a4c3e89ac98050598b17abb9e8e00e3294',
90-
},
91-
},
92-
},
93-
];
55+
export const packages: Package[] = [];
9456

9557
async function getInstalledVersion(config: Config, packageName: string) {
9658
const packageJSONPath = config.resolveFromRepo(
@@ -145,15 +107,20 @@ async function patchModule(
145107
}
146108
}
147109

148-
export const PatchNativeModules: Task = {
149-
description: 'Patching platform-specific native modules',
150-
async run(config, log, build) {
151-
for (const pkg of packages) {
152-
await Promise.all(
153-
config.getTargetPlatforms().map(async (platform) => {
154-
await patchModule(config, log, build, platform, pkg);
155-
})
156-
);
157-
}
158-
},
159-
};
110+
export function createPatchNativeModulesTask(customPackages?: Package[]): Task {
111+
return {
112+
description: 'Patching platform-specific native modules',
113+
async run(config, log, build) {
114+
const targetPackages = customPackages || packages;
115+
for (const pkg of targetPackages) {
116+
await Promise.all(
117+
config.getTargetPlatforms().map(async (platform) => {
118+
await patchModule(config, log, build, platform, pkg);
119+
})
120+
);
121+
}
122+
},
123+
};
124+
}
125+
126+
export const PatchNativeModules = createPatchNativeModulesTask();

src/plugins/vis_type_timeline/server/series_functions/label.js

+2-4
Original file line numberDiff line numberDiff line change
@@ -62,10 +62,8 @@ export default new Chainable('label', {
6262
const config = args.byName;
6363
return alter(args, function (eachSeries) {
6464
if (config.regex) {
65-
// not using a standard `import` so that if there's an issue with the re2 native module
66-
// that it doesn't prevent OpenSearch Dashboards from starting up and we only have an issue using Timeline labels
67-
const RE2 = require('re2');
68-
eachSeries.label = eachSeries.label.replace(new RE2(config.regex), config.label);
65+
const regex = new RegExp(config.regex);
66+
eachSeries.label = eachSeries.label.replace(regex, config.label);
6967
} else {
7068
eachSeries.label = config.label;
7169
}

src/plugins/vis_type_timeline/server/series_functions/label.test.js

+20
Original file line numberDiff line numberDiff line change
@@ -51,4 +51,24 @@ describe('label.js', () => {
5151
expect(r.output.list[0].label).to.equal('beerative');
5252
});
5353
});
54+
55+
it('can use a regex to capture groups to modify series label', () => {
56+
return invoke(fn, [seriesList, 'beer$2', '(N)(egative)']).then((r) => {
57+
expect(r.output.list[0].label).to.equal('beeregative');
58+
});
59+
});
60+
61+
it('can handle different regex patterns', () => {
62+
const seriesListCopy1 = JSON.parse(JSON.stringify(seriesList));
63+
const seriesListCopy2 = JSON.parse(JSON.stringify(seriesList));
64+
65+
return Promise.all([
66+
invoke(fn, [seriesListCopy1, 'beer$1 - $2', '(N)(egative)']).then((r) => {
67+
expect(r.output.list[0].label).to.equal('beerN - egative');
68+
}),
69+
invoke(fn, [seriesListCopy2, 'beer$1_$2', '(N)(eg.*)']).then((r) => {
70+
expect(r.output.list[0].label).to.equal('beerN_egative');
71+
}),
72+
]);
73+
});
5474
});

yarn.lock

+6-43
Original file line numberDiff line numberDiff line change
@@ -4342,7 +4342,7 @@ agentkeepalive@^3.4.1:
43424342
dependencies:
43434343
humanize-ms "^1.2.1"
43444344

4345-
agentkeepalive@^4.1.3:
4345+
agentkeepalive@^4.1.3, agentkeepalive@^4.2.1:
43464346
version "4.3.0"
43474347
resolved "https://registry.yarnpkg.com/agentkeepalive/-/agentkeepalive-4.3.0.tgz#bb999ff07412653c1803b3ced35e50729830a255"
43484348
integrity sha512-7Epl1Blf4Sy37j4v9f9FjICCh4+KAQOyXgHEwlyBiAQLbhKdq/i2QQU3amQalS/wPhdPzDXPL5DMR5bkn+YeWg==
@@ -4351,15 +4351,6 @@ agentkeepalive@^4.1.3:
43514351
depd "^2.0.0"
43524352
humanize-ms "^1.2.1"
43534353

4354-
agentkeepalive@^4.2.1:
4355-
version "4.2.1"
4356-
resolved "https://registry.yarnpkg.com/agentkeepalive/-/agentkeepalive-4.2.1.tgz#a7975cbb9f83b367f06c90cc51ff28fe7d499717"
4357-
integrity sha512-Zn4cw2NEqd+9fiSVWMscnjyQ1a8Yfoc5oBajLeo5w+YBHgDUcEBY2hS4YpTz6iN5f/2zQiktcuM6tS8x1p9dpA==
4358-
dependencies:
4359-
debug "^4.1.0"
4360-
depd "^1.1.2"
4361-
humanize-ms "^1.2.1"
4362-
43634354
aggregate-error@^3.0.0:
43644355
version "3.1.0"
43654356
resolved "https://registry.yarnpkg.com/aggregate-error/-/aggregate-error-3.1.0.tgz#92670ff50f5359bdb7a3e0d40d0ec30c5737687a"
@@ -7129,7 +7120,7 @@ delayed-stream@~1.0.0:
71297120
delegates@^1.0.0:
71307121
version "1.0.0"
71317122
resolved "https://registry.yarnpkg.com/delegates/-/delegates-1.0.0.tgz#84c6e159b81904fdca59a0ef44cd870d31250f9a"
7132-
integrity sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o=
7123+
integrity sha512-bd2L678uiWATM6m5Z1VzNCErI3jiGzt6HGY8OVICs40JQq/HALfbyNJmp0UDakEY4pMMaN0Ly5om/B1VI/+xfQ==
71337124

71347125
delete-empty@^2.0.0:
71357126
version "2.0.0"
@@ -7140,11 +7131,6 @@ delete-empty@^2.0.0:
71407131
relative "^3.0.2"
71417132
rimraf "^2.6.2"
71427133

7143-
depd@^1.1.2:
7144-
version "1.1.2"
7145-
resolved "https://registry.yarnpkg.com/depd/-/depd-1.1.2.tgz#9bcd52e14c097763e749b274c4346ed2e560b5a9"
7146-
integrity sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=
7147-
71487134
depd@^2.0.0:
71497135
version "2.0.0"
71507136
resolved "https://registry.yarnpkg.com/depd/-/depd-2.0.0.tgz#b696163cc757560d09cf22cc8fad1571b79e76df"
@@ -10246,11 +10232,6 @@ inquirer@^7.0.0, inquirer@^7.3.3:
1024610232
strip-ansi "^6.0.0"
1024710233
through "^2.3.6"
1024810234

10249-
install-artifact-from-github@^1.3.0:
10250-
version "1.3.1"
10251-
resolved "https://registry.yarnpkg.com/install-artifact-from-github/-/install-artifact-from-github-1.3.1.tgz#eefaad9af35d632e5d912ad1569c1de38c3c2462"
10252-
integrity sha512-3l3Bymg2eKDsN5wQuMfgGEj2x6l5MCAv0zPL6rxHESufFVlEAKW/6oY9F1aGgvY/EgWm5+eWGRjINveL4X7Hgg==
10253-
1025410235
internal-slot@^1.0.3:
1025510236
version "1.0.3"
1025610237
resolved "https://registry.yarnpkg.com/internal-slot/-/internal-slot-1.0.3.tgz#7347e307deeea2faac2ac6205d4bc7d34967f59c"
@@ -12729,26 +12710,17 @@ minipass-sized@^1.0.3:
1272912710
dependencies:
1273012711
minipass "^3.0.0"
1273112712

12732-
minipass@^3.0.0, minipass@^3.1.1:
12733-
version "3.1.6"
12734-
resolved "https://registry.yarnpkg.com/minipass/-/minipass-3.1.6.tgz#3b8150aa688a711a1521af5e8779c1d3bb4f45ee"
12735-
integrity sha512-rty5kpw9/z8SX9dmxblFA6edItUmwJgMeYDZRrwlIVN27i8gysGbznJwUggw2V/FVqFSDdWy040ZPS811DYAqQ==
12736-
dependencies:
12737-
yallist "^4.0.0"
12738-
12739-
minipass@^3.1.0, minipass@^3.1.3, minipass@^3.1.6:
12713+
minipass@^3.0.0, minipass@^3.1.0, minipass@^3.1.1, minipass@^3.1.3, minipass@^3.1.6:
1274012714
version "3.3.6"
1274112715
resolved "https://registry.yarnpkg.com/minipass/-/minipass-3.3.6.tgz#7bba384db3a1520d18c9c0e5251c3444e95dd94a"
1274212716
integrity sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==
1274312717
dependencies:
1274412718
yallist "^4.0.0"
1274512719

1274612720
minipass@^4.0.0:
12747-
version "4.0.0"
12748-
resolved "https://registry.yarnpkg.com/minipass/-/minipass-4.0.0.tgz#7cebb0f9fa7d56f0c5b17853cbe28838a8dbbd3b"
12749-
integrity sha512-g2Uuh2jEKoht+zvO6vJqXmYpflPqzRBT+Th2h01DKh5z7wbY/AZ2gCQ78cP70YoHPyFdY30YBV5WxgLOEwOykw==
12750-
dependencies:
12751-
yallist "^4.0.0"
12721+
version "4.2.8"
12722+
resolved "https://registry.yarnpkg.com/minipass/-/minipass-4.2.8.tgz#f0010f64393ecfc1d1ccb5f582bcaf45f48e1a3a"
12723+
integrity sha512-fNzuVyifolSLFL4NzpF+wEF4qrgqaaKX0haXPQEdQ7NKAN+WecoKMHV09YcuL/DHxrUsYQOK3MiuDf7Ip2OXfQ==
1275212724

1275312725
minipass@^5.0.0:
1275412726
version "5.0.0"
@@ -14599,15 +14571,6 @@ re-reselect@^3.4.0:
1459914571
resolved "https://registry.yarnpkg.com/re-reselect/-/re-reselect-3.4.0.tgz#0f2303f3c84394f57f0cd31fea08a1ca4840a7cd"
1460014572
integrity sha512-JsecfN+JlckncVXTWFWjn0Vk6uInl8GSf4eEd9tTk5qXHlgqkPdILpnYpgZcISXNYAzvfvsCZviaDk8AxyS5sg==
1460114573

14602-
re2@1.17.4:
14603-
version "1.17.4"
14604-
resolved "https://registry.yarnpkg.com/re2/-/re2-1.17.4.tgz#7bf29290bdde963014e77bd2c2e799a6d788386e"
14605-
integrity sha512-xyZ4h5PqE8I9tAxTh3G0UttcK5ufrcUxReFjGzfX61vtanNbS1XZHjnwRSyPcLgChI4KLxVgOT/ioZXnUAdoTA==
14606-
dependencies:
14607-
install-artifact-from-github "^1.3.0"
14608-
nan "^2.15.0"
14609-
node-gyp "^8.4.1"
14610-
1461114574
react-ace@^7.0.5:
1461214575
version "7.0.5"
1461314576
resolved "https://registry.yarnpkg.com/react-ace/-/react-ace-7.0.5.tgz#798299fd52ddf3a3dcc92afc5865538463544f01"

0 commit comments

Comments
 (0)