device-cloud 0.2.0 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
data/device-cloud.gemspec CHANGED
@@ -32,7 +32,7 @@ Gem::Specification.new do |spec|
32
32
  spec.add_development_dependency "guard-bundler"
33
33
  spec.add_development_dependency "libnotify"
34
34
  spec.add_development_dependency "coveralls"
35
-
35
+ spec.add_development_dependency "timecop"
36
36
 
37
37
 
38
38
  end
@@ -23,19 +23,19 @@ module DeviceCloud
23
23
  end
24
24
 
25
25
  def get(path, *args)
26
- RestClient.get base_url + path, args
26
+ RestClient.get base_url + path, *args
27
27
  end
28
28
 
29
29
  def put(path, *args)
30
- RestClient.put base_url + path, args
30
+ RestClient.put base_url + path, *args
31
31
  end
32
32
 
33
33
  def post(path, *args)
34
- RestClient.post base_url + path, args
34
+ RestClient.post base_url + path, *args
35
35
  end
36
36
 
37
37
  def delete(path, *args)
38
- RestClient.delete base_url + path, args
38
+ RestClient.delete base_url + path, *args
39
39
  end
40
40
 
41
41
  def base_url
@@ -8,12 +8,16 @@ module DeviceCloud
8
8
  attr_accessor :username, :password, :host, :protocol
9
9
 
10
10
  def initialize(args)
11
- args = Hash[*args.map { |k, v| [k.to_sym, v] }.flatten]
12
- @username = args[:username] || DEFAULT_USERNAME
13
- @password = args[:password] || DEFAULT_PASSWORD
14
- @host = args[:host] || DEFAULT_HOST
15
- @protocol = args[:protocol] || DEFAULT_PROTOCOL
11
+ args = Hash[*args.map { |k, v| [k.to_s, v] }.flatten] unless args.nil?
12
+ init_with args
16
13
  end
17
14
 
15
+ # YAML Initializer
16
+ def init_with(args)
17
+ @username = args["username"] || DEFAULT_USERNAME
18
+ @password = args["password"] || DEFAULT_PASSWORD
19
+ @host = args["host"] || DEFAULT_HOST
20
+ @protocol = args["protocol"] || DEFAULT_PROTOCOL
21
+ end
18
22
  end
19
23
  end
@@ -41,7 +41,11 @@ module DeviceCloud
41
41
  end
42
42
 
43
43
  def mac
44
- stream_id_parse[2].to_i(16)
44
+ path.to_i(16)
45
+ end
46
+
47
+ def path
48
+ stream_id_parse[2]
45
49
  end
46
50
 
47
51
  def name
@@ -0,0 +1,52 @@
1
+ require 'device_cloud'
2
+
3
+ module DeviceCloud
4
+ class DataStreamClient
5
+ attr_accessor :client, :ttl
6
+
7
+ attr_reader :last_updated, :raw_cache, :parsed_cache
8
+
9
+ def initialize(config, client = nil)
10
+ @client = client || Client.new(config)
11
+ @ttl = config["ttl"] || 60
12
+ @last_updated = nil
13
+ end
14
+
15
+ # match the stream_id against regex
16
+ def match(regex)
17
+ cache.select do |stream|
18
+ stream.stream_id.match regex
19
+ end
20
+ end
21
+
22
+ def devices
23
+ cache.map do |stream|
24
+ {
25
+ device_id: stream.device_id,
26
+ path: stream.path
27
+ }
28
+ end.uniq
29
+ end
30
+
31
+ def invalidate
32
+ @last_updated = nil
33
+ end
34
+
35
+ def valid?
36
+ !@last_updated.nil? and (Time.now - @ttl) < @last_updated
37
+ end
38
+
39
+ def cache
40
+ if !valid? || parsed_cache.nil?
41
+ # We need to update the cache
42
+
43
+ # Get all streams, and we will parse it out using xpath.
44
+ @raw_cache = client.get DataStream::RESOURCE_PATH
45
+ @parsed_cache = DataStream.parse raw_cache
46
+ #get the thing
47
+ @last_updated = Time.now
48
+ end
49
+ parsed_cache
50
+ end
51
+ end
52
+ end
@@ -1,3 +1,3 @@
1
1
  module DeviceCloud
2
- VERSION = "0.2.0"
2
+ VERSION = "0.3.0"
3
3
  end
