Add tests for codecs and P4Info parser when P4Runtime Translation is used

Change-Id: Ied0e83e81dad29f5b250548d2e26ec960b98f560
diff --git a/protocols/p4runtime/ctl/src/test/java/org/onosproject/p4runtime/ctl/codec/TableEntryEncoderTest.java b/protocols/p4runtime/ctl/src/test/java/org/onosproject/p4runtime/ctl/codec/TableEntryEncoderTest.java
index 0619f6a..c213753 100644
--- a/protocols/p4runtime/ctl/src/test/java/org/onosproject/p4runtime/ctl/codec/TableEntryEncoderTest.java
+++ b/protocols/p4runtime/ctl/src/test/java/org/onosproject/p4runtime/ctl/codec/TableEntryEncoderTest.java
@@ -66,6 +66,7 @@
     private static final String DST_ADDR = "dstAddr";
     private static final String SRC_ADDR = "srcAddr";
     private static final String STANDARD_METADATA = "standard_metadata";
+    private static final String LOCAL_METADATA = "local_metadata";
     private static final String ECMP_METADATA = "ecmp_metadata";
     private static final String INGRESS_PORT = "ingress_port";
     private static final String ETHER_TYPE = "etherType";
@@ -76,6 +77,7 @@
 
     private final Random rand = new Random();
     private final URL p4InfoUrl = this.getClass().getResource("/test.p4info");
+    private final URL p4InfoUrl2 = this.getClass().getResource("/test_p4runtime_translation_p4info.txt");
 
     private final PiPipeconf defaultPipeconf = DefaultPiPipeconf.builder()
             .withId(new PiPipeconfId("mock"))
@@ -83,17 +85,30 @@
             .addExtension(P4_INFO_TEXT, p4InfoUrl)
             .build();
 
+    private final PiPipeconf defaultPipeconf2 = DefaultPiPipeconf.builder()
+            .withId(new PiPipeconfId("mock"))
+            .withPipelineModel(EasyMock.niceMock(PiPipelineModel.class))
+            .addExtension(P4_INFO_TEXT, p4InfoUrl2)
+            .build();
+
     private final P4InfoBrowser browser = PipeconfHelper.getP4InfoBrowser(defaultPipeconf);
     private final ImmutableByteSequence ethAddr = copyFrom(rand.nextInt()).fit(48);
+    private final ImmutableByteSequence ethAddrString = ImmutableByteSequence.copyFrom(
+            "00:11:22:33:44:55:66".getBytes());
     private final ImmutableByteSequence portValue = copyFrom((short) rand.nextInt());
+    private final ImmutableByteSequence portValueString = ImmutableByteSequence.copyFrom(
+            String.format("Ethernet%d", rand.nextInt()).getBytes());
+    private final ImmutableByteSequence portValue32Bit = copyFrom((short) rand.nextInt()).fit(32);
     private final PiMatchFieldId ethDstAddrFieldId = PiMatchFieldId.of(HDR + DOT + ETHERNET + DOT + DST_ADDR);
     private final PiMatchFieldId ethSrcAddrFieldId = PiMatchFieldId.of(HDR + DOT + ETHERNET + DOT + SRC_ADDR);
     private final PiMatchFieldId inPortFieldId = PiMatchFieldId.of(STANDARD_METADATA + DOT + INGRESS_PORT);
+    private final PiMatchFieldId inPortFieldId2 = PiMatchFieldId.of(LOCAL_METADATA + DOT + INGRESS_PORT);
     private final PiMatchFieldId ethTypeFieldId = PiMatchFieldId.of(HDR + DOT + ETHERNET + DOT + ETHER_TYPE);
     private final PiMatchFieldId ecmpGroupFieldId =
             PiMatchFieldId.of(META + DOT + ECMP_METADATA + DOT + ECMP_GROUP_ID);
     private final PiActionParamId portParamId = PiActionParamId.of(PORT);
     private final PiActionId outActionId = PiActionId.of(SET_EGRESS_PORT);
