rbeapi 0.5.1 → 1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (57) hide show
  1. data/CHANGELOG.md +211 -76
  2. data/Gemfile +14 -3
  3. data/README.md +74 -38
  4. data/Rakefile +38 -17
  5. data/gems/inifile/inifile.spec.tmpl +31 -4
  6. data/gems/net_http_unix/net_http_unix.spec.tmpl +34 -8
  7. data/gems/netaddr/netaddr.spec.tmpl +31 -5
  8. data/guide/getting-started.rst +95 -64
  9. data/guide/installation.rst +27 -6
  10. data/guide/release-notes.rst +5 -1
  11. data/guide/testing.rst +5 -2
  12. data/guide/upgrading.rst +2 -0
  13. data/lib/rbeapi/api/dns.rb +8 -2
  14. data/lib/rbeapi/api/interfaces.rb +107 -21
  15. data/lib/rbeapi/api/ipinterfaces.rb +48 -0
  16. data/lib/rbeapi/api/prefixlists.rb +53 -23
  17. data/lib/rbeapi/api/routemaps.rb +11 -0
  18. data/lib/rbeapi/api/stp.rb +6 -3
  19. data/lib/rbeapi/api/switchports.rb +5 -11
  20. data/lib/rbeapi/api/system.rb +1 -1
  21. data/lib/rbeapi/api/users.rb +2 -0
  22. data/lib/rbeapi/api/varp.rb +6 -0
  23. data/lib/rbeapi/api/vlans.rb +44 -0
  24. data/lib/rbeapi/api/vrrp.rb +13 -0
  25. data/lib/rbeapi/client.rb +19 -4
  26. data/lib/rbeapi/switchconfig.rb +330 -0
  27. data/lib/rbeapi/version.rb +1 -1
  28. data/rbeapi.gemspec +2 -0
  29. data/rbeapi.spec.tmpl +30 -3
  30. data/spec/fixtures/.gitignore +1 -0
  31. data/spec/support/matchers/switch_config_sections.rb +80 -0
  32. data/spec/system/rbeapi/api/interfaces_base_spec.rb +32 -3
  33. data/spec/system/rbeapi/api/interfaces_ethernet_spec.rb +56 -8
  34. data/spec/system/rbeapi/api/interfaces_portchannel_spec.rb +33 -1
  35. data/spec/system/rbeapi/api/interfaces_vxlan_spec.rb +27 -0
  36. data/spec/system/rbeapi/api/ipinterfaces_spec.rb +34 -1
  37. data/spec/system/rbeapi/api/prefixlists_spec.rb +198 -0
  38. data/spec/system/rbeapi/api/stp_instances_spec.rb +49 -5
  39. data/spec/system/rbeapi/api/switchports_spec.rb +15 -9
  40. data/spec/system/rbeapi/api/vlans_spec.rb +46 -0
  41. data/spec/unit/rbeapi/api/interfaces/base_spec.rb +1 -1
  42. data/spec/unit/rbeapi/api/interfaces/ethernet_spec.rb +1 -1
  43. data/spec/unit/rbeapi/api/interfaces/portchannel_spec.rb +9 -2
  44. data/spec/unit/rbeapi/api/interfaces/vxlan_spec.rb +1 -1
  45. data/spec/unit/rbeapi/api/prefixlists/default_spec.rb +202 -0
  46. data/spec/unit/rbeapi/api/prefixlists/fixture_prefixlists.text +11 -0
  47. data/spec/unit/rbeapi/api/routemaps/default_spec.rb +5 -0
  48. data/spec/unit/rbeapi/api/switchports/default_spec.rb +4 -4
  49. data/spec/unit/rbeapi/api/system/default_spec.rb +5 -0
  50. data/spec/unit/rbeapi/api/system/fixture_system.text +1 -0
  51. data/spec/unit/rbeapi/api/vlans/default_spec.rb +30 -0
  52. data/spec/unit/rbeapi/api/vrrp/default_spec.rb +10 -0
  53. data/spec/unit/rbeapi/client_spec.rb +42 -0
  54. data/spec/unit/rbeapi/switchconfig2_spec.rb +119 -0
  55. data/spec/unit/rbeapi/switchconfig3_spec.rb +125 -0
  56. data/spec/unit/rbeapi/switchconfig_spec.rb +335 -0
  57. metadata +21 -7
