P4Runtime unit tests for api, ctl, model modules

Change-Id: Iac1b1ef6e274c355ce3a26cffbd8adcb39694f69
diff --git a/protocols/p4runtime/api/BUCK b/protocols/p4runtime/api/BUCK
index 8b740b84..fd05763 100644
--- a/protocols/p4runtime/api/BUCK
+++ b/protocols/p4runtime/api/BUCK
@@ -5,6 +5,13 @@
     '//incubator/grpc-dependencies:grpc-core-repkg-' + GRPC_VER,
 ]
 
-osgi_jar(
+TEST_DEPS = [
+    '//core/api:onos-api-tests',
+    '//lib:TEST',
+    '//protocols/p4runtime/api:onos-protocols-p4runtime-api',
+]
+
+osgi_jar_with_tests(
     deps = COMPILE_DEPS,
-)
\ No newline at end of file
+    test_deps = TEST_DEPS,
+)
diff --git a/protocols/p4runtime/ctl/src/test/java/org/onosproject/p4runtime/ctl/DefaultPacketInTest.java b/protocols/p4runtime/ctl/src/test/java/org/onosproject/p4runtime/ctl/DefaultPacketInTest.java
new file mode 100644
index 0000000..38fcf6d
--- /dev/null
+++ b/protocols/p4runtime/ctl/src/test/java/org/onosproject/p4runtime/ctl/DefaultPacketInTest.java
@@ -0,0 +1,154 @@
+/*
+ * Copyright 2017-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.p4runtime.ctl;
+
+import com.google.common.testing.EqualsTester;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.onlab.util.ImmutableByteSequence;
+import org.onosproject.net.DeviceId;
+import org.onosproject.net.pi.runtime.PiControlMetadata;
+import org.onosproject.net.pi.model.PiControlMetadataId;
+import org.onosproject.net.pi.runtime.PiPacketOperation;
+
+import static org.onlab.util.ImmutableByteSequence.copyFrom;
+import static org.onlab.util.ImmutableByteSequence.fit;
+import static org.onosproject.net.pi.model.PiPacketOperationType.PACKET_OUT;
+import static org.onosproject.net.pi.model.PiPacketOperationType.PACKET_IN;
+
+/**
+ * Test for DefaultPacketIn class.
+ */
+public class DefaultPacketInTest {
+
+    private static final int DEFAULT_ORIGINAL_VALUE = 255;
+    private static final int DEFAULT_BIT_WIDTH = 9;
+
+    private final DeviceId deviceId = DeviceId.deviceId("dummy:1");
+    private final DeviceId sameDeviceId = DeviceId.deviceId("dummy:1");
+    private final DeviceId deviceId2 = DeviceId.deviceId("dummy:2");
+    private final DeviceId nullDeviceId = null;
+
+    private PiPacketOperation packetOperation;
+    private PiPacketOperation packetOperation2;
+    private PiPacketOperation nullPacketOperation = null;
+
+    private DefaultPacketIn packetIn;
+    private DefaultPacketIn sameAsPacketIn;
+    private DefaultPacketIn packetIn2;
+    private DefaultPacketIn packetIn3;
+
+    /**
+     * Setup method for packetOperation and packetOperation2.
+     * @throws ImmutableByteSequence.ByteSequenceTrimException if byte sequence cannot be trimmed
+     */
+    @Before
+    public void setup() throws ImmutableByteSequence.ByteSequenceTrimException {
+
+        packetOperation = PiPacketOperation.builder()
+                .forDevice(deviceId)
+                .withData(ImmutableByteSequence.ofOnes(512))
+                .withType(PACKET_OUT)
+                .withMetadata(PiControlMetadata.builder()
+                                      .withId(PiControlMetadataId.of("egress_port"))
+                                      .withValue(fit(copyFrom(DEFAULT_ORIGINAL_VALUE), DEFAULT_BIT_WIDTH))
+                                      .build())
+                .build();
+
+        packetOperation2 = PiPacketOperation.builder()
+                .forDevice(deviceId2)
+                .withData(ImmutableByteSequence.ofOnes(512))
+                .withType(PACKET_IN)
+                .withMetadata(PiControlMetadata.builder()
+                                      .withId(PiControlMetadataId.of("ingress_port"))
+                                      .withValue(fit(copyFrom(DEFAULT_ORIGINAL_VALUE), DEFAULT_BIT_WIDTH))
+                                      .build())
+                .build();
+
+        packetIn = new DefaultPacketIn(deviceId, packetOperation);
+        sameAsPacketIn = new DefaultPacketIn(sameDeviceId, packetOperation);
+        packetIn2 = new DefaultPacketIn(deviceId2, packetOperation);
+        packetIn3 = new DefaultPacketIn(deviceId, packetOperation2);
+    }
+
+    /**
+     * tearDown method for packetOperation and packetOperation2.
+     */
+    @After
+    public void tearDown() {
+        packetOperation = null;
+        packetOperation2 = null;
+
+        packetIn = null;
+        sameAsPacketIn = null;
+        packetIn2 = null;
+        packetIn3 = null;
+    }
+
+
+    /**
+     * Tests constructor with null object as a DeviceId parameter.
+     */
+    @Test(expected = NullPointerException.class)
+    public void testConstructorWithNullDeviceId() {
+
+        new DefaultPacketIn(nullDeviceId, packetOperation);
+    }
+
+    /**
+     * Tests constructor with null object as PacketOperation parameter.
+     */
+    @Test(expected = NullPointerException.class)
+    public void testConstructorWithNullPacketOperation() {
+
+        new DefaultPacketIn(deviceId, nullPacketOperation);
+    }
+
+    /**
+     * Test for deviceId method.
+     */
+    @Test
+    public void deviceId() {
+        new EqualsTester()
+                .addEqualityGroup(deviceId, packetIn.deviceId(), sameAsPacketIn.deviceId())
+                .addEqualityGroup(packetIn2)
+                .testEquals();
+    }
+
+    /**
+     * Test for packetOperation method.
+     */
+    @Test
+    public void packetOperation() {
+        new EqualsTester()
+                .addEqualityGroup(packetOperation, packetIn.packetOperation())
+                .addEqualityGroup(packetIn3.packetOperation())
+                .testEquals();
+    }
+
+    /**
+     * Checks the operation of equals(), hashCode() and toString() methods.
+     */
+    @Test
+    public void testEquals() {
+        new EqualsTester()
+                .addEqualityGroup(packetIn, sameAsPacketIn)
+                .addEqualityGroup(packetIn2)
+                .addEqualityGroup(packetIn3)
+                .testEquals();
+    }
+}
\ No newline at end of file
diff --git a/protocols/p4runtime/model/BUCK b/protocols/p4runtime/model/BUCK
index 86c44c4..61e5d49 100644
--- a/protocols/p4runtime/model/BUCK
+++ b/protocols/p4runtime/model/BUCK
@@ -6,6 +6,9 @@
     '//lib:protobuf-java-' + PROTOBUF_VER,
 ]
 
