From f0157295c43af842cbbbb4d0c5bf4ff0c4f7a769 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bartos=20Anik=C3=B3?= Date: Fri, 4 Jun 2021 13:26:37 +0200 Subject: [PATCH 1/4] MDCL-3939: add maxduration and upperlimit, modify constantConcurrentUsers to constantUsersPerSec --- README.md | 23 ++++----- src/main/resources/config.ini | 16 ++++--- src/main/scala/gatling/Config.scala | 49 ++++++++++++------- src/main/scala/gatling/ScanSimulation.scala | 53 +++++++++++---------- 4 files changed, 81 insertions(+), 60 deletions(-) diff --git a/README.md b/README.md index 521ebb2..ac8bbe7 100644 --- a/README.md +++ b/README.md @@ -28,12 +28,13 @@ Example configuration for **Metadefender Cloud** usage: [general] BaseUrl=https://api.metadefender.com/v4/file ConstantUsers=5 -TestDuration=10 +InjectDuration=30 +MaxDuration=60 ScanWorkflow=multiscan,sanitize LocalPath=/home/opswatuser/testfiles PollingIntervals=500 ApiKey=1234567890abcdefghijklmnopqrstuv -WaitBeforePolling=1000 +ScanNumberUpperBound=13 ``` Example configuration for **local MetaDefender Core** usage: @@ -41,10 +42,10 @@ Example configuration for **local MetaDefender Core** usage: [general] BaseUrl=http://localhost:8008/file ConstantUsers=5 -TestDuration=10 +InjectDuration=30 LocalPath=/home/opswatuser/testfiles PollingIntervals=500 -WaitBeforePolling=1000 +ScanNumberUpperBound=13 ``` ***BaseURL:*** @@ -54,12 +55,16 @@ More information about file scanning: [File scanning API](https://onlinehelp.ops ***ConstantUsers:*** -The number of constant concurrent users for the test. Each simulated user will submit a randomly +The number of users injecting every second for the test. Each simulated user will submit a randomly selected file for scanning, wait for the scan result, then select a new file for scanning. -***TestDuration:*** +***InjectDuration:*** -Total test duration while the simulated users will continue to submit files. (seconds) +Injects users into the test during this duration. (seconds) + +***MaxDuration:*** + +The maximum duration of the test. It is a hard limit with a default value *InjectDuration* × 10. (seconds) ***ScanWorkflow [optional]:*** @@ -81,10 +86,6 @@ Sleep time between polling scan results. (milliseconds) OPSWAT MetaDefender Cloud API key. You can find your key at [metadefender.opswat.com](https://metadefender.opswat.com/account) -> *API key information and limits* -> *API key*. (Registration required.) -***WaitBeforePolling:*** - -Waiting time after file submission to start polling. (milliseconds) - *****ShowPollingDetails:*** If true, Gatling will also show the polling details as separate requests. By default, it is false. (true/false) diff --git a/src/main/resources/config.ini b/src/main/resources/config.ini index 3927bec..91a6692 100644 --- a/src/main/resources/config.ini +++ b/src/main/resources/config.ini @@ -1,16 +1,18 @@ [general] BaseUrl=https://api.metadefender.com/v4/file -;constant concurrent users -ConstantUsers=1 -;time to run, (s) -TestDuration=10 +;constant injected users per sec +ConstantUsers=4 +;user injection duration, (s) +InjectDuration=30 +;maximum test duration, (s) +MaxDuration=60 ;file scanning rule ScanWorkflow=multiscan,sanitize ;dataset folder LocalPath=C:\OPSWAT\data ;sleep time between each polling scan result (ms) -PollingIntervals=500 +PollingIntervals=10000 ;OPSWAT MetaDefender Cloud apikey ApiKey=opswat_metadefender_api -;waiting time between push file and start to polling (ms) -WaitBeforePolling=1000 \ No newline at end of file +;upper limit on the amount of files submitted +ScanNumberUpperBound=30 \ No newline at end of file diff --git a/src/main/scala/gatling/Config.scala b/src/main/scala/gatling/Config.scala index dd24ffb..ecc0403 100644 --- a/src/main/scala/gatling/Config.scala +++ b/src/main/scala/gatling/Config.scala @@ -7,33 +7,48 @@ import java.nio.file.{Files, Paths} class Config { var baseUrl = "" var constantUser = 2 - var testDuration = 5 + var injectDuration = 0 + var maxDuration = 60 var scanWorkflow = "" var localPath = "" var pollingIntervals = 500 var apikey = "" - var waitBeforePolling = 1000 var pollingDetails = false var developerMode = false + var scanNumberUpper = 0 } object Config { - def checkValues(config: Config): Unit ={ - if(config.baseUrl==null||config.baseUrl==""){throw new IOException("MISSING ENDPOINT")} - if(config.constantUser<1){config.constantUser=2} - if(config.testDuration<1){config.testDuration=5} - if(config.scanWorkflow==null){config.scanWorkflow=""} + def checkValues(config: Config): Unit = { + if (config.baseUrl == null || config.baseUrl == "") { + throw new IOException("MISSING ENDPOINT") + } + if (config.constantUser < 1) { + config.constantUser = 2 + } + if (config.injectDuration == 0) { + config.injectDuration = 10 + } + if (config.maxDuration == 0) { + config.maxDuration = config.injectDuration * 10 + } + if (config.scanWorkflow == null) { + config.scanWorkflow = "" + } - try{ - assert(Files.list(Paths.get(config.localPath)).count()>0) + try { + assert(Files.list(Paths.get(config.localPath)).count() > 0) } catch { - case _:Throwable => throw new IOException("WRONG PATH OR EMPTY DIRECTORY: "+config.localPath) + case _: Throwable => throw new IOException("WRONG PATH OR EMPTY DIRECTORY: " + config.localPath) } - if(config.pollingIntervals<1){config.pollingIntervals=500} - if(config.apikey==null){config.apikey=""} - if(config.waitBeforePolling<1){config.waitBeforePolling=1000} + if (config.pollingIntervals < 1) { + config.pollingIntervals = 500 + } + if (config.apikey == null) { + config.apikey = "" + } } def parseConfigure(filePath: String): Config = { @@ -43,16 +58,16 @@ object Config { v.baseUrl = ini.get("general", "BaseUrl", classOf[String]) v.constantUser = ini.get("general", "ConstantUsers", classOf[Int]) - v.testDuration = ini.get("general", "TestDuration", classOf[Int]) + v.injectDuration = ini.get("general", "InjectDuration", classOf[Int]) + v.maxDuration = ini.get("general", "MaxDuration", classOf[Int]) v.scanWorkflow = ini.get("general", "ScanWorkflow", classOf[String]) v.localPath = ini.get("general", "LocalPath", classOf[String]) v.pollingIntervals = ini.get("general", "PollingIntervals", classOf[Int]) v.apikey = ini.get("general", "ApiKey", classOf[String]) - v.apikey=ini.get("general", "ApiKey", classOf[String]) - v.waitBeforePolling = ini.get("general", "WaitBeforePolling", classOf[Int]) + v.apikey = ini.get("general", "ApiKey", classOf[String]) v.pollingDetails = ini.get("general", "ShowPollingDetails", classOf[Boolean]) v.developerMode = ini.get("general", "DeveloperMode", classOf[Boolean]) - + v.scanNumberUpper = ini.get("general", "ScanNumberUpperBound", classOf[Int]) checkValues(v) v diff --git a/src/main/scala/gatling/ScanSimulation.scala b/src/main/scala/gatling/ScanSimulation.scala index 0b66965..06f4484 100644 --- a/src/main/scala/gatling/ScanSimulation.scala +++ b/src/main/scala/gatling/ScanSimulation.scala @@ -5,12 +5,14 @@ import io.gatling.core.structure.{ChainBuilder, ScenarioBuilder} import io.gatling.http.Predef._ import io.gatling.http.protocol.HttpProtocolBuilder import io.gatling.http.request.builder.HttpRequestBuilder +import java.util.concurrent.atomic.AtomicInteger import scala.concurrent.duration._ class ScanSimulation extends Simulation { val config = Config.parseConfigure("config.ini") var localFiles = new LocalFiles(config.localPath) + var fileUploadCounter = new AtomicInteger(0) val httpProtocol: HttpProtocolBuilder = http .baseUrl(config.baseUrl) @@ -19,21 +21,21 @@ class ScanSimulation extends Simulation { .disableCaching object FileUpload { - def initFileUpload () : HttpRequestBuilder = { + def initFileUpload(): HttpRequestBuilder = { var base = http("submit-file") .post(config.baseUrl) - .header("filename","${filename}") + .header("filename", "${filename}") - if(config.scanWorkflow != ""){ + if (config.scanWorkflow != "") { base = base.header("rule", config.scanWorkflow) } - if(config.apikey != ""){ + if (config.apikey != "") { base = base.header("apikey", config.apikey) } base - .header("Content-Type","application/octet-stream") + .header("Content-Type", "application/octet-stream") .body(RawFileBody("${filepath}")) .check(status.is(200)) .check(jsonPath("$..data_id").find.exists) @@ -44,29 +46,29 @@ class ScanSimulation extends Simulation { } object ScanProgress { - def initScanProgress () : HttpRequestBuilder = { + def initScanProgress(): HttpRequestBuilder = { var base = http("get-scan-result") .get(config.baseUrl + "/${dataId}") - if(config.apikey != ""){ + if (config.apikey != "") { base = base.header("apikey", config.apikey) } - if(!config.pollingDetails){ + if (!config.pollingDetails) { base = base.silent } base .check(status.is(200)) .check(jsonPath("$..process_info.progress_percentage").optional.saveAs("progress")) - .check( jsonPath( "$" ).optional.saveAs( "response_data" ) ) + .check(jsonPath("$").optional.saveAs("response_data")) } - def printResponse (): ChainBuilder = { - exec( session => { - if(session.contains("response_data")) { + def printResponse(): ChainBuilder = { + exec(session => { + if (session.contains("response_data")) { println("Response:") - println(session( "response_data").as[String]) + println(session("response_data").as[String]) } session }) @@ -76,26 +78,27 @@ class ScanSimulation extends Simulation { val action: ChainBuilder = exec(_.set("progress", "0")) - .doIf(session => session("dataId").asOption[String].isDefined) { + .doIf(session => session("dataId").asOption[String].isDefined) { asLongAs(session => session("progress").as[String] != "100") { pause(config.pollingIntervals.millis) - .exec(getScanProgress) - .doIf(config.developerMode){ - printResponse() - } + .exec(getScanProgress) + .doIf(config.developerMode) { + printResponse() + } } - } + } } val pipeline: ScenarioBuilder = scenario("scan-pipeline") - .feed(localFiles.feeder) - .exec(FileUpload.submitFile) - .pause(config.waitBeforePolling.milliseconds) - .exec(ScanProgress.action) + .doIf(_ => (config.scanNumberUpper == 0 || fileUploadCounter.getAndIncrement() < config.scanNumberUpper)) { + feed(localFiles.feeder) + .exec(FileUpload.submitFile) + .exec(ScanProgress.action) + } setUp( pipeline - .inject(constantConcurrentUsers(config.constantUser).during(config.testDuration)) + .inject(constantUsersPerSec(config.constantUser).during(config.injectDuration)) .protocols(httpProtocol) - ) + ).maxDuration(config.maxDuration) } From 39d5e3ad9d84ce380478b148619090b5ea6da135 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bartos=20Anik=C3=B3?= Date: Fri, 4 Jun 2021 16:06:07 +0200 Subject: [PATCH 2/4] MDCL-3939: readme correction and rename constantuser --- README.md | 5 ++--- src/main/resources/config.ini | 4 ++-- src/main/scala/gatling/Config.scala | 9 ++++----- src/main/scala/gatling/ScanSimulation.scala | 2 +- 4 files changed, 9 insertions(+), 11 deletions(-) diff --git a/README.md b/README.md index ac8bbe7..4ba8294 100644 --- a/README.md +++ b/README.md @@ -53,10 +53,9 @@ ScanNumberUpperBound=13 MetaDefender REST URL, e.g.: https://api.metadefender.com/v4/file (Cloud) or http://localhost:8008/file (local). More information about file scanning: [File scanning API](https://onlinehelp.opswat.com/mdcloud/2.1_Scanning_a_file_by_file_upload.html) -***ConstantUsers:*** +***UsersPerSec:*** -The number of users injecting every second for the test. Each simulated user will submit a randomly -selected file for scanning, wait for the scan result, then select a new file for scanning. +The number of users injected every second for the test. Each simulated user will submit a randomly selected file for scanning and wait for the scan result. It is equal to scan request per second. ***InjectDuration:*** diff --git a/src/main/resources/config.ini b/src/main/resources/config.ini index 91a6692..25d720d 100644 --- a/src/main/resources/config.ini +++ b/src/main/resources/config.ini @@ -1,7 +1,7 @@ [general] BaseUrl=https://api.metadefender.com/v4/file -;constant injected users per sec -ConstantUsers=4 +;injected users per sec +UsersPerSec=4 ;user injection duration, (s) InjectDuration=30 ;maximum test duration, (s) diff --git a/src/main/scala/gatling/Config.scala b/src/main/scala/gatling/Config.scala index ecc0403..61a83c1 100644 --- a/src/main/scala/gatling/Config.scala +++ b/src/main/scala/gatling/Config.scala @@ -6,7 +6,7 @@ import java.nio.file.{Files, Paths} class Config { var baseUrl = "" - var constantUser = 2 + var usersPerSec = 2 var injectDuration = 0 var maxDuration = 60 var scanWorkflow = "" @@ -23,8 +23,8 @@ object Config { if (config.baseUrl == null || config.baseUrl == "") { throw new IOException("MISSING ENDPOINT") } - if (config.constantUser < 1) { - config.constantUser = 2 + if (config.usersPerSec < 1) { + config.usersPerSec = 2 } if (config.injectDuration == 0) { config.injectDuration = 10 @@ -57,14 +57,13 @@ object Config { val ini = new Wini(new File(filePath)) v.baseUrl = ini.get("general", "BaseUrl", classOf[String]) - v.constantUser = ini.get("general", "ConstantUsers", classOf[Int]) + v.usersPerSec = ini.get("general", "UsersPerSec", classOf[Int]) v.injectDuration = ini.get("general", "InjectDuration", classOf[Int]) v.maxDuration = ini.get("general", "MaxDuration", classOf[Int]) v.scanWorkflow = ini.get("general", "ScanWorkflow", classOf[String]) v.localPath = ini.get("general", "LocalPath", classOf[String]) v.pollingIntervals = ini.get("general", "PollingIntervals", classOf[Int]) v.apikey = ini.get("general", "ApiKey", classOf[String]) - v.apikey = ini.get("general", "ApiKey", classOf[String]) v.pollingDetails = ini.get("general", "ShowPollingDetails", classOf[Boolean]) v.developerMode = ini.get("general", "DeveloperMode", classOf[Boolean]) v.scanNumberUpper = ini.get("general", "ScanNumberUpperBound", classOf[Int]) diff --git a/src/main/scala/gatling/ScanSimulation.scala b/src/main/scala/gatling/ScanSimulation.scala index 06f4484..faf030b 100644 --- a/src/main/scala/gatling/ScanSimulation.scala +++ b/src/main/scala/gatling/ScanSimulation.scala @@ -98,7 +98,7 @@ class ScanSimulation extends Simulation { setUp( pipeline - .inject(constantUsersPerSec(config.constantUser).during(config.injectDuration)) + .inject(constantUsersPerSec(config.usersPerSec).during(config.injectDuration)) .protocols(httpProtocol) ).maxDuration(config.maxDuration) } From 820682e1b4d61730b42982b0dee1bf5aa775dde2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bartos=20Anik=C3=B3?= Date: Mon, 7 Jun 2021 11:27:27 +0200 Subject: [PATCH 3/4] MDCL-3939: readme correction and rename ScanNumberUpperBound to ScanRequestsUpperBound --- README.md | 10 +++++++--- src/main/resources/config.ini | 2 +- src/main/scala/gatling/Config.scala | 4 ++-- src/main/scala/gatling/ScanSimulation.scala | 2 +- 4 files changed, 11 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index 4ba8294..d2f6bae 100644 --- a/README.md +++ b/README.md @@ -34,7 +34,7 @@ ScanWorkflow=multiscan,sanitize LocalPath=/home/opswatuser/testfiles PollingIntervals=500 ApiKey=1234567890abcdefghijklmnopqrstuv -ScanNumberUpperBound=13 +ScanRequestsUpperBound=100 ``` Example configuration for **local MetaDefender Core** usage: @@ -45,7 +45,7 @@ ConstantUsers=5 InjectDuration=30 LocalPath=/home/opswatuser/testfiles PollingIntervals=500 -ScanNumberUpperBound=13 +ScanRequestsUpperBound=100 ``` ***BaseURL:*** @@ -55,7 +55,7 @@ More information about file scanning: [File scanning API](https://onlinehelp.ops ***UsersPerSec:*** -The number of users injected every second for the test. Each simulated user will submit a randomly selected file for scanning and wait for the scan result. It is equal to scan request per second. +The number of users injected every second during the test (i.e. the number of scan requests per second). Each simulated user will submit a randomly selected file for scanning and wait for the scan result. ***InjectDuration:*** @@ -85,6 +85,10 @@ Sleep time between polling scan results. (milliseconds) OPSWAT MetaDefender Cloud API key. You can find your key at [metadefender.opswat.com](https://metadefender.opswat.com/account) -> *API key information and limits* -> *API key*. (Registration required.) +***ScanRequestsUpperBound [optional]:*** + +Upper bound for scan requests. If the scan requests reached the limit the software does not send a new scan request. If this bound is zero or not given, the script upload files for a scan as long as the _InjectDuration_ lasts or running time does not reach the _Maxduration_. + *****ShowPollingDetails:*** If true, Gatling will also show the polling details as separate requests. By default, it is false. (true/false) diff --git a/src/main/resources/config.ini b/src/main/resources/config.ini index 25d720d..14677f7 100644 --- a/src/main/resources/config.ini +++ b/src/main/resources/config.ini @@ -15,4 +15,4 @@ PollingIntervals=10000 ;OPSWAT MetaDefender Cloud apikey ApiKey=opswat_metadefender_api ;upper limit on the amount of files submitted -ScanNumberUpperBound=30 \ No newline at end of file +ScanRequestsUpperBound=100 \ No newline at end of file diff --git a/src/main/scala/gatling/Config.scala b/src/main/scala/gatling/Config.scala index 61a83c1..eb8b660 100644 --- a/src/main/scala/gatling/Config.scala +++ b/src/main/scala/gatling/Config.scala @@ -15,7 +15,7 @@ class Config { var apikey = "" var pollingDetails = false var developerMode = false - var scanNumberUpper = 0 + var scanRequestsUpper = 0 } object Config { @@ -66,7 +66,7 @@ object Config { v.apikey = ini.get("general", "ApiKey", classOf[String]) v.pollingDetails = ini.get("general", "ShowPollingDetails", classOf[Boolean]) v.developerMode = ini.get("general", "DeveloperMode", classOf[Boolean]) - v.scanNumberUpper = ini.get("general", "ScanNumberUpperBound", classOf[Int]) + v.scanRequestsUpper = ini.get("general", "ScanRequestsUpperBound", classOf[Int]) checkValues(v) v diff --git a/src/main/scala/gatling/ScanSimulation.scala b/src/main/scala/gatling/ScanSimulation.scala index faf030b..3618f9a 100644 --- a/src/main/scala/gatling/ScanSimulation.scala +++ b/src/main/scala/gatling/ScanSimulation.scala @@ -90,7 +90,7 @@ class ScanSimulation extends Simulation { } val pipeline: ScenarioBuilder = scenario("scan-pipeline") - .doIf(_ => (config.scanNumberUpper == 0 || fileUploadCounter.getAndIncrement() < config.scanNumberUpper)) { + .doIf(_ => (config.scanRequestsUpper == 0 || fileUploadCounter.getAndIncrement() < config.scanRequestsUpper)) { feed(localFiles.feeder) .exec(FileUpload.submitFile) .exec(ScanProgress.action) From 5b2a18feb68ac2ad10688acbbd581b55fb738c41 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bartos=20Anik=C3=B3?= Date: Mon, 7 Jun 2021 14:38:58 +0200 Subject: [PATCH 4/4] MDCL-3939: readme correction and version increase --- README.md | 6 +++--- pom.xml | 2 +- start.sh | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index d2f6bae..b9c2a3b 100644 --- a/README.md +++ b/README.md @@ -87,7 +87,7 @@ OPSWAT MetaDefender Cloud API key. You can find your key at [metadefender.opswat ***ScanRequestsUpperBound [optional]:*** -Upper bound for scan requests. If the scan requests reached the limit the software does not send a new scan request. If this bound is zero or not given, the script upload files for a scan as long as the _InjectDuration_ lasts or running time does not reach the _Maxduration_. +Gatling will stop submitting new scan requests when this upper bound is reached. If this bound is zero or not given, the script will upload files for scanning as long as the _InjectDuration_ lasts or the running time does not reach the _MaxDuration_. *****ShowPollingDetails:*** @@ -100,7 +100,7 @@ It true, Gatling will print the HTTP responses to the console. By default, it is ## Running a test -The `metadefender-gatling-2.0.0-SNAPSHOT.jar` and `config.ini` files are required to run the test. +The `metadefender-gatling-3.0.0-SNAPSHOT.jar` and `config.ini` files are required to run the test. Maven will install these files in the `target` folder. Run a test using the helper script: @@ -109,5 +109,5 @@ Run a test using the helper script: The script runs the jar file with the following parameters: - java -cp metadefender-gatling-2.0.0-SNAPSHOT.jar io.gatling.app.Gatling -s ScanSimulation + java -cp metadefender-gatling-3.0.0-SNAPSHOT.jar io.gatling.app.Gatling -s ScanSimulation diff --git a/pom.xml b/pom.xml index 4fef450..5514af9 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ com.opswat metadefender-gatling jar - 2.0.0-SNAPSHOT + 3.0.0-SNAPSHOT metadefender-gatling http://maven.apache.org diff --git a/start.sh b/start.sh index 3410155..7b37880 100755 --- a/start.sh +++ b/start.sh @@ -1,4 +1,4 @@ #!/bin/bash cd target -java -cp metadefender-gatling-2.0.0-SNAPSHOT.jar io.gatling.app.Gatling -s ScanSimulation +java -cp metadefender-gatling-3.0.0-SNAPSHOT.jar io.gatling.app.Gatling -s ScanSimulation cd .. \ No newline at end of file