data/lib/device_cloud.rb CHANGED
@@ -3,6 +3,7 @@ require 'device_cloud/config'
3
3
  require 'device_cloud/client'
4
4
  require 'device_cloud/device_core'
5
5
  require 'device_cloud/data_stream'
6
+ require 'device_cloud/data_stream_client'
6
7
  require 'device_cloud/data_point'
7
8
  require 'device_cloud/result'
8
- require 'device_cloud/monitor'
9
+ require 'device_cloud/monitor'
@@ -1,7 +1,7 @@
1
1
  require "spec_helper"
2
2
 
3
3
  describe DeviceCloud::Client do
4
- subject do
4
+ subject(:client) do
5
5
  DeviceCloud::Client.new(:username => username, :password => password, :host => host, :protocol => protocol)
6
6
  end
7
7
  let(:username) { "test" }
@@ -11,10 +11,34 @@ describe DeviceCloud::Client do
11
11
 
12
12
 
13
13
  it 'will generate a base_url using the configuration' do
14
- subject.base_url.should == "#{protocol}://#{username}:#{password}@#{host}"
15
- subject.config.protocol = "http"
16
- subject.base_url.should == "http://#{username}:#{password}@#{host}"
17
- subject.config.host = "google.com"
18
- subject.base_url.should == "http://#{username}:#{password}@google.com"
14
+ client.base_url.should == "#{protocol}://#{username}:#{password}@#{host}"
15
+ client.config.protocol = "http"
16
+ client.base_url.should == "http://#{username}:#{password}@#{host}"
17
+ client.config.host = "google.com"
18
+ client.base_url.should == "http://#{username}:#{password}@google.com"
19
19
  end
