diff --git a/flake.nix b/flake.nix index 773eb61..ffed493 100644 --- a/flake.nix +++ b/flake.nix @@ -29,6 +29,8 @@ podman podman-compose newman + gron + fx ]; shellHook = '' export JAVA_HOME=${pkgs.jdk21} diff --git a/ilp-cw-api/[GET] dronesWithCooling/dronesWithCooling -- false.bru b/ilp-cw-api/[GET] dronesWithCooling/dronesWithCooling -- false.bru index 59b4b1a..a3318af 100644 --- a/ilp-cw-api/[GET] dronesWithCooling/dronesWithCooling -- false.bru +++ b/ilp-cw-api/[GET] dronesWithCooling/dronesWithCooling -- false.bru @@ -19,9 +19,9 @@ tests { expect(res.getBody()).to.be.an('array'); }); - test("Array is not empty and contains numbers", function() { + test("Array is not empty and contains Strings", function() { const data = res.getBody(); - expect(data[0]).to.be.a('number'); // data should be in number + expect(data[0]).to.be.a('string'); // data should be in string }); } diff --git a/ilp-cw-api/[GET] dronesWithCooling/dronesWithCooling -- true.bru b/ilp-cw-api/[GET] dronesWithCooling/dronesWithCooling -- true.bru index 295e3a2..67f496d 100644 --- a/ilp-cw-api/[GET] dronesWithCooling/dronesWithCooling -- true.bru +++ b/ilp-cw-api/[GET] dronesWithCooling/dronesWithCooling -- true.bru @@ -19,9 +19,9 @@ tests { expect(res.getBody()).to.be.an('array'); }); - test("Array is not empty and contains numbers", function() { + test("Array is not empty and contains String", function() { const data = res.getBody(); - expect(data[0]).to.be.a('number'); // data should be in number + expect(data[0]).to.be.a('string'); // data should be in String }); } diff --git a/ilp-cw-api/[GET] dronesWithCooling/invalid 200.bru b/ilp-cw-api/[GET] dronesWithCooling/invalid 200.bru new file mode 100644 index 0000000..cdec646 --- /dev/null +++ b/ilp-cw-api/[GET] dronesWithCooling/invalid 200.bru @@ -0,0 +1,16 @@ +meta { + name: null should return 200 + type: http + seq: 4 +} + +get { + url: {{API_BASE}}/dronesWithCooling/null + body: none + auth: inherit +} + +settings { + encodeUrl: true + timeout: 0 +} diff --git a/ilp-cw-api/[GET] queryAsPath/capacity = 4.bru b/ilp-cw-api/[GET] queryAsPath/capacity = 4.bru new file mode 100644 index 0000000..df9f027 --- /dev/null +++ b/ilp-cw-api/[GET] queryAsPath/capacity = 4.bru @@ -0,0 +1,35 @@ +meta { + name: capacity = 4 + type: http + seq: 3 +} + +get { + url: {{API_BASE}}/queryAsPath/capacity/4 + body: none + auth: inherit +} + +assert { + res.body: length 2 +} + +tests { + test("Status code is 200", function() { + expect(res.status).to.equal(200); + }); + + test("Response body is a JSON array", function() { + expect(res.getBody()).to.be.an('array'); + }); + + test("Array is not empty and contains Strings", function() { + const data = res.getBody(); + expect(data[0]).to.be.a('string'); // data should be in string + }); +} + +settings { + encodeUrl: true + timeout: 0 +} diff --git a/ilp-cw-api/[GET] queryAsPath/capacity = 8.0.bru b/ilp-cw-api/[GET] queryAsPath/capacity = 8.0.bru new file mode 100644 index 0000000..a04a739 --- /dev/null +++ b/ilp-cw-api/[GET] queryAsPath/capacity = 8.0.bru @@ -0,0 +1,35 @@ +meta { + name: capacity = 8.0 + type: http + seq: 2 +} + +get { + url: {{API_BASE}}/queryAsPath/capacity/8.0 + body: none + auth: inherit +} + +assert { + res.body: length 4 +} + +tests { + test("Status code is 200", function() { + expect(res.status).to.equal(200); + }); + + test("Response body is a JSON array", function() { + expect(res.getBody()).to.be.an('array'); + }); + + test("Array is not empty and contains Strings", function() { + const data = res.getBody(); + expect(data[0]).to.be.a('string'); // data should be in string + }); +} + +settings { + encodeUrl: true + timeout: 0 +} diff --git a/ilp-cw-api/[GET] queryAsPath/capacity = 8.bru b/ilp-cw-api/[GET] queryAsPath/capacity = 8.bru new file mode 100644 index 0000000..5e9f4cf --- /dev/null +++ b/ilp-cw-api/[GET] queryAsPath/capacity = 8.bru @@ -0,0 +1,35 @@ +meta { + name: capacity = 8 + type: http + seq: 1 +} + +get { + url: {{API_BASE}}/queryAsPath/capacity/8 + body: none + auth: inherit +} + +assert { + res.body: length 4 +} + +tests { + test("Status code is 200", function() { + expect(res.status).to.equal(200); + }); + + test("Response body is a JSON array", function() { + expect(res.getBody()).to.be.an('array'); + }); + + test("Array is not empty and contains Strings", function() { + const data = res.getBody(); + expect(data[0]).to.be.a('string'); // data should be in string + }); +} + +settings { + encodeUrl: true + timeout: 0 +} diff --git a/ilp-cw-api/[GET] queryAsPath/cooling = false.bru b/ilp-cw-api/[GET] queryAsPath/cooling = false.bru new file mode 100644 index 0000000..f512d6b --- /dev/null +++ b/ilp-cw-api/[GET] queryAsPath/cooling = false.bru @@ -0,0 +1,35 @@ +meta { + name: cooling = false + type: http + seq: 5 +} + +get { + url: {{API_BASE}}/queryAsPath/cooling/false + body: none + auth: inherit +} + +assert { + res.body: length 6 +} + +tests { + test("Status code is 200", function() { + expect(res.status).to.equal(200); + }); + + test("Response body is a JSON array", function() { + expect(res.getBody()).to.be.an('array'); + }); + + test("Array is not empty and contains Strings", function() { + const data = res.getBody(); + expect(data[0]).to.be.a('string'); // data should be in string + }); +} + +settings { + encodeUrl: true + timeout: 0 +} diff --git a/ilp-cw-api/[GET] queryAsPath/folder.bru b/ilp-cw-api/[GET] queryAsPath/folder.bru new file mode 100644 index 0000000..bc3f7a0 --- /dev/null +++ b/ilp-cw-api/[GET] queryAsPath/folder.bru @@ -0,0 +1,8 @@ +meta { + name: [GET] queryAsPath + seq: 3 +} + +auth { + mode: inherit +} diff --git a/ilp-cw-api/[GET] queryAsPath/heating = true.bru b/ilp-cw-api/[GET] queryAsPath/heating = true.bru new file mode 100644 index 0000000..9f0910a --- /dev/null +++ b/ilp-cw-api/[GET] queryAsPath/heating = true.bru @@ -0,0 +1,35 @@ +meta { + name: heating = true + type: http + seq: 4 +} + +get { + url: {{API_BASE}}/queryAsPath/heating/true + body: none + auth: inherit +} + +assert { + res.body: length 7 +} + +tests { + test("Status code is 200", function() { + expect(res.status).to.equal(200); + }); + + test("Response body is a JSON array", function() { + expect(res.getBody()).to.be.an('array'); + }); + + test("Array is not empty and contains Strings", function() { + const data = res.getBody(); + expect(data[0]).to.be.a('string'); // data should be in string + }); +} + +settings { + encodeUrl: true + timeout: 0 +} diff --git a/ilp-cw-api/[GET] queryAsPath/invalid = null.bru b/ilp-cw-api/[GET] queryAsPath/invalid = null.bru new file mode 100644 index 0000000..852f770 --- /dev/null +++ b/ilp-cw-api/[GET] queryAsPath/invalid = null.bru @@ -0,0 +1,27 @@ +meta { + name: invalid = null + type: http + seq: 7 +} + +get { + url: {{API_BASE}}/queryAsPath/invalid/null + body: none + auth: inherit +} + +assert { + res.status: eq 200 +} + +tests { + test("Status code is 200", function() { + expect(res.status).to.equal(200); + }); + +} + +settings { + encodeUrl: true + timeout: 0 +} diff --git a/ilp-cw-api/[GET] queryAsPath/maxMoves = 1000.bru b/ilp-cw-api/[GET] queryAsPath/maxMoves = 1000.bru new file mode 100644 index 0000000..c22d44b --- /dev/null +++ b/ilp-cw-api/[GET] queryAsPath/maxMoves = 1000.bru @@ -0,0 +1,36 @@ +meta { + name: maxMoves = 1000 + type: http + seq: 6 +} + +get { + url: {{API_BASE}}/queryAsPath/maxMoves/1000 + body: none + auth: inherit +} + +assert { + res.body: length 4 + res.status : eq 200 +} + +tests { + test("Status code is 200", function() { + expect(res.status).to.equal(200); + }); + + test("Response body is a JSON array", function() { + expect(res.getBody()).to.be.an('array'); + }); + + test("Array is not empty and contains Strings", function() { + const data = res.getBody(); + expect(data[0]).to.be.a('string'); // data should be in string + }); +} + +settings { + encodeUrl: true + timeout: 0 +} diff --git a/src/main/java/io/github/js0ny/ilp_coursework/controller/DroneController.java b/src/main/java/io/github/js0ny/ilp_coursework/controller/DroneController.java index e056a49..740b337 100644 --- a/src/main/java/io/github/js0ny/ilp_coursework/controller/DroneController.java +++ b/src/main/java/io/github/js0ny/ilp_coursework/controller/DroneController.java @@ -56,7 +56,7 @@ public class DroneController { * * @param id The id of the drone to be queried. * @return 200 with {@link DroneDto}-style json if success, 404 if {@code id} - * not found, 400 otherwise + * not found, 400 otherwise */ @GetMapping("/droneDetails/{id}") public ResponseEntity getDroneDetail(@PathVariable String id) { @@ -68,6 +68,14 @@ public class DroneController { } } + /** + * Handles GET requests to retrieve an array of drone ids that + * {@code capability.attrName = attrVal} + * + * @param attrName The name of the attribute to be queried + * @param attrVal The value of the attribute to be queried + * @return An array of drone id that matches the attribute name and value + */ @GetMapping("/queryAsPath/{attrName}/{attrVal}") public String[] getIdByAttrMap( @PathVariable String attrName, @@ -77,17 +85,17 @@ public class DroneController { @PostMapping("/query") public int[] getIdByAttrMapPost(@RequestBody AttrComparatorDto[] attrComparators) { - return new int[] {}; + return new int[]{}; } @PostMapping("/queryAvailableDrones") public int[] queryAvailableDrones(@RequestBody MedDispathRecDto[] records) { - return new int[] {}; + return new int[]{}; } @PostMapping("/calcDeliveryPath") public DeliveryPathDto calculateDeliveryPath(@RequestBody MedDispathRecDto[] record) { - return new DeliveryPathDto(0.0f, 0, new DronePathDto[] {}); + return new DeliveryPathDto(0.0f, 0, new DronePathDto[]{}); } @PostMapping("/calcDeliveryPathAsGeoJson") diff --git a/src/main/java/io/github/js0ny/ilp_coursework/service/DroneInfoService.java b/src/main/java/io/github/js0ny/ilp_coursework/service/DroneInfoService.java index b7b4a21..66376a2 100644 --- a/src/main/java/io/github/js0ny/ilp_coursework/service/DroneInfoService.java +++ b/src/main/java/io/github/js0ny/ilp_coursework/service/DroneInfoService.java @@ -1,8 +1,10 @@ package io.github.js0ny.ilp_coursework.service; import io.github.js0ny.ilp_coursework.data.DroneDto; + import java.net.URI; import java.util.Arrays; + import org.springframework.stereotype.Service; import org.springframework.web.client.RestTemplate; @@ -96,6 +98,7 @@ public class DroneInfoService { */ public String[] dronesWithAttribute(String attrName, String attrVal) { URI droneUrl = URI.create(baseUrl).resolve(dronesEndpoint); + // This is required to make sure the response is valid DroneDto[] drones = restTemplate.getForObject( droneUrl, DroneDto[].class); @@ -113,6 +116,7 @@ public class DroneInfoService { JsonNode node = mapper.valueToTree(drone); JsonNode attrNode = node.findValue(attrName); if (attrNode != null) { + // Manually handle different types of JsonNode return isValueMatched(attrNode, attrVal); } else { return false; @@ -122,6 +126,14 @@ public class DroneInfoService { .toArray(String[]::new); } + /** + * Helper for dynamic querying, to compare the json value with given value in + * {@code String}. + * + * @param node The {@code JsonNode} to be compared + * @param attrVal The Value passed, in {@code String} + * @return {@code true} if given values are equal, otherwise false. + */ private boolean isValueMatched(JsonNode node, String attrVal) { if (node.isTextual()) { return node.asText().equals(attrVal); @@ -136,5 +148,7 @@ public class DroneInfoService { public int[] dronesMatchesRequirements() { return new int[] {}; - }; + } + + ; }