Skip to content

Commit 8fc5fe7

Browse files
committed
[Tests] updated artifact script
Updating artifact to enable running integration tests and functional tests to pull an artifact from the current hosted distributions. At the time of this commit, there is not manifest hosted but there are static links which can have an unknown amount of RC versions if the GA snapshot does not exist for that version. But the assumption is that it will not be too high. Deprecating the previous implementation but we can remove that in a future iteration. Wanted to leave that available incase others use that for custom manifests. Enable tests that depended on snapshots as well. Issues resolved: opensearch-project#242 opensearch-project#19 Signed-off-by: Kawika Avilla <kavilla414@gmail.com>
1 parent ed17dd9 commit 8fc5fe7

File tree

5 files changed

+175
-104
lines changed

5 files changed

+175
-104
lines changed

packages/osd-opensearch-archiver/src/lib/docs/__tests__/generate_doc_records_stream.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,7 @@ describe('opensearchArchiver: createGenerateDocRecordsStream()', () => {
104104
await delay(200);
105105
return {
106106
_scroll_id: 'index1ScrollId',
107-
hits: { total: 2, hits: [{ _id: 1, _index: '.opensearch_dashboards_foo' }] },
107+
hits: { total: 2, hits: [{ _id: 1, _index: '.opensearch_dashboards_1' }] },
108108
};
109109
},
110110
async (name, params) => {

packages/osd-opensearch/src/artifact.js

+100-5
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,6 @@
2929
* Modifications Copyright OpenSearch Contributors. See
3030
* GitHub history for details.
3131
*/
32-
3332
const fetch = require('node-fetch');
3433
const AbortController = require('abort-controller');
3534
const fs = require('fs');
@@ -40,8 +39,12 @@ const { createHash } = require('crypto');
4039
const path = require('path');
4140

4241
const asyncPipeline = promisify(pipeline);
43-
const DAILY_SNAPSHOTS_BASE_URL = '';
42+
const DAILY_SNAPSHOTS_BASE_URL = 'https://artifacts.opensearch.org/snapshots/core/opensearch';
43+
// TODO: [RENAMEME] currently do not have an existing replacement
44+
// issue: https://github.com/opensearch-project/OpenSearch-Dashboards/issues/475
4445
const PERMANENT_SNAPSHOTS_BASE_URL = '';
46+
// Since we do not have a manifest URL, limiting how many RC checks to 5 should be more than enough
47+
const MAX_RC_CHECK = 5;
4548

4649
const { cache } = require('./utils');
4750
const { resolveCustomSnapshotUrl } = require('./custom_snapshots');
@@ -96,6 +99,21 @@ async function fetchSnapshotManifest(url, log) {
9699
return { abc, resp, json };
97100
}
98101

102+
async function verifySnapshotUrl(url, log) {
103+
log.info('Verifying snapshot URL at %s', chalk.bold(url));
104+
105+
const abc = new AbortController();
106+
const resp = await retry(
107+
log,
108+
async () => await fetch(url, { signal: abc.signal }, { method: 'HEAD' })
109+
);
110+
111+
return { abc, resp };
112+
}
113+
114+
/**
115+
* @deprecated This method should not be used, uses logic for resources we do not have access to.
116+
*/
99117
async function getArtifactSpecForSnapshot(urlVersion, license, log) {
100118
const desiredVersion = urlVersion.replace('-SNAPSHOT', '');
101119
const desiredLicense = license === 'oss' ? 'oss' : 'default';
@@ -153,10 +171,87 @@ async function getArtifactSpecForSnapshot(urlVersion, license, log) {
153171
};
154172
}
155173

174+
async function getArtifactSpecForSnapshotFromUrl(urlVersion, log) {
175+
const desiredVersion = urlVersion.replace('-SNAPSHOT', '');
176+
177+
if (process.env.OPENSEARCH_SNAPSHOT_MANIFEST) {
178+
return await getArtifactSpecForSnapshot(urlVersion, 'oss', log);
179+
}
180+
181+
// [RENAMEME] Need replacement for other platforms.
182+
// issue: https://github.com/opensearch-project/OpenSearch-Dashboards/issues/475
183+
const platform = process.platform === 'win32' ? 'windows' : process.platform;
184+
const arch = process.arch === 'arm64' ? 'arm64' : 'x64';
185+
if (platform !== 'linux' || arch !== 'x64') {
186+
throw createCliError(`Snapshots are only available for Linux x64`);
187+
}
188+
189+
const latestUrl = `${DAILY_SNAPSHOTS_BASE_URL}/${desiredVersion}`;
190+
const latestFile = `opensearch-${desiredVersion}-SNAPSHOT-${platform}-${arch}-latest.tar.gz`;
191+
const completeLatestUrl = `${latestUrl}/${latestFile}`;
192+
193+
let { abc, resp } = await verifySnapshotUrl(completeLatestUrl, log);
194+
195+
if (resp.ok) {
196+
return {
197+
url: completeLatestUrl,
198+
checksumUrl: completeLatestUrl + '.sha512',
199+
checksumType: 'sha512',
200+
filename: latestFile,
201+
};
202+
}
203+
204+
log.info(
205+
'Daily general-availability snapshot URL not found for current version, falling back to release-candidate snapshot URL.'
206+
);
207+
208+
let completeUrl = null;
209+
let snapshotFile = null;
210+
211+
// This checks and uses an RC if a RC exists at a higher increment than RC1 or it tries to use RC1
212+
// This is in replacement of having a manifest URL, so the exact RC number is unknown but expect it not to be a large number
213+
let rcCheck = MAX_RC_CHECK;
214+
do {
215+
const secondaryLatestUrl = `${DAILY_SNAPSHOTS_BASE_URL}/${desiredVersion}-rc${rcCheck}`;
216+
const secondaryLatestFile = `opensearch-${desiredVersion}-rc${rcCheck}-SNAPSHOT-${platform}-${arch}-latest.tar.gz`;
217+
const completeSecondaryLatestUrl = `${secondaryLatestUrl}/${secondaryLatestFile}`;
218+
({ abc, resp } = await verifySnapshotUrl(completeSecondaryLatestUrl, log));
219+
220+
if (resp.ok) {
221+
completeUrl = completeSecondaryLatestUrl;
222+
snapshotFile = secondaryLatestFile;
223+
break;
224+
}
225+
} while (rcCheck-- >= 1);
226+
227+
if (resp.status === 404 || !completeUrl || !snapshotFile) {
228+
abc.abort();
229+
throw createCliError(`Snapshots for ${desiredVersion} are not available`);
230+
}
231+
232+
if (!resp.ok) {
233+
abc.abort();
234+
throw new Error(`Unable to read snapshot url: ${resp.statusText}`);
235+
}
236+
237+
return {
238+
url: completeUrl,
239+
checksumUrl: completeUrl + '.sha512',
240+
checksumType: 'sha512',
241+
filename: snapshotFile,
242+
};
243+
}
244+
156245
exports.Artifact = class Artifact {
157246
/**
158-
* Fetch an Artifact from the Artifact API for a license level and version
159-
* @param {('oss'|'basic'|'trial')} license
247+
* Fetch an Artifact from the Artifact API for a license level and version.
248+
* Only OSS license should be used but the param was left to mitigate impact
249+
* until a later iteration.
250+
*
251+
* TODO: [RENAMEME] remove license param
252+
* issue: https://github.com/opensearch-project/OpenSearch-Dashboards/issues/475
253+
*
254+
* @param {('oss')} license
160255
* @param {string} version
161256
* @param {ToolingLog} log
162257
*/
@@ -168,7 +263,7 @@ exports.Artifact = class Artifact {
168263
return new Artifact(customSnapshotArtifactSpec, log);
169264
}
170265

171-
const artifactSpec = await getArtifactSpecForSnapshot(urlVersion, license, log);
266+
const artifactSpec = await getArtifactSpecForSnapshotFromUrl(urlVersion, log);
172267
return new Artifact(artifactSpec, log);
173268
}
174269

packages/osd-opensearch/src/artifact.test.js

+72-94
Original file line numberDiff line numberDiff line change
@@ -40,26 +40,34 @@ import { Artifact } from './artifact';
4040
const log = new ToolingLog();
4141
let MOCKS;
4242

43+
const DAILY_SNAPSHOT_BASE_URL = 'https://artifacts.opensearch.org/snapshots/core/opensearch';
44+
// eslint-disable-next-line no-unused-vars
45+
const PERMANENT_SNAPSHOT_BASE_URL = '';
46+
47+
const ORIGINAL_PLATFROM = process.platform;
48+
const ORIGINAL_ARCHITECTURE = process.arch;
4349
const PLATFORM = process.platform === 'win32' ? 'windows' : process.platform;
4450
const ARCHITECTURE = process.arch === 'arm64' ? 'arm64' : 'x64';
4551
const MOCK_VERSION = 'test-version';
46-
const MOCK_URL = 'http://127.0.0.1:12345';
47-
const MOCK_FILENAME = 'test-filename';
52+
const MOCK_RC_VERSION = `test-version-rc4`;
53+
const MOCK_FILENAME = 'opensearch-test-version-SNAPSHOT-linux-x64-latest.tar.gz';
54+
const MOCK_RC_FILENAME = `opensearch-test-version-rc4-SNAPSHOT-linux-x64-latest.tar.gz`;
55+
const MOCK_URL = `${DAILY_SNAPSHOT_BASE_URL}/${MOCK_VERSION}/${MOCK_FILENAME}`;
56+
const MOCK_RC_URL = `${DAILY_SNAPSHOT_BASE_URL}/${MOCK_RC_VERSION}/${MOCK_RC_FILENAME}`;
4857

49-
const DAILY_SNAPSHOT_BASE_URL = '';
50-
const PERMANENT_SNAPSHOT_BASE_URL = '';
58+
const itif = process.platform === 'linux' && process.arch === 'x64' ? it : it.skip;
5159

5260
const createArchive = (params = {}) => {
53-
const license = params.license || 'default';
5461
const architecture = params.architecture || ARCHITECTURE;
62+
const useRCVersion = params.useRCVersion || false;
5563

5664
return {
57-
license: 'default',
65+
license: 'oss',
5866
architecture,
59-
version: MOCK_VERSION,
60-
url: MOCK_URL + `/${license}`,
67+
version: !useRCVersion ? MOCK_VERSION : MOCK_RC_VERSION,
68+
url: !useRCVersion ? MOCK_URL : MOCK_RC_URL,
6169
platform: PLATFORM,
62-
filename: MOCK_FILENAME + `-${architecture}.${license}`,
70+
filename: !useRCVersion ? MOCK_FILENAME : MOCK_RC_FILENAME,
6371
...params,
6472
};
6573
};
@@ -92,99 +100,87 @@ beforeEach(() => {
92100
jest.resetAllMocks();
93101

94102
MOCKS = {
95-
valid: {
96-
archives: [createArchive({ license: 'oss' }), createArchive({ license: 'default' })],
103+
GA: {
104+
archives: [createArchive({ useRCVersion: false })],
105+
},
106+
RC: {
107+
archives: [createArchive({ useRCVersion: true })],
97108
},
98109
multipleArch: {
99110
archives: [
100-
createArchive({ architecture: 'fake_arch', license: 'oss' }),
101-
createArchive({ architecture: ARCHITECTURE, license: 'oss' }),
111+
createArchive({ architecture: 'fake_arch', useRCVersion: false }),
112+
createArchive({ architecture: ARCHITECTURE, useRCVersion: false }),
102113
],
103114
},
104115
};
105116
});
106117

107-
const artifactTest = (requestedLicense, expectedLicense, fetchTimesCalled = 1) => {
118+
const artifactTest = (fetchTimesCalled = 1) => {
108119
return async () => {
109-
const artifact = await Artifact.getSnapshot(requestedLicense, MOCK_VERSION, log);
120+
const artifact = await Artifact.getSnapshot('oss', MOCK_VERSION, log);
121+
const expectedUrl = fetchTimesCalled === 1 ? MOCK_URL : MOCK_RC_URL;
122+
const expectedFilename = fetchTimesCalled === 1 ? MOCK_FILENAME : MOCK_RC_FILENAME;
110123
expect(fetch).toHaveBeenCalledTimes(fetchTimesCalled);
111-
expect(fetch.mock.calls[0][0]).toEqual(
112-
`${DAILY_SNAPSHOT_BASE_URL}/${MOCK_VERSION}/manifest-latest-verified.json`
113-
);
114-
if (fetchTimesCalled === 2) {
115-
expect(fetch.mock.calls[1][0]).toEqual(
116-
`${PERMANENT_SNAPSHOT_BASE_URL}/${MOCK_VERSION}/manifest.json`
117-
);
124+
expect(fetch.mock.calls[0][0]).toEqual(MOCK_URL);
125+
if (fetchTimesCalled !== 1) {
126+
expect(fetch.mock.calls[fetchTimesCalled - 1][0]).toEqual(MOCK_RC_URL);
118127
}
119-
expect(artifact.getUrl()).toEqual(MOCK_URL + `/${expectedLicense}`);
120-
expect(artifact.getChecksumUrl()).toEqual(MOCK_URL + `/${expectedLicense}.sha512`);
128+
expect(artifact.getUrl()).toEqual(expectedUrl);
129+
expect(artifact.getChecksumUrl()).toEqual(expectedUrl + '.sha512');
121130
expect(artifact.getChecksumType()).toEqual('sha512');
122-
expect(artifact.getFilename()).toEqual(MOCK_FILENAME + `-${ARCHITECTURE}.${expectedLicense}`);
131+
expect(artifact.getFilename()).toEqual(expectedFilename);
123132
};
124133
};
125134

126135
describe('Artifact', () => {
127136
describe('getSnapshot()', () => {
128-
describe('with default snapshot', () => {
129-
beforeEach(() => {
130-
mockFetch(MOCKS.valid);
131-
});
132-
133-
it('should return artifact metadata for a daily oss artifact', artifactTest('oss', 'oss'));
137+
itif('should return artifact metadata for a daily GA artifact', () => {
138+
mockFetch(MOCKS.GA);
139+
artifactTest();
140+
});
134141

135-
it(
136-
'should return artifact metadata for a daily default artifact',
137-
artifactTest('default', 'default')
138-
);
142+
itif('should return artifact metadata for a RC artifact', () => {
143+
fetch.mockReturnValueOnce(Promise.resolve(new Response('', { status: 404 })));
144+
fetch.mockReturnValueOnce(Promise.resolve(new Response('', { status: 404 })));
145+
mockFetch(MOCKS.RC);
146+
artifactTest(3);
147+
});
139148

140-
it(
141-
'should default to default license with anything other than "oss"',
142-
artifactTest('INVALID_LICENSE', 'default')
149+
itif('should throw when an artifact cannot be found for the specified parameters', async () => {
150+
fetch.mockReturnValue(Promise.resolve(new Response('', { status: 404 })));
151+
await expect(Artifact.getSnapshot('default', 'INVALID_VERSION', log)).rejects.toThrow(
152+
'Snapshots for INVALID_VERSION are not available'
143153
);
144-
145-
it('should throw when an artifact cannot be found in the manifest for the specified parameters', async () => {
146-
await expect(Artifact.getSnapshot('default', 'INVALID_VERSION', log)).rejects.toThrow(
147-
"couldn't find an artifact"
148-
);
149-
});
150154
});
151155

152-
describe('with missing default snapshot', () => {
153-
beforeEach(() => {
154-
fetch.mockReturnValueOnce(Promise.resolve(new Response('', { status: 404 })));
155-
mockFetch(MOCKS.valid);
156+
describe('with snapshots for multiple architectures', () => {
157+
afterAll(() => {
158+
Object.defineProperties(process, {
159+
platform: {
160+
value: ORIGINAL_PLATFROM,
161+
},
162+
arch: {
163+
value: ORIGINAL_ARCHITECTURE,
164+
},
165+
});
156166
});
157167

158-
it(
159-
'should return artifact metadata for a permanent oss artifact',
160-
artifactTest('oss', 'oss', 2)
161-
);
162-
163-
it(
164-
'should return artifact metadata for a permanent default artifact',
165-
artifactTest('default', 'default', 2)
166-
);
167-
168-
it(
169-
'should default to default license with anything other than "oss"',
170-
artifactTest('INVALID_LICENSE', 'default', 2)
171-
);
172-
173-
it('should throw when an artifact cannot be found in the manifest for the specified parameters', async () => {
174-
await expect(Artifact.getSnapshot('default', 'INVALID_VERSION', log)).rejects.toThrow(
175-
"couldn't find an artifact"
168+
it('should throw when on a non-Linux platform', async () => {
169+
Object.defineProperty(process, 'platform', {
170+
value: 'win32',
171+
});
172+
await expect(Artifact.getSnapshot('default', 'INVALID_PLATFORM', log)).rejects.toThrow(
173+
'Snapshots are only available for Linux x64'
176174
);
177175
});
178-
});
179-
180-
describe('with snapshots for multiple architectures', () => {
181-
beforeEach(() => {
182-
mockFetch(MOCKS.multipleArch);
183-
});
184176

185-
it('should return artifact metadata for the correct architecture', async () => {
186-
const artifact = await Artifact.getSnapshot('oss', MOCK_VERSION, log);
187-
expect(artifact.getFilename()).toEqual(MOCK_FILENAME + `-${ARCHITECTURE}.oss`);
177+
it('should throw when on a non-x64 arch', async () => {
178+
Object.defineProperty(process, 'arch', {
179+
value: 'arm64',
180+
});
181+
await expect(Artifact.getSnapshot('default', 'INVALID_ARCH', log)).rejects.toThrow(
182+
'Snapshots are only available for Linux x64'
183+
);
188184
});
189185
});
190186

@@ -193,7 +189,7 @@ describe('Artifact', () => {
193189

194190
beforeEach(() => {
195191
process.env.OPENSEARCH_SNAPSHOT_MANIFEST = CUSTOM_URL;
196-
mockFetch(MOCKS.valid);
192+
mockFetch(MOCKS.GA);
197193
});
198194

199195
it('should use the custom URL when looking for a snapshot', async () => {
@@ -205,23 +201,5 @@ describe('Artifact', () => {
205201
delete process.env.OPENSEARCH_SNAPSHOT_MANIFEST;
206202
});
207203
});
208-
209-
describe('with latest unverified snapshot', () => {
210-
beforeEach(() => {
211-
process.env.OSD_OPENSEARCH_SNAPSHOT_USE_UNVERIFIED = 1;
212-
mockFetch(MOCKS.valid);
213-
});
214-
215-
it('should use the daily unverified URL when looking for a snapshot', async () => {
216-
await Artifact.getSnapshot('oss', MOCK_VERSION, log);
217-
expect(fetch.mock.calls[0][0]).toEqual(
218-
`${DAILY_SNAPSHOT_BASE_URL}/${MOCK_VERSION}/manifest-latest.json`
219-
);
220-
});
221-
222-
afterEach(() => {
223-
delete process.env.OSD_OPENSEARCH_SNAPSHOT_USE_UNVERIFIED;
224-
});
225-
});
226204
});
227205
});

src/core/server/ui_settings/create_or_upgrade_saved_config/integration_tests/create_or_upgrade.test.ts

+1-2
Original file line numberDiff line numberDiff line change
@@ -95,8 +95,7 @@ describe('createOrUpgradeSavedConfig()', () => {
9595
await osd.stop();
9696
}, 30000);
9797

98-
// TODO: [RENAMEME] Test can be enabled once there is a valid snapshot URL
99-
xit('upgrades the previous version on each increment', async function () {
98+
it('upgrades the previous version on each increment', async function () {
10099
// ------------------------------------
101100
// upgrade to 5.4.0
102101
await createOrUpgradeSavedConfig({

0 commit comments

Comments
 (0)