pio 0.10.1 → 0.11.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (59) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +6 -0
  3. data/README.md +33 -2
  4. data/examples/echo_read.rb +1 -1
  5. data/examples/features_read.rb +1 -1
  6. data/examples/flow_mod_new.rb +13 -0
  7. data/examples/flow_mod_read.rb +6 -0
  8. data/features/echo_read.feature +27 -3
  9. data/features/features_read.feature +46 -2
  10. data/features/flow_mod_read.feature +186 -0
  11. data/features/hello_read.feature +9 -0
  12. data/features/packet_data/flow_mod_add.raw +0 -0
  13. data/features/packet_data/flow_mod_delete.raw +0 -0
  14. data/features/packet_data/flow_mod_delete_strict.raw +0 -0
  15. data/features/packet_data/flow_mod_modify.raw +0 -0
  16. data/features/packet_data/flow_mod_modify_strict.raw +0 -0
  17. data/features/packet_in_read.feature +13 -0
  18. data/features/packet_out_read.feature +16 -0
  19. data/features/step_definitions/packet_data_steps.rb +10 -1
  20. data/lib/pio.rb +1 -0
  21. data/lib/pio/echo.rb +10 -8
  22. data/lib/pio/enqueue.rb +1 -1
  23. data/lib/pio/features.rb +64 -7
  24. data/lib/pio/flow_mod.rb +86 -0
  25. data/lib/pio/hello.rb +4 -74
  26. data/lib/pio/ipv4_address.rb +1 -1
  27. data/lib/pio/match.rb +167 -0
  28. data/lib/pio/open_flow.rb +1 -0
  29. data/lib/pio/open_flow/actions.rb +65 -0
  30. data/lib/pio/open_flow/flags.rb +12 -9
  31. data/lib/pio/open_flow/message.rb +105 -21
  32. data/lib/pio/open_flow/phy_port.rb +31 -27
  33. data/lib/pio/open_flow/type.rb +1 -0
  34. data/lib/pio/packet_in.rb +2 -12
  35. data/lib/pio/packet_out.rb +4 -74
  36. data/lib/pio/send_out_port.rb +1 -0
  37. data/lib/pio/type/ip_address.rb +2 -7
  38. data/lib/pio/version.rb +1 -1
  39. data/pio.gemspec +8 -8
  40. data/spec/pio/echo/reply_spec.rb +61 -6
  41. data/spec/pio/echo/request_spec.rb +61 -6
  42. data/spec/pio/features/reply_spec.rb +81 -4
  43. data/spec/pio/features/request_spec.rb +88 -41
  44. data/spec/pio/flow_mod_spec.rb +151 -0
  45. data/spec/pio/hello_spec.rb +73 -56
  46. data/spec/pio/match_spec.rb +194 -0
  47. data/spec/pio/packet_in_spec.rb +35 -38
  48. data/spec/pio/packet_out_spec.rb +243 -182
  49. data/spec/pio/wildcards_spec.rb +115 -0
  50. metadata +37 -30
  51. data/features/packet_data/echo.raw +0 -0
  52. data/lib/pio/echo/message.rb +0 -49
  53. data/lib/pio/echo/reply.rb +0 -41
  54. data/lib/pio/echo/request.rb +0 -43
  55. data/lib/pio/features/reply.rb +0 -88
  56. data/lib/pio/features/request.rb +0 -68
  57. data/lib/pio/open_flow/parser.rb +0 -22
  58. data/spec/pio/echo_spec.rb +0 -49
  59. data/spec/pio/features_spec.rb +0 -96
@@ -1,6 +1,7 @@
1
1
  require 'bindata'
2
2
  require 'forwardable'
3
3
  require 'pio/monkey_patch/integer'
4
+ require 'pio/open_flow/port_number'
4
5
 
5
6
  module Pio
6
7
  # An action to output a packet to a port.
@@ -8,16 +8,11 @@ module Pio
8
8
  array :octets, type: :uint8, initial_length: 4
9
9
 
10
10
  def set(value)
11
- case value
12
- when String
13
- self.octets = value.split('.').map(&:to_i)
14
- else
15
- self.octets = value
16
- end
11
+ self.octets = IPv4Address.new(value).to_a
17
12
  end
18
13
 
19
14
  def get