@@ -0,0 +1,198 @@
1
+ #
2
+ # Copyright (c) 2016, Arista Networks, Inc.
3
+ # All rights reserved.
4
+ #
5
+ # Redistribution and use in source and binary forms, with or without
6
+ # modification, are permitted provided that the following conditions are
7
+ # met:
8
+ #
9
+ # Redistributions of source code must retain the above copyright notice,
10
+ # this list of conditions and the following disclaimer.
11
+ #
12
+ # Redistributions in binary form must reproduce the above copyright
13
+ # notice, this list of conditions and the following disclaimer in the
14
+ # documentation and/or other materials provided with the distribution.
15
+ #
16
+ # Neither the name of Arista Networks nor the names of its
17
+ # contributors may be used to endorse or promote products derived from
18
+ # this software without specific prior written permission.
19
+ #
20
+ # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21
+ # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22
+ # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23
+ # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL ARISTA NETWORKS
24
+ # BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25
+ # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26
+ # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
27
+ # BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
28
+ # WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
29
+ # OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
30
+ # IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31
+ #
32
+ require 'spec_helper'
33
+
34
+ require 'rbeapi/client'
35
+ require 'rbeapi/api/prefixlists'
36
+
37
+ describe Rbeapi::Api::Prefixlists do
38
+ subject { described_class.new(node) }
39
+
40
+ let(:node) do
41
+ Rbeapi::Client.config.read(fixture_file('dut.conf'))
42
+ Rbeapi::Client.connect_to('dut')
43
+ end
44
+
45
+ describe '#get' do
46
+ before do
47
+ node.config(['no ip prefix-list test1',
48
+ 'ip prefix-list test1',
49
+ 'seq 10 permit 1.2.3.0/24',
50
+ 'seq 20 permit 2.3.4.0/24 le 30',
51
+ 'seq 30 deny 3.4.5.0/24 ge 26 le 30',
52
+ 'permit 5.6.7.16/28 eq 29'])
53
+ end
54
+
55
+ let(:prefixlist) { subject.get('test1') }
56
+
57
+ it 'returns the prefix list for an existing name' do
58
+ expect(prefixlist).to be_a_kind_of(Array)
59
+ end
60
+
61
+ it 'returns all rules as hash' do
62
+ expect(prefixlist).to all ( be_an(Hash) )
63
+ end
64
+
65
+ it 'has all keys for each rule' do
66
+ prefixlist.each do |rule|
67
+ expect(rule).to have_key('seq')
68
+ expect(rule).to have_key('prefix')
69
+ expect(rule).to have_key('action')
70
+ end
71
+ end
72
+
73
+ let(:values) do
74
+ [
75
+ {
76
+ 'seq' => '10',
77
+ 'action' => 'permit',
78
+ 'prefix' => '1.2.3.0/24'
79
+ },
80
+ {
81
+ 'seq' => '20',
82
+ 'action' => 'permit',
83
+ 'prefix' => '2.3.4.0/24 le 30'
84
+ },
85
+ {
86
+ 'seq' => '30',
87
+ 'action' => 'deny',
88
+ 'prefix' => '3.4.5.0/24 ge 26 le 30'
89
+ },
90
+ {
91
+ 'seq' => '40',
92
+ 'action' => 'permit',
93
+ 'prefix' => '5.6.7.16/28 eq 29'
94
+ }
95
+ ]
96
+ end
97
+
98
+ it 'returns the correct values for all the keys' do
99
+ expect(prefixlist).to eq(values)
100
+ end
101
+ end
102
+
103
+ describe '#getall' do
104
+ let(:del_pref_lists) {
105
+ subject.getall.keys.map { |k| "no ip prefix-list #{k}" }
106
+ }
107
+
108
+ before do
109
+ node.config(del_pref_lists +
110
+ ['ip prefix-list test1',
111
+ 'seq 10 permit 1.2.3.0/24',
112
+ 'seq 20 permit 2.3.4.0/24 le 30',
113
+ 'seq 30 deny 3.4.5.0/24 ge 26 le 30',
114
+ 'permit 5.6.7.8/28',
115
+ 'ip prefix-list test2',
116
+ 'seq 10 permit 10.11.0.0/16',
117
+ 'seq 20 permit 10.12.0.0/16 le 24',
118
+ 'ip prefix-list test3'])
119
+ end
120
+
121
+ let(:prefixlists) { subject.getall }
122
+
123
+ it 'returns the collection as hash' do
124
+ expect(prefixlists).to be_a_kind_of(Hash)
125
+ end
126
+
127
+ it 'returns all prefix lists as array' do
128
+ expect(prefixlists).to all ( be_an(Array) )
129
+ end
130
+
131
+ it 'has three prefix lists' do
132
+ expect(prefixlists.size).to eq(3)
133
+ end
134
+ end
135
+
136
+ describe '#create' do
137
+ before do
138
+ node.config('no ip prefix-list test4')
139
+ end
140
+
141
+ it 'creates a new prefix list' do
142
+ expect(subject.get('test4')).to eq(nil)
143
+ expect(subject.create('test4')).to be_truthy
144
+ expect(subject.get('test4')).to eq([])
145
+ expect(subject.get('test4').size).to eq(0)
146
+ end
147
+ end
148
+
149
+ describe '#add_rule' do
150
+ before do
151
+ node.config(['no ip prefix-list test5',
152
+ 'ip prefix-list test5'])
153
+ end
154
+
155
+ it 'adds rule to an existing prefix list' do
156
+ expect(subject.get('test5')).to eq([])
157
+ expect(subject.add_rule('test5', 'permit', '1.1.1.0/24')).to be_truthy
158
+ expect(subject.get('test5')).to eq([{
159
+ "seq" => "10",
160
+ "action" => "permit",
161
+ "prefix" => "1.1.1.0/24"}])
162
+ end
163
+
164
+ it 'adds rule to a non-existent prefix list' do
165
+ expect(subject.get('test6')).to eq(nil)
166
+ expect(subject.add_rule('test6', 'deny', '2.2.2.0/24')).to be_truthy
167
+ expect(subject.get('test6')).to eq([{
168
+ "seq" => "10",
169
+ "action" => "deny",
170
+ "prefix" => "2.2.2.0/24"}])
171
+ end
172
+ end
173
+
174
+ describe '#delete' do
175
+ before do
176
+ node.config(['no ip prefix-list test7',
177
+ 'no ip prefix-list test8',
178
+ 'ip prefix-list test7',
179
+ 'seq 10 permit 7.7.0.0/16',
180
+ 'ip prefix-list test8',
181
+ 'seq 10 permit 8.8.0.0/16',
182
+ 'deny 9.9.0.0/16 le 24'])
183
+ end
184
+
185
+ it 'delets a prefix list' do
186
+ expect(subject.get('test7')).to be_truthy
187
+ expect(subject.delete('test7')).to be_truthy
188
+ expect(subject.get('test7')).to eq(nil)
189
+ end
190
+
191
+ it 'deletes a rule in the prefix list' do
192
+ expect(subject.get('test8')).to be_truthy
193
+ expect(subject.delete('test8', 20)).to be_truthy
194
+ expect(subject.get('test8').size).to eq(1)
195
+ expect(subject.get('test8')[1]).to eq(nil)
196
+ end
197
+ end
198
+ end
@@ -15,14 +15,24 @@ describe Rbeapi::Api::StpInstances do
15
15
  before do
