cisco_node_utils 1.0.1 → 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (114) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +4 -0
  3. data/.rubocop.yml +81 -1
  4. data/.travis.yml +9 -0
  5. data/CHANGELOG.md +72 -6
  6. data/CONTRIBUTING.md +32 -7
  7. data/README.md +70 -7
  8. data/Rakefile +17 -0
  9. data/bin/check_metric_limits.rb +109 -0
  10. data/bin/git/hooks/commit-msg/enforce_style +81 -0
  11. data/bin/git/hooks/hook_lib +108 -0
  12. data/bin/git/hooks/hooks-wrapper +38 -0
  13. data/bin/git/hooks/post-flow-hotfix-start/update-version +24 -0
  14. data/bin/git/hooks/post-flow-release-finish/update-version +29 -0
  15. data/bin/git/hooks/post-flow-release-start/update-version +19 -0
  16. data/bin/git/hooks/post-merge/update-hooks +6 -0
  17. data/bin/git/hooks/post-rewrite/update-hooks +6 -0
  18. data/bin/git/hooks/pre-commit/rubocop +20 -0
  19. data/bin/git/hooks/pre-commit/validate-diffs +31 -0
  20. data/bin/git/hooks/pre-push/check-changelog +24 -0
  21. data/bin/git/hooks/pre-push/rubocop +7 -0
  22. data/bin/git/update-hooks +65 -0
  23. data/cisco_node_utils.gemspec +9 -3
  24. data/docs/README-develop-best-practices.md +404 -0
  25. data/docs/README-develop-node-utils-APIs.md +215 -365
  26. data/docs/README-maintainers.md +33 -3
  27. data/docs/template-router.rb +89 -91
  28. data/docs/template-test_router.rb +52 -55
  29. data/lib/.rubocop.yml +18 -0
  30. data/lib/cisco_node_utils.rb +2 -19
  31. data/lib/cisco_node_utils/README_YAML.md +1 -9
  32. data/lib/cisco_node_utils/bgp.rb +664 -0
  33. data/lib/cisco_node_utils/bgp_af.rb +530 -0
  34. data/lib/cisco_node_utils/bgp_neighbor.rb +425 -0
  35. data/lib/cisco_node_utils/bgp_neighbor_af.rb +709 -0
  36. data/lib/cisco_node_utils/cisco_cmn_utils.rb +59 -25
  37. data/lib/cisco_node_utils/command_reference.rb +72 -74
  38. data/lib/cisco_node_utils/command_reference_common.yaml +174 -9
  39. data/lib/cisco_node_utils/command_reference_common_bgp.yaml +535 -0
  40. data/lib/cisco_node_utils/command_reference_n7k.yaml +4 -0
  41. data/lib/cisco_node_utils/command_reference_n9k.yaml +0 -9
  42. data/lib/cisco_node_utils/configparser_lib.rb +152 -147
  43. data/lib/cisco_node_utils/dns_domain.rb +79 -0
  44. data/lib/cisco_node_utils/domain_name.rb +71 -0
  45. data/lib/cisco_node_utils/interface.rb +167 -161
  46. data/lib/cisco_node_utils/interface_ospf.rb +78 -81
  47. data/lib/cisco_node_utils/name_server.rb +64 -0
  48. data/lib/cisco_node_utils/node.rb +154 -198
  49. data/lib/cisco_node_utils/node_util.rb +61 -0
  50. data/lib/cisco_node_utils/ntp_config.rb +65 -0
  51. data/lib/cisco_node_utils/ntp_server.rb +76 -0
  52. data/lib/cisco_node_utils/platform.rb +174 -165
  53. data/lib/cisco_node_utils/radius_global.rb +146 -0
  54. data/lib/cisco_node_utils/radius_server.rb +295 -0
  55. data/lib/cisco_node_utils/router_ospf.rb +59 -63
  56. data/lib/cisco_node_utils/router_ospf_vrf.rb +226 -210
  57. data/lib/cisco_node_utils/snmpcommunity.rb +52 -58
  58. data/lib/cisco_node_utils/snmpgroup.rb +22 -23
  59. data/lib/cisco_node_utils/snmpserver.rb +99 -103
  60. data/lib/cisco_node_utils/snmpuser.rb +294 -274
  61. data/lib/cisco_node_utils/syslog_server.rb +92 -0
  62. data/lib/cisco_node_utils/syslog_settings.rb +69 -0
  63. data/lib/cisco_node_utils/tacacs_server.rb +137 -133
  64. data/lib/cisco_node_utils/tacacs_server_host.rb +84 -87
  65. data/lib/cisco_node_utils/version.rb +2 -1
  66. data/lib/cisco_node_utils/vlan.rb +28 -31
  67. data/lib/cisco_node_utils/vrf.rb +80 -0
  68. data/lib/cisco_node_utils/vtp.rb +100 -97
  69. data/lib/cisco_node_utils/yum.rb +15 -17
  70. data/tests/.rubocop.yml +15 -0
  71. data/tests/basetest.rb +81 -36
  72. data/tests/ciscotest.rb +38 -78
  73. data/{lib/cisco_node_utils → tests}/platform_info.rb +12 -8
  74. data/{lib/cisco_node_utils → tests}/platform_info.yaml +1 -1
  75. data/tests/test_bgp_af.rb +920 -0
  76. data/tests/test_bgp_neighbor.rb +403 -0
  77. data/tests/test_bgp_neighbor_af.rb +589 -0
  78. data/tests/test_command_config.rb +65 -62
  79. data/tests/test_command_reference.rb +31 -45
  80. data/tests/test_dns_domain.rb +113 -0
  81. data/tests/test_domain_name.rb +86 -0
  82. data/tests/test_interface.rb +424 -548
  83. data/tests/test_interface_ospf.rb +248 -432
  84. data/tests/test_interface_svi.rb +56 -79
  85. data/tests/test_interface_switchport.rb +196 -272
  86. data/tests/test_name_server.rb +85 -0
  87. data/tests/test_node.rb +7 -6
  88. data/tests/test_node_ext.rb +133 -186
  89. data/tests/test_ntp_config.rb +49 -0
  90. data/tests/test_ntp_server.rb +74 -0
  91. data/tests/test_platform.rb +58 -37
  92. data/tests/test_radius_global.rb +78 -0
  93. data/tests/test_radius_server.rb +185 -0
  94. data/tests/test_router_bgp.rb +838 -0
  95. data/tests/test_router_ospf.rb +49 -80
  96. data/tests/test_router_ospf_vrf.rb +274 -392
  97. data/tests/test_snmpcommunity.rb +128 -172
  98. data/tests/test_snmpgroup.rb +12 -14
  99. data/tests/test_snmpserver.rb +160 -189
  100. data/tests/test_snmpuser.rb +568 -717
  101. data/tests/test_syslog_server.rb +88 -0
  102. data/tests/test_syslog_settings.rb +54 -0
  103. data/tests/test_tacacs_server.rb +113 -148
  104. data/tests/test_tacacs_server_host.rb +108 -161
  105. data/tests/test_vlan.rb +63 -79
  106. data/tests/test_vrf.rb +92 -0
  107. data/tests/test_vtp.rb +108 -126
  108. data/tests/test_yum.rb +47 -41
  109. metadata +92 -56
  110. data/.rubocop_todo.yml +0 -293
  111. data/docs/.rubocop.yml +0 -13
  112. data/docs/template-feature.rb +0 -45
  113. data/docs/template-test_feature.rb +0 -51
  114. data/tests/test_all_cisco.rb +0 -46
