Merge "Implement service and repository layers for storing temporal data"
authorBruno Sakoto <bruno.sakoto@bell.ca>
Thu, 13 May 2021 13:15:53 +0000 (13:15 +0000)
committerGerrit Code Review <gerrit@onap.org>
Thu, 13 May 2021 13:15:53 +0000 (13:15 +0000)
13 files changed:
lombok.config [new file with mode: 0644]
pom.xml
src/main/java/org/onap/cps/temporal/domain/NetworkData.java [new file with mode: 0644]
src/main/java/org/onap/cps/temporal/domain/NetworkDataId.java [new file with mode: 0644]
src/main/java/org/onap/cps/temporal/repository/NetworkDataRepository.java [new file with mode: 0644]
src/main/java/org/onap/cps/temporal/service/NetworkDataService.java [new file with mode: 0644]
src/main/java/org/onap/cps/temporal/service/NetworkDataServiceImpl.java [moved from src/test/java/org/onap/cps/temporal/ApplicationTest.java with 55% similarity]
src/main/resources/application.yml
src/test/groovy/org/onap/cps/temporal/controller/QueryControllerSpec.groovy [moved from src/test/groovy/org/onap/cps/temporal/controller/QuerryControllerSpec.groovy with 100% similarity]
src/test/groovy/org/onap/cps/temporal/repository/NetworkDataRepositorySpec.groovy [new file with mode: 0644]
src/test/groovy/org/onap/cps/temporal/service/NetworkDataServiceImplSpec.groovy [new file with mode: 0644]
src/test/java/org/onap/cps/temporal/repository/containers/TimescaleContainer.java [moved from src/test/java/org/onap/cps/temporal/repository/TimescaleContainer.java with 97% similarity]
src/test/resources/application.yml

diff --git a/lombok.config b/lombok.config
new file mode 100644 (file)
index 0000000..a23edb4
--- /dev/null
@@ -0,0 +1,2 @@
+config.stopBubbling = true
+lombok.addLombokGeneratedAnnotation = true
\ No newline at end of file
diff --git a/pom.xml b/pom.xml
index a5ae5d0..9488873 100755 (executable)
--- a/pom.xml
+++ b/pom.xml
 
     <properties>
         <app>org.onap.cps.temporal.Application</app>
+        <cps.checkstyle.version>1.0.1</cps.checkstyle.version>
+        <cps.spotbugs.version>1.0.1</cps.spotbugs.version>
         <docker.repository.pull>nexus3.onap.org:10001/</docker.repository.pull>
         <docker.repository.push>nexus3.onap.org:10003/</docker.repository.push>
         <image.base>${docker.repository.pull}onap/integration-java11:8.0.0</image.base>
         <image.name>${docker.repository.push}onap/cps-temporal</image.name>
+        <hibernate-types.version>2.10.0</hibernate-types.version>
         <java.version>11</java.version>
-        <minimum-coverage>0.8</minimum-coverage>
-        <cps.checkstyle.version>1.0.1</cps.checkstyle.version>
-        <cps.spotbugs.version>1.0.1</cps.spotbugs.version>
         <jib-maven-plugin.version>3.0.0</jib-maven-plugin.version>
         <maven.build.timestamp.format>yyyyMMdd'T'HHmmss'Z'</maven.build.timestamp.format>
+        <minimum-coverage>0.8</minimum-coverage>
         <oparent.version>3.2.0</oparent.version>
         <spotbugs-maven-plugin.version>4.1.3</spotbugs-maven-plugin.version>
         <spotbugs.slf4j.version>1.8.0-beta4</spotbugs.slf4j.version>
             <groupId>org.springframework.boot</groupId>
             <artifactId>spring-boot-starter-data-jpa</artifactId>
         </dependency>
+        <dependency>
+            <groupId>com.vladmihalcea</groupId>
+            <artifactId>hibernate-types-52</artifactId>
+            <version>${hibernate-types.version}</version>
+        </dependency>
         <dependency>
             <groupId>org.liquibase</groupId>
             <artifactId>liquibase-core</artifactId>
             <version>4.3.2</version>
         </dependency>