16
16
  node.config(['spanning-tree mode mstp',
17
17
  'spanning-tree mst configuration',
18
- 'instance 1 vlans 1', 'exit'])
18
+ 'instance 10 vlans 100', 'exit'])
19
19
  end
20
20
 
21
21
  it 'returns the stp instance resource as a hash' do
22
+ expect(subject.get('10')).to be_a_kind_of(Hash)
23
+ end
24
+
25
+ it 'returns the default stp instance resources as a hash' do
26
+ expect(subject.get('0')).to be_a_kind_of(Hash)
22
27
  expect(subject.get('1')).to be_a_kind_of(Hash)
23
28
  end
24
29
 
25
30
  it 'returns the instance priority' do
31
+ expect(subject.get('10')).to include(:priority)
32
+ end
33
+
34
+ it 'returns the default instances priority' do
35
+ expect(subject.get('0')).to include(:priority)
26
36
  expect(subject.get('1')).to include(:priority)
27
37
  end
28
38
  end
@@ -41,38 +51,65 @@ describe Rbeapi::Api::StpInstances do
41
51
  before do
42
52
  node.config(['spanning-tree mode mstp',
43
53
  'spanning-tree mst configuration',
44
- 'instance 1 vlans 1', 'exit'])
54
+ 'instance 1 vlans 1',
55
+ 'instance 10 vlans 100', 'exit'])
45
56
  end
