Skip to content

Commit 9223fa8

Browse files
authored
Merge branch 'fix/more-types' into feat/remove-dto-deps
2 parents 9fee0ee + b10bbe3 commit 9223fa8

File tree

52 files changed

+2334
-65
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

52 files changed

+2334
-65
lines changed

README.md

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
# EvoMaster: A Tool For Automatically Generating System-Level Test Cases
22

33

4-
![](docs/img/carl-cerstrand-136810_compressed.jpg "Photo by Carl Cerstrand on Unsplash")
4+
[//]: # (![](docs/img/carl-cerstrand-136810_compressed.jpg "Photo by Carl Cerstrand on Unsplash"))
55

66
[![Maven Central](https://img.shields.io/maven-central/v/org.evomaster/evomaster-client-java.svg?label=Maven%20Central)](https://central.sonatype.com/artifact/org.evomaster/evomaster-client-java)
77
[![javadoc](https://javadoc.io/badge2/org.evomaster/evomaster-client-java-controller/javadoc.svg)](https://javadoc.io/doc/org.evomaster/evomaster-client-java-controller)
@@ -12,8 +12,14 @@
1212
[![Github All Releases](https://img.shields.io/github/downloads/WebFuzzing/evomaster/total.svg)](https://github.com/WebFuzzing/EvoMaster/releases)
1313

1414

15+
1516
### Summary
1617

18+
[//]: # (<div style="float: left; margin-right: 15px; margin-bottom: 10px;">)
19+
<img align="left" src="docs/img/em_mascot.png" alt="AI-generated mascot, with Bing" width="100" />
20+
21+
[//]: # (</div>)
22+
1723
_EvoMaster_ ([www.evomaster.org](http://evomaster.org)) is the first (2016) open-source AI-driven tool
1824
that automatically *generates* system-level test cases
1925
for web/enterprise applications.

core-parent/pom.xml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,14 @@
7272
<artifactId>overlay-jvm</artifactId>
7373
<version>0.2.0</version>
7474
</dependency>
75+
76+
77+
<dependency>
78+
<groupId>org.apache.commons</groupId>
79+
<artifactId>commons-csv</artifactId>
80+
<version>1.14.1</version>
81+
</dependency>
82+
7583
</dependencies>
7684
</dependencyManagement>
7785
</project>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,148 @@
1+
package com.foo.rest.examples.spring.openapi.v3.httporacle.failmodification.base
2+
3+
import org.springframework.boot.SpringApplication
4+
import org.springframework.boot.autoconfigure.SpringBootApplication
5+
import org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration
6+
import org.springframework.http.ResponseEntity
7+
import org.springframework.web.bind.annotation.GetMapping
8+
import org.springframework.web.bind.annotation.PatchMapping
9+
import org.springframework.web.bind.annotation.PathVariable
10+
import org.springframework.web.bind.annotation.PostMapping
11+
import org.springframework.web.bind.annotation.PutMapping
12+
import org.springframework.web.bind.annotation.RequestBody
13+
import org.springframework.web.bind.annotation.RequestMapping
14+
import org.springframework.web.bind.annotation.RestController
15+
16+
@SpringBootApplication(exclude = [SecurityAutoConfiguration::class])
17+
@RequestMapping(path = ["/api/resources"])
18+
@RestController
19+
open class FailModificationApplication {
20+
21+
companion object {
22+
@JvmStatic
23+
fun main(args: Array<String>) {
24+
SpringApplication.run(FailModificationApplication::class.java, *args)
25+
}
26+
27+
private val data = mutableMapOf<Int, ResourceData>()
28+
private val dataAlreadyExists = mutableMapOf<Int, ResourceData>()
29+
30+
fun reset(){
31+
data.clear()
32+
dataAlreadyExists.clear()
33+
dataAlreadyExists[0] = ResourceData("existing", 42)
34+
}
35+
}
36+
37+
data class ResourceData(
38+
var name: String,
39+
var value: Int
40+
)
41+
42+
data class UpdateRequest(
43+
val name: String,
44+
val value: Int
45+
)
46+
47+
48+
@PostMapping(path = ["/empty"])
49+
open fun create(@RequestBody body: ResourceData): ResponseEntity<ResourceData> {
50+
val id = data.size + 1
51+
data[id] = body.copy()
52+
return ResponseEntity.status(201).body(data[id])
53+
}
54+
55+
@GetMapping(path = ["/empty/{id}"])
56+
open fun get(@PathVariable("id") id: Int): ResponseEntity<ResourceData> {
57+
val resource = data[id]
58+
?: return ResponseEntity.status(404).build()
59+
return ResponseEntity.status(200).body(resource)
60+
}
61+
62+
@PutMapping(path = ["/empty/{id}"])
63+
open fun put(
64+
@PathVariable("id") id: Int,
65+
@RequestBody body: UpdateRequest
66+
): ResponseEntity<Any> {
67+
68+
val resource = data[id]
69+
?: return ResponseEntity.status(404).build()
70+
71+
// bug: modifies data even though it will return 4xx
72+
if(body.name != null) {
73+
resource.name = body.name
74+
}
75+
if(body.value != null) {
76+
resource.value = body.value
77+
}
78+
79+
// returns 400 Bad Request, but the data was already modified above
80+
return ResponseEntity.status(400).body("Invalid request")
81+
}
82+
83+
@PatchMapping(path = ["/empty/{id}"])
84+
open fun patch(
85+
@PathVariable("id") id: Int,
86+
@RequestBody body: UpdateRequest
87+
): ResponseEntity<Any> {
88+
89+
val resource = data[id]
90+
?: return ResponseEntity.status(404).build()
91+
92+
// correct: validation first, reject without modifying
93+
if(body.name == null && body.value == null) {
94+
return ResponseEntity.status(400).body("No fields to update")
95+
}
96+
97+
// correct: does NOT modify data, just returns 4xx
98+
return ResponseEntity.status(403).body("Forbidden")
99+
}
100+
101+
// pre-populated resource to test that it is not modified by failed PUT
102+
103+
@PostMapping(path = ["/notempty"])
104+
open fun createnotempty(@RequestBody body: ResourceData): ResponseEntity<ResourceData> {
105+
val id = dataAlreadyExists.size + 1
106+
dataAlreadyExists[id] = body.copy()
107+
return ResponseEntity.status(201).body(dataAlreadyExists[id])
108+
}
109+
110+
@GetMapping(path = ["/notempty/{id}"])
111+
open fun getnotempty(@PathVariable("id") id: Int): ResponseEntity<ResourceData> {
112+
val resource = dataAlreadyExists[id]
113+
?: return ResponseEntity.status(404).build()
114+
return ResponseEntity.status(200).body(resource)
115+
}
116+
117+
@PutMapping(path = ["/notempty/{id}"])
118+
open fun putnotempty(
119+
@PathVariable("id") id: Int,
120+
@RequestBody body: UpdateRequest
121+
): ResponseEntity<Any> {
122+
123+
val resource = dataAlreadyExists[id]
124+
?: return ResponseEntity.status(404).build()
125+
126+
resource.name = body.name
127+
resource.value = body.value
128+
129+
// returns 400 Bad Request, but the data was already modified above
130+
return ResponseEntity.status(400).body("Invalid request")
131+
}
132+
133+
@PatchMapping(path = ["/notempty/{id}"])
134+
open fun patchnotempty(
135+
@PathVariable("id") id: Int,
136+
@RequestBody body: UpdateRequest
137+
): ResponseEntity<Any> {
138+
139+
val resource = dataAlreadyExists[id]
140+
?: return ResponseEntity.status(404).build()
141+
142+
// correct: validation first, reject without modifying
143+
return ResponseEntity.status(400).body("No fields to update")
144+
145+
// correct: does NOT modify data, just returns 4xx
146+
return ResponseEntity.status(403).body("Forbidden")
147+
}
148+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
package com.foo.rest.examples.spring.openapi.v3.httporacle.failmodification.forbidden
2+
3+
import org.springframework.boot.SpringApplication
4+
import org.springframework.boot.autoconfigure.SpringBootApplication
5+
import org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration
6+
import org.springframework.http.ResponseEntity
7+
import org.springframework.web.bind.annotation.*
8+
9+
10+
@SpringBootApplication(exclude = [SecurityAutoConfiguration::class])
11+
@RequestMapping("/api/resources")
12+
@RestController
13+
open class FailModificationForbiddenApplication {
14+
15+
companion object {
16+
@JvmStatic
17+
fun main(args: Array<String>) {
18+
SpringApplication.run(FailModificationForbiddenApplication::class.java, *args)
19+
}
20+
21+
val USERS = setOf("FOO", "BAR")
22+
23+
private val data = mutableMapOf<Int, ResourceData>()
24+
25+
fun reset() {
26+
data.clear()
27+
}
28+
}
29+
30+
data class ResourceData(
31+
val name: String,
32+
var value: String
33+
)
34+
35+
data class UpdateRequest(
36+
val value: String
37+
)
38+
39+
private fun isValidUser(auth: String?) = auth != null && USERS.contains(auth)
40+
41+
@PostMapping
42+
open fun create(
43+
@RequestHeader(value = "Authorization", required = false) auth: String?,
44+
@RequestBody body: UpdateRequest
45+
): ResponseEntity<ResourceData> {
46+
if (!isValidUser(auth)) return ResponseEntity.status(401).build()
47+
val id = data.size + 1
48+
data[id] = ResourceData(name = auth!!, value = body.value)
49+
return ResponseEntity.status(201).body(data[id])
50+
}
51+
52+
@GetMapping("/{id}")
53+
open fun get(
54+
@RequestHeader(value = "Authorization", required = false) auth: String?,
55+
@PathVariable("id") id: Int
56+
): ResponseEntity<ResourceData> {
57+
if (!isValidUser(auth)) return ResponseEntity.status(401).build()
58+
val resource = data[id] ?: return ResponseEntity.status(404).build()
59+
return ResponseEntity.status(200).body(resource)
60+
}
61+
62+
@PatchMapping("/{id}")
63+
open fun patch(
64+
@RequestHeader(value = "Authorization", required = false) auth: String?,
65+
@PathVariable("id") id: Int,
66+
@RequestBody body: UpdateRequest
67+
): ResponseEntity<Any> {
68+
if (!isValidUser(auth)) return ResponseEntity.status(401).build()
69+
70+
val resource = data[id] ?: return ResponseEntity.status(404).build()
71+
72+
// BUG: side-effect before ownership check
73+
resource.value = body.value
74+
75+
if (resource.name != auth) return ResponseEntity.status(403).build()
76+
return ResponseEntity.status(200).build()
77+
}
78+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
package com.foo.rest.examples.spring.openapi.v3.httporacle.failmodification.notfound
2+
3+
import org.springframework.boot.SpringApplication
4+
import org.springframework.boot.autoconfigure.SpringBootApplication
5+
import org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration
6+
import org.springframework.http.ResponseEntity
7+
import org.springframework.web.bind.annotation.*
8+
9+
10+
@SpringBootApplication(exclude = [SecurityAutoConfiguration::class])
11+
@RequestMapping("/api/resources")
12+
@RestController
13+
open class FailModificationNotFoundApplication {
14+
15+
companion object {
16+
@JvmStatic
17+
fun main(args: Array<String>) {
18+
SpringApplication.run(FailModificationNotFoundApplication::class.java, *args)
19+
}
20+
21+
private val data = mutableMapOf<Int, ResourceData>()
22+
23+
fun reset() {
24+
data.clear()
25+
}
26+
}
27+
28+
data class ResourceData(val name: String, val value: Int)
29+
30+
data class UpdateRequest(val name: String, val value: Int)
31+
32+
33+
@GetMapping("/{id}")
34+
open fun get(@PathVariable("id") id: Int): ResponseEntity<ResourceData> {
35+
val resource = data[id] ?: return ResponseEntity.status(404).build()
36+
return ResponseEntity.ok(resource)
37+
}
38+
39+
@PutMapping("/{id}")
40+
open fun put(
41+
@PathVariable("id") id: Int,
42+
@RequestBody body: UpdateRequest
43+
): ResponseEntity<Any> {
44+
if (!data.containsKey(id)) {
45+
// BUG: stores the resource before returning 404
46+
data[id] = ResourceData(body.name, body.value)
47+
return ResponseEntity.status(404).build()
48+
}
49+
data[id] = ResourceData(body.name, body.value)
50+
return ResponseEntity.ok().build()
51+
}
52+
}

0 commit comments

Comments
 (0)