Add docker file for all simulators 12/103912/7
authorJim Hahn <jrh3@att.com>
Tue, 17 Mar 2020 21:41:59 +0000 (17:41 -0400)
committerJim Hahn <jrh3@att.com>
Fri, 20 Mar 2020 12:49:19 +0000 (08:49 -0400)
Some CSITs may require multiple simulators.  This adds a class that
will start all of the simulators.  A tarball is generated from which
a docker image can be built.
Added simulators for Topics: appc and appc-lcm.
Fixed licenses in files in packages directory.
Fixed per review comments:
- add version to Dockerfile

Issue-ID: POLICY-2434
Signed-off-by: Jim Hahn <jrh3@att.com>
Change-Id: Id7aa9cb5a5874f7b4185273ab0d2c074198554ff

35 files changed:
models-interactions/model-simulators/pom.xml
models-interactions/model-simulators/src/main/java/org/onap/policy/simulators/AppcLcmTopicServer.java [new file with mode: 0644]
models-interactions/model-simulators/src/main/java/org/onap/policy/simulators/AppcLegacyTopicServer.java [new file with mode: 0644]
models-interactions/model-simulators/src/main/java/org/onap/policy/simulators/TopicServer.java [new file with mode: 0644]
models-interactions/model-simulators/src/main/resources/org/onap/policy/simulators/appc/appc.legacy.success.json [new file with mode: 0644]
models-interactions/model-simulators/src/main/resources/org/onap/policy/simulators/appclcm/appc.lcm.success.json [new file with mode: 0644]
models-interactions/model-simulators/src/test/java/org/onap/policy/simulators/AppcLcmTopicServerTest.java [new file with mode: 0644]
models-interactions/model-simulators/src/test/java/org/onap/policy/simulators/AppcLegacyTopicServerTest.java [new file with mode: 0644]
models-interactions/model-simulators/src/test/java/org/onap/policy/simulators/TopicServerTest.java [new file with mode: 0644]
models-interactions/model-simulators/src/test/resources/org/onap/policy/simulators/appc/appc.legacy.request.json [new file with mode: 0644]
models-interactions/model-simulators/src/test/resources/org/onap/policy/simulators/appclcm/appc.lcm.request.json [new file with mode: 0644]
models-sim/policy-models-simulators/pom.xml [new file with mode: 0644]
models-sim/policy-models-simulators/src/main/java/org/onap/policy/models/simulators/ClassRestServerParameters.java [new file with mode: 0644]
models-sim/policy-models-simulators/src/main/java/org/onap/policy/models/simulators/Main.java [new file with mode: 0644]
models-sim/policy-models-simulators/src/main/java/org/onap/policy/models/simulators/SimulatorParameters.java [new file with mode: 0644]
models-sim/policy-models-simulators/src/main/java/org/onap/policy/models/simulators/TopicServerParameters.java [new file with mode: 0644]
models-sim/policy-models-simulators/src/main/package/docker/Dockerfile [new file with mode: 0644]
models-sim/policy-models-simulators/src/main/package/docker/docker_build.sh [new file with mode: 0644]
models-sim/policy-models-simulators/src/main/package/docker/simulators.sh [new file with mode: 0644]
models-sim/policy-models-simulators/src/main/package/tarball/assembly.xml [new file with mode: 0644]
models-sim/policy-models-simulators/src/main/resources/logback.xml [new file with mode: 0644]
models-sim/policy-models-simulators/src/main/resources/ssl/policy-keystore [new file with mode: 0644]
models-sim/policy-models-simulators/src/main/resources/ssl/policy-truststore [new file with mode: 0644]
models-sim/policy-models-simulators/src/test/java/org/onap/policy/models/simulators/ClassRestServerParametersTest.java [new file with mode: 0644]
models-sim/policy-models-simulators/src/test/java/org/onap/policy/models/simulators/MainTest.java [new file with mode: 0644]
models-sim/policy-models-simulators/src/test/java/org/onap/policy/models/simulators/SimulatorParametersTest.java [new file with mode: 0644]
models-sim/policy-models-simulators/src/test/java/org/onap/policy/models/simulators/TopicServerParametersTest.java [new file with mode: 0644]
models-sim/policy-models-simulators/src/test/resources/invalidSimParameters.json [new file with mode: 0644]
models-sim/policy-models-simulators/src/test/resources/invalidTopicServer.json [new file with mode: 0644]
models-sim/policy-models-simulators/src/test/resources/keystore-test [new file with mode: 0644]
models-sim/policy-models-simulators/src/test/resources/logback-test.xml [new file with mode: 0644]
models-sim/policy-models-simulators/src/test/resources/missingSink.json [new file with mode: 0644]
models-sim/policy-models-simulators/src/test/resources/missingSource.json [new file with mode: 0644]
models-sim/policy-models-simulators/src/test/resources/simParameters.json [new file with mode: 0644]
models-sim/pom.xml

index fc9fe12..d74aa05 100644 (file)
@@ -1,6 +1,6 @@
 <!--
   ============LICENSE_START=======================================================
-  simulators
+  ONAP
   ================================================================================
   Copyright (C) 2017-2020 AT&T Intellectual Property. All rights reserved.
   Modifications Copyright (C) 2019 Nordix Foundation.
@@ -8,9 +8,9 @@
   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.
   ============LICENSE_END=========================================================
   -->
 
-<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
-  <modelVersion>4.0.0</modelVersion>
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
 
-  <parent>
-    <groupId>org.onap.policy.models</groupId>
-    <artifactId>policy-models-interactions</artifactId>
-    <version>2.2.1-SNAPSHOT</version>
-  </parent>
+    <parent>
+        <groupId>org.onap.policy.models</groupId>
+        <artifactId>policy-models-interactions</artifactId>
+        <version>2.2.1-SNAPSHOT</version>
+    </parent>
 
-  <groupId>org.onap.policy.models.policy-models-interactions</groupId>
-  <artifactId>simulators</artifactId>
+    <groupId>org.onap.policy.models.policy-models-interactions</groupId>
+    <artifactId>simulators</artifactId>
 