46
57
 
47
58
  it 'deletes the mst instance' do
59
+ expect(subject.get('10')).not_to be_nil
60
+ expect(subject.delete('10')).to be_truthy
61
+ expect(subject.get('10')).to be_nil
62
+ end
63
+
64
+ it 'does not delete the default mst instance' do
48
65
  expect(subject.get('1')).not_to be_nil
49
66
  expect(subject.delete('1')).to be_truthy
50
- expect(subject.get('1')).to be_nil
67
+ expect(subject.get('1')).not_to be_nil
51
68
  end
52
69
  end
53
70
 
54
71
  describe '#set_priority' do
55
72
  before do
56
- node.config(['default spanning-tree mst 1 priority',
73
+ node.config(['default spanning-tree mst 10 priority',
74
+ 'no spanning-tree mst 1 priority',
57
75
  'spanning-tree mode mstp',
58
76
  'default spanning-tree mst configuration',
59
77
  'spanning-tree mst configuration',
60
- 'instance 1 vlans 1', 'exit'])
78
+ 'instance 10 vlans 100', 'exit'])
61
79
  end
62
80
 
63
81
  it 'set the instance priority' do
82
+ expect(subject.get('10')[:priority]).to eq('32768')
83
+ expect(subject.set_priority('10', value: '16384')).to be_truthy
84
+ expect(subject.get('10')[:priority]).to eq('16384')
85
+ end
86
+
87
+ it 'set the default instance priority' do
64
88
  expect(subject.get('1')[:priority]).to eq('32768')
65
89
  expect(subject.set_priority('1', value: '4096')).to be_truthy
66
90
  expect(subject.get('1')[:priority]).to eq('4096')
67
91
  end
68
92
 
69
93
  it 'set the instance priority to default' do
94
+ expect(subject.set_priority('10', value: '16384',
95
+ default: true)).to be_truthy
96
+ expect(subject.get('10')[:priority]).to eq('32768')
97
+ end
98
+
99
+ it 'set the default instance priority to default' do
70
100
  expect(subject.set_priority('1', value: '4096',
71
101
  default: true)).to be_truthy
72
102
  expect(subject.get('1')[:priority]).to eq('32768')
73
103
  end
74
104
 
75
105
  it 'set the instance priority to enable false' do
106
+ expect(subject.set_priority('10', value: '16384',
107
+ default: false,
108
+ enable: false)).to be_truthy
109
+ expect(subject.get('10')[:priority]).to eq('32768')
110
+ end
111
+
112
+ it 'set the default instance priority to enable false' do
76
113
  expect(subject.set_priority('1', value: '4096',
77
114
  default: false,
78
115
  enable: false)).to be_truthy
@@ -80,6 +117,13 @@ describe Rbeapi::Api::StpInstances do
80
117
  end
81
118
 
82
119
  it 'set the instance priority to enable true' do
120
+ expect(subject.set_priority('10', value: '16384',
121
+ default: false,
122
+ enable: true)).to be_truthy
123
+ expect(subject.get('10')[:priority]).to eq('16384')
124
+ end
125
+
126
+ it 'set the default instance priority to enable true' do
83
127
  expect(subject.set_priority('1', value: '4096',
84
128
  default: false,
85
129
  enable: true)).to be_truthy
