add new tests

add ability to generate binary files at runtime
restructure package layout
This commit is contained in:
Florian Schade
2020-12-02 04:02:57 +01:00
parent 1018725cdb
commit 938b2ea576
23 changed files with 1473 additions and 330 deletions

View File

@@ -11,7 +11,7 @@ $ yarn build
## How to run
```console
k6 run ./dist/test/NAME_OF_TEST.js
k6 run ./dist/NAME_OF_TEST.js
```
## Environment variables
@@ -20,5 +20,4 @@ $ OC_LOGIN=USERNAME OC_PASSWORD=PASSWORD k6 run ...
$ OC_HOST=URL k6 run ...
$ OC_OIDC_HOST=URL k6 run ...
$ OC_OIDC_ENABLED=BOOL k6 run ...
$ OC_TEST_FILE=STRING k6 run ...
```

View File

@@ -5,8 +5,7 @@
"scripts": {
"clean": "rm -rf ./dist",
"build": "rollup -c",
"build:w": "rollup -c -w",
"postinstall": "node ./scripts/postinstall.js"
"build:w": "rollup -c -w"
},
"devDependencies": {
"@babel/core": "^7.9.0",
@@ -25,7 +24,6 @@
"@types/lodash": "^4.14.165",
"@typescript-eslint/eslint-plugin": "^2.29.0",
"@typescript-eslint/parser": "^2.29.0",
"axios": "^0.21.0",
"babel-plugin-lodash": "^3.3.4",
"eslint": "^6.8.0",
"eslint-config-prettier": "^6.11.0",
@@ -34,13 +32,11 @@
"jest": "^25.4.0",
"k6": "^0.0.0",
"lint-staged": "^10.1.7",
"ora": "^5.1.0",
"prettier": "^2.0.5",
"rollup": "^2.7.2",
"rollup-plugin-babel": "^4.4.0",
"rollup-plugin-multi-input": "^1.1.1",
"rollup-plugin-terser": "^5.3.0",
"shelljs": "^0.8.4",
"typescript": "^3.8.3"
},
"dependencies": {

View File

@@ -0,0 +1,168 @@
{
"metrics": {
"checks": {
"fails": 0,
"passes": 6003,
"value": 0
},
"data_received": {
"count": 5232948,
"rate": 35275.75112278176
},
"data_sent": {
"count": 4637493,
"rate": 31261.737915538728
},
"http_req_blocked": {
"avg": 0.004372313843078474,
"max": 4.63,
"med": 0.003,
"min": 0.002,
"p(90)": 0.005,
"p(95)": 0.007
},
"http_req_connecting": {
"avg": 0.000056305180742961854,
"max": 0.338,
"med": 0,
"min": 0,
"p(90)": 0,
"p(95)": 0
},
"http_req_duration": {
"avg": 24.326444277861146,
"max": 493.144,
"med": 21.826,
"min": 10.256,
"p(90)": 38.041000000000004,
"p(95)": 43.9535
},
"http_req_receiving": {
"avg": 0.05978927203065133,
"max": 1.579,
"med": 0.05,
"min": 0.036,
"p(90)": 0.085,
"p(95)": 0.104
},
"http_req_sending": {
"avg": 0.03032550391470921,
"max": 0.223,
"med": 0.025,
"min": 0.018,
"p(90)": 0.043,
"p(95)": 0.056
},
"http_req_tls_handshaking": {
"avg": 0.0005380643011827419,
"max": 3.23,
"med": 0,
"min": 0,
"p(90)": 0,
"p(95)": 0
},
"http_req_waiting": {
"avg": 24.23632950191566,
"max": 492.043,
"med": 21.741,
"min": 10.192,
"p(90)": 37.92360000000001,
"p(95)": 43.8319
},
"http_reqs": {
"count": 6003,
"rate": 40.46673767636501
},
"iteration_duration": {
"avg": 49429.791962999996,
"max": 50603.792868,
"med": 49213.89341,
"min": 48471.689611,
"p(90)": 50325.8129764,
"p(95)": 50464.8029222
},
"iterations": {
"count": 3,
"rate": 0.020223257209577714
},
"oc_default_play_dav_file_delete_trend": {
"avg": 16.629310000000025,
"max": 75.491,
"med": 15.1365,
"min": 10.256,
"p(90)": 23.539,
"p(95)": 27.27049999999999
},
"oc_default_play_dav_file_delete_trend{asset:KB1": {
"avg": 16.629310000000025,
"max": 75.491,
"med": 15.1365,
"min": 10.256,
"p(90)": 23.539,
"p(95)": 27.27049999999999
},
"oc_default_play_dav_file_upload_trend": {
"avg": 31.677708999999993,
"max": 267.948,
"med": 29.3345,
"min": 19.082,
"p(90)": 43.212199999999996,
"p(95)": 50.722699999999996
},
"oc_default_play_dav_file_upload_trend{asset:KB1": {
"avg": 31.677708999999993,
"max": 267.948,
"med": 29.3345,
"min": 19.082,
"p(90)": 43.212199999999996,
"p(95)": 50.722699999999996
},
"oc_default_play_dav_propfind_trend": {
"avg": 370.19599999999997,
"max": 493.144,
"med": 310.431,
"min": 307.013,
"p(90)": 456.6014,
"p(95)": 474.8727
},
"vus": {
"max": 1,
"min": 1,
"value": 1
},
"vus_max": {
"max": 1,
"min": 1,
"value": 1
}
},
"root_group": {
"name": "",
"path": "",
"id": "d41d8cd98f00b204e9800998ecf8427e",
"groups": {},
"checks": {
"file delete status is 204": {
"name": "file delete status is 204",
"path": "::file delete status is 204",
"id": "18e4ac556fd01961812afd85e16bb9d9",
"passes": 3000,
"fails": 0
},
"file upload status is 201": {
"name": "file upload status is 201",
"path": "::file upload status is 201",
"id": "d530d65df94c4e70b68aac6f2f054f1f",
"passes": 3000,
"fails": 0
},
"propfind status is 207": {
"name": "propfind status is 207",
"path": "::propfind status is 207",
"id": "6cbc0cbc7ef202f356106cf063105452",
"passes": 3,
"fails": 0
}
}
}
}

View File

@@ -0,0 +1,224 @@
{
"metrics": {
"checks": {
"fails": 0,
"passes": 1440,
"value": 0
},
"data_received": {
"count": 1729675379,
"rate": 33808868.65162363
},
"data_sent": {
"count": 1736098107,
"rate": 33934409.646178715
},
"http_req_blocked": {
"avg": 0.006793055555555532,
"max": 4.046,
"med": 0.003,
"min": 0.002,
"p(90)": 0.006,
"p(95)": 0.008
},
"http_req_connecting": {
"avg": 0.00018055555555555557,
"max": 0.26,
"med": 0,
"min": 0,
"p(90)": 0,
"p(95)": 0
},
"http_req_duration": {
"avg": 32.08864027777775,
"max": 253.272,
"med": 26.4905,
"min": 10.372,
"p(90)": 50.71580000000001,
"p(95)": 64.83449999999998
},
"http_req_receiving": {
"avg": 4.024194444444447,
"max": 128.777,
"med": 0.064,
"min": 0.037,
"p(90)": 14.537700000000015,
"p(95)": 19.81769999999999
},
"http_req_sending": {
"avg": 5.342373611111132,
"max": 132.051,
"med": 0.03,
"min": 0.017,
"p(90)": 22.215200000000003,
"p(95)": 30.02865
},
"http_req_tls_handshaking": {
"avg": 0.00218125,
"max": 3.141,
"med": 0,
"min": 0,
"p(90)": 0,
"p(95)": 0
},
"http_req_waiting": {
"avg": 22.72207222222226,
"max": 251.256,
"med": 21.123,
"min": 8.077,
"p(90)": 34.120799999999996,
"p(95)": 37.62935
},
"http_reqs": {
"count": 1440,
"rate": 28.146767566573555
},
"iteration_duration": {
"avg": 17041.291093666667,
"max": 17397.314603,
"med": 16968.823006,
"min": 16757.735672,
"p(90)": 17311.6162836,
"p(95)": 17354.4654433
},
"iterations": {
"count": 3,
"rate": 0.05863909909702824
},
"oc_default_play_dav_file_delete_trend": {
"avg": 15.769127083333343,
"max": 49.32,
"med": 14.7855,
"min": 10.372,
"p(90)": 21.6302,
"p(95)": 24.0062
},
"oc_default_play_dav_file_delete_trend{asset:KB500": {
"avg": 16.38810000000001,
"max": 49.32,
"med": 15.4255,
"min": 10.372,
"p(90)": 23.0987,
"p(95)": 24.657150000000005
},
"oc_default_play_dav_file_delete_trend{asset:MB25": {
"avg": 14.155766666666667,
"max": 19.967,
"med": 13.262,
"min": 10.793,
"p(90)": 18.776000000000003,
"p(95)": 19.580849999999998
},
"oc_default_play_dav_file_delete_trend{asset:MB5": {
"avg": 14.853853333333339,
"max": 26.691,
"med": 14.0415,
"min": 10.496,
"p(90)": 18.943699999999996,
"p(95)": 20.62044999999999
},
"oc_default_play_dav_file_download_trend": {
"avg": 37.784668749999994,
"max": 183.499,
"med": 32.0055,
"min": 19.14,
"p(90)": 55.628600000000006,
"p(95)": 93.45874999999992
},
"oc_default_play_dav_file_download_trend{asset:KB500": {
"avg": 26.680456666666657,
"max": 55.922,
"med": 24.979,
"min": 19.14,
"p(90)": 34.91720000000001,
"p(95)": 37.47365
},
"oc_default_play_dav_file_download_trend{asset:MB25": {
"avg": 113.08066666666669,
"max": 183.499,
"med": 103.05799999999999,
"min": 83.728,
"p(90)": 148.6112,
"p(95)": 162.21334999999996
},
"oc_default_play_dav_file_download_trend{asset:MB5": {
"avg": 44.93389333333334,
"max": 75.914,
"med": 43.920500000000004,
"min": 31.472,
"p(90)": 56.58899999999999,
"p(95)": 60.417399999999994
},
"oc_default_play_dav_file_upload_trend": {
"avg": 42.71212500000003,
"max": 253.272,
"med": 36.876999999999995,
"min": 21.145,
"p(90)": 56.78170000000001,
"p(95)": 114.79089999999997
},
"oc_default_play_dav_file_upload_trend{asset:KB500": {
"avg": 32.439143333333334,
"max": 253.272,
"med": 30.240000000000002,
"min": 21.145,
"p(90)": 40.75260000000001,
"p(95)": 45.08695000000001
},
"oc_default_play_dav_file_upload_trend{asset:MB25": {
"avg": 121.4088,
"max": 146.226,
"med": 119.23599999999999,
"min": 100.77,
"p(90)": 138.50189999999998,
"p(95)": 142.34375
},
"oc_default_play_dav_file_upload_trend{asset:MB5": {
"avg": 47.518753333333365,
"max": 77.615,
"med": 46.457,
"min": 35.46,
"p(90)": 56.623099999999994,
"p(95)": 61.826049999999974
},
"vus": {
"max": 1,
"min": 1,
"value": 1
},
"vus_max": {
"max": 1,
"min": 1,
"value": 1
}
},
"root_group": {
"name": "",
"path": "",
"id": "d41d8cd98f00b204e9800998ecf8427e",
"groups": {},
"checks": {
"file delete status is 204": {
"name": "file delete status is 204",
"path": "::file delete status is 204",
"id": "18e4ac556fd01961812afd85e16bb9d9",
"passes": 480,
"fails": 0
},
"file download status is 200": {
"name": "file download status is 200",
"path": "::file download status is 200",
"id": "52b41fab3137d895e8ec58fd9dccd86e",
"passes": 480,
"fails": 0
},
"file upload status is 201": {
"name": "file upload status is 201",
"path": "::file upload status is 201",
"id": "d530d65df94c4e70b68aac6f2f054f1f",
"passes": 480,
"fails": 0
}
}
}
}

View File

@@ -0,0 +1,296 @@
{
"metrics": {
"checks": {
"fails": 0,
"passes": 54,
"value": 0
},
"data_received": {
"count": 4975515490,
"rate": 54283776.21668842
},
"data_sent": {
"count": 4995495858,
"rate": 54501765.65465097
},
"http_req_blocked": {
"avg": 0.07648148148148148,
"max": 3.614,
"med": 0.005,
"min": 0.003,
"p(90)": 0.024,
"p(95)": 0.03684999999999994
},
"http_req_connecting": {
"avg": 0.004203703703703703,
"max": 0.227,
"med": 0,
"min": 0,
"p(90)": 0,
"p(95)": 0
},
"http_req_duration": {
"avg": 1199.7894444444446,
"max": 11778.61,
"med": 81.80799999999999,
"min": 17.916,
"p(90)": 4263.4364000000005,
"p(95)": 7307.079449999999
},
"http_req_receiving": {
"avg": 586.4966296296295,
"max": 7419.291,
"med": 0.13,
"min": 0.04,
"p(90)": 1447.7991000000025,
"p(95)": 5254.929599999983
},
"http_req_sending": {
"avg": 555.0930740740743,
"max": 11707.466,
"med": 0.0775,
"min": 0.018,
"p(90)": 1635.9796000000044,
"p(95)": 3495.4676999999942
},
"http_req_tls_handshaking": {
"avg": 0.052833333333333336,
"max": 2.853,
"med": 0,
"min": 0,
"p(90)": 0,
"p(95)": 0
},
"http_req_waiting": {
"avg": 58.199740740740744,
"max": 305.282,
"med": 37.3425,
"min": 14.057,
"p(90)": 105.61020000000003,
"p(95)": 155.87789999999998
},
"http_reqs": {
"count": 54,
"rate": 0.5891497919346593
},
"iteration_duration": {
"avg": 30521.018089,
"max": 42157.485685,
"med": 26262.18445,
"min": 23143.384132,
"p(90)": 38978.425438,
"p(95)": 40567.9555615
},
"iterations": {
"count": 3,
"rate": 0.03273054399636997
},
"oc_default_play_dav_file_delete_trend": {
"avg": 42.30277777777778,
"max": 91.667,
"med": 33.669,
"min": 17.916,
"p(90)": 73.0931,
"p(95)": 86.0162
},
"oc_default_play_dav_file_delete_trend{asset:GB1": {
"avg": 36.54533333333333,
"max": 45.724,
"med": 33.698,
"min": 30.214,
"p(90)": 43.318799999999996,
"p(95)": 44.5214
},
"oc_default_play_dav_file_delete_trend{asset:KB50": {
"avg": 58.788333333333334,
"max": 85.019,
"med": 62.125,
"min": 29.221,
"p(90)": 80.4402,
"p(95)": 82.7296
},
"oc_default_play_dav_file_delete_trend{asset:KB500": {
"avg": 41.721333333333334,
"max": 67.982,
"med": 32.438,
"min": 24.744,
"p(90)": 60.8732,
"p(95)": 64.4276
},
"oc_default_play_dav_file_delete_trend{asset:MB5": {
"avg": 30.743666666666666,
"max": 56.309,
"med": 18.006,
"min": 17.916,
"p(90)": 48.648399999999995,
"p(95)": 52.478699999999996
},
"oc_default_play_dav_file_delete_trend{asset:MB50": {
"avg": 45.24466666666667,
"max": 91.667,
"med": 22.681,
"min": 21.386,
"p(90)": 77.86980000000001,
"p(95)": 84.7684
},
"oc_default_play_dav_file_delete_trend{asset:MB500": {
"avg": 40.77333333333333,
"max": 45.129,
"med": 43.551,
"min": 33.64,
"p(90)": 44.8134,
"p(95)": 44.971199999999996
},
"oc_default_play_dav_file_download_trend": {
"avg": 1815.5790555555557,
"max": 7454.559,
"med": 190.0605,
"min": 27.771,
"p(90)": 7302.4101,
"p(95)": 7380.7977
},
"oc_default_play_dav_file_download_trend{asset:GB1": {
"avg": 7365.578,
"max": 7454.559,
"med": 7367.781,
"min": 7274.394,
"p(90)": 7437.2034,
"p(95)": 7445.8812
},
"oc_default_play_dav_file_download_trend{asset:KB50": {
"avg": 77.559,
"max": 144.171,
"med": 60.735,
"min": 27.771,
"p(90)": 127.4838,
"p(95)": 135.82739999999998
},
"oc_default_play_dav_file_download_trend{asset:KB500": {
"avg": 64.77866666666667,
"max": 118.418,
"med": 47.796,
"min": 28.122,
"p(90)": 104.29360000000001,
"p(95)": 111.35580000000002
},
"oc_default_play_dav_file_download_trend{asset:MB5": {
"avg": 87.07633333333332,
"max": 132.468,
"med": 64.708,
"min": 64.053,
"p(90)": 118.916,
"p(95)": 125.69199999999998
},
"oc_default_play_dav_file_download_trend{asset:MB50": {
"avg": 465.49199999999996,
"max": 920.853,
"med": 239.673,
"min": 235.95,
"p(90)": 784.617,
"p(95)": 852.7349999999999
},
"oc_default_play_dav_file_download_trend{asset:MB500": {
"avg": 2832.990333333333,
"max": 4296.326,
"med": 2461.95,
"min": 1740.695,
"p(90)": 3929.4508,
"p(95)": 4112.8884
},
"oc_default_play_dav_file_upload_trend": {
"avg": 1741.4865,
"max": 11778.61,
"med": 277.241,
"min": 22.627,
"p(90)": 4528.384400000001,
"p(95)": 6293.604199999991
},
"oc_default_play_dav_file_upload_trend{asset:GB1": {
"avg": 7096.988666666667,
"max": 11778.61,
"med": 5325.662,
"min": 4186.694,
"p(90)": 10488.020400000001,
"p(95)": 11133.315200000001
},
"oc_default_play_dav_file_upload_trend{asset:KB50": {
"avg": 126.274,
"max": 243.95,
"med": 90.139,
"min": 44.733,
"p(90)": 213.18779999999998,
"p(95)": 228.56889999999999
},
"oc_default_play_dav_file_upload_trend{asset:KB500": {
"avg": 136.278,
"max": 307.61,
"med": 78.597,
"min": 22.627,
"p(90)": 261.80740000000003,
"p(95)": 284.7087
},
"oc_default_play_dav_file_upload_trend{asset:MB5": {
"avg": 105.57533333333333,
"max": 201.903,
"med": 61.229,
"min": 53.594,
"p(90)": 173.76819999999998,
"p(95)": 187.83559999999997
},
"oc_default_play_dav_file_upload_trend{asset:MB50": {
"avg": 426.2540000000001,
"max": 598.362,
"med": 433.528,
"min": 246.872,
"p(90)": 565.3951999999999,
"p(95)": 581.8786
},
"oc_default_play_dav_file_upload_trend{asset:MB500": {
"avg": 2557.549,
"max": 3159.682,
"med": 2397.078,
"min": 2115.887,
"p(90)": 3007.1612,
"p(95)": 3083.4215999999997
},
"vus": {
"max": 1,
"min": 1,
"value": 1
},
"vus_max": {
"max": 1,
"min": 1,
"value": 1
}
},
"root_group": {
"name": "",
"path": "",
"id": "d41d8cd98f00b204e9800998ecf8427e",
"groups": {},
"checks": {
"file delete status is 204": {
"name": "file delete status is 204",
"path": "::file delete status is 204",
"id": "18e4ac556fd01961812afd85e16bb9d9",
"passes": 18,
"fails": 0
},
"file download status is 200": {
"name": "file download status is 200",
"path": "::file download status is 200",
"id": "52b41fab3137d895e8ec58fd9dccd86e",
"passes": 18,
"fails": 0
},
"file upload status is 201": {
"name": "file upload status is 201",
"path": "::file upload status is 201",
"id": "d530d65df94c4e70b68aac6f2f054f1f",
"passes": 18,
"fails": 0
}
}
}
}

View File

@@ -26,7 +26,7 @@ export default [
],
plugins: [
multiInput({
transformOutputPath: (output, input) => `tests/${output.split('/').join('-')}`,
transformOutputPath: (output, input) => `${output.split('/').join('-')}`,
}),
json(),
resolve(

View File

@@ -1,53 +0,0 @@
const shell = require('shelljs')
const path = require("path")
const fs = require('fs');
const ora = require('ora');
const axios = require('axios');
const downloadFile = async (url, name) => {
const parsedPath = path.parse(url)
const destDir = './dist/_files/'
const destFile = path.join(destDir, name || parsedPath.base)
if (!fs.existsSync(destDir)) {
shell.mkdir('-p', destDir)
}
if(fs.existsSync(destFile)){
return
}
const spinner = ora(`downloading: ${ url }`).start();
const { data } = await axios({
method: "get",
url: url,
responseType: "stream"
});
const stream = fs.createWriteStream(destFile);
data.pipe(stream);
return new Promise((resolve, reject) => {
data.on('error', err => {
console.error(err);
spinner.stop();
reject(err);
});
data.on('end', () => {
stream.end();
spinner.stop();
resolve();
});
});
}
(async () => {
await downloadFile('https://www.sample-videos.com/img/Sample-jpg-image-50kb.jpg', 'kb_50.jpg')
await downloadFile('http://ipv4.download.thinkbroadband.com/5MB.zip', 'mb_5.zip')
await downloadFile('http://ipv4.download.thinkbroadband.com/10MB.zip', 'mb_10.zip')
await downloadFile('http://ipv4.download.thinkbroadband.com/20MB.zip', 'mb_20.zip')
await downloadFile('http://ipv4.download.thinkbroadband.com/50MB.zip', 'mb_50.zip')
await downloadFile('http://ipv4.download.thinkbroadband.com/100MB.zip', 'mb_100.zip')
await downloadFile('http://ipv4.download.thinkbroadband.com/200MB.zip', 'mb_200.zip')
})()

View File

@@ -1,5 +1,5 @@
import encoding from 'k6/encoding';
import * as types from "../types";
import * as types from '../types';
export const headersDefault = ({credential}: { credential: types.Credential }): { [key: string]: string } => {
const isOIDCGuard = (credential as types.Token).tokenType !== undefined;

View File

@@ -1,15 +1,32 @@
import http, {RefinedResponse, ResponseType} from "k6/http";
import http, {RefinedResponse, ResponseType} from 'k6/http';
import * as api from './api'
import * as defaults from "../defaults";
import * as types from "../types";
import * as defaults from '../defaults';
import * as types from '../types';
export const fileUpload = (
{
credential,
userName,
path = '',
asset,
tags,
}: {
credential: types.Credential;
userName: string;
asset: types.Asset;
path?: string;
tags?: { [key: string]: string };
}
): RefinedResponse<ResponseType> => {
export const fileUpload = <RT extends ResponseType | undefined>(
{credential, userName, asset}: { credential: types.Credential; userName: string; asset: types.Asset }
): RefinedResponse<RT> => {
return http.put(
`${defaults.ENV.HOST}/remote.php/dav/files/${userName}/${asset.fileName}`,
[
defaults.ENV.HOST,
...`/remote.php/dav/files/${userName}/${path}/${asset.name}`.split('/').filter(Boolean)
].join('/'),
asset.bytes as any,
{
tags,
headers: {
...api.headersDefault({credential})
}
@@ -17,12 +34,26 @@ export const fileUpload = <RT extends ResponseType | undefined>(
);
}
export const fileDownload = <RT extends ResponseType | undefined>(
{credential, userName, fileName}: { credential: types.Credential; userName: string; fileName: string }
): RefinedResponse<RT> => {
export const fileDownload = (
{
credential,
userName,
path,
tags,
}: {
credential: types.Credential;
userName: string;
path: string;
tags?: { [key: string]: string };
}
): RefinedResponse<ResponseType> => {
return http.get(
`${defaults.ENV.HOST}/remote.php/dav/files/${userName}/${fileName}`,
[
defaults.ENV.HOST,
...`/remote.php/dav/files/${userName}/${path}`.split('/').filter(Boolean)
].join('/'),
{
tags,
headers: {
...api.headersDefault({credential})
}
@@ -30,13 +61,87 @@ export const fileDownload = <RT extends ResponseType | undefined>(
);
}
export const fileDelete = <RT extends ResponseType | undefined>(
{credential, userName, fileName}: { credential: types.Credential; userName: string; fileName: string }
): RefinedResponse<RT> => {
export const fileDelete = (
{
credential,
userName,
path,
tags,
}: {
credential: types.Credential;
userName: string;
path: string;
tags?: { [key: string]: string };
}
): RefinedResponse<ResponseType> => {
return http.del(
`${defaults.ENV.HOST}/remote.php/dav/files/${userName}/${fileName}`,
[
defaults.ENV.HOST,
...`/remote.php/dav/files/${userName}/${path}`.split('/').filter(Boolean)
].join('/'),
{},
{
tags,
headers: {
...api.headersDefault({credential})
}
}
);
}
export const folderCreate = (
{
credential,
userName,
path,
tags,
}: {
credential: types.Credential;
userName: string;
path: string;
tags?: { [key: string]: string };
}
): RefinedResponse<ResponseType> => {
return http.request(
'MKCOL',
[
defaults.ENV.HOST,
...`/remote.php/dav/files/${userName}/${path}`.split('/').filter(Boolean)
].join('/'),
{},
{
tags,
headers: {
...api.headersDefault({credential})
}
}
);
}
export const folderDelete = fileDelete
export const propfind = (
{
credential,
userName,
path = '',
tags,
}: {
credential: types.Credential;
userName: string;
path?: string;
tags?: { [key: string]: string };
}
): RefinedResponse<ResponseType> => {
return http.request(
'PROPFIND',
[
defaults.ENV.HOST,
...`/remote.php/dav/files/${userName}/${path}`.split('/').filter(Boolean)
].join('/'),
{},
{
tags,
headers: {
...api.headersDefault({credential})
}

View File

@@ -1,14 +1,23 @@
import http, {RefinedResponse, ResponseType} from "k6/http";
import http, {RefinedResponse, ResponseType} from 'k6/http';
import * as api from './api'
import * as defaults from "../defaults";
import * as types from "../types";
import * as defaults from '../defaults';
import * as types from '../types';
export const userInfo = <RT extends ResponseType | undefined>(
{credential, userName}: { credential: types.Credential; userName: string; }
): RefinedResponse<RT> => {
export const userInfo = (
{
credential,
userName,
tags,
}: {
credential: types.Credential;
userName: string;
tags?: { [name: string]: string };
}
): RefinedResponse<ResponseType> => {
return http.get(
`${defaults.ENV.HOST}/ocs/v1.php/cloud/users/${userName}`,
{
tags,
headers: {
...api.headersDefault({credential})
},

View File

@@ -1,7 +1,7 @@
import * as defaults from "./defaults";
import http from "k6/http";
import queryString from "query-string";
import * as types from "./types";
import * as defaults from './defaults';
import http from 'k6/http';
import queryString from 'query-string';
import * as types from './types';
import {fail} from 'k6';
import {get} from 'lodash'

View File

@@ -1,13 +1,4 @@
import * as types from './types';
import {Options} from "k6/options";
export class K6 {
public static readonly OPTIONS: Options = {
insecureSkipTLSVerify: true,
iterations: 1,
vus: 1,
};
}
export class ENV {
public static readonly HOST = __ENV.OC_HOST || 'https://localhost:9200';
@@ -15,18 +6,12 @@ export class ENV {
public static readonly PASSWORD = __ENV.OC_PASSWORD;
public static readonly OIDC_HOST = __ENV.OC_OIDC_HOST || ENV.HOST;
public static readonly OIDC_ENABLED = __ENV.OC_OIDC_ENABLED === 'true' || false;
public static readonly FILE_NAME = '../_files/' + (__ENV.OC_TEST_FILE || 'kb_50.jpg').split('/').pop();
}
export const FILE = {
fileName: ENV.FILE_NAME,
bytes: open(ENV.FILE_NAME, 'b'),
};
export class ACCOUNT {
export class ACCOUNTS {
public static readonly EINSTEIN = 'einstein';
public static readonly RICHARD = 'richard';
private static readonly list: { [key: string]: types.Account; } = {
public static readonly ALL: { [key: string]: types.Account; } = {
einstein: {
login: 'einstein',
password: 'relativity',
@@ -36,15 +21,4 @@ export class ACCOUNT {
password: 'superfluidity',
},
}
public static for(key: string): types.Account {
if (ENV.LOGIN && ENV.PASSWORD) {
return {
login: ENV.LOGIN,
password: ENV.PASSWORD,
}
}
return this.list[key];
}
}
}

View File

@@ -1,70 +1,308 @@
import {Gauge, Trend} from "k6/metrics";
import * as api from "../api";
import * as utils from "../utils";
import {bytes, check} from "k6";
import * as types from "../types";
import {Gauge, Trend} from 'k6/metrics';
import * as api from '../api';
import {check} from 'k6';
import * as types from '../types';
import {RefinedResponse, ResponseType} from 'k6/http';
export const fileUpload = () => {
const fileUploadTrend = new Trend('occ_file_upload_trend', true);
const fileUploadErrorRate = new Gauge('occ_file_upload_error_rate');
export const fileUpload = ({name, metricID = 'default'}: { name?: string; metricID?: string; }) => {
const playName = name || `oc_${metricID}_play_dav_file_upload`;
const metricTrendName = `${playName}_trend`;
const metricTrend = new Trend(metricTrendName, true);
const metricErrorRateName = `${playName}_error_rate`;
const metricErrorRate = new Gauge(metricErrorRateName);
return ({credential, userName, asset}: { credential: types.Credential; userName: string; asset: types.Asset }): string => {
const fileName = `upload-${userName}-${__VU}-${__ITER}.${utils.extension(asset.fileName)}`;
const uploadResponse = api.dav.fileUpload({
credential: credential as any,
asset: {
fileName,
bytes: asset.bytes,
},
userName,
});
return {
playName,
metricTrendName,
metricErrorRateName,
exec: (
{
credential,
userName,
path,
asset,
tags,
}: {
credential: types.Credential;
path?: string;
userName: string;
asset: types.Asset;
tags?: { [key: string]: string };
}
): {
response: RefinedResponse<ResponseType>;
tags: { [key: string]: string };
} => {
tags = {play: playName, ...tags};
check(uploadResponse, {
'file upload status is 201': () => uploadResponse.status === 201,
}) || fileUploadErrorRate.add(1);
const response = api.dav.fileUpload({
credential: credential as types.Credential,
asset,
userName,
tags,
path,
});
fileUploadTrend.add(uploadResponse.timings.duration)
check(response, {
'file upload status is 201': () => response.status === 201,
}, tags) || metricErrorRate.add(1, tags);
return fileName
metricTrend.add(response.timings.duration, tags)
return {
response,
tags,
}
}
}
};
export const fileDelete = () => {
const fileDeleteTrend = new Trend('occ_file_delete_trend', true);
const fileDeleteErrorRate = new Gauge('occ_file_delete_error_rate');
export const fileDelete = ({name, metricID = 'default'}: { name?: string; metricID?: string; }) => {
const playName = name || `oc_${metricID}_play_dav_file_delete`;
const metricTrendName = `${playName}_trend`;
const metricTrend = new Trend(metricTrendName, true);
const metricErrorRateName = `${playName}_error_rate`;
const metricErrorRate = new Gauge(metricErrorRateName);
return ({credential, userName, fileName}: { credential: types.Credential, userName: string; fileName: string }) => {
const deleteResponse = api.dav.fileDelete({
credential: credential as any,
fileName,
userName,
});
return {
playName,
metricTrendName,
metricErrorRateName,
exec: (
{
credential,
userName,
path,
tags,
}: {
credential: types.Credential;
userName: string;
path: string;
tags?: { [key: string]: string };
}
): {
response: RefinedResponse<ResponseType>;
tags: { [key: string]: string };
} => {
tags = {play: playName, ...tags};
check(deleteResponse, {
'file delete status is 204': () => deleteResponse.status === 204,
}) || fileDeleteErrorRate.add(1);
const response = api.dav.fileDelete({
credential: credential as types.Credential,
path,
userName,
tags,
});
fileDeleteTrend.add(deleteResponse.timings.duration)
check(response, {
'file delete status is 204': () => response.status === 204,
}, tags) || metricErrorRate.add(1, tags);
metricTrend.add(response.timings.duration, tags)
return {
response,
tags,
}
}
}
};
export const fileDownload = () => {
const fileDownloadTrend = new Trend('occ_file_download_trend', true);
const fileDownloadErrorRate = new Gauge('occ_file_download_error_rate');
export const fileDownload = ({name, metricID = 'default'}: { name?: string; metricID?: string; }) => {
const playName = name || `oc_${metricID}_play_dav_file_download`;
const metricTrendName = `${playName}_trend`;
const metricTrend = new Trend(metricTrendName, true);
const metricErrorRateName = `${playName}_error_rate`;
const metricErrorRate = new Gauge(metricErrorRateName);
return ({credential, userName, fileName}: { credential: types.Credential, userName: string; fileName: string }): bytes => {
const downloadResponse = api.dav.fileDownload({
credential: credential as any,
fileName,
userName,
});
return {
playName,
metricTrendName,
metricErrorRateName,
exec: (
{
credential,
userName,
path,
tags,
}: {
credential: types.Credential;
userName: string;
path: string;
tags?: { [key: string]: string };
}
): {
response: RefinedResponse<ResponseType>;
tags: { [key: string]: string };
} => {
tags = {play: playName, ...tags};
check(downloadResponse, {
'file download status is 200': () => downloadResponse.status === 200,
}) || fileDownloadErrorRate.add(1);
const response = api.dav.fileDownload({
credential: credential as types.Credential,
path,
userName,
tags,
});
fileDownloadTrend.add(downloadResponse.timings.duration)
check(response, {
'file download status is 200': () => response.status === 200,
}, tags) || metricErrorRate.add(1, tags);
return downloadResponse.body as bytes
metricTrend.add(response.timings.duration, tags)
return {
response,
tags,
}
}
}
};
export const folderCreate = ({name, metricID = 'default'}: { name?: string; metricID?: string; }) => {
const playName = name || `oc_${metricID}_play_dav_folder_create`;
const metricTrendName = `${playName}_trend`;
const metricTrend = new Trend(metricTrendName, true);
const metricErrorRateName = `${playName}_error_rate`;
const metricErrorRate = new Gauge(metricErrorRateName);
return {
playName,
metricTrendName,
metricErrorRateName,
exec: (
{
credential,
userName,
path,
tags,
}: {
credential: types.Credential;
userName: string;
path: string;
tags?: { [key: string]: string };
}
): {
response: RefinedResponse<ResponseType>;
tags: { [key: string]: string };
} => {
tags = {play: playName, ...tags};
const response = api.dav.folderCreate({
credential: credential as types.Credential,
path,
userName,
tags,
});
check(response, {
'folder create status is 201': () => response.status === 201,
}, tags) || metricErrorRate.add(1, tags);
metricTrend.add(response.timings.duration, tags)
return {
response,
tags,
}
}
}
};
export const folderDelete = ({name, metricID = 'default'}: { name?: string; metricID?: string; }) => {
const playName = name || `oc_${metricID}_play_dav_folder_delete`;
const metricTrendName = `${playName}_trend`;
const metricTrend = new Trend(metricTrendName, true);
const metricErrorRateName = `${playName}_error_rate`;
const metricErrorRate = new Gauge(metricErrorRateName);
return {
playName,
metricTrendName,
metricErrorRateName,
exec: (
{
credential,
userName,
path,
tags,
}: {
credential: types.Credential;
userName: string;
path: string;
tags?: { [key: string]: string };
}
): {
response: RefinedResponse<ResponseType>;
tags: { [key: string]: string };
} => {
tags = {play: playName, ...tags};
const response = api.dav.folderDelete({
credential: credential as types.Credential,
path,
userName,
tags,
});
check(response, {
'folder delete status is 204': () => response.status === 204,
}, tags) || metricErrorRate.add(1, tags);
metricTrend.add(response.timings.duration, tags)
return {
response,
tags,
}
}
}
};
export const propfind = ({name, metricID = 'default'}: { name?: string; metricID?: string; }) => {
const playName = name || `oc_${metricID}_play_dav_propfind`;
const metricTrendName = `${playName}_trend`;
const metricTrend = new Trend(metricTrendName, true);
const metricErrorRateName = `${playName}_error_rate`;
const metricErrorRate = new Gauge(metricErrorRateName);
return {
playName,
metricTrendName,
metricErrorRateName,
exec: (
{
credential,
userName,
path,
tags,
}: {
credential: types.Credential;
userName: string;
path?: string;
tags?: { [key: string]: string };
}
): {
response: RefinedResponse<ResponseType>;
tags: { [key: string]: string };
} => {
tags = {play: playName, ...tags};
const response = api.dav.propfind({
credential: credential as types.Credential,
path,
userName,
tags,
});
check(response, {
'propfind status is 207': () => response.status === 207,
}, tags) || metricErrorRate.add(1, tags);
metricTrend.add(response.timings.duration, tags)
return {
response,
tags,
}
}
}
};

View File

@@ -1,8 +1,8 @@
import {bytes} from "k6";
import {bytes} from 'k6';
export interface Asset {
bytes: bytes;
fileName: string;
name: string;
}
export interface Token {
@@ -21,4 +21,6 @@ export type Credential = Token | Account
export interface AuthProvider {
credential: Credential
}
}
export type AssetUnit = 'KB' | 'MB' | 'GB'

View File

@@ -1,8 +1,57 @@
import {bytes} from 'k6';
import {randomBytes as k6_randomBytes} from 'k6/crypto';
import * as defaults from './defaults';
import * as types from './types';
export const randomNumber = ({min, max}: { min: number; max: number; }): number => {
return Math.random() * (max - min) + min;
}
export const randomString = (): string => {
return Math.random().toString(36).slice(2)
return Math.random().toString(20).substr(2)
}
export const extension = (p: string): string | undefined => {
return (p.split('/').pop())!.split('.').pop()
export const buildAccount = ({login = defaults.ACCOUNTS.EINSTEIN}: { login: string; }): types.Account => {
if (defaults.ENV.LOGIN && defaults.ENV.PASSWORD) {
return {
login: defaults.ENV.LOGIN,
password: defaults.ENV.PASSWORD,
}
}
return defaults.ACCOUNTS.ALL[login];
}
export const buildAsset = (
{
name = 'dummy.zip',
size = 1,
unit = 'MB',
}: {
name?: string;
size?: number;
unit?: types.AssetUnit;
}
): types.Asset => {
const gen = {
KB: (s: number): bytes => {
return k6_randomBytes(s * 1024)
},
MB: (s: number): bytes => {
return gen.KB(s * 1024)
},
GB: (s: number): bytes => {
return gen.MB(s * 1024)
},
}
const fileBaseName = name.split('/').reverse()[0]
const fileName = fileBaseName.split('.')[0]
const fileExtension = fileBaseName.split('.').reverse()[0] || 'zip'
return {
name: `${fileName}-${__VU}-${__ITER}-${size}-${unit}-${randomString()}.${fileExtension}`,
bytes: gen[unit](size),
}
}

View File

@@ -1,40 +0,0 @@
import {defaults, playbook} from '../../lib'
import {Options} from 'k6/options';
import {sleep} from "k6";
import auth from "../../lib/auth";
export const options: Options = {
...defaults.K6.OPTIONS,
};
const authFactory = new auth(defaults.ACCOUNT.for(defaults.ACCOUNT.EINSTEIN));
const plays = {
fileUpload: playbook.dav.fileUpload(),
fileDownload: playbook.dav.fileDownload(),
fileDelete: playbook.dav.fileDelete(),
}
export default () => {
const {login: userName} = authFactory.account;
const fileName = plays.fileUpload({
credential: authFactory.credential,
userName,
asset: defaults.FILE,
});
sleep(1)
plays.fileDownload({
credential: authFactory.credential,
userName,
fileName,
});
sleep(1)
plays.fileDelete({
credential: authFactory.credential,
userName,
fileName,
});
sleep(1)
};

View File

@@ -1,31 +0,0 @@
import {defaults, playbook} from '../../lib'
import {Options} from 'k6/options';
import {sleep} from "k6";
import auth from "../../lib/auth";
export const options: Options = {
...defaults.K6.OPTIONS,
};
const authFactory = new auth(defaults.ACCOUNT.for(defaults.ACCOUNT.EINSTEIN));
const plays = {
fileUpload: playbook.dav.fileUpload(),
fileDelete: playbook.dav.fileDelete(),
}
export default () => {
const {login: userName} = authFactory.account;
const fileName = plays.fileUpload({
credential: authFactory.credential,
userName,
asset: defaults.FILE,
});
sleep(1)
plays.fileDelete({
credential: authFactory.credential,
userName,
fileName,
});
sleep(1)
};

View File

@@ -1,9 +0,0 @@
import {Options} from 'k6/options';
import * as uploadFilesBenchmark from '../../../benchmark/file-upload'
export const options: Options = {
...uploadFilesBenchmark.options,
iterations: 200,
vus: 50,
};
export default uploadFilesBenchmark.default;

View File

@@ -0,0 +1,64 @@
import {Options} from "k6/options";
import {utils, auth, defaults, playbook} from '../../../../../../lib'
import {times} from 'lodash'
// put 1000 files into one dir and run a 'PROPFIND' through API
const files: {
size: number;
unit: any;
}[] = times(1000, () => ({size: 1, unit: 'KB'}))
const authFactory = new auth.default(utils.buildAccount({login: defaults.ACCOUNTS.EINSTEIN}));
const plays = {
fileUpload: playbook.dav.fileUpload({}),
propfind: playbook.dav.propfind({}),
fileDelete: playbook.dav.fileDelete({}),
}
export const options: Options = {
insecureSkipTLSVerify: true,
iterations: 3,
vus: 1,
thresholds: files.reduce((acc: any, c) => {
acc[`${plays.fileUpload.metricTrendName}{asset:${c.unit + c.size.toString()}`] = []
acc[`${plays.propfind.metricTrendName}`] = []
acc[`${plays.fileDelete.metricTrendName}{asset:${c.unit + c.size.toString()}`] = []
return acc
}, {}),
};
export default (): void => {
const filesUploaded: { id: string, name: string, }[] = []
const {account, credential} = authFactory;
files.forEach(f => {
const id = f.unit + f.size.toString();
const asset = utils.buildAsset({
name: `${account.login}-dummy.zip`,
unit: f.unit as any,
size: f.size,
})
plays.fileUpload.exec({
credential,
asset,
userName: account.login,
tags: {asset: id},
});
filesUploaded.push({id, name: asset.name})
})
plays.propfind.exec({
credential,
userName: account.login,
})
filesUploaded.forEach(f => {
plays.fileDelete.exec({
credential,
userName: account.login,
path: f.name,
tags: {asset: f.id},
});
})
}

View File

@@ -0,0 +1,81 @@
import {Options} from "k6/options";
import {utils, auth, defaults, playbook} from '../../../../../../lib'
import {times} from 'lodash'
// Unpack standard data tarball, run PROPFIND on each dir
const files: {
size: number;
unit: any;
}[] = times(1000, () => ({size: 1, unit: 'KB'}))
const authFactory = new auth.default(utils.buildAccount({login: defaults.ACCOUNTS.EINSTEIN}));
const plays = {
fileUpload: playbook.dav.fileUpload({}),
propfind: playbook.dav.propfind({}),
folderCreate: playbook.dav.folderCreate({}),
folderDelete: playbook.dav.folderDelete({}),
}
export const options: Options = {
insecureSkipTLSVerify: true,
iterations: 3,
vus: 1,
thresholds: files.reduce((acc: any, c) => {
acc[`${plays.fileUpload.metricTrendName}{asset:${c.unit + c.size.toString()}`] = []
acc[`${plays.propfind.metricTrendName}`] = []
acc[`${plays.folderCreate.metricTrendName}{asset:${c.unit + c.size.toString()}`] = []
acc[`${plays.folderDelete.metricTrendName}{asset:${c.unit + c.size.toString()}`] = []
return acc
}, {}),
};
export default (): void => {
const filesUploaded: { id: string, name: string, folder: string }[] = []
const {account, credential} = authFactory;
files.forEach(f => {
const id = f.unit + f.size.toString();
const asset = utils.buildAsset({
name: `${account.login}-dummy.zip`,
unit: f.unit as any,
size: f.size,
})
const folder = times(utils.randomNumber({min: 1, max: 10}), () => utils.randomString()).reduce((acc: string[], c) => {
acc.push(c)
plays.folderCreate.exec({
credential,
path: acc.join('/'),
userName: account.login,
tags: {asset: id},
});
return acc
}, []).join('/')
plays.fileUpload.exec({
credential,
asset,
path: folder,
userName: account.login,
tags: {asset: id},
});
filesUploaded.push({id, name: asset.name, folder})
})
plays.propfind.exec({
credential,
userName: account.login,
})
filesUploaded.forEach(f => {
plays.folderDelete.exec({
credential,
userName: account.login,
path: f.folder.split('/')[0],
tags: {asset: f.id},
});
})
}

View File

@@ -0,0 +1,72 @@
import {Options} from "k6/options";
import {utils, auth, defaults, playbook} from '../../../../../../lib'
import {times} from 'lodash'
// upload, download and delete of many files with several sizes and summary size of 500 MB in one directory
const files: {
size: number;
unit: any;
}[] = [
...times(100, () => ({size: 500, unit: 'KB'})),
...times(50, () => ({size: 5, unit: 'MB'})),
...times(10, () => ({size: 25, unit: 'MB'})),
]
const authFactory = new auth.default(utils.buildAccount({login: defaults.ACCOUNTS.EINSTEIN}));
const plays = {
fileUpload: playbook.dav.fileUpload({}),
fileDownload: playbook.dav.fileDownload({}),
fileDelete: playbook.dav.fileDelete({}),
}
export const options: Options = {
insecureSkipTLSVerify: true,
iterations: 3,
vus: 1,
thresholds: files.reduce((acc: any, c) => {
acc[`${plays.fileUpload.metricTrendName}{asset:${c.unit + c.size.toString()}`] = []
acc[`${plays.fileDownload.metricTrendName}{asset:${c.unit + c.size.toString()}`] = []
acc[`${plays.fileDelete.metricTrendName}{asset:${c.unit + c.size.toString()}`] = []
return acc
}, {}),
};
export default (): void => {
const filesUploaded: { id: string, name: string, }[] = []
const {account, credential} = authFactory;
files.forEach(f => {
const id = f.unit + f.size.toString();
const asset = utils.buildAsset({
name: `${account.login}-dummy.zip`,
unit: f.unit as any,
size: f.size,
})
plays.fileUpload.exec({
credential,
asset,
userName: account.login,
tags: {asset: id},
});
filesUploaded.push({id, name: asset.name})
})
filesUploaded.forEach(f => {
plays.fileDownload.exec({
credential,
userName: account.login,
path: f.name,
tags: {asset: f.id},
});
})
filesUploaded.forEach(f => {
plays.fileDelete.exec({
credential,
userName: account.login,
path: f.name,
tags: {asset: f.id},
});
})
}

View File

@@ -0,0 +1,75 @@
import {Options} from "k6/options";
import {utils, auth, defaults, playbook, types} from '../../../../../../lib'
// upload, download and delete of one file with sizes 50kb, 500kb, 5MB, 50MB, 500MB, 1GB
const files: {
size: number;
unit: types.AssetUnit;
}[] = [
{size: 50, unit: 'KB'},
{size: 500, unit: 'KB'},
{size: 5, unit: 'MB'},
{size: 50, unit: 'MB'},
{size: 500, unit: 'MB'},
{size: 1, unit: 'GB'},
]
const authFactory = new auth.default(utils.buildAccount({login: defaults.ACCOUNTS.EINSTEIN}));
const plays = {
fileUpload: playbook.dav.fileUpload({}),
fileDownload: playbook.dav.fileDownload({}),
fileDelete: playbook.dav.fileDelete({}),
}
export const options: Options = {
insecureSkipTLSVerify: true,
iterations: 3,
vus: 1,
thresholds: files.reduce((acc: any, c) => {
acc[`${plays.fileUpload.metricTrendName}{asset:${c.unit + c.size.toString()}`] = []
acc[`${plays.fileDownload.metricTrendName}{asset:${c.unit + c.size.toString()}`] = []
acc[`${plays.fileDelete.metricTrendName}{asset:${c.unit + c.size.toString()}`] = []
return acc
}, {}),
};
export default (): void => {
const filesUploaded: { id: string, name: string, }[] = []
const {account, credential} = authFactory;
files.forEach(f => {
const id = f.unit + f.size.toString();
const asset = utils.buildAsset({
name: `${account.login}-dummy.zip`,
unit: f.unit as any,
size: f.size,
})
plays.fileUpload.exec({
credential,
asset,
userName: account.login,
tags: {asset: id},
});
filesUploaded.push({id, name: asset.name})
})
filesUploaded.forEach(f => {
plays.fileDownload.exec({
credential,
userName: account.login,
path: f.name,
tags: {asset: f.id},
});
})
filesUploaded.forEach(f => {
plays.fileDelete.exec({
credential,
userName: account.login,
path: f.name,
tags: {asset: f.id},
});
})
}

View File

@@ -1682,13 +1682,6 @@ aws4@^1.8.0:
resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.11.0.tgz#d61f46d83b2519250e2784daf5b09479a8b41c59"
integrity sha512-xh1Rl34h6Fi1DC2WWKfxUTVqRsNnr6LsKz2+hfwDxQJWmrx8+c7ylaqBMcHfl1U1r2dsifOvKX3LQuLNZ+XSvA==
axios@^0.21.0:
version "0.21.0"
resolved "https://registry.yarnpkg.com/axios/-/axios-0.21.0.tgz#26df088803a2350dff2c27f96fef99fe49442aca"
integrity sha512-fmkJBknJKoZwem3/IKSSLpkdNXZeBu5Q7GA/aRsr2btgrptmSCxi2oFjZHqGdK9DoTil9PIHlPIZw2EcRJXRvw==
dependencies:
follow-redirects "^1.10.0"
babel-jest@^25.5.1:
version "25.5.1"
resolved "https://registry.yarnpkg.com/babel-jest/-/babel-jest-25.5.1.tgz#bc2e6101f849d6f6aec09720ffc7bc5332e62853"
@@ -2028,11 +2021,6 @@ cli-cursor@^3.1.0:
dependencies:
restore-cursor "^3.1.0"
cli-spinners@^2.4.0:
version "2.5.0"
resolved "https://registry.yarnpkg.com/cli-spinners/-/cli-spinners-2.5.0.tgz#12763e47251bf951cb75c201dfa58ff1bcb2d047"
integrity sha512-PC+AmIuK04E6aeSs/pUccSujsTzBhu4HzC2dL+CfJB/Jcc2qTRbEwZQDfIUpt2Xl8BodYBEq8w4fc0kU2I9DjQ==
cli-truncate@^2.1.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/cli-truncate/-/cli-truncate-2.1.0.tgz#c39e28bf05edcde5be3b98992a22deed5a2b93c7"
@@ -2055,11 +2043,6 @@ cliui@^6.0.0:
strip-ansi "^6.0.0"
wrap-ansi "^6.2.0"
clone@^1.0.2:
version "1.0.4"
resolved "https://registry.yarnpkg.com/clone/-/clone-1.0.4.tgz#da309cc263df15994c688ca902179ca3c7cd7c7e"
integrity sha1-2jCcwmPfFZlMaIypAheco8fNfH4=
co@^4.6.0:
version "4.6.0"
resolved "https://registry.yarnpkg.com/co/-/co-4.6.0.tgz#6ea6bdf3d853ae54ccb8e47bfa0bf3f9031fb184"
@@ -2345,13 +2328,6 @@ deepmerge@^4.2.2:
resolved "https://registry.yarnpkg.com/deepmerge/-/deepmerge-4.2.2.tgz#44d2ea3679b8f4d4ffba33f03d865fc1e7bf4955"
integrity sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg==
defaults@^1.0.3:
version "1.0.3"
resolved "https://registry.yarnpkg.com/defaults/-/defaults-1.0.3.tgz#c656051e9817d9ff08ed881477f3fe4019f3ef7d"
integrity sha1-xlYFHpgX2f8I7YgUd/P+QBnz730=
dependencies:
clone "^1.0.2"
define-properties@^1.1.3:
version "1.1.3"
resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.1.3.tgz#cf88da6cbee26fe6db7094f61d870cbd84cee9f1"
@@ -2875,11 +2851,6 @@ flatted@^2.0.0:
resolved "https://registry.yarnpkg.com/flatted/-/flatted-2.0.2.tgz#4575b21e2bcee7434aa9be662f4b7b5f9c2b5138"
integrity sha512-r5wGx7YeOwNWNlCA0wQ86zKyDLMQr+/RB8xy74M4hTphfmjlijTSSXGuH8rnvKZnfT9i+75zmd8jcKdMR4O6jA==
follow-redirects@^1.10.0:
version "1.13.0"
resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.13.0.tgz#b42e8d93a2a7eea5ed88633676d6597bc8e384db"
integrity sha512-aq6gF1BEKje4a9i9+5jimNFIpq4Q1WiwBToeRK5NvZBd/TRsmW8BsJfOEGkr76TbOyPVD3OVDN910EcUNtRYEA==
for-in@^1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/for-in/-/for-in-1.0.2.tgz#81068d295a8142ec0ac726c6e2200c30fb6d5e80"
@@ -3014,7 +2985,7 @@ glob-parent@^5.0.0, glob-parent@^5.1.0:
dependencies:
is-glob "^4.0.1"
glob@^7.0.0, glob@^7.1.1, glob@^7.1.2, glob@^7.1.3, glob@^7.1.4, glob@^7.1.6:
glob@^7.1.1, glob@^7.1.2, glob@^7.1.3, glob@^7.1.4, glob@^7.1.6:
version "7.1.6"
resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.6.tgz#141f33b81a7c2492e125594307480c46679278a6"
integrity sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==
@@ -3252,11 +3223,6 @@ inquirer@^7.0.0:
strip-ansi "^6.0.0"
through "^2.3.6"
interpret@^1.0.0:
version "1.4.0"
resolved "https://registry.yarnpkg.com/interpret/-/interpret-1.4.0.tgz#665ab8bc4da27a774a40584e812e3e0fa45b1a1e"
integrity sha512-agE4QfB2Lkp9uICn7BAqoscw4SZP9kTE2hxiFI3jBPmXJfdqiahTbUuKGsMoN2GtqL9AxhYioAcVvgsb1HvRbA==
ip-regex@^2.1.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/ip-regex/-/ip-regex-2.1.0.tgz#fa78bf5d2e6913c911ce9f819ee5146bb6d844e9"
@@ -3381,11 +3347,6 @@ is-glob@^4.0.0, is-glob@^4.0.1:
dependencies:
is-extglob "^2.1.1"
is-interactive@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/is-interactive/-/is-interactive-1.0.0.tgz#cea6e6ae5c870a7b0a0004070b7b587e0252912e"
integrity sha512-2HvIEKRoqS62guEC+qBjpvRubdX910WCMuJTZ+I9yvqKU2/12eSL549HMwtabb4oupdj2sMP50k+XJfB/8JE6w==
is-module@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/is-module/-/is-module-1.0.0.tgz#3258fb69f78c14d5b815d664336b4cffb6441591"
@@ -4575,20 +4536,6 @@ optionator@^0.8.1, optionator@^0.8.3:
type-check "~0.3.2"
word-wrap "~1.2.3"
ora@^5.1.0:
version "5.1.0"
resolved "https://registry.yarnpkg.com/ora/-/ora-5.1.0.tgz#b188cf8cd2d4d9b13fd25383bc3e5cba352c94f8"
integrity sha512-9tXIMPvjZ7hPTbk8DFq1f7Kow/HU/pQYB60JbNq+QnGwcyhWVZaQ4hM9zQDEsPxw/muLpgiHSaumUZxCAmod/w==
dependencies:
chalk "^4.1.0"
cli-cursor "^3.1.0"
cli-spinners "^2.4.0"
is-interactive "^1.0.0"
log-symbols "^4.0.0"
mute-stream "0.0.8"
strip-ansi "^6.0.0"
wcwidth "^1.0.1"
os-tmpdir@~1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274"
@@ -4944,13 +4891,6 @@ realpath-native@^2.0.0:
resolved "https://registry.yarnpkg.com/realpath-native/-/realpath-native-2.0.0.tgz#7377ac429b6e1fd599dc38d08ed942d0d7beb866"
integrity sha512-v1SEYUOXXdbBZK8ZuNgO4TBjamPsiSgcFr0aP+tEKpQZK8vooEUqV6nm6Cv502mX4NF2EfsnVqtNAHG+/6Ur1Q==
rechoir@^0.6.2:
version "0.6.2"
resolved "https://registry.yarnpkg.com/rechoir/-/rechoir-0.6.2.tgz#85204b54dba82d5742e28c96756ef43af50e3384"
integrity sha1-hSBLVNuoLVdC4oyWdW70OvUOM4Q=
dependencies:
resolve "^1.1.6"
redent@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/redent/-/redent-2.0.0.tgz#c1b2007b42d57eb1389079b3c8333639d5e1ccaa"
@@ -5154,7 +5094,7 @@ resolve@1.1.7:
resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.1.7.tgz#203114d82ad2c5ed9e8e0411b3932875e889e97b"
integrity sha1-IDEU2CrSxe2ejgQRs5ModeiJ6Xs=
resolve@^1.1.6, resolve@^1.10.0, resolve@^1.11.0, resolve@^1.14.2, resolve@^1.17.0, resolve@^1.3.2:
resolve@^1.10.0, resolve@^1.11.0, resolve@^1.14.2, resolve@^1.17.0, resolve@^1.3.2:
version "1.19.0"
resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.19.0.tgz#1af5bf630409734a067cae29318aac7fa29a267c"
integrity sha512-rArEXAgsBG4UgRGcynxWIWKFvh/XZCcS8UJdHhwy91zwAvCZIbcs+vAbflgBnNjYMs/i/i+/Ux6IZhML1yPvxg==
@@ -5381,15 +5321,6 @@ shebang-regex@^3.0.0:
resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-3.0.0.tgz#ae16f1644d873ecad843b0307b143362d4c42172"
integrity sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==
shelljs@^0.8.4:
version "0.8.4"
resolved "https://registry.yarnpkg.com/shelljs/-/shelljs-0.8.4.tgz#de7684feeb767f8716b326078a8a00875890e3c2"
integrity sha512-7gk3UZ9kOfPLIAbslLzyWeGiEqx9e3rxwZM0KE6EL8GlGwjym9Mrlx5/p33bWTu9YG6vcS4MBxYZDHYr5lr8BQ==
dependencies:
glob "^7.0.0"
interpret "^1.0.0"
rechoir "^0.6.2"
shellwords@^0.1.1:
version "0.1.1"
resolved "https://registry.yarnpkg.com/shellwords/-/shellwords-0.1.1.tgz#d6b9181c1a48d397324c84871efbcfc73fc0654b"
@@ -6089,13 +6020,6 @@ walker@^1.0.7, walker@~1.0.5:
dependencies:
makeerror "1.0.x"
wcwidth@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/wcwidth/-/wcwidth-1.0.1.tgz#f0b0dcf915bc5ff1528afadb2c0e17b532da2fe8"
integrity sha1-8LDc+RW8X/FSivrbLA4XtTLaL+g=
dependencies:
defaults "^1.0.3"
webidl-conversions@^4.0.2:
version "4.0.2"
resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-4.0.2.tgz#a855980b1f0b6b359ba1d5d9fb39ae941faa63ad"