20
- IPv4Address.new octets.map { |each| format('%d', each) }.join('.')
15
+ IPv4Address.new(octets.map { |each| format('%d', each) }.join('.'))
21
16
  end
22
17
 
23
18
  def ==(other)
data/lib/pio/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  # Base module.
2
2
  module Pio
3
3
  # gem version.
4
- VERSION = '0.10.1'.freeze
4
+ VERSION = '0.11.0'.freeze
5
5
  end
data/pio.gemspec CHANGED
@@ -37,11 +37,11 @@ Gem::Specification.new do |gem|
37
37
  gem.add_dependency 'bindata', '~> 2.1.0'
38
38
 
39
39
  gem.add_development_dependency 'rake'
40
- gem.add_development_dependency 'bundler', '~> 1.7.11'
40
+ gem.add_development_dependency 'bundler', '~> 1.7.12'
41
41
  gem.add_development_dependency 'pry', '~> 0.10.1'
42
42
 
43
43
  # Guard
44
- gem.add_development_dependency 'guard', '~> 2.10.5'
44
+ gem.add_development_dependency 'guard', '~> 2.11.1'
45
45
  gem.add_development_dependency 'guard-bundler', '~> 2.1.0'
46
46
  gem.add_development_dependency 'guard-cucumber', '~> 1.5.3'
47
47
  gem.add_development_dependency 'guard-rspec', '~> 4.5.0'
@@ -52,17 +52,17 @@ Gem::Specification.new do |gem|
52
52
  gem.add_development_dependency 'terminal-notifier-guard', '~> 1.6.4'
53
53
 
54
54
  # Docs
55
- gem.add_development_dependency 'inch', '~> 0.5.8'
55
+ gem.add_development_dependency 'inch', '~> 0.5.10'
56
56
  gem.add_development_dependency 'yard', '~> 0.8.7.6'
57
57
 
58
58
  # Test
59
- gem.add_development_dependency 'codeclimate-test-reporter', '~> 0.4.4'
59
+ gem.add_development_dependency 'codeclimate-test-reporter', '~> 0.4.5'
60
60
  gem.add_development_dependency 'coveralls', '~> 0.7.2'
61
61
  gem.add_development_dependency 'cucumber', '~> 1.3.18'
62
- gem.add_development_dependency 'flay', '~> 2.5.0'
63
- gem.add_development_dependency 'flog', '~> 4.3.0'
64
- gem.add_development_dependency 'reek', '~> 1.5.1'
62
+ gem.add_development_dependency 'flay', '~> 2.6.0'
63
+ gem.add_development_dependency 'flog', '~> 4.3.1'
64
+ gem.add_development_dependency 'reek', '~> 1.6.2'
65
65
  gem.add_development_dependency 'rspec', '~> 3.1.0'
66
- gem.add_development_dependency 'rspec-given', '~> 3.5.4'
66
+ gem.add_development_dependency 'rspec-given', '~> 3.6.0'
67
67
  gem.add_development_dependency 'rubocop', '~> 0.28.0'
68
68
  end
@@ -1,6 +1,34 @@
1
1
  require 'pio/echo'
2
2
 
3
3
  describe Pio::Echo::Reply do
4
+ describe '.read' do
5
+ When(:echo_reply) { Pio::Echo::Reply.read(binary) }
6
+
7
+ context 'with an echo reply message' do
8
+ Given(:binary) { [1, 3, 0, 8, 0, 0, 0, 0].pack('C*') }
9
+
10
+ Then { echo_reply.ofp_version == 1 }
11
+ Then { echo_reply.message_type == Pio::OpenFlow::Type::ECHO_REPLY }
12
+ Then { echo_reply.message_length == 8 }
13
+ Then { echo_reply.transaction_id == 0 }
14
+ Then { echo_reply.xid == 0 }
15
+ Then { echo_reply.user_data.empty? }
16
+ Then { echo_reply.user_data == '' }
17
+ Then { echo_reply.body.empty? }
18
+ Then { echo_reply.body == '' }
19
+ Then { echo_reply.to_binary == [1, 3, 0, 8, 0, 0, 0, 0].pack('C*') }
20
+ end
21
+
22
+ context 'with a hello message' do
23
+ Given(:binary) { [1, 0, 0, 8, 0, 0, 0, 0].pack('C*') }
24
+
25
+ Then do
26
+ echo_reply ==
27
+ Failure(Pio::ParseError, 'Invalid Echo Reply message.')
28
+ end
29
+ end
30
+ end
31
+
4
32
  describe '.new' do
