Add functionality to rAPP Catalogue 46/4946/7
authorelinuxhenrik <henrik.b.andersson@est.tech>
Fri, 30 Oct 2020 08:47:55 +0000 (09:47 +0100)
committerelinuxhenrik <henrik.b.andersson@est.tech>
Thu, 5 Nov 2020 12:07:13 +0000 (13:07 +0100)
Change-Id: Ic72a2bf558e2fe2f7bc7d3cfeca35e7386838189
Issue-ID: NONRTRIC-287
Signed-off-by: elinuxhenrik <henrik.b.andersson@est.tech>
r-app-catalogue/api/rac-api.json
r-app-catalogue/api/rac-api.yaml
r-app-catalogue/pom.xml
r-app-catalogue/src/main/java/org/oransc/rappcatalogue/api/GeneralRappCatalogueControllerAdvisor.java [new file with mode: 0644]
r-app-catalogue/src/main/java/org/oransc/rappcatalogue/api/ServicesApiDelegateImpl.java
r-app-catalogue/src/main/java/org/oransc/rappcatalogue/exception/HeaderException.java [new file with mode: 0644]
r-app-catalogue/src/main/java/org/oransc/rappcatalogue/exception/InvalidServiceException.java [new file with mode: 0644]
r-app-catalogue/src/main/java/org/oransc/rappcatalogue/exception/ServiceNotFoundException.java [new file with mode: 0644]
r-app-catalogue/src/test/java/org/oransc/rappcatalogue/api/GeneralRappCatalogueControllerAdvisorTest.java [new file with mode: 0644]
r-app-catalogue/src/test/java/org/oransc/rappcatalogue/api/ServicesApiDelegateImplTest.java