@@ -191,34 +191,40 @@ describe Rbeapi::Api::Switchports do
191
191
  .to raise_error(ArgumentError)
192
192
  end
193
193
 
194
- it 'sets vlan 8 and 9 to the trunk allowed vlans' do
194
+ it 'sets vlan 8-10 and 100 to the trunk allowed vlans' do
195
195
  node.config(['interface Ethernet1', 'switchport trunk allowed vlan none'])
196
196
  expect(subject.get('Ethernet1')[:trunk_allowed_vlans]).to be_empty
197
- expect(subject.set_trunk_allowed_vlans('Ethernet1', value: [8, 9]))
197
+ expect(subject.set_trunk_allowed_vlans('Ethernet1', value: ['8-10',
198
+ '100']))
198
199
  .to be_truthy
199
- expect(subject.get('Ethernet1')[:trunk_allowed_vlans]).to eq([8, 9])
200
+ expect(subject.get('Ethernet1')[:trunk_allowed_vlans]).to eq(['8-10',
201
+ '100'])
200
202
  end
201
203
 
202
204
  it 'negate switchport trunk allowed vlan' do
203
205
  node.config(['interface Ethernet1', 'switchport trunk allowed vlan none'])
204
206
  expect(subject.get('Ethernet1')[:trunk_allowed_vlans]).to be_empty
205
- expect(subject.set_trunk_allowed_vlans('Ethernet1', value: [8, 9]))
207
+ expect(subject.set_trunk_allowed_vlans('Ethernet1', value: ['8-10',
208
+ '100']))
206
209
  .to be_truthy
207
- expect(subject.get('Ethernet1')[:trunk_allowed_vlans]).to eq([8, 9])
210
+ expect(subject.get('Ethernet1')[:trunk_allowed_vlans])
211
+ .to eq(['8-10', '100'])
208
212
  expect(subject.set_trunk_allowed_vlans('Ethernet1', enable: false))
209
213
  .to be_truthy
210
- expect(subject.get('Ethernet1')[:trunk_allowed_vlans].length).to eq(4094)
214
+ expect(subject.get('Ethernet1')[:trunk_allowed_vlans]).to eq(['1-4094'])
211
215
  end
212
216
 
213
217
  it 'default switchport trunk allowed vlan' do
214
218
  node.config(['interface Ethernet1', 'switchport trunk allowed vlan none'])
215
219
  expect(subject.get('Ethernet1')[:trunk_allowed_vlans]).to be_empty
216
- expect(subject.set_trunk_allowed_vlans('Ethernet1', value: [8, 9]))
220
+ expect(subject.set_trunk_allowed_vlans('Ethernet1', value: ['8-10',
221
+ '100']))
217
222
  .to be_truthy
218
- expect(subject.get('Ethernet1')[:trunk_allowed_vlans]).to eq([8, 9])
223
+ expect(subject.get('Ethernet1')[:trunk_allowed_vlans])
224
+ .to eq(['8-10', '100'])
219
225
  expect(subject.set_trunk_allowed_vlans('Ethernet1', default: true))
220
226
  .to be_truthy
221
- expect(subject.get('Ethernet1')[:trunk_allowed_vlans].length).to eq(4094)
227
+ expect(subject.get('Ethernet1')[:trunk_allowed_vlans]).to eq(['1-4094'])
222
228
  end
223
229
  end
224
230
 
@@ -159,4 +159,50 @@ describe Rbeapi::Api::Vlans do
159
159
  expect(subject.get('1')[:trunk_groups]).not_to include('foo')
160
160
  end
161
161
  end