5
33
  context 'with no arguments' do
6
34
  When(:echo_reply) { Pio::Echo::Reply.new }
@@ -10,7 +38,10 @@ describe Pio::Echo::Reply do
10
38
  Then { echo_reply.message_length == 8 }
11
39
  Then { echo_reply.transaction_id == 0 }
12
40
  Then { echo_reply.xid == 0 }
41
+ Then { echo_reply.user_data.empty? }
13
42
  Then { echo_reply.user_data == '' }
43
+ Then { echo_reply.body.empty? }
44
+ Then { echo_reply.body == '' }
14
45
  Then { echo_reply.to_binary == [1, 3, 0, 8, 0, 0, 0, 0].pack('C*') }
15
46
  end
16
47
 
@@ -22,16 +53,13 @@ describe Pio::Echo::Reply do
22
53
  Then { echo_reply.message_length == 8 }
23
54
  Then { echo_reply.transaction_id == 123 }
24
55
  Then { echo_reply.xid == 123 }
56
+ Then { echo_reply.user_data.empty? }
25
57
  Then { echo_reply.user_data == '' }
58
+ Then { echo_reply.body.empty? }
59
+ Then { echo_reply.body == '' }
26
60
  Then { echo_reply.to_binary == [1, 3, 0, 8, 0, 0, 0, 123].pack('C*') }
27
61
  end
28
62
 
29
- context 'with 2**32' do
30
- When(:result) { Pio::Echo::Reply.new(2**32) }
31
-
32
- Then { result == Failure(ArgumentError) }
33
- end
34
-
35
63
  context 'with transaction_id: 123' do
36
64
  When(:echo_reply) { Pio::Echo::Reply.new(transaction_id: 123) }
37
65
 
@@ -40,7 +68,10 @@ describe Pio::Echo::Reply do
40
68
  Then { echo_reply.message_length == 8 }
41
69
  Then { echo_reply.transaction_id == 123 }
42
70
  Then { echo_reply.xid == 123 }
71
+ Then { echo_reply.user_data.empty? }
43
72
  Then { echo_reply.user_data == '' }
73
+ Then { echo_reply.body.empty? }
74
+ Then { echo_reply.body == '' }
44
75
  Then { echo_reply.to_binary == [1, 3, 0, 8, 0, 0, 0, 123].pack('C*') }
45
76
  end
46
77
 
@@ -52,7 +83,10 @@ describe Pio::Echo::Reply do
52
83
  Then { echo_reply.message_length == 8 }
53
84
  Then { echo_reply.transaction_id == 123 }
54
85
  Then { echo_reply.xid == 123 }
86
+ Then { echo_reply.user_data.empty? }
55
87
  Then { echo_reply.user_data == '' }
88
+ Then { echo_reply.body.empty? }
89
+ Then { echo_reply.body == '' }
56
90
  Then { echo_reply.to_binary == [1, 3, 0, 8, 0, 0, 0, 123].pack('C*') }
57
91
  end
58
92
 
@@ -65,12 +99,33 @@ describe Pio::Echo::Reply do
65
99
  Then { echo_reply.transaction_id == 123 }
66
100
  Then { echo_reply.xid == 123 }
67
101
  Then { echo_reply.user_data == 'foobar' }
102
+ Then { echo_reply.body == 'foobar' }
68
103
  Then do
69
104
  echo_reply.to_binary ==
70
105
  [1, 3, 0, 14, 0, 0, 0, 123, 102, 111, 111, 98, 97, 114].pack('C*')
71
106
  end
72
107
  end
73
108
 
109
+ context 'with -1' do
110
+ When(:result) { Pio::Echo::Reply.new(-1) }
111
+
112
+ Then do
113
+ result ==
114
+ Failure(ArgumentError,
115
+ 'Transaction ID should be an unsigned 32-bit integer.')
116
+ end
117
+ end
118
+
119
+ context 'with 2**32' do
120
+ When(:result) { Pio::Echo::Reply.new(2**32) }
121
+
122
+ Then do
123
+ result ==
124
+ Failure(ArgumentError,
125
+ 'Transaction ID should be an unsigned 32-bit integer.')
126
+ end
127
+ end
128
+
74
129
  context 'with :INVALID_ARGUMENT' do
