phut 0.7.7 → 0.7.8

Sign up to get free protection for your applications and to get access to all the features.
Files changed (79) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +1 -1
  3. data/.rubocop.yml +14 -1
  4. data/.travis.yml +2 -6
  5. data/Gemfile +30 -2
  6. data/Gemfile.lock +156 -0
  7. data/README.md +7 -2
  8. data/Rakefile +4 -3
  9. data/bin/phut +35 -83
  10. data/bin/vhost +28 -26
  11. data/features/{dsl.feature → dsl/error.feature} +8 -6
  12. data/features/{dsl_link.feature → dsl/link.feature} +11 -14
  13. data/features/dsl/netns.feature +115 -0
  14. data/features/dsl/vhost.feature +37 -0
  15. data/features/{dsl_vswitch.feature → dsl/vswitch.feature} +12 -12
  16. data/features/phut_run.feature +15 -0
  17. data/features/shell/vswitch#destroy.feature +10 -0
  18. data/features/shell/vswitch#ports.feature +36 -0
  19. data/features/shell/vswitch.all.feature +26 -0
  20. data/features/shell/vswitch.create.feature +30 -0
  21. data/features/shell/vswitch.destroy.feature +19 -0
  22. data/features/shell/vswitch.destroy_all.feature +18 -0
  23. data/features/step_definitions/link_steps.rb +5 -0
  24. data/features/step_definitions/netns_steps.rb +31 -0
  25. data/features/step_definitions/phut_steps.rb +5 -34
  26. data/features/step_definitions/vhost_steps.rb +5 -0
  27. data/features/step_definitions/vswitch_steps.rb +17 -0
  28. data/features/support/env.rb +3 -3
  29. data/features/support/hooks.rb +23 -15
  30. data/lib/phut.rb +3 -0
  31. data/lib/phut/finder.rb +19 -0
  32. data/lib/phut/link.rb +84 -0
  33. data/lib/phut/netns.rb +111 -22
  34. data/lib/phut/open_vswitch.rb +98 -96
  35. data/lib/phut/parser.rb +39 -8
  36. data/lib/phut/raw_socket.rb +4 -0
  37. data/lib/phut/route.rb +34 -0
  38. data/lib/phut/setting.rb +21 -4
  39. data/lib/phut/shell_runner.rb +13 -2
  40. data/lib/phut/syntax.rb +31 -14
  41. data/lib/phut/syntax/directive.rb +9 -1
  42. data/lib/phut/syntax/netns_directive.rb +13 -2
  43. data/lib/phut/syntax/vhost_directive.rb +2 -0
  44. data/lib/phut/syntax/vswitch_directive.rb +3 -1
  45. data/lib/phut/version.rb +3 -1
  46. data/lib/phut/veth.rb +68 -0
  47. data/lib/phut/vhost.rb +99 -58
  48. data/lib/phut/vhost_daemon.rb +53 -11
  49. data/lib/phut/vsctl.rb +125 -0
  50. data/lib/phut/vswitch.rb +10 -0
  51. data/phut.gemspec +9 -31
  52. data/tasks/cucumber.rake +5 -1
  53. data/tasks/flay.rake +2 -0
  54. data/tasks/flog.rake +3 -1
  55. data/tasks/gem.rake +2 -0
  56. data/tasks/minitest.rake +7 -0
  57. data/tasks/reek.rake +2 -0
  58. data/tasks/rubocop.rake +2 -0
  59. data/tasks/yard.rake +2 -0
  60. data/test/phut/link_test.rb +85 -0
  61. data/test/phut/netns_test.rb +58 -0
  62. data/test/phut/open_vswitch_test.rb +125 -0
  63. data/test/phut/veth_test.rb +48 -0
  64. data/test/phut/vhost_test.rb +56 -0
  65. metadata +41 -287
  66. data/.rspec +0 -3
  67. data/Guardfile +0 -29
  68. data/features/dsl_vhost.feature +0 -37
  69. data/features/phut_kill.feature +0 -27
  70. data/features/shell.feature +0 -39
  71. data/lib/phut/configuration.rb +0 -92
  72. data/lib/phut/null_logger.rb +0 -14
  73. data/lib/phut/virtual_link.rb +0 -109
  74. data/spec/phut/parser_spec.rb +0 -66
  75. data/spec/phut_spec.rb +0 -45
  76. data/spec/spec_helper.rb +0 -14
  77. data/tasks/LICENSE +0 -675
  78. data/tasks/relish.rake +0 -8
  79. data/tasks/rspec.rake +0 -8
