Skip to content

Commit 226d0e3

Browse files
authored
Move integration test to artifact API (#1436)
1 parent 9fa1e12 commit 226d0e3

File tree

4 files changed

+175
-107
lines changed

4 files changed

+175
-107
lines changed

.ci/Dockerfile

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,10 @@ FROM node:${NODE_JS_VERSION}
44
# Create app directory
55
WORKDIR /usr/src/app
66

7+
RUN apt-get clean -y
8+
RUN apt-get update -y
9+
RUN apt-get install -y zip
10+
711
# Install app dependencies
812
COPY package*.json ./
913
RUN npm install

package.json

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@
5050
"@sinonjs/fake-timers": "github:sinonjs/fake-timers#0bfffc1",
5151
"@types/node": "^14.14.28",
5252
"convert-hrtime": "^3.0.0",
53+
"cross-zip": "^4.0.0",
5354
"dedent": "^0.7.0",
5455
"deepmerge": "^4.2.2",
5556
"dezalgo": "^1.0.3",
@@ -58,6 +59,7 @@
5859
"js-yaml": "^4.0.0",
5960
"license-checker": "^25.0.1",
6061
"minimist": "^1.2.5",
62+
"node-fetch": "^2.6.1",
6163
"ora": "^5.3.0",
6264
"pretty-hrtime": "^1.0.3",
6365
"proxy": "^1.0.2",
@@ -102,4 +104,4 @@
102104
"coverage": false,
103105
"jobs-auto": true
104106
}
105-
}
107+
}

scripts/download-artifacts.js

