commit 4c11abd5d09ca5633683fc012429c1cb5bb5999c Author: Ilham Fadhilah Date: Tue May 20 16:56:21 2025 +0700 initial commit diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..4559ab7 --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +node_modules +results +*.log \ No newline at end of file diff --git a/index.js b/index.js new file mode 100644 index 0000000..de712c8 --- /dev/null +++ b/index.js @@ -0,0 +1,146 @@ +const shell = require('shelljs'); +const path = require('path'); + +const scriptsDir = path.join(__dirname, 'jmeter-scripts'); + +// Schedule configuration: time ranges and jmx file +// const schedule = [ +// { +// name: '20tps', +// startHour: 23, +// startMinute: 0, +// endHour: 23, +// endMinute: 10, +// jmx: 'lastlocation_20tps_10min_3000req.jmx', +// }, +// { +// name: '50tps', +// startHour: 23, +// startMinute: 15, +// endHour: 23, +// endMinute: 25, +// jmx: 'lastlocation_50tps_10min_3000req.jmx', +// }, +// { +// name: '100tps', +// startHour: 23, +// startMinute: 30, +// endHour: 23, +// endMinute: 40, +// jmx: 'lastlocation_100tps_10min_3000req.jmx', +// }, +// ]; +const schedule = [ + { + name: '20tps', + startHour: 16, + startMinute: 55, + endHour: 17, + endMinute: 0, + jmx: 'lastlocation_20tps_10min_3000req.jmx', + }, + { + name: '50tps', + startHour: 23, + startMinute: 15, + endHour: 23, + endMinute: 25, + jmx: 'lastlocation_50tps_10min_3000req.jmx', + }, + { + name: '100tps', + startHour: 23, + startMinute: 30, + endHour: 23, + endMinute: 40, + jmx: 'lastlocation_100tps_10min_3000req.jmx', + }, +]; + +// Track currently running schedule to avoid rerun within same slot +let currentlyRunning = null; + +function isNowInSchedule(now, sched) { + // now is a Date object + const start = new Date(now); + start.setHours(sched.startHour, sched.startMinute, 0, 0); + const end = new Date(now); + end.setHours(sched.endHour, sched.endMinute, 0, 0); + return now >= start && now < end; +} + +function formatDateForFolder(date) { + // Format YYYYMMDD_HHmmss for folder naming + const pad = (n) => n.toString().padStart(2, '0'); + return ( + date.getFullYear().toString() + + pad(date.getMonth() + 1) + + pad(date.getDate()) + + '_' + + pad(date.getHours()) + + pad(date.getMinutes()) + + pad(date.getSeconds()) + ); +} + +function runJMeter(jmxFile) { + const now = new Date(); + const timestamp = formatDateForFolder(now); + const resultFolder = path.join( + __dirname, + 'results', + `${timestamp}_${path.basename(jmxFile, '.jmx')}` + ); + const resultCsv = path.join(resultFolder, 'result.csv'); + + // Create result folder + shell.mkdir('-p', resultFolder); + + // Build command + const cmd = [ + 'jmeter', + '-n', + '-t', + `"${path.join(scriptsDir, jmxFile)}"`, + '-l', + `"${resultCsv}"`, + '-e', + '-o', + `"${resultFolder}"`, + ].join(' '); + + console.log(`[${now.toISOString()}] Running: ${cmd}`); + + // Run command asynchronously + shell.exec(cmd, { async: true }, (code, stdout, stderr) => { + if (code === 0) { + console.log(`[${new Date().toISOString()}] Finished running ${jmxFile}`); + } else { + console.error(`[${new Date().toISOString()}] JMeter exited with code ${code}`); + console.error(stderr); + } + currentlyRunning = null; // Allow next scheduled run + }); +} + +function checkSchedule() { + const now = new Date(); + + // If a job is already running, skip starting a new one + if (currentlyRunning) { + return; + } + + // Find schedule where current time fits + const activeSchedule = schedule.find((sched) => isNowInSchedule(now, sched)); + + if (activeSchedule) { + currentlyRunning = activeSchedule.name; + runJMeter(activeSchedule.jmx); + } +} + +// Run check every second +setInterval(checkSchedule, 1000); + +console.log(`Scheduler started on ${new Date()}. Waiting for scheduled times to run JMeter tests...`); diff --git a/jmeter-scripts/lastlocation_100tps_10min_3000req.jmx b/jmeter-scripts/lastlocation_100tps_10min_3000req.jmx new file mode 100644 index 0000000..90c5c25 --- /dev/null +++ b/jmeter-scripts/lastlocation_100tps_10min_3000req.jmx @@ -0,0 +1,101 @@ + + + + + + false + false + + + + + + + + continue + + -1 + false + + 20 + 1 + 600 + 0 + true + true + + + + 2 + + throughput + 6000.0 + 0.0 + + + + + + + + false + { + "consent_id": "cos_123123", + "msisdn": "6282215561862", + "latitude": "-6.9095928", + "longitude": "107.5601655", + "area": "500" +} + = + true + + + + + localhost + 3000 + http + /v1/last-location + POST + true + false + true + false + + + + true + + + + + + Accept + application/json + + + Authorization + Basic YWRtaW46MTIzNDU2 + + + Content-Type + application/json + + + + + + + groovy + = 3000) { + log.info("Reached 3000 requests, stopping test..."); + org.apache.jmeter.engine.StandardJMeterEngine.stopEngine(); + } + ]]> + + + + + + diff --git a/jmeter-scripts/lastlocation_20tps_10min_3000req.jmx b/jmeter-scripts/lastlocation_20tps_10min_3000req.jmx new file mode 100644 index 0000000..36d4da5 --- /dev/null +++ b/jmeter-scripts/lastlocation_20tps_10min_3000req.jmx @@ -0,0 +1,101 @@ + + + + + + false + false + + + + + + + + continue + + -1 + false + + 5 + 1 + 600 + 0 + true + true + + + + 2 + + throughput + 1200.0 + 0.0 + + + + + + + + false + { + "consent_id": "cos_123123", + "msisdn": "6282215561862", + "latitude": "-6.9095928", + "longitude": "107.5601655", + "area": "500" +} + = + true + + + + + localhost + 3000 + http + /v1/last-location + POST + true + false + true + false + + + + true + + + + + + Accept + application/json + + + Authorization + Basic YWRtaW46MTIzNDU2 + + + Content-Type + application/json + + + + + + + groovy + = 3000) { + log.info("Reached 3000 requests, stopping test..."); + org.apache.jmeter.engine.StandardJMeterEngine.stopEngine(); + } + ]]> + + + + + + diff --git a/jmeter-scripts/lastlocation_50tps_10min_3000req.jmx b/jmeter-scripts/lastlocation_50tps_10min_3000req.jmx new file mode 100644 index 0000000..015ba11 --- /dev/null +++ b/jmeter-scripts/lastlocation_50tps_10min_3000req.jmx @@ -0,0 +1,101 @@ + + + + + + false + false + + + + + + + + continue + + -1 + false + + 10 + 1 + 600 + 0 + true + true + + + + 2 + + throughput + 3000.0 + 0.0 + + + + + + + + false + { + "consent_id": "cos_123123", + "msisdn": "6282215561862", + "latitude": "-6.9095928", + "longitude": "107.5601655", + "area": "500" +} + = + true + + + + + localhost + 3000 + http + /v1/last-location + POST + true + false + true + false + + + + true + + + + + + Accept + application/json + + + Authorization + Basic YWRtaW46MTIzNDU2 + + + Content-Type + application/json + + + + + + + groovy + = 3000) { + log.info("Reached 3000 requests, stopping test..."); + org.apache.jmeter.engine.StandardJMeterEngine.stopEngine(); + } + ]]> + + + + + + diff --git a/notes.md b/notes.md new file mode 100644 index 0000000..e1afc0a --- /dev/null +++ b/notes.md @@ -0,0 +1,22 @@ +jmeter -n -t tsel-simswap.jmx -l tsel-simswap.csv -e -o tsel-simswap + +===============prompt================ +adjust it so it will run 50 tps, for 10 minutes and max 3000 request + +===============prompt================ +now i have files like this + +jmeter-scripts/lastlocation_20tps_10min_3000req.jmx +jmeter-scripts/lastlocation_50tps_10min_3000req.jmx +jmeter-scripts/lastlocation_100tps_10min_3000req.jmx +index.js + +make me a nodejs app, that will check the system clock every second to run the files in jmeter-scripts based on the time +1. 23.00-23.10: jmeter-scripts/lastlocation_20tps_10min_3000req.jmx +2. 23.15-23.25: jmeter-scripts/lastlocation_50tps_10min_3000req.jmx +3. 23.30-23.40: jmeter-scripts/lastlocation_100tps_10min_3000req.jmx + +i have prepare shelljs so when the time has come, it will run jmeter command like this +```bash +jmeter -n -t [jmx-file] -l [result-csv-file in a new folder] -e -o [output folder same as result-csv-file] +``` \ No newline at end of file diff --git a/package.json b/package.json new file mode 100644 index 0000000..789ae8f --- /dev/null +++ b/package.json @@ -0,0 +1,10 @@ +{ + "scripts": {}, + "dependencies": { + "shelljs": "^0.8.5" + }, + "devDependencies": { + "@types/shelljs": "^0.8.15" + }, + "packageManager": "yarn@1.22.22+sha512.a6b2f7906b721bba3d67d4aff083df04dad64c399707841b7acf00f6b133b7ac24255f2652fa22ae3534329dc6180534e98d17432037ff6fd140556e2bb3137e" +} diff --git a/yarn.lock b/yarn.lock new file mode 100644 index 0000000..955ebf6 --- /dev/null +++ b/yarn.lock @@ -0,0 +1,167 @@ +# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. +# yarn lockfile v1 + + +"@types/glob@~7.2.0": + version "7.2.0" + resolved "https://registry.yarnpkg.com/@types/glob/-/glob-7.2.0.tgz#bc1b5bf3aa92f25bd5dd39f35c57361bdce5b2eb" + integrity sha512-ZUxbzKl0IfJILTS6t7ip5fQQM/J3TJYubDm3nMbgubNNYS62eXeUpoLUC8/7fJNiFYHTrGPQn7hspDUzIHX3UA== + dependencies: + "@types/minimatch" "*" + "@types/node" "*" + +"@types/minimatch@*": + version "5.1.2" + resolved "https://registry.yarnpkg.com/@types/minimatch/-/minimatch-5.1.2.tgz#07508b45797cb81ec3f273011b054cd0755eddca" + integrity sha512-K0VQKziLUWkVKiRVrx4a40iPaxTUefQmjtkQofBkYRcoaaL/8rhwDWww9qWbrgicNOgnpIsMxyNIUM4+n6dUIA== + +"@types/node@*": + version "22.15.19" + resolved "https://registry.yarnpkg.com/@types/node/-/node-22.15.19.tgz#ba9f321675243af0456d607fa82a4865931e0cef" + integrity sha512-3vMNr4TzNQyjHcRZadojpRaD9Ofr6LsonZAoQ+HMUa/9ORTPoxVIw0e0mpqWpdjj8xybyCM+oKOUH2vwFu/oEw== + dependencies: + undici-types "~6.21.0" + +"@types/shelljs@^0.8.15": + version "0.8.16" + resolved "https://registry.yarnpkg.com/@types/shelljs/-/shelljs-0.8.16.tgz#d18efab20bb76e465575e16b8e0db94d2973036f" + integrity sha512-40SUXiH0tZfAg/oKkkGF1kdHPAmE4slv2xAmbfa8VtE6ztHYwdpW2phlzHTVdJh5JOGqA3Cx1Hzp7kxFalKHYA== + dependencies: + "@types/glob" "~7.2.0" + "@types/node" "*" + +balanced-match@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee" + integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw== + +brace-expansion@^1.1.7: + version "1.1.11" + resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" + integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA== + dependencies: + balanced-match "^1.0.0" + concat-map "0.0.1" + +concat-map@0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" + integrity sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg== + +fs.realpath@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" + integrity sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw== + +function-bind@^1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.2.tgz#2c02d864d97f3ea6c8830c464cbd11ab6eab7a1c" + integrity sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA== + +glob@^7.0.0: + version "7.2.3" + resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.3.tgz#b8df0fb802bbfa8e89bd1d938b4e16578ed44f2b" + integrity sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q== + dependencies: + fs.realpath "^1.0.0" + inflight "^1.0.4" + inherits "2" + minimatch "^3.1.1" + once "^1.3.0" + path-is-absolute "^1.0.0" + +hasown@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/hasown/-/hasown-2.0.2.tgz#003eaf91be7adc372e84ec59dc37252cedb80003" + integrity sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ== + dependencies: + function-bind "^1.1.2" + +inflight@^1.0.4: + version "1.0.6" + resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" + integrity sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA== + dependencies: + once "^1.3.0" + wrappy "1" + +inherits@2: + version "2.0.4" + resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" + integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== + +interpret@^1.0.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/interpret/-/interpret-1.4.0.tgz#665ab8bc4da27a774a40584e812e3e0fa45b1a1e" + integrity sha512-agE4QfB2Lkp9uICn7BAqoscw4SZP9kTE2hxiFI3jBPmXJfdqiahTbUuKGsMoN2GtqL9AxhYioAcVvgsb1HvRbA== + +is-core-module@^2.16.0: + version "2.16.1" + resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.16.1.tgz#2a98801a849f43e2add644fbb6bc6229b19a4ef4" + integrity sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w== + dependencies: + hasown "^2.0.2" + +minimatch@^3.1.1: + version "3.1.2" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.1.2.tgz#19cd194bfd3e428f049a70817c038d89ab4be35b" + integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw== + dependencies: + brace-expansion "^1.1.7" + +once@^1.3.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" + integrity sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w== + dependencies: + wrappy "1" + +path-is-absolute@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" + integrity sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg== + +path-parse@^1.0.7: + version "1.0.7" + resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.7.tgz#fbc114b60ca42b30d9daf5858e4bd68bbedb6735" + integrity sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw== + +rechoir@^0.6.2: + version "0.6.2" + resolved "https://registry.yarnpkg.com/rechoir/-/rechoir-0.6.2.tgz#85204b54dba82d5742e28c96756ef43af50e3384" + integrity sha512-HFM8rkZ+i3zrV+4LQjwQ0W+ez98pApMGM3HUrN04j3CqzPOzl9nmP15Y8YXNm8QHGv/eacOVEjqhmWpkRV0NAw== + dependencies: + resolve "^1.1.6" + +resolve@^1.1.6: + version "1.22.10" + resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.10.tgz#b663e83ffb09bbf2386944736baae803029b8b39" + integrity sha512-NPRy+/ncIMeDlTAsuqwKIiferiawhefFJtkNSW0qZJEqMEb+qBt/77B/jGeeek+F0uOeN05CDa6HXbbIgtVX4w== + dependencies: + is-core-module "^2.16.0" + path-parse "^1.0.7" + supports-preserve-symlinks-flag "^1.0.0" + +shelljs@^0.8.5: + version "0.8.5" + resolved "https://registry.yarnpkg.com/shelljs/-/shelljs-0.8.5.tgz#de055408d8361bed66c669d2f000538ced8ee20c" + integrity sha512-TiwcRcrkhHvbrZbnRcFYMLl30Dfov3HKqzp5tO5b4pt6G/SezKcYhmDg15zXVBswHmctSAQKznqNW2LO5tTDow== + dependencies: + glob "^7.0.0" + interpret "^1.0.0" + rechoir "^0.6.2" + +supports-preserve-symlinks-flag@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz#6eda4bd344a3c94aea376d4cc31bc77311039e09" + integrity sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w== + +undici-types@~6.21.0: + version "6.21.0" + resolved "https://registry.yarnpkg.com/undici-types/-/undici-types-6.21.0.tgz#691d00af3909be93a7faa13be61b3a5b50ef12cb" + integrity sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ== + +wrappy@1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" + integrity sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==