index 3741bdd..64f19d8 100644 (file)
 {
-  "openapi": "3.0.0",
-  "info": {
-    "title": "rAPP Catalogue API",
-    "description": "The Non RT-RIC Service Catalogue provides a way for services to register themselves for other services to discover.",
-    "version": "1.0.0"
-  },
-  "paths": {
-    "/services": {
-      "get": {
-        "summary": "Service names",
-        "deprecated": false,
-        "operationId": "getServiceNamesUsingGET",
-        "responses": {
-          "200": {
-            "description": "Service names",
-            "content": {
-              "application/json": {
-                "schema": {
-                  "type": "array",
-                  "items": {
-                    "type": "string"
-                  }
+    "openapi": "3.0.0",
+    "info": {
+        "title": "rAPP Catalogue API",
+        "description": "The Non RT-RIC Service Catalogue provides a way for services to register themselves for other services to discover.",
+        "version": "1.0.0"
+    },
+    "servers": [
+        {
+            "url": "/"
+        }
+    ],
+    "paths": {
+        "/services": {
+            "get": {
+                "summary": "Services",
+                "deprecated": false,
+                "operationId": "getServices",
+                "responses": {
+                    "200": {
+                        "description": "Services",
+                        "content": {
+                            "application/json": {
+                                "schema": {
+                                    "type": "array",
+                                    "items": {
+                                        "$ref": "#/components/schemas/service"
+                                    }
+                                }
+                            }
+                        }
+                    }
                 },
-                "example": [
-                  "DroneIdentifier",
-                  "Collector"
+                "tags": [
+                    "rAPP Catalogue API"
                 ]
-              }
             }
-          },
-          "401": {
-            "description": "Unauthorized"
-          },
-          "403": {
-            "description": "Forbidden"
-          },
-          "404": {
-            "description": "Not used"
-          }
         },
-        "tags": [
-          "rAPP Catalogue API"
-        ]
-      }
-    },
-    "/services/{serviceName}": {
-      "get": {
-        "summary": "Individual Service",
-        "deprecated": false,
-        "operationId": "getIndividualServiceUsingGET",
-        "responses": {
-          "200": {
-            "description": "EI Job",
-            "content": {
-              "application/json": {
-                "schema": {
-                  "$ref": "#/components/schemas/service"
-                }
-              }
+        "/services/{serviceName}": {
+            "get": {
+                "summary": "Individual Service",
+                "deprecated": false,
+                "operationId": "getIndividualService",
+                "responses": {
+                    "200": {
+                        "description": "Service",
+                        "content": {
+                            "application/json": {
+                                "schema": {
+                                    "$ref": "#/components/schemas/service"
+                                }
+                            }
+                        }
+                    },
+                    "404": {
+                        "description": "Service is not found",
+                        "content": {
+                            "application/json": {
+                                "schema": {
+                                    "$ref": "#/components/schemas/error_information"
+                                }
+                            }
+                        }
+                    }
+                },
+                "parameters": [
+                    {
+                        "in": "path",
+                        "name": "serviceName",
+                        "description": "serviceName",
+                        "schema": {
+                            "type": "string"
+                        },
+                        "required": true,
+                        "example": "DroneIdentifier"
+                    }
+                ],
+                "tags": [
+                    "rAPP Catalogue API"
+                ]
+            },
+            "put": {
+                "summary": "Create or update a Service",
+                "deprecated": false,
+                "operationId": "putIndividualService",
+                "responses": {
+                    "200": {
+                        "description": "Service updated"
+                    },
+                    "201": {
+                        "description": "Service created",
+                        "headers": {
+                            "Location": {
+                                "schema": {
+                                    "type": "string"
+                                },
+                                "description": "URL to the created Service"
+                            }
+                        }
+                    },
+                    "400": {
+                        "description": "Provided service is not correct",
+                        "content": {
+                            "application/json": {
+                                "schema": {
+                                    "$ref": "#/components/schemas/error_information"
+                                },
+                                "example": {
+                                    "detail": "Service is missing required property: version",
+                                    "status": 400
+                                }
+                            }
+                        }
+                    }
+                },
+                "parameters": [
+                    {
+                        "name": "serviceName",
+                        "in": "path",
+                        "required": true,
+                        "schema": {
+                            "type": "string"
+                        },
+                        "example": "DroneIdentifier"
+                    }
+                ],
+                "requestBody": {
+                    "description": "Service to create/update",
+                    "required": true,
+                    "content": {
+                        "application/json": {
+                            "schema": {
+                                "$ref": "#/components/schemas/inputService"
+                            }
+                        }
+                    }
+                },
+                "tags": [
+                    "rAPP Catalogue API"
+                ]
+            },
+            "delete": {
+                "summary": "Remove a Service from the catalogue",
+                "deprecated": false,
+                "operationId": "deleteIndividualService",
+                "responses": {
+                    "204": {
+                        "description": "Service deleted"
+                    }
+                },
+                "parameters": [
+                    {
+                        "name": "serviceName",
+                        "in": "path",
+                        "required": true,
+                        "schema": {
+                            "type": "string"
+                        },
+                        "example": "DroneIdentifier"
+                    }
+                ],
+                "tags": [
+                    "rAPP Catalogue API"
+                ]
             }
-          },
-          "401": {
-            "description": "Unauthorized"
-          },
-          "403": {
-            "description": "Forbidden"
-          },
-          "404": {
-            "description": "Service is not found",
-            "content": {
-              "application/json": {
-                "schema": {
-                  "$ref": "#/components/schemas/error_information"
+        }
+    },
+    "components": {
+        "schemas": {
+            "inputService": {
+                "description": "A Service to register",
+                "type": "object",
+                "title": "inputService",
+                "required": [
+                    "version"
+                ],
+                "properties": {
+                    "version": {
+                        "description": "Version of the Service",
+                        "type": "string",
+                        "example": "1.0.0"
+                    },
+                    "display_name": {
+                        "description": "Display name for the Service",
+                        "type": "string",
+                        "example": "Drone Identifier"
+                    },
+                    "description": {
+                        "description": "Description of the Service",
+                        "type": "string",
+                        "example": "Detects if a UE is a drone"
+                    }
                 }
-              }
-            }
-          }
-        },
-        "parameters": [
-          {
-            "in": "path",
-            "name": "serviceName",
-            "description": "serviceName",
-            "schema": {
-              "type": "string"
             },
-            "required": true,
-            "example": "DroneIdentifier"
-          }
-        ],
-        "tags": [
-          "rAPP Catalogue API"
-        ]
-      },
-      "put": {
-        "summary": "Create or update a Service",
-        "deprecated": false,
-        "operationId": "putIndividualServiceUsingPUT",
-        "responses": {
-          "200": {
-            "description": "Service updated"
-          },
-          "201": {
-            "description": "Service created"
-          },
-          "401": {
-            "description": "Unauthorized"
-          },
-          "403": {
-            "description": "Forbidden"
-          },
-          "404": {
-            "description": "Provided service is not correct",
-            "content": {
-              "application/json": {
-                "schema": {
-                  "$ref": "#/components/schemas/error_information"
-                },
-                "example": {
-                  "detail": "Service is missing required property version",
-                  "status": 404
+            "service": {
+                "description": "A Service",
+                "type": "object",
+                "title": "service",
+                "required": [
+                    "name",
+                    "version",
+                    "registrationDate"
+                ],
+                "properties": {
+                    "name": {
+                        "description": "Unique identifier of the Service",
+                        "type": "string",
+                        "example": "DroneIdentifier"
+                    },
+                    "version": {
+                        "description": "Version of the Service",
+                        "type": "string",
+                        "example": "1.0.0"
+                    },
+                    "display_name": {
+                        "description": "Display name for the Service",
+                        "type": "string",
+                        "example": "Drone Identifier"
+                    },
+                    "description": {
+                        "description": "Description of the Service",
+                        "type": "string",
+                        "example": "Detects if a UE is a drone"
+                    },
+                    "registrationDate": {
+                        "description": "Date when the Service was registered in the catalogue",
+                        "type": "string",
+                        "example": "2020-11-03"
+                    }
                 }
-              }
-            }
-          }
-        },
-        "parameters": [
-          {
-            "name": "serviceName",
-            "in": "path",
-            "required": true,
-            "schema": {
-              "type": "string"
             },
-            "example": "DroneIdentifier"
-          }
-        ],
-        "requestBody": {
-          "description": "Service to create/update",
-          "required": true,
-          "content": {
-            "application/json": {
-              "schema": {
-                "$ref": "#/components/schemas/service"
-              }
-            }
-          }
-        },
-        "tags": [
-          "rAPP Catalogue API"
-        ]
-      },
-      "delete": {
-        "summary": "Remove a Service from the catalogue",
-        "deprecated": false,
-        "operationId": "deleteIndividualServiceUsingDELETE",
-        "responses": {
-          "200": {
-            "description": "Not used"
-          },
-          "204": {
-            "description": "Job deleted"
-          },
-          "401": {
-            "description": "Unauthorized"
-          },
-          "403": {
-            "description": "Forbidden"
-          },
-          "404": {
-            "description": "Service is not found",
-            "content": {
-              "application/json": {
-                "schema": {
-                  "$ref": "#/components/schemas/error_information"
+            "error_information": {
+                "description": "Problem as defined in https://tools.ietf.org/html/rfc7807",
+                "type": "object",
+                "title": "error_information",
+                "properties": {
+                    "detail": {
+                        "description": "A human-readable explanation specific to this occurrence of the problem.",
+                        "type": "string",
+                        "example": "Service not found"
+                    },
+                    "status": {
+                        "format": "int32",
+                        "description": "The HTTP status code for this occurrence of the problem.",
+                        "type": "integer",
+                        "example": 404
+                    }
                 }
-              }
             }
-          }
-        },
-        "parameters": [
-          {
-            "name": "serviceName",
-            "in": "path",
-            "required": true,
-            "schema": {
-              "type": "string"
-            },
-            "example": "DroneIdentifier"
-          }
-        ],
-        "tags": [
-          "rAPP Catalogue API"
-        ]
-      }
-    }
-  },
-  "components": {
-    "schemas": {
-      "service": {
-        "description": "A Service",
-        "type": "object",
-        "title": "service",
-        "required": [
-          "version"
-        ],
-        "properties": {
-          "version": {
-            "description": "Version of the Service",
-            "type": "string",
-            "example": "1.0.0"
-          },
-          "display_name": {
-            "description": "Display name for the Service",
-            "type": "string",
-            "example": "Drone Identifier"
-          },
-          "description": {
-            "description": "Description of the Service",
-            "type": "string",
-            "example": "Detects if a UE is a drone"
-          }
-        }
-      },
-      "error_information": {
-        "description": "Problem as defined in https://tools.ietf.org/html/rfc7807",
-        "type": "object",
-        "title": "error_information",
-        "properties": {
-          "detail": {
-            "description": "A human-readable explanation specific to this occurrence of the problem.",
-            "type": "string",
-            "example": "Service not found"
-          },
-          "status": {
-            "format": "int32",
-            "description": "The HTTP status code generated by the origin server for this occurrence of the problem.",
-            "type": "integer",
-            "example": 404
-          }
         }
-      }
     }
-  }
-}
\ No newline at end of file
+}
index 87e2eb9..748cf2b 100644 (file)
@@ -11,33 +11,24 @@ paths:
     get:
       tags:
       - rAPP Catalogue API
-      summary: Service names
-      operationId: getServiceNamesUsingGET
+      summary: Services
+      operationId: getServices
       responses:
         200:
-          description: Service names
+          description: Services
           content:
             application/json:
               schema:
                 type: array
                 items:
-                  type: string
-              example:
-              - DroneIdentifier
-              - Collector
-        401:
-          description: Unauthorized
-        403:
-          description: Forbidden
-        404:
-          description: Not used
+                  $ref: '#/components/schemas/service'
       deprecated: false
   /services/{serviceName}:
     get:
       tags:
       - rAPP Catalogue API
       summary: Individual Service
-      operationId: getIndividualServiceUsingGET
+      operationId: getIndividualService
       parameters:
       - name: serviceName
         in: path
@@ -50,15 +41,11 @@ paths:
         example: DroneIdentifier
       responses:
         200:
-          description: EI Job
+          description: Service
           content:
             application/json:
               schema:
                 $ref: '#/components/schemas/service'
-        401:
-          description: Unauthorized
-        403:
-          description: Forbidden
         404:
           description: Service is not found
           content:
@@ -70,7 +57,7 @@ paths:
       tags:
       - rAPP Catalogue API
       summary: Create or update a Service
-      operationId: putIndividualServiceUsingPUT
+      operationId: putIndividualService
       parameters:
       - name: serviceName
         in: path
@@ -85,32 +72,35 @@ paths:
         content:
           application/json:
             schema:
-              $ref: '#/components/schemas/service'
+              $ref: '#/components/schemas/inputService'
         required: true
       responses:
         200:
           description: Service updated
         201:
           description: Service created
-        401:
-          description: Unauthorized
-        403:
-          description: Forbidden
-        404:
+          headers:
+            Location:
+              description: URL to the created Service
+              style: simple
+              explode: false
+              schema:
+                type: string
+        400:
           description: Provided service is not correct
           content:
             application/json:
               schema:
                 $ref: '#/components/schemas/error_information'
               example:
-                detail: Service is missing required property version
-                status: 404
+                detail: 'Service is missing required property: version'
+                status: 400
       deprecated: false
     delete:
       tags:
       - rAPP Catalogue API
       summary: Remove a Service from the catalogue
-      operationId: deleteIndividualServiceUsingDELETE
+      operationId: deleteIndividualService
       parameters:
       - name: serviceName
         in: path
@@ -121,29 +111,42 @@ paths:
           type: string
         example: DroneIdentifier
       responses:
-        200:
-          description: Not used
         204:
-          description: Job deleted
-        401:
-          description: Unauthorized
-        403:
-          description: Forbidden
-        404:
-          description: Service is not found
-          content:
-            application/json:
-              schema:
-                $ref: '#/components/schemas/error_information'
+          description: Service deleted
       deprecated: false
 components:
   schemas:
+    inputService:
+      title: inputService
+      required:
+      - version
+      type: object
+      properties:
+        version:
+          type: string
+          description: Version of the Service
+          example: 1.0.0
+        display_name:
+          type: string
+          description: Display name for the Service
+          example: Drone Identifier
+        description:
+          type: string
+          description: Description of the Service
+          example: Detects if a UE is a drone
+      description: A Service to register
     service:
       title: service
       required:
+      - name
+      - registrationDate
       - version
       type: object
       properties:
+        name:
+          type: string
+          description: Unique identifier of the Service
+          example: DroneIdentifier
         version:
           type: string
           description: Version of the Service
@@ -156,6 +159,10 @@ components:
           type: string
           description: Description of the Service
           example: Detects if a UE is a drone
+        registrationDate:
+          type: string
+          description: Date when the Service was registered in the catalogue
+          example: 2020-11-03
       description: A Service
     error_information:
       title: error_information
@@ -168,8 +175,7 @@ components:
           example: Service not found
         status:
           type: integer
-          description: The HTTP status code generated by the origin server for this
-            occurrence of the problem.
+          description: The HTTP status code for this occurrence of the problem.
           format: int32
           example: 404
       description: Problem as defined in https://tools.ietf.org/html/rfc7807
index 3ac8562..ea36b58 100644 (file)
             <artifactId>junit-jupiter-api</artifactId>\r
             <scope>test</scope>\r
         </dependency>\r
+        <dependency>\r
+            <groupId>org.mockito</groupId>\r
+            <artifactId>mockito-junit-jupiter</artifactId>\r
+            <scope>test</scope>\r
+        </dependency>\r
+        <dependency>\r
+            <groupId>org.mockito</groupId>\r
+            <artifactId>mockito-core</artifactId>\r
+            <scope>test</scope>\r
+        </dependency>\r
+        <dependency>\r
+            <groupId>org.junit.jupiter</groupId>\r
+            <artifactId>junit-jupiter-engine</artifactId>\r
+            <scope>test</scope>\r
+        </dependency>\r
     </dependencies>\r
 \r
     <build>\r
diff --git a/r-app-catalogue/src/main/java/org/oransc/rappcatalogue/api/GeneralRappCatalogueControllerAdvisor.java b/r-app-catalogue/src/main/java/org/oransc/rappcatalogue/api/GeneralRappCatalogueControllerAdvisor.java
new file mode 100644 (file)
index 0000000..939f7bf
--- /dev/null
@@ -0,0 +1,64 @@
+/*-
+ * ========================LICENSE_START=================================
+ * Copyright (C) 2020 Nordix Foundation. All rights reserved.
+ * ======================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ========================LICENSE_END===================================
+ */
+
+package org.oransc.rappcatalogue.api;
+
+import static org.springframework.http.HttpStatus.BAD_REQUEST;
+import static org.springframework.http.HttpStatus.INTERNAL_SERVER_ERROR;
+import static org.springframework.http.HttpStatus.NOT_FOUND;
+
+import org.oransc.rappcatalogue.exception.HeaderException;
+import org.oransc.rappcatalogue.exception.InvalidServiceException;
+import org.oransc.rappcatalogue.exception.ServiceNotFoundException;
+import org.oransc.rappcatalogue.model.ErrorInformation;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.bind.annotation.ControllerAdvice;
+import org.springframework.web.bind.annotation.ExceptionHandler;
+import org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExceptionHandler;
+
+@ControllerAdvice
+public class GeneralRappCatalogueControllerAdvisor extends ResponseEntityExceptionHandler {
+    @ExceptionHandler(InvalidServiceException.class)
+    public ResponseEntity<Object> handleInvalidServiceException(
+        InvalidServiceException ex) {
+
+        return new ResponseEntity<>(getErrorInformation(ex, BAD_REQUEST), BAD_REQUEST);
+    }
+
+    @ExceptionHandler(ServiceNotFoundException.class)
+    public ResponseEntity<Object> handleServiceNotFoundException(
+        ServiceNotFoundException ex) {
+
+        return new ResponseEntity<>(getErrorInformation(ex, NOT_FOUND), NOT_FOUND);
+    }
+
+    @ExceptionHandler(HeaderException.class)
+    public ResponseEntity<Object> handleHeaderException(
+        HeaderException ex) {
+
+        return new ResponseEntity<>(getErrorInformation(ex, INTERNAL_SERVER_ERROR), INTERNAL_SERVER_ERROR);
+    }
+
+    private ErrorInformation getErrorInformation(Exception cause, HttpStatus status) {
+        ErrorInformation errorInfo = new ErrorInformation();
+        errorInfo.setDetail(cause.getMessage());
+        errorInfo.setStatus(status.value());
+        return errorInfo;
+    }
+}
index 701f1d8..8c9469a 100644 (file)
+/*-\r
+ * ========================LICENSE_START=================================\r
+ * Copyright (C) 2020 Nordix Foundation. All rights reserved.\r
+ * ======================================================================\r
+ * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * you may not use this file except in compliance with the License.\r
+ * You may obtain a copy of the License at\r
+ *\r
+ *      http://www.apache.org/licenses/LICENSE-2.0\r
+ *\r
+ * Unless required by applicable law or agreed to in writing, software\r
+ * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * See the License for the specific language governing permissions and\r
+ * limitations under the License.\r
+ * ========================LICENSE_END===================================\r
+ */\r
+\r
 package org.oransc.rappcatalogue.api;\r
 \r
-import java.util.Arrays;\r
+import java.io.IOException;\r
+import java.sql.Date;\r
+import java.util.ArrayList;\r
 import java.util.List;\r
-\r
+import java.util.Optional;\r
+import java.util.concurrent.ConcurrentHashMap;\r
+import javax.servlet.http.HttpServletRequest;\r
+import javax.servlet.http.HttpServletResponse;\r
+import org.oransc.rappcatalogue.exception.HeaderException;\r
+import org.oransc.rappcatalogue.exception.InvalidServiceException;\r
+import org.oransc.rappcatalogue.exception.ServiceNotFoundException;\r
+import org.oransc.rappcatalogue.model.InputService;\r
+import org.oransc.rappcatalogue.model.Service;\r
+import org.springframework.beans.factory.annotation.Autowired;\r
 import org.springframework.http.HttpStatus;\r
 import org.springframework.http.ResponseEntity;\r
+import org.springframework.web.context.request.NativeWebRequest;\r
 \r
 @org.springframework.stereotype.Service\r
 public class ServicesApiDelegateImpl implements ServicesApiDelegate {\r
 \r
+    private static final String LOCATION_HEADER = "Location";\r
+\r
+    @Autowired\r
+    private NativeWebRequest nativeWebRequest;\r
+\r
+    private ConcurrentHashMap<String, Service> registeredServices = new ConcurrentHashMap<>();\r
+\r
+    ServicesApiDelegateImpl(NativeWebRequest nativeWebRequest) {\r
+        this.nativeWebRequest = nativeWebRequest;\r
+    }\r
+\r
+    @Override\r
+    public Optional<NativeWebRequest> getRequest() {\r
+        return Optional.of(nativeWebRequest);\r
+    }\r
+\r
     @Override\r
-    public ResponseEntity<Void> deleteIndividualServiceUsingDELETE(String serviceName) {\r
-        return new ResponseEntity<>(HttpStatus.NOT_IMPLEMENTED);\r
+    public ResponseEntity<Service> getIndividualService(String serviceName) {\r
+        Service service = registeredServices.get(serviceName);\r
+        if (service != null) {\r
+            return ResponseEntity.ok(service);\r
+        } else {\r
+            throw new ServiceNotFoundException(serviceName);\r
+        }\r
     }\r
 \r
-    // @Override\r
-    // public ResponseEntity<Service> getIndividualServiceUsingGET(String serviceName) {\r
-    //     return new ResponseEntity<>(HttpStatus.NOT_IMPLEMENTED);\r
+    @Override\r
+    public ResponseEntity<List<Service>> getServices() {\r
+        return ResponseEntity.ok(new ArrayList<>(registeredServices.values()));\r
+    }\r
+\r
+    @Override\r
+    public ResponseEntity<Void> putIndividualService(String serviceName, InputService inputService) {\r
+        if (isServiceValid(inputService)) {\r
+            if (registeredServices.put(serviceName, createService(serviceName, inputService)) == null) {\r
+                try {\r
+                    getRequest().ifPresent(request -> addLocationHeaderToResponse(serviceName, request));\r
+                } catch (Exception e) {\r
+                    registeredServices.remove(serviceName);\r
+                    throw e;\r
+                }\r
+                return new ResponseEntity<>(HttpStatus.CREATED);\r
+            } else {\r
+                return new ResponseEntity<>(HttpStatus.OK);\r
+            }\r
+        } else {\r
+            throw new InvalidServiceException();\r
+        }\r
+    }\r
 \r
-    // }\r
+    private void addLocationHeaderToResponse(String serviceName, NativeWebRequest request) {\r
+        try {\r
+            HttpServletRequest nativeRequest = request.getNativeRequest(HttpServletRequest.class);\r
+            HttpServletResponse nativeResponse = request.getNativeResponse(HttpServletResponse.class);\r
+            if (nativeRequest != null && nativeResponse != null) {\r
+                StringBuffer requestURL = nativeRequest.getRequestURL();\r
+                nativeResponse.addHeader(LOCATION_HEADER, requestURL.toString());\r
+                nativeResponse.getWriter().print("");\r
+            } else {\r
+                throw new HeaderException(LOCATION_HEADER, new Exception("Native Request or Response missing"));\r
+            }\r
+        } catch (IOException e) {\r
+            throw new HeaderException(LOCATION_HEADER, e);\r
+        }\r
+    }\r
 \r
     @Override\r
-    public ResponseEntity<List<String>> getServiceNamesUsingGET() {\r
-        List<String> services = Arrays.asList("a", "b");\r
-        return ResponseEntity.ok(services);\r
+    public ResponseEntity<Void> deleteIndividualService(String serviceName) {\r
+        registeredServices.remove(serviceName);\r
+        return new ResponseEntity<>(HttpStatus.NO_CONTENT);\r
     }\r
 \r
-    // @Override\r
-    // public ResponseEntity<Void> putIndividualServiceUsingPUT(String serviceName, Service service) {\r
-    //     return new ResponseEntity<>(HttpStatus.NOT_IMPLEMENTED);\r
+    /*\r
+     * java:S2589: Boolean expressions should not be gratuitous.\r
+     * Even though the version property is marked as @NotNull, it might be null coming from the client, hence the null\r
+     * check is needed.\r
+     */\r
+    @SuppressWarnings("java:S2589")\r
+    private boolean isServiceValid(InputService service) {\r
+        String version = service.getVersion();\r
+        return version != null && !version.isBlank();\r
+    }\r
 \r
-    // }\r
+    private Service createService(String serviceName, InputService inputService) {\r
+        Service service = new Service();\r
+        service.setName(serviceName);\r
+        service.setDescription(inputService.getDescription());\r
+        service.setDisplayName(inputService.getDisplayName());\r
+        service.setVersion(inputService.getVersion());\r
+        service.setRegistrationDate(getTodaysDate());\r
+        return service;\r
+    }\r
+\r
+    private String getTodaysDate() {\r
+        long millis = System.currentTimeMillis();\r
+        Date date = new Date(millis);\r
+        return date.toString();\r
+    }\r
 }\r
diff --git a/r-app-catalogue/src/main/java/org/oransc/rappcatalogue/exception/HeaderException.java b/r-app-catalogue/src/main/java/org/oransc/rappcatalogue/exception/HeaderException.java
new file mode 100644 (file)
index 0000000..90568de
--- /dev/null
@@ -0,0 +1,29 @@
+/*-
+ * ========================LICENSE_START=================================
+ * Copyright (C) 2020 Nordix Foundation. All rights reserved.
+ * ======================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ========================LICENSE_END===================================
+ */
+
+package org.oransc.rappcatalogue.exception;
+
+public class HeaderException extends RuntimeException {
+
+    private static final long serialVersionUID = -7798178963078284655L;
+
+    public HeaderException(String header, Exception cause) {
+        super(String.format("Unable to set header %s in response. Cause: %s", header, cause.getMessage()));
+    }
+
+}
diff --git a/r-app-catalogue/src/main/java/org/oransc/rappcatalogue/exception/InvalidServiceException.java b/r-app-catalogue/src/main/java/org/oransc/rappcatalogue/exception/InvalidServiceException.java
new file mode 100644 (file)
index 0000000..dce815b
--- /dev/null
@@ -0,0 +1,27 @@
+/*-
+ * ========================LICENSE_START=================================
+ * Copyright (C) 2020 Nordix Foundation. All rights reserved.
+ * ======================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ========================LICENSE_END===================================
+ */
+
+package org.oransc.rappcatalogue.exception;
+
+public class InvalidServiceException extends RuntimeException {
+    private static final long serialVersionUID = 3849219105170316564L;
+
+    public InvalidServiceException() {
+        super("Service is missing required property: version");
+    }
+}
diff --git a/r-app-catalogue/src/main/java/org/oransc/rappcatalogue/exception/ServiceNotFoundException.java b/r-app-catalogue/src/main/java/org/oransc/rappcatalogue/exception/ServiceNotFoundException.java
new file mode 100644 (file)
index 0000000..26b4b27
--- /dev/null
@@ -0,0 +1,27 @@
+/*-
+ * ========================LICENSE_START=================================
+ * Copyright (C) 2020 Nordix Foundation. All rights reserved.
+ * ======================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ========================LICENSE_END===================================
+ */
+
+package org.oransc.rappcatalogue.exception;
+
+public class ServiceNotFoundException extends RuntimeException {
+    private static final long serialVersionUID = 6579271315716003988L;
+
+    public ServiceNotFoundException(String serviceName) {
+        super(String.format("Service %s not found", serviceName));
+    }
+}
diff --git a/r-app-catalogue/src/test/java/org/oransc/rappcatalogue/api/GeneralRappCatalogueControllerAdvisorTest.java b/r-app-catalogue/src/test/java/org/oransc/rappcatalogue/api/GeneralRappCatalogueControllerAdvisorTest.java
new file mode 100644 (file)
index 0000000..1c4d414
--- /dev/null
@@ -0,0 +1,76 @@
+/*-
+ * ========================LICENSE_START=================================
+ * Copyright (C) 2020 Nordix Foundation. All rights reserved.
+ * ======================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ========================LICENSE_END===================================
+ */
+
+package org.oransc.rappcatalogue.api;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.springframework.http.HttpStatus.BAD_REQUEST;
+import static org.springframework.http.HttpStatus.INTERNAL_SERVER_ERROR;
+import static org.springframework.http.HttpStatus.NOT_FOUND;
+
+import org.junit.jupiter.api.Test;
+import org.oransc.rappcatalogue.exception.HeaderException;
+import org.oransc.rappcatalogue.exception.InvalidServiceException;
+import org.oransc.rappcatalogue.exception.ServiceNotFoundException;
+import org.oransc.rappcatalogue.model.ErrorInformation;
+import org.springframework.http.ResponseEntity;
+
+class GeneralRappCatalogueControllerAdvisorTest {
+
+    @Test
+    void handleInvalidServiceException_shouldReturnBadRequestWithMessage() {
+        GeneralRappCatalogueControllerAdvisor advisorUnderTest = new GeneralRappCatalogueControllerAdvisor();
+
+        InvalidServiceException exception = new InvalidServiceException();
+
+        ResponseEntity<Object> response = advisorUnderTest.handleInvalidServiceException(exception);
+
+        assertThat(response.getStatusCode()).isEqualTo(BAD_REQUEST);
+        ErrorInformation body = (ErrorInformation) response.getBody();
+        assertThat(body.getStatus()).isEqualTo(BAD_REQUEST.value());
+        assertThat(body.getDetail()).isEqualTo("Service is missing required property: version");
+    }
+
+    @Test
+    void handleServiceNotFoundException_shouldReturnNotFoundWithMessage() {
+        GeneralRappCatalogueControllerAdvisor advisorUnderTest = new GeneralRappCatalogueControllerAdvisor();
+
+        ServiceNotFoundException exception = new ServiceNotFoundException("Name");
+
+        ResponseEntity<Object> response = advisorUnderTest.handleServiceNotFoundException(exception);
+
+        assertThat(response.getStatusCode()).isEqualTo(NOT_FOUND);
+        ErrorInformation body = (ErrorInformation) response.getBody();
+        assertThat(body.getStatus()).isEqualTo(NOT_FOUND.value());
+        assertThat(body.getDetail()).isEqualTo("Service Name not found");
+    }
+
+    @Test
+    void handleHeaderException_shouldReturnInternalServerErrorWithMessage() {
+        GeneralRappCatalogueControllerAdvisor advisorUnderTest = new GeneralRappCatalogueControllerAdvisor();
+
+        HeaderException exception = new HeaderException("Header", new Exception("Cause"));
+
+        ResponseEntity<Object> response = advisorUnderTest.handleHeaderException(exception);
+
+        assertThat(response.getStatusCode()).isEqualTo(INTERNAL_SERVER_ERROR);
+        ErrorInformation body = (ErrorInformation) response.getBody();
+        assertThat(body.getStatus()).isEqualTo(INTERNAL_SERVER_ERROR.value());
+        assertThat(body.getDetail()).isEqualTo("Unable to set header Header in response. Cause: Cause");
+    }
+}
index 53dfc1a..c19e1de 100644 (file)
 package org.oransc.rappcatalogue.api;\r
 \r
 import static org.assertj.core.api.Assertions.assertThat;\r
+import static org.junit.jupiter.api.Assertions.assertThrows;\r
+import static org.mockito.Mockito.mock;\r
+import static org.mockito.Mockito.verify;\r
+import static org.mockito.Mockito.when;\r
+import static org.springframework.http.HttpStatus.CREATED;\r
+import static org.springframework.http.HttpStatus.NO_CONTENT;\r
+import static org.springframework.http.HttpStatus.OK;\r
 \r
+import java.io.IOException;\r
+import java.io.PrintWriter;\r
+import java.sql.Date;\r
 import java.util.Arrays;\r
 import java.util.List;\r
-\r
+import javax.servlet.http.HttpServletRequest;\r
+import javax.servlet.http.HttpServletResponse;\r
 import org.junit.jupiter.api.Test;\r
 import org.junit.jupiter.api.extension.ExtendWith;\r
-import org.springframework.http.HttpStatus;\r
+import org.mockito.Mock;\r
+import org.mockito.junit.jupiter.MockitoExtension;\r
+import org.oransc.rappcatalogue.exception.HeaderException;\r
+import org.oransc.rappcatalogue.exception.InvalidServiceException;\r
+import org.oransc.rappcatalogue.exception.ServiceNotFoundException;\r
+import org.oransc.rappcatalogue.model.InputService;\r
+import org.oransc.rappcatalogue.model.Service;\r
 import org.springframework.http.ResponseEntity;\r
-import org.springframework.test.context.junit.jupiter.SpringExtension;\r
+import org.springframework.web.context.request.NativeWebRequest;\r
 \r
-@ExtendWith(SpringExtension.class)\r
+@ExtendWith(MockitoExtension.class)\r
 class ServicesApiDelegateImplTest {\r
 \r
+    @Mock\r
+    NativeWebRequest webRequestMock;\r
+\r
+    private static final String INVALID_SERVICE_MESSAGE = "Service is missing required property: version";\r
+    private static final String SERVICE_NAME = "Service Name";\r
+    private static final String SERVICE_DESCRIPTION = "description";\r
+    private static final String SERVICE_VERSION = "1.0";\r
+    private static final String SERVICE_DISPLAY_NAME = "Display Name";\r
+\r
+    @Test\r
+    void getAddedService_shouldReturnService() {\r
+        ServicesApiDelegateImpl delegateUnderTest = new ServicesApiDelegateImpl(webRequestMock);\r
+\r
+        InputService service = new InputService();\r
+        service.setDescription(SERVICE_DESCRIPTION);\r
+        service.setVersion(SERVICE_VERSION);\r
+        service.setDisplayName(SERVICE_DISPLAY_NAME);\r
+\r
+        whenPrintResponseShouldWork();\r
+\r
+        delegateUnderTest.putIndividualService(SERVICE_NAME, service);\r
+\r
+        ResponseEntity<Service> response = delegateUnderTest.getIndividualService(SERVICE_NAME);\r
+\r
+        assertThat(response.getStatusCode()).isEqualTo(OK);\r
+        assertThat(response.getBody().getName()).isEqualTo(SERVICE_NAME);\r
+    }\r
+\r
+    @Test\r
+    void getMissingService_shouldThrowException() {\r
+        ServicesApiDelegateImpl delegateUnderTest = new ServicesApiDelegateImpl(null);\r
+\r
+        Exception exception = assertThrows(ServiceNotFoundException.class, () -> {\r
+            delegateUnderTest.getIndividualService(SERVICE_NAME);\r
+        });\r
+\r
+        String expectedMessage = "Service " + SERVICE_NAME + " not found";\r
+        String actualMessage = exception.getMessage();\r
+\r
+        assertThat(actualMessage).isEqualTo(expectedMessage);\r
+    }\r
+\r
+    @Test\r
+    void putNewValidService_shouldBeCreatedAndRegisteredAndUrlToNewServiceAddedToLocationHeaderInResponse() {\r
+        ServicesApiDelegateImpl delegateUnderTest = new ServicesApiDelegateImpl(webRequestMock);\r
+\r
+        InputService service = new InputService();\r
+        service.setDescription(SERVICE_DESCRIPTION);\r
+        service.setVersion(SERVICE_VERSION);\r
+        service.setDisplayName(SERVICE_DISPLAY_NAME);\r
+\r
+        String urlToCreatedService = "URL to created Service";\r
+        HttpServletResponse servletResponseMock = whenPrintResponseShouldWork(urlToCreatedService);\r
+\r
+        ResponseEntity<Void> putResponse = delegateUnderTest.putIndividualService(SERVICE_NAME, service);\r
+\r
+        assertThat(putResponse.getStatusCode()).isEqualTo(CREATED);\r
+        verify(servletResponseMock).addHeader("Location", urlToCreatedService);\r
+\r
+        ResponseEntity<Service> getResponse = delegateUnderTest.getIndividualService(SERVICE_NAME);\r
+\r
+        assertThat(getResponse.getStatusCode()).isEqualTo(OK);\r
+        Service body = getResponse.getBody();\r
+        assertThat(body.getName()).isEqualTo(SERVICE_NAME);\r
+        assertThat(body.getRegistrationDate()).isEqualTo(getTodaysDate());\r
+    }\r
+\r
+    @Test\r
+    void putModifiedService_shouldBeModified() {\r
+        ServicesApiDelegateImpl delegateUnderTest = new ServicesApiDelegateImpl(webRequestMock);\r
+\r
+        InputService service = new InputService();\r
+        service.setDescription(SERVICE_DESCRIPTION);\r
+        service.setVersion(SERVICE_VERSION);\r
+        service.setDisplayName(SERVICE_DISPLAY_NAME);\r
+\r
+        whenPrintResponseShouldWork();\r
+\r
+        delegateUnderTest.putIndividualService(SERVICE_NAME, service);\r
+\r
+        String newDescription = "New description";\r
+        service.setDescription(newDescription);\r
+        ResponseEntity<Void> putResponse = delegateUnderTest.putIndividualService(SERVICE_NAME, service);\r
+\r
+        assertThat(putResponse.getStatusCode()).isEqualTo(OK);\r
+\r
+        ResponseEntity<Service> getResponse = delegateUnderTest.getIndividualService(SERVICE_NAME);\r
+\r
+        assertThat(getResponse.getStatusCode()).isEqualTo(OK);\r
+        assertThat(getResponse.getBody().getDescription()).isEqualTo(newDescription);\r
+    }\r
+\r
+    @Test\r
+    void putServiceWithVersionNull_shouldThrowException() {\r
+        ServicesApiDelegateImpl delegateUnderTest = new ServicesApiDelegateImpl(null);\r
+\r
+        InputService service = new InputService();\r
+        service.setDescription(SERVICE_DESCRIPTION);\r
+        service.setDisplayName(SERVICE_DISPLAY_NAME);\r
+\r
+        Exception exception = assertThrows(InvalidServiceException.class, () -> {\r
+            delegateUnderTest.putIndividualService(SERVICE_NAME, service);\r
+        });\r
+\r
+        assertThat(exception.getMessage()).isEqualTo(INVALID_SERVICE_MESSAGE);\r
+    }\r
+\r
+    @Test\r
+    void putServiceWithBlankVersion_shouldThrowException() {\r
+        ServicesApiDelegateImpl delegateUnderTest = new ServicesApiDelegateImpl(null);\r
+\r
+        InputService service = new InputService();\r
+        service.setVersion("");\r
+        service.setDescription(SERVICE_DESCRIPTION);\r
+        service.setDisplayName(SERVICE_DISPLAY_NAME);\r
+\r
+        Exception exception = assertThrows(InvalidServiceException.class, () -> {\r
+            delegateUnderTest.putIndividualService(SERVICE_NAME, service);\r
+        });\r
+\r
+        assertThat(exception.getMessage()).isEqualTo(INVALID_SERVICE_MESSAGE);\r
+    }\r
+\r
     @Test\r
-    void putValidService_shouldBeOk() {\r
-        ServicesApiDelegateImpl delegateUnderTest = new ServicesApiDelegateImpl();\r
+    void putServiceWhenIoException_shouldThrowExceptionAndNoServiceCreated() throws Exception {\r
+        ServicesApiDelegateImpl delegateUnderTest = new ServicesApiDelegateImpl(webRequestMock);\r
+\r
+        whenGetRequestUrlThenReturnUrl();\r
+        HttpServletResponse servletResponseMock = mock(HttpServletResponse.class);\r
+        when(webRequestMock.getNativeResponse(HttpServletResponse.class)).thenReturn(servletResponseMock);\r
+        when(servletResponseMock.getWriter()).thenThrow(new IOException("Error"));\r
 \r
-        ResponseEntity<List<String>> response = delegateUnderTest.getServiceNamesUsingGET();\r
+        InputService service = new InputService();\r
+        service.setVersion("1.0");\r
+        service.setDescription(SERVICE_DESCRIPTION);\r
+        service.setDisplayName(SERVICE_DISPLAY_NAME);\r
+\r
+        Exception exception = assertThrows(HeaderException.class, () -> {\r
+            delegateUnderTest.putIndividualService(SERVICE_NAME, service);\r
+        });\r
+\r
+        assertThat(exception.getMessage()).isEqualTo("Unable to set header Location in response. Cause: Error");\r
+\r
+        ResponseEntity<List<Service>> response = delegateUnderTest.getServices();\r
+        assertThat(response.getBody()).isEmpty();\r
     }\r
 \r
     @Test\r
-    void getServices_shouldProvideArrayOfServices() throws Exception {\r
-        ServicesApiDelegateImpl delegateUnderTest = new ServicesApiDelegateImpl();\r
+    void getServices_shouldProvideArrayOfAddedServiceNames() throws Exception {\r
+        ServicesApiDelegateImpl delegateUnderTest = new ServicesApiDelegateImpl(webRequestMock);\r
+\r
+        InputService service1 = new InputService();\r
+        service1.setDescription("description 1");\r
+        service1.setVersion(SERVICE_VERSION);\r
+        service1.setDisplayName("Display Name 1");\r
+\r
+        InputService service2 = new InputService();\r
+        service2.setDescription("description 2");\r
+        service2.setVersion(SERVICE_VERSION);\r
+        service2.setDisplayName("Display Name 2");\r
+\r
+        whenPrintResponseShouldWork();\r
+\r
+        String serviceName1 = "Service Name 1";\r
+        delegateUnderTest.putIndividualService(serviceName1, service1);\r
+        String serviceName2 = "Service Name 2";\r
+        delegateUnderTest.putIndividualService(serviceName2, service2);\r
+\r
+        ResponseEntity<List<Service>> response = delegateUnderTest.getServices();\r
+\r
+        assertThat(response.getStatusCode()).isEqualTo(OK);\r
+        List<Service> services = response.getBody();\r
+        assertThat(services).hasSize(2);\r
+        List<String> expectedServiceNames = Arrays.asList(serviceName1, serviceName2);\r
+        assertThat(expectedServiceNames).contains(services.get(0).getName()) //\r
+                                        .contains(services.get(1).getName());\r
+    }\r
 \r
-        ResponseEntity<List<String>> response = delegateUnderTest.getServiceNamesUsingGET();\r
+    @Test\r
+    void deleteService_shouldBeOk() {\r
+        ServicesApiDelegateImpl delegateUnderTest = new ServicesApiDelegateImpl(webRequestMock);\r
+\r
+        InputService service = new InputService();\r
+        service.setDescription(SERVICE_DESCRIPTION);\r
+        service.setVersion(SERVICE_VERSION);\r
+        service.setDisplayName(SERVICE_DISPLAY_NAME);\r
+\r
+        whenPrintResponseShouldWork();\r
+\r
+        delegateUnderTest.putIndividualService(SERVICE_NAME, service);\r
+\r
+        ResponseEntity<List<Service>> servicesResponse = delegateUnderTest.getServices();\r
+\r
+        assertThat(servicesResponse.getBody()).hasSize(1);\r
+\r
+        ResponseEntity<Void> deleteResponse = delegateUnderTest.deleteIndividualService(SERVICE_NAME);\r
+\r
+        assertThat(deleteResponse.getStatusCode()).isEqualTo(NO_CONTENT);\r
+\r
+        servicesResponse = delegateUnderTest.getServices();\r
+\r
+        assertThat(servicesResponse.getBody()).isEmpty();\r
+    }\r
+\r
+    private void whenGetRequestUrlThenReturnUrl() {\r
+        whenGetRequestUrlThenReturnUrl("URL");\r
+    }\r
+\r
+    private void whenGetRequestUrlThenReturnUrl(String url) {\r
+        HttpServletRequest servletRequestMock = mock(HttpServletRequest.class);\r
+        when(webRequestMock.getNativeRequest(HttpServletRequest.class)).thenReturn(servletRequestMock);\r
+        when(servletRequestMock.getRequestURL()).thenReturn(new StringBuffer(url));\r
+    }\r
+\r
+    private HttpServletResponse whenPrintResponseShouldWork() {\r
+        return whenPrintResponseShouldWork("URL");\r
+    }\r
+\r
+    private HttpServletResponse whenPrintResponseShouldWork(String url) {\r
+        whenGetRequestUrlThenReturnUrl(url);\r
+        HttpServletResponse servletResponseMock = mock(HttpServletResponse.class);\r
+        when(webRequestMock.getNativeResponse(HttpServletResponse.class)).thenReturn(servletResponseMock);\r
+        PrintWriter printWriterMock = mock(PrintWriter.class);\r
+        try {\r
+            when(servletResponseMock.getWriter()).thenReturn(printWriterMock);\r
+        } catch (IOException e) {\r
+            // Nothing\r
+        }\r
+        return servletResponseMock;\r
+    }\r
 \r
-        assertThat(response.getStatusCode()).isEqualTo(HttpStatus.OK);\r
-        assertThat(response.getBody()).isEqualTo(Arrays.asList("a", "b"));\r
+    private String getTodaysDate() {\r
+        long millis = System.currentTimeMillis();\r
+        Date date = new Date(millis);\r
+        return date.toString();\r
     }\r
 }\r