|
@@ -0,0 +1,137 @@
|
|
|
|
+#!/usr/bin/env node
|
|
|
|
+
|
|
|
|
+const { ContentId } = require('@joystream/types/storage')
|
|
|
|
+const { ApiPromise, WsProvider } = require('@polkadot/api')
|
|
|
|
+const { types } = require('@joystream/types')
|
|
|
|
+
|
|
|
|
+const fsPromises = require('fs/promises')
|
|
|
|
+const fs = require('fs')
|
|
|
|
+const Path = require('path')
|
|
|
|
+
|
|
|
|
+const {
|
|
|
|
+ getActiveWorkersIds,
|
|
|
|
+ getWorkerEndpoint,
|
|
|
|
+ generateListOfDataObjectsToDownload,
|
|
|
|
+ makeAssetUrl,
|
|
|
|
+ downloadFile,
|
|
|
|
+ clearFolder,
|
|
|
|
+ computeMedian
|
|
|
|
+} = require('./utils')
|
|
|
|
+
|
|
|
|
+const { program } = require('commander')
|
|
|
|
+
|
|
|
|
+const TEMP_FOLDER = Path.resolve(__dirname, '../', 'temp')
|
|
|
|
+const PROVIDER_URL = 'wss://rome-rpc-endpoint.joystream.org:9944'
|
|
|
|
+const NR_DEFAULT_SMALL_ASSETS = 9
|
|
|
|
+const NR_BIG_ASSETS = 1
|
|
|
|
+
|
|
|
|
+async function main() {
|
|
|
|
+ program
|
|
|
|
+ .option('-w, --workers <workerId>', `the Worker id's to perform the tests, separated by comma. Ex: 4,5,6`)
|
|
|
|
+ .option('-f, --asset-file [path]', 'a list of assets ids to download the same files for different providers')
|
|
|
|
+ .option('-s, --nr-small-assets [number]', 'the number of small files to download', NR_DEFAULT_SMALL_ASSETS)
|
|
|
|
+ .option('-b, --nr-big-assets [number]', 'the number of big files to download', NR_BIG_ASSETS)
|
|
|
|
+ .parse()
|
|
|
|
+
|
|
|
|
+ const provider = new WsProvider(process.env.PROVIDER_URL || PROVIDER_URL)
|
|
|
|
+ const api = await ApiPromise.create({ provider, types })
|
|
|
|
+ await api.isReady
|
|
|
|
+
|
|
|
|
+ const args = program.opts()
|
|
|
|
+
|
|
|
|
+ let dataObjectsIds = []
|
|
|
|
+ const assetsFilePath = args.assetFile
|
|
|
|
+ if (assetsFilePath) {
|
|
|
|
+ try {
|
|
|
|
+ await fsPromises.access(assetsFilePath, fs.constants.R_OK)
|
|
|
|
+ } catch {
|
|
|
|
+ console.error('Unable to read ' + assetsFilePath)
|
|
|
|
+ process.exit(1)
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ const data = (await fsPromises.readFile(assetsFilePath, 'utf8')).toString()
|
|
|
|
+ dataObjectsIds = data
|
|
|
|
+ .split('\n')
|
|
|
|
+ .filter((line) => line)
|
|
|
|
+ .map((line) => ContentId.decode(api.registry, line))
|
|
|
|
+ } else {
|
|
|
|
+ dataObjectsIds = await generateListOfDataObjectsToDownload(api, args.nrSmallAssets, args.nrBigAssets)
|
|
|
|
+ const writeStream = fs.createWriteStream(Path.join(__dirname, '..', 'assets.txt'))
|
|
|
|
+ for (const id of dataObjectsIds) {
|
|
|
|
+ writeStream.write(id.encode() + '\n')
|
|
|
|
+ }
|
|
|
|
+ writeStream.close()
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ const dataObjects = await Promise.all(
|
|
|
|
+ dataObjectsIds.map(async (id) => {
|
|
|
|
+ const dataObject = await api.query.dataDirectory.dataByContentId(id)
|
|
|
|
+ dataObject.contentId = id
|
|
|
|
+ return dataObject
|
|
|
|
+ })
|
|
|
|
+ )
|
|
|
|
+
|
|
|
|
+ let workerIds = args.workers?.split(',')
|
|
|
|
+ if (!workerIds) {
|
|
|
|
+ workerIds = await getActiveWorkersIds(api)
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ let success = true
|
|
|
|
+ try {
|
|
|
|
+ for (const workerId of workerIds) {
|
|
|
|
+ try {
|
|
|
|
+ await testWorker(api, workerId, dataObjects)
|
|
|
|
+ } catch (e) {
|
|
|
|
+ console.error(e)
|
|
|
|
+ }
|
|
|
|
+ await clearFolder(TEMP_FOLDER)
|
|
|
|
+ }
|
|
|
|
+ } catch {
|
|
|
|
+ success = false
|
|
|
|
+ } finally {
|
|
|
|
+ await api.disconnect()
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if (!success) {
|
|
|
|
+ process.exit(2)
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+async function testWorker(api, workerId, dataObjects) {
|
|
|
|
+ const endpoint = await getWorkerEndpoint(api, workerId)
|
|
|
|
+ if (!endpoint) {
|
|
|
|
+ throw new Error(`Worker ${workerId} doesn't have an endpoint defined`)
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ const promises = []
|
|
|
|
+ const startRequests = process.hrtime.bigint()
|
|
|
|
+ for (const dataObject of dataObjects) {
|
|
|
|
+ const url = makeAssetUrl(dataObject.contentId, endpoint)
|
|
|
|
+ promises.push(downloadFile(url, TEMP_FOLDER, dataObject.contentId.toString()))
|
|
|
|
+ }
|
|
|
|
+ try {
|
|
|
|
+ const times = await Promise.all(promises)
|
|
|
|
+ const endRequests = process.hrtime.bigint()
|
|
|
|
+ const totalTime = Number((endRequests - startRequests) / BigInt(1000000))
|
|
|
|
+ const totalSizeInMegas =
|
|
|
|
+ dataObjects.reduce((accumulator, dataObject) => accumulator + Number(dataObject.size_in_bytes), 0) / 1024 / 1024
|
|
|
|
+
|
|
|
|
+ const average = times.reduce((accumulator, time) => accumulator + time, 0) / times.length
|
|
|
|
+ console.log(
|
|
|
|
+ JSON.stringify({
|
|
|
|
+ averageMs: Number(average.toFixed(2)),
|
|
|
|
+ medianMs: Number(computeMedian(times).toFixed(2)),
|
|
|
|
+ maxMs: Number(Math.max.apply(Math, times).toFixed(2)),
|
|
|
|
+ minMs: Number(Math.min.apply(Math, times).toFixed(2)),
|
|
|
|
+ totalTimeMs: totalTime,
|
|
|
|
+ averageSpeedMBpS: Number((totalSizeInMegas / (totalTime / 100)).toFixed(3)),
|
|
|
|
+ nrFilesDownloaded: times.length,
|
|
|
|
+ workerId: workerId,
|
|
|
|
+ })
|
|
|
|
+ )
|
|
|
|
+ } catch (e) {
|
|
|
|
+ throw new Error('Fail to download files from worker')
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+main()
|