+        <dependency>
+            <groupId>org.projectlombok</groupId>
+            <artifactId>lombok</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-validation</artifactId>
+        </dependency>
         <!-- Runtime dependencies-->
         <dependency>
             <groupId>org.postgresql</groupId>
             <artifactId>spock-core</artifactId>
             <scope>test</scope>
         </dependency>
+        <dependency>
+            <groupId>org.spockframework</groupId>
+            <artifactId>spock-spring</artifactId>
+            <scope>test</scope>
+        </dependency>
         <dependency>
             <groupId>org.testcontainers</groupId>
             <artifactId>junit-jupiter</artifactId>
             <plugin>
                 <groupId>org.jacoco</groupId>
                 <artifactId>jacoco-maven-plugin</artifactId>
-                <version>0.8.6</version>
                 <executions>
                     <execution>
                         <id>coverage-prepare-agent</id>
diff --git a/src/main/java/org/onap/cps/temporal/domain/NetworkData.java b/src/main/java/org/onap/cps/temporal/domain/NetworkData.java
new file mode 100644 (file)
index 0000000..c4f3176
--- /dev/null
@@ -0,0 +1,78 @@
+/*
+ * ============LICENSE_START=======================================================
+ * Copyright (c) 2021 Bell Canada.
+ * ================================================================================
+ * 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.onap.cps.temporal.domain;
+
+import com.vladmihalcea.hibernate.type.json.JsonBinaryType;
+import java.io.Serializable;
+import java.time.OffsetDateTime;
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.Id;
+import javax.persistence.IdClass;
+import javax.persistence.Table;
+import javax.validation.constraints.NotNull;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+import org.hibernate.annotations.CreationTimestamp;
+import org.hibernate.annotations.Type;
+import org.hibernate.annotations.TypeDef;
+
+/**
+ * Entity to store an anchor configuration or state along with the moment it has been observed.
+ */
+@Data
+@NoArgsConstructor
+@AllArgsConstructor
+@IdClass(NetworkDataId.class)
+@Builder
+@Entity
+@Table(name = "network_data")
+@TypeDef(name = "jsonb", typeClass = JsonBinaryType.class)
+public class NetworkData implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    @Id
+    @Column(name = "timestamp")
+    private OffsetDateTime observedTimestamp;
+
+    @Id
+    @Column
+    private String dataspace;
+
+    @Id
+    @Column
+    private String anchor;
+
+    @NotNull
+    @Column
+    private String schemaSet;
+
+    @NotNull
+    @Type(type = "jsonb")
+    @Column(columnDefinition = "jsonb")
+    private String payload;
+
+    @CreationTimestamp
+    @Column(name = "version", updatable = false)
+    private OffsetDateTime createdTimestamp;
+
+}
diff --git a/src/main/java/org/onap/cps/temporal/domain/NetworkDataId.java b/src/main/java/org/onap/cps/temporal/domain/NetworkDataId.java
new file mode 100644 (file)
index 0000000..e9742e2
--- /dev/null
@@ -0,0 +1,41 @@
+/*
+ * ============LICENSE_START=======================================================
+ * Copyright (c) 2021 Bell Canada.
+ * ================================================================================
+ * 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.onap.cps.temporal.domain;
+
+import java.io.Serializable;
+import java.time.OffsetDateTime;
+import lombok.AllArgsConstructor;
+import lombok.EqualsAndHashCode;
+import lombok.NoArgsConstructor;
+
+/**
+ * Identifier class for network data.
+ */
+@NoArgsConstructor
+@AllArgsConstructor
+@EqualsAndHashCode
+public class NetworkDataId implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    private String dataspace;
+    private String anchor;
+    private OffsetDateTime observedTimestamp;
+
+}
\ No newline at end of file
diff --git a/src/main/java/org/onap/cps/temporal/repository/NetworkDataRepository.java b/src/main/java/org/onap/cps/temporal/repository/NetworkDataRepository.java
new file mode 100644 (file)
index 0000000..2e9f34b
--- /dev/null
@@ -0,0 +1,28 @@
+/*
+ * ============LICENSE_START=======================================================
+ * Copyright (c) 2021 Bell Canada.
+ * ================================================================================
+ * 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.onap.cps.temporal.repository;
+
+import org.onap.cps.temporal.domain.NetworkData;
+import org.onap.cps.temporal.domain.NetworkDataId;
+import org.springframework.data.jpa.repository.JpaRepository;
+import org.springframework.stereotype.Repository;
+
+@Repository
+public interface NetworkDataRepository extends JpaRepository<NetworkData, NetworkDataId> {
+}
diff --git a/src/main/java/org/onap/cps/temporal/service/NetworkDataService.java b/src/main/java/org/onap/cps/temporal/service/NetworkDataService.java
new file mode 100644 (file)
index 0000000..509e470
--- /dev/null
@@ -0,0 +1,31 @@
+/*
+ * ============LICENSE_START=======================================================
+ * Copyright (c) 2021 Bell Canada.
+ * ================================================================================
+ * 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.onap.cps.temporal.service;
+
+import org.onap.cps.temporal.domain.NetworkData;
+
+public interface NetworkDataService {
+
+    /**
+     * Add Network data.
+     *
+     * @param networkData the network data to be stored
+     */
+    NetworkData addNetworkData(NetworkData networkData);
+}
  * ============LICENSE_END=========================================================
  */
 