@@ -0,0 +1,403 @@
1
+ #!/usr/bin/env ruby
2
+ # RouterBgpNeighbor Unit Tests
3
+ #
4
+ # Jie Yang, August 2015
5
+ #
6
+ # Copyright (c) 2015 Cisco and/or its affiliates.
7
+ #
8
+ # Licensed under the Apache License, Version 2.0 (the "License");
9
+ # you may not use this file except in compliance with the License.
10
+ # You may obtain a copy of the License at
11
+ #
12
+ # http://www.apache.org/licenses/LICENSE-2.0
13
+ #
14
+ # Unless required by applicable law or agreed to in writing, software
15
+ # distributed under the License is distributed on an "AS IS" BASIS,
16
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17
+ # See the License for the specific language governing permissions and
18
+ # limitations under the License.
19
+
20
+ require_relative 'ciscotest'
21
+ require_relative '../lib/cisco_node_utils/bgp'
22
+ require_relative '../lib/cisco_node_utils/bgp_neighbor'
23
+
24
+ # TestRouterBgpNeighbor - Minitest for RouterBgpNeighbor node utility class
25
+ class TestRouterBgpNeighbor < CiscoTestCase
26
+ # rubocop:disable Style/ClassVars
27
+ @@asn = 55
28
+ @@addr = '1.1.1.1'
29
+ # rubocop:enable Style/ClassVars
30
+
31
+ def setup
32
+ # Disable feature bgp before each test to ensure we
33
+ # are starting with a clean slate for each test.
34
+ super
35
+ config('no feature bgp', 'feature bgp', 'router bgp 55')
36
+ end
37
+
38
+ def teardown
39
+ config('no feature bgp')
40
+ end
41
+
42
+ def get_bgpneighbor_match_line(addr, vrf='default')
43
+ if vrf == 'default'
44
+ cmd = "show run bgp all | section 'router bgp' | no-more"
45
+ else
46
+ cmd = "show run bgp all | section 'vrf #{vrf}' | no-more"
47
+ end
48
+ CiscoLogger.debug("matching #{addr} with vrf #{vrf}")
49
+ s = @device.cmd("#{cmd}")
50
+ line = /neighbor #{addr}/.match(s)
51
+ CiscoLogger.debug(line)
52
+ line
53
+ end
54
+
55
+ def test_bgpneighbor_collection_empty
56
+ config('no feature bgp')
57
+ neighbors = RouterBgpNeighbor.neighbors
58
+ assert_empty(neighbors, 'BGP neighbor collection is not empty')
59
+ end
60
+
61
+ def test_bgpneighbor_collection_not_empty
62
+ config('router bgp 55',
63
+ 'neighbor 1.1.1.1',
64
+ 'vrf red',
65
+ 'neighbor 2.2.2.0/24',
66
+ 'neighbor 2000::2',
67
+ 'neighbor 2000:123:38::/64')
68
+ bgp_neighbors = RouterBgpNeighbor.neighbors
69
+ refute_empty(bgp_neighbors, 'BGP neighbor collection is empty')
70
+ # validate the collection
71
+ bgp_neighbors.each_value do |vrfs|
72
+ vrfs.each do |vrf, neighbors|
73
+ if vrf == 'default'
74
+ assert_equal(1, neighbors.size)
75
+ else
76
+ assert_equal(3, neighbors.size)
77
+ end
78
+ neighbors.each_value do |neighbor|
79
+ assert_equal(vrf, neighbor.vrf)
80
+ line = get_bgpneighbor_match_line(neighbor.nbr, vrf)
81
+ refute_nil(line)
82
+ end
83
+ end
84
+ end
85
+ end
86
+
87
+ def test_bgpneighbor_create_destroy
88
+ address = { '1.1.1.1' => '1.1.1.1',
89
+ '2.2.2.2/24' => '2.2.2.0/24',
90
+ '2000::2' => '2000::2',
91
+ '2000:123:38::34/64' => '2000:123:38::/64',
92
+ }
93
+ vrfs = %w(default red)
94
+ vrfs.each do |vrf|
95
+ address.each do |addr, expected_addr|
96
+ neighbor = RouterBgpNeighbor.new(@@asn, vrf, addr)
97
+ line = get_bgpneighbor_match_line(expected_addr, vrf)
98
+ refute_nil(line, "Error: failed to create bgp neighbor #{addr}")
99
+ neighbor.destroy
100
+ line = get_bgpneighbor_match_line(expected_addr, vrf)
101
+ assert_nil(line, "Error: failed to delete bgp neighbor #{addr}")
102
+ end
103
+ end
104
+ end
105
+
106
+ def test_bgpneighbor_set_get_description
107
+ %w(default test_vrf).each do |vrf|
108
+ neighbor = RouterBgpNeighbor.new(@@asn, vrf, @@addr)
109
+ description = "tested by mini test for vrf #{vrf}"
110
+ neighbor.description = description
111
+ assert_equal(description, neighbor.description)
112
+ neighbor.description = ' '
113
+ assert(neighbor.description.empty?)
114
+ neighbor.description = neighbor.default_description
115
+ assert_equal(neighbor.description, neighbor.default_description)
116
+ neighbor.destroy
117
+ end
118
+ end
119
+
120
+ def test_bgpneighbor_set_get_multiple_descriptions
121
+ # First create multiple routers with multiple desriptions.
122
+ address = ['1.1.1.1', '2.2.2.0/24', '2000::2', '2000:123:38::/64']
123
+ vrfs = %w(default red)
124
+ vrfs.each do |vrf|
125
+ address.each do |addr|
126
+ neighbor = RouterBgpNeighbor.new(@@asn, vrf, addr)
127
+ neighbor.description = "#{vrf}:#{addr}"
128
+ end
129
+ end
130
+ # Now test if the description has been correctly set
131
+ RouterBgpNeighbor.neighbors.each_value do |bgp_vrfs|
132
+ bgp_vrfs.each do |vrf, neighbors|
133
+ neighbors.each do |addr, neighbor|
134
+ assert_equal("#{vrf}:#{addr}", neighbor.description)
135
+ neighbor.description = ''
136
+ assert(neighbor.description.empty?)
137
+ neighbor.description = neighbor.default_description
138
+ assert_equal(neighbor.description, neighbor.default_description)
139
+ neighbor.destroy
140
+ end
141
+ end
142
+ end
143
+ end
144
+
145
+ def test_bgpneighbor_set_get_connected_check
146
+ %w(default test_vrf).each do |vrf|
147
+ neighbor = RouterBgpNeighbor.new(@@asn, vrf, @@addr)
148
+ check = [true, false, neighbor.default_connected_check]
149
+ check.each do |value|
150
+ neighbor.connected_check = value
151
+ assert_equal(value, neighbor.connected_check)
152
+ end
153
+ neighbor.destroy
154
+ end
155
+ end
156
+
157
+ def test_bgpneighbor_set_get_capability_negotiation
158
+ %w(default test_vrf).each do |vrf|
159
+ neighbor = RouterBgpNeighbor.new(@@asn, vrf, @@addr)
160
+ check = [true, false, neighbor.default_capability_negotiation]
161
+ check.each do |value|
162
+ neighbor.capability_negotiation = value
163
+ assert_equal(value, neighbor.capability_negotiation)
164
+ end
165
+ neighbor.destroy
166
+ end
167
+ end
168
+
169
+ def test_bgpneighbor_set_get_dynamic_capability
170
+ %w(default test_vrf).each do |vrf|
171
+ neighbor = RouterBgpNeighbor.new(@@asn, vrf, @@addr)
172
+ check = [true, false, neighbor.default_dynamic_capability]
173
+ check.each do |value|
174
+ neighbor.dynamic_capability = value
175
+ assert_equal(value, neighbor.dynamic_capability)
176
+ end
177
+ neighbor.destroy
178
+ end
179
+ end
180
+
181
+ def test_bgpneighbor_set_get_ebgp_multihop
182
+ %w(default test_vrf).each do |vrf|
183
+ neighbor = RouterBgpNeighbor.new(@@asn, vrf, @@addr)
184
+ ttls = [24, neighbor.default_ebgp_multihop]
185
+ ttls.each do |ebgp_multihop|
186
+ neighbor.ebgp_multihop = ebgp_multihop
187
+ assert_equal(ebgp_multihop, neighbor.ebgp_multihop)
188
+ end
189
+ neighbor.destroy
190
+ end
191
+ end
192
+
193
+ def test_bgpneighbor_set_get_local_as
194
+ %w(default test_vrf).each do |vrf|
195
+ neighbor = RouterBgpNeighbor.new(@@asn, vrf, @@addr)
196
+ local_asnum = [42, '52', '1.1', neighbor.default_local_as]
197
+ local_asnum.each do |asnum|
198
+ neighbor.local_as = asnum
199
+ if asnum == '52'
200
+ assert_equal(asnum.to_i, neighbor.local_as)
201
+ else
202
+ assert_equal(asnum, neighbor.local_as)
203
+ end
204
+ end
205
+ # test a negative value
206
+ assert_raises(ArgumentError) do
207
+ neighbor.local_as = '52 15'
208
+ end
209
+ neighbor.destroy
210
+ end
211
+ end
212
+
213
+ def test_bgpneighbor_set_get_log_neighbor_changes
214
+ %w(default test_vrf).each do |vrf|
215
+ neighbor = RouterBgpNeighbor.new(@@asn, vrf, @@addr)
216
+ check = [:enable, :disable, :inherit, 'enable', 'disable', 'inherit',
217
+ neighbor.default_log_neighbor_changes]
218
+ check.each do |value|
219
+ neighbor.log_neighbor_changes = value
220
+ assert_equal(value.to_sym, neighbor.log_neighbor_changes)
221
+ end
222
+ neighbor.destroy
223
+ end
224
+ end
225
+
226
+ def test_bgpneighbor_set_get_low_memory_exempt
227
+ %w(default test_vrf).each do |vrf|
228
+ neighbor = RouterBgpNeighbor.new(@@asn, vrf, @@addr)
229
+ check = [true, false, neighbor.default_low_memory_exempt]
230
+ check.each do |value|
231
+ neighbor.low_memory_exempt = value
232
+ assert_equal(value, neighbor.low_memory_exempt)
233
+ end
234
+ neighbor.destroy
235
+ end
236
+ end
237
+
238
+ def test_bgpneighbor_set_get_maximum_peers
239
+ # only "address/prefix" type of neighbor address will accept
240
+ # maximum_peers command
241
+ addr = '1.1.1.0/24'
242
+ %w(default test_vrf).each do |vrf|
243
+ neighbor = RouterBgpNeighbor.new(@@asn, vrf, addr)
244
+ peers = [200, neighbor.default_maximum_peers]
245
+ peers.each do |num|
246
+ neighbor.maximum_peers = num
247
+ assert_equal(num, neighbor.maximum_peers)
248
+ end
249
+ neighbor.destroy
250
+ end
251
+ end
252
+
253
+ def test_bgpneighbor_set_get_password
254
+ %w(default test_vrf).each do |vrf|
255
+ neighbor = RouterBgpNeighbor.new(@@asn, vrf, @@addr)
256
+ passwords = {}
257
+ passwords[:cleartext] = 'test'
258
+ passwords[:"3des"] = '386c0565965f89de'
259
+ passwords[:cisco_type_7] = '046E1803362E595C260E0B240619050A2D'
260
+
261
+ passwords.each do |type, password|
262
+ neighbor.password_set(password, type)
263
+ if type == :cleartext
264
+ assert_equal(:"3des", neighbor.password_type)
265
+ assert_equal(passwords[:"3des"], neighbor.password)
266
+ else
267
+ assert_equal(type, neighbor.password_type)
268
+ assert_equal(password, neighbor.password)
269
+ end
270
+ # now test removing the password setting
271
+ neighbor.password_set(' ')
272
+ assert(neighbor.password.empty?)
273
+ # now test default password
274
+ neighbor.password_set(neighbor.default_password)
275
+ assert_equal(neighbor.default_password, neighbor.password)
276
+ end
277
+ neighbor.destroy
278
+ end
279
+ end
280
+
281
+ def test_bgpneighbor_set_default_password_type
282
+ %w(default test_vrf).each do |vrf|
283
+ neighbor = RouterBgpNeighbor.new(@@asn, vrf, @@addr)
284
+ password = 'test'
285
+ expected_password = '386c0565965f89de'
286
+
287
+ # Test 1: if we don't set password type, default should be cleartext,
288
+ # we can verify by checking return type to be :3des, and encrypted text.
289
+ neighbor.password_set(password)
290
+ assert_equal(expected_password, neighbor.password)
291
+ assert_equal(:"3des", neighbor.password_type)
292
+ # clear password
293
+ neighbor.password_set('')
294
+ assert(neighbor.password.empty?)
295
+
296
+ # Test 2: we set explicitly the password type to be default password type:
297
+ # cleartext, and verify.
298
+ neighbor.password_set(password, neighbor.default_password_type)
299
+ assert_equal(expected_password, neighbor.password)
300
+ assert_equal(:"3des", neighbor.password_type)
301
+ neighbor.password_set('')
302
+ assert(neighbor.password.empty?)
303
+ neighbor.destroy
304
+ end
305
+ end
306
+
307
+ def test_bgpneighbor_set_get_remote_as
308
+ %w(default test_vrf).each do |vrf|
309
+ neighbor = RouterBgpNeighbor.new(@@asn, vrf, @@addr)
310
+ remote_asnum = [42, '1.1', neighbor.default_remote_as]
311
+ remote_asnum.each do |asnum|
312
+ neighbor.remote_as = asnum
313
+ assert_equal(asnum, neighbor.remote_as)
314
+ end
315
+ neighbor.destroy
316
+ end
317
+ end
318
+
319
+ def test_bgpneighbor_set_get_remove_private_as_options
320
+ %w(default test_vrf).each do |vrf|
321
+ neighbor = RouterBgpNeighbor.new(@@asn, vrf, @@addr)
322
+ options = [:enable, :disable, :all, :"replace-as", 'enable', 'disable',
323
+ 'all', 'replace-as', neighbor.default_remove_private_as]
324
+ options.each do |option|
325
+ neighbor.remove_private_as = option
326
+ assert_equal(option.to_sym, neighbor.remove_private_as)
327
+ end
328
+
329
+ neighbor.remove_private_as = neighbor.default_remove_private_as
330
+ assert_equal(neighbor.default_remove_private_as,
331
+ neighbor.remove_private_as)
332
+ neighbor.destroy
333
+ end
334
+ end
335
+
336
+ def test_bgpneighbor_set_get_shutdown
337
+ %w(default test_vrf).each do |vrf|
338
+ neighbor = RouterBgpNeighbor.new(@@asn, vrf, @@addr)
339
+ check = [true, false, neighbor.default_shutdown]
340
+ check.each do |value|
341
+ neighbor.shutdown = value
342
+ assert_equal(value, neighbor.shutdown)
343
+ end
344
+ neighbor.destroy
345
+ end
346
+ end
347
+
348
+ def test_bgpneighbor_set_get_suppress_4_byte_as
349
+ %w(default test_vrf).each do |vrf|
350
+ neighbor = RouterBgpNeighbor.new(@@asn, vrf, @@addr)
351
+ check = [true, false, neighbor.default_suppress_4_byte_as]
352
+ check.each do |value|
353
+ neighbor.suppress_4_byte_as = value
354
+ assert_equal(value, neighbor.suppress_4_byte_as)
355
+ end
356
+ neighbor.destroy
357
+ end
358
+ end
359
+
360
+ def test_bgpneighbor_set_get_timers
361
+ %w(default test_vrf).each do |vrf|
362
+ neighbor = RouterBgpNeighbor.new(@@asn, vrf, @@addr)
363
+ timers = [{ keep: 40, hold: 90 },
364
+ { keep: neighbor.default_timers_keepalive,
365
+ hold: neighbor.default_timers_holdtime },
366
+ { keep: neighbor.default_timers_keepalive,
367
+ hold: 90 },
368
+ { keep: 40, hold: neighbor.default_timers_holdtime },
369
+ ]
370
+ timers.each do |timer|
371
+ neighbor.timers_set(timer[:keep], timer[:hold])
372
+ assert_equal(timer[:keep], neighbor.timers_keepalive)
373
+ assert_equal(timer[:hold], neighbor.timers_holdtime)
374
+ end
375
+ neighbor.destroy
376
+ end
377
+ end
378
+
379
+ def test_bgpneighbor_set_get_transport_passive_only
380
+ %w(default test_vrf).each do |vrf|
381
+ neighbor = RouterBgpNeighbor.new(@@asn, vrf, @@addr)
382
+ check = [true, false, neighbor.default_transport_passive_only]
383
+ check.each do |value|
384
+ neighbor.transport_passive_only = value
385
+ assert_equal(value, neighbor.transport_passive_only)
386
+ end
387
+ neighbor.destroy
388
+ end
389
+ end
390
+
391
+ def test_bgpneighbor_set_get_update_source
392
+ %w(default test_vrf).each do |vrf|
393
+ neighbor = RouterBgpNeighbor.new(@@asn, vrf, @@addr)
394
+ interfaces = ['loopback1', 'Ethernet1/1', 'ethernet1/1',
395
+ neighbor.default_update_source]
396
+ interfaces.each do |interface|
397
+ neighbor.update_source = interface
398
+ assert_equal(interface.downcase, neighbor.update_source)
399
+ end
400
+ neighbor.destroy
401
+ end
402
+ end
403
+ end
@@ -0,0 +1,589 @@
1
+ #!/usr/bin/env ruby
2
+ # RouterBgpNeighborAF Unit Tests
3
+ #
4
+ # August 2015 Chris Van Heuveln
5
+ #
6
+ # Copyright (c) 2015 Cisco and/or its affiliates.
7
+ #
8
+ # Licensed under the Apache License, Version 2.0 (the "License");
9
+ # you may not use this file except in compliance with the License.
10
+ # You may obtain a copy of the License at
11
+ #
12
+ # http://www.apache.org/licenses/LICENSE-2.0
13
+ #
14
+ # Unless required by applicable law or agreed to in writing, software
15
+ # distributed under the License is distributed on an "AS IS" BASIS,
16
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17
+ # See the License for the specific language governing permissions and
18
+ # limitations under the License.
19
+
20
+ require_relative 'ciscotest'
21
+ require_relative '../lib/cisco_node_utils/cisco_cmn_utils'
22
+ require_relative '../lib/cisco_node_utils/bgp'
23
+ require_relative '../lib/cisco_node_utils/bgp_neighbor'
24
+ require_relative '../lib/cisco_node_utils/bgp_neighbor_af'
25
+
26
+ # TestRouterBgpNeighborAF - Minitest for RouterBgpNeighborAF class
27
+ class TestRouterBgpNeighborAF < CiscoTestCase
28
+ @@reset_feat = true # rubocop:disable Style/ClassVars
29
+
30
+ def setup
31
+ super
32
+ if @@reset_feat
33
+ config('no feature bgp', 'feature bgp')
34
+ @@reset_feat = false # rubocop:disable Style/ClassVars
35
+ else
36
+ # Just ensure that feature is enabled
37
+ config('feature bgp')
38
+ end
39
+ end
40
+
41
+ def clean_af(af_args, ebgp=true)
42
+ # Most tests only need an address-family cleanup
43
+ asn, vrf, nbr, af = af_args
44
+ dbg = sprintf('[VRF %s NBR %s AF %s]', vrf, nbr, af.join('/'))
45
+
46
+ obj_nbr = RouterBgpNeighbor.new(asn, vrf, nbr, true)
47
+ obj_nbr.remote_as = ebgp ? asn + 1 : asn
48
+
49
+ obj_af = RouterBgpNeighborAF.new(asn, vrf, nbr, af, true)
50
+
51
+ # clean up address-family only
52
+ obj_af.destroy
53
+ obj_af.create
54
+ [obj_af, dbg]
55
+ end
56
+
57
+ # def test_foo
58
+ # af, dbg = clean_af([2, 'red', '1.1.1.1', %w(ipv4 unicast)])
59
+ # foo(af, dbg)
60
+ # end
61
+
62
+ # AF test matrix
63
+ @@matrix = { # rubocop:disable Style/ClassVars
64
+ # 1 => [1, 'default', '10:1::1', %w(ipv4 multicast)], # UNSUPPORTED
65
+ # 2 => [1, 'default', '10:1::1', %w(ipv4 unicast)],
66
+ # 3 => [1, 'default', '10:1::1', %w(ipv6 multicast)],
67
+ # 4 => [1, 'default', '10:1::1', %w(ipv6 unicast)],
68
+ # 5 => [1, 'default', '1.1.1.1', %w(ipv4 multicast)],
69
+ 6 => [1, 'default', '1.1.1.1', %w(ipv4 unicast)],
70
+ # 7 => [1, 'default', '1.1.1.1', %w(ipv6 multicast)],
71
+ 8 => [1, 'default', '1.1.1.1', %w(ipv6 unicast)],
72
+ # 9 => [1, 'aa', '2.2.2.2', %w(ipv4 multicast)],
73
+ # 10 => [1, 'aa', '2.2.2.2', %w(ipv4 unicast)],
74
+ # 11 => [1, 'bb', '2.2.2.2', %w(ipv6 multicast)],
75
+ # 12 => [1, 'bb', '2.2.2.2', %w(ipv6 unicast)],
76
+ # 13 => [1, 'cc', '10:1::2', %w(ipv4 multicast)], # UNSUPPORTED
77
+ # 14 => [1, 'cc', '10:1::2', %w(ipv4 unicast)],
78
+ # 15 => [1, 'cc', '10:1::2', %w(ipv6 multicast)],
79
+ # 16 => [1, 'cc', '10:1::2', %w(ipv6 unicast)],
80
+ }
81
+
82
+ # ---------------------------------
83
+ def test_nbr_af_create_destroy
84
+ config('no feature bgp', 'feature bgp')
85
+
86
+ # Creates
87
+ obj = {}
88
+ @@matrix.each do |k, v|
89
+ asn, vrf, nbr, af = v
90
+ dbg = sprintf('[VRF %s NBR %s AF %s]', vrf, nbr, af)
91
+ obj[k] = RouterBgpNeighborAF.new(asn, vrf, nbr, af, true)
92
+ afs = RouterBgpNeighborAF.afs
93
+ assert(afs[asn][vrf][nbr].key?(af),
94
+ "#{dbg} Failed to create AF")
95
+ end
96
+
97
+ # Destroys
98
+ @@matrix.each do |k, v|
99
+ asn, vrf, nbr, af = v
100
+ dbg = sprintf('[VRF %s NBR %s AF %s]', vrf, nbr, af)
101
+ obj[k].destroy
102
+ afs = RouterBgpNeighborAF.afs
103
+ refute(afs[asn][vrf][nbr].key?(af),
104
+ "#{dbg} Failed to destroy AF")
105
+ end
106
+ end
107
+
108
+ # ---------------------------------
109
+ def test_nbrs_with_masks
110
+ config('no feature bgp', 'feature bgp')
111
+
112
+ # Creates
113
+ obj = {}
114
+ @@matrix.each do |k, v|
115
+ asn, vrf, nbr, af = v
116
+ nbr += (nbr[/:/]) ? '/64' : '/16'
117
+ dbg = sprintf('[VRF %s NBR %s AF %s]', vrf, nbr, af.join('/'))
118
+ obj[k] = RouterBgpNeighborAF.new(asn, vrf, nbr, af, true)
119
+ nbr_munged = Utils.process_network_mask(nbr)
120
+ afs = RouterBgpNeighborAF.afs
121
+ assert(afs[asn][vrf][nbr_munged].key?(af),
122
+ "#{dbg} Failed to create AF")
123
+ end
124
+
125
+ # Destroys
126
+ @@matrix.each do |k, v|
127
+ asn, vrf, nbr, af = v
128
+ nbr += (nbr[/:/]) ? '/64' : '/16'
129
+ dbg = sprintf('[VRF %s NBR %s AF %s]', vrf, nbr, af.join('/'))
130
+ obj[k].destroy
131
+ nbr_munged = Utils.process_network_mask(nbr)
132
+ afs = RouterBgpNeighborAF.afs
133
+ refute(afs[asn][vrf][nbr_munged].key?(af),
134
+ "#{dbg} Failed to destroy AF")
135
+ end
136
+ @@reset_feat = true # rubocop:disable Style/ClassVars
137
+ end
138
+
139
+ # ---------------------------------
140
+ def test_props_bool
141
+ @@matrix.values.each do |af_args|
142
+ af, dbg = clean_af(af_args)
143
+ props_bool(af, dbg)
144
+ end
145
+ end
146
+
147
+ def props_bool(af, dbg)
148
+ # These properties have simple boolean states. As such we can use a common
149
+ # set of tests to validate each property.
150
+ props = [
151
+ :as_override,
152
+ :disable_peer_as_check,
153
+ :next_hop_self,
154
+ :next_hop_third_party,
155
+ :suppress_inactive,
156
+ ]
157
+
158
+ # Call setter to false, then validate with getter
159
+ props.each { |k| af.send("#{k}=", false) }
160
+ props.each do |k|
161
+ refute(af.send(k), "Test 1. #{dbg} [#{k}=] did not set false")
162
+ end
163
+
164
+ # Call setter to true, then validate with getter
165
+ props.each { |k| af.send("#{k}=", true) }
166
+ props.each do |k|
167
+ assert(af.send(k), "Test 2. #{dbg} [#{k}=] did not set true")
168
+ end
169
+
170
+ # Set to default and validate
171
+ def_val = {}
172
+ props.each { |k| def_val[k] = af.send("default_#{k}") }
173
+ props.each { |k| af.send("#{k}=", def_val[k]) }
174
+ props.each do |k|
175
+ assert_equal(def_val[k], af.send(k),
176
+ "Test 3. #{dbg} [#{k}=] did not set to default")
177
+ end
178
+ end
179
+
180
+ # ---------------------------------
181
+ def test_props_string
182
+ @@matrix.values.each do |af_args|
183
+ af, dbg = clean_af(af_args)
184
+ props_string(af, dbg)
185
+ end
186
+ end
187
+
188
+ def props_string(af, dbg)
189
+ # These properties have a common string value (route-map), allowing them
190
+ # to use a common set of tests to validate each property.
191
+ props = {
192
+ filter_list_in: 'filt-in-name',
193
+ filter_list_out: 'filt-out-name',
194
+ prefix_list_in: 'pref-in-name',
195
+ prefix_list_out: 'pref-out-name',
196
+ route_map_in: 'route-map-in-name',
197
+ route_map_out: 'route-map-out-name',
198
+ unsuppress_map: 'unsupp-map-name',
199
+ }
200
+
201
+ props.each do |k, v|
202
+ # Call setter.
203
+ af.send("#{k}=", v)
204
+
205
+ # Validate with getter
206
+ assert_equal(v, af.send(k),
207
+ "Test 1. #{dbg} [#{k}=] did not set string '#{v}'")
208
+
209
+ af.send("#{k}=", v.reverse!)
210
+ assert_equal(v, af.send(k),
211
+ "Test 2. #{dbg} [#{k}=] did not set string '#{v}'")
212
+
213
+ # Set to default
214
+ af.send("#{k}=", af.send("default_#{k}"))
215
+ assert_empty(af.send(k),
216
+ "Test 3. #{dbg} [#{k}=] did not set default [default_#{k}]")
217
+ end
218
+ end
219
+
220
+ # ---------------------------------
221
+ # tri-state properties:
222
+ # additional_paths_receive
223
+ # additional_paths_send
224
+ # soft_reconfiguration_in
225
+ def test_tri_states
226
+ @@matrix.values.each do |af_args|
227
+ af, dbg = clean_af(af_args)
228
+
229
+ %w(additional_paths_receive additional_paths_send).each do |k|
230
+ [:enable, :disable, :inherit, 'enable', 'disable', 'inherit',
231
+ af.send("default_#{k}")
232
+ ].each do |val|
233
+ af.send("#{k}=", val)
234
+ assert_equal(val.to_sym, af.send(k), "#{dbg} Error: #{k}")
235
+ end
236
+ end
237
+
238
+ %w(soft_reconfiguration_in).each do |k|
239
+ [:enable, :always, :inherit, 'enable', 'always', 'inherit',
240
+ af.send("default_#{k}")
241
+ ].each do |val|
242
+ af.send("#{k}=", val)
243
+ assert_equal(val.to_sym, af.send(k), "#{dbg} Error: #{k}")
244
+ end
245
+ end
246
+ end
247
+ end
248
+
249
+ # ---------------------------------
250
+ def test_advertise_map
251
+ @@matrix.values.each do |af_args|
252
+ af, dbg = clean_af(af_args)
253
+ advertise_map(af, dbg)
254
+ end
255
+ end
256
+
257
+ def advertise_map(af, dbg)
258
+ %w(advertise_map_exist advertise_map_non_exist).each do |k|
259
+ v = %w(foo bar)
260
+ af.send("#{k}=", v)
261
+ assert_equal(v, af.send(k),
262
+ "Test 1. #{dbg} [#{k}=] did not set strings '#{v}'")
263
+
264
+ # Change to new strings
265
+ v = %w(baz inga)
266
+ af.send("#{k}=", v)
267
+ assert_equal(v, af.send(k),
268
+ "Test 2. #{dbg} [#{k}=] did not set strings '#{v}'")
269
+
270
+ # Set to default
271
+ af.send("#{k}=", af.send("default_#{k}"))
272
+ assert_empty(af.send(k),
273
+ "Test 3. #{dbg} [#{k}] did not set to default " \
274
+ "'[default_#{k}]'")
275
+ end
276
+ end
277
+
278
+ # ---------------------------------
279
+ def test_allowas_in
280
+ @@matrix.values.each do |af_args|
281
+ af, dbg = clean_af(af_args)
282
+ allowas_in(af, dbg)
283
+ end
284
+ end
285
+
286
+ def allowas_in(af, dbg)
287
+ af.allowas_in_set(true)
288
+ assert(af.allowas_in,
289
+ "Test 1. #{dbg} Failed to set state to True")
290
+
291
+ # Test true with value
292
+ af.allowas_in_set(true, 5)
293
+ assert_equal(5, af.allowas_in_max,
294
+ "Test 2. #{dbg} Failed to set True with Value")
295
+
296
+ # Test false with value
297
+ af.allowas_in_set(false)
298
+ refute(af.allowas_in,
299
+ "Test 3. #{dbg} Failed to set state to False")
300
+
301
+ # Test true with value, from false
302
+ af.allowas_in_set(true, 4)
303
+ assert_equal(4, af.allowas_in_max,
304
+ "Test 4. #{dbg} Failed to set True with Value, " \
305
+ 'from false state')
306
+
307
+ # Test default_state
308
+ af.allowas_in_set(af.default_allowas_in)
309
+ refute(af.allowas_in,
310
+ "Test 5. #{dbg} Failed to set state to default")
311
+
312
+ # Test true with value set to default
313
+ af.allowas_in_set(true, af.default_allowas_in_max)
314
+ assert_equal(af.default_allowas_in_max, af.allowas_in_max,
315
+ "Test 6. #{dbg} Failed to set True with default Value")
316
+ end
317
+
318
+ # ---------------------------------
319
+ def test_default_originate
320
+ @@matrix.values.each do |af_args|
321
+ af, dbg = clean_af(af_args)
322
+ default_originate(af, dbg)
323
+ end
324
+ end
325
+
326
+ def default_originate(af, dbg)
327
+ # Test basic true
328
+ af.default_originate_set(true)
329
+ assert(af.default_originate,
330
+ "Test 1. #{dbg} Failed to set state to True")
331
+
332
+ # Test true with route-map
333
+ af.default_originate_set(true, 'foo_bar')
334
+ assert_equal('foo_bar', af.default_originate_route_map,
335
+ "Test 2. #{dbg} Failed to set True with Route-map")
336
+
337
+ # Test false with route-map
338
+ af.default_originate_set(false)
339
+ refute(af.default_originate,
340
+ "Test 3. #{dbg} Failed to set state to False")
341
+
342
+ # Test true with route-map, from false
343
+ af.default_originate_set(true, 'baz_inga')
344
+ assert_equal('baz_inga', af.default_originate_route_map,
345
+ "Test 4. #{dbg} Failed to set True with Route-map, " \
346
+ 'from false state')
347
+
348
+ # Test default route-map, from true
349
+ af.default_originate_set(true, af.default_default_originate_route_map)
350
+ refute(af.default_originate_route_map,
351
+ "Test 5. #{dbg} Failed to set default route-map from existing")
352
+
353
+ # Test default_state
354
+ af.default_originate_set(af.default_default_originate)
355
+ refute(af.default_originate,
356
+ "Test 6. #{dbg} Failed to set state to default")
357
+ end
358
+
359
+ # ---------------------------------
360
+ def test_max_prefix
361
+ @@matrix.values.each do |af_args|
362
+ af, dbg = clean_af(af_args)
363
+ max_prefix(af, dbg)
364
+ max_prefix_defaults(af, dbg)
365
+ end
366
+ end
367
+
368
+ def max_prefix(af, dbg)
369
+ limit = 100
370
+ af.max_prefix_set(limit)
371
+ assert_equal(limit, af.max_prefix_limit,
372
+ "Test 1. #{dbg} Failed to set limit to '#{limit}'")
373
+
374
+ limit = 99
375
+ threshold = 49
376
+ af.max_prefix_set(limit, threshold)
377
+ assert_equal(limit, af.max_prefix_limit,
378
+ "Test 2a. #{dbg} Failed to set limit to '#{limit}'")
379
+ assert_equal(threshold, af.max_prefix_threshold,
380
+ "Test 2b. #{dbg} Failed to set threshold to '#{threshold}'")
381
+
382
+ limit = 98
383
+ threshold = 48
384
+ interval = 28
385
+ af.max_prefix_set(limit, threshold, interval)
386
+ assert_equal(limit, af.max_prefix_limit,
387
+ "Test 3a. #{dbg} Failed to set limit to '#{limit}'")
388
+ assert_equal(threshold, af.max_prefix_threshold,
389
+ "Test 3b. #{dbg} Failed to set threshold to '#{threshold}'")
390
+ assert_equal(interval, af.max_prefix_interval,
391
+ "Test 3c. #{dbg} Failed to set interval to '#{interval}'")
392
+
393
+ limit = 97
394
+ threshold = nil
395
+ warning = true
396
+ af.max_prefix_set(limit, threshold, warning)
397
+ assert_equal(limit, af.max_prefix_limit,
398
+ "Test 4a. #{dbg} Failed to set limit to '#{limit}'")
399
+ assert_equal(threshold, af.max_prefix_threshold,
400
+ "Test 4b. #{dbg} Failed to set threshold to '#{threshold}'")
401
+ assert_equal(warning, af.max_prefix_warning,
402
+ "Test 4c. #{dbg} Failed to set warning to '#{warning}'")
403
+
404
+ limit = 96
405
+ threshold = nil
406
+ interval = 26
407
+ af.max_prefix_set(limit, threshold, interval)
408
+ assert_equal(limit, af.max_prefix_limit,
409
+ "Test 5a. #{dbg} Failed to set limit to '#{limit}'")
410
+ assert_equal(threshold, af.max_prefix_threshold,
411
+ "Test 5b. #{dbg} Failed to set threshold to '#{threshold}'")
412
+ assert_equal(interval, af.max_prefix_interval,
413
+ "Test 5c. #{dbg} Failed to set interval to '#{interval}'")
414
+
415
+ limit = 95
416
+ threshold = 45
417
+ warning = true
418
+ af.max_prefix_set(limit, threshold, warning)
419
+ assert_equal(limit, af.max_prefix_limit,
420
+ "Test 6a. #{dbg} Failed to set limit to '#{limit}'")
421
+ assert_equal(threshold, af.max_prefix_threshold,
422
+ "Test 6b. #{dbg} Failed to set threshold to '#{threshold}'")
423
+ assert_equal(warning, af.max_prefix_warning,
424
+ "Test 6c. #{dbg} Failed to set warning to '#{warning}'")
425
+
426
+ af.max_prefix_set(af.default_max_prefix_limit)
427
+ refute(af.max_prefix_limit,
428
+ "Test 7. #{dbg} Failed to remove maximum_prefix")
429
+ end
430
+
431
+ def max_prefix_defaults(af, dbg)
432
+ limit = 94
433
+ threshold = af.default_max_prefix_threshold
434
+ interval = af.default_max_prefix_interval
435
+ af.max_prefix_set(limit, threshold, interval)
436
+ assert_equal(limit, af.max_prefix_limit,
437
+ "Test 8a. #{dbg} Failed to set limit to '#{limit}'")
438
+ assert_equal(threshold, af.max_prefix_threshold,
439
+ "Test 8b. #{dbg} Failed to set threshold to '#{threshold}'")
440
+ assert_equal(interval, af.max_prefix_interval,
441
+ "Test 8c. #{dbg} Failed to set interval to '#{interval}'")
442
+
443
+ limit = 93
444
+ threshold = af.default_max_prefix_threshold
445
+ warning = af.default_max_prefix_warning
446
+ af.max_prefix_set(limit, threshold, warning)
447
+ assert_equal(limit, af.max_prefix_limit,
448
+ "Test 9a. #{dbg} Failed to set limit to '#{limit}'")
449
+ assert_equal(threshold, af.max_prefix_threshold,
450
+ "Test 9b. #{dbg} Failed to set threshold to '#{threshold}'")
451
+ assert_equal(warning, af.max_prefix_warning,
452
+ "Test 9c. #{dbg} Failed to set warning to '#{warning}'")
453
+
454
+ af.max_prefix_set(nil)
455
+ refute(af.max_prefix_limit,
456
+ "Test 10. #{dbg} Failed to remove maximum_prefix")
457
+ end
458
+
459
+ # ---------------------------------
460
+ def test_route_reflector_client
461
+ @@matrix.values.each do |af_args|
462
+ # clean_af needs false since route_reflector_client is ibgp only
463
+ af, dbg = clean_af(af_args, false)
464
+ route_reflector_client(af, dbg)
465
+ end
466
+ end
467
+
468
+ def route_reflector_client(af, dbg)
469
+ # iBGP only
470
+ af.route_reflector_client = false
471
+ refute(af.route_reflector_client,
472
+ "Test 1. #{dbg} Did not set false")
473
+
474
+ af.route_reflector_client = true
475
+ assert(af.route_reflector_client,
476
+ "Test 2. #{dbg} Did not set true")
477
+
478
+ def_val = af.default_route_reflector_client
479
+ af.route_reflector_client = def_val
480
+ assert_equal(def_val, af.route_reflector_client,
481
+ "Test 3. #{dbg} Did not set to default")
482
+ end
483
+
484
+ # ---------------------------------
485
+ def test_send_community
486
+ # iBGP only, do extra cleanup
487
+ config('no feature bgp', 'feature bgp')
488
+ @@matrix.values.each do |af_args|
489
+ af, dbg = clean_af(af_args)
490
+ send_community(af, dbg)
491
+ end
492
+ @@reset_feat = true # rubocop:disable Style/ClassVars
493
+ end
494
+
495
+ def send_community(af, dbg)
496
+ v = 'both'
497
+ af.send_community = v
498
+ assert_equal(v, af.send_community,
499
+ "Test 1a. #{dbg} Failed to set '#{v}' from None")
500
+ af.send_community = v
501
+ assert_equal(v, af.send_community,
502
+ "Test 1b. #{dbg} Failed to set '#{v}' from 'both'")
503
+ v = 'extended'
504
+ af.send_community = v
505
+ assert_equal(v, af.send_community,
506
+ "Test 2a. #{dbg} Failed to set '#{v}' from 'both'")
507
+ af.send_community = v
508
+ assert_equal(v, af.send_community,
509
+ "Test 2b. #{dbg} Failed to set '#{v}' from 'extended'")
510
+ v = 'standard'
511
+ af.send_community = v
512
+ assert_equal(v, af.send_community,
513
+ "Test 3a. #{dbg} Failed to set '#{v}' from 'extended'")
514
+ af.send_community = v
515
+ assert_equal(v, af.send_community,
516
+ "Test 3b. #{dbg} Failed to set '#{v}' from 'standard'")
517
+
518
+ v = 'extended'
519
+ af.send_community = v
520
+ assert_equal(v, af.send_community,
521
+ "Test 4. #{dbg} Failed to set '#{v}' from 'standard'")
522
+
523
+ v = 'both'
524
+ af.send_community = v
525
+ assert_equal(v, af.send_community,
526
+ "Test 5. #{dbg} Failed to set '#{v}' from 'extended'")
527
+
528
+ v = 'standard'
529
+ af.send_community = v
530
+ assert_equal(v, af.send_community,
531
+ "Test 6. #{dbg} Failed to set '#{v}' from 'both'")
532
+ v = 'both'
533
+ af.send_community = v
534
+ assert_equal(v, af.send_community,
535
+ "Test 7. #{dbg} Failed to set '#{v}' from 'standard'")
536
+
537
+ v = 'none'
538
+ af.send_community = v
539
+ assert_equal(v, af.send_community,
540
+ "Test 8. #{dbg} Failed to remove send-community")
541
+
542
+ v = 'both'
543
+ af.send_community = v
544
+ assert_equal(v, af.send_community,
545
+ "Test 9. #{dbg} Failed to set '#{v}' from None")
546
+
547
+ v = af.default_send_community
548
+ af.send_community = af.default_send_community
549
+ assert_equal(v, af.send_community,
550
+ "Test 10. #{dbg} Failed to set state to default")
551
+ end
552
+
553
+ # ---------------------------------
554
+ def test_soo
555
+ @@matrix.values.each do |af_args|
556
+ af, dbg = clean_af(af_args)
557
+ soo(af, dbg)
558
+ end
559
+ end
560
+
561
+ def soo(af, dbg)
562
+ val = '1.1.1.1:1'
563
+
564
+ if dbg.include?('default')
565
+ assert_raises(CliError, "Test 1. #{dbg}[soo=] did not raise CliError") do
566
+ af.soo = val
567
+ end
568
+ # SOO is only allowed in non-default VRF
569
+ return
570
+ end
571
+
572
+ # Set initial
573
+ af.soo = val
574
+ assert_equal(val, af.soo,
575
+ "Test 2. #{dbg} Failed to set '#{val}'")
576
+
577
+ # Change to new string
578
+ val = '2:2'
579
+ af.soo = val
580
+ assert_equal(val, af.soo,
581
+ "Test 3. #{dbg} Failed to change to '#{val}'")
582
+
583
+ # Set to default
584
+ val = af.default_soo
585
+ af.soo = val
586
+ assert_empty(af.soo,
587
+ "Test 4. #{dbg} Failed to set default '#{val}'")
588
+ end
589
+ end