20
- end
20
+
21
+ describe "#devices" do
22
+ let(:result) { "Device Core XML" }
23
+ before :each do
24
+ client.stub(:get => result)
25
+ DeviceCloud::DeviceCore.stub(:parse)
26
+ end
27
+
28
+ context "No parameters" do
29
+ it "will use the correct url" do
30
+ client.devices("*")
31
+ expect(client).to have_received(:get).with("/ws/DeviceCore/*?")
32
+ expect(DeviceCloud::DeviceCore).to have_received(:parse).with(result)
33
+ end
34
+ end
35
+
36
+ context "Filtering with parameters" do
37
+ it "will use the correct url" do
38
+ client.devices("*", "grpPath" => "IVX", "test" => "true")
39
+ expect(client).to have_received(:get).with("/ws/DeviceCore/*?grpPath=IVX&test=true")
40
+ expect(DeviceCloud::DeviceCore).to have_received(:parse).with(result)
41
+ end
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,282 @@
1
+ require 'spec_helper'
2
+
3
+ require 'timecop'
4
+
5
+ describe DeviceCloud::DataStreamClient do
6
+ subject(:data_stream_client) { DeviceCloud::DataStreamClient.new config, client }
7
+ let(:client) { double("DeviceCloud::Client", :get => xml) }
8
+ let(:config) { {"ttl" => 55} }
9
+
10
+ let(:xml) do
11
+ <<-XML
12
+ <?xml version="1.0" encoding="ISO-8859-1"?>
13
+ <result>
14
+ <resultSize>8</resultSize>
15
+ <requestedSize>1000</requestedSize>
16
+ <pageCursor>76cab9ad-5-ebd5ccac</pageCursor>
17
+ <DataStream>
18
+ <cstId>5940</cstId>
19
+ <streamId>dia/channel/00000000-00000000-00409DFF-FF725771/0013a20040a52e1d/distance</streamId>
20
+ <dataType>DOUBLE</dataType>
21
+ <forwardTo/>
22
+ <currentValue>
23
+ <id>5101f920-53b4-11e3-8b51-bc764e113426</id>
24
+ <timestamp>1385151966954</timestamp>
25
+ <serverTimestamp>1385151968249</serverTimestamp>
26
+ <data>44.2</data>
27
+ <description/>
28
+ <quality>0</quality>
29
+ </currentValue>
30
+ <description/>
31
+ <units>in</units>
32
+ <dataTtl>2678400</dataTtl>
33
+ <rollupTtl>8035200</rollupTtl>
34
+ </DataStream>
35
+ <DataStream>
36
+ <cstId>5940</cstId>
37
+ <streamId>dia/channel/00000000-00000000-00409DFF-FF725771/0013a2004063d301/distance</streamId>
38
+ <dataType>DOUBLE</dataType>
39
+ <forwardTo/>
40
+ <currentValue>
41
+ <id>510c337d-53b4-11e3-8b51-bc764e113426</id>
42
+ <timestamp>1385151967021</timestamp>
43
+ <serverTimestamp>1385151968488</serverTimestamp>
44
+ <data>0.0</data>
45
+ <description/>
46
+ <quality>0</quality>
47
+ </currentValue>
48
+ <description/>
49
+ <units>in</units>
50
+ <dataTtl>2678400</dataTtl>
51
+ <rollupTtl>8035200</rollupTtl>
52
+ </DataStream>
53
+ <DataStream>
54
+ <cstId>5940</cstId>
55
+ <streamId>dia/channel/00000000-00000000-00409DFF-FF725771/0013a200408cb965/distance</streamId>
56
+ <dataType>DOUBLE</dataType>
57
+ <forwardTo/>
58
+ <currentValue>
59
+ <id>50e8a4e8-53b4-11e3-8b51-bc764e113426</id>
60
+ <timestamp>1385151966788</timestamp>
61
+ <serverTimestamp>1385151968064</serverTimestamp>
62
+ <data>0.0</data>
63
+ <description/>
64
+ <quality>0</quality>
65
+ </currentValue>
66
+ <description/>
67
+ <units>in</units>
68
+ <dataTtl>2678400</dataTtl>
69
+ <rollupTtl>8035200</rollupTtl>
70
+ </DataStream>
71
+ <DataStream>
72
+ <cstId>5940</cstId>
73
+ <streamId>dia/channel/00000000-00000000-00409DFF-FF725771/0013a20040a52b7a/distance</streamId>
74
+ <dataType>DOUBLE</dataType>
75
+ <forwardTo/>
76
+ <currentValue>
77
+ <id>50f1cc94-53b4-11e3-8b51-bc764e113426</id>
78
+ <timestamp>1385151966848</timestamp>
79
+ <serverTimestamp>1385151968068</serverTimestamp>
80
+ <data>0.0</data>
81
+ <description/>
82
+ <quality>0</quality>
83
+ </currentValue>
84
+ <description/>
85
+ <units>in</units>
86
+ <dataTtl>2678400</dataTtl>
87
+ <rollupTtl>8035200</rollupTtl>
88
+ </DataStream>
89
+ <DataStream>
90
+ <cstId>5940</cstId>
91
+ <streamId>dia/channel/00000000-00000000-00409DFF-FF725771/0013a20040a52e1d/temperature</streamId>
92
+ <dataType>DOUBLE</dataType>
93
+ <forwardTo/>
94
+ <currentValue>
95
+ <id>5101f920-53b4-11e3-8b51-bc764e113426</id>
96
+ <timestamp>1385151966954</timestamp>
97
+ <serverTimestamp>1385151968249</serverTimestamp>
98
+ <data>44.2</data>
99
+ <description/>
100
+ <quality>0</quality>
101
+ </currentValue>
102
+ <description/>
103
+ <units>in</units>
104
+ <dataTtl>2678400</dataTtl>
105
+ <rollupTtl>8035200</rollupTtl>
106
+ </DataStream>
107
+ <DataStream>
108
+ <cstId>5940</cstId>
109
+ <streamId>dia/channel/00000000-00000000-00409DFF-FF725771/0013a2004063d301/temperature</streamId>
110
+ <dataType>DOUBLE</dataType>
111
+ <forwardTo/>
112
+ <currentValue>
113
+ <id>510c337d-53b4-11e3-8b51-bc764e113426</id>
114
+ <timestamp>1385151967021</timestamp>
115
+ <serverTimestamp>1385151968488</serverTimestamp>
116
+ <data>21.2</data>
117
+ <description/>
118
+ <quality>0</quality>
119
+ </currentValue>
120
+ <description/>
121
+ <units>in</units>
122
+ <dataTtl>2678400</dataTtl>
123
+ <rollupTtl>8035200</rollupTtl>
124
+ </DataStream>
125
+ <DataStream>
126
+ <cstId>5940</cstId>
127
+ <streamId>dia/channel/00000000-00000000-00409DFF-FF725771/0013a200408cb965/temperature</streamId>
128
+ <dataType>DOUBLE</dataType>
129
+ <forwardTo/>
130
+ <currentValue>
131
+ <id>50e8a4e8-53b4-11e3-8b51-bc764e113426</id>
132
+ <timestamp>1385151966788</timestamp>
133
+ <serverTimestamp>1385151968064</serverTimestamp>
134
+ <data>20.0</data>
135
+ <description/>
136
+ <quality>0</quality>
137
+ </currentValue>
138
+ <description/>
139
+ <units>in</units>
140
+ <dataTtl>2678400</dataTtl>
141
+ <rollupTtl>8035200</rollupTtl>
142
+ </DataStream>
143
+ <DataStream>
144
+ <cstId>5940</cstId>
145
+ <streamId>dia/channel/00000000-00000000-00409DFF-FF725771/0013a20040a52b7a/temperature</streamId>
146
+ <dataType>DOUBLE</dataType>
147
+ <forwardTo/>
148
+ <currentValue>
149
+ <id>50f1cc94-53b4-11e3-8b51-bc764e113426</id>
150
+ <timestamp>1385151966848</timestamp>
151
+ <serverTimestamp>1385151968068</serverTimestamp>
152
+ <data>32.2</data>
153
+ <description/>
154
+ <quality>0</quality>
155
+ </currentValue>
156
+ <description/>
157
+ <units>in</units>
158
+ <dataTtl>2678400</dataTtl>
159
+ <rollupTtl>8035200</rollupTtl>
160
+ </DataStream>
161
+ </result>
162
+ XML
163
+ end
164
+
165
+
166
+ describe "#valid?" do
167
+ before :each do
168
+ Timecop.freeze
169
+ end
170
+
171
+ context("The cache has not been updated") do
172
+ it "will return false" do
173
+ expect(data_stream_client.valid?).to eql false
174
+ end
175
+ end
176
+
177
+ context("A request has recently been made") do
178
+ before(:each) do
179
+ data_stream_client.cache
180
+ Timecop.travel Time.now + 10
181
+ end
182
+
183
+ it "will return true" do
184
+ expect(data_stream_client.valid?).to eql true
185
+ end
186
+ end
187
+
188
+ after(:each) do
189
+ Timecop.return
190
+ end
191
+ end
192
+
193
+ describe "#devices" do
194
+ it "will return a data for every (device_id)/(path)/..." do
195
+
196
+ device_list = [{device_id: "00000000-00000000-00409DFF-FF725771", path: "0013a20040a52e1d"},
197
+ {device_id: "00000000-00000000-00409DFF-FF725771", path: "0013a2004063d301"},
198
+ {device_id: "00000000-00000000-00409DFF-FF725771", path: "0013a200408cb965"},
199
+ {device_id: "00000000-00000000-00409DFF-FF725771", path: "0013a20040a52b7a"}]
200
+
201
+
202
+ expect(data_stream_client.devices).to eql device_list
203
+ end
204
+ end
205
+
206
+ describe "#match" do
207
+ context "when the streams requested exit" do
208
+ it "returns a datastream object for each matched stream" do
209
+ streams = data_stream_client.match(".*/distance")
210
+ expect(streams.count).to eql 4
211
+ streams.each do |stream|
212
+ expect(stream.name).to eql "distance"
213
+ end
214
+ end
215
+ end
216
+
217
+ context "the requested stream does not exist" do
218
+ it "returns an empty array" do
219
+ expect(data_stream_client.match("foo")).to be_empty
220
+ end
221
+ end
222
+ end
223
+
224
+
225
+ describe "#invalidate" do
226
+ context "the cache is valid" do
227
+ before :each do
228
+ Timecop.freeze
229
+ data_stream_client.cache
230
+ end
231
+
232
+ after :each do
233
+ Timecop.return
234
+ end
235
+
236
+ it "sets last_updated to nil" do
237
+ expect { data_stream_client.invalidate }.to change { data_stream_client.last_updated }.from(Time.now).to nil
238
+ end
239
+ end
240
+ end
241
+
242
+ describe "#cache" do
243
+ let(:stream) { double("DeviceCloud::DataStream") }
244
+ before :each do
245
+ DeviceCloud::DataStream.stub(:parse => [stream])
246
+ Timecop.freeze
247
+ end
248
+
249
+ context "The cache is invalid" do
250
+ it "will update the cache age" do
251
+ expect { data_stream_client.cache }.to change { data_stream_client.last_updated }.to Time.now
252
+ end
253
+
254
+ it "will set the raw cache to the request xml" do
255
+ expect { data_stream_client.cache }.to change { data_stream_client.raw_cache }.to xml
256
+ end
257
+
258
+ it "will return the cache parsed as an array DataStreams" do
259
+ expect(data_stream_client.cache).to eql [stream]
260
+ expect(DeviceCloud::DataStream).to have_received(:parse).with(xml)
261
+ end
262
+ end
263
+
264
+ context "The cache is valid" do
265
+ before :each do
266
+ data_stream_client.stub(:valid? => true, :parsed_cache => [stream])
267
+ end
268
+
269
+ it "will only return the current cache value" do
270
+ expect(data_stream_client.cache).to eql [stream]
271
+ expect(DeviceCloud::DataStream).not_to have_received(:parse)
272
+ end
273
+ end
274
+
275
+ after :each do
276
+ Timecop.return
277
+ end
278
+ end
279
+
280
+ let(:serialized) { "--- !ruby/object:DeviceCloud::DataStreamCache \nttl: 33" }
281
+
282
+ end
@@ -135,6 +135,11 @@ describe DeviceCloud::DataStream do
135
135
  end
