device_cloud 0.0.1
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.
- data/.gitignore +17 -0
- data/.rspec +2 -0
- data/.ruby-version +1 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +29 -0
- data/Rakefile +1 -0
- data/device_cloud.gemspec +25 -0
- data/lib/device_cloud/configuration.rb +70 -0
- data/lib/device_cloud/push_notification/alert.rb +7 -0
- data/lib/device_cloud/push_notification/base.rb +27 -0
- data/lib/device_cloud/push_notification/event.rb +7 -0
- data/lib/device_cloud/push_notification/message/file_data.rb +64 -0
- data/lib/device_cloud/push_notification/message.rb +54 -0
- data/lib/device_cloud/push_notification.rb +23 -0
- data/lib/device_cloud/utils.rb +11 -0
- data/lib/device_cloud/version.rb +3 -0
- data/lib/device_cloud.rb +14 -0
- data/spec/device_cloud/push_notification/alert_spec.rb +26 -0
- data/spec/device_cloud/push_notification/base_spec.rb +30 -0
- data/spec/device_cloud/push_notification/event_spec.rb +26 -0
- data/spec/device_cloud/push_notification/message/file_data_spec.rb +129 -0
- data/spec/device_cloud/push_notification/message_spec.rb +144 -0
- data/spec/device_cloud/push_notification_spec.rb +87 -0
- data/spec/spec_helper.rb +13 -0
- data/spec/version_spec.rb +7 -0
- metadata +128 -0
data/.gitignore
ADDED
data/.rspec
ADDED
data/.ruby-version
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
1.9.3-p392
|
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2013 Erik Straub
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
# DeviceCloud
|
2
|
+
|
3
|
+
TODO: Write a gem description
|
4
|
+
|
5
|
+
## Installation
|
6
|
+
|
7
|
+
Add this line to your application's Gemfile:
|
8
|
+
|
9
|
+
gem 'device_cloud'
|
10
|
+
|
11
|
+
And then execute:
|
12
|
+
|
13
|
+
$ bundle
|
14
|
+
|
15
|
+
Or install it yourself as:
|
16
|
+
|
17
|
+
$ gem install device_cloud
|
18
|
+
|
19
|
+
## Usage
|
20
|
+
|
21
|
+
TODO: Write usage instructions here
|
22
|
+
|
23
|
+
## Contributing
|
24
|
+
|
25
|
+
1. Fork it
|
26
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
27
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
28
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
29
|
+
5. Create new Pull Request
|
data/Rakefile
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require "bundler/gem_tasks"
|
@@ -0,0 +1,25 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'device_cloud/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "device_cloud"
|
8
|
+
spec.version = DeviceCloud::VERSION
|
9
|
+
spec.authors = ["Erik Straub"]
|
10
|
+
spec.email = ["erik@madgloryint.com"]
|
11
|
+
spec.description = %q{A Ruby wrapper for the Etherios Device Cloud}
|
12
|
+
spec.summary = %q{A Ruby wrapper for the Etherios Device Cloud}
|
13
|
+
spec.homepage = "http://github.com/madgloryint/device_cloud"
|
14
|
+
spec.license = "MIT"
|
15
|
+
|
16
|
+
spec.files = `git ls-files`.split($/)
|
17
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
18
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
19
|
+
spec.require_paths = ["lib"]
|
20
|
+
|
21
|
+
spec.add_development_dependency "bundler", "~> 1.3"
|
22
|
+
spec.add_development_dependency "rake"
|
23
|
+
|
24
|
+
spec.add_development_dependency 'rspec'
|
25
|
+
end
|
@@ -0,0 +1,70 @@
|
|
1
|
+
require 'logger'
|
2
|
+
|
3
|
+
module DeviceCloud
|
4
|
+
module Configuration
|
5
|
+
|
6
|
+
# DeviceCloud account root_url
|
7
|
+
attr_writer :root_url
|
8
|
+
|
9
|
+
# DeviceCloud account username
|
10
|
+
attr_writer :username
|
11
|
+
|
12
|
+
# DeviceCloud account password
|
13
|
+
attr_writer :password
|
14
|
+
|
15
|
+
# DeviceCloud defualt logger
|
16
|
+
attr_writer :logger
|
17
|
+
|
18
|
+
# Proc that will be called for handling
|
19
|
+
# DeviceCloud::PushNotification::Event objects
|
20
|
+
# Proc will be called with the event object
|
21
|
+
attr_accessor :push_notification_event_handler
|
22
|
+
|
23
|
+
# Proc that will be called for handling
|
24
|
+
# DeviceCloud::PushNotification::Alert objects
|
25
|
+
# Proc will be called with the alert object
|
26
|
+
attr_accessor :push_notification_alert_handler
|
27
|
+
|
28
|
+
# Yield self to be able to configure ActivityFeed with
|
29
|
+
# block-style configuration.
|
30
|
+
#
|
31
|
+
# Example:
|
32
|
+
#
|
33
|
+
# ActivityFeed.configure do |configuration|
|
34
|
+
# configuration.root_url = 'https://example.com'
|
35
|
+
# end
|
36
|
+
def configure
|
37
|
+
yield self
|
38
|
+
end
|
39
|
+
|
40
|
+
# DeviceCloud url
|
41
|
+
#
|
42
|
+
# @return the DeviceCloud url or the default of 'https://my.idigi.com' if not set.
|
43
|
+
def root_url
|
44
|
+
@root_url ||= 'https://my.idigi.com'
|
45
|
+
end
|
46
|
+
|
47
|
+
# DeviceCloud username
|
48
|
+
#
|
49
|
+
# @return the DeviceCloud username or raises an error
|
50
|
+
def username
|
51
|
+
raise 'DeviceCloud username is blank' if @username.blank?
|
52
|
+
@username
|
53
|
+
end
|
54
|
+
|
55
|
+
# DeviceCloud password
|
56
|
+
#
|
57
|
+
# @return the DeviceCloud password or raises an error
|
58
|
+
def password
|
59
|
+
raise 'DeviceCloud password is blank' if @password.blank?
|
60
|
+
@password
|
61
|
+
end
|
62
|
+
|
63
|
+
# DeviceCloud logger
|
64
|
+
#
|
65
|
+
# @return the DeviceCloud logger or set the default to stdout
|
66
|
+
def logger
|
67
|
+
@root_url ||= Logger.new(STDOUT)
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
module DeviceCloud
|
2
|
+
class PushNotification::Base
|
3
|
+
attr_reader :id, :device_id, :value, :queued_at, :type
|
4
|
+
|
5
|
+
def self.handle!(file_data)
|
6
|
+
event = new(file_data)
|
7
|
+
event.handle!
|
8
|
+
end
|
9
|
+
|
10
|
+
def initialize(file_data)
|
11
|
+
@file_data = file_data
|
12
|
+
@id = data["id"]
|
13
|
+
@device_id = data["device_id"]
|
14
|
+
@type = data["type"]
|
15
|
+
@queued_at = data["queued_dt"]
|
16
|
+
@value = data["value"]
|
17
|
+
end
|
18
|
+
|
19
|
+
def handle!
|
20
|
+
raise NotImplementedError
|
21
|
+
end
|
22
|
+
|
23
|
+
def data
|
24
|
+
@file_data.data
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,64 @@
|
|
1
|
+
require 'json'
|
2
|
+
require 'base64'
|
3
|
+
|
4
|
+
module DeviceCloud
|
5
|
+
class PushNotification::Message::FileData
|
6
|
+
attr_accessor :id, :fdLastModifiedDate, :fdSize, :fdContentType, :fdData, :fdArchive, :cstId, :fdType, :fdCreatedDate
|
7
|
+
attr_reader :errors
|
8
|
+
|
9
|
+
def initialize(attributes = {})
|
10
|
+
@errors = []
|
11
|
+
attributes.each do |name, value|
|
12
|
+
send("#{name}=", value)
|
13
|
+
end
|
14
|
+
DeviceCloud.logger.warn "DeviceCloud::PushNotification::Message::FileData Invalid (#{errors.join(',')}) - #{full_path}" unless valid?
|
15
|
+
end
|
16
|
+
|
17
|
+
def full_path
|
18
|
+
file_path + file_name
|
19
|
+
end
|
20
|
+
|
21
|
+
def data
|
22
|
+
return false unless valid?
|
23
|
+
@data ||= JSON.parse unencoded_data
|
24
|
+
end
|
25
|
+
|
26
|
+
def file_name
|
27
|
+
return '' unless id
|
28
|
+
id['fdName']
|
29
|
+
end
|
30
|
+
|
31
|
+
def file_path
|
32
|
+
return '' unless id
|
33
|
+
id['fdPath']
|
34
|
+
end
|
35
|
+
|
36
|
+
def valid?
|
37
|
+
return false if @errors.any?
|
38
|
+
validate_content_type! && validate_content!
|
39
|
+
end
|
40
|
+
private
|
41
|
+
|
42
|
+
def unencoded_data
|
43
|
+
@unencode_data ||= Base64.decode64(fdData)
|
44
|
+
end
|
45
|
+
|
46
|
+
def validate_content_type!
|
47
|
+
if file_name =~ /\.json/
|
48
|
+
true
|
49
|
+
else
|
50
|
+
@errors << 'wrong file type'
|
51
|
+
false
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
def validate_content!
|
56
|
+
if fdData.size == 0 || fdSize.to_i < 1
|
57
|
+
@errors << 'no content'
|
58
|
+
false
|
59
|
+
else
|
60
|
+
true
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
module DeviceCloud
|
2
|
+
class PushNotification::Message
|
3
|
+
attr_accessor :timestamp, :topic, :file_data, :operation, :group, :replay
|
4
|
+
|
5
|
+
ALLOWED_TOPICS = %w{alert event}
|
6
|
+
|
7
|
+
def self.parse_raw_messages(raw_message_data)
|
8
|
+
if raw_message_data.is_a? Array
|
9
|
+
messages = raw_message_data.map {|message| new(message) }
|
10
|
+
else
|
11
|
+
messages = [new(raw_message_data)]
|
12
|
+
end
|
13
|
+
messages
|
14
|
+
end
|
15
|
+
|
16
|
+
def initialize(attributes = {})
|
17
|
+
attributes.each do |name, value|
|
18
|
+
if name == 'FileData'
|
19
|
+
@file_data = value
|
20
|
+
else
|
21
|
+
send("#{name}=", value)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
DeviceCloud.logger.warn "DeviceCloud::PushNotification::Message Invalid (no content) - #{topic}" unless valid?
|
25
|
+
end
|
26
|
+
|
27
|
+
def parsed_file_data
|
28
|
+
return false unless valid?
|
29
|
+
@parsed_file_data ||= FileData.new file_data
|
30
|
+
end
|
31
|
+
|
32
|
+
def valid?
|
33
|
+
!!file_data && topic_allowed?
|
34
|
+
end
|
35
|
+
|
36
|
+
def valid_parsed_file_data?
|
37
|
+
parsed_file_data.valid?
|
38
|
+
end
|
39
|
+
|
40
|
+
def topic_type
|
41
|
+
topic_matches.first
|
42
|
+
end
|
43
|
+
|
44
|
+
private
|
45
|
+
def topic_allowed?
|
46
|
+
return false if !topic
|
47
|
+
topic_matches.any?
|
48
|
+
end
|
49
|
+
|
50
|
+
def topic_matches
|
51
|
+
topic.split('/') & ALLOWED_TOPICS
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module DeviceCloud
|
2
|
+
class PushNotification
|
3
|
+
attr_reader :messages
|
4
|
+
|
5
|
+
def initialize(raw_messages)
|
6
|
+
@messages = DeviceCloud::PushNotification::Message.parse_raw_messages(raw_messages)
|
7
|
+
end
|
8
|
+
|
9
|
+
def handle_each!
|
10
|
+
messages.each do |message|
|
11
|
+
next unless message.valid? && message.valid_parsed_file_data?
|
12
|
+
|
13
|
+
klass = class_type(message.topic_type)
|
14
|
+
|
15
|
+
klass.handle!(message.parsed_file_data)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
private
|
19
|
+
def class_type(class_name)
|
20
|
+
DeviceCloud.constantize "DeviceCloud::PushNotification::#{class_name.capitalize}"
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
data/lib/device_cloud.rb
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
require 'device_cloud/configuration'
|
2
|
+
require 'device_cloud/utils'
|
3
|
+
require 'device_cloud/version'
|
4
|
+
require 'device_cloud/push_notification'
|
5
|
+
require 'device_cloud/push_notification/base'
|
6
|
+
require 'device_cloud/push_notification/alert'
|
7
|
+
require 'device_cloud/push_notification/event'
|
8
|
+
require 'device_cloud/push_notification/message'
|
9
|
+
require 'device_cloud/push_notification/message/file_data'
|
10
|
+
|
11
|
+
module DeviceCloud
|
12
|
+
extend Configuration
|
13
|
+
extend Utils
|
14
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe DeviceCloud::PushNotification::Alert do
|
4
|
+
describe "#handle!" do
|
5
|
+
let(:data) do
|
6
|
+
{
|
7
|
+
'id' => 1234,
|
8
|
+
'device_id' => 'm:1392301029',
|
9
|
+
'type' => 'some type',
|
10
|
+
'queued_dt' => '2013-06-24T14:52:55.421Z',
|
11
|
+
'value' => {'this' => 'is a value'}
|
12
|
+
}
|
13
|
+
end
|
14
|
+
let(:file_data) { OpenStruct.new(data: data, full_path: '/foo/bar/baz.json') }
|
15
|
+
|
16
|
+
subject { DeviceCloud::PushNotification::Alert.new file_data }
|
17
|
+
|
18
|
+
it "should call the DeviceCloud.push_notification_alert_handler with self" do
|
19
|
+
handled_alert = nil
|
20
|
+
DeviceCloud.push_notification_alert_handler = ->(alert) { handled_alert = alert }
|
21
|
+
|
22
|
+
subject.handle!
|
23
|
+
expect(handled_alert).to eq subject
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe DeviceCloud::PushNotification::Base do
|
4
|
+
let(:data) do
|
5
|
+
{
|
6
|
+
'id' => 1234,
|
7
|
+
'device_id' => 'm:1392301029',
|
8
|
+
'type' => 'some type',
|
9
|
+
'queued_dt' => '2013-06-24T14:52:55.421Z',
|
10
|
+
'value' => {'this' => 'is a value'}
|
11
|
+
}
|
12
|
+
end
|
13
|
+
let(:file_data) { OpenStruct.new(data: data, full_path: '/foo/bar/baz.json') }
|
14
|
+
|
15
|
+
subject { DeviceCloud::PushNotification::Base.new file_data }
|
16
|
+
|
17
|
+
describe "attributes" do
|
18
|
+
its(:id) { should eq data['id'] }
|
19
|
+
its(:device_id) { should eq data['device_id'] }
|
20
|
+
its(:type) { should eq data['type'] }
|
21
|
+
its(:queued_at) { should eq data['queued_dt'] }
|
22
|
+
its(:value) { should eq data['value'] }
|
23
|
+
end
|
24
|
+
|
25
|
+
describe "#handle!" do
|
26
|
+
it "should raise NotImplementedError" do
|
27
|
+
expect{subject.handle!}.to raise_error NotImplementedError
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe DeviceCloud::PushNotification::Event do
|
4
|
+
describe "#handle!" do
|
5
|
+
let(:data) do
|
6
|
+
{
|
7
|
+
'id' => 1234,
|
8
|
+
'device_id' => 'm:1392301029',
|
9
|
+
'type' => 'some type',
|
10
|
+
'queued_dt' => '2013-06-24T14:52:55.421Z',
|
11
|
+
'value' => {'this' => 'is a value'}
|
12
|
+
}
|
13
|
+
end
|
14
|
+
let(:file_data) { OpenStruct.new(data: data, full_path: '/foo/bar/baz.json') }
|
15
|
+
|
16
|
+
subject { DeviceCloud::PushNotification::Event.new file_data }
|
17
|
+
|
18
|
+
it "should call the DeviceCloud.push_notification_event_handler with self" do
|
19
|
+
handled_event = nil
|
20
|
+
DeviceCloud.push_notification_event_handler = ->(event) { handled_event = event }
|
21
|
+
|
22
|
+
subject.handle!
|
23
|
+
expect(handled_event).to eq subject
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,129 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe DeviceCloud::PushNotification::Message::FileData do
|
4
|
+
let(:raw_file_data) do
|
5
|
+
{
|
6
|
+
"id" => {
|
7
|
+
"fdPath" => " /db/4044_MadGlory_Interactive/00000000-00000000-001395FF-FF0E6012/alert/",
|
8
|
+
"fdName" => "foo-0966595cdcdd11e2abf50013950e6012.json"
|
9
|
+
},
|
10
|
+
"fdLastModifiedDate" => "2013-06-24T14:52:55.421Z",
|
11
|
+
"fdSize" => 156,
|
12
|
+
"fdContentType" => "application/json",
|
13
|
+
"fdData" => "eyJ2YWx1ZSI6IHt9LCAiY2xhc3MiOiAiYWxlcnQiLCAicXVldWVkX2R0IjogIjIwMTMtMDYtMjRUMTQ6NDc6NDdaIiwgInR5cGUiOiAiZm9vIiwgImlkIjogIjA5NjY1OTVjZGNkZDExZTJhYmY1MDAxMzk1MGU2MDEyIiwgImRldmljZV9pZCI6ICJtOjAwMTM5NTBFNjAxMiJ9",
|
14
|
+
"fdArchive" => false,
|
15
|
+
"cstId" => 4044,
|
16
|
+
"fdType" => "file",
|
17
|
+
"fdCreatedDate" => "2013-06-24T14:52:55.421Z"
|
18
|
+
}
|
19
|
+
end
|
20
|
+
|
21
|
+
describe "attributes" do
|
22
|
+
subject { DeviceCloud::PushNotification::Message::FileData.new raw_file_data }
|
23
|
+
|
24
|
+
its(:id) { should eq(raw_file_data['id']) }
|
25
|
+
its(:fdLastModifiedDate) { should eq(raw_file_data['fdLastModifiedDate']) }
|
26
|
+
its(:fdSize) { should eq(raw_file_data['fdSize']) }
|
27
|
+
its(:fdArchive) { should eq(raw_file_data['fdArchive']) }
|
28
|
+
its(:cstId) { should eq(raw_file_data['cstId']) }
|
29
|
+
its(:fdType) { should eq(raw_file_data['fdType']) }
|
30
|
+
its(:fdCreatedDate) { should eq(raw_file_data['fdCreatedDate']) }
|
31
|
+
its(:fdData) { should eq(raw_file_data["fdData"]) }
|
32
|
+
end
|
33
|
+
|
34
|
+
describe '#valid?' do
|
35
|
+
subject { DeviceCloud::PushNotification::Message::FileData.new }
|
36
|
+
context 'wrong file type' do
|
37
|
+
let(:raw_file_data) do
|
38
|
+
{
|
39
|
+
"id" => {
|
40
|
+
"fdPath" => "/db/4044_MadGlory_Interactive/00000000-00000000-001395FF-FF0E6014/",
|
41
|
+
"fdName" => "event"
|
42
|
+
},
|
43
|
+
"fdLastModifiedDate" => "2013-06-26T16:18:39.675Z",
|
44
|
+
"fdSize" => 0,
|
45
|
+
"fdContentType" => "application/octet-stream",
|
46
|
+
"fdArchive" => false,
|
47
|
+
"cstId" => 4044,
|
48
|
+
"fdType" => "directory",
|
49
|
+
"fdCreatedDate" => "2013-06-26T16:18:39.675Z"
|
50
|
+
}
|
51
|
+
end
|
52
|
+
|
53
|
+
subject { DeviceCloud::PushNotification::Message::FileData.new raw_file_data}
|
54
|
+
its(:valid?) { should be_false }
|
55
|
+
it "should set a 'wrong file type' error" do
|
56
|
+
subject.valid?
|
57
|
+
expect(subject.errors.include?('wrong file type')).to be_true
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
context 'without content' do
|
62
|
+
let(:raw_file_data) do
|
63
|
+
{
|
64
|
+
"id" => {
|
65
|
+
"fdPath" => " /db/4044_MadGlory_Interactive/00000000-00000000-001395FF-FF0E6012/alert/",
|
66
|
+
"fdName" => "foo-0966595cdcdd11e2abf50013950e6012.json"
|
67
|
+
},
|
68
|
+
"fdLastModifiedDate" => "2013-06-24T14:52:55.421Z",
|
69
|
+
"fdSize" => 156,
|
70
|
+
"fdContentType" => "application/octet-stream",
|
71
|
+
"fdData" => "",
|
72
|
+
"fdArchive" => false,
|
73
|
+
"cstId" => 4044,
|
74
|
+
"fdType" => "file",
|
75
|
+
"fdCreatedDate" => "2013-06-24T14:52:55.421Z"
|
76
|
+
}
|
77
|
+
end
|
78
|
+
|
79
|
+
subject { DeviceCloud::PushNotification::Message::FileData.new raw_file_data}
|
80
|
+
its(:valid?) { should be_false }
|
81
|
+
it "should set a 'wrong file type' error" do
|
82
|
+
subject.valid?
|
83
|
+
expect(subject.errors.include?('no content')).to be_true
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
describe "#file_path" do
|
89
|
+
context "when id present" do
|
90
|
+
subject { DeviceCloud::PushNotification::Message::FileData.new raw_file_data }
|
91
|
+
|
92
|
+
its(:file_path) { should eq raw_file_data['id']['fdPath'] }
|
93
|
+
end
|
94
|
+
|
95
|
+
context "when id blank" do
|
96
|
+
its(:file_path) { should eq '' }
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
describe "#file_name" do
|
101
|
+
context "when id present" do
|
102
|
+
subject { DeviceCloud::PushNotification::Message::FileData.new raw_file_data }
|
103
|
+
|
104
|
+
its(:file_name) { should eq raw_file_data['id']['fdName'] }
|
105
|
+
end
|
106
|
+
|
107
|
+
context "when id blank" do
|
108
|
+
its(:file_name) { should eq '' }
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
describe "#data" do
|
113
|
+
context 'when valid' do
|
114
|
+
subject { DeviceCloud::PushNotification::Message::FileData.new raw_file_data }
|
115
|
+
|
116
|
+
its(:data) { should eq(JSON.parse(Base64.decode64(raw_file_data['fdData']))) }
|
117
|
+
end
|
118
|
+
|
119
|
+
context 'when invalid' do
|
120
|
+
its(:data) { should be_false }
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
describe "#full_path" do
|
125
|
+
subject { DeviceCloud::PushNotification::Message::FileData.new raw_file_data }
|
126
|
+
|
127
|
+
its(:full_path) { should eq(raw_file_data['id']['fdPath'] + raw_file_data['id']['fdName']) }
|
128
|
+
end
|
129
|
+
end
|
@@ -0,0 +1,144 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe DeviceCloud::PushNotification::Message do
|
4
|
+
let(:single_raw_message) do
|
5
|
+
{
|
6
|
+
"timestamp" => "2013-06-24T14:52:55.427Z",
|
7
|
+
"topic" => "4044/FileData/db/4044_MadGlory_Interactive/00000000-00000000-001395FF-FF0E6012/alert/foo-0966595cdcdd11e2abf50013950e6012.json",
|
8
|
+
"FileData" => {
|
9
|
+
"id" => {
|
10
|
+
"fdPath" => " /db/4044_MadGlory_Interactive/00000000-00000000-001395FF-FF0E6012/alert/",
|
11
|
+
"fdName" => "foo-0966595cdcdd11e2abf50013950e6012.json"
|
12
|
+
},
|
13
|
+
"fdLastModifiedDate" => "2013-06-24T14:52:55.421Z",
|
14
|
+
"fdSize" => 156,
|
15
|
+
"fdContentType" => "application/json",
|
16
|
+
"fdData" => "eyJ2YWx1ZSI6IHt9LCAiY2xhc3MiOiAiYWxlcnQiLCAicXVldWVkX2R0IjogIjIwMTMtMDYtMjRUMTQ6NDc6NDdaIiwgInR5cGUiOiAiZm9vIiwgImlkIjogIjA5NjY1OTVjZGNkZDExZTJhYmY1MDAxMzk1MGU2MDEyIiwgImRldmljZV9pZCI6ICJtOjAwMTM5NTBFNjAxMiJ9",
|
17
|
+
"fdArchive" => false,
|
18
|
+
"cstId" => 4044,
|
19
|
+
"fdType" => "file",
|
20
|
+
"fdCreatedDate" => "2013-06-24T14:52:55.421Z"
|
21
|
+
},
|
22
|
+
"operation" => "INSERTION",
|
23
|
+
"replay" => true,
|
24
|
+
"group" => "*"
|
25
|
+
}
|
26
|
+
end
|
27
|
+
|
28
|
+
let(:multiple_raw_messages) do
|
29
|
+
[
|
30
|
+
{
|
31
|
+
"timestamp" => "2013-06-24T14:52:55.427Z",
|
32
|
+
"topic" => "4044/FileData/db/4044_MadGlory_Interactive/00000000-00000000-001395FF-FF0E6012/alert/foo-0966595cdcdd11e2abf50013950e6012.json",
|
33
|
+
"FileData" => {
|
34
|
+
"id" => {
|
35
|
+
"fdPath" => " /db/4044_MadGlory_Interactive/00000000-00000000-001395FF-FF0E6012/alert/",
|
36
|
+
"fdName" => "foo-0966595cdcdd11e2abf50013950e6012.json"
|
37
|
+
},
|
38
|
+
"fdLastModifiedDate" => "2013-06-24T14:52:55.421Z",
|
39
|
+
"fdSize" => 156,
|
40
|
+
"fdContentType" => "application/json",
|
41
|
+
"fdData" => "eyJ2YWx1ZSI6IHt9LCAiY2xhc3MiOiAiYWxlcnQiLCAicXVldWVkX2R0IjogIjIwMTMtMDYtMjRUMTQ6NDc6NDdaIiwgInR5cGUiOiAiZm9vIiwgImlkIjogIjA5NjY1OTVjZGNkZDExZTJhYmY1MDAxMzk1MGU2MDEyIiwgImRldmljZV9pZCI6ICJtOjAwMTM5NTBFNjAxMiJ9",
|
42
|
+
"fdArchive" => false,
|
43
|
+
"cstId" => 4044,
|
44
|
+
"fdType" => "file",
|
45
|
+
"fdCreatedDate" => "2013-06-24T14:52:55.421Z"
|
46
|
+
},
|
47
|
+
"operation" => "INSERTION",
|
48
|
+
"replay" => true,
|
49
|
+
"group" => "*"
|
50
|
+
},
|
51
|
+
{
|
52
|
+
"timestamp" => "2013-06-24T14:52:55.427Z",
|
53
|
+
"topic" => "4044/FileData/db/4044_MadGlory_Interactive/00000000-00000000-001395FF-FF0E6012/alert/foo-0966595cdcdd11e2abf50013950e6012.json",
|
54
|
+
"FileData" => {
|
55
|
+
"id" => {
|
56
|
+
"fdPath" => " /db/4044_MadGlory_Interactive/00000000-00000000-001395FF-FF0E6012/alert/",
|
57
|
+
"fdName" => "foo-0966595cdcdd11e2abf50013950e6012.json"
|
58
|
+
},
|
59
|
+
"fdLastModifiedDate" => "2013-06-24T14:52:55.421Z",
|
60
|
+
"fdSize" => 156,
|
61
|
+
"fdContentType" => "application/json",
|
62
|
+
"fdData" => "eyJ2YWx1ZSI6IHt9LCAiY2xhc3MiOiAiYWxlcnQiLCAicXVldWVkX2R0IjogIjIwMTMtMDYtMjRUMTQ6NDc6NDdaIiwgInR5cGUiOiAiZm9vIiwgImlkIjogIjA5NjY1OTVjZGNkZDExZTJhYmY1MDAxMzk1MGU2MDEyIiwgImRldmljZV9pZCI6ICJtOjAwMTM5NTBFNjAxMiJ9",
|
63
|
+
"fdArchive" => false,
|
64
|
+
"cstId" => 4044,
|
65
|
+
"fdType" => "file",
|
66
|
+
"fdCreatedDate" => "2013-06-24T14:52:55.421Z"
|
67
|
+
},
|
68
|
+
"operation" => "INSERTION",
|
69
|
+
"replay" => true,
|
70
|
+
"group" => "*"
|
71
|
+
}
|
72
|
+
]
|
73
|
+
end
|
74
|
+
|
75
|
+
describe "#parse_raw_messages" do
|
76
|
+
context "single message" do
|
77
|
+
it "should return an array" do
|
78
|
+
expect(DeviceCloud::PushNotification::Message.parse_raw_messages(single_raw_message).class).to eq(Array)
|
79
|
+
end
|
80
|
+
|
81
|
+
it "array objects should be of class DeviceCloud::PushNotification::Message" do
|
82
|
+
expect(DeviceCloud::PushNotification::Message.parse_raw_messages(single_raw_message).first.class).to eq(DeviceCloud::PushNotification::Message)
|
83
|
+
end
|
84
|
+
|
85
|
+
it "should return an array with a single item" do
|
86
|
+
expect(DeviceCloud::PushNotification::Message.parse_raw_messages(single_raw_message).size).to eq(1)
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
context "multiple messages" do
|
91
|
+
it "should return an array" do
|
92
|
+
expect(DeviceCloud::PushNotification::Message.parse_raw_messages(multiple_raw_messages).class).to eq(Array)
|
93
|
+
end
|
94
|
+
|
95
|
+
it "array objects should be of class DeviceCloud::PushNotification::Message" do
|
96
|
+
DeviceCloud::PushNotification::Message.parse_raw_messages(multiple_raw_messages).each do |item|
|
97
|
+
expect(item.class).to eq(DeviceCloud::PushNotification::Message)
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
it "should return an array with the same amount of items it was passed" do
|
102
|
+
expect(DeviceCloud::PushNotification::Message.parse_raw_messages(multiple_raw_messages).size).to eq(multiple_raw_messages.size)
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
describe "#valid?" do
|
107
|
+
context "with file_data and allowed topic" do
|
108
|
+
subject { DeviceCloud::PushNotification::Message.new 'FileData' => 'present', 'topic' => DeviceCloud::PushNotification::Message::ALLOWED_TOPICS.sample }
|
109
|
+
its(:valid?) { should be_true }
|
110
|
+
end
|
111
|
+
|
112
|
+
context "without file_data" do
|
113
|
+
subject { DeviceCloud::PushNotification::Message.new 'topic' => DeviceCloud::PushNotification::Message::ALLOWED_TOPICS.sample }
|
114
|
+
its(:valid?) { should_not be_true }
|
115
|
+
end
|
116
|
+
|
117
|
+
context "without allowed topic" do
|
118
|
+
subject { DeviceCloud::PushNotification::Message.new 'FileData' => 'present' }
|
119
|
+
its(:valid?) { should_not be_true }
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
describe "#parsed_file_data" do
|
124
|
+
context "when invalid" do
|
125
|
+
it "should be false" do
|
126
|
+
expect(subject.parsed_file_data).to be_false
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
130
|
+
context "when valid" do
|
131
|
+
subject { DeviceCloud::PushNotification::Message.new 'FileData' => single_raw_message["FileData"], 'topic' => DeviceCloud::PushNotification::Message::ALLOWED_TOPICS.sample }
|
132
|
+
|
133
|
+
it "should return a DeviceCloud::PushNotification::Message::FileData object" do
|
134
|
+
expect(subject.parsed_file_data.class).to eq(DeviceCloud::PushNotification::Message::FileData)
|
135
|
+
end
|
136
|
+
|
137
|
+
it "should cache the FileData object" do
|
138
|
+
file_data1 = subject.parsed_file_data
|
139
|
+
subject.parsed_file_data.should === file_data1
|
140
|
+
end
|
141
|
+
end
|
142
|
+
end
|
143
|
+
end
|
144
|
+
end
|
@@ -0,0 +1,87 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe DeviceCloud::PushNotification do
|
4
|
+
let(:raw_messages) do
|
5
|
+
[
|
6
|
+
{ 'topic_type' => 'an alert' },
|
7
|
+
{ 'topic_type' => 'an event' }
|
8
|
+
]
|
9
|
+
end
|
10
|
+
let(:valid_parsed_messages) do
|
11
|
+
[
|
12
|
+
OpenStruct.new(
|
13
|
+
valid?: true,
|
14
|
+
valid_parsed_file_data?: true,
|
15
|
+
topic_type: 'alert',
|
16
|
+
parsed_file_data: 'the alert data'
|
17
|
+
),
|
18
|
+
OpenStruct.new(
|
19
|
+
valid?: true,
|
20
|
+
valid_parsed_file_data?: true,
|
21
|
+
topic_type: 'event',
|
22
|
+
parsed_file_data: 'the event data'
|
23
|
+
)
|
24
|
+
]
|
25
|
+
end
|
26
|
+
|
27
|
+
subject { DeviceCloud::PushNotification.new raw_messages }
|
28
|
+
|
29
|
+
describe "attributes" do
|
30
|
+
before(:each) do
|
31
|
+
DeviceCloud::PushNotification::Message.should_receive(:parse_raw_messages).with(raw_messages).and_return(valid_parsed_messages)
|
32
|
+
end
|
33
|
+
its(:messages) { should eq valid_parsed_messages }
|
34
|
+
end
|
35
|
+
|
36
|
+
describe "#handle_each!" do
|
37
|
+
before(:each) do
|
38
|
+
DeviceCloud::PushNotification::Message.should_receive(:parse_raw_messages).with(raw_messages).and_return(valid_parsed_messages)
|
39
|
+
end
|
40
|
+
|
41
|
+
context "all valid" do
|
42
|
+
|
43
|
+
it "should call handle! on each of the message's topic_type classes" do
|
44
|
+
DeviceCloud::PushNotification::Alert.should_receive(:handle!).with(valid_parsed_messages[0].parsed_file_data)
|
45
|
+
|
46
|
+
DeviceCloud::PushNotification::Event.should_receive(:handle!).with(valid_parsed_messages[1].parsed_file_data)
|
47
|
+
|
48
|
+
subject.handle_each!
|
49
|
+
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
context "an invalid message" do
|
54
|
+
it "should not be handled" do
|
55
|
+
valid_parsed_messages[0] = OpenStruct.new(
|
56
|
+
valid?: false, # test condition
|
57
|
+
valid_parsed_file_data?: true,
|
58
|
+
topic_type: 'alert',
|
59
|
+
parsed_file_data: 'the alert data'
|
60
|
+
)
|
61
|
+
|
62
|
+
DeviceCloud::PushNotification::Alert.should_not_receive(:handle!)
|
63
|
+
|
64
|
+
DeviceCloud::PushNotification::Event.should_receive(:handle!)
|
65
|
+
|
66
|
+
subject.handle_each!
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
context "an invalid parsed_file_data" do
|
71
|
+
it "should not be handled" do
|
72
|
+
valid_parsed_messages[0] = OpenStruct.new(
|
73
|
+
valid?: true,
|
74
|
+
valid_parsed_file_data?: false, # test condition
|
75
|
+
topic_type: 'alert',
|
76
|
+
parsed_file_data: 'the alert data'
|
77
|
+
)
|
78
|
+
|
79
|
+
DeviceCloud::PushNotification::Alert.should_not_receive(:handle!)
|
80
|
+
|
81
|
+
DeviceCloud::PushNotification::Event.should_receive(:handle!)
|
82
|
+
|
83
|
+
subject.handle_each!
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
require 'device_cloud'
|
2
|
+
require 'ostruct'
|
3
|
+
|
4
|
+
RSpec.configure do |config|
|
5
|
+
config.mock_with :rspec
|
6
|
+
|
7
|
+
config.before(:each) do
|
8
|
+
DeviceCloud.configure do |configuration|
|
9
|
+
configuration.username = 'a username'
|
10
|
+
configuration.password = 'a password'
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
metadata
ADDED
@@ -0,0 +1,128 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: device_cloud
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Erik Straub
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2013-08-07 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: bundler
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ~>
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: '1.3'
|
22
|
+
type: :development
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ~>
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: '1.3'
|
30
|
+
- !ruby/object:Gem::Dependency
|
31
|
+
name: rake
|
32
|
+
requirement: !ruby/object:Gem::Requirement
|
33
|
+
none: false
|
34
|
+
requirements:
|
35
|
+
- - ! '>='
|
36
|
+
- !ruby/object:Gem::Version
|
37
|
+
version: '0'
|
38
|
+
type: :development
|
39
|
+
prerelease: false
|
40
|
+
version_requirements: !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - ! '>='
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: '0'
|
46
|
+
- !ruby/object:Gem::Dependency
|
47
|
+
name: rspec
|
48
|
+
requirement: !ruby/object:Gem::Requirement
|
49
|
+
none: false
|
50
|
+
requirements:
|
51
|
+
- - ! '>='
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: '0'
|
54
|
+
type: :development
|
55
|
+
prerelease: false
|
56
|
+
version_requirements: !ruby/object:Gem::Requirement
|
57
|
+
none: false
|
58
|
+
requirements:
|
59
|
+
- - ! '>='
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
description: A Ruby wrapper for the Etherios Device Cloud
|
63
|
+
email:
|
64
|
+
- erik@madgloryint.com
|
65
|
+
executables: []
|
66
|
+
extensions: []
|
67
|
+
extra_rdoc_files: []
|
68
|
+
files:
|
69
|
+
- .gitignore
|
70
|
+
- .rspec
|
71
|
+
- .ruby-version
|
72
|
+
- Gemfile
|
73
|
+
- LICENSE.txt
|
74
|
+
- README.md
|
75
|
+
- Rakefile
|
76
|
+
- device_cloud.gemspec
|
77
|
+
- lib/device_cloud.rb
|
78
|
+
- lib/device_cloud/configuration.rb
|
79
|
+
- lib/device_cloud/push_notification.rb
|
80
|
+
- lib/device_cloud/push_notification/alert.rb
|
81
|
+
- lib/device_cloud/push_notification/base.rb
|
82
|
+
- lib/device_cloud/push_notification/event.rb
|
83
|
+
- lib/device_cloud/push_notification/message.rb
|
84
|
+
- lib/device_cloud/push_notification/message/file_data.rb
|
85
|
+
- lib/device_cloud/utils.rb
|
86
|
+
- lib/device_cloud/version.rb
|
87
|
+
- spec/device_cloud/push_notification/alert_spec.rb
|
88
|
+
- spec/device_cloud/push_notification/base_spec.rb
|
89
|
+
- spec/device_cloud/push_notification/event_spec.rb
|
90
|
+
- spec/device_cloud/push_notification/message/file_data_spec.rb
|
91
|
+
- spec/device_cloud/push_notification/message_spec.rb
|
92
|
+
- spec/device_cloud/push_notification_spec.rb
|
93
|
+
- spec/spec_helper.rb
|
94
|
+
- spec/version_spec.rb
|
95
|
+
homepage: http://github.com/madgloryint/device_cloud
|
96
|
+
licenses:
|
97
|
+
- MIT
|
98
|
+
post_install_message:
|
99
|
+
rdoc_options: []
|
100
|
+
require_paths:
|
101
|
+
- lib
|
102
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
103
|
+
none: false
|
104
|
+
requirements:
|
105
|
+
- - ! '>='
|
106
|
+
- !ruby/object:Gem::Version
|
107
|
+
version: '0'
|
108
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
109
|
+
none: false
|
110
|
+
requirements:
|
111
|
+
- - ! '>='
|
112
|
+
- !ruby/object:Gem::Version
|
113
|
+
version: '0'
|
114
|
+
requirements: []
|
115
|
+
rubyforge_project:
|
116
|
+
rubygems_version: 1.8.23
|
117
|
+
signing_key:
|
118
|
+
specification_version: 3
|
119
|
+
summary: A Ruby wrapper for the Etherios Device Cloud
|
120
|
+
test_files:
|
121
|
+
- spec/device_cloud/push_notification/alert_spec.rb
|
122
|
+
- spec/device_cloud/push_notification/base_spec.rb
|
123
|
+
- spec/device_cloud/push_notification/event_spec.rb
|
124
|
+
- spec/device_cloud/push_notification/message/file_data_spec.rb
|
125
|
+
- spec/device_cloud/push_notification/message_spec.rb
|
126
|
+
- spec/device_cloud/push_notification_spec.rb
|
127
|
+
- spec/spec_helper.rb
|
128
|
+
- spec/version_spec.rb
|