75
130
  When(:result) { Pio::Echo::Reply.new(:INVALID_ARGUMENT) }
76
131
 
@@ -1,6 +1,34 @@
1
1
  require 'pio/echo'
2
2
 
3
3
  describe Pio::Echo::Request do
4
+ describe '.read' do
5
+ When(:echo_request) { Pio::Echo::Request.read(binary) }
6
+
7
+ context 'with an echo request message' do
8
+ Given(:binary) { [1, 2, 0, 8, 0, 0, 0, 0].pack('C*') }
9
+
10
+ Then { echo_request.ofp_version == 1 }
11
+ Then { echo_request.message_type == Pio::OpenFlow::Type::ECHO_REQUEST }
12
+ Then { echo_request.message_length == 8 }
13
+ Then { echo_request.transaction_id == 0 }
14
+ Then { echo_request.xid == 0 }
15
+ Then { echo_request.user_data.empty? }
16
+ Then { echo_request.user_data == '' }
17
+ Then { echo_request.body.empty? }
18
+ Then { echo_request.body == '' }
19
+ Then { echo_request.to_binary == [1, 2, 0, 8, 0, 0, 0, 0].pack('C*') }
20
+ end
21
+
22
+ context 'with a hello message' do
23
+ Given(:binary) { [1, 0, 0, 8, 0, 0, 0, 0].pack('C*') }
24
+
25
+ Then do
26
+ echo_request ==
27
+ Failure(Pio::ParseError, 'Invalid Echo Request message.')
28
+ end
29
+ end
30
+ end
31
+
4
32
  describe '.new' do
5
33
  context 'with no arguments' do
6
34
  When(:echo_request) { Pio::Echo::Request.new }
@@ -11,6 +39,9 @@ describe Pio::Echo::Request do
11
39
  Then { echo_request.transaction_id == 0 }
12
40
  Then { echo_request.xid == 0 }
13
41
  Then { echo_request.user_data.empty? }
42
+ Then { echo_request.user_data == '' }
43
+ Then { echo_request.body.empty? }
44
+ Then { echo_request.body == '' }
14
45
  Then { echo_request.to_binary == [1, 2, 0, 8, 0, 0, 0, 0].pack('C*') }
15
46
  end
16
47
 
@@ -23,15 +54,12 @@ describe Pio::Echo::Request do
23
54
  Then { echo_request.transaction_id == 123 }
24
55
  Then { echo_request.xid == 123 }
25
56
  Then { echo_request.user_data.empty? }
57
+ Then { echo_request.user_data == '' }
58
+ Then { echo_request.body.empty? }
59
+ Then { echo_request.body == '' }
26
60
  Then { echo_request.to_binary == [1, 2, 0, 8, 0, 0, 0, 123].pack('C*') }
27
61
  end
28
62
 
29
- context 'with 2**32' do
30
- When(:result) { Pio::Echo::Request.new(2**32) }
31
-
32
- Then { result == Failure(ArgumentError) }
33
- end
34
-
35
63
  context 'with transaction_id: 123' do
36
64
  When(:echo_request) { Pio::Echo::Request.new(transaction_id: 123) }
37
65
 
@@ -41,6 +69,9 @@ describe Pio::Echo::Request do
41
69
  Then { echo_request.transaction_id == 123 }
42
70
  Then { echo_request.xid == 123 }
43
71
  Then { echo_request.user_data.empty? }
72
+ Then { echo_request.user_data == '' }
73
+ Then { echo_request.body.empty? }
74
+ Then { echo_request.body == '' }
44
75
  Then { echo_request.to_binary == [1, 2, 0, 8, 0, 0, 0, 123].pack('C*') }
45
76
  end
46
77
 
@@ -53,6 +84,9 @@ describe Pio::Echo::Request do
53
84
  Then { echo_request.transaction_id == 123 }
54
85
  Then { echo_request.xid == 123 }
55
86
  Then { echo_request.user_data.empty? }
87
+ Then { echo_request.user_data == '' }
88
+ Then { echo_request.body.empty? }
89
+ Then { echo_request.body == '' }
56
90
  Then { echo_request.to_binary == [1, 2, 0, 8, 0, 0, 0, 123].pack('C*') }