@@ -0,0 +1,125 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'phut/shell_runner'
4
+ require 'pio'
5
+
6
+ module Phut
7
+ # ovs-vsctl wrapper
8
+ class Vsctl
9
+ MAX_BRIDGE_NAME_LENGTH = 15
10
+
11
+ extend ShellRunner
12
+
13
+ def self.list_br(prefix)
14
+ sudo('ovs-vsctl list-br').split.each_with_object([]) do |each, list|
15
+ match = /^#{prefix}(\S+)/.match(each)
16
+ next unless match
17
+ name = match[1]
18
+ vsctl = new(name: name, bridge: prefix + name)
19
+ list << { name: vsctl.name,
20
+ dpid: vsctl.dpid,
21
+ openflow_version: vsctl.openflow_version,
22
+ tcp_port: vsctl.tcp_port }
23
+ end
24
+ end
25
+
26
+ include ShellRunner
27
+
28
+ attr_reader :name
29
+ attr_reader :bridge
30
+
31
+ def initialize(name:, bridge:)
32
+ @name = name
33
+ @bridge = bridge
34
+ end
35
+
36
+ def dpid
37
+ ('0x' +
38
+ sudo("ovs-vsctl get bridge #{@bridge} datapath-id").delete('"')).hex
39
+ end
40
+
41
+ def openflow_version
42
+ case sudo("ovs-ofctl show #{@bridge} -O OpenFlow10,OpenFlow13")
43
+ when /^OFPT_FEATURES_REPLY \(xid=0x[^\)]+\):/
44
+ 1.0
45
+ when /^OFPT_FEATURES_REPLY \(OF(\d\.\d)\)/
46
+ Regexp.last_match(1).to_f
47
+ else
48
+ raise "Couldn't identify the OpenFlow version of #{@bridge}"
49
+ end
50
+ end
51
+
52
+ def add_bridge
53
+ sudo "ovs-vsctl add-br #{@bridge}"
54
+ sudo "/sbin/sysctl -w net.ipv6.conf.#{@bridge}.disable_ipv6=1 -q"
55
+ end
56
+
57
+ def delete_bridge
58
+ sudo "ovs-vsctl del-br #{@bridge}"
59
+ end
60
+
61
+ def openflow_version=(version)
62
+ sudo "ovs-vsctl set bridge #{@bridge} "\
63
+ "protocols=OpenFlow#{version.to_s.delete('.')} "
64
+ rescue
65
+ raise "Invalid openflow_version: #{version}"
66
+ end
67
+
68
+ def dpid=(dpid)
69
+ sudo "ovs-vsctl set bridge #{@bridge} "\
70
+ "other-config:datapath-id=#{fill_zero(dpid)}"
71
+ end
72
+
73
+ def tcp_port
74
+ controller_info = sudo("ovs-vsctl get-controller #{@bridge}")
75
+ return if controller_info.empty?
76
+ controller_info.chomp.split(':').last.to_i
77
+ end
78
+
79
+ def tcp_port=(tcp_port)
80
+ raise "Invalid tcp_port: #{tcp_port}" if tcp_port.negative?
81
+ sudo "ovs-vsctl set-controller #{@bridge} "\
82
+ "tcp:127.0.0.1:#{tcp_port} "\
83
+ "-- set controller #{@bridge} connection-mode=out-of-band"
84
+ end
85
+
86
+ def delete_controller
87
+ sudo "ovs-vsctl del-controller #{@bridge}"
88
+ end
89
+
90
+ def set_fail_mode_secure
91
+ sudo "ovs-vsctl set-fail-mode #{@bridge} secure"
92
+ end
93
+
94
+ def add_port(device)
95
+ sudo "ovs-vsctl add-port #{@bridge} #{device}"
96
+ nil
97
+ end
98
+
99
+ def add_numbered_port(port_number, device)
100
+ add_port device
101
+ sudo "ovs-vsctl set Interface #{device} "\
102
+ "ofport_request=#{port_number}"
103
+ nil
104
+ end
105
+
106
+ def bring_port_up(port_number)
107
+ sh "sudo ovs-ofctl mod-port #{@bridge} #{port_number} up"
108
+ end
109
+
110
+ def bring_port_down(port_number)
111
+ sh "sudo ovs-ofctl mod-port #{@bridge} #{port_number} down"
112
+ end
113
+
114
+ def ports
115
+ sudo("ovs-vsctl list-ports #{@bridge}").split
116
+ end
117
+
118
+ private
119
+
120
+ def fill_zero(dpid)
121
+ hex = format('%x', dpid)
122
+ '0' * (16 - hex.length) + hex
123
+ end
124
+ end
125
+ end
@@ -0,0 +1,10 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'phut/open_vswitch'
4
+
5
+ # Base module
6
+ module Phut
7
+ # Open vSwitch controller.
8
+ class Vswitch < OpenVswitch; end
9
+ Vswitch.bridge_prefix = 'vsw_'
10
+ end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  lib = File.expand_path('../lib', __FILE__)
2
4
  $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