162
+
163
+ describe '#set_trunk_groups' do
164
+ before do
165
+ node.config(['vlan 1', 'default trunk group'])
166
+ end
167
+
168
+ it 'raises an ArgumentError if value is not an array' do
169
+ expect { subject.set_trunk_groups('1', value: 'foo') }
170
+ .to raise_error(ArgumentError)
171
+ end
172
+
173
+ it 'sets trunk group to foo bar bang' do
174
+ node.config(['vlan 1', 'trunk group bang', 'trunk group baz'])
175
+ expect(subject.get('1')[:trunk_groups]).to eq(%w(bang baz))
176
+ expect(subject.set_trunk_groups('1', value: %w(foo bar bang)))
177
+ .to be_truthy
178
+ expect(subject.get('1')[:trunk_groups].sort).to eq(%w(bang bar foo))
179
+ end
180
+
181
+ it 'clears trunk group if no value specified' do
182
+ node.config(['vlan 1', 'trunk group bang', 'trunk group baz'])
183
+ expect(subject.get('1')[:trunk_groups]).to eq(%w(bang baz))
184
+ expect(subject.set_trunk_groups('1')).to be_truthy
185
+ expect(subject.get('1')[:trunk_groups]).to be_empty
186
+ end
187
+
188
+ it 'negate trunk group' do
189
+ node.config(['vlan 1', 'trunk group bang', 'trunk group baz'])
190
+ expect(subject.get('1')[:trunk_groups]).to eq(%w(bang baz))
191
+ expect(subject.set_trunk_groups('1', value: %w(foo bar bang)))
192
+ .to be_truthy
193
+ expect(subject.get('1')[:trunk_groups].sort).to eq(%w(bang bar foo))
194
+ expect(subject.set_trunk_groups('1', enable: false)).to be_truthy
195
+ expect(subject.get('1')[:trunk_groups]).to be_empty
196
+ end
197
+
198
+ it 'default trunk group' do
199
+ node.config(['vlan 1', 'trunk group bang', 'trunk group baz'])
200
+ expect(subject.get('1')[:trunk_groups]).to eq(%w(bang baz))
201
+ expect(subject.set_trunk_groups('1', value: %w(foo bar bang)))
202
+ .to be_truthy
203
+ expect(subject.get('1')[:trunk_groups].sort).to eq(%w(bang bar foo))
204
+ expect(subject.set_trunk_groups('1', default: true)).to be_truthy
205
+ expect(subject.get('1')[:trunk_groups]).to be_empty
206
+ end
207
+ end
162
208
  end
@@ -23,7 +23,7 @@ describe Rbeapi::Api::BaseInterface do
23
23
  let(:resource) { subject.get('Loopback0') }
24
24
 
25
25
  let(:keys) do
26
- [:type, :shutdown, :description, :name]
26
+ [:type, :shutdown, :load_interval, :description, :name]
27
27
  end
28
28
 
29
29
  it 'returns an ethernet resource as a hash' do
@@ -24,7 +24,7 @@ describe Rbeapi::Api::EthernetInterface do
24
24
 
25
25
  let(:keys) do
26
26
  [:type, :speed, :sflow, :flowcontrol_send, :flowcontrol_receive,
27
- :forced, :shutdown, :description, :name]
27
+ :shutdown, :description, :name, :load_interval, :lacp_priority]
28
28
  end
29
29
 
30
30
  it 'returns an ethernet resource as a hash' do
@@ -31,8 +31,8 @@ describe Rbeapi::Api::PortchannelInterface do
31
31
  let(:resource) { subject.get('Port-Channel1') }
32
32
 
33
33
  let(:keys) do
34
- [:type, :shutdown, :description, :name, :members, :lacp_mode,
35
- :minimum_links, :lacp_timeout, :lacp_fallback]
34
+ [:type, :shutdown, :load_interval, :description, :name, :members,
35
+ :lacp_mode, :minimum_links, :lacp_timeout, :lacp_fallback]
36
36
  end
37
37
 
38
38
  it 'returns an ethernet resource as a hash' do
@@ -141,4 +141,11 @@ describe Rbeapi::Api::PortchannelInterface do
141
141
  expect(subject.set_shutdown('Port-Channel1', opts)).to be_truthy
142
142
  end
143
143
  end
144
+
145
+ describe '#set_members' do
146
+ it 'raises an ArgumentError if members is not an array' do
147
+ expect { subject.set_members('Port-Channel1', 'Ethernet3') }.to \
148
+ raise_error(ArgumentError)
149
+ end
150
+ end
144
151
  end