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.
- checksums.yaml +7 -0
- data/.gitignore +4 -0
- data/.rubocop.yml +81 -1
- data/.travis.yml +9 -0
- data/CHANGELOG.md +72 -6
- data/CONTRIBUTING.md +32 -7
- data/README.md +70 -7
- data/Rakefile +17 -0
- data/bin/check_metric_limits.rb +109 -0
- data/bin/git/hooks/commit-msg/enforce_style +81 -0
- data/bin/git/hooks/hook_lib +108 -0
- data/bin/git/hooks/hooks-wrapper +38 -0
- data/bin/git/hooks/post-flow-hotfix-start/update-version +24 -0
- data/bin/git/hooks/post-flow-release-finish/update-version +29 -0
- data/bin/git/hooks/post-flow-release-start/update-version +19 -0
- data/bin/git/hooks/post-merge/update-hooks +6 -0
- data/bin/git/hooks/post-rewrite/update-hooks +6 -0
- data/bin/git/hooks/pre-commit/rubocop +20 -0
- data/bin/git/hooks/pre-commit/validate-diffs +31 -0
- data/bin/git/hooks/pre-push/check-changelog +24 -0
- data/bin/git/hooks/pre-push/rubocop +7 -0
- data/bin/git/update-hooks +65 -0
- data/cisco_node_utils.gemspec +9 -3
- data/docs/README-develop-best-practices.md +404 -0
- data/docs/README-develop-node-utils-APIs.md +215 -365
- data/docs/README-maintainers.md +33 -3
- data/docs/template-router.rb +89 -91
- data/docs/template-test_router.rb +52 -55
- data/lib/.rubocop.yml +18 -0
- data/lib/cisco_node_utils.rb +2 -19
- data/lib/cisco_node_utils/README_YAML.md +1 -9
- data/lib/cisco_node_utils/bgp.rb +664 -0
- data/lib/cisco_node_utils/bgp_af.rb +530 -0
- data/lib/cisco_node_utils/bgp_neighbor.rb +425 -0
- data/lib/cisco_node_utils/bgp_neighbor_af.rb +709 -0
- data/lib/cisco_node_utils/cisco_cmn_utils.rb +59 -25
- data/lib/cisco_node_utils/command_reference.rb +72 -74
- data/lib/cisco_node_utils/command_reference_common.yaml +174 -9
- data/lib/cisco_node_utils/command_reference_common_bgp.yaml +535 -0
- data/lib/cisco_node_utils/command_reference_n7k.yaml +4 -0
- data/lib/cisco_node_utils/command_reference_n9k.yaml +0 -9
- data/lib/cisco_node_utils/configparser_lib.rb +152 -147
- data/lib/cisco_node_utils/dns_domain.rb +79 -0
- data/lib/cisco_node_utils/domain_name.rb +71 -0
- data/lib/cisco_node_utils/interface.rb +167 -161
- data/lib/cisco_node_utils/interface_ospf.rb +78 -81
- data/lib/cisco_node_utils/name_server.rb +64 -0
- data/lib/cisco_node_utils/node.rb +154 -198
- data/lib/cisco_node_utils/node_util.rb +61 -0
- data/lib/cisco_node_utils/ntp_config.rb +65 -0
- data/lib/cisco_node_utils/ntp_server.rb +76 -0
- data/lib/cisco_node_utils/platform.rb +174 -165
- data/lib/cisco_node_utils/radius_global.rb +146 -0
- data/lib/cisco_node_utils/radius_server.rb +295 -0
- data/lib/cisco_node_utils/router_ospf.rb +59 -63
- data/lib/cisco_node_utils/router_ospf_vrf.rb +226 -210
- data/lib/cisco_node_utils/snmpcommunity.rb +52 -58
- data/lib/cisco_node_utils/snmpgroup.rb +22 -23
- data/lib/cisco_node_utils/snmpserver.rb +99 -103
- data/lib/cisco_node_utils/snmpuser.rb +294 -274
- data/lib/cisco_node_utils/syslog_server.rb +92 -0
- data/lib/cisco_node_utils/syslog_settings.rb +69 -0
- data/lib/cisco_node_utils/tacacs_server.rb +137 -133
- data/lib/cisco_node_utils/tacacs_server_host.rb +84 -87
- data/lib/cisco_node_utils/version.rb +2 -1
- data/lib/cisco_node_utils/vlan.rb +28 -31
- data/lib/cisco_node_utils/vrf.rb +80 -0
- data/lib/cisco_node_utils/vtp.rb +100 -97
- data/lib/cisco_node_utils/yum.rb +15 -17
- data/tests/.rubocop.yml +15 -0
- data/tests/basetest.rb +81 -36
- data/tests/ciscotest.rb +38 -78
- data/{lib/cisco_node_utils → tests}/platform_info.rb +12 -8
- data/{lib/cisco_node_utils → tests}/platform_info.yaml +1 -1
- data/tests/test_bgp_af.rb +920 -0
- data/tests/test_bgp_neighbor.rb +403 -0
- data/tests/test_bgp_neighbor_af.rb +589 -0
- data/tests/test_command_config.rb +65 -62
- data/tests/test_command_reference.rb +31 -45
- data/tests/test_dns_domain.rb +113 -0
- data/tests/test_domain_name.rb +86 -0
- data/tests/test_interface.rb +424 -548
- data/tests/test_interface_ospf.rb +248 -432
- data/tests/test_interface_svi.rb +56 -79
- data/tests/test_interface_switchport.rb +196 -272
- data/tests/test_name_server.rb +85 -0
- data/tests/test_node.rb +7 -6
- data/tests/test_node_ext.rb +133 -186
- data/tests/test_ntp_config.rb +49 -0
- data/tests/test_ntp_server.rb +74 -0
- data/tests/test_platform.rb +58 -37
- data/tests/test_radius_global.rb +78 -0
- data/tests/test_radius_server.rb +185 -0
- data/tests/test_router_bgp.rb +838 -0
- data/tests/test_router_ospf.rb +49 -80
- data/tests/test_router_ospf_vrf.rb +274 -392
- data/tests/test_snmpcommunity.rb +128 -172
- data/tests/test_snmpgroup.rb +12 -14
- data/tests/test_snmpserver.rb +160 -189
- data/tests/test_snmpuser.rb +568 -717
- data/tests/test_syslog_server.rb +88 -0
- data/tests/test_syslog_settings.rb +54 -0
- data/tests/test_tacacs_server.rb +113 -148
- data/tests/test_tacacs_server_host.rb +108 -161
- data/tests/test_vlan.rb +63 -79
- data/tests/test_vrf.rb +92 -0
- data/tests/test_vtp.rb +108 -126
- data/tests/test_yum.rb +47 -41
- metadata +92 -56
- data/.rubocop_todo.yml +0 -293
- data/docs/.rubocop.yml +0 -13
- data/docs/template-feature.rb +0 -45
- data/docs/template-test_feature.rb +0 -51
- data/tests/test_all_cisco.rb +0 -46
|
@@ -0,0 +1,920 @@
|
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
|
+
# -*- coding: utf-8 -*-
|
|
3
|
+
# RouterBgpAF Unit Tests
|
|
4
|
+
#
|
|
5
|
+
# Richard Wellum, August, 2015
|
|
6
|
+
#
|
|
7
|
+
# Copyright (c) 2015 Cisco and/or its affiliates.
|
|
8
|
+
#
|
|
9
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
10
|
+
# you may not use this file except in compliance with the License.
|
|
11
|
+
# You may obtain a copy of the License at
|
|
12
|
+
#
|
|
13
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
14
|
+
#
|
|
15
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
16
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
17
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
18
|
+
# See the License for the specific language governing permissions and
|
|
19
|
+
# limitations under the License.
|
|
20
|
+
|
|
21
|
+
require_relative 'ciscotest'
|
|
22
|
+
require_relative '../lib/cisco_node_utils/bgp'
|
|
23
|
+
require_relative '../lib/cisco_node_utils/bgp_af'
|
|
24
|
+
|
|
25
|
+
# TestRouterBgpAF - Minitest for RouterBgpAF class
|
|
26
|
+
class TestRouterBgpAF < CiscoTestCase
|
|
27
|
+
def setup
|
|
28
|
+
super
|
|
29
|
+
# Disable and enable feature bgp before each test to ensure we
|
|
30
|
+
# are starting with a clean slate for each test.
|
|
31
|
+
config('no feature bgp', 'feature bgp')
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def get_bgp_af_cfg(asn, vrf, af)
|
|
35
|
+
afi, safi = af
|
|
36
|
+
string =
|
|
37
|
+
@device.cmd("show run bgp all | sec 'bgp #{asn}' | sec 'vrf #{vrf}' | " \
|
|
38
|
+
"sec 'address-family #{afi} #{safi}' | no-more")
|
|
39
|
+
string
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
# show bgp ipv4 unicast dampening parameters
|
|
43
|
+
# Route Flap Dampening Parameters for VRF default Address family IPv4 Unicast:
|
|
44
|
+
# Default values in use:
|
|
45
|
+
# Half-life time : 15 mins
|
|
46
|
+
# Suppress penalty : 2000
|
|
47
|
+
# Reuse penalty : 750
|
|
48
|
+
# Max suppress time : 45 mins
|
|
49
|
+
# Max suppress penalty : 6000
|
|
50
|
+
def get_bgp_af_dampening_params(_asn, vrf, af)
|
|
51
|
+
afi = af.first
|
|
52
|
+
safi = af.last
|
|
53
|
+
@device.cmd("show bgp vrf #{vrf} #{afi} #{safi} dampening parameters")
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
##
|
|
57
|
+
## BGP Address Family
|
|
58
|
+
## Validate that RouterBgp.afs is empty when bgp is not enabled
|
|
59
|
+
##
|
|
60
|
+
def test_collection_empty
|
|
61
|
+
node.cache_flush
|
|
62
|
+
afs = RouterBgpAF.afs
|
|
63
|
+
assert_empty(afs, 'BGP address-family collection is not empty')
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
##
|
|
67
|
+
## BGP Address Family
|
|
68
|
+
## Configure router bgp, some VRF's and address-family statements
|
|
69
|
+
## - verify that the final instance objects are correctly populated
|
|
70
|
+
##
|
|
71
|
+
def test_collection_not_empty
|
|
72
|
+
config('feature bgp',
|
|
73
|
+
'router bgp 55',
|
|
74
|
+
'address-family ipv4 unicast',
|
|
75
|
+
'vrf red',
|
|
76
|
+
'address-family ipv4 unicast',
|
|
77
|
+
'vrf blue',
|
|
78
|
+
'address-family ipv6 multicast',
|
|
79
|
+
'vrf orange',
|
|
80
|
+
'address-family ipv4 multicast',
|
|
81
|
+
'vrf black',
|
|
82
|
+
'address-family ipv6 unicast')
|
|
83
|
+
|
|
84
|
+
# Construct a hash of routers, vrfs, afs
|
|
85
|
+
routers = RouterBgpAF.afs
|
|
86
|
+
refute_empty(routers, 'Error: BGP address_family collection is empty')
|
|
87
|
+
|
|
88
|
+
# Validate the collection
|
|
89
|
+
routers.each do |asn, vrfs|
|
|
90
|
+
assert((asn.kind_of? Fixnum),
|
|
91
|
+
'Error: Autonomous number must be a fixed number')
|
|
92
|
+
refute_empty(vrfs, 'Error: Collection is empty')
|
|
93
|
+
|
|
94
|
+
vrfs.each do |vrf, afs|
|
|
95
|
+
refute_empty(afs, 'Error: No Address Family found')
|
|
96
|
+
assert(vrf.length > 0, 'Error: No VRF found')
|
|
97
|
+
afs.each_key do |af_key|
|
|
98
|
+
afi = af_key[0]
|
|
99
|
+
safi = af_key[1]
|
|
100
|
+
assert(afi.length > 0, 'Error: AFI length is zero')
|
|
101
|
+
assert_match(/^ipv[46]/, afi, 'Error: AFI must be ipv4 or ipv6')
|
|
102
|
+
assert(safi.length > 0, 'Error: SAFI length is zero')
|
|
103
|
+
end
|
|
104
|
+
end
|
|
105
|
+
end
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
########################################################
|
|
109
|
+
# PROPERTIES #
|
|
110
|
+
########################################################
|
|
111
|
+
|
|
112
|
+
##
|
|
113
|
+
## default-information originate
|
|
114
|
+
##
|
|
115
|
+
def test_default_information_originate
|
|
116
|
+
asn = '55'
|
|
117
|
+
vrf = 'red'
|
|
118
|
+
af = %w(ipv4 unicast)
|
|
119
|
+
|
|
120
|
+
#
|
|
121
|
+
# Set and verify
|
|
122
|
+
#
|
|
123
|
+
bgp_af = RouterBgpAF.new(asn, vrf, af)
|
|
124
|
+
bgp_af.default_information_originate = true
|
|
125
|
+
assert(bgp_af.default_information_originate,
|
|
126
|
+
'Error: default-information originate not set')
|
|
127
|
+
|
|
128
|
+
pattern = /^ *default-information originate$/
|
|
129
|
+
af_string = get_bgp_af_cfg(asn, vrf, af)
|
|
130
|
+
|
|
131
|
+
assert_match(pattern, af_string,
|
|
132
|
+
"Error: 'default_information originate' is not" \
|
|
133
|
+
' configured and should be')
|
|
134
|
+
|
|
135
|
+
#
|
|
136
|
+
# Unset and verify
|
|
137
|
+
#
|
|
138
|
+
|
|
139
|
+
# Do a 'no default-information originate'
|
|
140
|
+
bgp_af.default_information_originate = false
|
|
141
|
+
|
|
142
|
+
pattern = /^ *default-information originate$/
|
|
143
|
+
af_string = get_bgp_af_cfg(asn, vrf, af)
|
|
144
|
+
|
|
145
|
+
refute_match(pattern, af_string,
|
|
146
|
+
"Error: 'default_information originate' " \
|
|
147
|
+
'is configured and should not be')
|
|
148
|
+
end
|
|
149
|
+
|
|
150
|
+
##
|
|
151
|
+
## client-to-client reflection
|
|
152
|
+
##
|
|
153
|
+
def test_client_to_client
|
|
154
|
+
asn = '55'
|
|
155
|
+
vrf = 'red'
|
|
156
|
+
af = %w(ipv4 unicast)
|
|
157
|
+
|
|
158
|
+
bgp_af = RouterBgpAF.new(asn, vrf, af)
|
|
159
|
+
pattern = /^ *client-to-client reflection$/
|
|
160
|
+
#
|
|
161
|
+
# Default is 'client-to-client' is configured
|
|
162
|
+
#
|
|
163
|
+
af_string = get_bgp_af_cfg(asn, vrf, af)
|
|
164
|
+
|
|
165
|
+
assert_match(pattern, af_string,
|
|
166
|
+
"Error: 'client-to-client reflection' is not configured " \
|
|
167
|
+
'and should be')
|
|
168
|
+
|
|
169
|
+
assert(bgp_af.client_to_client,
|
|
170
|
+
"Error: 'client-to-client is not configured but should be")
|
|
171
|
+
#
|
|
172
|
+
# Unset and verify
|
|
173
|
+
#
|
|
174
|
+
|
|
175
|
+
# Do a 'no client-to-client reflection'
|
|
176
|
+
bgp_af.client_to_client = false
|
|
177
|
+
pattern = /^ *no client-to-client reflection$/
|
|
178
|
+
af_string = get_bgp_af_cfg(asn, vrf, af)
|
|
179
|
+
|
|
180
|
+
assert_match(pattern, af_string,
|
|
181
|
+
"Error: 'no client-to-client' is not configured and should be")
|
|
182
|
+
|
|
183
|
+
#
|
|
184
|
+
# Set and verify
|
|
185
|
+
#
|
|
186
|
+
|
|
187
|
+
# Do a 'client-to-client reflection'
|
|
188
|
+
bgp_af.client_to_client = true
|
|
189
|
+
af_string = get_bgp_af_cfg(asn, vrf, af)
|
|
190
|
+
|
|
191
|
+
refute_match(pattern, af_string,
|
|
192
|
+
"Error: 'no client-to-client' is configured and should not be")
|
|
193
|
+
end
|
|
194
|
+
|
|
195
|
+
##
|
|
196
|
+
## next_hop route-map
|
|
197
|
+
##
|
|
198
|
+
def test_next_hop_route_map
|
|
199
|
+
asn = '55'
|
|
200
|
+
vrf = 'red'
|
|
201
|
+
af = %w(ipv4 unicast)
|
|
202
|
+
|
|
203
|
+
#
|
|
204
|
+
# Set and verify
|
|
205
|
+
#
|
|
206
|
+
bgp_af = RouterBgpAF.new(asn, vrf, af)
|
|
207
|
+
bgp_af.next_hop_route_map = 'drop_all'
|
|
208
|
+
assert_match(bgp_af.next_hop_route_map, 'drop_all',
|
|
209
|
+
'Error: nexthop route-map not set')
|
|
210
|
+
pattern = /^ *nexthop route-map drop_all$/
|
|
211
|
+
af_string = get_bgp_af_cfg(asn, vrf, af)
|
|
212
|
+
|
|
213
|
+
assert_match(pattern, af_string,
|
|
214
|
+
"Error: 'nexthop route-map drop_all' is " \
|
|
215
|
+
'not configured and should be')
|
|
216
|
+
|
|
217
|
+
#
|
|
218
|
+
# Unset and verify
|
|
219
|
+
#
|
|
220
|
+
|
|
221
|
+
# Do a 'no nexthop route-map drop_all'
|
|
222
|
+
bgp_af.next_hop_route_map = bgp_af.default_next_hop_route_map
|
|
223
|
+
af_string = get_bgp_af_cfg(asn, vrf, af)
|
|
224
|
+
|
|
225
|
+
refute_match(pattern, af_string,
|
|
226
|
+
"Error: 'nexthop route-map drop_all' is " \
|
|
227
|
+
'configured and should not be')
|
|
228
|
+
end
|
|
229
|
+
|
|
230
|
+
##
|
|
231
|
+
## additional_paths
|
|
232
|
+
##
|
|
233
|
+
def test_additional_paths
|
|
234
|
+
asn = '55'
|
|
235
|
+
vrf = 'red'
|
|
236
|
+
af = %w(ipv4 unicast)
|
|
237
|
+
|
|
238
|
+
bgp_af = RouterBgpAF.new(asn, vrf, af)
|
|
239
|
+
|
|
240
|
+
pattern_send = 'additional-paths send'
|
|
241
|
+
pattern_receive = 'additional-paths receive'
|
|
242
|
+
pattern_install = 'additional-paths install backup'
|
|
243
|
+
|
|
244
|
+
#
|
|
245
|
+
# Default is not configured
|
|
246
|
+
#
|
|
247
|
+
af_string = get_bgp_af_cfg(asn, vrf, af)
|
|
248
|
+
|
|
249
|
+
[pattern_send, pattern_receive, pattern_install].each do |pat|
|
|
250
|
+
refute_match(pat, af_string,
|
|
251
|
+
"Error: '#{pat}' is configured but should not be")
|
|
252
|
+
end
|
|
253
|
+
|
|
254
|
+
#
|
|
255
|
+
# Test default and getter methods
|
|
256
|
+
#
|
|
257
|
+
assert_equal(bgp_af.default_additional_paths_send,
|
|
258
|
+
bgp_af.additional_paths_send)
|
|
259
|
+
assert_equal(bgp_af.default_additional_paths_receive,
|
|
260
|
+
bgp_af.additional_paths_receive)
|
|
261
|
+
assert_equal(bgp_af.default_additional_paths_install,
|
|
262
|
+
bgp_af.additional_paths_install)
|
|
263
|
+
|
|
264
|
+
#
|
|
265
|
+
# Set and verify
|
|
266
|
+
#
|
|
267
|
+
|
|
268
|
+
# Do a 'additional-paths send, receive, install'
|
|
269
|
+
bgp_af.additional_paths_send = true
|
|
270
|
+
bgp_af.additional_paths_receive = true
|
|
271
|
+
bgp_af.additional_paths_install = true
|
|
272
|
+
|
|
273
|
+
af_string = get_bgp_af_cfg(asn, vrf, af)
|
|
274
|
+
|
|
275
|
+
[pattern_send, pattern_receive, pattern_install].each do |pat|
|
|
276
|
+
assert_match(pat, af_string,
|
|
277
|
+
"Error: '#{pat}' is not configured and should be")
|
|
278
|
+
end
|
|
279
|
+
|
|
280
|
+
#
|
|
281
|
+
# Test getter
|
|
282
|
+
#
|
|
283
|
+
|
|
284
|
+
assert(bgp_af.additional_paths_send)
|
|
285
|
+
assert(bgp_af.additional_paths_receive)
|
|
286
|
+
assert(bgp_af.additional_paths_install)
|
|
287
|
+
|
|
288
|
+
#
|
|
289
|
+
# Unset and verify
|
|
290
|
+
#
|
|
291
|
+
|
|
292
|
+
# Do a 'no additional-paths send, receive, install'
|
|
293
|
+
bgp_af.additional_paths_send = false
|
|
294
|
+
bgp_af.additional_paths_receive = false
|
|
295
|
+
bgp_af.additional_paths_install = false
|
|
296
|
+
|
|
297
|
+
af_string = get_bgp_af_cfg(asn, vrf, af)
|
|
298
|
+
|
|
299
|
+
[pattern_send, pattern_receive, pattern_install].each do |pat|
|
|
300
|
+
refute_match(pat, af_string,
|
|
301
|
+
"Error: '#{pat}' is configured but should not be")
|
|
302
|
+
end
|
|
303
|
+
end
|
|
304
|
+
|
|
305
|
+
##
|
|
306
|
+
## additional_paths_selection route-map
|
|
307
|
+
##
|
|
308
|
+
def test_additional_paths_selection
|
|
309
|
+
asn = '55'
|
|
310
|
+
vrf = 'red'
|
|
311
|
+
af = %w(ipv4 unicast)
|
|
312
|
+
|
|
313
|
+
#
|
|
314
|
+
# Set and verify
|
|
315
|
+
#
|
|
316
|
+
bgp_af = RouterBgpAF.new(asn, vrf, af)
|
|
317
|
+
bgp_af.additional_paths_selection = 'drop_all'
|
|
318
|
+
|
|
319
|
+
assert_equal(bgp_af.additional_paths_selection, 'drop_all',
|
|
320
|
+
'Error: additional-paths selection route-map not set')
|
|
321
|
+
|
|
322
|
+
af_string = get_bgp_af_cfg(asn, vrf, af)
|
|
323
|
+
pattern = /^ *additional-paths selection route-map drop_all$/
|
|
324
|
+
|
|
325
|
+
assert_match(pattern, af_string,
|
|
326
|
+
"Error: 'additional-paths selection route-map drop_all' is " \
|
|
327
|
+
'not configured and should be')
|
|
328
|
+
|
|
329
|
+
#
|
|
330
|
+
# Test getter
|
|
331
|
+
#
|
|
332
|
+
pattern = /^ *drop_all$/
|
|
333
|
+
assert_match(pattern, bgp_af.additional_paths_selection,
|
|
334
|
+
"Error: 'route-map drop_all' is not configured and should be")
|
|
335
|
+
|
|
336
|
+
#
|
|
337
|
+
# Unset and verify
|
|
338
|
+
#
|
|
339
|
+
|
|
340
|
+
# Do a 'no additional-paths selection route-map drop_all'
|
|
341
|
+
bgp_af.additional_paths_selection =
|
|
342
|
+
bgp_af.default_additional_paths_selection
|
|
343
|
+
|
|
344
|
+
af_string = get_bgp_af_cfg(asn, vrf, af)
|
|
345
|
+
|
|
346
|
+
refute_match(pattern, af_string,
|
|
347
|
+
"Error: 'additional-paths selection route-map drop_all' is " \
|
|
348
|
+
'configured and should not be')
|
|
349
|
+
end
|
|
350
|
+
|
|
351
|
+
##
|
|
352
|
+
## get_dampen_igp_metric
|
|
353
|
+
##
|
|
354
|
+
def test_dampen_igp_metric
|
|
355
|
+
asn = '44'
|
|
356
|
+
vrf = 'green'
|
|
357
|
+
af = %w(ipv4 multicast)
|
|
358
|
+
|
|
359
|
+
bgp_af = RouterBgpAF.new(asn, vrf, af)
|
|
360
|
+
|
|
361
|
+
#
|
|
362
|
+
# Verify default value
|
|
363
|
+
#
|
|
364
|
+
assert_equal(bgp_af.dampen_igp_metric, bgp_af.default_dampen_igp_metric,
|
|
365
|
+
"Error: Default 'dampen-igp-metric' value should be " \
|
|
366
|
+
"#{bgp_af.default_dampen_igp_metric}")
|
|
367
|
+
|
|
368
|
+
#
|
|
369
|
+
# Set and verify 'dampen-igp-metric <value>'
|
|
370
|
+
#
|
|
371
|
+
|
|
372
|
+
# Do a 'dampen-igp-metric 555'
|
|
373
|
+
pattern = /^ *dampen-igp-metric 555$/
|
|
374
|
+
bgp_af.dampen_igp_metric = 555
|
|
375
|
+
|
|
376
|
+
af_string = get_bgp_af_cfg(asn, vrf, af)
|
|
377
|
+
|
|
378
|
+
assert_match(pattern, af_string,
|
|
379
|
+
"Error: 'dampen-igp-metric 555' is not configured " \
|
|
380
|
+
'and should be')
|
|
381
|
+
#
|
|
382
|
+
# Test getter
|
|
383
|
+
#
|
|
384
|
+
assert_equal(bgp_af.dampen_igp_metric, 555,
|
|
385
|
+
'Error: dampen_igp_metric should be 555')
|
|
386
|
+
|
|
387
|
+
#
|
|
388
|
+
# Set and verify 'no dampen-igp-metric'
|
|
389
|
+
#
|
|
390
|
+
|
|
391
|
+
# Do a 'no dampen-igp-metric'
|
|
392
|
+
pattern = /no dampen-igp-metric$/
|
|
393
|
+
bgp_af.dampen_igp_metric = nil
|
|
394
|
+
|
|
395
|
+
af_string = get_bgp_af_cfg(asn, vrf, af)
|
|
396
|
+
|
|
397
|
+
assert_match(pattern, af_string,
|
|
398
|
+
"Error: 'no dampen-igp-metric' is not configured " \
|
|
399
|
+
'and should be')
|
|
400
|
+
#
|
|
401
|
+
# Test getter
|
|
402
|
+
#
|
|
403
|
+
assert_equal(bgp_af.dampen_igp_metric, nil,
|
|
404
|
+
'Error: dampen_igp_metric should be nil')
|
|
405
|
+
|
|
406
|
+
#
|
|
407
|
+
# Set default value explicitly
|
|
408
|
+
#
|
|
409
|
+
bgp_af.dampen_igp_metric = bgp_af.default_dampen_igp_metric
|
|
410
|
+
assert_equal(bgp_af.dampen_igp_metric, bgp_af.default_dampen_igp_metric,
|
|
411
|
+
"Error: Default 'dampen-igp-metric' value should be " \
|
|
412
|
+
"#{bgp_af.default_dampen_igp_metric}")
|
|
413
|
+
end
|
|
414
|
+
|
|
415
|
+
##
|
|
416
|
+
## dampening
|
|
417
|
+
##
|
|
418
|
+
# rubocop:disable Metrics/MethodLength
|
|
419
|
+
def test_dampening
|
|
420
|
+
asn = '101'
|
|
421
|
+
|
|
422
|
+
############################################
|
|
423
|
+
# Set and verify 'dampening' with defaults #
|
|
424
|
+
############################################
|
|
425
|
+
vrf = 'orange'
|
|
426
|
+
af = %w(ipv4 unicast)
|
|
427
|
+
bgp_af = RouterBgpAF.new(asn, vrf, af)
|
|
428
|
+
|
|
429
|
+
# Test no dampening configured
|
|
430
|
+
assert_nil(bgp_af.dampening)
|
|
431
|
+
|
|
432
|
+
pattern = /^ *dampening$/
|
|
433
|
+
|
|
434
|
+
bgp_af.dampening = []
|
|
435
|
+
|
|
436
|
+
# Check property got set
|
|
437
|
+
af_string = get_bgp_af_cfg(asn, vrf, af)
|
|
438
|
+
|
|
439
|
+
assert_match(pattern, af_string,
|
|
440
|
+
"Error: 'dampening' is not configured and should be")
|
|
441
|
+
|
|
442
|
+
# Check properties got set
|
|
443
|
+
af_string = get_bgp_af_dampening_params(asn, vrf, af)
|
|
444
|
+
|
|
445
|
+
pattern_params1 = 'Half-life time : 15 mins'
|
|
446
|
+
pattern_params2 = 'Suppress penalty : 2000'
|
|
447
|
+
pattern_params3 = 'Reuse penalty : 750'
|
|
448
|
+
pattern_params4 = 'Max suppress time : 45 mins'
|
|
449
|
+
pattern_params5 = 'Max suppress penalty : 6000'
|
|
450
|
+
|
|
451
|
+
error = ("Error: 'dampening' properties are incorrect")
|
|
452
|
+
|
|
453
|
+
assert_match(pattern_params1, af_string, error)
|
|
454
|
+
assert_match(pattern_params2, af_string, error)
|
|
455
|
+
assert_match(pattern_params3, af_string, error)
|
|
456
|
+
assert_match(pattern_params4, af_string, error)
|
|
457
|
+
assert_match(pattern_params5, af_string, error)
|
|
458
|
+
|
|
459
|
+
# Check getter
|
|
460
|
+
assert_empty(bgp_af.dampening, 'Error: dampening is configured and ' \
|
|
461
|
+
'should not be')
|
|
462
|
+
|
|
463
|
+
#
|
|
464
|
+
# Unset and verify
|
|
465
|
+
#
|
|
466
|
+
bgp_af.dampening = nil
|
|
467
|
+
|
|
468
|
+
af_string = get_bgp_af_cfg(asn, vrf, af)
|
|
469
|
+
pattern = /^ *dampening$/
|
|
470
|
+
|
|
471
|
+
refute_match(pattern, af_string, "Error: 'dampening' is still configured")
|
|
472
|
+
|
|
473
|
+
#
|
|
474
|
+
# Test Getters
|
|
475
|
+
#
|
|
476
|
+
assert_nil(bgp_af.dampening)
|
|
477
|
+
assert_nil(bgp_af.dampening_half_time)
|
|
478
|
+
assert_nil(bgp_af.dampening_reuse_time)
|
|
479
|
+
assert_nil(bgp_af.dampening_suppress_time)
|
|
480
|
+
assert_nil(bgp_af.dampening_max_suppress_time)
|
|
481
|
+
assert_nil(bgp_af.dampening_routemap)
|
|
482
|
+
|
|
483
|
+
bgp_af.destroy
|
|
484
|
+
|
|
485
|
+
#############################################
|
|
486
|
+
# Set and verify 'dampening' with overrides #
|
|
487
|
+
#############################################
|
|
488
|
+
vrf = 'green'
|
|
489
|
+
af = %w(ipv4 multicast)
|
|
490
|
+
bgp_af = RouterBgpAF.new(asn, vrf, af)
|
|
491
|
+
|
|
492
|
+
bgp_af.dampening = %w(1 2 3 4)
|
|
493
|
+
|
|
494
|
+
# Check property got set
|
|
495
|
+
af_string = get_bgp_af_cfg(asn, vrf, af)
|
|
496
|
+
pattern = /^ *dampening 1 2 3 4$/
|
|
497
|
+
|
|
498
|
+
assert_match(pattern, af_string,
|
|
499
|
+
"Error: 'dampening' is not configured and should be")
|
|
500
|
+
|
|
501
|
+
# Check properties got set
|
|
502
|
+
af_string = get_bgp_af_dampening_params(asn, vrf, af)
|
|
503
|
+
|
|
504
|
+
pattern_params1 = 'Half-life time : 1 mins'
|
|
505
|
+
pattern_params2 = 'Suppress penalty : 3'
|
|
506
|
+
pattern_params3 = 'Reuse penalty : 2'
|
|
507
|
+
pattern_params4 = 'Max suppress time : 4 mins'
|
|
508
|
+
pattern_params5 = 'Max suppress penalty : 32'
|
|
509
|
+
|
|
510
|
+
error = ("Error: 'dampening' properties are incorrect")
|
|
511
|
+
|
|
512
|
+
assert_match(pattern_params1, af_string, error)
|
|
513
|
+
assert_match(pattern_params2, af_string, error)
|
|
514
|
+
assert_match(pattern_params3, af_string, error)
|
|
515
|
+
assert_match(pattern_params4, af_string, error)
|
|
516
|
+
assert_match(pattern_params5, af_string, error)
|
|
517
|
+
|
|
518
|
+
# Check getters
|
|
519
|
+
assert_equal(bgp_af.dampening, %w(1 2 3 4),
|
|
520
|
+
'Error: dampening getter did not match')
|
|
521
|
+
assert_equal(1, bgp_af.dampening_half_time,
|
|
522
|
+
'The wrong dampening half_time value is configured')
|
|
523
|
+
assert_equal(2, bgp_af.dampening_reuse_time,
|
|
524
|
+
'The wrong dampening reuse_time value is configured')
|
|
525
|
+
assert_equal(3, bgp_af.dampening_suppress_time,
|
|
526
|
+
'The wrong dampening suppress_time value is configured')
|
|
527
|
+
assert_equal(4, bgp_af.dampening_max_suppress_time,
|
|
528
|
+
'The wrong dampening max_suppress_time value is configured')
|
|
529
|
+
assert_empty(bgp_af.dampening_routemap,
|
|
530
|
+
'A routemap should not be configured')
|
|
531
|
+
|
|
532
|
+
#
|
|
533
|
+
# Unset and verify
|
|
534
|
+
#
|
|
535
|
+
bgp_af.dampening = nil
|
|
536
|
+
|
|
537
|
+
af_string = get_bgp_af_cfg(asn, vrf, af)
|
|
538
|
+
pattern = /^ *dampening$/
|
|
539
|
+
|
|
540
|
+
refute_match(pattern, af_string, "Error: 'dampening' is still configured")
|
|
541
|
+
|
|
542
|
+
#############################################
|
|
543
|
+
# Set and verify 'dampening' with route-map #
|
|
544
|
+
#############################################
|
|
545
|
+
vrf = 'brown'
|
|
546
|
+
af = %w(ipv6 unicast)
|
|
547
|
+
bgp_af = RouterBgpAF.new(asn, vrf, af)
|
|
548
|
+
|
|
549
|
+
bgp_af.dampening = 'DropAllTraffic'
|
|
550
|
+
|
|
551
|
+
pattern = /^ *dampening route-map DropAllTraffic$/
|
|
552
|
+
|
|
553
|
+
# Check property got set
|
|
554
|
+
af_string = get_bgp_af_cfg(asn, vrf, af)
|
|
555
|
+
|
|
556
|
+
assert_match(pattern, af_string,
|
|
557
|
+
"Error: 'dampening' is not configured and should be")
|
|
558
|
+
|
|
559
|
+
# Check properties got set
|
|
560
|
+
af_string = get_bgp_af_dampening_params(asn, vrf, af)
|
|
561
|
+
pattern_params = 'Dampening policy configured: DropAllTraffic'
|
|
562
|
+
|
|
563
|
+
assert_match(pattern_params, af_string,
|
|
564
|
+
'Error: dampening properties DropAllTraffic is not ' \
|
|
565
|
+
'configured and should be')
|
|
566
|
+
|
|
567
|
+
# Check getters
|
|
568
|
+
assert_equal(bgp_af.dampening, 'DropAllTraffic',
|
|
569
|
+
'Error: dampening getter did not match')
|
|
570
|
+
assert_equal(bgp_af.dampening_routemap, 'DropAllTraffic',
|
|
571
|
+
'Error: dampening getter did not match')
|
|
572
|
+
|
|
573
|
+
#
|
|
574
|
+
# Unset and verify
|
|
575
|
+
#
|
|
576
|
+
bgp_af.dampening = nil
|
|
577
|
+
af_string = get_bgp_af_cfg(asn, vrf, af)
|
|
578
|
+
pattern = /^ *dampening$/
|
|
579
|
+
|
|
580
|
+
refute_match(pattern, af_string, "Error: 'dampening' is still configured")
|
|
581
|
+
|
|
582
|
+
#############################################
|
|
583
|
+
# Set and verify 'dampening' with default #
|
|
584
|
+
#############################################
|
|
585
|
+
vrf = 'sangria'
|
|
586
|
+
af = %w(ipv4 multicast)
|
|
587
|
+
bgp_af = RouterBgpAF.new(asn, vrf, af)
|
|
588
|
+
|
|
589
|
+
bgp_af.dampening = bgp_af.default_dampening
|
|
590
|
+
|
|
591
|
+
# Check property got set
|
|
592
|
+
af_string = get_bgp_af_cfg(asn, vrf, af)
|
|
593
|
+
|
|
594
|
+
assert_match(pattern, af_string,
|
|
595
|
+
"Error: 'dampening' is not configured and should be")
|
|
596
|
+
|
|
597
|
+
# Check properties got set
|
|
598
|
+
af_string = get_bgp_af_dampening_params(asn, vrf, af)
|
|
599
|
+
|
|
600
|
+
pattern_params1 = 'Half-life time : 15 mins'
|
|
601
|
+
pattern_params2 = 'Suppress penalty : 2000'
|
|
602
|
+
pattern_params3 = 'Reuse penalty : 750'
|
|
603
|
+
pattern_params4 = 'Max suppress time : 45 mins'
|
|
604
|
+
pattern_params5 = 'Max suppress penalty : 6000'
|
|
605
|
+
|
|
606
|
+
error = ("Error: 'dampening' properties are incorrect")
|
|
607
|
+
|
|
608
|
+
assert_match(pattern_params1, af_string, error)
|
|
609
|
+
assert_match(pattern_params2, af_string, error)
|
|
610
|
+
assert_match(pattern_params3, af_string, error)
|
|
611
|
+
assert_match(pattern_params4, af_string, error)
|
|
612
|
+
assert_match(pattern_params5, af_string, error)
|
|
613
|
+
|
|
614
|
+
# Check getters
|
|
615
|
+
assert_empty(bgp_af.dampening, 'Error: dampening not configured ' \
|
|
616
|
+
'and should be')
|
|
617
|
+
assert_equal(bgp_af.default_dampening_half_time, bgp_af.dampening_half_time,
|
|
618
|
+
'Wrong default dampening half_time value configured')
|
|
619
|
+
assert_equal(bgp_af.default_dampening_reuse_time,
|
|
620
|
+
bgp_af.dampening_reuse_time,
|
|
621
|
+
'Wrong default dampening reuse_time value configured')
|
|
622
|
+
assert_equal(bgp_af.default_dampening_suppress_time,
|
|
623
|
+
bgp_af.dampening_suppress_time,
|
|
624
|
+
'Wrong default dampening suppress_time value configured')
|
|
625
|
+
assert_equal(bgp_af.default_dampening_max_suppress_time,
|
|
626
|
+
bgp_af.dampening_max_suppress_time,
|
|
627
|
+
'Wrong default dampening suppress_max_time value configured')
|
|
628
|
+
assert_equal(bgp_af.default_dampening_routemap,
|
|
629
|
+
bgp_af.dampening_routemap,
|
|
630
|
+
'The default dampening routemap should configured')
|
|
631
|
+
|
|
632
|
+
#
|
|
633
|
+
# Unset and verify
|
|
634
|
+
#
|
|
635
|
+
bgp_af.dampening = nil
|
|
636
|
+
af_string = get_bgp_af_cfg(asn, vrf, af)
|
|
637
|
+
|
|
638
|
+
refute_match(pattern, af_string, "Error: 'dampening' is still configured")
|
|
639
|
+
end
|
|
640
|
+
# rubocop:enable Metrics/AbcSize,Metrics/MethodLength
|
|
641
|
+
|
|
642
|
+
##
|
|
643
|
+
## maximum_paths
|
|
644
|
+
##
|
|
645
|
+
def maximum_paths(asn, vrf, af)
|
|
646
|
+
bgp_af = RouterBgpAF.new(asn, vrf, af)
|
|
647
|
+
|
|
648
|
+
#
|
|
649
|
+
# Set and verify
|
|
650
|
+
#
|
|
651
|
+
val = 7
|
|
652
|
+
bgp_af.maximum_paths = val
|
|
653
|
+
assert_equal(bgp_af.maximum_paths, val,
|
|
654
|
+
'Error: maximum paths value not match to set value')
|
|
655
|
+
|
|
656
|
+
val = 9
|
|
657
|
+
bgp_af.maximum_paths = val
|
|
658
|
+
assert_equal(bgp_af.maximum_paths, val,
|
|
659
|
+
'Error: maximum paths value not match to set value')
|
|
660
|
+
|
|
661
|
+
val = bgp_af.default_maximum_paths
|
|
662
|
+
bgp_af.maximum_paths = val
|
|
663
|
+
assert_equal(bgp_af.maximum_paths, val,
|
|
664
|
+
'Error: maximum paths value not match to default value')
|
|
665
|
+
end
|
|
666
|
+
|
|
667
|
+
def test_maximum_paths
|
|
668
|
+
vrfs = %w(default red)
|
|
669
|
+
afs = [%w(ipv4 unicast), %w(ipv6 unicast)]
|
|
670
|
+
vrfs.each do |vrf|
|
|
671
|
+
afs.each do |af|
|
|
672
|
+
maximum_paths(55, vrf, af)
|
|
673
|
+
end
|
|
674
|
+
end
|
|
675
|
+
end
|
|
676
|
+
|
|
677
|
+
##
|
|
678
|
+
## maximum_paths_ibgp
|
|
679
|
+
##
|
|
680
|
+
def maximum_paths_ibgp(asn, vrf, af)
|
|
681
|
+
/ipv4/.match(af) ? af = %w(ipv4 unicast) : af = %w(ipv6 unicast)
|
|
682
|
+
bgp_af = RouterBgpAF.new(asn, vrf, af)
|
|
683
|
+
|
|
684
|
+
#
|
|
685
|
+
# Set and verify
|
|
686
|
+
#
|
|
687
|
+
val = 7
|
|
688
|
+
bgp_af.maximum_paths_ibgp = val
|
|
689
|
+
assert_equal(bgp_af.maximum_paths_ibgp, val,
|
|
690
|
+
'Error: maximum paths ibgp value not match to set value')
|
|
691
|
+
|
|
692
|
+
val = 9
|
|
693
|
+
bgp_af.maximum_paths_ibgp = val
|
|
694
|
+
assert_equal(bgp_af.maximum_paths_ibgp, val,
|
|
695
|
+
'Error: maximum paths ibgp value not match to set value')
|
|
696
|
+
|
|
697
|
+
val = bgp_af.default_maximum_paths_ibgp
|
|
698
|
+
bgp_af.maximum_paths = val
|
|
699
|
+
assert_equal(bgp_af.default_maximum_paths_ibgp, val,
|
|
700
|
+
'Error: maximum paths ibgp value not match to default value')
|
|
701
|
+
end
|
|
702
|
+
|
|
703
|
+
def test_maximum_paths_ibgp
|
|
704
|
+
asn = '55'
|
|
705
|
+
vrf = 'default'
|
|
706
|
+
af = 'ipv4 unicast'
|
|
707
|
+
maximum_paths_ibgp(asn, vrf, af)
|
|
708
|
+
|
|
709
|
+
asn = '55'
|
|
710
|
+
vrf = 'red'
|
|
711
|
+
af = 'ipv4 unicast'
|
|
712
|
+
maximum_paths_ibgp(asn, vrf, af)
|
|
713
|
+
|
|
714
|
+
asn = '55'
|
|
715
|
+
vrf = 'default'
|
|
716
|
+
af = 'ipv6 unicast'
|
|
717
|
+
maximum_paths_ibgp(asn, vrf, af)
|
|
718
|
+
|
|
719
|
+
asn = '55'
|
|
720
|
+
vrf = 'red'
|
|
721
|
+
af = 'ipv6 unicast'
|
|
722
|
+
maximum_paths_ibgp(asn, vrf, af)
|
|
723
|
+
end
|
|
724
|
+
|
|
725
|
+
##
|
|
726
|
+
## network
|
|
727
|
+
##
|
|
728
|
+
|
|
729
|
+
def test_network
|
|
730
|
+
vrfs = %w(default red)
|
|
731
|
+
afs = [%w(ipv4 unicast), %w(ipv6 unicast)]
|
|
732
|
+
vrfs.each do |vrf|
|
|
733
|
+
afs.each do |af|
|
|
734
|
+
dbg = sprintf('[VRF %s AF %s]', vrf, af.join('/'))
|
|
735
|
+
af_obj = RouterBgpAF.new(1, vrf, af)
|
|
736
|
+
network_cmd(af_obj, dbg)
|
|
737
|
+
end
|
|
738
|
+
end
|
|
739
|
+
end
|
|
740
|
+
|
|
741
|
+
def network_cmd(af, dbg)
|
|
742
|
+
# Initial 'should' state
|
|
743
|
+
if /ipv6/.match(dbg)
|
|
744
|
+
master = [
|
|
745
|
+
['2000:123:38::/64', 'rtmap1'],
|
|
746
|
+
['2000:123:39::/64', 'rtmap2'],
|
|
747
|
+
['2000:123:40::/64', 'rtmap3'],
|
|
748
|
+
['2000:123:41::/64'],
|
|
749
|
+
['2000:123:42::/64', 'rtmap5'],
|
|
750
|
+
['2000:123:43::/64', 'rtmap6'],
|
|
751
|
+
['2000:123:44::/64'],
|
|
752
|
+
['2000:123:45::/64', 'rtmap7'],
|
|
753
|
+
]
|
|
754
|
+
else
|
|
755
|
+
master = [
|
|
756
|
+
['192.168.5.0/24', 'rtmap1'],
|
|
757
|
+
['192.168.6.0/24', 'rtmap2'],
|
|
758
|
+
['192.168.7.0/24', 'rtmap3'],
|
|
759
|
+
['192.168.8.0/24'],
|
|
760
|
+
['192.168.9.0/24', 'rtmap5'],
|
|
761
|
+
['192.168.10.0/24', 'rtmap6'],
|
|
762
|
+
['192.168.11.0/24'],
|
|
763
|
+
['192.168.12.0/24', 'rtmap7'],
|
|
764
|
+
]
|
|
765
|
+
end
|
|
766
|
+
|
|
767
|
+
# Test: all networks are set when current is empty.
|
|
768
|
+
should = master.clone
|
|
769
|
+
af.networks = should
|
|
770
|
+
result = af.networks
|
|
771
|
+
assert_equal(should.sort, result.sort,
|
|
772
|
+
"#{dbg} Test 1. From empty, to all networks")
|
|
773
|
+
|
|
774
|
+
# Test: remove half of the networks
|
|
775
|
+
should.shift(4)
|
|
776
|
+
af.networks = should
|
|
777
|
+
result = af.networks
|
|
778
|
+
assert_equal(should.sort, result.sort,
|
|
779
|
+
"#{dbg} Test 2. Remove half of the networks")
|
|
780
|
+
|
|
781
|
+
# Test: restore the removed networks
|
|
782
|
+
should = master.clone
|
|
783
|
+
af.networks = should
|
|
784
|
+
result = af.networks
|
|
785
|
+
assert_equal(should.sort, result.sort,
|
|
786
|
+
"#{dbg} Test 3. Restore the removed networks")
|
|
787
|
+
|
|
788
|
+
# Test: Change route-maps on existing networks
|
|
789
|
+
should = master.map { |network, rm| [network, "#{rm}_55"] }
|
|
790
|
+
af.networks = should
|
|
791
|
+
result = af.networks
|
|
792
|
+
assert_equal(should.sort, result.sort,
|
|
793
|
+
"#{dbg} Test 4. Change route-map on existing networks")
|
|
794
|
+
|
|
795
|
+
# Test: 'default'
|
|
796
|
+
should = af.default_networks
|
|
797
|
+
af.networks = should
|
|
798
|
+
result = af.networks
|
|
799
|
+
assert_equal(should.sort, result.sort,
|
|
800
|
+
"#{dbg} Test 5. 'Default'")
|
|
801
|
+
end
|
|
802
|
+
|
|
803
|
+
##
|
|
804
|
+
## redistribute
|
|
805
|
+
##
|
|
806
|
+
|
|
807
|
+
def test_redistribute
|
|
808
|
+
vrfs = %w(default red)
|
|
809
|
+
afs = [%w(ipv4 unicast), %w(ipv6 unicast)]
|
|
810
|
+
vrfs.each do |vrf|
|
|
811
|
+
afs.each do |af|
|
|
812
|
+
dbg = sprintf('[VRF %s AF %s]', vrf, af.join('/'))
|
|
813
|
+
af = RouterBgpAF.new(1, vrf, af)
|
|
814
|
+
redistribute_cmd(af, dbg)
|
|
815
|
+
end
|
|
816
|
+
end
|
|
817
|
+
end
|
|
818
|
+
|
|
819
|
+
def redistribute_cmd(af, dbg)
|
|
820
|
+
# rubocop:disable Style/WordArray
|
|
821
|
+
# Initial 'should' state
|
|
822
|
+
ospf = (dbg.include? 'ipv6') ? 'ospfv3 3' : 'ospf 3'
|
|
823
|
+
master = [['direct', 'rm_direct'],
|
|
824
|
+
['lisp', 'rm_lisp'],
|
|
825
|
+
['static', 'rm_static'],
|
|
826
|
+
['eigrp 1', 'rm_eigrp'],
|
|
827
|
+
['isis 2', 'rm_isis'],
|
|
828
|
+
[ospf, 'rm_ospf'],
|
|
829
|
+
['rip 4', 'rm_rip']]
|
|
830
|
+
# rubocop:enable Style/WordArray
|
|
831
|
+
|
|
832
|
+
# Test: Add all protocols w/route-maps when no cmds are present
|
|
833
|
+
should = master.clone
|
|
834
|
+
af.redistribute = should
|
|
835
|
+
result = af.redistribute
|
|
836
|
+
assert_equal(should.sort, result.sort,
|
|
837
|
+
"#{dbg} Test 1. From empty, to all protocols")
|
|
838
|
+
|
|
839
|
+
# Test: remove half of the protocols
|
|
840
|
+
should.shift(4)
|
|
841
|
+
af.redistribute = should
|
|
842
|
+
result = af.redistribute
|
|
843
|
+
assert_equal(should.sort, result.sort,
|
|
844
|
+
"#{dbg} Test 2. Remove half of the protocols")
|
|
845
|
+
|
|
846
|
+
# Test: restore the removed protocols
|
|
847
|
+
should = master.clone
|
|
848
|
+
af.redistribute = should
|
|
849
|
+
result = af.redistribute
|
|
850
|
+
assert_equal(should.sort, result.sort,
|
|
851
|
+
"#{dbg} Test 3. Restore the removed protocols")
|
|
852
|
+
|
|
853
|
+
# Test: Change route-maps on existing commands
|
|
854
|
+
should = master.map { |prot_only, rm| [prot_only, "#{rm}_2"] }
|
|
855
|
+
af.redistribute = should
|
|
856
|
+
result = af.redistribute
|
|
857
|
+
assert_equal(should.sort, result.sort,
|
|
858
|
+
"#{dbg} Test 4. Change route-maps on existing commands")
|
|
859
|
+
|
|
860
|
+
# Test: 'default'
|
|
861
|
+
should = af.default_redistribute
|
|
862
|
+
af.redistribute = should
|
|
863
|
+
result = af.redistribute
|
|
864
|
+
assert_equal(should.sort, result.sort,
|
|
865
|
+
"#{dbg} Test 5. 'Default'")
|
|
866
|
+
end
|
|
867
|
+
|
|
868
|
+
##
|
|
869
|
+
## common utilities
|
|
870
|
+
##
|
|
871
|
+
|
|
872
|
+
def test_utils_delta_add_remove
|
|
873
|
+
# Note: AF context is not needed. This test is only validating the
|
|
874
|
+
# delta_add_remove class method and does not test directly on the device.
|
|
875
|
+
|
|
876
|
+
# rubocop:disable Style/WordArray
|
|
877
|
+
# Initial 'should' state
|
|
878
|
+
should = [['direct', 'rm_direct'],
|
|
879
|
+
['lisp', 'rm_lisp'],
|
|
880
|
+
['static', 'rm_static'],
|
|
881
|
+
['eigrp 1', 'rm_eigrp'],
|
|
882
|
+
['isis 2', 'rm_isis'],
|
|
883
|
+
['ospf 3', 'rm_ospf'],
|
|
884
|
+
['rip 4', 'rm_rip']]
|
|
885
|
+
# rubocop:enable Style/WordArray
|
|
886
|
+
|
|
887
|
+
# Test: Check delta when every protocol is specified and has a route-map.
|
|
888
|
+
current = []
|
|
889
|
+
expected = { add: should, remove: [] }
|
|
890
|
+
result = Utils.delta_add_remove(should, current)
|
|
891
|
+
assert_equal(expected, result, 'Test 1. delta mismatch')
|
|
892
|
+
|
|
893
|
+
# Test: Check delta when should is the same as current.
|
|
894
|
+
current = should.clone
|
|
895
|
+
expected = { add: [], remove: [] }
|
|
896
|
+
result = Utils.delta_add_remove(should, current)
|
|
897
|
+
assert_equal(expected, result, 'Test 2. delta mismatch')
|
|
898
|
+
|
|
899
|
+
# Test: Move half the 'current' entries to 'should'. Check delta.
|
|
900
|
+
should = current.shift(4)
|
|
901
|
+
expected = { add: should, remove: current }
|
|
902
|
+
result = Utils.delta_add_remove(should, current)
|
|
903
|
+
assert_equal(expected, result, 'Test 3. delta mismatch')
|
|
904
|
+
|
|
905
|
+
# Test: Remove the route-maps from the current list. Check delta.
|
|
906
|
+
# Note: The :remove list should be empty since this is just
|
|
907
|
+
# an update of the route-map.
|
|
908
|
+
should = current.map { |prot_only, _route_map| [prot_only] }
|
|
909
|
+
expected = { add: should, remove: [] }
|
|
910
|
+
result = Utils.delta_add_remove(should, current)
|
|
911
|
+
assert_equal(expected, result, 'Test 4. delta mismatch')
|
|
912
|
+
|
|
913
|
+
# Test: Check empty inputs
|
|
914
|
+
should = []
|
|
915
|
+
current = []
|
|
916
|
+
expected = { add: [], remove: [] }
|
|
917
|
+
result = Utils.delta_add_remove(should, current)
|
|
918
|
+
assert_equal(expected, result, 'Test 5. delta mismatch')
|
|
919
|
+
end
|
|
920
|
+
end
|