3
5
  require 'phut/version'
@@ -9,46 +11,22 @@ Gem::Specification.new do |gem|
9
11
  gem.description = 'A simple network emulator '\
10
12
  'with capabilities similar to mininet.'
11
13
 
12
- gem.license = 'GPL3'
14
+ gem.licenses = %w[GPLv2 MIT]
13
15
 
14
16
  gem.authors = ['Yasuhito Takamiya']
15
17
  gem.email = ['yasuhito@gmail.com']
16
18
  gem.homepage = 'http://github.com/trema/phut'
17
19
 
18
- gem.executables = %w(phut vhost)
20
+ gem.executables = %w[phut vhost]
19
21
  gem.files = `git ls-files`.split("\n")
20
22
 
21
23
  gem.extra_rdoc_files = ['README.md']
22
- gem.test_files = `git ls-files -- {spec,features}/*`.split("\n")
24
+ gem.test_files = `git ls-files -- {test,features}/*`.split("\n")
23
25
 
24
- gem.required_ruby_version = '>= 2.0.0'
26
+ gem.required_ruby_version = '>= 2.3.0'
25
27
 
26
- gem.add_dependency 'activesupport', '~> 4.2', '>= 4.2.5'
27
- gem.add_dependency 'gli', '~> 2.13.4'
28
- gem.add_dependency 'pio', '~> 0.30.0'
28
+ gem.add_dependency 'activesupport', '~> 5.1.0'
29
+ gem.add_dependency 'gli', '~> 2.16.0'
30
+ gem.add_dependency 'pio', '~> 0.30.2'
29
31
  gem.add_dependency 'pry', '~> 0.10.3'
30
-
31
- # Docs
32
- gem.add_development_dependency 'relish'
33
- gem.add_development_dependency 'yard', '~> 0.8.7.6'
34
-
35
- # Development
36
- gem.add_development_dependency 'guard', '~> 2.13.0'
37
- gem.add_development_dependency 'guard-bundler', '~> 2.1.0'
38
- gem.add_development_dependency 'guard-cucumber', '~> 2.0.0'
39
- gem.add_development_dependency 'guard-rspec', '~> 4.6.4'
40
- gem.add_development_dependency 'guard-rubocop', '~> 1.2.0'
41
-
42
- # Test
43
- gem.add_development_dependency 'aruba', '~> 0.11.2'
44
- gem.add_development_dependency 'codeclimate-test-reporter'
45
- gem.add_development_dependency 'coveralls', '~> 0.8.10'
46
- gem.add_development_dependency 'cucumber', '~> 2.1.0'
47
- gem.add_development_dependency 'flay', '~> 2.6.1'
48
- gem.add_development_dependency 'flog', '~> 4.3.2'
49
- gem.add_development_dependency 'rake'
50
- gem.add_development_dependency 'reek', '~> 3.7.1'
51
- gem.add_development_dependency 'rspec', '~> 3.4.0'
52
- gem.add_development_dependency 'rspec-given', '~> 3.7.1'
53
- gem.add_development_dependency 'rubocop', '~> 0.35.1'
54
32
  end
