Skip to content

Commit

Permalink
Merge pull request #6 from OPSWAT/feature/MDCL-3939_fix_scan_number
Browse files Browse the repository at this point in the history
MDCL-3939: maxduration and upperlimit
  • Loading branch information
anikobartos authored Jun 7, 2021
2 parents d8b0728 + 5b2a18f commit 75fc425
Show file tree
Hide file tree
Showing 6 changed files with 89 additions and 66 deletions.
30 changes: 17 additions & 13 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,38 +28,42 @@ 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
ScanRequestsUpperBound=100
```

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
ScanRequestsUpperBound=100
```

***BaseURL:***

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 constant concurrent users 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 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.

***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]:***

Expand All @@ -81,9 +85,9 @@ 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:***
***ScanRequestsUpperBound [optional]:***

Waiting time after file submission to start polling. (milliseconds)
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:***

Expand All @@ -96,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:
Expand All @@ -105,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

2 changes: 1 addition & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
<groupId>com.opswat</groupId>
<artifactId>metadefender-gatling</artifactId>
<packaging>jar</packaging>
<version>2.0.0-SNAPSHOT</version>
<version>3.0.0-SNAPSHOT</version>
<name>metadefender-gatling</name>
<url>http://maven.apache.org</url>

Expand Down
16 changes: 9 additions & 7 deletions src/main/resources/config.ini
Original file line number Diff line number Diff line change
@@ -1,16 +1,18 @@
[general]
BaseUrl=https://api.metadefender.com/v4/file
;constant concurrent users
ConstantUsers=1
;time to run, (s)
TestDuration=10
;injected users per sec
UsersPerSec=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
;upper limit on the amount of files submitted
ScanRequestsUpperBound=100
52 changes: 33 additions & 19 deletions src/main/scala/gatling/Config.scala
Original file line number Diff line number Diff line change
Expand Up @@ -6,34 +6,49 @@ import java.nio.file.{Files, Paths}

class Config {
var baseUrl = ""
var constantUser = 2
var testDuration = 5
var usersPerSec = 2
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 scanRequestsUpper = 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.usersPerSec < 1) {
config.usersPerSec = 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 = {
Expand All @@ -42,17 +57,16 @@ 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.testDuration = ini.get("general", "TestDuration", 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.waitBeforePolling = ini.get("general", "WaitBeforePolling", classOf[Int])
v.pollingDetails = ini.get("general", "ShowPollingDetails", classOf[Boolean])
v.developerMode = ini.get("general", "DeveloperMode", classOf[Boolean])

v.scanRequestsUpper = ini.get("general", "ScanRequestsUpperBound", classOf[Int])
checkValues(v)

v
Expand Down
53 changes: 28 additions & 25 deletions src/main/scala/gatling/ScanSimulation.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -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)
Expand All @@ -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
})
Expand All @@ -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.scanRequestsUpper == 0 || fileUploadCounter.getAndIncrement() < config.scanRequestsUpper)) {
feed(localFiles.feeder)
.exec(FileUpload.submitFile)
.exec(ScanProgress.action)
}

setUp(
pipeline
.inject(constantConcurrentUsers(config.constantUser).during(config.testDuration))
.inject(constantUsersPerSec(config.usersPerSec).during(config.injectDuration))
.protocols(httpProtocol)
)
).maxDuration(config.maxDuration)
}
2 changes: 1 addition & 1 deletion start.sh
Original file line number Diff line number Diff line change
@@ -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 ..

0 comments on commit 75fc425

Please sign in to comment.