-package org.onap.cps.temporal;
+package org.onap.cps.temporal.service;
 
-import org.assertj.core.util.Arrays;
-import org.junit.jupiter.api.Test;
-import org.onap.cps.temporal.repository.TimescaleContainer;
-import org.springframework.boot.test.context.SpringBootTest;
+import lombok.extern.slf4j.Slf4j;
+import org.onap.cps.temporal.domain.NetworkData;
+import org.onap.cps.temporal.repository.NetworkDataRepository;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
 
-// This test class without any assertion is obviously not really useful.
-// Its only purpose is to be able to cover current code.
-// It should be deleted when more code will be added to the project.
-@SpringBootTest
-class ApplicationTest {
-
-    private static final TimescaleContainer TIMESCALE_CONTAINER = TimescaleContainer.getInstance();
+/**
+ * Service implementation for Network Data.
+ */
+@Component
+@Slf4j
+public class NetworkDataServiceImpl implements NetworkDataService {
 
-    static {
-        TIMESCALE_CONTAINER.start();
-    }
+    @Autowired
+    NetworkDataRepository networkDataRepository;
 
-    @Test
-    void testMain() {
-        Application.main(Arrays.array());
+    @Override
+    public NetworkData addNetworkData(final NetworkData networkData) {
+        return networkDataRepository.save(networkData);
     }
-
 }
index ff70e46..d4c799c 100755 (executable)
@@ -15,6 +15,9 @@
 # limitations under the License.
 # ============LICENSE_END=========================================================
 
+server:
+    port: 8080
+
 spring:
     datasource:
         url: jdbc:postgresql://${DB_HOST}:${DB_PORT}/cpstemporaldb
@@ -22,3 +25,12 @@ spring:
         password: ${DB_PASSWORD}
     liquibase:
         change-log: classpath:/db/changelog/changelog-master.xml
+    jpa:
+        properties:
+            hibernate:
+                dialect: org.hibernate.dialect.PostgreSQLDialect
+
+logging:
+    level:
+        org:
+            springframework: INFO
diff --git a/src/test/groovy/org/onap/cps/temporal/repository/NetworkDataRepositorySpec.groovy b/src/test/groovy/org/onap/cps/temporal/repository/NetworkDataRepositorySpec.groovy
new file mode 100644 (file)
index 0000000..ec976ee
--- /dev/null
@@ -0,0 +1,70 @@
+/*
+ * ============LICENSE_START=======================================================
+ * Copyright (c) 2021 Bell Canada.
+ * ================================================================================
+ * 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.onap.cps.temporal.repository
+
+
+import org.onap.cps.temporal.domain.NetworkData
+import org.onap.cps.temporal.repository.containers.TimescaleContainer
+import org.springframework.beans.factory.annotation.Autowired
+import org.springframework.boot.test.context.SpringBootTest
+import org.testcontainers.junit.jupiter.Testcontainers
+import spock.lang.Shared
+import spock.lang.Specification
+
+import java.time.OffsetDateTime
+
+@SpringBootTest
+@Testcontainers
+class NetworkDataRepositorySpec extends Specification {
+
+    def observedTimestamp = OffsetDateTime.now()
+    def dataspaceName = 'TEST_DATASPACE'
+    def schemaSetName = 'TEST_SCHEMA_SET'
+    def anchorName = 'TEST_ANCHOR'
+    def payload = '{ \"message\": \"Hello World!\" }'
+
+    @Autowired
+    NetworkDataRepository networkDataRepository
+
+    def networkData = NetworkData.builder().observedTimestamp(observedTimestamp).dataspace(dataspaceName)
+            .schemaSet(schemaSetName).anchor(anchorName).payload(payload).build()
+
+    @Shared
+    def databaseTestContainer = TimescaleContainer.getInstance()
+
+    def setupSpec() {
+        databaseTestContainer.start()
+    }
+
+    def 'Store latest network data in timeseries database.'() {
+        when: 'a new Network Data is stored'
+            NetworkData savedData = networkDataRepository.save(networkData)
+        then: ' the saved Network Data is returned'
+            savedData.getDataspace() == networkData.getDataspace()
+            savedData.getSchemaSet() == networkData.getSchemaSet()
+            savedData.getAnchor() == networkData.getAnchor()
+            savedData.getPayload() == networkData.getPayload()
+            savedData.getObservedTimestamp() == networkData.getObservedTimestamp()
+        and: ' createdTimestamp is auto populated by db '
+            networkData.getCreatedTimestamp() == null
+            savedData.getCreatedTimestamp() != null
+        and: ' the CreationTimestamp is ahead of ObservedTimestamp'
+            savedData.getCreatedTimestamp() > networkData.getObservedTimestamp()
+    }
+}
diff --git a/src/test/groovy/org/onap/cps/temporal/service/NetworkDataServiceImplSpec.groovy b/src/test/groovy/org/onap/cps/temporal/service/NetworkDataServiceImplSpec.groovy
new file mode 100644 (file)
index 0000000..70ac2bc
--- /dev/null
@@ -0,0 +1,45 @@
+/*
+ * ============LICENSE_START=======================================================
+ * Copyright (c) 2021 Bell Canada.
+ * ================================================================================
+ * 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.onap.cps.temporal.service
+
+import java.time.OffsetDateTime
+import org.onap.cps.temporal.domain.NetworkData
+import org.onap.cps.temporal.repository.NetworkDataRepository
+import spock.lang.Specification
+
+class NetworkDataServiceImplSpec extends Specification {
+
+    def objectUnderTest = new NetworkDataServiceImpl()
+
+    def mockNetworkDataRepository = Mock(NetworkDataRepository)
+
+    def networkData = new NetworkData()
+
+    def setup() {
+        objectUnderTest.networkDataRepository = mockNetworkDataRepository
+    }
+
+    def 'Add network data in timeseries database.'() {
+        when: 'a new network data is added'
+            objectUnderTest.addNetworkData(networkData)
+        then: ' repository service is called with the correct parameters'
+            1 * mockNetworkDataRepository.save(networkData)
+    }
+
+}
@@ -16,7 +16,7 @@
  * ============LICENSE_END=========================================================
  */
 
-package org.onap.cps.temporal.repository;
+package org.onap.cps.temporal.repository.containers;
 
 import org.testcontainers.containers.PostgreSQLContainer;
 import org.testcontainers.utility.DockerImageName;
index 5f64bd9..afaff6c 100644 (file)
@@ -14,6 +14,9 @@
 # limitations under the License.
 # ============LICENSE_END=========================================================
 
+server:
+    port: 8080
+
 spring:
     datasource:
         url: ${DB_URL}
@@ -21,3 +24,13 @@ spring:
         username: ${DB_USERNAME}
     liquibase:
         change-log: classpath:/db/changelog/changelog-master.xml
+    jpa:
+        open-in-view: false
+        properties:
+            hibernate:
+                dialect: org.hibernate.dialect.PostgreSQLDialect
+
+logging:
+    level:
+        org:
+            springframework: INFO