Skip to content

Commit ded2a04

Browse files
authored
Merge branch 'master' into ssrf-final-fixes
2 parents 100167a + d6f6278 commit ded2a04

1 file changed

Lines changed: 63 additions & 9 deletions

File tree

  • core/src/main/kotlin/org/evomaster/core/search/service

core/src/main/kotlin/org/evomaster/core/search/service/Statistics.kt

Lines changed: 63 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import org.evomaster.client.java.instrumentation.shared.ObjectiveNaming
66
import org.evomaster.core.EMConfig
77
import org.evomaster.core.output.service.PartialOracles
88
import org.evomaster.core.problem.httpws.HttpWsCallResult
9+
import org.evomaster.core.problem.rest.service.AIResponseClassifier
910
import org.evomaster.core.remote.service.RemoteController
1011
import org.evomaster.core.search.Solution
1112
import org.evomaster.core.utils.IncrementalAverage
@@ -57,6 +58,9 @@ class Statistics : SearchListener {
5758
@Inject
5859
private lateinit var oracles: PartialOracles
5960

61+
@Inject(optional = true)
62+
private lateinit var aiResponseClassifier: AIResponseClassifier
63+
6064
/**
6165
* How often test executions did timeout
6266
*/
@@ -126,25 +130,24 @@ class Statistics : SearchListener {
126130
}
127131
}
128132

129-
val headers = "interval," + snapshots.values.first().map { it.header }.joinToString(",")
133+
// All headers, including AI-related ones
134+
val headers = "interval," + snapshots.values.first().joinToString(",") { it.header }
130135

131136
val path = Paths.get(config.snapshotStatisticsFile).toAbsolutePath()
132-
133137
Files.createDirectories(path.parent)
134138

135-
if (!Files.exists(path) or !config.appendToStatisticsFile) {
139+
if (!Files.exists(path) || !config.appendToStatisticsFile) {
136140
Files.deleteIfExists(path)
137141
Files.createFile(path)
138-
139142
path.toFile().appendText("$headers\n")
140143
}
141144

142145
snapshots.entries.stream()
143-
.sorted { o1, o2 -> o1.key.compareTo(o2.key) }
144-
.forEach {
145-
val elements = it.value.map { it.element }.joinToString(",")
146-
path.toFile().appendText("${it.key},$elements\n")
147-
}
146+
.sorted { o1, o2 -> o1.key.compareTo(o2.key) }
147+
.forEach { (key, pairs) ->
148+
val elements = pairs.joinToString(",") { it.element }
149+
path.toFile().appendText("$key,$elements\n")
150+
}
148151
}
149152

150153

@@ -339,9 +342,60 @@ class Statistics : SearchListener {
339342
}
340343
addConfig(list)
341344

345+
// Adding AI data
346+
list.addAll(getAIData())
347+
342348
return list
343349
}
344350

351+
// For building AI metric pairs
352+
fun aiMetricsAsPairs(
353+
enabled: Boolean,
354+
type: String,
355+
accuracy: Double,
356+
precision: Double,
357+
recall: Double,
358+
f1: Double,
359+
mcc: Double
360+
): List<Pair> = listOf(
361+
Pair("ai_model_enabled", enabled.toString()),
362+
Pair("ai_model_type", type),
363+
Pair("ai_accuracy", "%.4f".format(accuracy)),
364+
Pair("ai_precision400", "%.4f".format(precision)),
365+
Pair("ai_recall400", "%.4f".format(recall)),
366+
Pair("ai_f1Score400", "%.4f".format(f1)),
367+
Pair("ai_mcc400", "%.4f".format(mcc))
368+
)
369+
370+
fun getAIData(): List<Pair> {
371+
// AI model is unable
372+
if (!config.isEnabledAIModelForResponseClassification()) {
373+
return aiMetricsAsPairs(
374+
enabled = false,
375+
type = "NONE",
376+
accuracy = 0.0,
377+
precision = 0.0,
378+
recall = 0.0,
379+
f1 = 0.0,
380+
mcc = 0.0
381+
)
382+
}
383+
384+
// Compute metrics
385+
val metrics = aiResponseClassifier.viewInnerModel().estimateOverallMetrics()
386+
387+
return aiMetricsAsPairs(
388+
enabled = true,
389+
type = config.aiModelForResponseClassification.name,
390+
accuracy = metrics.accuracy,
391+
precision = metrics.precision400,
392+
recall = metrics.recall400,
393+
f1 = metrics.f1Score400,
394+
mcc = metrics.mcc
395+
)
396+
}
397+
398+
345399
private fun distinctActions() : Int {
346400
if(sampler == null){
347401
return 0

0 commit comments

Comments
 (0)