+    private final PiActionId outActionId2 = PiActionId.of(SET_EGRESS_PORT + "2");
     private final PiTableId tableId = PiTableId.of(TABLE_0);
     private final PiTableId ecmpTableId = PiTableId.of(TABLE_ECMP);
     private final PiCounterCellData counterCellData = new PiCounterCellData(PACKETS, BYTES);
@@ -117,6 +132,42 @@
             .withCounterCellData(counterCellData)
             .build();
 
+    private final PiTableEntry piTableEntry2 = PiTableEntry
+            .builder()
+            .forTable(tableId)
+            .withMatchKey(PiMatchKey.builder()
+                                  .addFieldMatch(new PiExactFieldMatch(inPortFieldId2, portValue32Bit))
+                                  .addFieldMatch(new PiExactFieldMatch(ethDstAddrFieldId, ethAddrString))
+                                  .addFieldMatch(new PiExactFieldMatch(ethSrcAddrFieldId, ethAddrString))
+                                  .addFieldMatch(new PiExactFieldMatch(ethTypeFieldId, portValue))
+                                  .build())
+            .withAction(PiAction
+                                .builder()
+                                .withId(outActionId)
+                                .withParameter(new PiActionParam(portParamId, portValueString))
+                                .build())
+            .withPriority(1)
+            .withCookie(2)
+            .build();
+
+    private final PiTableEntry piTableEntry3 = PiTableEntry
+            .builder()
+            .forTable(tableId)
+            .withMatchKey(PiMatchKey.builder()
+                                  .addFieldMatch(new PiExactFieldMatch(inPortFieldId2, portValue32Bit))
+                                  .addFieldMatch(new PiExactFieldMatch(ethDstAddrFieldId, ethAddrString))
+                                  .addFieldMatch(new PiExactFieldMatch(ethSrcAddrFieldId, ethAddrString))
+                                  .addFieldMatch(new PiExactFieldMatch(ethTypeFieldId, portValue))
+                                  .build())
+            .withAction(PiAction
+                                .builder()
+                                .withId(outActionId2)
+                                .withParameter(new PiActionParam(portParamId, portValue32Bit))
+                                .build())
+            .withPriority(1)
+            .withCookie(2)
+            .build();
+
     private final PiTableEntry piTableEntryWithoutAction = PiTableEntry
             .builder()
             .forTable(tableId)
@@ -175,7 +226,6 @@
         new EqualsTester()
                 .addEqualityGroup(piTableEntry, decodedPiTableEntry)
                 .testEquals();
-
         // Table ID.
         int p4InfoTableId = browser.tables().getByName(tableId.id()).getPreamble().getId();
         int encodedTableId = tableEntryMsg.getTableId();
@@ -211,6 +261,39 @@
     }
 
     @Test