57
91
  end
58
92
 
@@ -67,12 +101,33 @@ describe Pio::Echo::Request do
67
101
  Then { echo_request.transaction_id == 123 }
68
102
  Then { echo_request.xid == 123 }
69
103
  Then { echo_request.user_data == 'foobar' }
104
+ Then { echo_request.body == 'foobar' }
70
105
  Then do
71
106
  echo_request.to_binary ==
72
107
  [1, 2, 0, 14, 0, 0, 0, 123, 102, 111, 111, 98, 97, 114].pack('C*')
73
108
  end
74
109
  end
75
110
 
111
+ context 'with -1' do
112
+ When(:result) { Pio::Echo::Request.new(-1) }
113
+
114
+ Then do
115
+ result ==
116
+ Failure(ArgumentError,
117
+ 'Transaction ID should be an unsigned 32-bit integer.')
118
+ end
119
+ end
120
+
121
+ context 'with 2**32' do
122
+ When(:result) { Pio::Echo::Request.new(2**32) }
123
+
124
+ Then do
125
+ result ==
126
+ Failure(ArgumentError,
127
+ 'Transaction ID should be an unsigned 32-bit integer.')
128
+ end
129
+ end
130
+
76
131
  context 'with :INVALID_ARGUMENT' do
77
132
  When(:result) { Pio::Echo::Request.new(:INVALID_ARGUMENT) }
78
133
 
@@ -1,6 +1,83 @@
1
1
  require 'pio/features'
2
2
 
3
3
  describe Pio::Features::Reply do
4
+ context 'with a Features Reply message' do
5
+ When(:result) { Pio::Features::Reply.read(binary) }
6
+
7
+ describe '.read' do
8
+ Given(:binary) do
9
+ [0x01, 0x06, 0x00, 0xb0, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00,
10
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x01, 0x00,
11
+ 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x87, 0x00, 0x00,
12
+ 0x0f, 0xff, 0x00, 0x02, 0x16, 0x7d, 0xa4, 0x37, 0xba, 0x10,
13
+ 0x74, 0x72, 0x65, 0x6d, 0x61, 0x30, 0x2d, 0x30, 0x00, 0x00,
14
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
15
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00,
16
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
17
+ 0xff, 0xfe, 0x2a, 0xb4, 0xd6, 0x3c, 0x66, 0xba, 0x76, 0x73,
18
+ 0x77, 0x5f, 0x30, 0x78, 0x31, 0x00, 0x00, 0x00, 0x00, 0x00,
19
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00,
20
+ 0x00, 0x01, 0x00, 0x00, 0x00, 0x82, 0x00, 0x00, 0x00, 0x00,
21
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
22
+ 0x62, 0x94, 0x3a, 0xf6, 0x40, 0xdb, 0x74, 0x72, 0x65, 0x6d,
23
+ 0x61, 0x31, 0x2d, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
24
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
25
+ 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
26
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00].pack('C*')
27
+ end
28
+
29
+ Then { result.class == Pio::Features::Reply }
30
+ Then { result.ofp_version == 1 }
31
+ Then do
32
+ result.message_type ==
33
+ Pio::OpenFlow::Type::FEATURES_REPLY
34
+ end
35
+ Then { result.message_length == 176 }
36
+ Then { result.transaction_id == 2 }
37
+ Then { result.xid == 2 }
38
+ Then { !result.body.empty? }
39
+ Then { result.datapath_id == 1 }
40
+ Then { result.n_buffers == 0x100 }
41
+ Then { result.n_tables == 1 }
42
+ Then do
43
+ result.capabilities ==
44
+ [:flow_stats, :table_stats, :port_stats, :arp_match_ip]
45
+ end
46
+ Then do
47
+ result.actions ==
48
+ [:output, :set_vlan_vid, :set_vlan_pcp, :strip_vlan,
49
+ :set_dl_src, :set_dl_dst, :set_nw_src, :set_nw_dst,
50
+ :set_nw_tos, :set_tp_src, :set_tp_dst, :enqueue]
51
+ end
52
+ Then { result.ports.size == 3 }
53
+ Then { result.ports.all? { |each| each.port_no > 0 } }
54
+ Then do
55
+ result.ports.all? do |each|
56
+ /^([0-9a-fA-F]{2}[:-]){5}[0-9a-fA-F]{2}$/i=~
57
+ each.hardware_address.to_s
58
+ end
59
+ end
60
+ Then { result.ports.all? { |each| !each.name.empty? } }
61
+ Then { result.ports.any? { |each| each.config == [:port_down] } }
62
+ Then { result.ports.any? { |each| each.state == [:link_down] } }
63
+ Then { result.ports.all? { |each| each.curr.include? :port_copper } }
64
+ Then { result.ports.all? { |each| each.advertised.empty? } }
65
+ Then { result.ports.all? { |each| each.supported.empty? } }
66
+ Then { result.ports.all? { |each| each.peer.empty? } }
67
+ end
68
+
69
+ context 'with a Hello message' do
70
+ Given(:binary) { [1, 0, 0, 8, 0, 0, 0, 0].pack('C*') }
71
+
72
+ When(:result) { Pio::Features::Reply.read(binary) }
73
+
74
+ Then do
75
+ result == Failure(Pio::ParseError,
76
+ 'Invalid Features Reply message.')
77
+ end
78
+ end
79
+ end
80
+
4
81
  Given(:options) do
