pio 0.10.1 → 0.11.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +6 -0
- data/README.md +33 -2
- data/examples/echo_read.rb +1 -1
- data/examples/features_read.rb +1 -1
- data/examples/flow_mod_new.rb +13 -0
- data/examples/flow_mod_read.rb +6 -0
- data/features/echo_read.feature +27 -3
- data/features/features_read.feature +46 -2
- data/features/flow_mod_read.feature +186 -0
- data/features/hello_read.feature +9 -0
- data/features/packet_data/flow_mod_add.raw +0 -0
- data/features/packet_data/flow_mod_delete.raw +0 -0
- data/features/packet_data/flow_mod_delete_strict.raw +0 -0
- data/features/packet_data/flow_mod_modify.raw +0 -0
- data/features/packet_data/flow_mod_modify_strict.raw +0 -0
- data/features/packet_in_read.feature +13 -0
- data/features/packet_out_read.feature +16 -0
- data/features/step_definitions/packet_data_steps.rb +10 -1
- data/lib/pio.rb +1 -0
- data/lib/pio/echo.rb +10 -8
- data/lib/pio/enqueue.rb +1 -1
- data/lib/pio/features.rb +64 -7
- data/lib/pio/flow_mod.rb +86 -0
- data/lib/pio/hello.rb +4 -74
- data/lib/pio/ipv4_address.rb +1 -1
- data/lib/pio/match.rb +167 -0
- data/lib/pio/open_flow.rb +1 -0
- data/lib/pio/open_flow/actions.rb +65 -0
- data/lib/pio/open_flow/flags.rb +12 -9
- data/lib/pio/open_flow/message.rb +105 -21
- data/lib/pio/open_flow/phy_port.rb +31 -27
- data/lib/pio/open_flow/type.rb +1 -0
- data/lib/pio/packet_in.rb +2 -12
- data/lib/pio/packet_out.rb +4 -74
- data/lib/pio/send_out_port.rb +1 -0
- data/lib/pio/type/ip_address.rb +2 -7
- data/lib/pio/version.rb +1 -1
- data/pio.gemspec +8 -8
- data/spec/pio/echo/reply_spec.rb +61 -6
- data/spec/pio/echo/request_spec.rb +61 -6
- data/spec/pio/features/reply_spec.rb +81 -4
- data/spec/pio/features/request_spec.rb +88 -41
- data/spec/pio/flow_mod_spec.rb +151 -0
- data/spec/pio/hello_spec.rb +73 -56
- data/spec/pio/match_spec.rb +194 -0
- data/spec/pio/packet_in_spec.rb +35 -38
- data/spec/pio/packet_out_spec.rb +243 -182
- data/spec/pio/wildcards_spec.rb +115 -0
- metadata +37 -30
- data/features/packet_data/echo.raw +0 -0
- data/lib/pio/echo/message.rb +0 -49
- data/lib/pio/echo/reply.rb +0 -41
- data/lib/pio/echo/request.rb +0 -43
- data/lib/pio/features/reply.rb +0 -88
- data/lib/pio/features/request.rb +0 -68
- data/lib/pio/open_flow/parser.rb +0 -22
- data/spec/pio/echo_spec.rb +0 -49
- data/spec/pio/features_spec.rb +0 -96
data/lib/pio/send_out_port.rb
CHANGED
data/lib/pio/type/ip_address.rb
CHANGED
@@ -8,16 +8,11 @@ module Pio
|
|
8
8
|
array :octets, type: :uint8, initial_length: 4
|
9
9
|
|
10
10
|
def set(value)
|
11
|
-
|
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
|
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
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.
|
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.
|
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.
|
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.
|
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.
|
63
|
-
gem.add_development_dependency 'flog', '~> 4.3.
|
64
|
-
gem.add_development_dependency 'reek', '~> 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.
|
66
|
+
gem.add_development_dependency 'rspec-given', '~> 3.6.0'
|
67
67
|
gem.add_development_dependency 'rubocop', '~> 0.28.0'
|
68
68
|
end
|
data/spec/pio/echo/reply_spec.rb
CHANGED
@@ -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
|
-
|
56
|
-
|
131
|
+
describe '#to_binary' do
|
132
|
+
When(:result) { Pio::Features::Reply.new(options).to_binary }
|
57
133
|
|
58
|
-
|
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(:
|
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
|
-
|
18
|
-
|
19
|
-
|
20
|
-
Then {
|
21
|
-
Then {
|
22
|
-
Then {
|
23
|
-
Then {
|
24
|
-
Then {
|
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
|
30
|
-
When(:result) { Pio::Features::Request.new(
|
47
|
+
context 'with 123' do
|
48
|
+
When(:result) { Pio::Features::Request.new(123) }
|
31
49
|
|
32
|
-
Then { result ==
|
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(:
|
37
|
-
|
38
|
-
Then {
|
39
|
-
Then {
|
40
|
-
Then {
|
41
|
-
Then {
|
42
|
-
Then {
|
43
|
-
Then {
|
44
|
-
Then {
|
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(:
|
49
|
-
|
50
|
-
Then {
|
51
|
-
Then {
|
52
|
-
Then {
|
53
|
-
Then {
|
54
|
-
Then {
|
55
|
-
Then {
|
56
|
-
Then {
|
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
|