@@ -1,6 +1,10 @@
1
+ # frozen_string_literal: true
2
+
1
3
  begin
2
4
  require 'cucumber/rake/task'
3
- Cucumber::Rake::Task.new
5
+ Cucumber::Rake::Task.new do |task|
6
+ task.cucumber_opts = '--tags ~@wip'
7
+ end
4
8
  Cucumber::Rake::Task.new('cucumber:travis') do |task|
5
9
  task.cucumber_opts = '--tags ~@wip --tags ~@sudo --tags ~@shell'
6
10
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  begin
2
4
  require 'rake/tasklib'
3
5
  require 'flay'
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  begin
2
4
  require 'flog'
3
5
 
@@ -8,7 +10,7 @@ begin
8
10
  threshold = 10
9
11
 
10
12
  bad_methods = flog.totals.select do |name, score|
11
- !(/##{flog.no_method}$/ =~ name) && score > threshold
13
+ /##{flog.no_method}$/ !~ name && score > threshold
12
14
  end
13
15
  bad_methods.sort { |a, b| a[1] <=> b[1] }.reverse_each do |name, score|
14
16
  printf "%8.1f: %s\n", score, name
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  begin
2
4
  unless Dir.glob(File.join(__dir__, '../*.gemspec')).empty?
3
5
  require 'bundler/gem_tasks'
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'rake/testtask'
4
+
5
+ Rake::TestTask.new do |t|
6
+ t.test_files = FileList['test/**/*_test.rb']
7
+ end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  begin
2
4
  require 'reek/rake/task'
3
5
  Reek::Rake::Task.new do |t|
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  begin
2
4
  require 'rubocop/rake_task'
3
5
  RuboCop::RakeTask.new
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  begin
2
4
  require 'yard'
3
5
  YARD::Rake::YardocTask.new do |t|
@@ -0,0 +1,85 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'active_support/core_ext/array/access'
4
+ require 'minitest/autorun'
5
+ require 'phut/link'
6
+
7
+ module Phut
8
+ class LinkTest < Minitest::Test
9
+ def test_link_all
10
+ assert Link.all.empty?
11
+
12
+ Link.create :switch1, :switch2
13
+ assert_equal 1, Link.all.size
14
+ assert_equal %w[switch1 switch2], Link.all.first.ends.map(&:name)
15
+
16
+ Link.create :host1, :host2
17
+ assert_equal 2, Link.all.size
18
+ assert_equal %w[host1 host2], Link.all.second.ends.map(&:name)
19
+ end
20
+
21
+ def test_link_find
22
+ assert_nil Link.find(:switch1, :switch2)
23
+
24
+ link = Link.create(:switch1, :switch2)
25
+ assert_equal link, Link.find(:switch1, :switch2)
26
+ assert_equal link, Link.find(:switch2, :switch1)
27
+ assert_equal link, Link.find('switch1', 'switch2')
28
+ assert_equal link, Link.find('switch2', 'switch1')
29
+ end
30
+
31
+ def test_start
32
+ link = Link.new(:switch1, :switch2)
33
+ link.start
34
+
35
+ assert_equal link, Link.all.first
36
+ assert_equal link, link.start
37
+ end
38
+
39
+ def test_destroy
40
+ link = Link.create(:switch1, :switch2)
41
+
42
+ link.destroy
43
+ assert Link.all.empty?
44
+ end
45
+
46
+ def test_ends
47
+ link = Link.create(:switch1, :switch2)
48
+
49
+ assert_equal 2, link.ends.size
50
+ assert_equal 'switch1', link.ends.first.name
51
+ assert_equal 'switch2', link.ends.second.name
52
+ end
53
+
54
+ def test_device
55
+ link1 = Link.create(:switch1, :switch2)
56
+ link2 = Link.create(:host1, :host2)
57
+
58
+ assert_equal 'L0_switch1', link1.device(:switch1).to_s
59
+ assert_equal 'L0_switch1', link1.device('switch1').to_s
60
+ assert_equal 'L0_switch2', link1.device(:switch2).to_s
61
+ assert_equal 'L0_switch2', link1.device('switch2').to_s
62
+
63
+ assert_equal 'L1_host1', link2.device(:host1).to_s
64
+ assert_equal 'L1_host1', link2.device('host1').to_s
65
+ assert_equal 'L1_host2', link2.device(:host2).to_s
66
+ assert_equal 'L1_host2', link2.device('host2').to_s
67
+
68
+ assert_nil link1.device(:firewall)
69
+ end
70
+
71
+ private
72
+
73
+ def setup
74
+ log_dir = File.expand_path('../../log', __dir__)
75
+ Phut.logger = ::Logger.new("#{log_dir}/test.log")
76
+ end
77
+
78
+ def teardown
79
+ `ifconfig -a`.split("\n").each do |each|
80
+ next unless /^(#{Veth::PREFIX}\S+)/ =~ each
81
+ system "sudo ip link delete #{Regexp.last_match(1)} 2>/dev/null"
82
+ end
83
+ end
84
+ end
85
+ end
@@ -0,0 +1,58 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'active_support/core_ext/array/access'
4
+ require 'minitest/autorun'
5
+ require 'phut/link'
6
+ require 'phut/netns'
7
+
8
+ module Phut
9
+ class NetnsTest < Minitest::Test
10
+ def test_netns_all
11
+ assert Netns.all.empty?
12
+
13
+ link = Link.create('host1', 'host2')
14
+
15
+ host1 = Netns.create(name: 'host1', ip_address: '192.168.0.1')
16
+ host1.device = link.device('host1')
17
+ assert_equal 1, Netns.all.size
18
+ assert_equal 'host1', Netns.all.first.name
19
+ assert_equal '192.168.0.1', Netns.all.first.ip_address
20
+
21
+ host2 = Netns.create(name: 'host2', ip_address: '192.168.0.1')
22
+ host2.device = link.device('host2')
23
+ assert_equal 2, Netns.all.size
24
+ assert_equal 'host2', Netns.all.second.name
25
+ assert_equal '192.168.0.1', Netns.all.second.ip_address
26
+ end
27
+
28
+ def test_netns_create
29
+ netns = Netns.create(name: 'netns',
30
+ ip_address: '192.168.8.6',
31
+ netmask: '255.255.255.0',
32
+ route: { net: '0.0.0.0', gateway: '192.168.8.1' })
33
+ assert_equal 'netns', netns.name
34
+ assert_equal '192.168.8.6', netns.ip_address
35
+ end
36
+
37
+ def test_device
38
+ link = Link.create('host', 'switch')
39
+ netns = Netns.create(name: 'netns', ip_address: '192.168.0.1')
40
+
41
+ netns.device = link.device('host')
42
+
43
+ assert_equal 'host', netns.device.name
44
+ end
45
+
46
+ private
47
+
48
+ def setup
49
+ Netns.destroy_all
50
+ Link.destroy_all
51
+ end
52
+
53
+ def teardown
54
+ Netns.destroy_all
55
+ Link.destroy_all
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,125 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'minitest/autorun'
4
+ require 'phut/open_vswitch'
5
+
6
+ module Phut
7
+ class OpenVswitchTest < Minitest::Test
8
+ def test_open_vswitch_all
9
+ assert OpenVswitch.all.empty?
10
+
11
+ OpenVswitch.create(dpid: 0xc001)
12
+ assert_equal 1, OpenVswitch.all.size
13
+ assert_equal 0xc001, OpenVswitch.all.first.dpid
14
+ assert_equal '0xc001', OpenVswitch.all.first.name
15
+ assert_equal '0xc001', OpenVswitch.all.first.bridge
16
+ assert_equal 1.0, OpenVswitch.all.first.openflow_version
17
+ assert_equal 6653, OpenVswitch.all.first.tcp_port
18
+
19
+ OpenVswitch.create(dpid: 0xdad1)
20
+ assert_equal 2, OpenVswitch.all.size
21
+ assert_equal 0xdad1, OpenVswitch.all.second.dpid
22
+ assert_equal '0xdad1', OpenVswitch.all.second.name
23
+ assert_equal '0xdad1', OpenVswitch.all.second.bridge
24
+ assert_equal 1.0, OpenVswitch.all.second.openflow_version
25
+ assert_equal 6653, OpenVswitch.all.second.tcp_port
26
+ end
27
+
28
+ def test_open_vswitch_create_with_dpid
29
+ vswitch = OpenVswitch.create(dpid: 0xc001)
30
+ assert_equal 0xc001, vswitch.dpid
31
+ assert_equal '0xc001', vswitch.name
32
+ assert_equal '0xc001', vswitch.bridge
33
+ assert_equal 1.0, vswitch.openflow_version
34
+ assert_equal 6653, vswitch.tcp_port
35
+
36
+ assert_raises(RuntimeError) do
37
+ OpenVswitch.create(dpid: 0xc001)
38
+ end
39
+ end
40
+
41
+ def test_open_vswitch_create_with_name_and_dpid
42
+ vswitch = OpenVswitch.create(name: 'dadi', dpid: 0xc001)
43
+ assert_equal 0xc001, vswitch.dpid
44
+ assert_equal 'dadi', vswitch.name
45
+ assert_equal 'dadi', vswitch.bridge
46
+ assert_equal 1.0, vswitch.openflow_version
47
+ assert_equal 6653, vswitch.tcp_port
48
+
49
+ assert_raises(RuntimeError) do
50
+ OpenVswitch.create(name: 'dadi', dpid: 0xc001)
51
+ end
52
+ end
53
+
54
+ def test_open_vswitch_create_exceptions
55
+ assert_raises(RuntimeError) do
56
+ OpenVswitch.create(dpid: 0xdad1, name: '1234567890123456')
57
+ end
58
+
59
+ assert_raises(RuntimeError) do
60
+ OpenVswitch.create(dpid: 0xdad1, openflow_version: 999)
61
+ end
62
+
63
+ assert_raises(RuntimeError) do
64
+ OpenVswitch.create(dpid: 0xdad1, tcp_port: -999)
65
+ end
66
+ end
67
+
68
+ def test_open_vswitch_find_by
69
+ OpenVswitch.create(dpid: 0xc001)
70
+ vswitch = OpenVswitch.find_by(dpid: 0xc001)
71
+ assert_equal '0xc001', vswitch.name
72
+ assert_equal 0xc001, vswitch.dpid
73
+ end
74
+
75
+ def test_open_vswitch_destroy
76
+ OpenVswitch.create(dpid: 0xc001)
77
+ OpenVswitch.destroy('0xc001')
78
+ assert OpenVswitch.all.empty?
79
+ end
80
+
81
+ def test_open_vswitch_destroy_all
82
+ OpenVswitch.create(dpid: 0xc001)
83
+ OpenVswitch.destroy_all
84
+ assert OpenVswitch.all.empty?
85
+ end
86
+
87
+ def test_new
88
+ assert_raises(NoMethodError) do
89
+ OpenVswitch.new
90
+ end
91
+ end
92
+
93
+ def test_destroy
94
+ vswitch = OpenVswitch.create(dpid: 0xc001)
95
+ vswitch.destroy
96
+ assert OpenVswitch.all.empty?
97
+ end
98
+
99
+ def test_stop
100
+ vswitch = OpenVswitch.create(dpid: 0xc001)
101
+ vswitch.stop
102
+ assert vswitch.tcp_port.nil?
103
+ end
104
+
105
+ def test_dump_flows
106
+ vswitch = OpenVswitch.create(dpid: 0xc001)
107
+ assert_equal '', vswitch.dump_flows
108
+ end
109
+
110
+ def test_add_port
111
+ vswitch = OpenVswitch.create(dpid: 0xc001)
112
+ vswitch.add_port 'port1'
113
+ assert_equal ['port1'], vswitch.ports
114
+ end
115
+
116
+ private
117
+
118
+ def teardown
119
+ `sudo ovs-vsctl list-br`.chomp.split.each do |each|
120
+ next unless /^#{OpenVswitch.bridge_prefix}/ =~ each
121
+ system "sudo ovs-vsctl del-br #{each}"
122
+ end
123
+ end
124
+ end
125
+ end