Lines changed: 159 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,159 @@
1+
'use strict'
2+
3+
const { join } = require('path')
4+
const minimist = require('minimist')
5+
const stream = require('stream')
6+
const { promisify } = require('util')
7+
const { createWriteStream, promises } = require('fs')
8+
const rimraf = require('rimraf')
9+
const fetch = require('node-fetch')
10+
const crossZip = require('cross-zip')
11+
const ora = require('ora')
12+
13+
const { mkdir, writeFile } = promises
14+
const pipeline = promisify(stream.pipeline)
15+
const unzip = promisify(crossZip.unzip)
16+
const rm = promisify(rimraf)
17+
18+
const esFolder = join(__dirname, '..', 'elasticsearch')
19+
const zipFolder = join(esFolder, 'artifacts.zip')
20+
const specFolder = join(esFolder, 'rest-api-spec', 'api')
21+
const freeTestFolder = join(esFolder, 'rest-api-spec', 'test', 'free')
22+
const xPackTestFolder = join(esFolder, 'rest-api-spec', 'test', 'platinum')
23+
const artifactInfo = join(esFolder, 'info.json')
24+
25+
async function downloadArtifacts (opts) {
26+
if (typeof opts.version !== 'string') {
27+
throw new Error('Missing version')
28+
}
29+
30+
const log = ora('Checking out spec and test').start()
31+
32+
log.text = 'Resolving versions'
33+
let resolved
34+
try {
35+
resolved = await resolve(opts.version, opts.hash)
36+
} catch (err) {
37+
log.fail(err.message)
38+
process.exit(1)
39+
}
40+
41+
opts.id = opts.id || resolved.id
42+
opts.hash = opts.hash || resolved.hash
43+
opts.version = resolved.version
44+
45+
const info = loadInfo()
46+
47+
if (info && info.version === opts.version) {
48+
if (info.hash === opts.hash && info.id === opts.id) {
49+
log.succeed('The artifact copy present locally is already up to date')
50+
return
51+
}
52+
}
53+
54+
log.text = 'Cleanup checkouts/elasticsearch'
55+
await rm(esFolder)
56+
await mkdir(esFolder, { recursive: true })
57+
58+
log.text = 'Downloading artifacts'
59+
const response = await fetch(resolved.url)
60+
if (!response.ok) {
61+
log.fail(`unexpected response ${response.statusText}`)
62+
process.exit(1)
63+
}
64+
await pipeline(response.body, createWriteStream(zipFolder))
65+
66+
log.text = 'Unzipping'
67+
await unzip(zipFolder, esFolder)
68+
69+
log.text = 'Cleanup'
70+
await rm(zipFolder)
71+
72+
log.text = 'Update info'
73+
await writeFile(artifactInfo, JSON.stringify(opts), 'utf8')
74+
75+
log.succeed('Done')
76+
}
77+
78+
function loadInfo () {
79+
try {
80+
return require(artifactInfo)
81+
} catch (err) {
82+
return null
83+
}
84+
}
85+
86+
async function resolve (version, hash) {
87+
const response = await fetch(`https://artifacts-api.elastic.co/v1/versions/${version}`)
88+
if (!response.ok) {
89+
throw new Error(`unexpected response ${response.statusText}`)
90+
}
91+
92+
const data = await response.json()
93+
const esBuilds = data.version.builds
94+
.filter(build => build.projects.elasticsearch != null)
95+
.map(build => {
96+
return {
97+
projects: build.projects.elasticsearch,
98+
buildId: build.build_id,
99+
date: build.start_time,
100+
version: build.version
101+
}
102+
})
103+
.sort((a, b) => {
104+
const dA = new Date(a.date)
105+
const dB = new Date(b.date)
106+
if (dA > dB) return -1
107+
if (dA < dB) return 1
108+
return 0
109+
})
110+
111+
if (hash != null) {
112+
const build = esBuilds.find(build => build.projects.commit_hash === hash)
113+
if (!build) {
114+
throw new Error(`Can't find any build with hash '${hash}'`)
115+
}
116+
const zipKey = Object.keys(build.projects.packages).find(key => key.startsWith('rest-resources-zip-') && key.endsWith('.zip'))
117+
return {
118+
url: build.projects.packages[zipKey].url,
119+
id: build.buildId,
120+
hash: build.projects.commit_hash,
121+
version: build.version
122+
}
123+
}
124+
125+
const lastBuild = esBuilds[0]
126+
const zipKey = Object.keys(lastBuild.projects.packages).find(key => key.startsWith('rest-resources-zip-') && key.endsWith('.zip'))
127+
return {
128+
url: lastBuild.projects.packages[zipKey].url,
129+
id: lastBuild.buildId,
130+
hash: lastBuild.projects.commit_hash,
131+
version: lastBuild.version
132+
}
133+
}
134+
135+
async function main (options) {
136+
delete options._
137+
await downloadArtifacts(options)
138+
}
139+
if (require.main === module) {
140+
process.on('unhandledRejection', function (err) {
141+
console.error(err)
142+
process.exit(1)
143+
})
144+
145+
const options = minimist(process.argv.slice(2), {
146+
string: ['id', 'version', 'hash']
147+
})
148+
main(options).catch(t => {
149+
console.log(t)
150+
process.exit(2)
151+
})
152+
}
153+
154+
module.exports = downloadArtifacts
155+
module.exports.locations = {
156+
specFolder,
157+
freeTestFolder,
158+
xPackTestFolder
159+
}

test/integration/index.js

Lines changed: 9 additions & 106 deletions
Original file line numberDiff line numberDiff line change
@@ -24,20 +24,18 @@ process.on('unhandledRejection', function (err) {
2424
process.exit(1)
2525
})
2626

27-
const { writeFileSync, readFileSync, accessSync, mkdirSync, readdirSync, statSync } = require('fs')
27+
const { writeFileSync, readFileSync, readdirSync, statSync } = require('fs')
2828
const { join, sep } = require('path')
2929
const yaml = require('js-yaml')
30-
const Git = require('simple-git')
3130
const ms = require('ms')
3231
const { Client } = require('../../index')
3332
const build = require('./test-runner')
3433
const { sleep } = require('./helper')
3534
const createJunitReporter = require('./reporter')
35+
const downloadArtifacts = require('../../scripts/download-artifacts')
3636

37-
const esRepo = 'https://github.com/elastic/elasticsearch.git'
38-
const esFolder = join(__dirname, '..', '..', 'elasticsearch')
39-
const yamlFolder = join(esFolder, 'rest-api-spec', 'src', 'main', 'resources', 'rest-api-spec', 'test')
40-
const xPackYamlFolder = join(esFolder, 'x-pack', 'plugin', 'src', 'test', 'resources', 'rest-api-spec', 'test')
37+
const yamlFolder = downloadArtifacts.locations.freeTestFolder
38+
const xPackYamlFolder = downloadArtifacts.locations.xPackTestFolder
4139