136
136
  end
137
137
 
138
+ describe "#path" do
139
+ it "returns the path of the datastream, which is the part of the streamId between the stream name and device_id" do
140
+ expect(data_stream.path).to eql "0013a20040a52e1d"
141
+ end
142
+ end
138
143
  describe "#mac" do
139
144
  it "returns the sensor mac from the device id and converts it to an integer" do
140
145
  expect(data_stream.mac).to eql "0013a20040a52e1d".to_i(16)
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: device-cloud
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0
4
+ version: 0.3.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2014-01-15 00:00:00.000000000 Z
12
+ date: 2014-02-07 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: nokogiri
@@ -219,6 +219,22 @@ dependencies:
219
219
  - - ! '>='
220
220
  - !ruby/object:Gem::Version
221
221
  version: '0'
222
+ - !ruby/object:Gem::Dependency
223
+ name: timecop
224
+ requirement: !ruby/object:Gem::Requirement
225
+ none: false
226
+ requirements:
227
+ - - ! '>='
228
+ - !ruby/object:Gem::Version
229
+ version: '0'
230
+ type: :development
231
+ prerelease: false
232
+ version_requirements: !ruby/object:Gem::Requirement
233
+ none: false
234
+ requirements:
235
+ - - ! '>='
236
+ - !ruby/object:Gem::Version
237
+ version: '0'
222
238
  description: REST Wrapper for Etherios Devicecloud
