UPnP 1.0.0 → 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.
@@ -1,10 +1,13 @@
1
1
  require 'test/unit'
2
2
  require 'test/utilities'
3
3
  require 'UPnP/SSDP'
4
+ require 'UPnP/device'
4
5
 
5
6
  class TestUPnPSSDP < UPnP::TestCase
6
7
 
7
8
  def setup
9
+ super
10
+
8
11
  @ssdp = UPnP::SSDP.new
9
12
  @ssdp.timeout = 0
10
13
  end
@@ -20,15 +23,6 @@ class TestUPnPSSDP < UPnP::TestCase
20
23
  notifications = @ssdp.discover
21
24
 
22
25
  assert_equal [], socket.sent
23
- assert_equal [Socket::INADDR_ANY, @ssdp.port], socket.bound
24
-
25
- expected = [
26
- [Socket::IPPROTO_IP, Socket::IP_TTL, [@ssdp.ttl].pack('i')],
27
- [Socket::IPPROTO_IP, Socket::IP_ADD_MEMBERSHIP,
28
- "\357\377\377\372\000\000\000\000"]
29
- ]
30
-
31
- assert_equal expected, socket.socket_options
32
26
 
33
27
  assert_equal 1, notifications.length
34
28
  assert_equal 'upnp:rootdevice', notifications.first.type
@@ -44,6 +38,24 @@ class TestUPnPSSDP < UPnP::TestCase
44
38
  assert_equal 'upnp:rootdevice', notification.type
45
39
  end
46
40
 
41
+ def test_new_socket
42
+ UPnP::SSDP.send :const_set, :UDPSocket, UPnP::FakeSocket
43
+
44
+ socket = @ssdp.new_socket
45
+
46
+ ttl = [@ssdp.ttl].pack 'i'
47
+ expected = [
48
+ [Socket::IPPROTO_IP, Socket::IP_ADD_MEMBERSHIP, "\357\377\377\372\000\000\000\000"],
49
+ [Socket::IPPROTO_IP, Socket::IP_MULTICAST_LOOP, "\000"],
50
+ [Socket::IPPROTO_IP, Socket::IP_MULTICAST_TTL, ttl],
51
+ [Socket::IPPROTO_IP, Socket::IP_TTL, ttl],
52
+ ]
53
+
54
+ assert_equal expected, socket.socket_options
55
+ ensure
56
+ UPnP::SSDP.send :remove_const, :UDPSocket
57
+ end
58
+
47
59
  def test_parse_bad
48
60
  assert_raise UPnP::SSDP::Error do
49
61
  @ssdp.parse ''
@@ -62,6 +74,12 @@ class TestUPnPSSDP < UPnP::TestCase
62
74
  assert_equal 'upnp:rootdevice', notification.type
63
75
  end
64
76
 
77
+ def test_parse_search
78
+ response = @ssdp.parse util_search
79
+
80
+ assert_equal 'upnp:rootdevice', response.target
81
+ end
82
+
65
83
  def test_parse_search_response
66
84
  response = @ssdp.parse util_search_response
67
85
 
@@ -74,8 +92,6 @@ class TestUPnPSSDP < UPnP::TestCase
74
92
 
75
93
  responses = @ssdp.search
76
94
 
77
- assert_equal nil, socket.bound
78
-
79
95
  m_search = <<-M_SEARCH
80
96
  M-SEARCH * HTTP/1.1\r
81
97
  HOST: 239.255.255.250:1900\r
@@ -87,12 +103,6 @@ ST: ssdp:all\r
87
103
 
88
104
  assert_equal [[m_search, 0, @ssdp.broadcast, @ssdp.port]], socket.sent
89
105
 
90
- expected = [
91
- [Socket::IPPROTO_IP, Socket::IP_TTL, [@ssdp.ttl].pack('i')],
92
- ]
93
-
94
- assert_equal expected, socket.socket_options
95
-
96
106
  assert_equal 1, responses.length
97
107
  assert_equal 'upnp:rootdevice', responses.first.target
98
108
  end