-osgi_jar(
-    deps = COMPILE_DEPS,
+TEST_DEPS = [
+]
+
+osgi_jar_with_tests(
+    deps = COMPILE_DEPS + TEST_DEPS,
 )
diff --git a/protocols/p4runtime/model/src/test/java/org/onosproject/p4runtime/model/P4ActionModelTest.java b/protocols/p4runtime/model/src/test/java/org/onosproject/p4runtime/model/P4ActionModelTest.java
new file mode 100644
index 0000000..387fad4
--- /dev/null
+++ b/protocols/p4runtime/model/src/test/java/org/onosproject/p4runtime/model/P4ActionModelTest.java
@@ -0,0 +1,96 @@
+/*
+ * Copyright 2017-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.p4runtime.model;
+
+import com.google.common.collect.ImmutableMap;
+import com.google.common.testing.EqualsTester;
+import org.junit.Test;
+import org.onosproject.net.pi.model.PiActionId;
+import org.onosproject.net.pi.model.PiActionParamId;
+import org.onosproject.net.pi.model.PiActionParamModel;
+
+import static org.onlab.junit.ImmutableClassChecker.assertThatClassIsImmutable;
+
+/**
+ * Test for P4ActionModel class.
+ */
+public class P4ActionModelTest {
+
+    final PiActionId actionId = PiActionId.of("dec_ttl");
+    final PiActionId sameAsActionId = PiActionId.of("dec_ttl");
+    final PiActionId actionId2 = PiActionId.of("mod_vlan_vid");
+
+    private final PiActionParamId piActionParamId = PiActionParamId.of("port");
+    private final PiActionParamId sameAsPiActionParamId = PiActionParamId.of("port");
+    private final PiActionParamId piActionParamId2 = PiActionParamId.of("dstAddr");
+
+    private static final int BIT_WIDTH = 32;
+
+    private final P4ActionParamModel actionParamModel = new P4ActionParamModel(piActionParamId, BIT_WIDTH);
+
+    private final P4ActionParamModel actionParamModel2 = new P4ActionParamModel(piActionParamId2, BIT_WIDTH);
+
+
+    private final ImmutableMap<PiActionParamId, PiActionParamModel> params = new
+            ImmutableMap.Builder<PiActionParamId, PiActionParamModel>()
+            .put(piActionParamId, actionParamModel)
+            .build();
+    private final ImmutableMap<PiActionParamId, PiActionParamModel> sameAsParams = new
+            ImmutableMap.Builder<PiActionParamId, PiActionParamModel>()
+            .put(sameAsPiActionParamId, actionParamModel)
+            .build();
+    private final ImmutableMap<PiActionParamId, PiActionParamModel> params2 = new
+            ImmutableMap.Builder<PiActionParamId, PiActionParamModel>()
+            .put(piActionParamId2, actionParamModel)
+            .build();
+    private final ImmutableMap<PiActionParamId, PiActionParamModel> params3 = new
+            ImmutableMap.Builder<PiActionParamId, PiActionParamModel>()
+            .put(piActionParamId, actionParamModel2)
+            .build();
+
+    private final P4ActionModel actionModel = new P4ActionModel(actionId, params);
+
+    private final P4ActionModel sameAsActionModel = new P4ActionModel(sameAsActionId, params);
+
+    private final P4ActionModel sameAsActionModel2 = new P4ActionModel(actionId, sameAsParams);
+
+    private final P4ActionModel actionModel2 = new P4ActionModel(actionId2, params);
+
+    private final P4ActionModel actionModel3 = new P4ActionModel(actionId, params2);
+
+    private final P4ActionModel actionModel4 = new P4ActionModel(actionId, params3);
+
+    /**
+     * Checks that the P4ActionModel class is immutable.
+     */
+    @Test
+    public void testImmutability() {
+        assertThatClassIsImmutable(P4ActionModel.class);
+    }
+
+    /**
+     * Checks the operation of equals(), hashCode() and toString() methods.
+     */
+    @Test
+    public void testEquals() {
+        new EqualsTester()
+                .addEqualityGroup(actionModel, sameAsActionModel, sameAsActionModel2)
+                .addEqualityGroup(actionModel2)
+                .addEqualityGroup(actionModel3)
+                .addEqualityGroup(actionModel4)
+                .testEquals();
+    }
+}
\ No newline at end of file
diff --git a/protocols/p4runtime/model/src/test/java/org/onosproject/p4runtime/model/P4ActionParamModelTest.java b/protocols/p4runtime/model/src/test/java/org/onosproject/p4runtime/model/P4ActionParamModelTest.java
new file mode 100644
index 0000000..035465c
--- /dev/null
+++ b/protocols/p4runtime/model/src/test/java/org/onosproject/p4runtime/model/P4ActionParamModelTest.java
@@ -0,0 +1,65 @@
+/*
+ * Copyright 2017-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.p4runtime.model;
+
+import com.google.common.testing.EqualsTester;
+import org.junit.Test;
+import org.onosproject.net.pi.model.PiActionParamId;
+
+import static org.onlab.junit.ImmutableClassChecker.assertThatClassIsImmutable;
+
+/**
+ * Test for P4ActionParamModel class.
+ */
+public class P4ActionParamModelTest {
+    private final PiActionParamId piActionParamId = PiActionParamId.of("port");
+    private final PiActionParamId sameAsPiActionParamId = PiActionParamId.of("port");
+    private final PiActionParamId piActionParamId2 = PiActionParamId.of("dstAddr");
+
+    private static final int BIT_WIDTH_32 = 32;
+    private static final int BIT_WIDTH_64 = 64;
+
+    private final P4ActionParamModel actionParamModel = new P4ActionParamModel(piActionParamId, BIT_WIDTH_32);
+
+    private final P4ActionParamModel sameAsActionParamModel = new P4ActionParamModel(sameAsPiActionParamId,
+                                                                                     BIT_WIDTH_32);
+
+    private final P4ActionParamModel actionParamModel2 = new P4ActionParamModel(piActionParamId2, BIT_WIDTH_32);
+
+    private final P4ActionParamModel actionParamModel3 = new P4ActionParamModel(piActionParamId, BIT_WIDTH_64);
+
+
+
+    /**
+     * Checks that the P4CounterModel class is immutable.
+     */
+    @Test
+    public void testImmutability() {
+        assertThatClassIsImmutable(P4ActionParamModel.class);
+    }
+
+    /**
+     * Checks the operation of equals(), hashCode() and toString() methods.
+     */
+    @Test
+    public void testEquals() {
+        new EqualsTester()
+                .addEqualityGroup(actionParamModel, sameAsActionParamModel)
+                .addEqualityGroup(actionParamModel2)
+                .addEqualityGroup(actionParamModel3)
+                .testEquals();
+    }
+}
\ No newline at end of file
diff --git a/protocols/p4runtime/model/src/test/java/org/onosproject/p4runtime/model/P4ActionProfileModelTest.java b/protocols/p4runtime/model/src/test/java/org/onosproject/p4runtime/model/P4ActionProfileModelTest.java
new file mode 100644
index 0000000..3042414
--- /dev/null
+++ b/protocols/p4runtime/model/src/test/java/org/onosproject/p4runtime/model/P4ActionProfileModelTest.java
@@ -0,0 +1,88 @@
+/*
+ * Copyright 2017-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.p4runtime.model;
+
+import com.google.common.collect.ImmutableSet;
+import com.google.common.testing.EqualsTester;
+import org.junit.Test;
+import org.onosproject.net.pi.model.PiActionProfileId;
+import org.onosproject.net.pi.model.PiTableId;
+
+
+import static org.onlab.junit.ImmutableClassChecker.assertThatClassIsImmutable;
+
+/**
+ * Test for P4ActionProfile class.
+ */
+public class P4ActionProfileModelTest {
+
+    private static final String TABLE_0 = "table0";
+    private static final String WCMP_TABLE = "wcmp_table";
+
+    private final PiTableId tableId = PiTableId.of(TABLE_0);
+    private final PiTableId sameAsTableId = PiTableId.of(TABLE_0);
+    private final PiTableId tableId2 = PiTableId.of(WCMP_TABLE);
+
+    private final ImmutableSet<PiTableId> tables = new ImmutableSet.Builder<PiTableId>()
+            .add(tableId, tableId2)
+            .build();
+
+    private final ImmutableSet<PiTableId> sameAsTables = new ImmutableSet.Builder<PiTableId>()
+            .add(sameAsTableId, tableId2)
+            .build();
+
+    private final ImmutableSet<PiTableId> tables2 = new ImmutableSet.Builder<PiTableId>()
+            .add(tableId, sameAsTableId)
+            .build();
+
+    private final PiActionProfileId id = PiActionProfileId.of("name");
+    private final PiActionProfileId id2 = PiActionProfileId.of("name2");
+
+    private final P4ActionProfileModel metadataModel = new P4ActionProfileModel(id, tables,
+                                                                                true, 64);
+    private final P4ActionProfileModel sameAsMetadataModel = new P4ActionProfileModel(id, sameAsTables,
+                                                                                      true, 64);
+    private final P4ActionProfileModel metadataModel2 = new P4ActionProfileModel(id, tables2,
+                                                                                 true, 64);
+    private final P4ActionProfileModel metadataModel3 = new P4ActionProfileModel(id2, tables,
+                                                                                 true, 64);
+    private final P4ActionProfileModel metadataModel4 = new P4ActionProfileModel(id, tables,
+                                                                                 false, 64);
+    private final P4ActionProfileModel metadataModel5 = new P4ActionProfileModel(id, tables,
+                                                                                 true, 32);
+
+    /**
+     * Checks that the P4ActionProfileModel class is immutable.
+     */
+    @Test
+    public void testImmutability() {
+        assertThatClassIsImmutable(P4ActionProfileModel.class);
+    }
+
+    /**
+     * Checks the operation of equals(), hashCode() and toString() methods.
+     */
+    @Test
+    public void testEquals() {
+        new EqualsTester()
+                .addEqualityGroup(metadataModel, sameAsMetadataModel)
+                .addEqualityGroup(metadataModel2)
+                .addEqualityGroup(metadataModel3)
+                .addEqualityGroup(metadataModel4)
+                .addEqualityGroup(metadataModel5)
+                .testEquals();
+    }
+}
\ No newline at end of file
diff --git a/protocols/p4runtime/model/src/test/java/org/onosproject/p4runtime/model/P4ControlMetadataModelTest.java b/protocols/p4runtime/model/src/test/java/org/onosproject/p4runtime/model/P4ControlMetadataModelTest.java
new file mode 100644
index 0000000..998875a
--- /dev/null
+++ b/protocols/p4runtime/model/src/test/java/org/onosproject/p4runtime/model/P4ControlMetadataModelTest.java
@@ -0,0 +1,68 @@
+/*
+ * Copyright 2017-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.p4runtime.model;
+
+import com.google.common.testing.EqualsTester;
+import org.junit.Test;
+import org.onosproject.net.pi.model.PiControlMetadataId;
+
+import static org.junit.Assert.*;
+import static org.onlab.junit.ImmutableClassChecker.assertThatClassIsImmutable;
+
+/**
+ * Test for P4ControlMetadataModel class.
+ */
+public class P4ControlMetadataModelTest {
+
+    private final PiControlMetadataId piControlMetadataId = PiControlMetadataId.of("EGRESS_PORT");
+    private final PiControlMetadataId sameAsPiControlMetadataId = PiControlMetadataId.of("EGRESS_PORT");
+    private final PiControlMetadataId piControlMetadataId2 = PiControlMetadataId.of("INGRESS_PORT");
+
+    private static final int BIT_WIDTH_32 = 32;
+    private static final int BIT_WIDTH_64 = 64;
+
+    private final P4ControlMetadataModel metadataModel = new P4ControlMetadataModel(piControlMetadataId, BIT_WIDTH_32);
+
+    private final P4ControlMetadataModel sameAsMetadataModel = new P4ControlMetadataModel(sameAsPiControlMetadataId,
+                                                                                          BIT_WIDTH_32);
+
+    private final P4ControlMetadataModel metadataModel2 = new P4ControlMetadataModel(piControlMetadataId2,
+                                                                                     BIT_WIDTH_32);
+
+    private final P4ControlMetadataModel metadataModel3 = new P4ControlMetadataModel(piControlMetadataId, BIT_WIDTH_64);
+
+
+
+    /**
+     * Checks that the P4CounterModel class is immutable.
+     */
+    @Test
+    public void testImmutability() {
+        assertThatClassIsImmutable(P4ControlMetadataModel.class);
+    }
+
+    /**
+     * Checks the operation of equals(), hashCode() and toString() methods.
+     */
+    @Test
+    public void testEquals() {
+        new EqualsTester()
+                .addEqualityGroup(metadataModel, sameAsMetadataModel)
+                .addEqualityGroup(metadataModel2)
+                .addEqualityGroup(metadataModel3)
+                .testEquals();
+    }
+}
\ No newline at end of file
diff --git a/protocols/p4runtime/model/src/test/java/org/onosproject/p4runtime/model/P4CounterModelTest.java b/protocols/p4runtime/model/src/test/java/org/onosproject/p4runtime/model/P4CounterModelTest.java
new file mode 100644
index 0000000..a3be5b4
--- /dev/null
+++ b/protocols/p4runtime/model/src/test/java/org/onosproject/p4runtime/model/P4CounterModelTest.java
@@ -0,0 +1,78 @@
+/*
+ * Copyright 2017-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.p4runtime.model;
+
+import com.google.common.testing.EqualsTester;
+import org.junit.Test;
+import org.onosproject.net.pi.model.PiCounterId;
+import org.onosproject.net.pi.model.PiCounterModel;
+import org.onosproject.net.pi.model.PiCounterType;
+import org.onosproject.net.pi.model.PiTableId;
+
+import static org.onlab.junit.ImmutableClassChecker.assertThatClassIsImmutable;
+
+/**
+ * Test for P4CounterModel class.
+ */
+public class P4CounterModelTest {
+    private static final String TABLE_0 = "table0";
+    private static final String WCMP_TABLE = "wcmp_table";
+
+    private final PiTableId tableId = PiTableId.of(TABLE_0);
+    private final PiTableId sameAsTableId = PiTableId.of(TABLE_0);
+    private final PiTableId tableId2 = PiTableId.of(WCMP_TABLE);
+
+    private final PiCounterId counterId = PiCounterId.of("name");
+
+    private final P4CounterModel counterModel = new P4CounterModel(counterId, PiCounterType.DIRECT,
+                                                                   PiCounterModel.Unit.BYTES, tableId, 16);
+
+    private final P4CounterModel sameAsCounterModel = new P4CounterModel(counterId, PiCounterType.DIRECT,
+                                                                         PiCounterModel.Unit.BYTES, sameAsTableId, 16);
+
+    private final P4CounterModel counterModel2 = new P4CounterModel(counterId, PiCounterType.INDIRECT,
+                                                                    PiCounterModel.Unit.BYTES, tableId, 16);
+
+    private final P4CounterModel counterModel3 = new P4CounterModel(counterId, PiCounterType.DIRECT,
+                                                                    PiCounterModel.Unit.PACKETS, tableId, 16);
+
+    private final P4CounterModel counterModel4 = new P4CounterModel(counterId, PiCounterType.DIRECT,
+                                                                    PiCounterModel.Unit.BYTES, tableId2, 16);
+
+    private final P4CounterModel counterModel5 = new P4CounterModel(counterId, PiCounterType.DIRECT,
+                                                                    PiCounterModel.Unit.BYTES, tableId, 32);
+    /**
+     * Checks that the P4CounterModel class is immutable.
+     */
+    @Test
+    public void testImmutability() {
+        assertThatClassIsImmutable(P4CounterModel.class);
+    }
+
+    /**
+     * Checks the operation of equals(), hashCode() and toString() methods.
+     */
+    @Test
+    public void testEquals() {
+        new EqualsTester()
+                .addEqualityGroup(counterModel, sameAsCounterModel)
+                .addEqualityGroup(counterModel2)
+                .addEqualityGroup(counterModel3)
+                .addEqualityGroup(counterModel4)
+                .addEqualityGroup(counterModel5)
+                .testEquals();
+    }
+}
\ No newline at end of file
diff --git a/protocols/p4runtime/model/src/test/java/org/onosproject/p4runtime/model/P4InfoParserTest.java b/protocols/p4runtime/model/src/test/java/org/onosproject/p4runtime/model/P4InfoParserTest.java
new file mode 100644
index 0000000..452a7a7
--- /dev/null
+++ b/protocols/p4runtime/model/src/test/java/org/onosproject/p4runtime/model/P4InfoParserTest.java
@@ -0,0 +1,294 @@
+/*
+ * Copyright 2017-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.p4runtime.model;
+
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.testing.EqualsTester;
+import com.google.protobuf.ExtensionRegistry;
+import com.google.protobuf.TextFormat;
+import org.hamcrest.collection.IsIterableContainingInAnyOrder;
+import org.hamcrest.collection.IsIterableContainingInOrder;
+import org.junit.Test;
+import org.onosproject.net.pi.model.PiActionId;
+import org.onosproject.net.pi.model.PiActionModel;
+import org.onosproject.net.pi.model.PiActionParamId;
+import org.onosproject.net.pi.model.PiActionParamModel;
+import org.onosproject.net.pi.model.PiActionProfileId;
+import org.onosproject.net.pi.model.PiActionProfileModel;
+import org.onosproject.net.pi.model.PiCounterId;
+import org.onosproject.net.pi.model.PiCounterModel;
+import org.onosproject.net.pi.model.PiMatchFieldId;
+import org.onosproject.net.pi.model.PiMatchFieldModel;
+import org.onosproject.net.pi.model.PiMatchType;
+import org.onosproject.net.pi.model.PiMeterModel;
+import org.onosproject.net.pi.model.PiPacketOperationModel;
+import org.onosproject.net.pi.model.PiPacketOperationType;
+import org.onosproject.net.pi.model.PiPipelineModel;
+import org.onosproject.net.pi.model.PiTableId;
+import org.onosproject.net.pi.model.PiTableModel;
+import p4.config.P4InfoOuterClass.Table;
+import p4.config.P4InfoOuterClass.P4Info;
+import p4.config.P4InfoOuterClass.MatchField;
+import p4.config.P4InfoOuterClass.ActionRef;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.*;
+import static org.hamcrest.core.IsNull.notNullValue;
+
+/**
+ * Test for P4Info Parser.
+ */
+public class P4InfoParserTest {
+    private static final String PATH = "basic.p4info";
+
+    private final URL p4InfoUrl = P4InfoParserTest.class.getResource(PATH);
+
+    private static final Long DEFAULT_MAX_TABLE_SIZE = 1024L;
+    private static final Long DEFAULT_MAX_ACTION_PROFILE_SIZE = 64L;
+
+    public P4InfoParserTest() throws MalformedURLException { }
+
+    /**
+     * Tests parse method.
+     * @throws Exception if equality group objects dose not match as expected
+     */
+    @Test
+    public void testParse() throws Exception {
+        // Generate two PiPipelineModels from p4Info file
+        PiPipelineModel model = P4InfoParser.parse(p4InfoUrl);
+        PiPipelineModel model2 = P4InfoParser.parse(p4InfoUrl);
+
+        // Check equality
+        new EqualsTester().addEqualityGroup(model, model2).testEquals();
+
+        // Generate a P4Info object from the file
+        final P4Info p4info;
+        try {
+            p4info = getP4InfoMessage(p4InfoUrl);
+        } catch (IOException e) {
+            throw new P4InfoParserException("Unable to parse protobuf " + p4InfoUrl.toString(), e);
+        }
+
+        List<Table> tableMsgs =  p4info.getTablesList();
+        PiTableId table0Id = PiTableId.of(tableMsgs.get(0).getPreamble().getName());
+        PiTableId wcmpTableId = PiTableId.of(tableMsgs.get(1).getPreamble().getName());
+
+        //parse tables
+        PiTableModel table0Model = model.table(table0Id).orElse(null);
+        PiTableModel wcmpTableModel = model.table(wcmpTableId).orElse(null);
+        PiTableModel table0Model2 = model2.table(table0Id).orElse(null);
+        PiTableModel wcmpTableModel2 = model2.table(wcmpTableId).orElse(null);
+
+        new EqualsTester().addEqualityGroup(table0Model, table0Model2)
+                .addEqualityGroup(wcmpTableModel, wcmpTableModel2).testEquals();
+
+        // Check existence
+        assertThat("model parsed value is null", table0Model, notNullValue());
+        assertThat("model parsed value is null", wcmpTableModel, notNullValue());
+        assertThat("Incorrect size for table0 size", table0Model.maxSize(), is(equalTo(DEFAULT_MAX_TABLE_SIZE)));
+        assertThat("Incorrect size for wcmp_table size", wcmpTableModel.maxSize(), is(equalTo(DEFAULT_MAX_TABLE_SIZE)));
+
+        // Check matchFields
+        List<MatchField> matchFieldList = tableMsgs.get(0).getMatchFieldsList();
+        List<PiMatchFieldModel> piMatchFieldList = new ArrayList<>();
+
+        for (MatchField matchFieldIter : matchFieldList) {
+            int matchTypeNumber = matchFieldIter.getMatchType().getNumber();
+            PiMatchType piMatchType = PiMatchType.VALID;
+            switch (matchTypeNumber) {
+                case 1: piMatchType = PiMatchType.VALID; break;
+                case 2: piMatchType = PiMatchType.EXACT; break;
+                case 3: piMatchType = PiMatchType.LPM; break;
+                case 4: piMatchType = piMatchType.TERNARY; break;
+                case 5: piMatchType = piMatchType.RANGE; break;
+                default: piMatchType = PiMatchType.VALID; break;
+            }
+            piMatchFieldList.add(new P4MatchFieldModel(PiMatchFieldId.of(matchFieldIter.getName()),
+                                                       matchFieldIter.getBitwidth(), piMatchType));
+        }
+        // Check MatchFields size
+        assertThat("Incorrect size for matchFields", table0Model.matchFields().size(), is(equalTo(9)));
+        // Check if matchFields are in order
+        assertThat("Incorrect order for matchFields", table0Model.matchFields(), IsIterableContainingInOrder.contains(
+                piMatchFieldList.get(0), piMatchFieldList.get(1),
+                piMatchFieldList.get(2), piMatchFieldList.get(3),
+                piMatchFieldList.get(4), piMatchFieldList.get(5),
+                piMatchFieldList.get(6), piMatchFieldList.get(7),
+                piMatchFieldList.get(8)));
+
+        assertThat("Incorrect size for matchFields", wcmpTableModel.matchFields().size(), is(equalTo(1)));
+
+        // check if matchFields are in order
+        matchFieldList = tableMsgs.get(1).getMatchFieldsList();
+        assertThat("Incorrect order for matchFields",
+                   wcmpTableModel.matchFields(), IsIterableContainingInOrder.contains(
+                        new P4MatchFieldModel(PiMatchFieldId.of(matchFieldList.get(0).getName()),
+                                              matchFieldList.get(0).getBitwidth(), PiMatchType.EXACT)));
+
+        //check table0 actionsRefs
+        List<ActionRef> actionRefList = tableMsgs.get(0).getActionRefsList();
+        assertThat("Incorrect size for actionRefs", actionRefList.size(), is(equalTo(4)));
+
+        //create action instances
+        PiActionId actionId = PiActionId.of("set_egress_port");
+        PiActionParamId piActionParamId = PiActionParamId.of("port");
+        int bitWitdth = 9;
+        PiActionParamModel actionParamModel = new P4ActionParamModel(piActionParamId, bitWitdth);
+        ImmutableMap<PiActionParamId, PiActionParamModel> params = new
+                ImmutableMap.Builder<PiActionParamId, PiActionParamModel>()
+                .put(piActionParamId, actionParamModel).build();
+
+        PiActionModel setEgressPortAction = new P4ActionModel(actionId, params);
+
+        actionId = PiActionId.of("send_to_cpu");
+        PiActionModel sendToCpuAction =
+                new P4ActionModel(actionId, new ImmutableMap.Builder<PiActionParamId, PiActionParamModel>().build());
+
+        actionId = PiActionId.of("_drop");
+        PiActionModel dropAction =
+                new P4ActionModel(actionId, new ImmutableMap.Builder<PiActionParamId, PiActionParamModel>().build());
+
+        actionId = PiActionId.of("NoAction");
+        PiActionModel noAction =
+                new P4ActionModel(actionId, new ImmutableMap.Builder<PiActionParamId, PiActionParamModel>().build());
+
+        actionId = PiActionId.of("table0_control.set_next_hop_id");
+        piActionParamId = PiActionParamId.of("next_hop_id");
+        bitWitdth = 16;
+        actionParamModel = new P4ActionParamModel(piActionParamId, bitWitdth);
+        params = new ImmutableMap.Builder<PiActionParamId, PiActionParamModel>()
+                .put(piActionParamId, actionParamModel).build();
+
+        PiActionModel setNextHopIdAction = new P4ActionModel(actionId, params);
+
+        //check table0 actions
+        assertThat("action dose not match",
+                   table0Model.actions(), IsIterableContainingInAnyOrder.containsInAnyOrder(
+                        setEgressPortAction, sendToCpuAction, setNextHopIdAction, dropAction));
+
+        //check wcmp_table actions
+        assertThat("actions dose not match",
+                   wcmpTableModel.actions(), IsIterableContainingInAnyOrder.containsInAnyOrder(
+                        setEgressPortAction, noAction));
+
+        PiActionModel table0DefaultAction = table0Model.defaultAction().orElse(null);
+
+        new EqualsTester().addEqualityGroup(table0DefaultAction, dropAction).testEquals();
+
+        // Check existence
+        assertThat("model parsed value is null", table0DefaultAction, notNullValue());
+
+        //parse action profiles
+        PiTableId tableId = PiTableId.of("wcmp_control.wcmp_table");
+        ImmutableSet<PiTableId> tableIds = new ImmutableSet.Builder<PiTableId>().add(tableId).build();
+        PiActionProfileId actionProfileId = PiActionProfileId.of("wcmp_control.wcmp_selector");
+        PiActionProfileModel wcmpSelector3 = new P4ActionProfileModel(actionProfileId, tableIds,
+                                                                      true, DEFAULT_MAX_ACTION_PROFILE_SIZE);
+        PiActionProfileModel wcmpSelector = model.actionProfiles(actionProfileId).orElse(null);
+        PiActionProfileModel wcmpSelector2 = model2.actionProfiles(actionProfileId).orElse(null);
+
+        new EqualsTester().addEqualityGroup(wcmpSelector, wcmpSelector2, wcmpSelector3).testEquals();
+
+        // Check existence
+        assertThat("model parsed value is null", wcmpSelector, notNullValue());
+        assertThat("Incorrect value for actions profiles", model.actionProfiles(), containsInAnyOrder(wcmpSelector));
+        // ActionProfiles size
+        assertThat("Incorrect size for action profiles", model.actionProfiles().size(), is(equalTo(1)));
+
+        //parse counters
+        PiCounterModel ingressPortCounterModel =
+                model.counter(PiCounterId.of("port_counters_ingress.ingress_port_counter")).orElse(null);
+        PiCounterModel egressPortCounterModel =
+                model.counter(PiCounterId.of("port_counters_egress.egress_port_counter")).orElse(null);
+        PiCounterModel table0CounterModel =
+                model.counter(PiCounterId.of("table0_control.table0_counter")).orElse(null);
+        PiCounterModel wcmpTableCounterModel =
+                model.counter(PiCounterId.of("wcmp_control.wcmp_table_counter")).orElse(null);
+
+        PiCounterModel ingressPortCounterModel2 =
+                model2.counter(PiCounterId.of("port_counters_ingress.ingress_port_counter")).orElse(null);
+        PiCounterModel egressPortCounterModel2 =
+                model2.counter(PiCounterId.of("port_counters_egress.egress_port_counter")).orElse(null);
+        PiCounterModel table0CounterModel2 =
+                model2.counter(PiCounterId.of("table0_control.table0_counter")).orElse(null);
+        PiCounterModel wcmpTableCounterModel2 =
+                model2.counter(PiCounterId.of("wcmp_control.wcmp_table_counter")).orElse(null);
+
+        new EqualsTester()
+                .addEqualityGroup(ingressPortCounterModel, ingressPortCounterModel2)
+                .addEqualityGroup(egressPortCounterModel, egressPortCounterModel2)
+                .addEqualityGroup(table0CounterModel, table0CounterModel2)
+                .addEqualityGroup(wcmpTableCounterModel, wcmpTableCounterModel2)
+                .testEquals();
+
+        assertThat("model parsed value is null", ingressPortCounterModel, notNullValue());
+        assertThat("model parsed value is null", egressPortCounterModel, notNullValue());
+        assertThat("model parsed value is null", table0CounterModel, notNullValue());
+        assertThat("model parsed value is null", wcmpTableCounterModel, notNullValue());
+
+        //Parse meters
+        Collection<PiMeterModel> meterModel = model.meters();
+        Collection<PiMeterModel> meterModel2 = model2.meters();
+
+        assertThat("model pased meter collaction should be empty", meterModel.isEmpty(), is(true));
+        assertThat("model pased meter collaction should be empty", meterModel2.isEmpty(), is(true));
+
+        //parse packet operations
+        PiPacketOperationModel packetInOperationalModel =
+                model.packetOperationModel(PiPacketOperationType.PACKET_IN).orElse(null);
+        PiPacketOperationModel packetOutOperationalModel =
+                model.packetOperationModel(PiPacketOperationType.PACKET_OUT).orElse(null);
+
+        PiPacketOperationModel packetInOperationalModel2 =
+                model2.packetOperationModel(PiPacketOperationType.PACKET_IN).orElse(null);
+        PiPacketOperationModel packetOutOperationalModel2 =
+                model2.packetOperationModel(PiPacketOperationType.PACKET_OUT).orElse(null);
+
+        new EqualsTester()
+                .addEqualityGroup(packetInOperationalModel, packetInOperationalModel2)
+                .addEqualityGroup(packetOutOperationalModel, packetOutOperationalModel2)
+                .testEquals();
+
+        // Check existence
+        assertThat("model parsed value is null", packetInOperationalModel, notNullValue());
+        assertThat("model parsed value is null", packetOutOperationalModel, notNullValue());
+    }
+
+    /**
+     * Gets P4Info message from the URL.
+     * @param p4InfoUrl link to the p4Info file
+     * @return a P4Info object
+     * @throws IOException if any problem occurs while reading from the URL connection.
+     */
+    private P4Info getP4InfoMessage(URL p4InfoUrl) throws IOException {
+        InputStream p4InfoStream = p4InfoUrl.openStream();
+        P4Info.Builder p4InfoBuilder = P4Info.newBuilder();
+        TextFormat.getParser().merge(new InputStreamReader(p4InfoStream),
+                                     ExtensionRegistry.getEmptyRegistry(),
+                                     p4InfoBuilder);
+        return p4InfoBuilder.build();
+    }
+}
diff --git a/protocols/p4runtime/model/src/test/resources/org/onosproject/p4runtime/model/basic.p4info b/protocols/p4runtime/model/src/test/resources/org/onosproject/p4runtime/model/basic.p4info
new file mode 100644
index 0000000..8010892
--- /dev/null
+++ b/protocols/p4runtime/model/src/test/resources/org/onosproject/p4runtime/model/basic.p4info
@@ -0,0 +1,222 @@
+tables {
+  preamble {
+    id: 33571508
+    name: "table0_control.table0"
+    alias: "table0"
+  }
+  match_fields {
+    id: 1
+    name: "standard_metadata.ingress_port"
+    bitwidth: 9
+    match_type: TERNARY
+  }
+  match_fields {
+    id: 2
+    name: "hdr.ethernet.src_addr"
+    bitwidth: 48
+    match_type: TERNARY
+  }
+  match_fields {
+    id: 3
+    name: "hdr.ethernet.dst_addr"
+    bitwidth: 48
+    match_type: TERNARY
+  }
+  match_fields {
+    id: 4
+    name: "hdr.ethernet.ether_type"
+    bitwidth: 16
+    match_type: TERNARY
+  }
+  match_fields {
+    id: 5
+    name: "hdr.ipv4.src_addr"
+    bitwidth: 32
+    match_type: TERNARY
+  }
+  match_fields {
+    id: 6
+    name: "hdr.ipv4.dst_addr"
+    bitwidth: 32
+    match_type: TERNARY
+  }
+  match_fields {
+    id: 7
+    name: "hdr.ipv4.protocol"
+    bitwidth: 8
+    match_type: TERNARY
+  }
+  match_fields {
+    id: 8
+    name: "local_metadata.l4_src_port"
+    bitwidth: 16
+    match_type: TERNARY
+  }
+  match_fields {
+    id: 9
+    name: "local_metadata.l4_dst_port"
+    bitwidth: 16
+    match_type: TERNARY
+  }
+  action_refs {
+    id: 16794308
+  }
+  action_refs {
+    id: 16829080
+  }
+  action_refs {
+    id: 16802895
+  }
+  action_refs {
+    id: 16784184
+  }
+  const_default_action_id: 16784184
+  direct_resource_ids: 302046050
+  size: 1024
+}
+tables {
+  preamble {
+    id: 33592597
+    name: "wcmp_control.wcmp_table"
+    alias: "wcmp_table"
+  }
+  match_fields {
+    id: 1
+    name: "local_metadata.next_hop_id"
+    bitwidth: 16
+    match_type: EXACT
+  }
+  action_refs {
+    id: 16794308
+  }
+  action_refs {
+    id: 16800567
+    annotations: "@defaultonly()"
+  }
+  implementation_id: 285259294
+  direct_resource_ids: 302001091
+  size: 1024
+}
+actions {
+  preamble {
+    id: 16794308
+    name: "set_egress_port"
+    alias: "set_egress_port"
+  }
+  params {
+    id: 1
+    name: "port"
+    bitwidth: 9
+  }
+}
+actions {
+  preamble {
+    id: 16829080
+    name: "send_to_cpu"
+    alias: "send_to_cpu"
+  }
+}
+actions {
+  preamble {
+    id: 16784184
+    name: "_drop"
+    alias: "_drop"
+  }
+}
+actions {
+  preamble {
+    id: 16800567
+    name: "NoAction"
+    alias: "NoAction"
+  }
+}
+actions {
+  preamble {
+    id: 16802895
+    name: "table0_control.set_next_hop_id"
+    alias: "set_next_hop_id"
+  }
+  params {
+    id: 1
+    name: "next_hop_id"
+    bitwidth: 16
+  }
+}
+action_profiles {
+  preamble {
+    id: 285259294
+    name: "wcmp_control.wcmp_selector"
+    alias: "wcmp_selector"
+  }
+  table_ids: 33592597
+  with_selector: true
+  size: 64
+}
+counters {
+  preamble {
+    id: 302012579
+    name: "port_counters_ingress.ingress_port_counter"
+    alias: "ingress_port_counter"
+  }
+  spec {
+    unit: PACKETS
+  }
+  size: 511
+}
+counters {
+  preamble {
+    id: 302012501
+    name: "port_counters_egress.egress_port_counter"
+    alias: "egress_port_counter"
+  }
+  spec {
+    unit: PACKETS
+  }
+  size: 511
+}
+direct_counters {
+  preamble {
+    id: 302046050
+    name: "table0_control.table0_counter"
+    alias: "table0_counter"
+  }
+  spec {
+    unit: BOTH
+  }
+  direct_table_id: 33571508
+}
+direct_counters {
+  preamble {
+    id: 302001091
+    name: "wcmp_control.wcmp_table_counter"
+    alias: "wcmp_table_counter"
+  }
+  spec {
+    unit: BOTH
+  }
+  direct_table_id: 33592597
+}
+controller_packet_metadata {
+  preamble {
+    id: 2868941301
+    name: "packet_in"
+    annotations: "@controller_header(\"packet_in\")"
+  }
+  metadata {
+    id: 1
+    name: "ingress_port"
+    bitwidth: 9
+  }
+}
+controller_packet_metadata {
+  preamble {
+    id: 2868916615
+    name: "packet_out"
+    annotations: "@controller_header(\"packet_out\")"
+  }
+  metadata {
+    id: 1
+    name: "egress_port"
+    bitwidth: 9
+  }
+}