223
239
  email:
224
240
  - eric@clean-logix.com
@@ -239,6 +255,7 @@ files:
239
255
  - lib/device_cloud/config.rb
240
256
  - lib/device_cloud/data_point.rb
241
257
  - lib/device_cloud/data_stream.rb
258
+ - lib/device_cloud/data_stream_client.rb
242
259
  - lib/device_cloud/device_core.rb
243
260
  - lib/device_cloud/monitor.rb
244
261
  - lib/device_cloud/result.rb
@@ -246,6 +263,7 @@ files:
246
263
  - spec/device_cloud/client_spec.rb
247
264
  - spec/device_cloud/config_spec.rb
248
265
  - spec/device_cloud/data_point_spec.rb
266
+ - spec/device_cloud/data_stream_client_spec.rb
249
267
  - spec/device_cloud/data_stream_spec.rb
250
268
  - spec/device_cloud/device_core_spec.rb
251
269
  - spec/device_cloud/monitor_spec.rb
@@ -280,6 +298,7 @@ test_files:
280
298
  - spec/device_cloud/client_spec.rb
281
299
  - spec/device_cloud/config_spec.rb
282
300
  - spec/device_cloud/data_point_spec.rb
301
+ - spec/device_cloud/data_stream_client_spec.rb
283
302
  - spec/device_cloud/data_stream_spec.rb
284
303
  - spec/device_cloud/device_core_spec.rb
285
304
  - spec/device_cloud/monitor_spec.rb