go.ligato.io/vpp-agent/v3@v3.5.0/proto/ligato/vpp/interfaces/models_test.go (about)

     1  //  Copyright (c) 2018 Cisco and/or its affiliates.
     2  //
     3  //  Licensed under the Apache License, Version 2.0 (the "License");
     4  //  you may not use this file except in compliance with the License.
     5  //  You may obtain a copy of the License at:
     6  //
     7  //      http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  //  Unless required by applicable law or agreed to in writing, software
    10  //  distributed under the License is distributed on an "AS IS" BASIS,
    11  //  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  //  See the License for the specific language governing permissions and
    13  //  limitations under the License.
    14  
    15  package vpp_interfaces
    16  
    17  import (
    18  	"testing"
    19  
    20  	"go.ligato.io/vpp-agent/v3/proto/ligato/netalloc"
    21  )
    22  
    23  /*func TestInterfaceKey(t *testing.T) {
    24  	tests := []struct {
    25  		name        string
    26  		iface       string
    27  		expectedKey string
    28  	}{
    29  		{
    30  			name:        "valid interface name",
    31  			iface:       "memif0",
    32  			expectedKey: "vpp/config/v2/interface/memif0",
    33  		},
    34  		{
    35  			name:        "invalid interface name",
    36  			iface:       "",
    37  			expectedKey: "vpp/config/v2/interface/<invalid>",
    38  		},
    39  		{
    40  			name:        "Gbe interface",
    41  			iface:       "GigabitEthernet0/8/0",
    42  			expectedKey: "vpp/config/v2/interface/GigabitEthernet0/8/0",
    43  		},
    44  	}
    45  	for _, test := range tests {
    46  		t.Run(test.name, func(t *testing.T) {
    47  			key := InterfaceKey(test.iface)
    48  			if key != test.expectedKey {
    49  				t.Errorf("failed for: iface=%s\n"+
    50  					"expected key:\n\t%q\ngot key:\n\t%q",
    51  					test.iface, test.expectedKey, key)
    52  			}
    53  		})
    54  	}
    55  }
    56  
    57  func TestParseNameFromKey(t *testing.T) {
    58  	tests := []struct {
    59  		name               string
    60  		key                string
    61  		expectedIface      string
    62  		expectedIsIfaceKey bool
    63  	}{
    64  		{
    65  			name:               "valid interface name",
    66  			key:                "vpp/config/v2/interface/memif0",
    67  			expectedIface:      "memif0",
    68  			expectedIsIfaceKey: true,
    69  		},
    70  		{
    71  			name:               "invalid interface name",
    72  			key:                "vpp/config/v2/interface/<invalid>",
    73  			expectedIface:      "<invalid>",
    74  			expectedIsIfaceKey: true,
    75  		},
    76  		{
    77  			name:               "Gbe interface",
    78  			key:                "vpp/config/v2/interface/GigabitEthernet0/8/0",
    79  			expectedIface:      "GigabitEthernet0/8/0",
    80  			expectedIsIfaceKey: true,
    81  		},
    82  		{
    83  			name:               "not an interface key",
    84  			key:                "vpp/config/v2/bd/bd1",
    85  			expectedIface:      "",
    86  			expectedIsIfaceKey: false,
    87  		},
    88  		{
    89  			name:               "not an interface key (empty interface)",
    90  			key:                "vpp/config/v2/interface/",
    91  			expectedIface:      "",
    92  			expectedIsIfaceKey: false,
    93  		},
    94  	}
    95  	for _, test := range tests {
    96  		t.Run(test.name, func(t *testing.T) {
    97  			iface, isInterfaceKey := models.Model(&Interface{}).ParseKey(test.key)
    98  			if isInterfaceKey != test.expectedIsIfaceKey {
    99  				t.Errorf("expected isInterfaceKey: %v\tgot: %v", test.expectedIsIfaceKey, isInterfaceKey)
   100  			}
   101  			if iface != test.expectedIface {
   102  				t.Errorf("expected iface: %s\tgot: %s", test.expectedIface, iface)
   103  			}
   104  		})
   105  	}
   106  }*/
   107  
   108  func TestInterfaceErrorKey(t *testing.T) {
   109  	tests := []struct {
   110  		name        string
   111  		iface       string
   112  		expectedKey string
   113  	}{
   114  		{
   115  			name:        "valid interface name",
   116  			iface:       "memif0",
   117  			expectedKey: "vpp/status/v2/interface/error/memif0",
   118  		},
   119  		{
   120  			name:        "invalid interface name",
   121  			iface:       "",
   122  			expectedKey: "vpp/status/v2/interface/error/<invalid>",
   123  		},
   124  		{
   125  			name:        "Gbe interface",
   126  			iface:       "GigabitEthernet0/8/0",
   127  			expectedKey: "vpp/status/v2/interface/error/GigabitEthernet0/8/0",
   128  		},
   129  	}
   130  	for _, test := range tests {
   131  		t.Run(test.name, func(t *testing.T) {
   132  			key := InterfaceErrorKey(test.iface)
   133  			if key != test.expectedKey {
   134  				t.Errorf("failed for: iface=%s\n"+
   135  					"expected key:\n\t%q\ngot key:\n\t%q",
   136  					test.iface, test.expectedKey, key)
   137  			}
   138  		})
   139  	}
   140  }
   141  
   142  func TestInterfaceStateKey(t *testing.T) {
   143  	tests := []struct {
   144  		name        string
   145  		iface       string
   146  		expectedKey string
   147  	}{
   148  		{
   149  			name:        "valid interface name",
   150  			iface:       "memif0",
   151  			expectedKey: "vpp/status/v2/interface/memif0",
   152  		},
   153  		{
   154  			name:        "invalid interface name",
   155  			iface:       "",
   156  			expectedKey: "vpp/status/v2/interface/<invalid>",
   157  		},
   158  		{
   159  			name:        "Gbe interface",
   160  			iface:       "GigabitEthernet0/8/0",
   161  			expectedKey: "vpp/status/v2/interface/GigabitEthernet0/8/0",
   162  		},
   163  	}
   164  	for _, test := range tests {
   165  		t.Run(test.name, func(t *testing.T) {
   166  			key := InterfaceStateKey(test.iface)
   167  			if key != test.expectedKey {
   168  				t.Errorf("failed for: iface=%s\n"+
   169  					"expected key:\n\t%q\ngot key:\n\t%q",
   170  					test.iface, test.expectedKey, key)
   171  			}
   172  		})
   173  	}
   174  }
   175  
   176  func TestInterfaceAddressKey(t *testing.T) {
   177  	tests := []struct {
   178  		name        string
   179  		iface       string
   180  		address     string
   181  		source      netalloc.IPAddressSource
   182  		expectedKey string
   183  	}{
   184  		{
   185  			name:        "IPv4 address",
   186  			iface:       "memif0",
   187  			address:     "192.168.1.12/24",
   188  			source:      netalloc.IPAddressSource_STATIC,
   189  			expectedKey: "vpp/interface/memif0/address/static/192.168.1.12/24",
   190  		},
   191  		{
   192  			name:        "IPv4 address from DHCP",
   193  			iface:       "memif0",
   194  			address:     "192.168.1.12/24",
   195  			source:      netalloc.IPAddressSource_FROM_DHCP,
   196  			expectedKey: "vpp/interface/memif0/address/from_dhcp/192.168.1.12/24",
   197  		},
   198  		{
   199  			name:        "IPv6 address",
   200  			iface:       "memif0",
   201  			address:     "2001:db8::/32",
   202  			source:      netalloc.IPAddressSource_STATIC,
   203  			expectedKey: "vpp/interface/memif0/address/static/2001:db8::/32",
   204  		},
   205  		{
   206  			name:        "IPv6 address from DHCP",
   207  			iface:       "memif0",
   208  			address:     "2001:db8::/32",
   209  			source:      netalloc.IPAddressSource_FROM_DHCP,
   210  			expectedKey: "vpp/interface/memif0/address/from_dhcp/2001:db8::/32",
   211  		},
   212  		{
   213  			name:        "invalid interface",
   214  			iface:       "",
   215  			address:     "10.10.10.10/32",
   216  			source:      netalloc.IPAddressSource_STATIC,
   217  			expectedKey: "vpp/interface/<invalid>/address/static/10.10.10.10/32",
   218  		},
   219  		{
   220  			name:        "undefined source",
   221  			iface:       "memif1",
   222  			address:     "10.10.10.10/32",
   223  			expectedKey: "vpp/interface/memif1/address/undefined_source/10.10.10.10/32",
   224  		},
   225  		{
   226  			name:        "invalid address",
   227  			iface:       "tap0",
   228  			address:     "invalid-addr",
   229  			source:      netalloc.IPAddressSource_STATIC,
   230  			expectedKey: "vpp/interface/tap0/address/static/invalid-addr",
   231  		},
   232  		{
   233  			name:        "missing mask",
   234  			iface:       "tap1",
   235  			address:     "10.10.10.10",
   236  			source:      netalloc.IPAddressSource_STATIC,
   237  			expectedKey: "vpp/interface/tap1/address/static/10.10.10.10",
   238  		},
   239  		{
   240  			name:        "empty address",
   241  			iface:       "tap1",
   242  			address:     "",
   243  			source:      netalloc.IPAddressSource_STATIC,
   244  			expectedKey: "vpp/interface/tap1/address/static/",
   245  		},
   246  		{
   247  			name:        "IPv4 address requested from netalloc",
   248  			iface:       "memif0",
   249  			address:     "alloc:net1",
   250  			source:      netalloc.IPAddressSource_STATIC,
   251  			expectedKey: "vpp/interface/memif0/address/alloc_ref/alloc:net1",
   252  		},
   253  		{
   254  			name:        "IPv6 address requested from netalloc",
   255  			iface:       "memif0",
   256  			address:     "alloc:net1/IPV6_ADDR",
   257  			source:      netalloc.IPAddressSource_STATIC,
   258  			expectedKey: "vpp/interface/memif0/address/alloc_ref/alloc:net1/IPV6_ADDR",
   259  		},
   260  	}
   261  	for _, test := range tests {
   262  		t.Run(test.name, func(t *testing.T) {
   263  			key := InterfaceAddressKey(test.iface, test.address, test.source)
   264  			if key != test.expectedKey {
   265  				t.Errorf("failed for: iface=%s address=%s source=%s\n"+
   266  					"expected key:\n\t%q\ngot key:\n\t%q",
   267  					test.iface, test.address, string(test.source), test.expectedKey, key)
   268  			}
   269  		})
   270  	}
   271  }
   272  
   273  func TestParseInterfaceAddressKey(t *testing.T) {
   274  	tests := []struct {
   275  		name               string
   276  		key                string
   277  		expectedIface      string
   278  		expectedIfaceAddr  string
   279  		expectedSource     netalloc.IPAddressSource
   280  		expectedInvalidKey bool
   281  		expectedIsAddrKey  bool
   282  	}{
   283  		{
   284  			name:              "IPv4 address",
   285  			key:               "vpp/interface/memif0/address/static/192.168.1.12/24",
   286  			expectedIface:     "memif0",
   287  			expectedIfaceAddr: "192.168.1.12/24",
   288  			expectedSource:    netalloc.IPAddressSource_STATIC,
   289  			expectedIsAddrKey: true,
   290  		},
   291  		{
   292  			name:              "IPv4 address from DHCP",
   293  			key:               "vpp/interface/memif0/address/from_dhcp/192.168.1.12/24",
   294  			expectedIface:     "memif0",
   295  			expectedIfaceAddr: "192.168.1.12/24",
   296  			expectedSource:    netalloc.IPAddressSource_FROM_DHCP,
   297  			expectedIsAddrKey: true,
   298  		},
   299  		{
   300  			name:              "IPv4 address requested from Netalloc",
   301  			key:               "vpp/interface/memif0/address/alloc_ref/alloc:net1",
   302  			expectedIface:     "memif0",
   303  			expectedIfaceAddr: "alloc:net1",
   304  			expectedSource:    netalloc.IPAddressSource_ALLOC_REF,
   305  			expectedIsAddrKey: true,
   306  		},
   307  		{
   308  			name:              "IPv6 address",
   309  			key:               "vpp/interface/tap1/address/static/2001:db8:85a3::8a2e:370:7334/48",
   310  			expectedIface:     "tap1",
   311  			expectedIfaceAddr: "2001:db8:85a3::8a2e:370:7334/48",
   312  			expectedSource:    netalloc.IPAddressSource_STATIC,
   313  			expectedIsAddrKey: true,
   314  		},
   315  		{
   316  			name:              "IPv6 address requested from netalloc",
   317  			key:               "vpp/interface/tap1/address/alloc_ref/alloc:net1/IPV6_ADDR",
   318  			expectedIface:     "tap1",
   319  			expectedIfaceAddr: "alloc:net1/IPV6_ADDR",
   320  			expectedSource:    netalloc.IPAddressSource_ALLOC_REF,
   321  			expectedIsAddrKey: true,
   322  		},
   323  		{
   324  			name:              "IPv6 address from DHCP",
   325  			key:               "vpp/interface/tap1/address/from_dhcp/2001:db8:85a3::8a2e:370:7334/48",
   326  			expectedIface:     "tap1",
   327  			expectedIfaceAddr: "2001:db8:85a3::8a2e:370:7334/48",
   328  			expectedSource:    netalloc.IPAddressSource_FROM_DHCP,
   329  			expectedIsAddrKey: true,
   330  		},
   331  		{
   332  			name:              "invalid interface",
   333  			key:               "vpp/interface/<invalid>/address/static/10.10.10.10/30",
   334  			expectedIface:     "<invalid>",
   335  			expectedIfaceAddr: "10.10.10.10/30",
   336  			expectedSource:    netalloc.IPAddressSource_STATIC,
   337  			expectedIsAddrKey: true,
   338  		},
   339  		{
   340  			name:              "gbe interface",
   341  			key:               "vpp/interface/GigabitEthernet0/8/0/address/static/192.168.5.5/16",
   342  			expectedIface:     "GigabitEthernet0/8/0",
   343  			expectedIfaceAddr: "192.168.5.5/16",
   344  			expectedSource:    netalloc.IPAddressSource_STATIC,
   345  			expectedIsAddrKey: true,
   346  		},
   347  		{
   348  			name:               "missing interface",
   349  			key:                "vpp/interface//address/static/192.168.5.5/16",
   350  			expectedIface:      "<invalid>",
   351  			expectedIfaceAddr:  "192.168.5.5/16",
   352  			expectedSource:     netalloc.IPAddressSource_STATIC,
   353  			expectedInvalidKey: true,
   354  			expectedIsAddrKey:  true,
   355  		},
   356  		{
   357  			name:               "missing interface (from DHCP)",
   358  			key:                "vpp/interface//address/from_dhcp/192.168.5.5/16",
   359  			expectedIface:      "<invalid>",
   360  			expectedIfaceAddr:  "192.168.5.5/16",
   361  			expectedSource:     netalloc.IPAddressSource_FROM_DHCP,
   362  			expectedInvalidKey: true,
   363  			expectedIsAddrKey:  true,
   364  		},
   365  		{
   366  			name:               "missing IP",
   367  			key:                "vpp/interface/tap3/address/static/",
   368  			expectedIface:      "tap3",
   369  			expectedIfaceAddr:  "",
   370  			expectedSource:     netalloc.IPAddressSource_STATIC,
   371  			expectedInvalidKey: true,
   372  			expectedIsAddrKey:  true,
   373  		},
   374  		{
   375  			name:               "missing IP (from DHCP)",
   376  			key:                "vpp/interface/tap3/address/from_dhcp/",
   377  			expectedIface:      "tap3",
   378  			expectedIfaceAddr:  "",
   379  			expectedSource:     netalloc.IPAddressSource_FROM_DHCP,
   380  			expectedInvalidKey: true,
   381  			expectedIsAddrKey:  true,
   382  		},
   383  		{
   384  			name:               "missing IP for Gbe",
   385  			key:                "vpp/interface/Gbe0/1/2/address/static/",
   386  			expectedIface:      "Gbe0/1/2",
   387  			expectedIfaceAddr:  "",
   388  			expectedSource:     netalloc.IPAddressSource_STATIC,
   389  			expectedInvalidKey: true,
   390  			expectedIsAddrKey:  true,
   391  		},
   392  		{
   393  			name:              "not interface address key",
   394  			key:               "vpp/config/v2/interface/GigabitEthernet0/8/0",
   395  			expectedIface:     "",
   396  			expectedIfaceAddr: "",
   397  			expectedIsAddrKey: false,
   398  		},
   399  		{
   400  			name:               "invalid address source",
   401  			key:                "vpp/interface/memif0/address/<invalid>/192.168.1.12/24",
   402  			expectedIface:      "memif0",
   403  			expectedInvalidKey: true,
   404  			expectedIsAddrKey:  true,
   405  		},
   406  		{
   407  			name:               "empty address source",
   408  			key:                "vpp/interface/memif0/address//192.168.1.12/24",
   409  			expectedIface:      "memif0",
   410  			expectedInvalidKey: true,
   411  			expectedIsAddrKey:  true,
   412  		},
   413  		{
   414  			name:               "missing address source",
   415  			key:                "vpp/interface/memif0/address/192.168.1.12/24",
   416  			expectedIface:      "memif0",
   417  			expectedInvalidKey: true,
   418  			expectedIsAddrKey:  true,
   419  		},
   420  	}
   421  	for _, test := range tests {
   422  		t.Run(test.name, func(t *testing.T) {
   423  			iface, ipAddr, source, invalidKey, isAddrKey := ParseInterfaceAddressKey(test.key)
   424  			if isAddrKey != test.expectedIsAddrKey {
   425  				t.Errorf("expected isAddrKey: %v\tgot: %v", test.expectedIsAddrKey, isAddrKey)
   426  			}
   427  			if source != test.expectedSource {
   428  				t.Errorf("expected source: %v\tgot: %v", test.expectedSource, source)
   429  			}
   430  			if invalidKey != test.expectedInvalidKey {
   431  				t.Errorf("expected invalidKey: %v\tgot: %v", test.expectedInvalidKey, invalidKey)
   432  			}
   433  			if iface != test.expectedIface {
   434  				t.Errorf("expected iface: %s\tgot: %s", test.expectedIface, iface)
   435  			}
   436  			if ipAddr != test.expectedIfaceAddr {
   437  				t.Errorf("expected ipAddr: %s\tgot: %s", test.expectedIfaceAddr, ipAddr)
   438  			}
   439  		})
   440  	}
   441  }
   442  
   443  func TestInterfaceVrfTableKey(t *testing.T) {
   444  	tests := []struct {
   445  		name        string
   446  		iface       string
   447  		vrf         int
   448  		ipv4        bool
   449  		ipv6        bool
   450  		expectedKey string
   451  	}{
   452  		{
   453  			name:        "default IPv4 VRF",
   454  			iface:       "memif0",
   455  			vrf:         0,
   456  			ipv4:        true,
   457  			expectedKey: "vpp/interface/memif0/vrf/0/ip-version/v4",
   458  		},
   459  		{
   460  			name:        "default IPv6 VRF",
   461  			iface:       "memif0",
   462  			vrf:         0,
   463  			ipv6:        true,
   464  			expectedKey: "vpp/interface/memif0/vrf/0/ip-version/v6",
   465  		},
   466  		{
   467  			name:        "default VRF for both versions",
   468  			iface:       "memif0",
   469  			vrf:         0,
   470  			ipv4:        true,
   471  			ipv6:        true,
   472  			expectedKey: "vpp/interface/memif0/vrf/0/ip-version/both",
   473  		},
   474  		{
   475  			name:        "IPv4 VRF 1",
   476  			iface:       "memif0",
   477  			vrf:         1,
   478  			ipv4:        true,
   479  			expectedKey: "vpp/interface/memif0/vrf/1/ip-version/v4",
   480  		},
   481  		{
   482  			name:        "IPv6 VRF 1",
   483  			iface:       "memif0",
   484  			vrf:         1,
   485  			ipv6:        true,
   486  			expectedKey: "vpp/interface/memif0/vrf/1/ip-version/v6",
   487  		},
   488  		{
   489  			name:        "interface name with forward slashes",
   490  			iface:       "Gbe0/2/1",
   491  			vrf:         10,
   492  			ipv4:        true,
   493  			expectedKey: "vpp/interface/Gbe0/2/1/vrf/10/ip-version/v4",
   494  		},
   495  		{
   496  			name:        "missing interface name",
   497  			iface:       "",
   498  			vrf:         10,
   499  			ipv4:        true,
   500  			expectedKey: "vpp/interface/<invalid>/vrf/10/ip-version/v4",
   501  		},
   502  		{
   503  			name:        "undefined version",
   504  			iface:       "memif0",
   505  			vrf:         10,
   506  			expectedKey: "vpp/interface/memif0/vrf/10/ip-version/<invalid>",
   507  		},
   508  		{
   509  			name:        "invalid VRF table ID",
   510  			iface:       "memif0",
   511  			vrf:         -5,
   512  			ipv4:        true,
   513  			expectedKey: "vpp/interface/memif0/vrf/<invalid>/ip-version/v4",
   514  		},
   515  	}
   516  	for _, test := range tests {
   517  		t.Run(test.name, func(t *testing.T) {
   518  			key := InterfaceVrfKey(test.iface, test.vrf, test.ipv4, test.ipv6)
   519  			if key != test.expectedKey {
   520  				t.Errorf("failed for: iface=%s vrf=%d ipv4=%t ipv6=%t\n"+
   521  					"expected key:\n\t%q\ngot key:\n\t%q",
   522  					test.iface, test.vrf, test.ipv4, test.ipv6, test.expectedKey, key)
   523  			}
   524  		})
   525  	}
   526  }
   527  
   528  func TestParseInterfaceVrfKey(t *testing.T) {
   529  	tests := []struct {
   530  		name                  string
   531  		key                   string
   532  		expectedIface         string
   533  		expectedVrf           int
   534  		expectedIpv4          bool
   535  		expectedIpv6          bool
   536  		expectedIsIfaceVrfKey bool
   537  	}{
   538  		{
   539  			name:                  "default IPv4 VRF",
   540  			key:                   "vpp/interface/memif0/vrf/0/ip-version/v4",
   541  			expectedIface:         "memif0",
   542  			expectedVrf:           0,
   543  			expectedIpv4:          true,
   544  			expectedIsIfaceVrfKey: true,
   545  		},
   546  		{
   547  			name:                  "default IPv6 VRF",
   548  			key:                   "vpp/interface/memif0/vrf/0/ip-version/v6",
   549  			expectedIface:         "memif0",
   550  			expectedVrf:           0,
   551  			expectedIpv6:          true,
   552  			expectedIsIfaceVrfKey: true,
   553  		},
   554  		{
   555  			name:                  "IPv4 VRF 1",
   556  			key:                   "vpp/interface/memif0/vrf/1/ip-version/v4",
   557  			expectedIface:         "memif0",
   558  			expectedVrf:           1,
   559  			expectedIpv4:          true,
   560  			expectedIsIfaceVrfKey: true,
   561  		},
   562  		{
   563  			name:                  "IPv6 VRF 1",
   564  			key:                   "vpp/interface/memif0/vrf/1/ip-version/v6",
   565  			expectedIface:         "memif0",
   566  			expectedVrf:           1,
   567  			expectedIpv6:          true,
   568  			expectedIsIfaceVrfKey: true,
   569  		},
   570  		{
   571  			name:                  "invalid interface name",
   572  			key:                   "vpp/interface/<invalid>/vrf/1/ip-version/v6",
   573  			expectedIface:         "<invalid>",
   574  			expectedVrf:           1,
   575  			expectedIpv6:          true,
   576  			expectedIsIfaceVrfKey: true,
   577  		},
   578  		{
   579  			name:                  "invalid ip version",
   580  			key:                   "vpp/interface/memif0/vrf/1/ip-version/<invalid>",
   581  			expectedIface:         "memif0",
   582  			expectedVrf:           1,
   583  			expectedIsIfaceVrfKey: true,
   584  		},
   585  		{
   586  			name:                  "missing table ID",
   587  			key:                   "vpp/interface/memif0/vrf//ip-version/v6",
   588  			expectedIface:         "memif0",
   589  			expectedVrf:           -1,
   590  			expectedIpv6:          true,
   591  			expectedIsIfaceVrfKey: true,
   592  		},
   593  		{
   594  			name:                  "invalid table ID",
   595  			key:                   "vpp/interface/memif0/vrf/<invalid>/ip-version/v6",
   596  			expectedIface:         "memif0",
   597  			expectedVrf:           -1,
   598  			expectedIpv6:          true,
   599  			expectedIsIfaceVrfKey: true,
   600  		},
   601  		{
   602  			name:                  "interface name with forward slashes",
   603  			key:                   "vpp/interface/Gbe1/2/3/vrf/12/ip-version/v6",
   604  			expectedIface:         "Gbe1/2/3",
   605  			expectedVrf:           12,
   606  			expectedIpv6:          true,
   607  			expectedIsIfaceVrfKey: true,
   608  		},
   609  		{
   610  			name:                  "not vrf table key",
   611  			key:                   "vpp/config/v2/interface/GigabitEthernet0/8/0",
   612  			expectedIsIfaceVrfKey: false,
   613  		},
   614  		{
   615  			name:                  "not vrf table key (inherited VRF)",
   616  			key:                   "vpp/interface/Gbe1/2/3/vrf/from-interface/memif0",
   617  			expectedIsIfaceVrfKey: false,
   618  		},
   619  	}
   620  	for _, test := range tests {
   621  		t.Run(test.name, func(t *testing.T) {
   622  			iface, vrf, ipv4, ipv6, isIfaceVrfKey := ParseInterfaceVrfKey(test.key)
   623  			if isIfaceVrfKey != test.expectedIsIfaceVrfKey {
   624  				t.Errorf("expected isVrfTableKey: %v\tgot: %v", test.expectedIsIfaceVrfKey, isIfaceVrfKey)
   625  			}
   626  			if iface != test.expectedIface {
   627  				t.Errorf("expected iface: %s\tgot: %s", test.expectedIface, iface)
   628  			}
   629  			if vrf != test.expectedVrf {
   630  				t.Errorf("expected vrf: %d\tgot: %d", test.expectedVrf, vrf)
   631  			}
   632  			if ipv4 != test.expectedIpv4 {
   633  				t.Errorf("expected ipv4: %t\tgot: %t", test.expectedIpv4, ipv4)
   634  			}
   635  			if ipv6 != test.expectedIpv6 {
   636  				t.Errorf("expected ipv6: %t\tgot: %t", test.expectedIpv6, ipv6)
   637  			}
   638  		})
   639  	}
   640  }
   641  
   642  func TestInterfaceInheritedVrfKey(t *testing.T) {
   643  	tests := []struct {
   644  		name        string
   645  		iface       string
   646  		fromIface   string
   647  		expectedKey string
   648  	}{
   649  		{
   650  			name:        "memifs",
   651  			iface:       "memif0",
   652  			fromIface:   "memif1",
   653  			expectedKey: "vpp/interface/memif0/vrf/from-interface/memif1",
   654  		},
   655  		{
   656  			name:        "memif and Gbe",
   657  			iface:       "memif0",
   658  			fromIface:   "Gbe0/1/2",
   659  			expectedKey: "vpp/interface/memif0/vrf/from-interface/Gbe0/1/2",
   660  		},
   661  		{
   662  			name:        "Gbe-s",
   663  			iface:       "Gbe3/4/5",
   664  			fromIface:   "Gbe0/1/2",
   665  			expectedKey: "vpp/interface/Gbe3/4/5/vrf/from-interface/Gbe0/1/2",
   666  		},
   667  		{
   668  			name:        "missing interface",
   669  			iface:       "",
   670  			fromIface:   "memif1",
   671  			expectedKey: "vpp/interface/<invalid>/vrf/from-interface/memif1",
   672  		},
   673  		{
   674  			name:        "missing from-interface",
   675  			iface:       "memif0",
   676  			fromIface:   "",
   677  			expectedKey: "vpp/interface/memif0/vrf/from-interface/<invalid>",
   678  		},
   679  	}
   680  	for _, test := range tests {
   681  		t.Run(test.name, func(t *testing.T) {
   682  			key := InterfaceInheritedVrfKey(test.iface, test.fromIface)
   683  			if key != test.expectedKey {
   684  				t.Errorf("failed for: iface=%s fromIface=%s\n"+
   685  					"expected key:\n\t%q\ngot key:\n\t%q",
   686  					test.iface, test.fromIface, test.expectedKey, key)
   687  			}
   688  		})
   689  	}
   690  }
   691  
   692  func TestParseInterfaceInheritedVrfKey(t *testing.T) {
   693  	tests := []struct {
   694  		name                       string
   695  		key                        string
   696  		expectedIface              string
   697  		expectedFromIface          string
   698  		expectedIsIfaceInherVrfKey bool
   699  	}{
   700  		{
   701  			name:                       "memifs",
   702  			key:                        "vpp/interface/memif0/vrf/from-interface/memif1",
   703  			expectedIface:              "memif0",
   704  			expectedFromIface:          "memif1",
   705  			expectedIsIfaceInherVrfKey: true,
   706  		},
   707  		{
   708  			name:                       "Gbe-s",
   709  			key:                        "vpp/interface/Gbe1/2/3/vrf/from-interface/Gbe4/5/6",
   710  			expectedIface:              "Gbe1/2/3",
   711  			expectedFromIface:          "Gbe4/5/6",
   712  			expectedIsIfaceInherVrfKey: true,
   713  		},
   714  		{
   715  			name:                       "invalid interface",
   716  			key:                        "vpp/interface/<invalid>/vrf/from-interface/Gbe4/5/6",
   717  			expectedIface:              "<invalid>",
   718  			expectedFromIface:          "Gbe4/5/6",
   719  			expectedIsIfaceInherVrfKey: true,
   720  		},
   721  		{
   722  			name:                       "invalid from-interface",
   723  			key:                        "vpp/interface/Gbe1/2/3/vrf/from-interface/<invalid>",
   724  			expectedIface:              "Gbe1/2/3",
   725  			expectedFromIface:          "<invalid>",
   726  			expectedIsIfaceInherVrfKey: true,
   727  		},
   728  		{
   729  			name:                       "missing interface",
   730  			key:                        "vpp/interface//vrf/from-interface/Gbe4/5/6",
   731  			expectedIface:              "<invalid>",
   732  			expectedFromIface:          "Gbe4/5/6",
   733  			expectedIsIfaceInherVrfKey: true,
   734  		},
   735  		{
   736  			name:                       "missing from-interface",
   737  			key:                        "vpp/interface/Gbe1/2/3/vrf/from-interface/",
   738  			expectedIface:              "Gbe1/2/3",
   739  			expectedFromIface:          "<invalid>",
   740  			expectedIsIfaceInherVrfKey: true,
   741  		},
   742  		{
   743  			name:                       "not interface inherited-vrf key",
   744  			key:                        "vpp/interface/memif0/vrf/1/ip-version/v6",
   745  			expectedIsIfaceInherVrfKey: false,
   746  		},
   747  	}
   748  	for _, test := range tests {
   749  		t.Run(test.name, func(t *testing.T) {
   750  			iface, fromIface, isIfaceInherVrfKey := ParseInterfaceInheritedVrfKey(test.key)
   751  			if isIfaceInherVrfKey != test.expectedIsIfaceInherVrfKey {
   752  				t.Errorf("expected isIfaceInherVrfKey: %v\tgot: %v", test.expectedIsIfaceInherVrfKey, isIfaceInherVrfKey)
   753  			}
   754  			if iface != test.expectedIface {
   755  				t.Errorf("expected iface: %s\tgot: %s", test.expectedIface, iface)
   756  			}
   757  			if fromIface != test.expectedFromIface {
   758  				t.Errorf("expected fromIface: %s\tgot: %s", test.expectedFromIface, fromIface)
   759  			}
   760  		})
   761  	}
   762  }
   763  
   764  func TestUnnumberedKey(t *testing.T) {
   765  	tests := []struct {
   766  		name        string
   767  		iface       string
   768  		expectedKey string
   769  	}{
   770  		{
   771  			name:        "valid interface name",
   772  			iface:       "memif0",
   773  			expectedKey: "vpp/interface/unnumbered/memif0",
   774  		},
   775  		{
   776  			name:        "invalid interface name",
   777  			iface:       "",
   778  			expectedKey: "vpp/interface/unnumbered/<invalid>",
   779  		},
   780  		{
   781  			name:        "Gbe interface",
   782  			iface:       "GigabitEthernet0/8/0",
   783  			expectedKey: "vpp/interface/unnumbered/GigabitEthernet0/8/0",
   784  		},
   785  	}
   786  	for _, test := range tests {
   787  		t.Run(test.name, func(t *testing.T) {
   788  			key := UnnumberedKey(test.iface)
   789  			if key != test.expectedKey {
   790  				t.Errorf("failed for: iface=%s\n"+
   791  					"expected key:\n\t%q\ngot key:\n\t%q",
   792  					test.iface, test.expectedKey, key)
   793  			}
   794  		})
   795  	}
   796  }
   797  
   798  func TestDHCPClientKey(t *testing.T) {
   799  	tests := []struct {
   800  		name        string
   801  		iface       string
   802  		expectedKey string
   803  	}{
   804  		{
   805  			name:        "valid interface name",
   806  			iface:       "memif0",
   807  			expectedKey: "vpp/interface/dhcp-client/memif0",
   808  		},
   809  		{
   810  			name:        "invalid interface name",
   811  			iface:       "",
   812  			expectedKey: "vpp/interface/dhcp-client/<invalid>",
   813  		},
   814  		{
   815  			name:        "Gbe interface",
   816  			iface:       "GigabitEthernet0/8/0",
   817  			expectedKey: "vpp/interface/dhcp-client/GigabitEthernet0/8/0",
   818  		},
   819  	}
   820  	for _, test := range tests {
   821  		t.Run(test.name, func(t *testing.T) {
   822  			key := DHCPClientKey(test.iface)
   823  			if key != test.expectedKey {
   824  				t.Errorf("failed for: iface=%s\n"+
   825  					"expected key:\n\t%q\ngot key:\n\t%q",
   826  					test.iface, test.expectedKey, key)
   827  			}
   828  		})
   829  	}
   830  }
   831  
   832  func TestParseNameFromDHCPClientKey(t *testing.T) {
   833  	tests := []struct {
   834  		name                    string
   835  		key                     string
   836  		expectedIface           string
   837  		expectedIsDHCPClientKey bool
   838  	}{
   839  		{
   840  			name:                    "valid interface name",
   841  			key:                     "vpp/interface/dhcp-client/memif0",
   842  			expectedIface:           "memif0",
   843  			expectedIsDHCPClientKey: true,
   844  		},
   845  		{
   846  			name:                    "invalid interface name",
   847  			key:                     "vpp/interface/dhcp-client/<invalid>",
   848  			expectedIface:           "<invalid>",
   849  			expectedIsDHCPClientKey: true,
   850  		},
   851  		{
   852  			name:                    "Gbe interface",
   853  			key:                     "vpp/interface/dhcp-client/GigabitEthernet0/8/0",
   854  			expectedIface:           "GigabitEthernet0/8/0",
   855  			expectedIsDHCPClientKey: true,
   856  		},
   857  		{
   858  			name:                    "not DHCP client key",
   859  			key:                     "vpp/config/v2/bd/bd1",
   860  			expectedIface:           "",
   861  			expectedIsDHCPClientKey: false,
   862  		},
   863  		{
   864  			name:                    "not DHCP client key (empty interface)",
   865  			key:                     "vpp/interface/dhcp-client/",
   866  			expectedIface:           "",
   867  			expectedIsDHCPClientKey: false,
   868  		},
   869  	}
   870  	for _, test := range tests {
   871  		t.Run(test.name, func(t *testing.T) {
   872  			iface, isDHCPClientKey := ParseNameFromDHCPClientKey(test.key)
   873  			if isDHCPClientKey != test.expectedIsDHCPClientKey {
   874  				t.Errorf("expected isInterfaceKey: %v\tgot: %v", test.expectedIsDHCPClientKey, isDHCPClientKey)
   875  			}
   876  			if iface != test.expectedIface {
   877  				t.Errorf("expected iface: %s\tgot: %s", test.expectedIface, iface)
   878  			}
   879  		})
   880  	}
   881  }
   882  
   883  func TestDHCPLeaseKey(t *testing.T) {
   884  	tests := []struct {
   885  		name        string
   886  		iface       string
   887  		expectedKey string
   888  	}{
   889  		{
   890  			name:        "valid interface name",
   891  			iface:       "memif0",
   892  			expectedKey: "vpp/interface/dhcp-lease/memif0",
   893  		},
   894  		{
   895  			name:        "invalid interface name",
   896  			iface:       "",
   897  			expectedKey: "vpp/interface/dhcp-lease/<invalid>",
   898  		},
   899  		{
   900  			name:        "Gbe interface",
   901  			iface:       "GigabitEthernet0/8/0",
   902  			expectedKey: "vpp/interface/dhcp-lease/GigabitEthernet0/8/0",
   903  		},
   904  	}
   905  	for _, test := range tests {
   906  		t.Run(test.name, func(t *testing.T) {
   907  			key := DHCPLeaseKey(test.iface)
   908  			if key != test.expectedKey {
   909  				t.Errorf("failed for: iface=%s\n"+
   910  					"expected key:\n\t%q\ngot key:\n\t%q",
   911  					test.iface, test.expectedKey, key)
   912  			}
   913  		})
   914  	}
   915  }
   916  
   917  func TestLinkStateKey(t *testing.T) {
   918  	tests := []struct {
   919  		name        string
   920  		iface       string
   921  		linkIsUp    bool
   922  		expectedKey string
   923  	}{
   924  		{
   925  			name:        "link is UP",
   926  			iface:       "memif0",
   927  			linkIsUp:    true,
   928  			expectedKey: "vpp/interface/memif0/link-state/UP",
   929  		},
   930  		{
   931  			name:        "link is DOWN",
   932  			iface:       "memif0",
   933  			linkIsUp:    false,
   934  			expectedKey: "vpp/interface/memif0/link-state/DOWN",
   935  		},
   936  		{
   937  			name:        "invalid interface name",
   938  			iface:       "",
   939  			linkIsUp:    true,
   940  			expectedKey: "vpp/interface/<invalid>/link-state/UP",
   941  		},
   942  		{
   943  			name:        "Gbe interface",
   944  			iface:       "GigabitEthernet0/8/0",
   945  			linkIsUp:    false,
   946  			expectedKey: "vpp/interface/GigabitEthernet0/8/0/link-state/DOWN",
   947  		},
   948  	}
   949  	for _, test := range tests {
   950  		t.Run(test.name, func(t *testing.T) {
   951  			key := LinkStateKey(test.iface, test.linkIsUp)
   952  			if key != test.expectedKey {
   953  				t.Errorf("failed for: iface=%s linkIsUp=%v\n"+
   954  					"expected key:\n\t%q\ngot key:\n\t%q",
   955  					test.iface, test.linkIsUp, test.expectedKey, key)
   956  			}
   957  		})
   958  	}
   959  }
   960  
   961  func TestParseLinkStateKey(t *testing.T) {
   962  	tests := []struct {
   963  		name                   string
   964  		key                    string
   965  		expectedIface          string
   966  		expectedIsLinkUp       bool
   967  		expectedIsLinkStateKey bool
   968  	}{
   969  		{
   970  			name:                   "link is UP",
   971  			key:                    "vpp/interface/memif0/link-state/UP",
   972  			expectedIface:          "memif0",
   973  			expectedIsLinkUp:       true,
   974  			expectedIsLinkStateKey: true,
   975  		},
   976  		{
   977  			name:                   "link is DOWN",
   978  			key:                    "vpp/interface/memif0/link-state/DOWN",
   979  			expectedIface:          "memif0",
   980  			expectedIsLinkUp:       false,
   981  			expectedIsLinkStateKey: true,
   982  		},
   983  		{
   984  			name:                   "invalid interface name",
   985  			key:                    "vpp/interface/<invalid>/link-state/DOWN",
   986  			expectedIsLinkStateKey: false,
   987  		},
   988  		{
   989  			name:                   "Gbe interface",
   990  			key:                    "vpp/interface/GigabitEthernet0/8/0/link-state/UP",
   991  			expectedIface:          "GigabitEthernet0/8/0",
   992  			expectedIsLinkUp:       true,
   993  			expectedIsLinkStateKey: true,
   994  		},
   995  		{
   996  			name:                   "invalid link state",
   997  			key:                    "vpp/interface/GigabitEthernet0/8/0/link-state/<invalid>",
   998  			expectedIsLinkStateKey: false,
   999  		},
  1000  		{
  1001  			name:                   "missing link state",
  1002  			key:                    "vpp/interface/GigabitEthernet0/8/0/link-state",
  1003  			expectedIsLinkStateKey: false,
  1004  		},
  1005  		{
  1006  			name:                   "not link state key",
  1007  			key:                    "vpp/interface/unnumbered/GigabitEthernet0/8/0",
  1008  			expectedIsLinkStateKey: false,
  1009  		},
  1010  	}
  1011  	for _, test := range tests {
  1012  		t.Run(test.name, func(t *testing.T) {
  1013  			iface, isLinkUp, isLinkStateKey := ParseLinkStateKey(test.key)
  1014  			if isLinkStateKey != test.expectedIsLinkStateKey {
  1015  				t.Errorf("expected isLinkStateKey: %v\tgot: %v",
  1016  					test.expectedIsLinkStateKey, isLinkStateKey)
  1017  			}
  1018  			if iface != test.expectedIface {
  1019  				t.Errorf("expected iface: %s\tgot: %s", test.expectedIface, iface)
  1020  			}
  1021  			if isLinkUp != test.expectedIsLinkUp {
  1022  				t.Errorf("expected isLinkUp: %t\tgot: %t", test.expectedIsLinkUp, isLinkUp)
  1023  			}
  1024  		})
  1025  	}
  1026  }
  1027  
  1028  func TestRxPlacementKey(t *testing.T) {
  1029  	tests := []struct {
  1030  		name        string
  1031  		iface       string
  1032  		queue       uint32
  1033  		expectedKey string
  1034  	}{
  1035  		{
  1036  			name:        "queue 0",
  1037  			iface:       "memif0",
  1038  			queue:       0,
  1039  			expectedKey: "vpp/interface/memif0/rx-placement/queue/0",
  1040  		},
  1041  		{
  1042  			name:        "queue 1",
  1043  			iface:       "memif0",
  1044  			queue:       1,
  1045  			expectedKey: "vpp/interface/memif0/rx-placement/queue/1",
  1046  		},
  1047  		{
  1048  			name:        "invalid interface name",
  1049  			iface:       "",
  1050  			queue:       1,
  1051  			expectedKey: "vpp/interface/<invalid>/rx-placement/queue/1",
  1052  		},
  1053  		{
  1054  			name:        "Gbe interface",
  1055  			iface:       "GigabitEthernet0/8/0",
  1056  			queue:       2,
  1057  			expectedKey: "vpp/interface/GigabitEthernet0/8/0/rx-placement/queue/2",
  1058  		},
  1059  	}
  1060  	for _, test := range tests {
  1061  		t.Run(test.name, func(t *testing.T) {
  1062  			key := RxPlacementKey(test.iface, test.queue)
  1063  			if key != test.expectedKey {
  1064  				t.Errorf("failed for: iface=%s queue=%d\n"+
  1065  					"expected key:\n\t%q\ngot key:\n\t%q",
  1066  					test.iface, test.queue, test.expectedKey, key)
  1067  			}
  1068  		})
  1069  	}
  1070  }
  1071  
  1072  func TestParseRxPlacementKey(t *testing.T) {
  1073  	tests := []struct {
  1074  		name                     string
  1075  		key                      string
  1076  		expectedIface            string
  1077  		expectedQueue            uint32
  1078  		expectedIsRxPlacementKey bool
  1079  	}{
  1080  		{
  1081  			name:                     "queue 0",
  1082  			key:                      "vpp/interface/memif0/rx-placement/queue/0",
  1083  			expectedIface:            "memif0",
  1084  			expectedQueue:            0,
  1085  			expectedIsRxPlacementKey: true,
  1086  		},
  1087  		{
  1088  			name:                     "queue 1",
  1089  			key:                      "vpp/interface/memif0/rx-placement/queue/1",
  1090  			expectedIface:            "memif0",
  1091  			expectedQueue:            1,
  1092  			expectedIsRxPlacementKey: true,
  1093  		},
  1094  		{
  1095  			name:                     "invalid interface name",
  1096  			key:                      "vpp/interface/<invalid>/rx-placement/queue/1",
  1097  			expectedIsRxPlacementKey: false,
  1098  		},
  1099  		{
  1100  			name:                     "invalid queue",
  1101  			key:                      "vpp/interface/memif0/rx-placement/queue/<invalid>",
  1102  			expectedIsRxPlacementKey: false,
  1103  		},
  1104  		{
  1105  			name:                     "missing queue",
  1106  			key:                      "vpp/interface/memif0/rx-placement/",
  1107  			expectedIsRxPlacementKey: false,
  1108  		},
  1109  		{
  1110  			name:                     "missing queue ID",
  1111  			key:                      "vpp/interface/memif0/rx-placement/queue",
  1112  			expectedIsRxPlacementKey: false,
  1113  		},
  1114  		{
  1115  			name:                     "Gbe interface",
  1116  			key:                      "vpp/interface/GigabitEthernet0/8/0/rx-placement/queue/3",
  1117  			expectedIface:            "GigabitEthernet0/8/0",
  1118  			expectedQueue:            3,
  1119  			expectedIsRxPlacementKey: true,
  1120  		},
  1121  		{
  1122  			name:                     "not rx placement key",
  1123  			key:                      "vpp/interface/memif0/link-state/DOWN",
  1124  			expectedIsRxPlacementKey: false,
  1125  		},
  1126  	}
  1127  	for _, test := range tests {
  1128  		t.Run(test.name, func(t *testing.T) {
  1129  			iface, queue, isRxPlacementKey := ParseRxPlacementKey(test.key)
  1130  			if isRxPlacementKey != test.expectedIsRxPlacementKey {
  1131  				t.Errorf("expected isRxPlacementKey: %v\tgot: %v",
  1132  					test.expectedIsRxPlacementKey, isRxPlacementKey)
  1133  			}
  1134  			if queue != test.expectedQueue {
  1135  				t.Errorf("expected queue: %d\tgot: %d", test.expectedQueue, queue)
  1136  			}
  1137  			if iface != test.expectedIface {
  1138  				t.Errorf("expected iface: %s\tgot: %s", test.expectedIface, iface)
  1139  			}
  1140  		})
  1141  	}
  1142  }
  1143  
  1144  func TestRxModesKey(t *testing.T) {
  1145  	tests := []struct {
  1146  		name        string
  1147  		iface       string
  1148  		expectedKey string
  1149  	}{
  1150  		{
  1151  			name:        "memif",
  1152  			iface:       "memif0",
  1153  			expectedKey: "vpp/interface/memif0/rx-modes",
  1154  		},
  1155  		{
  1156  			name:        "Gbe",
  1157  			iface:       "GigabitEthernet0/8/0",
  1158  			expectedKey: "vpp/interface/GigabitEthernet0/8/0/rx-modes",
  1159  		},
  1160  		{
  1161  			name:        "invalid interface name",
  1162  			iface:       "",
  1163  			expectedKey: "vpp/interface/<invalid>/rx-modes",
  1164  		},
  1165  	}
  1166  	for _, test := range tests {
  1167  		t.Run(test.name, func(t *testing.T) {
  1168  			key := RxModesKey(test.iface)
  1169  			if key != test.expectedKey {
  1170  				t.Errorf("failed for: iface=%s\n"+
  1171  					"expected key:\n\t%q\ngot key:\n\t%q",
  1172  					test.iface, test.expectedKey, key)
  1173  			}
  1174  		})
  1175  	}
  1176  }
  1177  
  1178  func TestParseRxModesKey(t *testing.T) {
  1179  	tests := []struct {
  1180  		name                 string
  1181  		key                  string
  1182  		expectedIface        string
  1183  		expectedIsRxModesKey bool
  1184  	}{
  1185  		{
  1186  			name:                 "memif",
  1187  			key:                  "vpp/interface/memif0/rx-modes",
  1188  			expectedIface:        "memif0",
  1189  			expectedIsRxModesKey: true,
  1190  		},
  1191  		{
  1192  			name:                 "Gbe",
  1193  			key:                  "vpp/interface/GigabitEthernet0/8/0/rx-modes",
  1194  			expectedIface:        "GigabitEthernet0/8/0",
  1195  			expectedIsRxModesKey: true,
  1196  		},
  1197  		{
  1198  			name:                 "invalid interface name",
  1199  			key:                  "vpp/interface/<invalid>/rx-modes",
  1200  			expectedIsRxModesKey: false,
  1201  		},
  1202  		{
  1203  			name:                 "missing rx-mode suffix",
  1204  			key:                  "vpp/interface/<invalid>",
  1205  			expectedIsRxModesKey: false,
  1206  		},
  1207  		{
  1208  			name:                 "not rx-mode key",
  1209  			key:                  "vpp/interface/memif0/address/192.168.1.12/24",
  1210  			expectedIsRxModesKey: false,
  1211  		},
  1212  	}
  1213  	for _, test := range tests {
  1214  		t.Run(test.name, func(t *testing.T) {
  1215  			iface, isRxModesKey := ParseRxModesKey(test.key)
  1216  			if isRxModesKey != test.expectedIsRxModesKey {
  1217  				t.Errorf("expected isRxModesKey: %v\tgot: %v",
  1218  					test.expectedIsRxModesKey, isRxModesKey)
  1219  			}
  1220  			if iface != test.expectedIface {
  1221  				t.Errorf("expected iface: %s\tgot: %s", test.expectedIface, iface)
  1222  			}
  1223  		})
  1224  	}
  1225  }
  1226  
  1227  func TestInterfaceWithIPKey(t *testing.T) {
  1228  	tests := []struct {
  1229  		name        string
  1230  		iface       string
  1231  		expectedKey string
  1232  	}{
  1233  		{
  1234  			name:        "memif",
  1235  			iface:       "memif0",
  1236  			expectedKey: "vpp/interface/memif0/has-IP-address",
  1237  		},
  1238  		{
  1239  			name:        "invalid interface name",
  1240  			iface:       "",
  1241  			expectedKey: "vpp/interface/<invalid>/has-IP-address",
  1242  		},
  1243  		{
  1244  			name:        "Gbe interface",
  1245  			iface:       "GigabitEthernet0/8/0",
  1246  			expectedKey: "vpp/interface/GigabitEthernet0/8/0/has-IP-address",
  1247  		},
  1248  	}
  1249  	for _, test := range tests {
  1250  		t.Run(test.name, func(t *testing.T) {
  1251  			key := InterfaceWithIPKey(test.iface)
  1252  			if key != test.expectedKey {
  1253  				t.Errorf("failed for: iface=%s\n"+
  1254  					"expected key:\n\t%q\ngot key:\n\t%q",
  1255  					test.iface, test.expectedKey, key)
  1256  			}
  1257  		})
  1258  	}
  1259  }
  1260  
  1261  func TestParseInterfaceWithIPKey(t *testing.T) {
  1262  	tests := []struct {
  1263  		name                     string
  1264  		key                      string
  1265  		expectedIface            string
  1266  		expectedIsIfaceWithIPKey bool
  1267  	}{
  1268  		{
  1269  			name:                     "memif",
  1270  			key:                      "vpp/interface/memif0/has-IP-address",
  1271  			expectedIface:            "memif0",
  1272  			expectedIsIfaceWithIPKey: true,
  1273  		},
  1274  		{
  1275  			name:                     "Gbe",
  1276  			key:                      "vpp/interface/GigabitEthernet0/8/0/has-IP-address",
  1277  			expectedIface:            "GigabitEthernet0/8/0",
  1278  			expectedIsIfaceWithIPKey: true,
  1279  		},
  1280  		{
  1281  			name:                     "invalid interface name",
  1282  			key:                      "vpp/interface/<invalid>/has-IP-address",
  1283  			expectedIsIfaceWithIPKey: false,
  1284  		},
  1285  		{
  1286  			name:                     "missing has-IP-address suffix",
  1287  			key:                      "vpp/interface/<invalid>",
  1288  			expectedIsIfaceWithIPKey: false,
  1289  		},
  1290  		{
  1291  			name:                     "not has-IP-address key",
  1292  			key:                      "vpp/interface/memif0/address/192.168.1.12/24",
  1293  			expectedIsIfaceWithIPKey: false,
  1294  		},
  1295  	}
  1296  	for _, test := range tests {
  1297  		t.Run(test.name, func(t *testing.T) {
  1298  			iface, isInterfaceWithIPKey := ParseInterfaceWithIPKey(test.key)
  1299  			if isInterfaceWithIPKey != test.expectedIsIfaceWithIPKey {
  1300  				t.Errorf("expected isInterfaceWithIPKey: %v\tgot: %v",
  1301  					test.expectedIsIfaceWithIPKey, isInterfaceWithIPKey)
  1302  			}
  1303  			if iface != test.expectedIface {
  1304  				t.Errorf("expected iface: %s\tgot: %s", test.expectedIface, iface)
  1305  			}
  1306  		})
  1307  	}
  1308  }