@@ -205,6 +215,55 @@ ST: uuid:foo\r
205
215
  assert_equal [[m_search, 0, @ssdp.broadcast, @ssdp.port]], socket.sent
206
216
  end
207
217
 
218
+ def test_send_notify
219
+ socket = UPnP::FakeSocket.new
220
+ @ssdp.socket = socket
221
+
222
+ uri = 'http://127.255.255.255:65536/description'
223
+ device = UPnP::Device.new 'TestDevice', 'test device'
224
+
225
+ @ssdp.send_notify uri, 'upnp:rootdevice', device
226
+
227
+ search = <<-SEARCH
228
+ NOTIFY * HTTP/1.1\r
229
+ HOST: 239.255.255.250:1900\r
230
+ CACHE-CONTROL: max-age=120\r
231
+ LOCATION: #{uri}\r
232
+ NT: upnp:rootdevice\r
233
+ NTS: ssdp:alive\r
234
+ SERVER: Ruby UPnP/#{UPnP::VERSION} UPnP/1.0 #{util_device_version}\r
235
+ USN: #{device.name}::upnp:rootdevice\r
236
+ \r
237
+ SEARCH
238
+
239
+ assert_equal [[search, 0, @ssdp.broadcast, @ssdp.port]], socket.sent
240
+ end
241
+
242
+ def test_send_response
243
+ socket = UPnP::FakeSocket.new
244
+ @ssdp.socket = socket
245
+
246
+ uri = 'http://127.255.255.255:65536/description'
247
+ device = UPnP::Device.new 'TestDevice', 'test device'
248
+
249
+ @ssdp.send_response uri, 'upnp:rootdevice', device.name, device
250
+
251
+ search = <<-SEARCH
252
+ HTTP/1.1 200 OK\r
253
+ CACHE-CONTROL: max-age=120\r
254
+ EXT:\r
255
+ LOCATION: #{uri}\r
256
+ SERVER: Ruby UPnP/#{UPnP::VERSION} UPnP/1.0 #{util_device_version}\r
257
+ ST: upnp:rootdevice\r
258
+ NTS: ssdp:alive\r
259
+ USN: #{device.name}\r
260
+ Content-Length: 0\r
261
+ \r
262
+ SEARCH
263
+
264
+ assert_equal [[search, 0, @ssdp.broadcast, @ssdp.port]], socket.sent
265
+ end
266
+
208
267
  def test_send_search
209
268
  socket = UPnP::FakeSocket.new
210
269
  @ssdp.socket = socket
@@ -233,5 +292,9 @@ ST: bunnies\r
233
292
  assert_equal nil, @ssdp.listener
234
293
  end
235
294
 
295
+ def util_device_version
296
+ "UPnP::Device::TestDevice/#{UPnP::VERSION}"
297
+ end
298
+
236
299
  end
237
300
 
@@ -5,6 +5,8 @@ require 'UPnP/SSDP'
5
5
  class TestUPnPSSDPResponse < UPnP::TestCase
6
6
 
7
7
  def setup
8
+ super
9
+
8
10
  @response = UPnP::SSDP::Response.parse util_search_response
9
11
  end
10
12
 
@@ -0,0 +1,25 @@
1
+ require 'test/unit'
2
+ require 'test/utilities'
3
+ require 'UPnP/SSDP'
4
+
5
+ class TestUPnPSSDPSearch < UPnP::TestCase
6
+
7
+ def test_self_parse_search
8
+ search = UPnP::SSDP::Search.parse util_search
9
+
10
+ assert_equal Time, search.date.class
11
+ assert_equal 'upnp:rootdevice', search.target
12
+ assert_equal 2, search.wait_time
13
+ end
14
+
15
+ def test_inspect
16
+ search = UPnP::SSDP::Search.parse util_search
17
+
18
+ id = search.object_id.to_s 16
19
+ expected = "#<UPnP::SSDP::Search:0x#{id} upnp:rootdevice>"
20
+
21
+ assert_equal expected, search.inspect
22
+ end
23
+
24
+ end
25
+
@@ -6,6 +6,8 @@ require 'UPnP/control/device'
6
6
  class TestUPnPControlDevice < UPnP::TestCase
