device_cloud 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore ADDED
@@ -0,0 +1,17 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --format nested
2
+ --color
data/.ruby-version ADDED
@@ -0,0 +1 @@
1
+ 1.9.3-p392
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in device_cloud.gemspec
4
+ gemspec
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,7 @@
1
+ module DeviceCloud
2
+ class PushNotification::Alert < PushNotification::Base
3
+ def handle!
4
+ DeviceCloud.push_notification_alert_handler.call(self)
5
+ end
6
+ end
7
+ 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,7 @@
1
+ module DeviceCloud
2
+ class PushNotification::Event < PushNotification::Base
3
+ def handle!
4
+ DeviceCloud.push_notification_event_handler.call(self)
5
+ end
6
+ end
7
+ 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
@@ -0,0 +1,11 @@
1
+ module DeviceCloud
2
+ module Utils
3
+ def mac_address_from_device_id(device_id)
4
+ device_id.sub(/\Am:/, '').scan(/.{2}|.+/).join(':')
5
+ end
6
+
7
+ def constantize(string)
8
+ string.split("::").inject(Module) {|acc, val| acc.const_get(val)}
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,3 @@
1
+ module DeviceCloud
2
+ VERSION = "0.0.1"
3
+ end
@@ -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
@@ -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
@@ -0,0 +1,7 @@
1
+ require 'spec_helper'
2
+
3
+ describe 'DeviceCloud::VERSION' do
4
+ it 'should be the correct version' do
5
+ DeviceCloud::VERSION.should == '0.0.1'
6
+ end
7
+ 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