+    public void testTableEntryEncoderWithTranslations() throws Exception {
+        TableEntry tableEntryMsg = Codecs.CODECS.tableEntry().encode(
+                piTableEntry2, null, defaultPipeconf2);
+        PiTableEntry decodedPiTableEntry = Codecs.CODECS.tableEntry().decode(
+                tableEntryMsg, null, defaultPipeconf2);
+
+        // Test equality for decoded entry.
+        new EqualsTester()
+                .addEqualityGroup(piTableEntry2, decodedPiTableEntry)
+                .testEquals();
+
+        // Check the exact match with string
+        byte[] encodedExactMatchValueString = tableEntryMsg.getMatch(1).getExact().getValue().toByteArray();
+        assertThat(encodedExactMatchValueString, is(ethAddrString.asArray()));
+
+        Action actionMsg = tableEntryMsg.getAction().getAction();
+
+        // Check action param value with string
+        byte[] encodedActionParamString = actionMsg.getParams(0).getValue().toByteArray();
+        assertThat(encodedActionParamString, is(portValueString.asArray()));
+
+        TableEntry tableEntryMsg1 = Codecs.CODECS.tableEntry().encode(
+                piTableEntry3, null, defaultPipeconf2);
+        PiTableEntry decodedPiTableEntry1 = Codecs.CODECS.tableEntry().decode(
+                tableEntryMsg1, null, defaultPipeconf2);
+
+        // Test equality for decoded entry.
+        new EqualsTester()
+                .addEqualityGroup(piTableEntry3, decodedPiTableEntry1)
+                .testEquals();
+    }
+
+    @Test
     public void testActopProfileGroup() throws Exception {
         TableEntry tableEntryMsg = Codecs.CODECS.tableEntry().encode(
                 piTableEntryWithGroupAction, null, defaultPipeconf);
diff --git a/protocols/p4runtime/ctl/src/test/resources/Makefile b/protocols/p4runtime/ctl/src/test/resources/Makefile
new file mode 100644
index 0000000..964ca18
--- /dev/null
+++ b/protocols/p4runtime/ctl/src/test/resources/Makefile
@@ -0,0 +1,7 @@
+all: test
+
+test: test_p4runtime_translation.p4
+	@./bmv2-compile.sh "test_p4runtime_translation" ""
+
+clean:
+	rm test_p4runtime_translation_p4info.txt
diff --git a/protocols/p4runtime/ctl/src/test/resources/bmv2-compile.sh b/protocols/p4runtime/ctl/src/test/resources/bmv2-compile.sh
new file mode 100755
index 0000000..4bcf40b
--- /dev/null
+++ b/protocols/p4runtime/ctl/src/test/resources/bmv2-compile.sh
@@ -0,0 +1,21 @@
+#!/usr/bin/env bash
+
+set -e
+
+PROFILE=$1
+OTHER_FLAGS=$2
+
+SRC_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )"
+
+echo
+echo "## Compiling profile ${PROFILE} in ${SRC_DIR}..."
+
+# Using stable-20210108 because stable doesn't support @p4runtime_translation annotations
+dockerImage=opennetworking/p4c:stable-20210108
+dockerRun="docker run --rm -w ${SRC_DIR} -v ${SRC_DIR}:${SRC_DIR} ${dockerImage}"
+
+
+# Generate BMv2 JSON and P4Info.
+(set -x; ${dockerRun} p4c-bm2-ss --arch v1model \
+        ${OTHER_FLAGS} \
+        --p4runtime-files ${SRC_DIR}/${PROFILE}_p4info.txt ${PROFILE}.p4)
diff --git a/protocols/p4runtime/ctl/src/test/resources/test_p4runtime_translation.p4 b/protocols/p4runtime/ctl/src/test/resources/test_p4runtime_translation.p4
new file mode 100644
index 0000000..6ebf306
--- /dev/null
+++ b/protocols/p4runtime/ctl/src/test/resources/test_p4runtime_translation.p4
@@ -0,0 +1,185 @@
+/*
+ * Copyright 2020-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.
+ */
+
+#include <core.p4>
+#include <v1model.p4>
+
+typedef bit<9> port_t;
+
+@p4runtime_translation("", string)
+type bit<48> mac_addr_t;
+
+@p4runtime_translation("", 32)
+type port_t port_id_bit_t;
+
+@p4runtime_translation("", string)
+type port_t port_id_str_t;
+
+const port_t CPU_PORT = 255;
+
+@controller_header("packet_in")
+header packet_in_header_t {
+    bit<9> ingress_port;
+    bit<7> _padding;
+}
+
+@controller_header("packet_out")
+header packet_out_header_t {
+    bit<9> egress_port;
+    bit<7> _padding;
+}
+
+header ethernet_t {
+    mac_addr_t dstAddr;
+    mac_addr_t srcAddr;
+    bit<16> etherType;
+}
+
+struct headers_t {
+    packet_out_header_t packet_out;
+    packet_in_header_t packet_in;
+    ethernet_t ethernet;
+}
+
+struct local_metadata_t {
+    port_id_bit_t ingress_port;
+}
+
+// Test P4 Program for P4Runtime translation (simplified version of basic.p4).
+
+//------------------------------------------------------------------------------
+// PARSER
+//------------------------------------------------------------------------------
+parser parser_impl(packet_in packet,
+                  out headers_t hdr,
+                  inout local_metadata_t local_metadata,
+                  inout standard_metadata_t standard_metadata) {
+
+    state start {
+        local_metadata.ingress_port = (port_id_bit_t) standard_metadata.ingress_port;
+        transition select(standard_metadata.ingress_port) {
+            CPU_PORT: parse_packet_out;
+            default: parse_ethernet;
+        }
+    }
+
+    state parse_packet_out {
+        packet.extract(hdr.packet_out);
+        transition parse_ethernet;
+    }
+
+    state parse_ethernet {
+        packet.extract(hdr.ethernet);
+        transition accept;
+    }
+}
+
+//------------------------------------------------------------------------------
+// DEPARSER
+//------------------------------------------------------------------------------
+control deparser(packet_out packet, in headers_t hdr) {
+    apply {
+        packet.emit(hdr.packet_in);
+        packet.emit(hdr.ethernet);
+    }
+}
+
+
+//------------------------------------------------------------------------------
+// INGRESS PIPELINE
+//------------------------------------------------------------------------------
+
+control ingress(inout headers_t hdr,
+                inout local_metadata_t local_metadata,
+                inout standard_metadata_t standard_metadata) {
+
+    @name(".send_to_cpu")
+    action send_to_cpu() {
+        standard_metadata.egress_spec = CPU_PORT;
+    }
+
+    @name(".set_egress_port")
+    action set_egress_port(port_id_str_t port) {
+        standard_metadata.egress_spec = (bit<9>) port;
+    }
+    @name(".set_egress_port2")
+    action set_egress_port2(port_id_bit_t port) {
+        standard_metadata.egress_spec = (bit<9>) port;
+    }
+
+    @name(".drop")
+    action drop() {
+        mark_to_drop(standard_metadata);
+    }
+    @name(".table0")
+    table table0 {
+        key = {
+            local_metadata.ingress_port : exact;
+            hdr.ethernet.srcAddr        : exact;
+            hdr.ethernet.dstAddr        : exact;
+            hdr.ethernet.etherType      : exact;
+        }
+        actions = {
+            set_egress_port;
+            set_egress_port2;
+            send_to_cpu;
+            drop;
+        }
+        const default_action = drop();
+    }
+
+    apply {
+        table0.apply();
+     }
+}
+
+//------------------------------------------------------------------------------
+// EGRESS PIPELINE
+//------------------------------------------------------------------------------
+
+control egress(inout headers_t hdr,
+               inout local_metadata_t local_metadata,
+               inout standard_metadata_t standard_metadata) {
+
+    apply {
+    // no-op
+    }
+}
+
+control verify_checksum_control(inout headers_t hdr,
+                                inout local_metadata_t local_metadata) {
+    apply {
+        // Assume checksum is always correct.
+    }
+}
+
+control compute_checksum_control(inout headers_t hdr,
+                                 inout local_metadata_t local_metadata) {
+    apply {
+    // no-op for the test program
+    }
+}
+
+//------------------------------------------------------------------------------
+// SWITCH INSTANTIATION
+//------------------------------------------------------------------------------
+
+V1Switch(parser_impl(),
+         verify_checksum_control(),
+         ingress(),
+         egress(),
+         compute_checksum_control(),
+         deparser()) main;
diff --git a/protocols/p4runtime/ctl/src/test/resources/test_p4runtime_translation_p4info.txt b/protocols/p4runtime/ctl/src/test/resources/test_p4runtime_translation_p4info.txt
new file mode 100644
index 0000000..241d989
--- /dev/null
+++ b/protocols/p4runtime/ctl/src/test/resources/test_p4runtime_translation_p4info.txt
@@ -0,0 +1,162 @@
+pkg_info {
+  arch: "v1model"
+}
+tables {
+  preamble {
+    id: 36960149
+    name: "table0"
+    alias: "table0"
+  }
+  match_fields {
+    id: 1
+    name: "local_metadata.ingress_port"
+    bitwidth: 32
+    match_type: EXACT
+    type_name {
+      name: "port_id_bit_t"
+    }
+  }
+  match_fields {
+    id: 2
+    name: "hdr.ethernet.srcAddr"
+    match_type: EXACT
+    type_name {
+      name: "mac_addr_t"
+    }
+  }
+  match_fields {
+    id: 3
+    name: "hdr.ethernet.dstAddr"
+    match_type: EXACT
+    type_name {
+      name: "mac_addr_t"
+    }
+  }
+  match_fields {
+    id: 4
+    name: "hdr.ethernet.etherType"
+    bitwidth: 16
+    match_type: EXACT
+  }
+  action_refs {
+    id: 27607748
+  }
+  action_refs {
+    id: 32872817
+  }
+  action_refs {
+    id: 24562328
+  }
+  action_refs {
+    id: 18759588
+  }
+  const_default_action_id: 18759588
+  size: 1024
+}
+actions {
+  preamble {
+    id: 24562328
+    name: "send_to_cpu"
+    alias: "send_to_cpu"
+  }
+}
+actions {
+  preamble {
+    id: 27607748
+    name: "set_egress_port"
+    alias: "set_egress_port"
+  }
+  params {
+    id: 1
+    name: "port"
+    type_name {
+      name: "port_id_str_t"
+    }
+  }
+}
+actions {
+  preamble {
+    id: 32872817
+    name: "set_egress_port2"
+    alias: "set_egress_port2"
+  }
+  params {
+    id: 1
+    name: "port"
+    bitwidth: 32
+    type_name {
+      name: "port_id_bit_t"
+    }
+  }
+}
+actions {
+  preamble {
+    id: 18759588
+    name: "drop"
+    alias: "drop"
+  }
+}
+controller_packet_metadata {
+  preamble {
+    id: 81826293
+    name: "packet_in"
+    alias: "packet_in"
+    annotations: "@controller_header(\"packet_in\")"
+  }
+  metadata {
+    id: 1
+    name: "ingress_port"
+    bitwidth: 9
+  }
+  metadata {
+    id: 2
+    name: "_padding"
+    bitwidth: 7
+  }
+}
+controller_packet_metadata {
+  preamble {
+    id: 76689799
+    name: "packet_out"
+    alias: "packet_out"
+    annotations: "@controller_header(\"packet_out\")"
+  }
+  metadata {
+    id: 1
+    name: "egress_port"
+    bitwidth: 9
+  }
+  metadata {
+    id: 2
+    name: "_padding"
+    bitwidth: 7
+  }
+}
+type_info {
+  new_types {
+    key: "mac_addr_t"
+    value {
+      translated_type {
+        sdn_string {
+        }
+      }
+    }
+  }
+  new_types {
+    key: "port_id_bit_t"
+    value {
+      translated_type {
+        sdn_bitwidth: 32
+      }
+    }
+  }
+  new_types {
+    key: "port_id_str_t"
+    value {
+      translated_type {
+        sdn_string {
+        }
+      }
+    }
+  }
+}
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
index c05a84c..0432a18 100644
--- 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
@@ -65,8 +65,10 @@
  */
 public class P4InfoParserTest {
     private static final String PATH = "basic.p4info";
+    private static final String PATH2 = "test_p4runtime_translation_p4info.txt";
 
     private final URL p4InfoUrl = P4InfoParserTest.class.getResource(PATH);
+    private final URL p4InfoUrl2 = P4InfoParserTest.class.getResource(PATH2);
 
     private static final Long DEFAULT_MAX_TABLE_SIZE = 1024L;
     private static final Long DEFAULT_MAX_ACTION_PROFILE_SIZE = 64L;
@@ -279,6 +281,96 @@
     }
 
     /**
+     * Tests parse method with P4Runtime translation fields.
+     * @throws Exception if equality group objects dose not match as expected
+     */
+    @Test
+    public void testParseP4RuntimeTranslation() throws Exception {
+        PiPipelineModel model = P4InfoParser.parse(p4InfoUrl2);
+        // Generate a P4Info object from the file
+        final P4Info p4info;
+        try {
+            p4info = getP4InfoMessage(p4InfoUrl2);
+        } 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());
+
+        //parse tables
+        PiTableModel table0Model = model.table(table0Id).orElse(null);
+
+        // Check matchFields
+        List<MatchField> matchFieldList = tableMsgs.get(0).getMatchFieldsList();
+        List<PiMatchFieldModel> piMatchFieldList = new ArrayList<>();
+
+        for (MatchField matchFieldIter : matchFieldList) {
+            MatchField.MatchType matchType = matchFieldIter.getMatchType();
+            PiMatchType piMatchType;
+            switch (matchType) {
+                case EXACT: piMatchType = PiMatchType.EXACT; break;
+                case LPM: piMatchType = PiMatchType.LPM; break;
+                case TERNARY: piMatchType = PiMatchType.TERNARY; break;
+                case RANGE: piMatchType = PiMatchType.RANGE; break;
+                default: Assert.fail(); return;
+            }
+            if (matchFieldIter.getTypeName().getName().equals("mac_addr_t")) {
+                piMatchFieldList.add(new P4MatchFieldModel(PiMatchFieldId.of(matchFieldIter.getName()),
+                                                           P4MatchFieldModel.BIT_WIDTH_UNDEFINED, piMatchType));
+            } else {
+                piMatchFieldList.add(new P4MatchFieldModel(PiMatchFieldId.of(matchFieldIter.getName()),
+                                                           matchFieldIter.getBitwidth(), piMatchType));
+            }
+        }
+        assertThat("Incorrect order for matchFields",
+                   table0Model.matchFields(),
+                   IsIterableContainingInOrder.contains(
+                           piMatchFieldList.get(0), piMatchFieldList.get(1),
+                           piMatchFieldList.get(2), piMatchFieldList.get(3)));
+
+        //check table0 actionsRefs
+        List<ActionRef> actionRefList = tableMsgs.get(0).getActionRefsList();
+        assertThat("Incorrect size for actionRefs",
+                   actionRefList.size(),
+                   is(equalTo(4)));
+
+        //create action instances
+        // Set egress with string as parameter
+        PiActionId actionId = PiActionId.of("set_egress_port");
+        PiActionParamId piActionParamId = PiActionParamId.of("port");
+        PiActionParamModel actionParamModel = new P4ActionParamModel(
+                piActionParamId, P4ActionParamModel.BIT_WIDTH_UNDEFINED);
+        ImmutableMap<PiActionParamId, PiActionParamModel> params = new
+                ImmutableMap.Builder<PiActionParamId, PiActionParamModel>()
+                .put(piActionParamId, actionParamModel).build();
+        PiActionModel setEgressPortAction = new P4ActionModel(actionId, params);
+
+        // Set egress with 32 bit as parameter
+        actionId = PiActionId.of("set_egress_port2");
+        piActionParamId = PiActionParamId.of("port");
+        int bitWitdth = 32;
+        actionParamModel = new P4ActionParamModel(
+                piActionParamId, bitWitdth);
+        params = new ImmutableMap.Builder<PiActionParamId, PiActionParamModel>()
+                .put(piActionParamId, actionParamModel).build();
+
+        PiActionModel setEgressPortAction2 = 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());
+
+        //check table0 actions
+        assertThat("action dose not match",
+                   table0Model.actions(), IsIterableContainingInAnyOrder.containsInAnyOrder(
+                        setEgressPortAction, setEgressPortAction2, sendToCpuAction, dropAction));
+    }
+
+    /**
      * Gets P4Info message from the URL.
      * @param p4InfoUrl link to the p4Info file
      * @return a P4Info object
diff --git a/protocols/p4runtime/model/src/test/resources/org/onosproject/p4runtime/model/test_p4runtime_translation_p4info.txt b/protocols/p4runtime/model/src/test/resources/org/onosproject/p4runtime/model/test_p4runtime_translation_p4info.txt
new file mode 100644
index 0000000..241d989
--- /dev/null
+++ b/protocols/p4runtime/model/src/test/resources/org/onosproject/p4runtime/model/test_p4runtime_translation_p4info.txt
@@ -0,0 +1,162 @@
+pkg_info {
+  arch: "v1model"
+}
+tables {
+  preamble {
+    id: 36960149
+    name: "table0"
+    alias: "table0"
+  }
+  match_fields {
+    id: 1
+    name: "local_metadata.ingress_port"
+    bitwidth: 32
+    match_type: EXACT
+    type_name {
+      name: "port_id_bit_t"
+    }
+  }
+  match_fields {
+    id: 2
+    name: "hdr.ethernet.srcAddr"
+    match_type: EXACT
+    type_name {
+      name: "mac_addr_t"
+    }
+  }
+  match_fields {
+    id: 3
+    name: "hdr.ethernet.dstAddr"
+    match_type: EXACT
+    type_name {
+      name: "mac_addr_t"
+    }
+  }
+  match_fields {
+    id: 4
+    name: "hdr.ethernet.etherType"
+    bitwidth: 16
+    match_type: EXACT
+  }
+  action_refs {
+    id: 27607748
+  }
+  action_refs {
+    id: 32872817
+  }
+  action_refs {
+    id: 24562328
+  }
+  action_refs {
+    id: 18759588
+  }
+  const_default_action_id: 18759588
+  size: 1024
+}
+actions {
+  preamble {
+    id: 24562328
+    name: "send_to_cpu"
+    alias: "send_to_cpu"
+  }
+}
+actions {
+  preamble {
+    id: 27607748
+    name: "set_egress_port"
+    alias: "set_egress_port"
+  }
+  params {
+    id: 1
+    name: "port"
+    type_name {
+      name: "port_id_str_t"
+    }
+  }
+}
+actions {
+  preamble {
+    id: 32872817
+    name: "set_egress_port2"
+    alias: "set_egress_port2"
+  }
+  params {
+    id: 1
+    name: "port"
+    bitwidth: 32
+    type_name {
+      name: "port_id_bit_t"
+    }
+  }
+}
+actions {
+  preamble {
+    id: 18759588
+    name: "drop"
+    alias: "drop"
+  }
+}
+controller_packet_metadata {
+  preamble {
+    id: 81826293
+    name: "packet_in"
+    alias: "packet_in"
+    annotations: "@controller_header(\"packet_in\")"
+  }
+  metadata {
+    id: 1
+    name: "ingress_port"
+    bitwidth: 9
+  }
+  metadata {
+    id: 2
+    name: "_padding"
+    bitwidth: 7
+  }
+}
+controller_packet_metadata {
+  preamble {
+    id: 76689799
+    name: "packet_out"
+    alias: "packet_out"
+    annotations: "@controller_header(\"packet_out\")"
+  }
+  metadata {
+    id: 1
+    name: "egress_port"
+    bitwidth: 9
+  }
+  metadata {
+    id: 2
+    name: "_padding"
+    bitwidth: 7
+  }
+}
+type_info {
+  new_types {
+    key: "mac_addr_t"
+    value {
+      translated_type {
+        sdn_string {
+        }
+      }
+    }
+  }
+  new_types {
+    key: "port_id_bit_t"
+    value {
+      translated_type {
+        sdn_bitwidth: 32
+      }
+    }
+  }
+  new_types {
+    key: "port_id_str_t"
+    value {
+      translated_type {
+        sdn_string {
+        }
+      }
+    }
+  }
+}