7
7
 
8
8
  def setup
9
+ super
10
+
9
11
  @device_url = URI.parse 'http://example.com/device.xml'
10
12
 
11
13
  UPnP::OpenStub::FILES[@device_url] = StringIO.new UPnP::TestCase::IGD_XML
@@ -5,6 +5,8 @@ require 'UPnP/control/service'
5
5
  class TestUPnPControlService < UPnP::TestCase
6
6
 
7
7
  def setup
8
+ super
9
+
8
10
  @url = URI.parse 'http://example.com'
9
11
  service_description = <<-XML
10
12
  <service>
@@ -0,0 +1,295 @@
1
+ require 'test/unit'
2
+ require 'test/utilities'
3
+ require 'UPnP/device'
4
+
5
+ class TestUPnPDevice < UPnP::TestCase
6
+
7
+ def setup
8
+ super
9
+
10
+ @device = UPnP::Device.new 'TestDevice', 'test device'
11
+ @device.manufacturer = 'UPnP Manufacturer'
12
+ @device.model_name = 'UPnP Model'
13
+
14
+ @sub_device = @device.add_device 'TestDevice', 'test sub-device'
15
+ @sub_device.manufacturer = 'UPnP Sub Manufacturer'
16
+ @sub_device.model_name = 'UPnP Sub Model'
17
+
18
+ @service = @device.add_service 'TestService'
19
+ end
20
+
21
+ def test_self_create
22
+ device1 = UPnP::Device.create 'TestDevice', 'test device'
23
+
24
+ dump = File.join @home, '.UPnP', 'TestDevice', 'test device'
25
+
26
+ assert File.exist?(dump)
27
+
28
+ device2 = UPnP::Device.create 'TestDevice', 'test device'
29
+
30
+ assert_equal device1.name, device2.name, 'UUIDs not identical'
31
+ end
32
+
33
+ def test_self_create_edit
34
+ device1 = UPnP::Device.create 'TestDevice', 'test device' do |d|
35
+ d.manufacturer = 'manufacturer 1'
36
+
37
+ d.add_device 'TestDevice', 'embedded device' do |d2|
38
+ d2.manufacturer = 'embedded manufacturer'
39
+ end
40
+ end
41
+
42
+ device2 = UPnP::Device.create 'TestDevice', 'test device' do |d|
43
+ d.manufacturer = 'manufacturer 2'
44
+
45
+ d.add_device 'TestDevice', 'embedded device' do |d2|
46
+ d2.manufacturer = 'embedded manufacturer 2'
47
+ end
48
+ end
49
+
50
+ assert_equal device1.name, device2.name, 'UUIDs not identical'
51
+
52
+ assert_equal 2, device2.devices.length, 'wrong number of devices'
53
+
54
+ assert_equal device1.devices.last.name,
55
+ device2.devices.last.name, 'sub-device UUIDs not identical'
56
+
57
+ assert_not_equal device2.name, device2.devices.last.name
58
+
59
+ assert_equal 'manufacturer 2', device2.manufacturer, 'block not called'
60
+ assert_equal 'embedded manufacturer 2',
61
+ device2.devices.last.manufacturer,
62
+ 'sub-device block not called'
63
+
64
+ device3 = UPnP::Device.create 'TestDevice', 'test device'
65
+
66
+ assert_equal 'manufacturer 2', device3.manufacturer,
67
+ 'not dumped from Marshal'
68
+ end
69
+
70
+ def test_initialize
71
+ assert_kind_of UPnP::Device::TestDevice, @device
72
+ assert_equal 'test device', @device.friendly_name
73
+ assert_match %r%\Auuid:.{36}\Z%, @device.name
74
+ end
75
+
76
+ def test_add_device
77
+ assert_equal @device, @sub_device.parent
78
+ assert_equal 'test sub-device', @sub_device.friendly_name
79
+ assert_equal 'TestDevice', @sub_device.type
80
+
81
+ assert @device.sub_devices.include?(@sub_device)
82
+ end
83
+
84
+ def test_add_device_exists
85
+ device = @device.add_device @sub_device.type,
86
+ @sub_device.friendly_name do |d|
87
+ d.manufacturer = 'new manufacturer'
88
+ end
89
+
90
+ assert_equal 2, @device.devices.length, 'wrong number of devices'
91
+
92
+ assert_equal 'new manufacturer', device.manufacturer
93
+ end
94
+
95
+ def test_add_service
96
+ assert_equal @device, @service.device
97
+
98
+ assert @device.sub_services.include?(@service)
99
+ end
100
+
101
+ def test_description
102
+ desc = @device.description
103
+
104
+ desc = desc.gsub(/uuid:.{8}-.{4}-.{4}-.{4}-.{12}/,
105
+ 'uuid:XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX')
106
+
107
+ expected = <<-XML
108
+ <?xml version="1.0" encoding="UTF-8"?>
109
+ <root xmlns="urn:schemas-upnp-org:device-1-0">
110
+ <specVersion>
111
+ <major>1</major>
112
+ <minor>0</minor>
113
+ </specVersion>
114
+ <device>
115
+ <deviceType>urn:schemas-upnp-org:device:TestDevice:1</deviceType>
116
+ <UDN>uuid:XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX</UDN>
117
+ <friendlyName>test device</friendlyName>
118
+ <manufacturer>UPnP Manufacturer</manufacturer>
119
+ <modelName>UPnP Model</modelName>
120
+ <serviceList>
121
+ <service>
122
+ <serviceType>urn:schemas-upnp-org:service:TestService:1</serviceType>
123
+ <serviceId>urn:upnp-org:serviceId:TestService</serviceId>
124
+ <SCPDURL>/TestDevice/TestService</SCPDURL>
125
+ <controlURL>/TestDevice/TestService/control</controlURL>
126
+ <eventSubURL>/TestDevice/TestService/event_sub</eventSubURL>
127
+ </service>
128
+ </serviceList>
129
+ <deviceList>
130
+ <device>
131
+ <deviceType>urn:schemas-upnp-org:device:TestDevice:1</deviceType>
132
+ <UDN>uuid:XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX</UDN>
133
+ <friendlyName>test sub-device</friendlyName>
134
+ <manufacturer>UPnP Sub Manufacturer</manufacturer>
135
+ <modelName>UPnP Sub Model</modelName>
136
+ </device>
137
+ </deviceList>
138
+ </device>
139
+ </root>
140
+ XML
141
+
142
+ assert_equal expected, desc
143
+ end
144
+
145
+ def test_device_description
146
+ desc = ''
147
+ xml = Builder::XmlMarkup.new :indent => 2, :target => desc
148
+
149
+ @sub_device.device_description xml
150
+
151
+ desc = desc.gsub(/uuid:.{8}-.{4}-.{4}-.{4}-.{12}/,
152
+ 'uuid:XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX')
153
+
154
+ expected = <<-XML
155
+ <device>
156
+ <deviceType>urn:schemas-upnp-org:device:TestDevice:1</deviceType>
157
+ <UDN>uuid:XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX</UDN>
158
+ <friendlyName>test sub-device</friendlyName>
159
+ <manufacturer>UPnP Sub Manufacturer</manufacturer>
160
+ <modelName>UPnP Sub Model</modelName>
161
+ </device>
162
+ XML
163
+
164
+ assert_equal expected, desc
165
+ end
166
+
167
+ def test_devices
168
+ assert_equal ['test device', 'test sub-device'],
169
+ @device.devices.map { |d| d.friendly_name }, 'device'
170
+ assert_equal ['test sub-device'],
171
+ @sub_device.devices.map { |d| d.friendly_name }, 'sub-device'
172
+ end
173
+
174
+ def test_dump
175
+ @device.dump
176
+
177
+ dump_file = File.join @home, '.UPnP', @device.type, @device.friendly_name
178
+
179
+ assert File.exist?(dump_file)
180
+
181
+ marshal_version = IO.read dump_file, 2
182
+
183
+ major, minor = marshal_version.unpack 'CC'
184
+
185
+ assert_equal Marshal::MAJOR_VERSION, major
186
+ assert_equal Marshal::MINOR_VERSION, minor
187
+ end
188
+
189
+ def test_marshal_dump
190
+ dump = @device.marshal_dump
191
+ assert_equal 'TestDevice', dump.shift, 'type'
192
+ assert_equal 'test device', dump.shift, 'friendly name'
193
+ assert_equal [@sub_device], dump.shift, 'sub-devices'
194
+ assert_equal [@service], dump.shift, 'sub-services'
195
+ assert_equal nil, dump.shift, 'parent'
196
+ assert_match %r%uuid:.{36}%, dump.shift, 'name'
197
+ assert_equal 'UPnP Manufacturer', dump.shift, 'manufacturer'
198
+ assert_equal nil, dump.shift, 'manufacturer url'
199
+ assert_equal nil, dump.shift, 'model description'
200
+ assert_equal 'UPnP Model', dump.shift, 'model name'
201
+ assert_equal nil, dump.shift, 'model number'
202
+ assert_equal nil, dump.shift, 'model url'
203
+ assert_equal nil, dump.shift, 'serial number'
204
+ assert_equal nil, dump.shift, 'upc'
205
+
206
+ assert dump.empty?, 'device not empty'
207
+ end
208
+
209
+ def test_marshal_load
210
+ data = (1..14).to_a
211
+
212
+ @device.marshal_load data
213
+
214
+ assert_equal 1, @device.type
215
+ assert_equal 2, @device.friendly_name
216
+ assert_equal 3, @device.sub_devices
217
+ assert_equal 4, @device.sub_services
218
+ assert_equal 5, @device.parent
219
+ assert_equal 6, @device.name
220
+ assert_equal 7, @device.manufacturer
221
+ assert_equal 8, @device.manufacturer_url
222
+ assert_equal 9, @device.model_description
223
+ assert_equal 10, @device.model_name
224
+ assert_equal 11, @device.model_number
225
+ assert_equal 12, @device.model_url
226
+ assert_equal 13, @device.serial_number
227
+ assert_equal 14, @device.upc
228
+
229
+ assert data.empty?, 'data not consumed'
230
+ end
231
+
232
+ def test_root_device
233
+ assert_equal @device, @device.root_device
234
+ assert_equal @device, @sub_device.root_device
235
+ end
236
+
237
+ def test_service_id
238
+ assert_equal 'TestService', @device.service_id(@service)
239
+ end
240
+
241
+ def test_service_ids
242
+ expected = { UPnP::Service::TestService => 'TestService' }
243
+ assert_equal expected, @device.service_ids
244
+ end
245
+
246
+ def test_services
247
+ assert_equal [@service], @device.services
248
+ assert_equal [], @sub_device.services
249
+ end
250
+
251
+ def test_setup_server
252
+ server = @device.setup_server
253
+
254
+ mount_tab = server.instance_variable_get :@mount_tab
255
+
256
+ assert mount_tab[@service.scpd_url]
257
+ end
258
+
259
+ def test_type_urn
260
+ assert_equal "#{UPnP::DEVICE_SCHEMA_PREFIX}:TestDevice:1",
261
+ @device.type_urn
262
+ end
263
+
264
+ def test_validate
265
+ @device.friendly_name = nil
266
+
267
+ e = assert_raise UPnP::Device::ValidationError do
268
+ @device.validate
269
+ end
270
+
271
+ assert_equal 'friendly_name missing', e.message
272
+
273
+ @device.friendly_name = 'name'
274
+
275
+ @device.manufacturer = nil
276
+
277
+ e = assert_raise UPnP::Device::ValidationError do
278
+ @device.validate
279
+ end
280
+
281
+ assert_equal 'manufacturer missing', e.message
282
+
283
+ @device.manufacturer = 'manufacturer'
284
+
285
+ @device.model_name = nil
286
+
287
+ e = assert_raise UPnP::Device::ValidationError do
288
+ @device.validate
289
+ end
290
+
291
+ assert_equal 'model_name missing', e.message
292
+ end
293
+
294
+ end
295
+