4240
const MAX_API_TIME = 1000 * 90
4341
const MAX_FILE_TIME = 1000 * 30
@@ -84,6 +82,7 @@ const platinumBlackList = {
8482
],
8583
// The cleanup fails with a index not found when retrieving the jobs
8684
'ml/get_datafeed_stats.yml': ['Test get datafeed stats when total_search_time_ms mapping is missing'],
85+
'ml/preview_datafeed.yml': ['*'],
8786
// Investigate why is failing
8887
'ml/inference_crud.yml': ['*'],
8988
// investigate why this is failing
@@ -169,10 +168,10 @@ async function start ({ client, isXPack }) {
169168
await waitCluster(client)
170169

171170
const { body } = await client.info()
172-
const { number: version, build_hash: sha } = body.version
171+
const { number: version, build_hash: hash } = body.version
173172

174-
log(`Checking out sha ${sha}...`)
175-
await withSHA(sha)
173+
log(`Downloading artifacts for hash ${hash}...`)
174+
await downloadArtifacts({ hash, version })
176175

177176
log(`Testing ${isXPack ? 'Platinum' : 'Free'} api...`)
178177
const junit = createJunitReporter()
@@ -217,7 +216,7 @@ async function start ({ client, isXPack }) {
217216
const testRunner = build({
218217
client,
219218
version,
220-
isXPack: file.includes('x-pack')
219+
isXPack: file.includes('platinum')
221220
})
222221
const fileTime = now()
223222
const data = readFileSync(file, 'utf8')
@@ -325,102 +324,6 @@ function parse (data) {
325324
return doc
326325
}
327326

328-
/**
329-
* Sets the elasticsearch repository to the given sha.
330-
* If the repository is not present in `esFolder` it will
331-
* clone the repository and the checkout the sha.
332-
* If the repository is already present but it cannot checkout to
333-
* the given sha, it will perform a pull and then try again.
334-
* @param {string} sha
335-
* @param {function} callback
336-
*/
337-
function withSHA (sha) {
338-
return new Promise((resolve, reject) => {
339-
_withSHA(err => err ? reject(err) : resolve())
340-
})
341-
342-
function _withSHA (callback) {
343-
let fresh = false
344-
let retry = 0
345-
346-
if (!pathExist(esFolder)) {
347-
if (!createFolder(esFolder)) {
348-
return callback(new Error('Failed folder creation'))
349-
}
350-
fresh = true
351-
}
352-
353-
const git = Git(esFolder)
354-
355-
if (fresh) {
356-
clone(checkout)
357-
} else {
358-
checkout()
359-
}
360-
361-
function checkout () {
362-
log(`Checking out sha '${sha}'`)
363-
git.checkout(sha, err => {
364-
if (err) {
365-
if (retry++ > 0) {
366-
return callback(err)
367-
}
368-
return pull(checkout)
369-
}
370-
callback()
371-
})
372-
}
373-
374-
function pull (cb) {
375-
log('Pulling elasticsearch repository...')
376-
git.pull(err => {
377-
if (err) {
378-
return callback(err)
379-
}
380-
cb()
381-
})
382-
}
383-
384-
function clone (cb) {
385-
log('Cloning elasticsearch repository...')
386-
git.clone(esRepo, esFolder, err => {
387-
if (err) {
388-
return callback(err)
389-
}
390-
cb()
391-
})
392-
}
393-
}
394-
}
395-
396-
/**
397-
* Checks if the given path exists
398-
* @param {string} path
399-
* @returns {boolean} true if exists, false if not
400-
*/
401-
function pathExist (path) {
402-
try {
403-
accessSync(path)
404-
return true
405-
} catch (err) {
406-
return false
407-
}
408-
}
409-
410-
/**
411-
* Creates the given folder
412-
* @param {string} name
413-
* @returns {boolean} true on success, false on failure
414-
*/
415-
function createFolder (name) {
416-
try {
417-
mkdirSync(name)
418-
return true
419-
} catch (err) {
420-
return false
421-
}
422-
}
423-
424327
function generateJunitXmlReport (junit, suite) {
425328
writeFileSync(
426329
join(__dirname, '..', '..', `${suite}-report-junit.xml`),

0 commit comments

Comments
 (0)