[ONOS-7683] Add FlowInfo and StatsInfo impls with unit tests

Change-Id: I86327507c528a9b7eea60af858ccfb1fb4b2f8ce
diff --git a/apps/openstacktelemetry/api/src/main/java/org/onosproject/openstacktelemetry/api/FlowInfo.java b/apps/openstacktelemetry/api/src/main/java/org/onosproject/openstacktelemetry/api/FlowInfo.java
new file mode 100644
index 0000000..502d692
--- /dev/null
+++ b/apps/openstacktelemetry/api/src/main/java/org/onosproject/openstacktelemetry/api/FlowInfo.java
@@ -0,0 +1,248 @@
+/*
+ * Copyright 2018-present Open Networking Foundation
+ *
+ * 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.
+ */
+package org.onosproject.openstacktelemetry.api;
+
+import org.onlab.packet.IpPrefix;
+import org.onlab.packet.MacAddress;
+import org.onlab.packet.VlanId;
+import org.onosproject.net.DeviceId;
+import org.onosproject.net.PortNumber;
+
+/**
+ * Flow info interface.
+ */
+public interface FlowInfo {
+
+    /**
+     * Obtains flow type.
+     *
+     * @return flow type
+     */
+    byte flowType();
+
+    /**
+     * Obtains device identifier.
+     *
+     * @return device identifier
+     */
+    DeviceId deviceId();
+
+    /**
+     * Obtains input interface identifier.
+     *
+     * @return input interface identifier
+     */
+    int inputInterfaceId();
+
+    /**
+     * Obtains output interface identifier.
+     *
+     * @return output interface identifier
+     */
+    int outputInterfaceId();
+
+    /**
+     * Obtains VLAN identifier.
+     *
+     * @return VLAN identifier
+     */
+    VlanId vlanId();
+
+    /**
+     * Obtains VxLAN identifier.
+     *
+     * @return VxLAN identifier
+     */
+    short vxlanId();
+
+    /**
+     * Obtains source IP address.
+     *
+     * @return source IP address
+     */
+    IpPrefix srcIp();
+
+    /**
+     * Obtains destination IP address.
+     *
+     * @return destination IP address
+     */
+    IpPrefix dstIp();
+
+    /**
+     * Obtains source port.
+     *
+     * @return source port
+     */
+    PortNumber srcPort();
+
+    /**
+     * Obtains destination port.
+     *
+     * @return destination port
+     */
+    PortNumber dstPort();
+
+    /**
+     * Obtains protocol type.
+     *
+     * @return protocol type
+     */
+    byte protocol();
+
+    /**
+     * Obtains source MAC address.
+     *
+     * @return source MAC address
+     */
+    MacAddress srcMac();
+
+    /**
+     * Obtains destination MAC address.
+     *
+     * @return destination MAC address
+     */
+    MacAddress dstMac();
+
+    /**
+     * Obtains flow level stats information.
+     *
+     * @return flow level stats information
+     */
+    StatsInfo statsInfo();
+
+    interface Builder {
+
+        /**
+         * Sets flow type.
+         *
+         * @param flowType flow type
+         * @return builder instance
+         */
+        Builder withFlowType(byte flowType);
+
+        /**
+         * Sets device identifier.
+         *
+         * @param deviceId device identifier
+         * @return builder instance
+         */
+        Builder withDeviceId(DeviceId deviceId);
+
+        /**
+         * Sets input interface identifier.
+         *
+         * @param inputInterfaceId input interface identifier
+         * @return builder instance
+         */
+        Builder withInputInterfaceId(int inputInterfaceId);
+
+        /**
+         * Sets output interface identifier.
+         *
+         * @param outputInterfaceId output interface identifier
+         * @return builder instance
+         */
+        Builder withOutputInterfaceId(int outputInterfaceId);
+
+        /**
+         * Sets VLAN identifier.
+         *
+         * @param vlanId VLAN identifier
+         * @return builder instance
+         */
+        Builder withVlanId(VlanId vlanId);
+
+        /**
+         * Sets VxLAN identifier.
+         *
+         * @param vxlanId VxLAN identifier
+         * @return builder instance
+         */
+        Builder withVxlanId(short vxlanId);
+
+        /**
+         * Sets source IP address.
+         *
+         * @param srcIp source IP address
+         * @return builder instance
+         */
+        Builder withSrcIp(IpPrefix srcIp);
+
+        /**
+         * Sets destination IP address.
+         *
+         * @param dstIp destination IP address
+         * @return builder instance
+         */
+        Builder withDstIp(IpPrefix dstIp);
+
+        /**
+         * Sets source port number.
+         *
+         * @param srcPort source port number
+         * @return builder instance
+         */
+        Builder withSrcPort(PortNumber srcPort);
+
+        /**
+         * Sets destination port number.
+         *
+         * @param dstPort destination port number
+         * @return builder instance
+         */
+        Builder withDstPort(PortNumber dstPort);
+
+        /**
+         * Sets protocol type.
+         *
+         * @param protocol protocol type
+         * @return builder instance
+         */
+        Builder withProtocol(byte protocol);
+
+        /**
+         * Sets source MAC address.
+         *
+         * @param srcMac source MAC address
+         * @return builder instance
+         */
+        Builder withSrcMac(MacAddress srcMac);
+
+        /**
+         * Sets destination MAC address.
+         *
+         * @param dstMac destination MAC address
+         * @return builder instance
+         */
+        Builder withDstMac(MacAddress dstMac);
+
+        /**
+         * Sets flow level stats info.
+         *
+         * @param statsInfo flow level stats info
+         * @return builder instance
+         */
+        Builder withStatsInfo(StatsInfo statsInfo);
+
+        /**
+         * Creates a FlowInfo instance.
+         *
+         * @return FlowInfo instance
+         */
+        FlowInfo build();
+    }
+}
diff --git a/apps/openstacktelemetry/api/src/main/java/org/onosproject/openstacktelemetry/api/StatsInfo.java b/apps/openstacktelemetry/api/src/main/java/org/onosproject/openstacktelemetry/api/StatsInfo.java
new file mode 100644
index 0000000..a256527
--- /dev/null
+++ b/apps/openstacktelemetry/api/src/main/java/org/onosproject/openstacktelemetry/api/StatsInfo.java
@@ -0,0 +1,167 @@
+/*
+ * Copyright 2018-present Open Networking Foundation
+ *
+ * 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.
+ */
+package org.onosproject.openstacktelemetry.api;
+
+/**
+ * Stats info interface.
+ */
+public interface StatsInfo {
+
+    /**
+     * Obtains startup time.
+     *
+     * @return startup time
+     */
+    long startupTime();
+
+    /**
+     * Obtains first packet arrival time.
+     *
+     * @return first packet arrival time
+     */
+    long fstPktArrTime();
+
+    /**
+     * Obtains last packet offset.
+     *
+     * @return last packet offset
+     */
+    int lstPktOffset();
+
+    /**
+     * Obtains previous accumulated bytes.
+     *
+     * @return previous accumulated bytes
+     */
+    long prevAccBytes();
+
+    /**
+     * Obtains previous accumulated packets.
+     *
+     * @return previous accumulated packets
+     */
+    int prevAccPkts();
+
+    /**
+     * Obtains current accumulated bytes.
+     *
+     * @return current accumulated bytes
+     */
+    long currAccBytes();
+
+    /**
+     * Obtains current accumulated packets.
+     *
+     * @return current accumulated packets
+     */
+    int currAccPkts();
+
+    /**
+     * Obtains error packets stats.
+     *
+     * @return error packets stats
+     */
+    short errorPkts();
+
+    /**
+     * Obtains dropped packets stats.
+     *
+     * @return dropped packets stats
+     */
+    short dropPkts();
+
+    interface Builder {
+
+        /**
+         * Sets startup time.
+         *
+         * @param startupTime startup time
+         * @return builder instance
+         */
+        Builder withStartupTime(long startupTime);
+
+        /**
+         * Sets first packet arrival time.
+         *
+         * @param fstPktArrTime first packet arrival time
+         * @return builder instance
+         */
+        Builder withFstPktArrTime(long fstPktArrTime);
+
+        /**
+         * Sets last packet offset.
+         *
+         * @param lstPktOffset last packet offset
+         * @return builder instance
+         */
+        Builder withLstPktOffset(int lstPktOffset);
+
+        /**
+         * Sets previous accumulated bytes.
+         *
+         * @param prevAccBytes previous accumulated bytes
+         * @return builder instance
+         */
+        Builder withPrevAccBytes(long prevAccBytes);
+
+        /**
+         * Sets previous accumulated packets.
+         *
+         * @param prevAccPkts previous accumulated packets
+         * @return builder instance
+         */
+        Builder withPrevAccPkts(int prevAccPkts);
+
+        /**
+         * Sets current accumulated bytes.
+         *
+         * @param currAccBytes current accumulated bytes
+         * @return builder instance
+         */
+        Builder withCurrAccBytes(long currAccBytes);
+
+        /**
+         * Sets currently accumulated packets.
+         *
+         * @param currAccPkts current accumulated packets
+         * @return builder instance
+         */
+        Builder withCurrAccPkts(int currAccPkts);
+
+        /**
+         * Sets error packets stats.
+         *
+         * @param errorPkts error packets stats
+         * @return builder instance
+         */
+        Builder withErrorPkts(short errorPkts);
+
+        /**
+         * Sets dropped packets stats.
+         *
+         * @param dropPkts dropped packets stats
+         * @return builder instance
+         */
+        Builder withDropPkts(short dropPkts);
+
+        /**
+         * Creates flow level stats info instance.
+         *
+         * @return stats info instance
+         */
+        StatsInfo build();
+    }
+}
diff --git a/apps/openstacktelemetry/app/src/main/java/org/onosproject/openstacktelemetry/impl/DefaultFlowInfo.java b/apps/openstacktelemetry/app/src/main/java/org/onosproject/openstacktelemetry/impl/DefaultFlowInfo.java
new file mode 100644
index 0000000..b7a9545
--- /dev/null
+++ b/apps/openstacktelemetry/app/src/main/java/org/onosproject/openstacktelemetry/impl/DefaultFlowInfo.java
@@ -0,0 +1,313 @@
+/*
+ * Copyright 2018-present Open Networking Foundation
+ *
+ * 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.
+ */
+package org.onosproject.openstacktelemetry.impl;
+
+import org.onlab.packet.IpPrefix;
+import org.onlab.packet.MacAddress;
+import org.onlab.packet.VlanId;
+import org.onosproject.net.DeviceId;
+import org.onosproject.net.PortNumber;
+import org.onosproject.openstacktelemetry.api.FlowInfo;
+import org.onosproject.openstacktelemetry.api.StatsInfo;
+
+import java.util.Objects;
+
+import static com.google.common.base.MoreObjects.toStringHelper;
+import static com.google.common.base.Preconditions.checkNotNull;
+
+/**
+ * Implementation class of FlowInfo.
+ */
+public final class DefaultFlowInfo implements FlowInfo {
+
+    private final byte flowType;
+    private final DeviceId deviceId;
+    private final int inputInterfaceId;
+    private final int outputInterfaceId;
+    private final VlanId vlanId;
+    private final short vxlanId;
+    private final IpPrefix srcIp;
+    private final IpPrefix dstIp;
+    private final PortNumber srcPort;
+    private final PortNumber dstPort;
+    private final byte protocol;
+    private final MacAddress srcMac;
+    private final MacAddress dstMac;
+    private final StatsInfo statsInfo;
+
+    private DefaultFlowInfo(byte flowType, DeviceId deviceId,
+                            int inputInterfaceId, int outputInterfaceId,
+                            VlanId vlanId, short vxlanId, IpPrefix srcIp,
+                            IpPrefix dstIp, PortNumber srcPort, PortNumber dstPort,
+                            byte protocol, MacAddress srcMac, MacAddress dstMac,
+                            StatsInfo statsInfo) {
+        this.flowType = flowType;
+        this.deviceId = deviceId;
+        this.inputInterfaceId = inputInterfaceId;
+        this.outputInterfaceId = outputInterfaceId;
+        this.vlanId = vlanId;
+        this.vxlanId = vxlanId;
+        this.srcIp = srcIp;
+        this.dstIp = dstIp;
+        this.srcPort = srcPort;
+        this.dstPort = dstPort;
+        this.protocol = protocol;
+        this.srcMac = srcMac;
+        this.dstMac = dstMac;
+        this.statsInfo = statsInfo;
+    }
+
+    @Override
+    public byte flowType() {
+        return flowType;
+    }
+
+    @Override
+    public DeviceId deviceId() {
+        return deviceId;
+    }
+
+    @Override
+    public int inputInterfaceId() {
+        return inputInterfaceId;
+    }
+
+    @Override
+    public int outputInterfaceId() {
+        return outputInterfaceId;
+    }
+
+    @Override
+    public VlanId vlanId() {
+        return vlanId;
+    }
+
+    @Override
+    public short vxlanId() {
+        return vxlanId;
+    }
+
+    @Override
+    public IpPrefix srcIp() {
+        return srcIp;
+    }
+
+    @Override
+    public IpPrefix dstIp() {
+        return dstIp;
+    }
+
+    @Override
+    public PortNumber srcPort() {
+        return srcPort;
+    }
+
+    @Override
+    public PortNumber dstPort() {
+        return dstPort;
+    }
+
+    @Override
+    public byte protocol() {
+        return protocol;
+    }
+
+    @Override
+    public MacAddress srcMac() {
+        return srcMac;
+    }
+
+    @Override
+    public MacAddress dstMac() {
+        return dstMac;
+    }
+
+    @Override
+    public StatsInfo statsInfo() {
+        return statsInfo;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+
+        if (obj instanceof DefaultFlowInfo) {
+            final DefaultFlowInfo other = (DefaultFlowInfo) obj;
+            return Objects.equals(this.flowType, other.flowType) &&
+                    Objects.equals(this.deviceId, other.deviceId) &&
+                    Objects.equals(this.inputInterfaceId, other.inputInterfaceId) &&
+                    Objects.equals(this.outputInterfaceId, other.outputInterfaceId) &&
+                    Objects.equals(this.vlanId, other.vlanId) &&
+                    Objects.equals(this.vxlanId, other.vxlanId) &&
+                    Objects.equals(this.srcIp, other.srcIp) &&
+                    Objects.equals(this.dstIp, other.dstIp) &&
+                    Objects.equals(this.srcPort, other.srcPort) &&
+                    Objects.equals(this.dstPort, other.dstPort) &&
+                    Objects.equals(this.protocol, other.protocol) &&
+                    Objects.equals(this.srcMac, other.srcMac) &&
+                    Objects.equals(this.dstMac, other.dstMac) &&
+                    Objects.equals(this.statsInfo, other.statsInfo);
+        }
+        return false;
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(flowType, deviceId, inputInterfaceId,
+                outputInterfaceId, vlanId, vxlanId, srcIp, dstIp, srcPort, dstPort,
+                protocol, srcMac, dstMac, statsInfo);
+    }
+
+    @Override
+    public String toString() {
+        return toStringHelper(this)
+                .add("flowType", flowType)
+                .add("deviceId", deviceId)
+                .add("inputInterfaceId", inputInterfaceId)
+                .add("outputInterfaceId", outputInterfaceId)
+                .add("vlanId", vlanId)
+                .add("vxlanId", vxlanId)
+                .add("srcIp", srcIp)
+                .add("dstIp", dstIp)
+                .add("srcPort", srcPort)
+                .add("dstPort", dstPort)
+                .add("protocol", protocol)
+                .add("srcMac", srcMac)
+                .add("dstMac", dstMac)
+                .add("statsInfo", statsInfo)
+                .toString();
+    }
+
+    /**
+     * Builder class of DefaultFlowInfo.
+     */
+    public static final class DefaultBuilder implements FlowInfo.Builder {
+
+        private byte flowType;
+        private DeviceId deviceId;
+        private int inputInterfaceId;
+        private int outputInterfaceId;
+        private VlanId vlanId;
+        private short vxlanId;
+        private IpPrefix srcIp;
+        private IpPrefix dstIp;
+        private PortNumber srcPort;
+        private PortNumber dstPort;
+        private byte protocol;
+        private MacAddress srcMac;
+        private MacAddress dstMac;
+        private StatsInfo statsInfo;
+
+        @Override
+        public Builder withFlowType(byte flowType) {
+            this.flowType = flowType;
+            return this;
+        }
+
+        @Override
+        public Builder withDeviceId(DeviceId deviceId) {
+            this.deviceId = deviceId;
+            return this;
+        }
+
+        @Override
+        public Builder withInputInterfaceId(int inputInterfaceId) {
+            this.inputInterfaceId = inputInterfaceId;
+            return this;
+        }
+
+        @Override
+        public Builder withOutputInterfaceId(int outputInterfaceId) {
+            this.outputInterfaceId = outputInterfaceId;
+            return this;
+        }
+
+        @Override
+        public Builder withVlanId(VlanId vlanId) {
+            this.vlanId = vlanId;
+            return this;
+        }
+
+        @Override
+        public Builder withVxlanId(short vxlanId) {
+            this.vxlanId = vxlanId;
+            return this;
+        }
+
+        @Override
+        public Builder withSrcIp(IpPrefix srcIp) {
+            this.srcIp = srcIp;
+            return this;
+        }
+
+        @Override
+        public Builder withDstIp(IpPrefix dstIp) {
+            this.dstIp = dstIp;
+            return this;
+        }
+
+        @Override
+        public Builder withSrcPort(PortNumber srcPort) {
+            this.srcPort = srcPort;
+            return this;
+        }
+
+        @Override
+        public Builder withDstPort(PortNumber dstPort) {
+            this.dstPort = dstPort;
+            return this;
+        }
+
+        @Override
+        public Builder withProtocol(byte protocol) {
+            this.protocol = protocol;
+            return this;
+        }
+
+        @Override
+        public Builder withSrcMac(MacAddress srcMac) {
+            this.srcMac = srcMac;
+            return this;
+        }
+
+        @Override
+        public Builder withDstMac(MacAddress dstMac) {
+            this.dstMac = dstMac;
+            return this;
+        }
+
+        @Override
+        public Builder withStatsInfo(StatsInfo statsInfo) {
+            this.statsInfo = statsInfo;
+            return this;
+        }
+
+        @Override
+        public FlowInfo build() {
+
+            // TODO: need to check the null value for more properties
+            checkNotNull(srcIp, "Source IP address cannot be null");
+            checkNotNull(dstIp, "Destination IP address cannot be null");
+            checkNotNull(statsInfo, "StatsInfo cannot be null");
+
+            return new DefaultFlowInfo(flowType, deviceId, inputInterfaceId,
+                    outputInterfaceId, vlanId, vxlanId, srcIp, dstIp, srcPort, dstPort,
+                    protocol, srcMac, dstMac, statsInfo);
+        }
+    }
+}
diff --git a/apps/openstacktelemetry/app/src/main/java/org/onosproject/openstacktelemetry/impl/DefaultStatsInfo.java b/apps/openstacktelemetry/app/src/main/java/org/onosproject/openstacktelemetry/impl/DefaultStatsInfo.java
new file mode 100644
index 0000000..6e085a2
--- /dev/null
+++ b/apps/openstacktelemetry/app/src/main/java/org/onosproject/openstacktelemetry/impl/DefaultStatsInfo.java
@@ -0,0 +1,217 @@
+/*
+ * Copyright 2018-present Open Networking Foundation
+ *
+ * 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.
+ */
+package org.onosproject.openstacktelemetry.impl;
+
+import org.onosproject.openstacktelemetry.api.StatsInfo;
+
+import java.util.Objects;
+
+import static com.google.common.base.MoreObjects.toStringHelper;
+
+/**
+ * Implementation class of StatsInfo.
+ */
+public final class DefaultStatsInfo implements StatsInfo {
+
+    private final long startupTime;
+    private final long fstPktArrTime;
+    private final int lstPktOffset;
+    private final long prevAccBytes;
+    private final int prevAccPkts;
+    private final long currAccBytes;
+    private final int currAccPkts;
+    private final short errorPkts;
+    private final short dropPkts;
+
+    private DefaultStatsInfo(long startupTime, long fstPktArrTime, int lstPktOffset,
+                             long prevAccBytes, int prevAccPkts, long currAccBytes,
+                             int currAccPkts, short errorPkts, short dropPkts) {
+        this.startupTime = startupTime;
+        this.fstPktArrTime = fstPktArrTime;
+        this.lstPktOffset = lstPktOffset;
+        this.prevAccBytes = prevAccBytes;
+        this.prevAccPkts = prevAccPkts;
+        this.currAccBytes = currAccBytes;
+        this.currAccPkts = currAccPkts;
+        this.errorPkts = errorPkts;
+        this.dropPkts = dropPkts;
+    }
+
+    @Override
+    public long startupTime() {
+        return startupTime;
+    }
+
+    @Override
+    public long fstPktArrTime() {
+        return fstPktArrTime;
+    }
+
+    @Override
+    public int lstPktOffset() {
+        return lstPktOffset;
+    }
+
+    @Override
+    public long prevAccBytes() {
+        return prevAccBytes;
+    }
+
+    @Override
+    public int prevAccPkts() {
+        return prevAccPkts;
+    }
+
+    @Override
+    public long currAccBytes() {
+        return currAccBytes;
+    }
+
+    @Override
+    public int currAccPkts() {
+        return currAccPkts;
+    }
+
+    @Override
+    public short errorPkts() {
+        return errorPkts;
+    }
+
+    @Override
+    public short dropPkts() {
+        return dropPkts;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+
+        if (obj instanceof DefaultStatsInfo) {
+            final DefaultStatsInfo other = (DefaultStatsInfo) obj;
+            return Objects.equals(this.startupTime, other.startupTime) &&
+                    Objects.equals(this.fstPktArrTime, other.fstPktArrTime) &&
+                    Objects.equals(this.lstPktOffset, other.lstPktOffset) &&
+                    Objects.equals(this.prevAccBytes, other.prevAccBytes) &&
+                    Objects.equals(this.prevAccPkts, other.prevAccPkts) &&
+                    Objects.equals(this.currAccBytes, other.currAccBytes) &&
+                    Objects.equals(this.currAccPkts, other.currAccPkts) &&
+                    Objects.equals(this.errorPkts, other.errorPkts) &&
+                    Objects.equals(this.dropPkts, other.dropPkts);
+        }
+        return false;
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(startupTime, fstPktArrTime, lstPktOffset,
+                prevAccBytes, prevAccPkts, currAccBytes, currAccPkts,
+                errorPkts, dropPkts);
+    }
+
+    @Override
+    public String toString() {
+        return toStringHelper(this)
+                .add("startupTime", startupTime)
+                .add("fstPktArrTime", fstPktArrTime)
+                .add("lstPktOffset", lstPktOffset)
+                .add("prevAccBytes", prevAccBytes)
+                .add("prevAccPkts", prevAccPkts)
+                .add("currAccBytes", currAccBytes)
+                .add("currAccPkts", currAccPkts)
+                .add("errorPkts", errorPkts)
+                .add("dropPkts", dropPkts)
+                .toString();
+    }
+
+    /**
+     * Builder class of DefaultStatsInfo.
+     */
+    public static final class DefaultBuilder implements StatsInfo.Builder {
+        private long startupTime;
+        private long fstPktArrTime;
+        private int lstPktOffset;
+        private long prevAccBytes;
+        private int prevAccPkts;
+        private long currAccBytes;
+        private int currAccPkts;
+        private short errorPkts;
+        private short dropPkts;
+
+        @Override
+        public Builder withStartupTime(long startupTime) {
+            this.startupTime = startupTime;
+            return this;
+        }
+
+        @Override
+        public Builder withFstPktArrTime(long fstPktArrTime) {
+            this.fstPktArrTime = fstPktArrTime;
+            return this;
+        }
+
+        @Override
+        public Builder withLstPktOffset(int lstPktOffset) {
+            this.lstPktOffset = lstPktOffset;
+            return this;
+        }
+
+        @Override
+        public Builder withPrevAccBytes(long prevAccBytes) {
+            this.prevAccBytes = prevAccBytes;
+            return this;
+        }
+
+        @Override
+        public Builder withPrevAccPkts(int prevAccPkts) {
+            this.prevAccPkts = prevAccPkts;
+            return this;
+        }
+
+        @Override
+        public Builder withCurrAccBytes(long currAccBytes) {
+            this.currAccBytes = currAccBytes;
+            return this;
+        }
+
+        @Override
+        public Builder withCurrAccPkts(int currAccPkts) {
+            this.currAccPkts = currAccPkts;
+            return this;
+        }
+
+        @Override
+        public Builder withErrorPkts(short errorPkts) {
+            this.errorPkts = errorPkts;
+            return this;
+        }
+
+        @Override
+        public Builder withDropPkts(short dropPkts) {
+            this.dropPkts = dropPkts;
+            return this;
+        }
+
+        @Override
+        public StatsInfo build() {
+
+            return new DefaultStatsInfo(startupTime, fstPktArrTime, lstPktOffset,
+                    prevAccBytes, prevAccPkts, currAccBytes, currAccPkts,
+                    errorPkts, dropPkts);
+        }
+    }
+}
diff --git a/apps/openstacktelemetry/app/src/test/java/org/onosproject/openstacktelemetry/impl/TestDefaultFlowInfo.java b/apps/openstacktelemetry/app/src/test/java/org/onosproject/openstacktelemetry/impl/TestDefaultFlowInfo.java
new file mode 100644
index 0000000..e661672
--- /dev/null
+++ b/apps/openstacktelemetry/app/src/test/java/org/onosproject/openstacktelemetry/impl/TestDefaultFlowInfo.java
@@ -0,0 +1,151 @@
+/*
+ * Copyright 2018-present Open Networking Foundation
+ *
+ * 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.
+ */
+package org.onosproject.openstacktelemetry.impl;
+
+import com.google.common.testing.EqualsTester;
+import org.junit.Before;
+import org.junit.Test;
+import org.onlab.packet.IpAddress;
+import org.onlab.packet.IpPrefix;
+import org.onlab.packet.MacAddress;
+import org.onlab.packet.VlanId;
+import org.onosproject.net.DeviceId;
+import org.onosproject.net.PortNumber;
+import org.onosproject.openstacktelemetry.api.FlowInfo;
+import org.onosproject.openstacktelemetry.api.StatsInfo;
+
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.is;
+
+/**
+ * Unit tests for DefaultFlowInfo class.
+ */
+public final class TestDefaultFlowInfo {
+
+    private static final String IP_ADDRESS_1 = "10.10.10.1";
+    private static final String IP_ADDRESS_2 = "20.20.20.1";
+
+    private static final String MAC_ADDRESS_1 = "AA:BB:CC:DD:EE:FF";
+    private static final String MAC_ADDRESS_2 = "FF:EE:DD:CC:BB:AA";
+
+    private static final int IP_PREFIX_LENGTH_1 = 10;
+    private static final int IP_PREFIX_LENGTH_2 = 20;
+
+    private static final int PORT_1 = 1000;
+    private static final int PORT_2 = 2000;
+
+    private static final int STATIC_INTEGER_1 = 1;
+    private static final int STATIC_INTEGER_2 = 2;
+
+    private static final String STATIC_STRING_1 = "1";
+    private static final String STATIC_STRING_2 = "2";
+
+
+    private FlowInfo info1;
+    private FlowInfo sameAsInfo1;
+    private FlowInfo info2;
+
+    @Before
+    public void setup() {
+
+        FlowInfo.Builder builder1 = new DefaultFlowInfo.DefaultBuilder();
+        FlowInfo.Builder builder2 = new DefaultFlowInfo.DefaultBuilder();
+        FlowInfo.Builder builder3 = new DefaultFlowInfo.DefaultBuilder();
+
+        StatsInfo statsInfo = new DefaultStatsInfo.DefaultBuilder().build();
+
+        info1 = builder1
+                .withFlowType((byte) STATIC_INTEGER_1)
+                .withInputInterfaceId(STATIC_INTEGER_1)
+                .withOutputInterfaceId(STATIC_INTEGER_1)
+                .withDeviceId(DeviceId.deviceId(STATIC_STRING_1))
+                .withSrcIp(IpPrefix.valueOf(
+                        IpAddress.valueOf(IP_ADDRESS_1), IP_PREFIX_LENGTH_1))
+                .withDstIp(IpPrefix.valueOf(
+                        IpAddress.valueOf(IP_ADDRESS_1), IP_PREFIX_LENGTH_1))
+                .withSrcPort(PortNumber.portNumber(PORT_1))
+                .withDstPort(PortNumber.portNumber(PORT_1))
+                .withProtocol((byte) STATIC_INTEGER_1)
+                .withVlanId(VlanId.vlanId(STATIC_STRING_1))
+                .withSrcMac(MacAddress.valueOf(MAC_ADDRESS_1))
+                .withDstMac(MacAddress.valueOf(MAC_ADDRESS_1))
+                .withStatsInfo(statsInfo)
+                .build();
+
+        sameAsInfo1 = builder2
+                .withFlowType((byte) STATIC_INTEGER_1)
+                .withInputInterfaceId(STATIC_INTEGER_1)
+                .withOutputInterfaceId(STATIC_INTEGER_1)
+                .withDeviceId(DeviceId.deviceId(STATIC_STRING_1))
+                .withSrcIp(IpPrefix.valueOf(
+                        IpAddress.valueOf(IP_ADDRESS_1), IP_PREFIX_LENGTH_1))
+                .withDstIp(IpPrefix.valueOf(
+                        IpAddress.valueOf(IP_ADDRESS_1), IP_PREFIX_LENGTH_1))
+                .withSrcPort(PortNumber.portNumber(PORT_1))
+                .withDstPort(PortNumber.portNumber(PORT_1))
+                .withProtocol((byte) STATIC_INTEGER_1)
+                .withVlanId(VlanId.vlanId(STATIC_STRING_1))
+                .withSrcMac(MacAddress.valueOf(MAC_ADDRESS_1))
+                .withDstMac(MacAddress.valueOf(MAC_ADDRESS_1))
+                .withStatsInfo(statsInfo)
+                .build();
+
+        info2 = builder3
+                .withFlowType((byte) STATIC_INTEGER_2)
+                .withInputInterfaceId(STATIC_INTEGER_2)
+                .withOutputInterfaceId(STATIC_INTEGER_2)
+                .withDeviceId(DeviceId.deviceId(STATIC_STRING_2))
+                .withSrcIp(IpPrefix.valueOf(
+                        IpAddress.valueOf(IP_ADDRESS_2), IP_PREFIX_LENGTH_2))
+                .withDstIp(IpPrefix.valueOf(
+                        IpAddress.valueOf(IP_ADDRESS_2), IP_PREFIX_LENGTH_2))
+                .withSrcPort(PortNumber.portNumber(PORT_2))
+                .withDstPort(PortNumber.portNumber(PORT_2))
+                .withProtocol((byte) STATIC_INTEGER_2)
+                .withVlanId(VlanId.vlanId(STATIC_STRING_2))
+                .withSrcMac(MacAddress.valueOf(MAC_ADDRESS_2))
+                .withDstMac(MacAddress.valueOf(MAC_ADDRESS_2))
+                .withStatsInfo(statsInfo)
+                .build();
+    }
+
+    @Test
+    public void testEquality() {
+        new EqualsTester()
+                .addEqualityGroup(info1, sameAsInfo1)
+                .addEqualityGroup(info2).testEquals();
+    }
+
+    @Test
+    public void testConstruction() {
+        FlowInfo info = info1;
+
+        assertThat(info.flowType(), is((byte) STATIC_INTEGER_1));
+        assertThat(info.inputInterfaceId(), is(STATIC_INTEGER_1));
+        assertThat(info.outputInterfaceId(), is(STATIC_INTEGER_1));
+        assertThat(info.deviceId(), is(DeviceId.deviceId(STATIC_STRING_1)));
+        assertThat(info.srcIp(), is(IpPrefix.valueOf(
+                IpAddress.valueOf(IP_ADDRESS_1), IP_PREFIX_LENGTH_1)));
+        assertThat(info.dstIp(), is(IpPrefix.valueOf(
+                IpAddress.valueOf(IP_ADDRESS_1), IP_PREFIX_LENGTH_1)));
+        assertThat(info.srcPort(), is(PortNumber.portNumber(PORT_1)));
+        assertThat(info.dstPort(), is(PortNumber.portNumber(PORT_1)));
+        assertThat(info.protocol(), is((byte) STATIC_INTEGER_1));
+        assertThat(info.vlanId(), is(VlanId.vlanId(STATIC_STRING_1)));
+        assertThat(info.srcMac(), is(MacAddress.valueOf(MAC_ADDRESS_1)));
+        assertThat(info.dstMac(), is(MacAddress.valueOf(MAC_ADDRESS_1)));
+    }
+}
diff --git a/apps/openstacktelemetry/app/src/test/java/org/onosproject/openstacktelemetry/impl/TestDefaultStatsInfo.java b/apps/openstacktelemetry/app/src/test/java/org/onosproject/openstacktelemetry/impl/TestDefaultStatsInfo.java
new file mode 100644
index 0000000..f13b9b7
--- /dev/null
+++ b/apps/openstacktelemetry/app/src/test/java/org/onosproject/openstacktelemetry/impl/TestDefaultStatsInfo.java
@@ -0,0 +1,102 @@
+/*
+ * Copyright 2018-present Open Networking Foundation
+ *
+ * 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.
+ */
+package org.onosproject.openstacktelemetry.impl;
+
+import com.google.common.testing.EqualsTester;
+import org.junit.Before;
+import org.junit.Test;
+import org.onosproject.openstacktelemetry.api.StatsInfo;
+
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.is;
+
+/**
+ * Unit tests for DefaultStatsInfo class.
+ */
+public final class TestDefaultStatsInfo {
+
+    private static final int STATIC_INTEGER_1 = 1;
+    private static final int STATIC_INTEGER_2 = 2;
+
+    private StatsInfo info1;
+    private StatsInfo sameAsInfo1;
+    private StatsInfo info2;
+
+    @Before
+    public void setup() {
+        StatsInfo.Builder builder1 = new DefaultStatsInfo.DefaultBuilder();
+        StatsInfo.Builder builder2 = new DefaultStatsInfo.DefaultBuilder();
+        StatsInfo.Builder builder3 = new DefaultStatsInfo.DefaultBuilder();
+
+        info1 = builder1
+                .withStartupTime(STATIC_INTEGER_1)
+                .withCurrAccPkts(STATIC_INTEGER_1)
+                .withCurrAccBytes(STATIC_INTEGER_1)
+                .withPrevAccPkts(STATIC_INTEGER_1)
+                .withPrevAccBytes(STATIC_INTEGER_1)
+                .withFstPktArrTime(STATIC_INTEGER_1)
+                .withLstPktOffset(STATIC_INTEGER_1)
+                .withErrorPkts((short) STATIC_INTEGER_1)
+                .withDropPkts((short) STATIC_INTEGER_1)
+                .build();
+
+        sameAsInfo1 = builder2
+                .withStartupTime(STATIC_INTEGER_1)
+                .withCurrAccPkts(STATIC_INTEGER_1)
+                .withCurrAccBytes(STATIC_INTEGER_1)
+                .withPrevAccPkts(STATIC_INTEGER_1)
+                .withPrevAccBytes(STATIC_INTEGER_1)
+                .withFstPktArrTime(STATIC_INTEGER_1)
+                .withLstPktOffset(STATIC_INTEGER_1)
+                .withErrorPkts((short) STATIC_INTEGER_1)
+                .withDropPkts((short) STATIC_INTEGER_1)
+                .build();
+
+        info2 = builder3
+                .withStartupTime(STATIC_INTEGER_2)
+                .withCurrAccPkts(STATIC_INTEGER_2)
+                .withCurrAccBytes(STATIC_INTEGER_2)
+                .withPrevAccPkts(STATIC_INTEGER_2)
+                .withPrevAccBytes(STATIC_INTEGER_2)
+                .withFstPktArrTime(STATIC_INTEGER_2)
+                .withLstPktOffset(STATIC_INTEGER_2)
+                .withErrorPkts((short) STATIC_INTEGER_2)
+                .withDropPkts((short) STATIC_INTEGER_2)
+                .build();
+    }
+
+    @Test
+    public void testEquality() {
+        new EqualsTester()
+                .addEqualityGroup(info1, sameAsInfo1)
+                .addEqualityGroup(info2).testEquals();
+    }
+
+    @Test
+    public void testConstruction() {
+        StatsInfo info = info1;
+
+        assertThat(info.startupTime(), is((long) STATIC_INTEGER_1));
+        assertThat(info.currAccPkts(), is(STATIC_INTEGER_1));
+        assertThat(info.currAccBytes(), is((long) STATIC_INTEGER_1));
+        assertThat(info.prevAccPkts(), is(STATIC_INTEGER_1));
+        assertThat(info.prevAccBytes(), is((long) STATIC_INTEGER_1));
+        assertThat(info.fstPktArrTime(), is((long) STATIC_INTEGER_1));
+        assertThat(info.lstPktOffset(), is(STATIC_INTEGER_1));
+        assertThat(info.errorPkts(), is((short) STATIC_INTEGER_1));
+        assertThat(info.dropPkts(), is((short) STATIC_INTEGER_1));
+    }
+}