Add pnf simulator

Issue-ID: INT-458
Change-Id: I6fd6b58e5d302d83e4b4e1d1dfd59247a6df9700
Signed-off-by: Pawel Kadlubanski <pawel.kadlubanski@nokia.com>
diff --git a/test/mocks/pnfsimulator/README.md b/test/mocks/pnfsimulator/README.md
new file mode 100644
index 0000000..5b9871a
--- /dev/null
+++ b/test/mocks/pnfsimulator/README.md
@@ -0,0 +1,2 @@
+# pnf-simulator
+Generate VES event related to PNF integration.
diff --git a/test/mocks/pnfsimulator/body.json b/test/mocks/pnfsimulator/body.json
new file mode 100644
index 0000000..e0de14a
--- /dev/null
+++ b/test/mocks/pnfsimulator/body.json
@@ -0,0 +1,18 @@
+{
+"testDuration": "10",
+"messageInterval": "1",
+"pnfSerialNumber": "val1",
+"pnfVendorName": "val2",
+"pnfOamIpv4Address": "val3",
+"pnfOamIpv6Address": "val4",
+"pnfFamily": "val5",
+"pnfModelNumber": "val6",
+"pnfSoftwareVersion": "val7",
+"pnfType": "val8",
+"eventName": "val9",
+"nfNamingCode": "val10",
+"nfcNamingCode": "val11",
+"sourceName": "val12",
+"sourceId": "val13",
+"reportingEntityName": "val14"
+}
diff --git a/test/mocks/pnfsimulator/pom.xml b/test/mocks/pnfsimulator/pom.xml
new file mode 100644
index 0000000..4b39d75
--- /dev/null
+++ b/test/mocks/pnfsimulator/pom.xml
@@ -0,0 +1,154 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<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.oparent</groupId>
+        <artifactId>oparent</artifactId>
+        <version>0.1.1</version>
+    </parent>
+
+    <groupId>org.onap.pnfsimulator</groupId>
+    <artifactId>pnf-simulator</artifactId>
+    <version>1.0-SNAPSHOT</version>
+
+    <name>pnf-simulator</name>
+
+    <properties>
+        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+        <maven.compiler.source>1.8</maven.compiler.source>
+        <maven.compiler.target>1.8</maven.compiler.target>
+        <simulator.main.class>org.onap.pnfsimulator.Main</simulator.main.class>
+        <dependency.directory.name>libs</dependency.directory.name>
+        <dependency.directory.location>${project.build.directory}/${dependency.directory.name}</dependency.directory.location>
+        <onap.nexus.dockerregistry.daily>nexus3.onap.org:10003</onap.nexus.dockerregistry.daily>
+    </properties>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.apache.logging.log4j</groupId>
+            <artifactId>log4j-core</artifactId>
+            <version>2.11.0</version>
+        </dependency>
+        <dependency>
+            <groupId>commons-io</groupId>
+            <artifactId>commons-io</artifactId>
+            <version>2.6</version>
+        </dependency>
+        <dependency>
+            <groupId>org.json</groupId>
+            <artifactId>json</artifactId>
+            <version>20180130</version>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.httpcomponents</groupId>
+            <artifactId>httpclient</artifactId>
+            <version>4.5.5</version>
+        </dependency>
+        <dependency>
+            <groupId>com.google.guava</groupId>
+            <artifactId>guava</artifactId>
+            <version>21.0</version>
+        </dependency>
+        <dependency>
+            <groupId>commons-cli</groupId>
+            <artifactId>commons-cli</artifactId>
+            <version>1.4</version>
+        </dependency>
+        <dependency>
+            <groupId>org.junit.jupiter</groupId>
+            <artifactId>junit-jupiter-engine</artifactId>
+            <version>5.1.1</version>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.assertj</groupId>
+            <artifactId>assertj-core</artifactId>
+            <version>3.9.1</version>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.commons</groupId>
+            <artifactId>commons-lang3</artifactId>
+            <version>3.7</version>
+        </dependency>
+    </dependencies>
+
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-compiler-plugin</artifactId>
+                <configuration>
+                    <source>${maven.compiler.source}</source>
+                    <target>${maven.compiler.target}</target>
+                    <showWarnings>true</showWarnings>
+                    <showDeprecation>true</showDeprecation>
+                </configuration>
+            </plugin>
+            <plugin>
+                <artifactId>maven-surefire-plugin</artifactId>
+                <version>2.19</version>
+                <dependencies>
+                    <dependency>
+                        <groupId>org.junit.platform</groupId>
+                        <artifactId>junit-platform-surefire-provider</artifactId>
+                        <version>1.1.1</version>
+                    </dependency>
+                </dependencies>
+                <configuration>
+                    <detail>true</detail>
+                    <printSummary>true</printSummary>
+                </configuration>
+            </plugin>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-dependency-plugin</artifactId>
+                <configuration>
+                    <outputDirectory>${dependency.directory.location}</outputDirectory>
+                    <includeScope>runtime</includeScope>
+                    <silent>true</silent>
+                </configuration>
+                <executions>
+                    <execution>
+                        <id>copy-external-dependencies</id>
+                        <phase>package</phase>
+                        <goals>
+                            <goal>copy-dependencies</goal>
+                        </goals>
+                    </execution>
+                </executions>
+            </plugin>
+            <plugin>
+                <groupId>com.spotify</groupId>
+                <artifactId>docker-maven-plugin</artifactId>
+                <configuration>
+                <skipDockerBuild>false</skipDockerBuild>
+                <imageName>
+                    ${onap.nexus.dockerregistry.daily}/onap/${project.groupId}.${project.artifactId}
+                </imageName>
+                <cmd>java -cp ${dependency.directory.name}/*:${project.build.finalName}.jar ${simulator.main.class}
+                </cmd>
+                <resources>
+                    <resource>
+                        <targetPath>${dependency.directory.name}</targetPath>
+                        <directory>${dependency.directory.location}</directory>
+                    </resource>
+                    <resource>
+                        <targetPath>/</targetPath>
+                        <directory>${project.build.directory}</directory>
+                        <include>${project.build.finalName}.jar</include>
+                    </resource>
+                </resources>
+                <imageTags>
+                    <imageTag>${project.version}-SNAPSHOT-${maven.build.timestamp}Z</imageTag>
+                    <imageTag>${project.version}</imageTag>
+                    <imageTag>latest</imageTag>
+                </imageTags>
+                <serverId>${onap.nexus.dockerregistry.daily}</serverId>
+            </plugin>
+        </plugins>
+    </build>
+</project>
diff --git a/test/mocks/pnfsimulator/simulator.sh b/test/mocks/pnfsimulator/simulator.sh
new file mode 100755
index 0000000..27384dd
--- /dev/null
+++ b/test/mocks/pnfsimulator/simulator.sh
@@ -0,0 +1,108 @@
+#!/usr/bin/env bash
+
+set -euo pipefail
+
+CONTAINER_NAME=pnf-simulator
+CONFIG_FILE_PATH=/config/body.json
+SIMULATOR_DOCKER_HUB=hub-name
+SIMULATOR_TAG=latest
+
+function main(){
+
+    COMMAND=${1:-"help"}
+
+    case $COMMAND in
+        "build")
+            build_image;;
+        "start")
+            start_simulator $2 $CONFIG_FILE_PATH $SIMULATOR_DOCKER_HUB/pnf-simulator:$SIMULATOR_TAG;;
+        "start-dev")
+            start_simulator $2 $CONFIG_FILE_PATH pnf-simulator:$SIMULATOR_TAG;;
+        "stop")
+            stop_simulator;;
+        "status")
+            print_status;;
+        "logs")
+            get_logs;;
+        "help")
+            print_help;;
+        *)
+            print_help;;
+    esac
+}
+
+function build_image(){
+    if [ -f pom.xml ]; then
+        mvn clean package
+    else
+        echo "pom.xml file not found"
+        exit 1
+    fi
+}
+
+function start_simulator(){
+
+    stop_and_remove_container || true
+
+    if [ $(docker run -d --name $CONTAINER_NAME -v $(pwd):/config -e VES_ADDRESS=$1 -e CONFIG_FILE_PATH=$2 $3) > /dev/null ]; then
+        echo "Simulator started"
+    else
+        echo "Failed to start simulator"
+    fi
+}
+
+function stop_and_remove_container(){
+    docker rm -f $CONTAINER_NAME 1> /dev/null
+}
+
+function stop_simulator(){
+    if [ $(docker kill $CONTAINER_NAME) > /dev/null ]; then
+        echo "Simulator stopped"
+    else
+        echo "Failed to stop simulator"
+    fi
+
+}
+
+function print_status(){
+cat << EndOfMessage
+
+Simulator container status:
+
+$(docker ps -a -f name=$CONTAINER_NAME)
+
+EndOfMessage
+}
+
+function print_help(){
+cat << EndOfMessage
+
+Available options:
+build - locally builds simulator image from existing code
+start <ves-url> - starts simulator using remote docker image and connects to given VES server
+start-dev <ves-url> - starts simulator using local docker image and connects to given VES server
+stop - stops simulator
+status - prints container status
+logs - prints logs
+help - prints this message
+
+Starting simulation:
+Use "./simulator.sh start". It will download required docker image from the internet and start simulator using body.json file
+
+To stop simulation use "./simulator.sh stop" command. To check simulator's status use "./simulator.sh status".
+If you want to change message parameters simply edit body.json file then run simulator again.
+
+FOR DEVELOPERS
+1. Build local simulator image using "./simulator.sh build"
+2. Run simulation with "./simulator.sh start-dev"
+
+If you change the source code you have to rebuild image with "./simulator.sh build" and run  "./simulator.sh start-dev" again
+
+EndOfMessage
+}
+
+function get_logs(){
+    docker logs --tail all $CONTAINER_NAME
+}
+
+main $@
\ No newline at end of file
diff --git a/test/mocks/pnfsimulator/src/main/java/org/onap/pnfsimulator/Main.java b/test/mocks/pnfsimulator/src/main/java/org/onap/pnfsimulator/Main.java
new file mode 100644
index 0000000..7dfa686
--- /dev/null
+++ b/test/mocks/pnfsimulator/src/main/java/org/onap/pnfsimulator/Main.java
@@ -0,0 +1,37 @@
+package org.onap.pnfsimulator;
+
+import java.io.IOException;
+import org.apache.commons.cli.ParseException;
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+import org.onap.pnfsimulator.cli.SimulatorParamsProvider;
+import org.onap.pnfsimulator.cli.SimulatorParams;
+import org.onap.pnfsimulator.message.MessageProvider;
+import org.onap.pnfsimulator.simulator.SimulatorFactory;
+import org.onap.pnfsimulator.simulator.validation.ParamsValidator;
+import org.onap.pnfsimulator.simulator.validation.ValidationException;
+
+public class Main {
+
+    private static Logger logger = LogManager.getLogger(Main.class);
+    private static SimulatorFactory simulatorFactory =
+        new SimulatorFactory(MessageProvider.getInstance(), ParamsValidator.getInstance());
+
+    public static void main(String[] args) {
+
+        try {
+
+            SimulatorParams params = new SimulatorParamsProvider().parse(args);
+            simulatorFactory
+                .create(params.getVesAddress(), params.getConfigFilePath())
+                .start();
+
+        } catch (IOException e) {
+            logger.error("Invalid config file format", e);
+        } catch (ParseException e) {
+            logger.error("Invalid cli params", e);
+        } catch (ValidationException e){
+            logger.error("Missing some mandatory params:", e);
+        }
+    }
+}
diff --git a/test/mocks/pnfsimulator/src/main/java/org/onap/pnfsimulator/cli/SimulatorParams.java b/test/mocks/pnfsimulator/src/main/java/org/onap/pnfsimulator/cli/SimulatorParams.java
new file mode 100644
index 0000000..64b3589
--- /dev/null
+++ b/test/mocks/pnfsimulator/src/main/java/org/onap/pnfsimulator/cli/SimulatorParams.java
@@ -0,0 +1,45 @@
+package org.onap.pnfsimulator.cli;
+
+import java.util.Objects;
+
+public class SimulatorParams {
+
+    private String vesAddress;
+    private String configFilePath;
+
+    public SimulatorParams(String vesAddress, String configFilePath) {
+        this.vesAddress = vesAddress;
+        this.configFilePath = configFilePath;
+    }
+
+    public String getVesAddress() {
+        return vesAddress;
+    }
+
+    public String getConfigFilePath() {
+        return configFilePath;
+    }
+
+    @Override
+    public String toString() {
+        return String.format("VES address=%s, Configuration file=%s", vesAddress, configFilePath);
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) {
+            return true;
+        }
+        if (!(o instanceof SimulatorParams)) {
+            return false;
+        }
+        SimulatorParams params = (SimulatorParams) o;
+        return Objects.equals(vesAddress, params.vesAddress) &&
+            Objects.equals(configFilePath, params.configFilePath);
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(vesAddress, configFilePath);
+    }
+}
diff --git a/test/mocks/pnfsimulator/src/main/java/org/onap/pnfsimulator/cli/SimulatorParamsProvider.java b/test/mocks/pnfsimulator/src/main/java/org/onap/pnfsimulator/cli/SimulatorParamsProvider.java
new file mode 100644
index 0000000..fcf5d79
--- /dev/null
+++ b/test/mocks/pnfsimulator/src/main/java/org/onap/pnfsimulator/cli/SimulatorParamsProvider.java
@@ -0,0 +1,41 @@
+package org.onap.pnfsimulator.cli;
+
+import org.apache.commons.cli.CommandLine;
+import org.apache.commons.cli.CommandLineParser;
+import org.apache.commons.cli.DefaultParser;
+import org.apache.commons.cli.Option;
+import org.apache.commons.cli.Options;
+import org.apache.commons.cli.ParseException;
+
+public class SimulatorParamsProvider {
+
+    private static final String CLI_VAR_VES_ADDRESS = "address";
+    private static final String CLI_VAR_CONFIG_FILE_PATH = "config";
+    private static final String ENV_VAR_VES_ADDRESS = "VES_ADDRESS";
+    private static final String ENV_VAR_CONFIG_FILE_PATH = "CONFIG_FILE_PATH";
+
+    private Options options;
+    private CommandLineParser parser;
+
+    public SimulatorParamsProvider() {
+        createOptions();
+        parser = new DefaultParser();
+    }
+
+    public SimulatorParams parse(String[] arg) throws ParseException {
+        CommandLine line = parser.parse(options, arg);
+        return new SimulatorParams(
+            line.getOptionValue(CLI_VAR_VES_ADDRESS, System.getenv().get(ENV_VAR_VES_ADDRESS)),
+            line.getOptionValue(CLI_VAR_CONFIG_FILE_PATH, System.getenv().get(ENV_VAR_CONFIG_FILE_PATH)));
+    }
+
+    private void createOptions() {
+        options = new Options();
+
+        Option vesCollectorUlrOpt = new Option(CLI_VAR_VES_ADDRESS, true, "VES collector URL");
+        options.addOption(vesCollectorUlrOpt);
+
+        Option simulatorConfigFilePathOpt = new Option(CLI_VAR_CONFIG_FILE_PATH, true, "Simulator configuration file location.");
+        options.addOption(simulatorConfigFilePathOpt);
+    }
+}
diff --git a/test/mocks/pnfsimulator/src/main/java/org/onap/pnfsimulator/message/MessageConstants.java b/test/mocks/pnfsimulator/src/main/java/org/onap/pnfsimulator/message/MessageConstants.java
new file mode 100644
index 0000000..77b3727
--- /dev/null
+++ b/test/mocks/pnfsimulator/src/main/java/org/onap/pnfsimulator/message/MessageConstants.java
@@ -0,0 +1,33 @@
+package org.onap.pnfsimulator.message;
+
+public final class MessageConstants {
+
+    public static final String DOMAIN = "domain";
+    public static final String EVENT_ID = "eventId";
+    public static final String EVENT_TYPE = "eventType";
+    public static final String LAST_EPOCH_MICROSEC = "lastEpochMicrosec";
+    public static final String PRIORITY = "priority";
+    public static final String SEQUENCE = "sequence";
+    public static final String START_EPOCH_MICROSEC = "startEpochMicrosec";
+    public static final String INTERNAL_HEADER_FIELDS = "internalHeaderFields";
+    public static final String VERSION = "version";
+    public static final String OTHER_FIELDS_VERSION = "otherFieldsVersion";
+    public static final String PNF_LAST_SERVICE_DATE = "pnfLastServiceDate";
+    public static final String PNF_MANUFACTURE_DATE = "pnfManufactureDate";
+
+    // mandatory
+    public static final String PNF_OAM_IPV4_ADDRESS = "pnfOamIpv4Address";
+    public static final String PNF_OAM_IPV6_ADDRESS = "pnfOamIpv6Address";
+    public static final String PNF_SERIAL_NUMBER = "pnfSerialNumber";
+    public static final String PNF_VENDOR_NAME = "pnfVendorName";
+
+    public static final String PNF_PREFIX = "pnf";
+    public static final String COMMON_EVENT_HEADER = "commonEventHeader";
+    public static final String OTHER_FIELDS = "otherFields";
+    public static final String TEST_DURATION = "testDuration";
+    public static final String MESSAGE_INTERVAL = "messageInterval";
+
+    private MessageConstants() {
+    }
+
+}
diff --git a/test/mocks/pnfsimulator/src/main/java/org/onap/pnfsimulator/message/MessageProvider.java b/test/mocks/pnfsimulator/src/main/java/org/onap/pnfsimulator/message/MessageProvider.java
new file mode 100644
index 0000000..5e8e535
--- /dev/null
+++ b/test/mocks/pnfsimulator/src/main/java/org/onap/pnfsimulator/message/MessageProvider.java
@@ -0,0 +1,88 @@
+package org.onap.pnfsimulator.message;
+
+import static org.onap.pnfsimulator.message.MessageConstants.COMMON_EVENT_HEADER;
+import static org.onap.pnfsimulator.message.MessageConstants.DOMAIN;
+import static org.onap.pnfsimulator.message.MessageConstants.EVENT_ID;
+import static org.onap.pnfsimulator.message.MessageConstants.EVENT_TYPE;
+import static org.onap.pnfsimulator.message.MessageConstants.INTERNAL_HEADER_FIELDS;
+import static org.onap.pnfsimulator.message.MessageConstants.LAST_EPOCH_MICROSEC;
+import static org.onap.pnfsimulator.message.MessageConstants.OTHER_FIELDS;
+import static org.onap.pnfsimulator.message.MessageConstants.OTHER_FIELDS_VERSION;
+import static org.onap.pnfsimulator.message.MessageConstants.PNF_LAST_SERVICE_DATE;
+import static org.onap.pnfsimulator.message.MessageConstants.PNF_MANUFACTURE_DATE;
+import static org.onap.pnfsimulator.message.MessageConstants.PNF_PREFIX;
+import static org.onap.pnfsimulator.message.MessageConstants.PRIORITY;
+import static org.onap.pnfsimulator.message.MessageConstants.SEQUENCE;
+import static org.onap.pnfsimulator.message.MessageConstants.START_EPOCH_MICROSEC;
+import static org.onap.pnfsimulator.message.MessageConstants.VERSION;
+
+import java.util.Map;
+import java.util.UUID;
+
+import com.google.common.base.Preconditions;
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+import org.json.JSONObject;
+
+public class MessageProvider {
+
+    private static MessageProvider instance;
+
+    public static MessageProvider getInstance() {
+        if (instance == null) {
+            instance = new MessageProvider();
+        }
+        return instance;
+    }
+
+    public JSONObject createMessage(JSONObject params) {
+
+        Preconditions.checkArgument(params != null, "Params object cannot be null");
+         Map<String, Object> paramsMap = params.toMap();
+        JSONObject root = new JSONObject();
+        JSONObject commonEventHeader = generateConstantCommonEventHeader();
+        JSONObject otherFields = generateConstantOtherFields();
+
+        paramsMap.forEach((key, value) -> {
+
+            if (key.startsWith(PNF_PREFIX)) {
+                otherFields.put(key, value);
+            } else {
+                commonEventHeader.put(key, value);
+            }
+        });
+
+        root.put(COMMON_EVENT_HEADER, commonEventHeader);
+        root.put(OTHER_FIELDS, otherFields);
+        return root;
+    }
+
+    private JSONObject generateConstantCommonEventHeader() {
+
+        JSONObject commonEventHeader = new JSONObject();
+        long timestamp = System.currentTimeMillis();
+
+        commonEventHeader.put(DOMAIN, "other");
+        commonEventHeader.put(EVENT_ID, UUID.randomUUID() + "-reg");
+        commonEventHeader.put(EVENT_TYPE, "pnfRegistration");
+        commonEventHeader.put(LAST_EPOCH_MICROSEC, timestamp);
+        commonEventHeader.put(PRIORITY, "Normal");
+        commonEventHeader.put(SEQUENCE, 0);
+        commonEventHeader.put(START_EPOCH_MICROSEC, timestamp);
+        commonEventHeader.put(INTERNAL_HEADER_FIELDS, new JSONObject());
+        commonEventHeader.put(VERSION, 3);
+
+        return commonEventHeader;
+    }
+
+    private JSONObject generateConstantOtherFields() {
+
+        JSONObject otherFields = new JSONObject();
+
+        otherFields.put(OTHER_FIELDS_VERSION, 1);
+        otherFields.put(PNF_LAST_SERVICE_DATE, System.currentTimeMillis());
+        otherFields.put(PNF_MANUFACTURE_DATE, System.currentTimeMillis());
+
+        return otherFields;
+    }
+}
diff --git a/test/mocks/pnfsimulator/src/main/java/org/onap/pnfsimulator/simulator/Simulator.java b/test/mocks/pnfsimulator/src/main/java/org/onap/pnfsimulator/simulator/Simulator.java
new file mode 100644
index 0000000..75ce71e
--- /dev/null
+++ b/test/mocks/pnfsimulator/src/main/java/org/onap/pnfsimulator/simulator/Simulator.java
@@ -0,0 +1,45 @@
+package org.onap.pnfsimulator.simulator;
+
+import java.time.Duration;
+import java.time.Instant;
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+import org.json.JSONObject;
+import org.onap.pnfsimulator.simulator.client.HttpClientProvider;
+
+public class Simulator {
+
+    private static final Logger logger = LogManager.getLogger(HttpClientProvider.class);
+    private HttpClientProvider clientProvider;
+    private JSONObject messageBody;
+    private Duration duration;
+    private Duration interval;
+
+    public Simulator(String vesServerUrl, JSONObject messageBody, Duration duration, Duration interval) {
+        this.messageBody = messageBody;
+        this.duration = duration;
+        this.interval = interval;
+        this.clientProvider = new HttpClientProvider(vesServerUrl);
+    }
+
+    public void start() {
+        logger.info("SIMULATOR STARTED - DURATION: {}s, INTERVAL: {}s", duration.getSeconds(), interval.getSeconds());
+
+        Instant endTime = Instant.now().plus(duration);
+        while (runningTimeNotExceeded(endTime)) {
+            try {
+                logger.info("MESSAGE TO BE SENT:\n{}", messageBody.toString(4));
+                clientProvider.sendMsg(messageBody.toString());
+                Thread.sleep(interval.toMillis());
+            } catch (InterruptedException e) {
+                logger.error("SIMULATOR INTERRUPTED");
+                break;
+            }
+        }
+        logger.info("SIMULATOR FINISHED");
+    }
+
+    private boolean runningTimeNotExceeded(Instant endTime) {
+        return Instant.now().isBefore(endTime);
+    }
+}
\ No newline at end of file
diff --git a/test/mocks/pnfsimulator/src/main/java/org/onap/pnfsimulator/simulator/SimulatorFactory.java b/test/mocks/pnfsimulator/src/main/java/org/onap/pnfsimulator/simulator/SimulatorFactory.java
new file mode 100644
index 0000000..c9bd8d7
--- /dev/null
+++ b/test/mocks/pnfsimulator/src/main/java/org/onap/pnfsimulator/simulator/SimulatorFactory.java
@@ -0,0 +1,42 @@
+package org.onap.pnfsimulator.simulator;
+
+import static org.onap.pnfsimulator.message.MessageConstants.MESSAGE_INTERVAL;
+import static org.onap.pnfsimulator.message.MessageConstants.TEST_DURATION;
+
+import java.io.File;
+import java.io.IOException;
+import java.nio.charset.StandardCharsets;
+import java.time.Duration;
+import java.util.List;
+import org.apache.commons.io.FileUtils;
+import org.json.JSONObject;
+import org.onap.pnfsimulator.message.MessageProvider;
+import org.onap.pnfsimulator.simulator.validation.ParamsValidator;
+import org.onap.pnfsimulator.simulator.validation.ValidationException;
+
+public class SimulatorFactory {
+
+    private MessageProvider messageProvider;
+    private ParamsValidator paramsValidator;
+
+    public SimulatorFactory(MessageProvider messageProvider, ParamsValidator paramsValidator) {
+        this.messageProvider = messageProvider;
+        this.paramsValidator = paramsValidator;
+    }
+
+    public Simulator create(String vesServerUrl, String configFilePath) throws IOException, ValidationException {
+
+        String configJson = FileUtils.readFileToString(new File(configFilePath), StandardCharsets.UTF_8);
+        JSONObject configObject = new JSONObject(configJson);
+
+        paramsValidator.validate(configObject);
+        Duration duration = Duration.ofSeconds(parseJsonField(configObject, TEST_DURATION));
+        Duration interval = Duration.ofSeconds(parseJsonField(configObject, MESSAGE_INTERVAL));
+        JSONObject messageBody = messageProvider.createMessage(configObject);
+        return new Simulator(vesServerUrl, messageBody, duration, interval);
+    }
+
+    private int parseJsonField(JSONObject json, String fieldName) {
+        return Integer.parseInt((String) json.remove(fieldName));
+    }
+}
\ No newline at end of file
diff --git a/test/mocks/pnfsimulator/src/main/java/org/onap/pnfsimulator/simulator/client/HttpClientProvider.java b/test/mocks/pnfsimulator/src/main/java/org/onap/pnfsimulator/simulator/client/HttpClientProvider.java
new file mode 100644
index 0000000..a24889c
--- /dev/null
+++ b/test/mocks/pnfsimulator/src/main/java/org/onap/pnfsimulator/simulator/client/HttpClientProvider.java
@@ -0,0 +1,56 @@
+package org.onap.pnfsimulator.simulator.client;
+
+import java.io.IOException;
+import java.io.UnsupportedEncodingException;
+import org.apache.http.HttpResponse;
+import org.apache.http.client.HttpClient;
+import org.apache.http.client.config.RequestConfig;
+import org.apache.http.client.methods.HttpPost;
+import org.apache.http.entity.StringEntity;
+import org.apache.http.impl.client.HttpClientBuilder;
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+
+public class HttpClientProvider {
+
+    private static final Logger logger = LogManager.getLogger(HttpClientProvider.class);
+    private static final String CONTENT_TYPE = "Content-Type";
+    private static final String APPLICATION_JSON = "application/json";
+
+    private HttpClient client;
+    private String url;
+
+    public HttpClientProvider(String url) {
+
+        RequestConfig config = RequestConfig.custom()
+            .setConnectTimeout(1000)
+            .setConnectionRequestTimeout(1000)
+            .setSocketTimeout(1000)
+            .build();
+
+        this.client = HttpClientBuilder
+            .create()
+            .setDefaultRequestConfig(config)
+            .build();
+
+        this.url = url;
+    }
+
+    public void sendMsg(String content) {
+        try {
+            HttpPost request = createRequest(content);
+            HttpResponse response = client.execute(request);
+            logger.info("MESSAGE SENT, VES RESPONSE CODE: {}", response.getStatusLine());
+        } catch (IOException e) {
+            logger.info("ERROR SENDING MESSAGE TO VES: {}", e.getMessage());
+        }
+    }
+
+    private HttpPost createRequest(String content) throws UnsupportedEncodingException {
+        StringEntity stringEntity = new StringEntity(content);
+        HttpPost request = new HttpPost(url);
+        request.addHeader(CONTENT_TYPE, APPLICATION_JSON);
+        request.setEntity(stringEntity);
+        return request;
+    }
+}
diff --git a/test/mocks/pnfsimulator/src/main/java/org/onap/pnfsimulator/simulator/validation/ParamsValidator.java b/test/mocks/pnfsimulator/src/main/java/org/onap/pnfsimulator/simulator/validation/ParamsValidator.java
new file mode 100644
index 0000000..a0fc110
--- /dev/null
+++ b/test/mocks/pnfsimulator/src/main/java/org/onap/pnfsimulator/simulator/validation/ParamsValidator.java
@@ -0,0 +1,82 @@
+package org.onap.pnfsimulator.simulator.validation;
+
+import static org.onap.pnfsimulator.message.MessageConstants.MESSAGE_INTERVAL;
+import static org.onap.pnfsimulator.message.MessageConstants.PNF_OAM_IPV4_ADDRESS;
+import static org.onap.pnfsimulator.message.MessageConstants.PNF_OAM_IPV6_ADDRESS;
+import static org.onap.pnfsimulator.message.MessageConstants.PNF_SERIAL_NUMBER;
+import static org.onap.pnfsimulator.message.MessageConstants.PNF_VENDOR_NAME;
+import static org.onap.pnfsimulator.message.MessageConstants.TEST_DURATION;
+
+import com.google.common.collect.ImmutableMap;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.function.BiPredicate;
+import org.apache.commons.lang3.StringUtils;
+import org.json.JSONObject;
+
+
+public class ParamsValidator {
+
+    private final static String MISSING_PARAMS_ERROR = "Some mandatory params are missing";
+    private static ParamsValidator instance;
+
+
+    public static ParamsValidator getInstance() {
+        if (instance == null) {
+            instance = new ParamsValidator();
+        }
+        return instance;
+    }
+
+    public void validate(JSONObject params) throws ValidationException {
+        ImmutableMap<String, BiPredicate<JSONObject, String>> paramValidators = ImmutableMap
+            .<String, BiPredicate<JSONObject, String>>builder()
+            .put(TEST_DURATION, this::isNotNumeric)
+            .put(MESSAGE_INTERVAL, this::isNotNumeric)
+            .put(PNF_SERIAL_NUMBER, this::nullOrEmpty)
+            .put(PNF_VENDOR_NAME, this::nullOrEmpty)
+            .put(PNF_OAM_IPV4_ADDRESS, this::nullOrEmpty)
+            .put(PNF_OAM_IPV6_ADDRESS, this::nullOrEmpty)
+            .build();
+
+        List<String> missingParams = new ArrayList<>();
+
+        paramValidators.forEach((param, validator) -> {
+            if (validator.test(params, param)) {
+                missingParams.add(param);
+            }
+        });
+
+        clearIPError(missingParams);
+        if (!missingParams.isEmpty()) {
+            throw new ValidationException(constructMessage(missingParams));
+        }
+    }
+
+    private String constructMessage(List<String> missingParams) {
+        StringBuilder msg = new StringBuilder(MISSING_PARAMS_ERROR);
+
+        missingParams.forEach(param -> {
+            msg.append('\n');
+            msg.append(param);
+        });
+
+        return msg.toString();
+    }
+
+    private boolean isNotNumeric(JSONObject params, String param) {
+        return nullOrEmpty(params, param) || !StringUtils.isNumeric(params.getString(param));
+    }
+
+    private boolean nullOrEmpty(JSONObject params, String param) {
+        return !params.has(param) || params.getString(param).isEmpty();
+    }
+
+    private void clearIPError(List<String> missingParams) {
+        // if only one IP is missing clear the error
+        if (!(missingParams.contains(PNF_OAM_IPV4_ADDRESS) && missingParams.contains(PNF_OAM_IPV6_ADDRESS))) {
+            missingParams.remove(PNF_OAM_IPV4_ADDRESS);
+            missingParams.remove(PNF_OAM_IPV6_ADDRESS);
+        }
+    }
+}
diff --git a/test/mocks/pnfsimulator/src/main/java/org/onap/pnfsimulator/simulator/validation/ValidationException.java b/test/mocks/pnfsimulator/src/main/java/org/onap/pnfsimulator/simulator/validation/ValidationException.java
new file mode 100644
index 0000000..9855a78
--- /dev/null
+++ b/test/mocks/pnfsimulator/src/main/java/org/onap/pnfsimulator/simulator/validation/ValidationException.java
@@ -0,0 +1,8 @@
+package org.onap.pnfsimulator.simulator.validation;
+
+public class ValidationException extends Exception {
+
+    public ValidationException(String message) {
+        super(message);
+    }
+}
diff --git a/test/mocks/pnfsimulator/src/main/resources/log4j2.xml b/test/mocks/pnfsimulator/src/main/resources/log4j2.xml
new file mode 100644
index 0000000..250f417
--- /dev/null
+++ b/test/mocks/pnfsimulator/src/main/resources/log4j2.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<Configuration status="WARN">
+    <Properties>
+        <Property name="log4j.logLevel" value="info"/>
+    </Properties>
+    <Appenders>
+        <Console name="Console" target="SYSTEM_OUT">
+            <PatternLayout pattern="%d{ISO8601} +%r [%t] %-5p %c %x - %m%n"/>
+        </Console>
+        <Console name="ColorConsole" target="SYSTEM_OUT">
+            <PatternLayout pattern="%style{%d{ISO8601} +%r}{yellow} %highlight{%-5level}{STYLE=Logback} %style{[%t]}{yellow} %style{%c{1.}}{BRIGHT} %message%n"/>
+        </Console>
+    </Appenders>
+    <Loggers>
+        <Root level="${sys:log4j.logLevel}">
+            <AppenderRef ref="ColorConsole"/>
+        </Root>
+    </Loggers>
+</Configuration>
diff --git a/test/mocks/pnfsimulator/src/test/java/org/onap/pnfsimulator/SimulatorParamsProviderTest.java b/test/mocks/pnfsimulator/src/test/java/org/onap/pnfsimulator/SimulatorParamsProviderTest.java
new file mode 100644
index 0000000..96397ea
--- /dev/null
+++ b/test/mocks/pnfsimulator/src/test/java/org/onap/pnfsimulator/SimulatorParamsProviderTest.java
@@ -0,0 +1,31 @@
+package org.onap.pnfsimulator;
+
+import org.apache.commons.cli.ParseException;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.onap.pnfsimulator.cli.SimulatorParamsProvider;
+import org.onap.pnfsimulator.cli.SimulatorParams;
+
+import static org.assertj.core.api.Assertions.assertThatThrownBy;
+import static org.assertj.core.api.Java6Assertions.assertThat;
+
+public class SimulatorParamsProviderTest {
+
+    SimulatorParamsProvider parser;
+
+    @BeforeEach
+    public void setUp() {
+        parser = new SimulatorParamsProvider();
+    }
+
+    @Test
+    public void whenParserReceiveArgLisWithTwoCorrectParametersShouldReturnCorrectStructOfParams()
+        throws ParseException {
+        String[] arg = new String[]{
+            "-address", "http://localhost:808/eventListner/v5",
+            "-config", "config.json"};
+        SimulatorParams params = parser.parse(arg);
+        assertThat(params.getConfigFilePath()).isEqualToIgnoringCase("config.json");
+        assertThat(params.getVesAddress()).isEqualToIgnoringCase("http://localhost:808/eventListner/v5");
+    }
+}
\ No newline at end of file
diff --git a/test/mocks/pnfsimulator/src/test/java/org/onap/pnfsimulator/SimulatorTest.java b/test/mocks/pnfsimulator/src/test/java/org/onap/pnfsimulator/SimulatorTest.java
new file mode 100644
index 0000000..ccbb728
--- /dev/null
+++ b/test/mocks/pnfsimulator/src/test/java/org/onap/pnfsimulator/SimulatorTest.java
@@ -0,0 +1,12 @@
+package org.onap.pnfsimulator;
+
+import org.assertj.core.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+public class SimulatorTest {
+
+    @Test
+    public void dummyTestToCheckEnvirometn() {
+        Assertions.assertThat(true).isTrue();
+    }
+}
\ No newline at end of file
diff --git a/test/mocks/pnfsimulator/src/test/java/org/onap/pnfsimulator/message/MessageProviderTest.java b/test/mocks/pnfsimulator/src/test/java/org/onap/pnfsimulator/message/MessageProviderTest.java
new file mode 100644
index 0000000..3854057
--- /dev/null
+++ b/test/mocks/pnfsimulator/src/test/java/org/onap/pnfsimulator/message/MessageProviderTest.java
@@ -0,0 +1,110 @@
+package org.onap.pnfsimulator.message;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.onap.pnfsimulator.message.MessageConstants.COMMON_EVENT_HEADER;
+import static org.onap.pnfsimulator.message.MessageConstants.DOMAIN;
+import static org.onap.pnfsimulator.message.MessageConstants.EVENT_ID;
+import static org.onap.pnfsimulator.message.MessageConstants.EVENT_TYPE;
+import static org.onap.pnfsimulator.message.MessageConstants.INTERNAL_HEADER_FIELDS;
+import static org.onap.pnfsimulator.message.MessageConstants.LAST_EPOCH_MICROSEC;
+import static org.onap.pnfsimulator.message.MessageConstants.OTHER_FIELDS;
+import static org.onap.pnfsimulator.message.MessageConstants.OTHER_FIELDS_VERSION;
+import static org.onap.pnfsimulator.message.MessageConstants.PNF_LAST_SERVICE_DATE;
+import static org.onap.pnfsimulator.message.MessageConstants.PNF_MANUFACTURE_DATE;
+import static org.onap.pnfsimulator.message.MessageConstants.PRIORITY;
+import static org.onap.pnfsimulator.message.MessageConstants.SEQUENCE;
+import static org.onap.pnfsimulator.message.MessageConstants.START_EPOCH_MICROSEC;
+import static org.onap.pnfsimulator.message.MessageConstants.VERSION;
+
+import java.util.UUID;
+import org.json.JSONObject;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.Test;
+
+public class MessageProviderTest {
+
+    private static final String testParamsJson =
+        "{\"key1\": \"val1\",\"key2\": \"val2\",\"pnfKey3\": \"pnfVal3\",\"key4\": \"val4\"}";
+
+    private static MessageProvider messageProvider;
+
+    @BeforeAll
+    public static void setup() {
+        messageProvider = MessageProvider.getInstance();
+    }
+
+    @Test
+    public void createMessage_should_throw_when_given_null_argument() {
+        assertThrows(IllegalArgumentException.class,
+            () -> messageProvider.createMessage(null),
+            "Params object cannot be null");
+    }
+
+    @Test
+    public void createMessage_should_create_constant_message_when_no_params_specified() {
+        JSONObject message = messageProvider.createMessage(new JSONObject());
+
+        JSONObject commonEventHeader = message.getJSONObject(COMMON_EVENT_HEADER);
+        JSONObject otherFields = message.getJSONObject(OTHER_FIELDS);
+
+        JSONObject expectedCommonEventHeader = generateConstantCommonEventHeader();
+        JSONObject expectedOtherFields = generateConstantOtherFields();
+
+        expectedCommonEventHeader
+            .toMap()
+            .forEach((key, val) -> assertTrue(commonEventHeader.has(key),
+                () -> String.format("Key %s is not present", key)));
+
+        expectedOtherFields
+            .toMap()
+            .forEach((key, val) -> assertTrue(otherFields.has(key),
+                () -> String.format("Key %s is not present", key)));
+    }
+
+
+    @Test
+    public void createMessage_should_add_specified_params_to_valid_subobjects() {
+        JSONObject params = new JSONObject(testParamsJson);
+        JSONObject message = messageProvider.createMessage(params);
+
+        JSONObject commonEventHeader = message.getJSONObject(COMMON_EVENT_HEADER);
+        JSONObject otherFields = message.getJSONObject(OTHER_FIELDS);
+
+        assertEquals("pnfVal3", otherFields.getString("pnfKey3"));
+        assertEquals("val1", commonEventHeader.getString("key1"));
+        assertEquals("val2", commonEventHeader.getString("key2"));
+        assertEquals("val4", commonEventHeader.getString("key4"));
+    }
+
+
+    private JSONObject generateConstantCommonEventHeader() {
+
+        JSONObject commonEventHeader = new JSONObject();
+        long timestamp = System.currentTimeMillis();
+
+        commonEventHeader.put(DOMAIN, "other");
+        commonEventHeader.put(EVENT_ID, UUID.randomUUID() + "-reg");
+        commonEventHeader.put(EVENT_TYPE, "pnfRegistration");
+        commonEventHeader.put(LAST_EPOCH_MICROSEC, timestamp);
+        commonEventHeader.put(PRIORITY, "Normal");
+        commonEventHeader.put(SEQUENCE, 0);
+        commonEventHeader.put(START_EPOCH_MICROSEC, timestamp);
+        commonEventHeader.put(INTERNAL_HEADER_FIELDS, new JSONObject());
+        commonEventHeader.put(VERSION, 3);
+
+        return commonEventHeader;
+    }
+
+    private JSONObject generateConstantOtherFields() {
+        JSONObject otherFields = new JSONObject();
+
+        otherFields.put(OTHER_FIELDS_VERSION, 1);
+        otherFields.put(PNF_LAST_SERVICE_DATE, 1517206400);
+        otherFields.put(PNF_MANUFACTURE_DATE, 1516406400);
+
+        return otherFields;
+    }
+
+}