5
82
  {
6
83
  dpid: 0x123,
@@ -50,11 +127,11 @@ describe Pio::Features::Reply do
50
127
  Then { features_reply.ports[0].advertised.empty? }
51
128
  Then { features_reply.ports[0].supported.empty? }
52
129
  Then { features_reply.ports[0].peer.empty? }
53
- end
54
130
 
55
- describe '#to_binary' do
56
- When(:binary) { Pio::Features::Reply.new(options).to_binary }
131
+ describe '#to_binary' do
132
+ When(:result) { Pio::Features::Reply.new(options).to_binary }
57
133
 
58
- Then { binary.length > 0 }
134
+ Then { result.length > 0 }
135
+ end
59
136
  end
60
137
  end
@@ -1,59 +1,106 @@
1
1
  require 'pio/features'
2
2
 
3
3
  describe Pio::Features::Request do
4
+ describe '.read' do
5
+ When(:result) { Pio::Features::Request.read(binary) }
6
+
7
+ context 'with a Features Request message' do
8
+ Given(:binary) { [1, 5, 0, 8, 0, 0, 0, 0].pack('C*') }
9
+
10
+ Then { result.class == Pio::Features::Request }
11
+ Then { result.ofp_version == 1 }
12
+ Then do
13
+ result.message_type ==
14
+ Pio::OpenFlow::Type::FEATURES_REQUEST
15
+ end
16
+ Then { result.message_length == 8 }
17
+ Then { result.transaction_id == 0 }
18
+ Then { result.xid == 0 }
19
+ Then { result.body.empty? }
20
+ Then { result.body == '' }
21
+ end
22
+
23
+ context 'with a Hello message' do
24
+ Given(:binary) { [1, 0, 0, 8, 0, 0, 0, 0].pack('C*') }
25
+
26
+ Then do
27
+ result == Failure(Pio::ParseError,
28
+ 'Invalid Features Request message.')
29
+ end
30
+ end
31
+ end
32
+
4
33
  describe '.new' do
5
34
  context 'with no arguments' do
6
- When(:request) { Pio::Features::Request.new }
7
-
8
- Then { request.ofp_version == 1 }
9
- Then { request.message_type == Pio::OpenFlow::Type::FEATURES_REQUEST }
10
- Then { request.message_length == 8 }
11
- Then { request.transaction_id == 0 }
12
- Then { request.xid == 0 }
13
- Then { request.body.empty? }
14
- Then { request.to_binary == [1, 5, 0, 8, 0, 0, 0, 0].pack('C*') }
15
- end
35
+ When(:result) { Pio::Features::Request.new }
16
36
 
17
- context 'with 123' do
18
- When(:request) { Pio::Features::Request.new(123) }
19
-
20
- Then { request.ofp_version == 1 }
21
- Then { request.message_type == Pio::OpenFlow::Type::FEATURES_REQUEST }
22
- Then { request.message_length == 8 }
23
- Then { request.transaction_id == 123 }
24
- Then { request.xid == 123 }
25
- Then { request.body.empty? }
26
- Then { request.to_binary == [1, 5, 0, 8, 0, 0, 0, 123].pack('C*') }
37
+ Then { result.ofp_version == 1 }
38
+ Then { result.message_type == Pio::OpenFlow::Type::FEATURES_REQUEST }
39
+ Then { result.message_length == 8 }
40
+ Then { result.transaction_id == 0 }
41
+ Then { result.xid == 0 }
42
+ Then { result.body.empty? }
43
+ Then { result.body == '' }
44
+ Then { result.to_binary == [1, 5, 0, 8, 0, 0, 0, 0].pack('C*') }
27
45
  end
28
46
 
29
- context 'with 2**32' do
30
- When(:result) { Pio::Features::Request.new(2**32) }
47
+ context 'with 123' do
48
+ When(:result) { Pio::Features::Request.new(123) }
31
49
 
32
- Then { result == Failure(ArgumentError) }
50
+ Then { result.ofp_version == 1 }
51
+ Then { result.message_type == Pio::OpenFlow::Type::FEATURES_REQUEST }
52
+ Then { result.message_length == 8 }
53
+ Then { result.transaction_id == 123 }
54
+ Then { result.xid == 123 }
55
+ Then { result.body.empty? }
56
+ Then { result.body == '' }
57
+ Then { result.to_binary == [1, 5, 0, 8, 0, 0, 0, 123].pack('C*') }
33
58
  end
34
59
 
35
60
  context 'with transaction_id: 123' do
36
- When(:request) { Pio::Features::Request.new(transaction_id: 123) }
37
-
38
- Then { request.ofp_version == 1 }
39
- Then { request.message_type == Pio::OpenFlow::Type::FEATURES_REQUEST }
40
- Then { request.message_length == 8 }
41
- Then { request.transaction_id == 123 }
42
- Then { request.xid == 123 }
43
- Then { request.body.empty? }
44
- Then { request.to_binary == [1, 5, 0, 8, 0, 0, 0, 123].pack('C*') }
61
+ When(:result) { Pio::Features::Request.new(transaction_id: 123) }
62
+
63
+ Then { result.ofp_version == 1 }
64
+ Then { result.message_type == Pio::OpenFlow::Type::FEATURES_REQUEST }
65
+ Then { result.message_length == 8 }
66
+ Then { result.transaction_id == 123 }
67
+ Then { result.xid == 123 }
68
+ Then { result.body.empty? }
69
+ Then { result.body == '' }
70
+ Then { result.to_binary == [1, 5, 0, 8, 0, 0, 0, 123].pack('C*') }
45
71
  end
46
72
 
47
73
  context 'with xid: 123' do
48
- When(:request) { Pio::Features::Request.new(xid: 123) }
49
-
50
- Then { request.ofp_version == 1 }
51
- Then { request.message_type == Pio::OpenFlow::Type::FEATURES_REQUEST }
52
- Then { request.message_length == 8 }
53
- Then { request.transaction_id == 123 }
54
- Then { request.xid == 123 }
55
- Then { request.body.empty? }
56
- Then { request.to_binary == [1, 5, 0, 8, 0, 0, 0, 123].pack('C*') }
74
+ When(:result) { Pio::Features::Request.new(xid: 123) }
75
+
76
+ Then { result.ofp_version == 1 }
77
+ Then { result.message_type == Pio::OpenFlow::Type::FEATURES_REQUEST }
78
+ Then { result.message_length == 8 }
79
+ Then { result.transaction_id == 123 }
80
+ Then { result.xid == 123 }
81
+ Then { result.body.empty? }
82
+ Then { result.body == '' }
83
+ Then { result.to_binary == [1, 5, 0, 8, 0, 0, 0, 123].pack('C*') }
84
+ end
85
+
86
+ context 'with -1' do
87
+ When(:result) { Pio::Features::Request.new(-1) }
88
+
89
+ Then do
90
+ result ==
91
+ Failure(ArgumentError,
92
+ 'Transaction ID should be an unsigned 32-bit integer.')
93
+ end
94
+ end
95
+
96
+ context 'with 2**32' do
97
+ When(:result) { Pio::Features::Request.new(2**32) }
98
+
99
+ Then do
100
+ result ==
101
+ Failure(ArgumentError,
102
+ 'Transaction ID should be an unsigned 32-bit integer.')
103
+ end
57
104
  end
58
105
 
59
106
  context 'with :INVALID_ARGUMENT' do