-  <dependencies>
-    <dependency>
-      <groupId>org.onap.policy.common</groupId>
-      <artifactId>policy-endpoints</artifactId>
-      <version>${policy.common.version}</version>
-    </dependency>
-    <dependency>
-      <groupId>junit</groupId>
-      <artifactId>junit</artifactId>
-      <scope>test</scope>
-    </dependency>
-    <dependency>
-      <groupId>org.onap.policy.models.policy-models-interactions.model-impl</groupId>
-      <artifactId>aai</artifactId>
-      <version>${project.version}</version>
-    </dependency>
-    <dependency>
-      <groupId>org.onap.policy.models.policy-models-interactions.model-impl</groupId>
-      <artifactId>so</artifactId>
-      <version>${project.version}</version>
-    </dependency>
-    <dependency>
-      <groupId>org.onap.policy.models.policy-models-interactions.model-impl</groupId>
-      <artifactId>vfc</artifactId>
-      <version>${project.version}</version>
-      <scope>test</scope>
-    </dependency>
-    <dependency>
-      <groupId>com.google.code.gson</groupId>
-      <artifactId>gson</artifactId>
-      <scope>provided</scope>
-    </dependency>
-    <dependency>
-      <groupId>org.onap.policy.models.policy-models-interactions.model-impl</groupId>
-      <artifactId>sdnc</artifactId>
-      <version>${project.version}</version>
-    </dependency>
-    <dependency>
-      <groupId>org.onap.policy.models</groupId>
-      <artifactId>policy-models-decisions</artifactId>
-      <version>${project.version}</version>
-    </dependency>
-    <dependency>
-      <groupId>org.onap.policy.models.sim</groupId>
-      <artifactId>policy-models-sim-dmaap</artifactId>
-      <version>${project.version}</version>
-    </dependency>
-  </dependencies>
+    <dependencies>
+        <dependency>
+            <groupId>org.onap.policy.common</groupId>
+            <artifactId>policy-endpoints</artifactId>
+            <version>${policy.common.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>junit</groupId>
+            <artifactId>junit</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.onap.policy.models.policy-models-interactions.model-impl</groupId>
+            <artifactId>aai</artifactId>
+            <version>${project.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.onap.policy.models.policy-models-interactions.model-impl</groupId>
+            <artifactId>appc</artifactId>
+            <version>${project.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.onap.policy.models.policy-models-interactions.model-impl</groupId>
+            <artifactId>appclcm</artifactId>
+            <version>${project.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.onap.policy.models.policy-models-interactions.model-impl</groupId>
+            <artifactId>so</artifactId>
+            <version>${project.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.onap.policy.models.policy-models-interactions.model-impl</groupId>
+            <artifactId>vfc</artifactId>
+            <version>${project.version}</version>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>com.google.code.gson</groupId>
+            <artifactId>gson</artifactId>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.onap.policy.models.policy-models-interactions.model-impl</groupId>
+            <artifactId>sdnc</artifactId>
+            <version>${project.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.onap.policy.models</groupId>
+            <artifactId>policy-models-decisions</artifactId>
+            <version>${project.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.onap.policy.models.sim</groupId>
+            <artifactId>policy-models-sim-dmaap</artifactId>
+            <version>${project.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.powermock</groupId>
+            <artifactId>powermock-api-mockito2</artifactId>
+            <scope>test</scope>
+        </dependency>
+    </dependencies>
 </project>
diff --git a/models-interactions/model-simulators/src/main/java/org/onap/policy/simulators/AppcLcmTopicServer.java b/models-interactions/model-simulators/src/main/java/org/onap/policy/simulators/AppcLcmTopicServer.java
new file mode 100644 (file)
index 0000000..df4cbb3
--- /dev/null
@@ -0,0 +1,42 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP
+ * ================================================================================
+ * Copyright (C) 2020 AT&T Intellectual Property. 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.onap.policy.simulators;
+
+import org.onap.policy.appclcm.AppcLcmDmaapWrapper;
+import org.onap.policy.common.endpoints.event.comm.TopicSink;
+import org.onap.policy.common.endpoints.event.comm.TopicSource;
+import org.onap.policy.common.utils.coder.StandardCoder;
+import org.onap.policy.common.utils.resources.ResourceUtils;
+
+/**
+ * APPC-LCM topic server.
+ */
+public class AppcLcmTopicServer extends TopicServer<AppcLcmDmaapWrapper> {
+    public AppcLcmTopicServer(TopicSink sink, TopicSource source) {
+        super(sink, source, new StandardCoder(), AppcLcmDmaapWrapper.class);
+    }
+
+    @Override
+    protected String process(AppcLcmDmaapWrapper request) {
+        String response = ResourceUtils.getResourceAsString("org/onap/policy/simulators/appclcm/appc.lcm.success.json");
+        return response.replace("${replaceMe}", request.getBody().getInput().getCommonHeader().getSubRequestId());
+    }
+}
diff --git a/models-interactions/model-simulators/src/main/java/org/onap/policy/simulators/AppcLegacyTopicServer.java b/models-interactions/model-simulators/src/main/java/org/onap/policy/simulators/AppcLegacyTopicServer.java
new file mode 100644 (file)
index 0000000..5ebd3bd
--- /dev/null
@@ -0,0 +1,42 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP
+ * ================================================================================
+ * Copyright (C) 2020 AT&T Intellectual Property. 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.onap.policy.simulators;
+
+import org.onap.policy.appc.Request;
+import org.onap.policy.common.endpoints.event.comm.TopicSink;
+import org.onap.policy.common.endpoints.event.comm.TopicSource;
+import org.onap.policy.common.utils.coder.StandardCoderInstantAsMillis;
+import org.onap.policy.common.utils.resources.ResourceUtils;
+
+/**
+ * Legacy APPC topic server.
+ */
+public class AppcLegacyTopicServer extends TopicServer<Request> {
+    public AppcLegacyTopicServer(TopicSink sink, TopicSource source) {
+        super(sink, source, new StandardCoderInstantAsMillis(), Request.class);
+    }
+
+    @Override
+    protected String process(Request request) {
+        String response = ResourceUtils.getResourceAsString("org/onap/policy/simulators/appc/appc.legacy.success.json");
+        return response.replace("${replaceMe}", request.getCommonHeader().getSubRequestId());
+    }
+}
diff --git a/models-interactions/model-simulators/src/main/java/org/onap/policy/simulators/TopicServer.java b/models-interactions/model-simulators/src/main/java/org/onap/policy/simulators/TopicServer.java
new file mode 100644 (file)
index 0000000..0abe5f4
--- /dev/null
@@ -0,0 +1,72 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP
+ * ================================================================================
+ * Copyright (C) 2020 AT&T Intellectual Property. 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.onap.policy.simulators;
+
+import org.onap.policy.common.endpoints.event.comm.Topic.CommInfrastructure;
+import org.onap.policy.common.endpoints.event.comm.TopicListener;
+import org.onap.policy.common.endpoints.event.comm.TopicSink;
+import org.onap.policy.common.endpoints.event.comm.TopicSource;
+import org.onap.policy.common.utils.coder.Coder;
+import org.onap.policy.common.utils.coder.CoderException;
+
+/**
+ * Server whose requests are received from a topic, and whose responses are sent to a
+ * topic.
+ */
+public abstract class TopicServer<Q> implements TopicListener {
+    private final TopicSink sink;
+    private final TopicSource source;
+    private final Coder coder;
+    private final Class<Q> reqClass;
+
+    /**
+     * Constructs the object.
+     *
+     * @param sink sink to which responses should be published
+     * @param source source from which requests arrive
+     */
+    public TopicServer(TopicSink sink, TopicSource source, Coder coder, Class<Q> reqClass) {
+        this.sink = sink;
+        this.source = source;
+        this.coder = coder;
+        this.reqClass = reqClass;
+
+        source.register(this);
+    }
+
+    public void shutdown() {
+        source.unregister(this);
+    }
+
+    @Override
+    public void onTopicEvent(CommInfrastructure commType, String topic, String request) {
+        Q req;
+        try {
+            req = coder.decode(request, reqClass);
+        } catch (CoderException e) {
+            throw new IllegalArgumentException("cannot decode request from " + source.getTopic());
+        }
+
+        sink.send(process(req));
+    }
+
+    protected abstract String process(Q request);
+}
diff --git a/models-interactions/model-simulators/src/main/resources/org/onap/policy/simulators/appc/appc.legacy.success.json b/models-interactions/model-simulators/src/main/resources/org/onap/policy/simulators/appc/appc.legacy.success.json
new file mode 100644 (file)
index 0000000..eb19c68
--- /dev/null
@@ -0,0 +1,17 @@
+{
+  "CommonHeader": {
+    "TimeStamp": 1506051879001,
+    "APIver": "1.01",
+    "RequestID": "c7c6a4aa-bb61-4a15-b831-ba1472dd4a65",
+    "SubRequestID": "${replaceMe}",
+    "RequestTrack": [],
+    "Flags": []
+  },
+  "Status": {
+    "Code": 400,
+    "Value": "SUCCESS"
+  },
+  "Payload": {
+    "generic-vnf.vnf-id": "jimmy-test-vnf2"
+  }
+}
diff --git a/models-interactions/model-simulators/src/main/resources/org/onap/policy/simulators/appclcm/appc.lcm.success.json b/models-interactions/model-simulators/src/main/resources/org/onap/policy/simulators/appclcm/appc.lcm.success.json
new file mode 100644 (file)
index 0000000..3310217
--- /dev/null
@@ -0,0 +1,22 @@
+{
+  "body": {
+    "output": {
+      "common-header": {
+        "timestamp": "2017-08-25T21:06:23.037Z",
+        "api-ver": "5.00",
+        "originator-id": "664be3d2-6c12-4f4b-a3e7-c349acced200",
+        "request-id": "664be3d2-6c12-4f4b-a3e7-c349acced200",
+        "sub-request-id": "${replaceMe}",
+        "flags": {}
+      },
+      "status": {
+        "code": 400,
+        "message": "Restart Successful"
+      }
+    }
+  },
+  "version": "2.0",
+  "rpc-name": "restart",
+  "correlation-id": "664be3d2-6c12-4f4b-a3e7-c349acced200-1",
+  "type": "response"
+}
diff --git a/models-interactions/model-simulators/src/test/java/org/onap/policy/simulators/AppcLcmTopicServerTest.java b/models-interactions/model-simulators/src/test/java/org/onap/policy/simulators/AppcLcmTopicServerTest.java
new file mode 100644 (file)
index 0000000..bc80315
--- /dev/null
@@ -0,0 +1,69 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP
+ * ================================================================================
+ * Copyright (C) 2020 AT&T Intellectual Property. 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.onap.policy.simulators;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.junit.Assert.assertNotNull;
+import static org.mockito.Mockito.verify;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.onap.policy.common.endpoints.event.comm.Topic.CommInfrastructure;
+import org.onap.policy.common.endpoints.event.comm.TopicSink;
+import org.onap.policy.common.endpoints.event.comm.TopicSource;
+import org.onap.policy.common.utils.resources.ResourceUtils;
+
+public class AppcLcmTopicServerTest {
+    private static final String MY_TOPIC = "my-topic";
+
+    @Mock
+    private TopicSink sink;
+    @Mock
+    private TopicSource source;
+
+    private AppcLcmTopicServer server;
+
+    /**
+     * Sets up.
+     */
+    @Before
+    public void setUp() {
+        MockitoAnnotations.initMocks(this);
+
+        server = new AppcLcmTopicServer(sink, source);
+    }
+
+    @Test
+    public void testProcessAppcLcmDmaapWrapper() {
+        String request = ResourceUtils.getResourceAsString("org/onap/policy/simulators/appclcm/appc.lcm.request.json");
+        assertNotNull(request);
+
+        server.onTopicEvent(CommInfrastructure.NOOP, MY_TOPIC, request);
+
+        ArgumentCaptor<String> respCaptor = ArgumentCaptor.forClass(String.class);
+        verify(sink).send(respCaptor.capture());
+
+        assertThat(respCaptor.getValue()).contains("111be3d2").doesNotContain("replaceMe");
+    }
+}
diff --git a/models-interactions/model-simulators/src/test/java/org/onap/policy/simulators/AppcLegacyTopicServerTest.java b/models-interactions/model-simulators/src/test/java/org/onap/policy/simulators/AppcLegacyTopicServerTest.java
new file mode 100644 (file)
index 0000000..57d574a
--- /dev/null
@@ -0,0 +1,69 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP
+ * ================================================================================
+ * Copyright (C) 2020 AT&T Intellectual Property. 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.onap.policy.simulators;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.junit.Assert.assertNotNull;
+import static org.mockito.Mockito.verify;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.onap.policy.common.endpoints.event.comm.Topic.CommInfrastructure;
+import org.onap.policy.common.endpoints.event.comm.TopicSink;
+import org.onap.policy.common.endpoints.event.comm.TopicSource;
+import org.onap.policy.common.utils.resources.ResourceUtils;
+
+public class AppcLegacyTopicServerTest {
+    private static final String MY_TOPIC = "my-topic";
+
+    @Mock
+    private TopicSink sink;
+    @Mock
+    private TopicSource source;
+
+    private AppcLegacyTopicServer server;
+
+    /**
+     * Sets up.
+     */
+    @Before
+    public void setUp() {
+        MockitoAnnotations.initMocks(this);
+
+        server = new AppcLegacyTopicServer(sink, source);
+    }
+
+    @Test
+    public void testProcessAppcLcmDmaapWrapper() {
+        String request = ResourceUtils.getResourceAsString("org/onap/policy/simulators/appc/appc.legacy.request.json");
+        assertNotNull(request);
+
+        server.onTopicEvent(CommInfrastructure.NOOP, MY_TOPIC, request);
+
+        ArgumentCaptor<String> respCaptor = ArgumentCaptor.forClass(String.class);
+        verify(sink).send(respCaptor.capture());
+
+        assertThat(respCaptor.getValue()).contains("111be3d2").doesNotContain("replaceMe");
+    }
+}
diff --git a/models-interactions/model-simulators/src/test/java/org/onap/policy/simulators/TopicServerTest.java b/models-interactions/model-simulators/src/test/java/org/onap/policy/simulators/TopicServerTest.java
new file mode 100644 (file)
index 0000000..6e17642
--- /dev/null
@@ -0,0 +1,104 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP
+ * ================================================================================
+ * Copyright (C) 2020 AT&T Intellectual Property. 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.onap.policy.simulators;
+
+import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
+import static org.junit.Assert.assertEquals;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.onap.policy.common.endpoints.event.comm.Topic.CommInfrastructure;
+import org.onap.policy.common.endpoints.event.comm.TopicSink;
+import org.onap.policy.common.endpoints.event.comm.TopicSource;
+import org.onap.policy.common.utils.coder.StandardCoder;
+
+public class TopicServerTest {
+    private static final String MY_TOPIC = "my-topic";
+    private static final String TEXT = "hello";
+    private static final String RESPONSE = "world";
+
+    @Mock
+    private TopicSink sink;
+    @Mock
+    private TopicSource source;
+
+    private MyServer server;
+
+    /**
+     * Sets up.
+     */
+    @Before
+    public void setUp() {
+        MockitoAnnotations.initMocks(this);
+
+        server = new MyServer();
+    }
+
+    @Test
+    public void testConstructor() {
+        verify(source).register(server);
+    }
+
+    @Test
+    public void testShutdown() {
+        server.shutdown();
+        verify(source).unregister(server);
+    }
+
+    @Test
+    public void testOnTopicEvent() {
+        server.onTopicEvent(CommInfrastructure.NOOP, MY_TOPIC, "{\"text\": \"hello\"}");
+        verify(sink).send(RESPONSE);
+    }
+
+    /**
+     * Tests onTopicEvent() when the coder throws an exception.
+     */
+    @Test
+    public void testOnTopicEventException() {
+        assertThatIllegalArgumentException()
+                        .isThrownBy(() -> server.onTopicEvent(CommInfrastructure.NOOP, MY_TOPIC, "{invalid json"));
+
+        verify(sink, never()).send(any());
+    }
+
+
+    private class MyRequest {
+        private String text;
+    }
+
+    private class MyServer extends TopicServer<MyRequest> {
+        public MyServer() {
+            super(sink, source, new StandardCoder(), MyRequest.class);
+        }
+
+        @Override
+        protected String process(MyRequest request) {
+            assertEquals(TEXT, request.text);
+            return RESPONSE;
+        }
+    }
+}
diff --git a/models-interactions/model-simulators/src/test/resources/org/onap/policy/simulators/appc/appc.legacy.request.json b/models-interactions/model-simulators/src/test/resources/org/onap/policy/simulators/appc/appc.legacy.request.json
new file mode 100644 (file)
index 0000000..8b3b73a
--- /dev/null
@@ -0,0 +1,10 @@
+{
+    "CommonHeader": {
+        "TimeStamp": 1506051879001,
+        "APIver": "1.01",
+        "RequestID": "c7c6a4aa-bb61-4a15-b831-ba1472dd4a65",
+        "SubRequestID": "111be3d2-6c12-4f4b-a3e7-c349acced200",
+        "RequestTrack": [],
+        "Flags": []
+    }
+}
diff --git a/models-interactions/model-simulators/src/test/resources/org/onap/policy/simulators/appclcm/appc.lcm.request.json b/models-interactions/model-simulators/src/test/resources/org/onap/policy/simulators/appclcm/appc.lcm.request.json
new file mode 100644 (file)
index 0000000..cf2ebd5
--- /dev/null
@@ -0,0 +1,17 @@
+{
+  "body": {
+    "input": {
+      "common-header": {
+        "timestamp": "2017-08-25T21:06:23.037Z",
+        "api-ver": "5.00",
+        "originator-id": "664be3d2-6c12-4f4b-a3e7-c349acced200",
+        "request-id": "664be3d2-6c12-4f4b-a3e7-c349acced200",
+        "sub-request-id": "111be3d2-6c12-4f4b-a3e7-c349acced200",
+        "flags": {}
+      }
+    }
+  },
+  "version": "2.0",
+  "rpc-name": "restart",
+  "type": "request"
+}
diff --git a/models-sim/policy-models-simulators/pom.xml b/models-sim/policy-models-simulators/pom.xml
new file mode 100644 (file)
index 0000000..5b9e4df
--- /dev/null
@@ -0,0 +1,98 @@
+<!--
+  ============LICENSE_START=======================================================
+  ONAP
+  ================================================================================
+   Copyright (C) 2020 AT&T Intellectual Property. 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.
+
+  SPDX-License-Identifier: Apache-2.0
+  ============LICENSE_END=========================================================
+-->
+
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+    <parent>
+        <groupId>org.onap.policy.models.sim</groupId>
+        <artifactId>policy-models-sim</artifactId>
+        <version>2.2.1-SNAPSHOT</version>
+    </parent>
+
+    <artifactId>policy-models-simulators</artifactId>
+
+    <name>${project.artifactId}</name>
+    <description>A module that runs all "simulators", including DMaaP.</description>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.onap.policy.models.policy-models-interactions</groupId>
+            <artifactId>simulators</artifactId>
+            <version>${project.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>junit</groupId>
+            <artifactId>junit</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.powermock</groupId>
+            <artifactId>powermock-api-mockito2</artifactId>
+            <scope>test</scope>
+        </dependency>
+    </dependencies>
+
+    <build>
+        <resources>
+            <!-- Output the version of the service -->
+            <resource>
+                <directory>src/main/resources</directory>
+                <filtering>true</filtering>
+                <includes>
+                    <include>**/version.txt</include>
+                </includes>
+            </resource>
+            <resource>
+                <directory>src/main/resources</directory>
+                <filtering>false</filtering>
+                <excludes>
+                    <exclude>**/version.txt</exclude>
+                </excludes>
+            </resource>
+        </resources>
+
+        <plugins>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-assembly-plugin</artifactId>
+                <executions>
+                    <execution>
+                        <id>generate-complete-tar</id>
+                        <phase>package</phase>
+                        <goals>
+                            <goal>single</goal>
+                        </goals>
+                        <configuration>
+                            <descriptors>
+                                <descriptor>src/main/package/tarball/assembly.xml</descriptor>
+                            </descriptors>
+                            <finalName>${project.artifactId}-${project.version}</finalName>
+                        </configuration>
+                    </execution>
+                </executions>
+            </plugin>
+        </plugins>
+
+    </build>
+</project>
diff --git a/models-sim/policy-models-simulators/src/main/java/org/onap/policy/models/simulators/ClassRestServerParameters.java b/models-sim/policy-models-simulators/src/main/java/org/onap/policy/models/simulators/ClassRestServerParameters.java
new file mode 100644 (file)
index 0000000..030d774
--- /dev/null
@@ -0,0 +1,48 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP
+ * ================================================================================
+ * Copyright (C) 2020 AT&T Intellectual Property. 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.onap.policy.models.simulators;
+
+import lombok.Getter;
+import org.apache.commons.lang3.StringUtils;
+import org.onap.policy.common.endpoints.parameters.RestServerParameters;
+import org.onap.policy.common.parameters.ObjectValidationResult;
+import org.onap.policy.common.parameters.ValidationResult;
+import org.onap.policy.common.parameters.ValidationStatus;
+
+@Getter
+public class ClassRestServerParameters extends RestServerParameters {
+    private String providerClass;
+
+    /**
+     * Validates the parameters.
+     *
+     * @param containerName name of the parameter container
+     * @return the validation result
+     */
+    public ValidationResult validate(String containerName) {
+        // not using a BeanValidator because username and password are not required
+        if (StringUtils.isBlank(providerClass)) {
+            return new ObjectValidationResult("providerClass", providerClass, ValidationStatus.INVALID, "is empty");
+        }
+
+        return new ObjectValidationResult("providerClass", providerClass);
+    }
+}
diff --git a/models-sim/policy-models-simulators/src/main/java/org/onap/policy/models/simulators/Main.java b/models-sim/policy-models-simulators/src/main/java/org/onap/policy/models/simulators/Main.java
new file mode 100644 (file)
index 0000000..8333800
--- /dev/null
@@ -0,0 +1,281 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * Copyright (C) 2020 AT&T Intellectual Property. 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.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.policy.models.simulators;
+
+import java.io.FileNotFoundException;
+import java.lang.reflect.InvocationTargetException;
+import java.util.List;
+import java.util.Properties;
+import java.util.concurrent.atomic.AtomicReference;
+import lombok.AccessLevel;
+import lombok.Getter;
+import org.onap.policy.common.endpoints.event.comm.TopicEndpointManager;
+import org.onap.policy.common.endpoints.event.comm.TopicSink;
+import org.onap.policy.common.endpoints.event.comm.TopicSource;
+import org.onap.policy.common.endpoints.http.server.HttpServletServer;
+import org.onap.policy.common.endpoints.http.server.HttpServletServerFactoryInstance;
+import org.onap.policy.common.endpoints.parameters.TopicParameters;
+import org.onap.policy.common.endpoints.properties.PolicyEndPointProperties;
+import org.onap.policy.common.gson.GsonMessageBodyHandler;
+import org.onap.policy.common.parameters.BeanValidationResult;
+import org.onap.policy.common.utils.coder.Coder;
+import org.onap.policy.common.utils.coder.CoderException;
+import org.onap.policy.common.utils.coder.StandardCoder;
+import org.onap.policy.common.utils.network.NetworkUtil;
+import org.onap.policy.common.utils.resources.ResourceUtils;
+import org.onap.policy.common.utils.services.ServiceManagerContainer;
+import org.onap.policy.models.sim.dmaap.parameters.DmaapSimParameterGroup;
+import org.onap.policy.models.sim.dmaap.provider.DmaapSimProvider;
+import org.onap.policy.models.sim.dmaap.rest.CambriaMessageBodyHandler;
+import org.onap.policy.models.sim.dmaap.rest.TextMessageBodyHandler;
+import org.onap.policy.simulators.TopicServer;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * This class runs all simulators specified in the parameter file.
+ */
+public class Main extends ServiceManagerContainer {
+    private static final Logger logger = LoggerFactory.getLogger(Main.class);
+
+    private static final String CANNOT_CONNECT = "cannot connect to port ";
+
+    @Getter(AccessLevel.PROTECTED)
+    private static Main instance;
+
+
+    /**
+     * Runs the simulators.
+     *
+     * @param paramFile parameter file name
+     */
+    public Main(String paramFile) {
+        super(Main.class.getPackage().getName());
+
+        SimulatorParameters params = readParameters(paramFile);
+        BeanValidationResult result = params.validate("simulators");
+        if (!result.isValid()) {
+            logger.error("invalid parameters:\n{}", result.getResult());
+            throw new IllegalArgumentException("invalid simulator parameters");
+        }
+
+        DmaapSimParameterGroup dmaapProv = params.getDmaapProvider();
+        String dmaapName = dmaapProv.getName();
+        String provName = dmaapName.replace("simulator", "provider");
+
+        // dmaap provider
+        AtomicReference<DmaapSimProvider> provRef = new AtomicReference<>();
+        addAction(provName, () -> provRef.set(buildDmaapProvider(dmaapProv)), () -> provRef.get().shutdown());
+
+        // @formatter:off
+
+        // REST server simulators
+        for (ClassRestServerParameters restsim : params.getRestServers()) {
+            AtomicReference<HttpServletServer> ref = new AtomicReference<>();
+            addAction(restsim.getName(),
+                () -> ref.set(buildRestServer(dmaapName, restsim)),
+                () -> ref.get().shutdown());
+        }
+
+        // NOTE: topics must be started AFTER the (dmaap) rest servers
+
+        // topic sinks
+        AtomicReference<List<TopicSink>> sinkRef = new AtomicReference<>();
+        addAction("topic sinks", () -> sinkRef.set(buildSinks(params.getTopicSinks())),
+            () -> shutdownSinks(sinkRef.get()));
+
+        // topic sources
+        AtomicReference<List<TopicSource>> sourceRef = new AtomicReference<>();
+        addAction("topic sources", () -> sourceRef.set(buildSources(params.getTopicSources())),
+            () -> shutdownSources(sourceRef.get()));
+
+        // topic server simulators
+        for (TopicServerParameters topicsim : params.getTopicServers()) {
+            AtomicReference<TopicServer<?>> ref = new AtomicReference<>();
+            addAction(topicsim.getName(),
+                () -> ref.set(buildTopicServer(topicsim, sinkRef.get(), sourceRef.get())),
+                () -> ref.get().shutdown());
+        }
+
+        // @formatter:on
+    }
+
+    /**
+     * The main method.
+     *
+     * @param args the arguments, the first of which is the name of the parameter file
+     */
+    public static void main(final String[] args) {
+        try {
+            if (args.length != 1) {
+                throw new IllegalArgumentException("arg(s): parameter-file-name");
+            }
+
+            instance = new Main(args[0]);
+            instance.start();
+
+        } catch (RuntimeException e) {
+            logger.error("failed to start simulators", e);
+        }
+    }
+
+    private SimulatorParameters readParameters(String paramFile) {
+        try {
+            String paramsJson = getResourceAsString(paramFile);
+            if (paramsJson == null) {
+                throw new IllegalArgumentException(new FileNotFoundException(paramFile));
+            }
+
+            String hostName = NetworkUtil.getHostname();
+            logger.info("replacing 'HOST_NAME' with {} in {}", hostName, paramFile);
+
+            paramsJson = paramsJson.replace("${HOST_NAME}", hostName);
+
+            return makeCoder().decode(paramsJson, SimulatorParameters.class);
+
+        } catch (CoderException e) {
+            throw new IllegalArgumentException("cannot decode " + paramFile, e);
+        }
+    }
+
+    private DmaapSimProvider buildDmaapProvider(DmaapSimParameterGroup params) {
+        DmaapSimProvider prov = new DmaapSimProvider(params);
+        DmaapSimProvider.setInstance(prov);
+        prov.start();
+
+        return prov;
+    }
+
+    protected List<TopicSink> buildSinks(List<TopicParameters> params) {
+        return TopicEndpointManager.getManager().addTopicSinks(params);
+    }
+
+    private void shutdownSinks(List<TopicSink> sinks) {
+        sinks.forEach(TopicSink::shutdown);
+    }
+
+    protected List<TopicSource> buildSources(List<TopicParameters> params) {
+        return TopicEndpointManager.getManager().addTopicSources(params);
+    }
+
+    private void shutdownSources(List<TopicSource> sources) {
+        sources.forEach(TopicSource::shutdown);
+    }
+
+    private HttpServletServer buildRestServer(String dmaapName, ClassRestServerParameters params) {
+        try {
+            Properties props = getServerProperties(dmaapName, params);
+            HttpServletServer testServer = makeServer(props);
+            testServer.waitedStart(5000);
+
+            String svcpfx = PolicyEndPointProperties.PROPERTY_HTTP_SERVER_SERVICES + "." + params.getName();
+            String hostName = props.getProperty(svcpfx + PolicyEndPointProperties.PROPERTY_HTTP_HOST_SUFFIX);
+
+            if (!isTcpPortOpen(hostName, testServer.getPort())) {
+                throw new IllegalStateException(CANNOT_CONNECT + testServer.getPort());
+            }
+
+            return testServer;
+
+        } catch (InterruptedException e) {
+            Thread.currentThread().interrupt();
+            throw new IllegalStateException("interrupted while building " + params.getName(), e);
+        }
+    }
+
+    private TopicServer<?> buildTopicServer(TopicServerParameters params, List<TopicSink> sinks,
+                    List<TopicSource> sources) {
+        try {
+            // find the desired sink
+            TopicSink sink = sinks.stream().filter(sink2 -> sink2.getTopic().equals(params.getSink())).findAny()
+                            .orElseThrow(() -> new IllegalArgumentException("invalid sink topic " + params.getSink()));
+
+            // find the desired source
+            TopicSource source = sources.stream().filter(source2 -> source2.getTopic().equals(params.getSource()))
+                            .findAny().orElseThrow(() -> new IllegalArgumentException(
+                                            "invalid source topic " + params.getSource()));
+
+            // create the topic server
+            return (TopicServer<?>) Class.forName(params.getProviderClass())
+                            .getDeclaredConstructor(TopicSink.class, TopicSource.class).newInstance(sink, source);
+
+        } catch (InstantiationException | IllegalAccessException | InvocationTargetException | NoSuchMethodException
+                        | SecurityException | ClassNotFoundException e) {
+            throw new IllegalArgumentException("cannot create TopicServer: " + params.getName(), e);
+        }
+    }
+
+    /**
+     * Creates a set of properties, suitable for building a REST server, from the
+     * parameters.
+     *
+     * @param params parameters from which to build the properties
+     * @return a set of properties representing the given parameters
+     */
+    private static Properties getServerProperties(String dmaapName, ClassRestServerParameters params) {
+        final Properties props = new Properties();
+        props.setProperty(PolicyEndPointProperties.PROPERTY_HTTP_SERVER_SERVICES, params.getName());
+
+        final String svcpfx = PolicyEndPointProperties.PROPERTY_HTTP_SERVER_SERVICES + "." + params.getName();
+
+        props.setProperty(PolicyEndPointProperties.PROPERTY_HTTP_SERVER_SERVICES, params.getName());
+        props.setProperty(svcpfx + PolicyEndPointProperties.PROPERTY_HTTP_HOST_SUFFIX, params.getHost());
+        props.setProperty(svcpfx + PolicyEndPointProperties.PROPERTY_HTTP_PORT_SUFFIX,
+                        Integer.toString(params.getPort()));
+        props.setProperty(svcpfx + PolicyEndPointProperties.PROPERTY_HTTP_HTTPS_SUFFIX,
+                        Boolean.toString(params.isHttps()));
+        props.setProperty(svcpfx + PolicyEndPointProperties.PROPERTY_HTTP_REST_CLASSES_SUFFIX,
+                        params.getProviderClass());
+        props.setProperty(svcpfx + PolicyEndPointProperties.PROPERTY_MANAGED_SUFFIX, "false");
+        props.setProperty(svcpfx + PolicyEndPointProperties.PROPERTY_HTTP_SWAGGER_SUFFIX, "false");
+        props.setProperty(svcpfx + PolicyEndPointProperties.PROPERTY_MANAGED_SUFFIX, "true");
+
+        if (dmaapName.equals(params.getName())) {
+            props.setProperty(svcpfx + PolicyEndPointProperties.PROPERTY_HTTP_SERIALIZATION_PROVIDER,
+                            String.join(",", CambriaMessageBodyHandler.class.getName(),
+                                            GsonMessageBodyHandler.class.getName(),
+                                            TextMessageBodyHandler.class.getName()));
+        } else {
+            props.setProperty(svcpfx + PolicyEndPointProperties.PROPERTY_HTTP_SERIALIZATION_PROVIDER, String.join(",",
+                            GsonMessageBodyHandler.class.getName(), TextMessageBodyHandler.class.getName()));
+        }
+
+        return props;
+    }
+
+    // the following methods may be overridden by junit tests
+
+    protected String getResourceAsString(String resourceName) {
+        return ResourceUtils.getResourceAsString(resourceName);
+    }
+
+    protected Coder makeCoder() {
+        return new StandardCoder();
+    }
+
+    protected HttpServletServer makeServer(Properties props) {
+        return HttpServletServerFactoryInstance.getServerFactory().build(props).get(0);
+    }
+
+    protected boolean isTcpPortOpen(String hostName, int port) throws InterruptedException {
+        return NetworkUtil.isTcpPortOpen(hostName, port, 100, 200L);
+    }
+}
diff --git a/models-sim/policy-models-simulators/src/main/java/org/onap/policy/models/simulators/SimulatorParameters.java b/models-sim/policy-models-simulators/src/main/java/org/onap/policy/models/simulators/SimulatorParameters.java
new file mode 100644 (file)
index 0000000..c47ff88
--- /dev/null
@@ -0,0 +1,82 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP
+ * ================================================================================
+ * Copyright (C) 2020 AT&T Intellectual Property. 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.onap.policy.models.simulators;
+
+import java.util.LinkedList;
+import java.util.List;
+import lombok.Getter;
+import org.onap.policy.common.endpoints.parameters.TopicParameters;
+import org.onap.policy.common.parameters.BeanValidationResult;
+import org.onap.policy.common.parameters.BeanValidator;
+import org.onap.policy.common.parameters.annotations.NotNull;
+import org.onap.policy.models.sim.dmaap.parameters.DmaapSimParameterGroup;
+
+/**
+ * Simulator parameters.
+ */
+@Getter
+@NotNull
+public class SimulatorParameters {
+
+    /**
+     * Note: this is only used to capture the provider's parameters; the rest server
+     * parameters that it contains are ignored. Instead, the parameters for the rest
+     * server are contained within the {@link #restServers} entry having the same name as
+     * the provider parameters.
+     */
+    private DmaapSimParameterGroup dmaapProvider;
+
+    /**
+     * Parameters for the REST server simulators that are to be started.
+     */
+    private List<ClassRestServerParameters> restServers = new LinkedList<>();
+
+    /**
+     * Topic sinks that are used by {@link #topicServers}.
+     */
+    private List<TopicParameters> topicSinks = new LinkedList<>();
+
+    /**
+     * Topic sources that are used by {@link #topicServers}.
+     */
+    private List<TopicParameters> topicSources = new LinkedList<>();
+
+    /**
+     * Parameters for the TOPIC server simulators that are to be started.
+     */
+    private List<TopicServerParameters> topicServers = new LinkedList<>();
+
+
+    /**
+     * Validates the parameters.
+     *
+     * @param containerName name of the parameter container
+     * @return the validation result
+     */
+    public BeanValidationResult validate(String containerName) {
+        BeanValidationResult result = new BeanValidator().validateTop(containerName, this);
+
+        result.validateList("restServers", restServers, params -> params.validate("restServers"));
+        result.validateList("topicServers", topicServers, params -> params.validate("topicServers"));
+
+        return result;
+    }
+}
diff --git a/models-sim/policy-models-simulators/src/main/java/org/onap/policy/models/simulators/TopicServerParameters.java b/models-sim/policy-models-simulators/src/main/java/org/onap/policy/models/simulators/TopicServerParameters.java
new file mode 100644 (file)
index 0000000..8a477b2
--- /dev/null
@@ -0,0 +1,48 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP
+ * ================================================================================
+ * Copyright (C) 2020 AT&T Intellectual Property. 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.onap.policy.models.simulators;
+
+import lombok.Getter;
+import org.onap.policy.common.parameters.BeanValidationResult;
+import org.onap.policy.common.parameters.BeanValidator;
+import org.onap.policy.common.parameters.annotations.NotBlank;
+import org.onap.policy.common.parameters.annotations.NotNull;
+
+@Getter
+@NotNull
+@NotBlank
+public class TopicServerParameters {
+    private String name;
+    private String providerClass;
+    private String sink;
+    private String source;
+
+
+    /**
+     * Validates the parameters.
+     *
+     * @param containerName name of the parameter container
+     * @return the validation result
+     */
+    public BeanValidationResult validate(String containerName) {
+        return new BeanValidator().validateTop(containerName, this);
+    }
+}
diff --git a/models-sim/policy-models-simulators/src/main/package/docker/Dockerfile b/models-sim/policy-models-simulators/src/main/package/docker/Dockerfile
new file mode 100644 (file)
index 0000000..c41cd38
--- /dev/null
@@ -0,0 +1,59 @@
+#
+# ============LICENSE_START=======================================================
+# ONAP
+# ================================================================================
+# Copyright (C) 2020 AT&T Intellectual Property. 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.
+#
+# SPDX-License-Identifier: Apache-2.0
+# ============LICENSE_END=========================================================
+#
+
+#
+# Docker file to build an image that runs the simulators
+#
+
+FROM onap/policy-jre-alpine:2.0.1
+
+LABEL maintainer="Policy Team"
+
+ARG POLICY_LOGS=/var/log/onap/policy/simulators
+
+ENV POLICY_HOME /opt/app/policy
+ENV POLICY_LOGS ${POLICY_LOGS}
+
+# Create DMaaP simulator user and group
+# Add simulator-specific directories and set ownership as the simulator user
+RUN mkdir -p ${POLICY_HOME}/simulators \
+    && mkdir -p ${POLICY_HOME}/simulators/bin \
+    && mkdir -p ${POLICY_LOGS} \
+    && mkdir /packages
+
+# Unpack the tarball
+COPY policy-models-simulators-tarball.tar.gz /packages
+RUN tar xvfz /packages/policy-models-simulators-tarball.tar.gz --directory ${POLICY_HOME}/simulators \
+    && rm /packages/policy-models-simulators-tarball.tar.gz
+
+# Ensure everything has the correct permissions
+# Copy scripts simulator user area
+COPY simulators.sh ${POLICY_HOME}/simulators/bin
+RUN find /opt/app -type d -perm 755 \
+    && find /opt/app -type f -perm 644 \
+    && chmod 755 ${POLICY_HOME}/simulators/bin/* \
+    && chown -R policy:policy $POLICY_HOME $POLICY_LOGS
+
+USER policy:policy
+
+ENV PATH ${POLICY_HOME}/simulators/bin:$PATH
+ENTRYPOINT [ "bash", "simulators.sh" ]
diff --git a/models-sim/policy-models-simulators/src/main/package/docker/docker_build.sh b/models-sim/policy-models-simulators/src/main/package/docker/docker_build.sh
new file mode 100644 (file)
index 0000000..efbb1dc
--- /dev/null
@@ -0,0 +1,67 @@
+#!/bin/bash
+#
+# ============LICENSE_START=======================================================
+# ONAP
+# ================================================================================
+# Copyright (C) 2020 AT&T Intellectual Property. 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.
+#
+# SPDX-License-Identifier: Apache-2.0
+# ============LICENSE_END=========================================================
+#
+
+#
+# Script to build a Docker file for the simulators. The docker image
+# generated by this script should NOT be placed in the ONAP nexus, it is
+# only for testing purposes.
+#
+
+if [ -z "$SIMULATOR_HOME" ]
+then
+    SIMULATOR_HOME=$PWD
+fi
+
+# Check for the dockerfile
+if [ ! -f "$SIMULATOR_HOME/src/main/package/docker/Dockerfile" ]
+then
+    echo docker file "$SIMULATOR_HOME/src/main/package/docker/Dockerfile" not found
+    exit 1
+fi
+
+# Check for the start script
+if [ ! -f "$SIMULATOR_HOME/src/main/package/docker/simulators.sh" ]
+then
+    echo start script "$SIMULATOR_HOME/src/main/package/docker/simulators.sh" not found
+    exit 1
+fi
+
+# Check for the tarball
+tarball_count=`ls $SIMULATOR_HOME/target/policy-models-simulators-*tarball.tar.gz 2> /dev/null | wc | awk '{print $1}'`
+if [ "$tarball_count" -ne "1" ]
+then
+    echo one and only one tarball should exist in the target directory
+    exit 2
+fi
+
+# Set up the docker build
+rm -fr $SIMULATOR_HOME/target/docker
+mkdir $SIMULATOR_HOME/target/docker
+cp $SIMULATOR_HOME/src/main/package/docker/Dockerfile $SIMULATOR_HOME/target/docker
+cp $SIMULATOR_HOME/src/main/package/docker/simulators.sh $SIMULATOR_HOME/target/docker
+cp $SIMULATOR_HOME/target/policy-models-simulators-*tarball.tar.gz \
+    $SIMULATOR_HOME/target/docker/policy-models-simulators-tarball.tar.gz
+
+# Run the docker build
+cd $SIMULATOR_HOME/target
+docker build -t policy/simulators docker
diff --git a/models-sim/policy-models-simulators/src/main/package/docker/simulators.sh b/models-sim/policy-models-simulators/src/main/package/docker/simulators.sh
new file mode 100644 (file)
index 0000000..57e7427
--- /dev/null
@@ -0,0 +1,43 @@
+#!/bin/bash
+#
+# ============LICENSE_START=======================================================
+# ONAP
+# ================================================================================
+# Copyright (C) 2020 AT&T Intellectual Property. 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.
+#
+# SPDX-License-Identifier: Apache-2.0
+# ============LICENSE_END=========================================================
+#
+
+if [ -z "$SIMULATOR_HOME" ]
+then
+    SIMULATOR_HOME=${POLICY_HOME}/simulators
+fi
+
+JAVA_HOME=/usr/lib/jvm/java-11-openjdk
+KEYSTORE="${SIMULATOR_HOME}/etc/ssl/policy-keystore"
+KEYSTORE_PASSWD="Pol1cy_0nap"
+TRUSTSTORE="${SIMULATOR_HOME}/etc/ssl/policy-truststore"
+TRUSTSTORE_PASSWD="Pol1cy_0nap"
+
+${JAVA_HOME}/bin/java \
+    -cp "${SIMULATOR_HOME}/etc:${SIMULATOR_HOME}/lib/*" \
+    -Dlogback.configurationFile=${SIMULATOR_HOME}/etc/logback.xml \
+    -Djavax.net.ssl.keyStore="${KEYSTORE}" \
+    -Djavax.net.ssl.keyStorePassword="${KEYSTORE_PASSWD}" \
+    -Djavax.net.ssl.trustStore="${TRUSTSTORE}" \
+    -Djavax.net.ssl.trustStorePassword="${TRUSTSTORE_PASSWD}" \
+    org.onap.policy.models.simulators.Main \
+        ${SIMULATOR_HOME}/etc/parameters/simParameters.json
diff --git a/models-sim/policy-models-simulators/src/main/package/tarball/assembly.xml b/models-sim/policy-models-simulators/src/main/package/tarball/assembly.xml
new file mode 100644 (file)
index 0000000..8496fd3
--- /dev/null
@@ -0,0 +1,57 @@
+<!--
+  ============LICENSE_START=======================================================
+  Copyright (C) 2020 AT&T Intellectual Property. 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.
+
+  SPDX-License-Identifier: Apache-2.0
+  ============LICENSE_END=========================================================
+-->
+
+<assembly>
+    <id>tarball</id>
+    <formats>
+        <format>tar.gz</format>
+    </formats>
+    <includeBaseDirectory>false</includeBaseDirectory>
+    <dependencySets>
+        <dependencySet>
+            <useProjectArtifact>true</useProjectArtifact>
+            <outputDirectory>/lib</outputDirectory>
+            <unpack>false</unpack>
+            <scope>runtime</scope>
+            <includes>
+                <include>*:jar</include>
+            </includes>
+        </dependencySet>
+    </dependencySets>
+    <fileSets>
+        <fileSet>
+            <directory>${project.basedir}/src/main/resources</directory>
+            <includes>
+                <include>logback.xml</include>
+            </includes>
+            <outputDirectory>etc</outputDirectory>
+            <lineEnding>unix</lineEnding>
+        </fileSet>
+        <fileSet>
+            <directory>${project.basedir}/src/main/resources/ssl
+            </directory>
+            <includes>
+                <include>policy*</include>
+            </includes>
+            <outputDirectory>etc${file.separator}ssl</outputDirectory>
+            <lineEnding>keep</lineEnding>
+        </fileSet>
+    </fileSets>
+</assembly>
diff --git a/models-sim/policy-models-simulators/src/main/resources/logback.xml b/models-sim/policy-models-simulators/src/main/resources/logback.xml
new file mode 100644 (file)
index 0000000..da9821a
--- /dev/null
@@ -0,0 +1,56 @@
+<!--
+  ============LICENSE_START=======================================================
+  Copyright (C) 2020 AT&T Intellectual Property. 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.
+
+  SPDX-License-Identifier: Apache-2.0
+  ============LICENSE_END=========================================================
+-->
+
+<configuration scan="true" scanPeriod="30 seconds" debug="false">
+
+    <contextName>Simulators</contextName>
+    <statusListener class="ch.qos.logback.core.status.OnConsoleStatusListener" />
+    <property name="logDir" value="${POLICY_LOGS}" />
+
+    <appender name="DebugOut"
+        class="ch.qos.logback.core.rolling.RollingFileAppender">
+        <file>${logDir}/debug.log</file>
+        <rollingPolicy
+            class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
+            <fileNamePattern>${logDir}/debug.%d{yyyy-MM-dd}.%i.log.zip
+            </fileNamePattern>
+            <maxFileSize>50MB</maxFileSize>
+            <maxHistory>10</maxHistory>
+            <totalSizeCap>500MB</totalSizeCap>
+        </rollingPolicy>
+        <encoder>
+            <Pattern>%d %contextName [%t] %level %logger{36} - %msg%n
+            </Pattern>
+        </encoder>
+    </appender>
+
+    <root level="info">
+        <appender-ref ref="DebugOut" />
+    </root>
+
+    <logger name="org.eclipse.jetty" level="info" additivity="false">
+        <appender-ref ref="DebugOut" />
+    </logger>
+
+    <logger name="org.onap.policy.models.sim.dmaap" level="debug" additivity="false">
+        <appender-ref ref="DebugOut" />
+    </logger>
+
+</configuration>
diff --git a/models-sim/policy-models-simulators/src/main/resources/ssl/policy-keystore b/models-sim/policy-models-simulators/src/main/resources/ssl/policy-keystore
new file mode 100644 (file)
index 0000000..144caf2
Binary files /dev/null and b/models-sim/policy-models-simulators/src/main/resources/ssl/policy-keystore differ
diff --git a/models-sim/policy-models-simulators/src/main/resources/ssl/policy-truststore b/models-sim/policy-models-simulators/src/main/resources/ssl/policy-truststore
new file mode 100644 (file)
index 0000000..8834ac2
Binary files /dev/null and b/models-sim/policy-models-simulators/src/main/resources/ssl/policy-truststore differ
diff --git a/models-sim/policy-models-simulators/src/test/java/org/onap/policy/models/simulators/ClassRestServerParametersTest.java b/models-sim/policy-models-simulators/src/test/java/org/onap/policy/models/simulators/ClassRestServerParametersTest.java
new file mode 100644 (file)
index 0000000..7663761
--- /dev/null
@@ -0,0 +1,48 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP
+ * ================================================================================
+ * Copyright (C) 2020 AT&T Intellectual Property. 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.onap.policy.models.simulators;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+
+import java.io.File;
+import org.junit.Test;
+import org.onap.policy.common.parameters.ValidationResult;
+import org.onap.policy.common.utils.coder.CoderException;
+import org.onap.policy.common.utils.coder.StandardCoder;
+
+public class ClassRestServerParametersTest {
+
+    @Test
+    public void testValidateString() throws CoderException {
+        // some fields missing
+        ValidationResult result = new ClassRestServerParameters().validate("InvalidParams");
+        assertFalse(result.isValid());
+        assertNotNull(result.getResult());
+
+        // everything populated
+        SimulatorParameters simParams = new StandardCoder()
+                        .decode(new File("src/test/resources/simParameters.json"), SimulatorParameters.class);
+        ClassRestServerParameters params = simParams.getRestServers().get(0);
+        assertNull(params.validate("ValidParams").getResult());
+    }
+}
diff --git a/models-sim/policy-models-simulators/src/test/java/org/onap/policy/models/simulators/MainTest.java b/models-sim/policy-models-simulators/src/test/java/org/onap/policy/models/simulators/MainTest.java
new file mode 100644 (file)
index 0000000..e9e8cbd
--- /dev/null
@@ -0,0 +1,256 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP
+ * ================================================================================
+ * Copyright (C) 2020 AT&T Intellectual Property. 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.onap.policy.models.simulators;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
+import static org.assertj.core.api.Assertions.assertThatThrownBy;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import java.io.FileNotFoundException;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Properties;
+import java.util.concurrent.LinkedBlockingQueue;
+import java.util.concurrent.TimeUnit;
+import javax.ws.rs.core.Response;
+import org.junit.After;
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.onap.policy.common.endpoints.event.comm.bus.internal.BusTopicParams;
+import org.onap.policy.common.endpoints.http.client.HttpClient;
+import org.onap.policy.common.endpoints.http.client.HttpClientConfigException;
+import org.onap.policy.common.endpoints.http.client.HttpClientFactoryInstance;
+import org.onap.policy.common.endpoints.http.server.HttpServletServer;
+import org.onap.policy.common.endpoints.http.server.internal.JettyJerseyServer;
+import org.onap.policy.common.utils.coder.Coder;
+import org.onap.policy.common.utils.coder.CoderException;
+import org.onap.policy.common.utils.network.NetworkUtil;
+
+public class MainTest {
+    private static final String PARAMETER_FILE = "simParameters.json";
+    private static final String HOST = "localhost";
+    private static final String EXPECTED_EXCEPTION = "expected exception";
+
+    private static Map<String, String> savedValues;
+
+    /**
+     * Saves system properties.
+     */
+    @BeforeClass
+    public static void setUpBeforeClass() {
+        savedValues = new HashMap<>();
+
+        for (String prop : List.of(JettyJerseyServer.SYSTEM_KEYSTORE_PASSWORD_PROPERTY_NAME,
+                        JettyJerseyServer.SYSTEM_KEYSTORE_PROPERTY_NAME,
+                        JettyJerseyServer.SYSTEM_TRUSTSTORE_PASSWORD_PROPERTY_NAME,
+                        JettyJerseyServer.SYSTEM_TRUSTSTORE_PROPERTY_NAME)) {
+
+            savedValues.put(prop, System.getProperty(prop));
+        }
+
+        System.setProperty(JettyJerseyServer.SYSTEM_KEYSTORE_PROPERTY_NAME, "src/test/resources/keystore-test");
+        System.setProperty(JettyJerseyServer.SYSTEM_KEYSTORE_PASSWORD_PROPERTY_NAME, "kstest");
+
+        System.setProperty(JettyJerseyServer.SYSTEM_TRUSTSTORE_PROPERTY_NAME, "src/test/resources/keystore-test");
+        System.setProperty(JettyJerseyServer.SYSTEM_TRUSTSTORE_PASSWORD_PROPERTY_NAME, "kstest");
+    }
+
+    /**
+     * Restores system properties.
+     */
+    @AfterClass
+    public static void tearDownAfterClass() {
+        for (Entry<String, String> ent : savedValues.entrySet()) {
+            if (ent.getValue() == null) {
+                System.getProperties().remove(ent.getKey());
+            } else {
+                System.setProperty(ent.getKey(), ent.getValue());
+            }
+        }
+    }
+
+    /**
+     * Shuts down the simulator instance.
+     */
+    @After
+    public void tearDown() {
+        Main main = Main.getInstance();
+        if (main != null && main.isAlive()) {
+            main.shutdown();
+        }
+    }
+
+    @Test
+    public void testConstructor() throws Exception {
+        assertThatIllegalArgumentException().isThrownBy(() -> new Main("invalidSimParameters.json"))
+                        .withMessage("invalid simulator parameters");
+    }
+
+    /**
+     * Verifies that all of the simulators are brought up and that HTTPS works with at
+     * least one of them.
+     */
+    @Test
+    public void testMain() throws Exception {
+        Main.main(new String[0]);
+        assertTrue(Main.getInstance() == null || !Main.getInstance().isAlive());
+
+        Main.main(new String[] {PARAMETER_FILE});
+
+        // don't need to wait long, because buildXxx() does the wait for us
+        for (int port = 6666; port <= 6670; ++port) {
+            assertTrue("simulator on port " + port, NetworkUtil.isTcpPortOpen(HOST, port, 1, 100));
+        }
+
+        // it's sufficient to verify that one of the simulators works
+        checkAai();
+    }
+
+    private void checkAai() throws HttpClientConfigException {
+        BusTopicParams params = BusTopicParams.builder().clientName("client").hostname(HOST).port(6666).useHttps(true)
+                        .allowSelfSignedCerts(true).basePath("aai").build();
+        HttpClient client = HttpClientFactoryInstance.getClientFactory().build(params);
+
+        Response response = client.get("/v8/network/generic-vnfs/generic-vnf/my-vnf");
+        assertEquals(200, response.getStatus());
+
+        String result = response.readEntity(String.class);
+        assertThat(result).contains("USUCP0PCOIL0110UJZZ01-vsrx");
+    }
+
+    /**
+     * Tests readParameters() when the file cannot be found.
+     */
+    @Test
+    public void testReadParametersNoFile() {
+        assertThatIllegalArgumentException().isThrownBy(() -> new Main("missing-file.json"))
+                        .withCauseInstanceOf(FileNotFoundException.class);
+    }
+
+    /**
+     * Tests readParameters() when the json cannot be decoded.
+     */
+    @Test
+    public void testReadParametersInvalidJson() throws CoderException {
+        Coder coder = mock(Coder.class);
+        when(coder.decode(any(String.class), any())).thenThrow(new CoderException(EXPECTED_EXCEPTION));
+
+        assertThatIllegalArgumentException().isThrownBy(() -> new Main(PARAMETER_FILE) {
+            @Override
+            protected Coder makeCoder() {
+                return coder;
+            }
+        }).withCauseInstanceOf(CoderException.class);
+    }
+
+    /**
+     * Tests buildRestServer() when the server port is not open.
+     */
+    @Test
+    public void testBuildRestServerNotOpen() {
+        HttpServletServer server = mock(HttpServletServer.class);
+
+        Main main = new Main(PARAMETER_FILE) {
+            @Override
+            protected HttpServletServer makeServer(Properties props) {
+                return server;
+            }
+
+            @Override
+            protected boolean isTcpPortOpen(String hostName, int port) throws InterruptedException {
+                return false;
+            }
+        };
+
+        assertThatThrownBy(main::start).hasCauseInstanceOf(IllegalStateException.class);
+    }
+
+    /**
+     * Tests buildRestServer() when the port checker is interrupted.
+     */
+    @Test
+    public void testBuildRestServerInterrupted() throws InterruptedException {
+        HttpServletServer server = mock(HttpServletServer.class);
+
+        Main main = new Main(PARAMETER_FILE) {
+            @Override
+            protected HttpServletServer makeServer(Properties props) {
+                return server;
+            }
+
+            @Override
+            protected boolean isTcpPortOpen(String hostName, int port) throws InterruptedException {
+                throw new InterruptedException(EXPECTED_EXCEPTION);
+            }
+        };
+
+        // run in another thread so we don't interrupt this thread
+        LinkedBlockingQueue<RuntimeException> queue = new LinkedBlockingQueue<>();
+        Thread thread = new Thread(() -> {
+            try {
+                main.start();
+            } catch (RuntimeException e) {
+                queue.add(e);
+            }
+        });
+
+        thread.setDaemon(true);
+        thread.start();
+
+        RuntimeException ex = queue.poll(5, TimeUnit.SECONDS);
+        assertNotNull(ex);
+        assertTrue(ex.getCause() instanceof IllegalStateException);
+        assertThat(ex.getCause()).hasMessageStartingWith("interrupted while building");
+    }
+
+    /**
+     * Tests buildTopicServer() when the provider class is invalid.
+     */
+    @Test
+    public void testBuildTopicServerInvalidProvider() {
+        assertThatThrownBy(() -> new Main("invalidTopicServer.json").start());
+    }
+
+    /**
+     * Tests buildTopicServer() when the sink is missing.
+     */
+    @Test
+    public void testBuildTopicServerNoSink() {
+        assertThatThrownBy(() -> new Main("missingSink.json").start());
+    }
+
+    /**
+     * Tests buildTopicServer() when the sink is missing.
+     */
+    @Test
+    public void testBuildTopicServerNoSource() {
+        assertThatThrownBy(() -> new Main("missingSource.json").start());
+    }
+}
diff --git a/models-sim/policy-models-simulators/src/test/java/org/onap/policy/models/simulators/SimulatorParametersTest.java b/models-sim/policy-models-simulators/src/test/java/org/onap/policy/models/simulators/SimulatorParametersTest.java
new file mode 100644 (file)
index 0000000..5294ca4
--- /dev/null
@@ -0,0 +1,47 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP
+ * ================================================================================
+ * Copyright (C) 2020 AT&T Intellectual Property. 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.onap.policy.models.simulators;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+
+import java.io.File;
+import org.junit.Test;
+import org.onap.policy.common.parameters.BeanValidationResult;
+import org.onap.policy.common.utils.coder.CoderException;
+import org.onap.policy.common.utils.coder.StandardCoder;
+
+public class SimulatorParametersTest {
+
+    @Test
+    public void testValidate() throws CoderException {
+        // some fields missing
+        BeanValidationResult result = new SimulatorParameters().validate("InvalidParams");
+        assertFalse(result.isValid());
+        assertNotNull(result.getResult());
+
+        // everything populated
+        SimulatorParameters params = new StandardCoder().decode(new File("src/test/resources/simParameters.json"),
+                        SimulatorParameters.class);
+        assertNull(params.validate("ValidParams").getResult());
+    }
+}
diff --git a/models-sim/policy-models-simulators/src/test/java/org/onap/policy/models/simulators/TopicServerParametersTest.java b/models-sim/policy-models-simulators/src/test/java/org/onap/policy/models/simulators/TopicServerParametersTest.java
new file mode 100644 (file)
index 0000000..2d182d8
--- /dev/null
@@ -0,0 +1,48 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP
+ * ================================================================================
+ * Copyright (C) 2020 AT&T Intellectual Property. 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.onap.policy.models.simulators;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+
+import java.io.File;
+import org.junit.Test;
+import org.onap.policy.common.parameters.ValidationResult;
+import org.onap.policy.common.utils.coder.CoderException;
+import org.onap.policy.common.utils.coder.StandardCoder;
+
+public class TopicServerParametersTest {
+
+    @Test
+    public void testValidateString() throws CoderException {
+        // some fields missing
+        ValidationResult result = new TopicServerParameters().validate("InvalidParams");
+        assertFalse(result.isValid());
+        assertNotNull(result.getResult());
+
+        // everything populated
+        SimulatorParameters simParams = new StandardCoder()
+                        .decode(new File("src/test/resources/simParameters.json"), SimulatorParameters.class);
+        TopicServerParameters params = simParams.getTopicServers().get(0);
+        assertNull(params.validate("ValidParams").getResult());
+    }
+}
diff --git a/models-sim/policy-models-simulators/src/test/resources/invalidSimParameters.json b/models-sim/policy-models-simulators/src/test/resources/invalidSimParameters.json
new file mode 100644 (file)
index 0000000..2c63c08
--- /dev/null
@@ -0,0 +1,2 @@
+{
+}
diff --git a/models-sim/policy-models-simulators/src/test/resources/invalidTopicServer.json b/models-sim/policy-models-simulators/src/test/resources/invalidTopicServer.json
new file mode 100644 (file)
index 0000000..b3d31f6
--- /dev/null
@@ -0,0 +1,35 @@
+{
+    "dmaapProvider": {
+        "name": "DMaaP simulator",
+        "topicSweepSec": 300,
+        "restServerParameters": {
+
+        }
+    },
+    "topicSinks": [
+        {
+            "topic": "APPC-LCM-READ",
+            "servers": ["localhost"],
+            "port": 3905,
+            "topicCommInfrastructure": "DMAAP",
+            "https": true
+        }
+    ],
+    "topicSources": [
+        {
+            "topic": "APPC-LCM-WRITE",
+            "servers": ["localhost"],
+            "port": 3905,
+            "topicCommInfrastructure": "DMAAP",
+            "https": true
+        }
+    ],
+    "topicServers": [
+        {
+            "name": "Invalid Topic simulator",
+            "providerClass": "org.onap.policy.simulators.InvalidTopicServer",
+            "sink": "APPC-LCM-READ",
+            "source": "APPC-LCM-WRITE"
+        }
+    ]
+}
diff --git a/models-sim/policy-models-simulators/src/test/resources/keystore-test b/models-sim/policy-models-simulators/src/test/resources/keystore-test
new file mode 100644 (file)
index 0000000..5820e0f
Binary files /dev/null and b/models-sim/policy-models-simulators/src/test/resources/keystore-test differ
diff --git a/models-sim/policy-models-simulators/src/test/resources/logback-test.xml b/models-sim/policy-models-simulators/src/test/resources/logback-test.xml
new file mode 100644 (file)
index 0000000..e599a94
--- /dev/null
@@ -0,0 +1,49 @@
+<!--
+  ============LICENSE_START=======================================================
+  Copyright (C) 2020 AT&T Intellectual Property. 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.
+
+  SPDX-License-Identifier: Apache-2.0
+  ============LICENSE_END=========================================================
+-->
+
+<configuration scan="true" scanPeriod="30 seconds"
+    debug="false">
+
+    <contextName>Simulators</contextName>
+    <statusListener
+        class="ch.qos.logback.core.status.OnConsoleStatusListener" />
+
+    <!-- USE FOR STD OUT ONLY -->
+    <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
+        <encoder>
+            <Pattern>%d %contextName [%t] %level %logger{36} - %msg%n</Pattern>
+        </encoder>
+    </appender>
+
+    <root level="info">
+        <appender-ref ref="STDOUT" />
+    </root>
+
+    <logger name="org.eclipse.jetty" level="info"
+        additivity="false">
+        <appender-ref ref="STDOUT" />
+    </logger>
+
+    <logger name="org.onap.policy.models.sim.dmaap" level="debug"
+        additivity="false">
+        <appender-ref ref="STDOUT" />
+    </logger>
+
+</configuration>
diff --git a/models-sim/policy-models-simulators/src/test/resources/missingSink.json b/models-sim/policy-models-simulators/src/test/resources/missingSink.json
new file mode 100644 (file)
index 0000000..e7d63e0
--- /dev/null
@@ -0,0 +1,26 @@
+{
+    "dmaapProvider": {
+        "name": "DMaaP simulator",
+        "topicSweepSec": 300,
+        "restServerParameters": {
+
+        }
+    },
+    "topicSources": [
+        {
+            "topic": "APPC-LCM-WRITE",
+            "servers": ["localhost"],
+            "port": 3905,
+            "topicCommInfrastructure": "DMAAP",
+            "https": true
+        }
+    ],
+    "topicServers": [
+        {
+            "name": "APPC-LCM simulator",
+            "providerClass": "org.onap.policy.simulators.AppcLcmTopicServer",
+            "sink": "APPC-LCM-READ",
+            "source": "APPC-LCM-WRITE"
+        }
+    ]
+}
diff --git a/models-sim/policy-models-simulators/src/test/resources/missingSource.json b/models-sim/policy-models-simulators/src/test/resources/missingSource.json
new file mode 100644 (file)
index 0000000..0f02e40
--- /dev/null
@@ -0,0 +1,26 @@
+{
+    "dmaapProvider": {
+        "name": "DMaaP simulator",
+        "topicSweepSec": 300,
+        "restServerParameters": {
+
+        }
+    },
+    "topicSinks": [
+        {
+            "topic": "APPC-LCM-READ",
+            "servers": ["localhost"],
+            "port": 3905,
+            "topicCommInfrastructure": "DMAAP",
+            "https": true
+        }
+    ],
+    "topicServers": [
+        {
+            "name": "APPC-LCM simulator",
+            "providerClass": "org.onap.policy.simulators.AppcLcmTopicServer",
+            "sink": "APPC-LCM-READ",
+            "source": "APPC-LCM-WRITE"
+        }
+    ]
+}
diff --git a/models-sim/policy-models-simulators/src/test/resources/simParameters.json b/models-sim/policy-models-simulators/src/test/resources/simParameters.json
new file mode 100644 (file)
index 0000000..c7abb29
--- /dev/null
@@ -0,0 +1,95 @@
+{
+    "dmaapProvider": {
+        "name": "DMaaP simulator",
+        "topicSweepSec": 300,
+        "restServerParameters": {
+
+        }
+    },
+    "restServers": [
+        {
+            "name": "DMaaP simulator",
+            "providerClass": "org.onap.policy.models.sim.dmaap.rest.DmaapSimRestControllerV1",
+            "host": "localhost",
+            "port": 3905,
+            "https": true
+        },
+        {
+            "name": "A&AI simulator",
+            "providerClass": "org.onap.policy.simulators.AaiSimulatorJaxRs",
+            "host": "localhost",
+            "port": 6666,
+            "https": true
+        },
+        {
+            "name": "Guard simulator",
+            "providerClass": "org.onap.policy.simulators.GuardSimulatorJaxRs",
+            "host": "localhost",
+            "port": 6667,
+            "https": true
+        },
+        {
+            "name": "SDNC simulator",
+            "providerClass": "org.onap.policy.simulators.SdncSimulatorJaxRs",
+            "host": "localhost",
+            "port": 6668,
+            "https": true
+        },
+        {
+            "name": "SO simulator",
+            "providerClass": "org.onap.policy.simulators.SoSimulatorJaxRs",
+            "host": "localhost",
+            "port": 6669,
+            "https": true
+        },
+        {
+            "name": "VFC simulator",
+            "providerClass": "org.onap.policy.simulators.VfcSimulatorJaxRs",
+            "host": "localhost",
+            "port": 6670,
+            "https": true
+        }
+    ],
+    "topicSinks": [
+        {
+            "topic": "APPC-CL",
+            "servers": ["localhost"],
+            "topicCommInfrastructure": "DMAAP",
+            "useHttps": true
+        },
+        {
+            "topic": "APPC-LCM-READ",
+            "servers": ["localhost"],
+            "topicCommInfrastructure": "DMAAP",
+            "useHttps": true
+        }
+    ],
+    "topicSources": [
+        {
+            "topic": "APPC-CL",
+            "servers": ["localhost"],
+            "topicCommInfrastructure": "DMAAP",
+            "useHttps": true
+        },
+        {
+            "topic": "APPC-LCM-WRITE",
+            "servers": ["localhost"],
+            "topicCommInfrastructure": "DMAAP",
+            "useHttps": true
+        }
+    ],
+    "topicServers": [
+        {
+            "name": "APPC Legacy simulator",
+            "providerClass": "org.onap.policy.simulators.AppcLegacyTopicServer",
+            "sink": "APPC-CL",
+            "source": "APPC-CL"
+        },
+        {
+            "name": "APPC-LCM simulator",
+            "providerClass": "org.onap.policy.simulators.AppcLcmTopicServer",
+            "sink": "APPC-LCM-READ",
+            "source": "APPC-LCM-WRITE"
+        }
+    ]
+}
index 5bcb878..213ff1f 100644 (file)
@@ -39,5 +39,6 @@
   <modules>
       <module>models-sim-dmaap</module>
       <module>policy-models-sim-pdp</module>
+      <module>policy-models-simulators</module>
   </modules>
 </project>