diff --git a/device_cloud.gemspec b/device_cloud.gemspec
index a9cc6de..9e9d4a6 100644
--- a/device_cloud.gemspec
+++ b/device_cloud.gemspec
@@ -4,22 +4,24 @@ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
require 'device_cloud/version'
Gem::Specification.new do |spec|
- spec.name = "device_cloud"
+ spec.name = 'device_cloud'
spec.version = DeviceCloud::VERSION
- spec.authors = ["Erik Straub"]
- spec.email = ["erik@madgloryint.com"]
+ spec.authors = ['Erik Straub']
+ spec.email = ['erik@madgloryint.com']
spec.description = %q{A Ruby wrapper for the Etherios Device Cloud}
spec.summary = %q{A Ruby wrapper for the Etherios Device Cloud}
- spec.homepage = "http://github.com/madgloryint/device_cloud"
- spec.license = "MIT"
+ spec.homepage = 'http://github.com/madgloryint/device_cloud'
+ spec.license = 'MIT'
spec.files = `git ls-files`.split($/)
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
- spec.require_paths = ["lib"]
+ spec.require_paths = ['lib']
- spec.add_development_dependency "bundler", "~> 1.3"
- spec.add_development_dependency "rake"
+ spec.add_dependency 'nori', '~> 2.3'
+
+ spec.add_development_dependency 'bundler', '~> 1.3'
+ spec.add_development_dependency 'rake'
spec.add_development_dependency 'rspec'
spec.add_development_dependency 'webmock'
spec.add_development_dependency 'pry'
diff --git a/lib/device_cloud.rb b/lib/device_cloud.rb
index 4492862..233294d 100644
--- a/lib/device_cloud.rb
+++ b/lib/device_cloud.rb
@@ -1,6 +1,10 @@
require 'device_cloud/configuration'
require 'device_cloud/utils'
require 'device_cloud/version'
+require 'device_cloud/alarm'
+require 'device_cloud/device_disconnect_alarm'
+require 'device_cloud/alarm_template'
+require 'device_cloud/group'
require 'device_cloud/monitor'
require 'device_cloud/push_notification'
require 'device_cloud/push_notification/base_notification'
@@ -11,6 +15,7 @@
require 'device_cloud/push_notification/message/file_data'
require 'device_cloud/request'
require 'device_cloud/response'
+require 'nori'
module DeviceCloud
extend Configuration
diff --git a/lib/device_cloud/alarm.rb b/lib/device_cloud/alarm.rb
new file mode 100644
index 0000000..1652f4b
--- /dev/null
+++ b/lib/device_cloud/alarm.rb
@@ -0,0 +1,173 @@
+module DeviceCloud
+ class Alarm
+
+ attr_accessor :almId, :cstId, :almtId, :grpId, :almName, :almDescription, :almScopeConfig, :almRuleConfig
+ attr_reader :error, :almEnabled, :almPriority
+
+ class << self
+ def all
+ response = DeviceCloud::Request.new(path: '/ws/Alarm').get
+ alarms = response.to_hash_from_xml
+
+ return [] unless response.code == '200' && alarms['result']['resultSize'].to_i > 0
+
+ if alarms['result']['resultSize'].to_i == 1
+ [initialize_proper_alarm_type(alarms['result']['Alarm'])]
+ else
+ alarms['result']['Alarm'].map { |alarm|
+ initialize_proper_alarm_type(alarm)
+ }
+ end
+ end
+
+ def find(id)
+ response = DeviceCloud::Request.new(path: "/ws/Alarm/#{id}").get
+ alarms = response.to_hash_from_xml
+
+ return nil unless response.code == '200' && alarms['result']['resultSize'].to_i > 0
+
+ if alarms['result']['resultSize'].to_i == 1
+ initialize_proper_alarm_type(alarms['result']['Alarm'])
+ else
+ initialize_proper_alarm_type(alarms['result']['Alarm'].first)
+ end
+ end
+
+ protected
+ def initialize_proper_alarm_type(alarm)
+ case alarm['almtId']
+ when '2' then DeviceDisconnectAlarm.new(alarm)
+ else Alarm.new(alarm)
+ end
+ end
+ end
+
+ def initialize(attributes = {})
+ set_defaults
+
+ attributes.each do |name, value|
+ send("#{name}=", value)
+ end
+ end
+
+ def almEnabled=(value)
+ @almEnabled = !!value
+ end
+
+ def almPriority=(value)
+ raise DeviceCloud::Error, 'almPriority must be 0 (high), 1 (medium), or 2 (low)' unless [0,1,2].include?(value.to_i)
+ @almPriority = value.to_i
+ end
+
+ def persist!
+ remove_instance_variable '@error' if error
+ almId.nil? ? create : update
+ end
+
+ def destroy!
+ return false if almId.nil?
+
+ response = DeviceCloud::Request.new(path: "/ws/Alarm/#{almId}").delete
+
+ response.code == '200' ? true : false
+ end
+
+ def attributes
+ available_attributes.inject({}) do |memo, attr_name|
+ memo[attr_name] = send(attr_name) unless send(attr_name).nil?
+ memo
+ end
+ end
+
+ protected
+ def set_defaults
+ # no-op
+ end
+
+ def available_attributes
+ %w{
+ almtId
+ almName
+ almDescription
+ almPriority
+ almEnabled
+ grpId
+ }
+ end
+
+ def create
+ response = DeviceCloud::Request.new(path: '/ws/Alarm', body: to_xml).post
+ xml_result = response.to_hash_from_xml['result']
+
+ if response.code == '201'
+ self.almId = xml_result['location'].sub /Alarm\//, ''
+ return true
+ else
+ @error = xml_result['error']
+ return false
+ end
+ end
+
+ def update
+ response = DeviceCloud::Request.new(path: "/ws/Alarm/#{almId}", body: to_xml).put
+
+ if response.code == '200'
+ return true
+ else
+ @error = error_from_response_xml(response)
+ return false
+ end
+ end
+
+ def to_xml
+ xml = ''
+ attributes.each do |key,value|
+ xml << "<#{key}>#{value}#{key}>"
+ end
+ xml << alarm_scope_config_xml
+ xml << alarm_rule_config_xml
+ xml << ''
+ end
+
+ # Method to set the Alarm's scope
+ #
+ # Example:
+ #
+ #
+ #
+ #
+ #
+ def alarm_scope_config_xml
+ raise NotImplementedError
+ end
+
+ # Method to set the Alarm's rules
+ #
+ # Example:
+ #
+ #
+ #
+ #
+ #
+ #
+ #
+ #
+ #
+ #
+ #
+ #
+ #
+ #
+ #
+ #
+ #
+ #
+ def alarm_rule_config_xml
+ raise NotImplementedError
+ end
+
+ def error_from_response_xml(response)
+ response.body.match(/(.*)<\/error>/)[1]
+ end
+ end
+end
diff --git a/lib/device_cloud/alarm_template.rb b/lib/device_cloud/alarm_template.rb
new file mode 100644
index 0000000..9d7a255
--- /dev/null
+++ b/lib/device_cloud/alarm_template.rb
@@ -0,0 +1,38 @@
+module DeviceCloud
+ class AlarmTemplate
+
+ attr_reader :almtId, :almtName, :almtDescription, :grpId, :almtTopic, :almtScopeOptions, :almtRules, :almtResourceList
+
+ class << self
+ def all
+ response = DeviceCloud::Request.new(path: '/ws/AlarmTemplate').get
+ templates = response.to_hash_from_xml
+
+ return [] unless response.code == '200' && templates['result']['resultSize'].to_i > 0
+
+ if templates['result']['resultSize'].to_i == 1
+ [AlarmTemplate.new(templates['result']['AlarmTemplate'])]
+ else
+ templates['result']['AlarmTemplate'].map { |template|
+ AlarmTemplate.new template
+ }
+ end
+ end
+
+ def find(id)
+ response = DeviceCloud::Request.new(path: "/ws/AlarmTemplate/#{id}").get
+ templates = response.to_hash_from_xml
+
+ return nil unless response.code == '200' && templates['result']['resultSize'].to_i == 1
+
+ AlarmTemplate.new(templates['result']['AlarmTemplate'])
+ end
+ end
+
+ def initialize(attributes = {})
+ attributes.each do |name, value|
+ instance_variable_set("@#{name}", value)
+ end
+ end
+ end
+end
diff --git a/lib/device_cloud/configuration.rb b/lib/device_cloud/configuration.rb
index 35d255d..bfd294e 100644
--- a/lib/device_cloud/configuration.rb
+++ b/lib/device_cloud/configuration.rb
@@ -110,5 +110,19 @@ def password
def logger
@logger ||= Logger.new(STDOUT)
end
+
+ # DeviceCloud logger
+ #
+ # @return the DeviceCloud logger or set the default to stdout
+ def logger
+ @logger ||= Logger.new(STDOUT)
+ end
+
+ # DeviceCloud xml_parser
+ #
+ # @return the DeviceCloud xml_parser - default is Nori using rexml
+ def xml_parser
+ Nori.new(parser: :rexml)
+ end
end
end
diff --git a/lib/device_cloud/device_disconnect_alarm.rb b/lib/device_cloud/device_disconnect_alarm.rb
new file mode 100644
index 0000000..43e7461
--- /dev/null
+++ b/lib/device_cloud/device_disconnect_alarm.rb
@@ -0,0 +1,86 @@
+module DeviceCloud
+ class DeviceDisconnectAlarm < Alarm
+ attr_accessor :reconnectWindowDuration, :reset_on_reconnect, :device_id, :group
+ attr_reader :group
+
+ def group=(group_object)
+ raise DeviceCloud::Error, 'Must be a DeviceCloud::Group' unless group_object.is_a?(DeviceCloud::Group)
+
+ @group = group_object
+ self.grpId = group.grpId
+ end
+
+ def initialize(attributes = {})
+ super
+ load_group
+ load_device_id
+ self.almtId = 2
+ end
+
+ def persist!
+ raise DeviceCloud::Error, 'Must specify @group or @device_id.' unless group || device_id
+ super
+ end
+ private
+ def default_create_options
+ {
+ 'reconnectWindowDuration' => '5',
+ 'reset_on_reconnect' => true
+ }
+ end
+
+ def set_defaults
+ super
+ default_create_options.each do |k,v|
+ send("#{k}=",v)
+ end
+ end
+
+ def alarm_scope_config_xml
+ return '' if group.nil? && device_id.nil?
+ "\n#{scope_xml}\n"
+ end
+
+ def scope_xml
+ group.nil? ? device_scope_xml : group_scope_xml
+ end
+
+ def group_scope_xml
+ ""
+ end
+
+ def device_scope_xml
+ ""
+ end
+
+ def alarm_rule_config_xml
+ xml = "\n"
+ xml << fire_rule_xml
+ xml << reset_rule_xml
+ xml << "\n"
+ end
+
+ def reset_rule_xml
+ xml = '\n"
+ end
+
+ def fire_rule_xml
+ xml = ''
+ xml << '\n"
+ end
+
+ def load_group
+ return if almScopeConfig.nil? || almScopeConfig['ScopingOptions']['Scope']['@name'] != 'Group'
+ @group ||= DeviceCloud::Group.find(grpId)
+ end
+
+ def load_device_id
+ return if almScopeConfig.nil? || almScopeConfig['ScopingOptions']['Scope']['@name'] != 'Device'
+ @device_id ||= almScopeConfig['ScopingOptions']['Scope']['@value']
+ end
+ end
+end
diff --git a/lib/device_cloud/group.rb b/lib/device_cloud/group.rb
new file mode 100644
index 0000000..2102f30
--- /dev/null
+++ b/lib/device_cloud/group.rb
@@ -0,0 +1,53 @@
+module DeviceCloud
+ class Group
+ attr_reader :grpId, :grpName, :grpDescription, :grpPath, :grpParentId
+
+ ALLOWED_ATTRIBUTES = %w{
+ grpId
+ grpName
+ grpDescription
+ grpPath
+ grpParentId
+ }
+
+ class << self
+ def all
+ groups = DeviceCloud::Request.new(path: '/ws/Group/.json').get.to_hash_from_json
+
+ return [] unless groups['resultSize'].to_i > 0
+
+ groups['items'].map { |group|
+ Group.new group
+ }
+ end
+
+ def find(group_id)
+ groups = DeviceCloud::Request.new(path: "/ws/Group/#{group_id}.json").get.to_hash_from_json
+
+ return nil unless groups['resultSize'].to_i > 0
+
+ Group.new groups['items'].first
+ end
+
+ def find_all_by_parent_id(parent_id)
+ parent_id = parent_id.to_i
+
+ path = "/ws/Group/.json?condition=grpParentId='#{parent_id}'"
+
+ groups = DeviceCloud::Request.new(path: path).get.to_hash_from_json
+
+ return [] unless groups['resultSize'].to_i > 0
+
+ groups['items'].map { |group|
+ Group.new group
+ }
+ end
+ end
+
+ def initialize(attributes = {})
+ ALLOWED_ATTRIBUTES.each do |attr_name|
+ instance_variable_set("@#{attr_name}", attributes[attr_name])
+ end
+ end
+ end
+end
diff --git a/lib/device_cloud/response.rb b/lib/device_cloud/response.rb
index b871023..bb47dd9 100644
--- a/lib/device_cloud/response.rb
+++ b/lib/device_cloud/response.rb
@@ -10,6 +10,10 @@ def initialize(http_response)
@body = original_response.body
end
+ def to_hash_from_xml
+ DeviceCloud.xml_parser.parse(body)
+ end
+
def to_hash_from_json
JSON.parse(body)
end
diff --git a/spec/device_cloud/alarm_spec.rb b/spec/device_cloud/alarm_spec.rb
new file mode 100644
index 0000000..1f86a87
--- /dev/null
+++ b/spec/device_cloud/alarm_spec.rb
@@ -0,0 +1,247 @@
+require 'spec_helper'
+
+describe DeviceCloud::Alarm do
+ its(:almId) { should be_nil }
+ its(:cstId) { should be_nil }
+ its(:almtId) { should be_nil }
+ its(:grpId) { should be_nil }
+ its(:almName) { should be_nil }
+ its(:almDescription) { should be_nil }
+ its(:almScopeConfig) { should be_nil }
+ its(:almRuleConfig) { should be_nil }
+ its(:almEnabled) { should be_nil }
+ its(:almPriority) { should be_nil }
+ its(:error) { should be_nil }
+
+ context 'when attributes given' do
+ let(:attributes) do
+ {
+ almId: 'foo',
+ cstId: 'foo',
+ almtId: 'foo',
+ grpId: 'foo',
+ almName: 'foo',
+ almDescription: 'foo',
+ almScopeConfig: 'foo',
+ almRuleConfig: 'foo',
+ almEnabled: true,
+ almPriority: 2
+ }
+ end
+
+ subject { DeviceCloud::Alarm.new attributes}
+
+ its(:almId) { should eq 'foo' }
+ its(:cstId) { should eq 'foo' }
+ its(:almtId) { should eq 'foo' }
+ its(:grpId) { should eq 'foo' }
+ its(:almName) { should eq 'foo' }
+ its(:almDescription) { should eq 'foo' }
+ its(:almScopeConfig) { should eq 'foo' }
+ its(:almRuleConfig) { should eq 'foo' }
+ its(:almEnabled) { should eq true }
+ its(:almPriority) { should eq 2 }
+ end
+
+ describe '::all' do
+ let(:group_body) do
+ %{{"resultTotalRows": "1","requestedStartRow": "0","resultSize": "1","requestedSize": "1000","remainingSize": "0","items": [{ "grpId": "9769", "grpName": "Staging", "grpPath": "/4044_MadGlory_Interactive/Staging/", "grpParentId": "4946"}] }}
+ end
+
+ before(:each) do
+ stub_request(:get, "https://foouser:barpass@my.idigi.com/ws/Alarm").
+ with(:headers => {'Accept'=>'*/*', 'User-Agent'=>'Ruby'}).
+ to_return(:status => 200, :body => response_body, :headers => {})
+ end
+
+ subject { DeviceCloud::Alarm.all }
+
+ context 'when results are found' do
+ before(:each) do
+ stub_request(:get, "https://foouser:barpass@my.idigi.com/ws/Group/9769.json").
+ with(:headers => {'Accept'=>'*/*', 'User-Agent'=>'Ruby'}).
+ to_return(:status => 200, :body => group_body, :headers => {})
+ end
+
+ let(:response_body) do
+ %{
+
+ 1
+ 0
+ 1
+ 1000
+ 0
+
+ 1898
+ 4044
+ #{almtId}
+ 9769
+ Staging Device Disconnect
+ Detects when a device disconnects from Device Cloud and fails to reconnected within the specified time
+ true
+ 1
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ }
+ end
+
+
+ context 'result has a known almtId' do
+ let(:almtId) { 2 }
+
+ it { should be_a(Array) }
+ its(:first) { should be_a(DeviceCloud::DeviceDisconnectAlarm) }
+ end
+
+ context 'result has unknown almtId' do
+ let(:almtId) { 26 }
+
+ it { should be_a(Array) }
+ its(:first) { should be_a(DeviceCloud::Alarm) }
+ end
+ end
+
+ context 'when results are not found' do
+ let(:response_body) do
+ %{
+
+ 0
+ 0
+ 0
+ 1000
+ 0
+ }
+ end
+
+ it { should eq [] }
+ end
+ end
+
+ describe '::find' do
+ before(:each) do
+ stub_request(:get, "https://foouser:barpass@my.idigi.com/ws/Alarm/1898").
+ with(:headers => {'Accept'=>'*/*', 'User-Agent'=>'Ruby'}).
+ to_return(:status => 200, :body => response_body, :headers => {})
+ end
+
+ subject { DeviceCloud::Alarm.find 1898 }
+
+ context 'when result is found' do
+ let(:group_body) do
+ %{{"resultTotalRows": "1","requestedStartRow": "0","resultSize": "1","requestedSize": "1000","remainingSize": "0","items": [{ "grpId": "9769", "grpName": "Staging", "grpPath": "/4044_MadGlory_Interactive/Staging/", "grpParentId": "4946"}] }}
+ end
+
+ before(:each) do
+ stub_request(:get, "https://foouser:barpass@my.idigi.com/ws/Group/9769.json").
+ with(:headers => {'Accept'=>'*/*', 'User-Agent'=>'Ruby'}).
+ to_return(:status => 200, :body => group_body, :headers => {})
+ end
+
+ let(:response_body) do
+ %{
+
+ 1
+ 0
+ 1
+ 1000
+ 0
+
+ 1898
+ 4044
+ #{almtId}
+ 9769
+ Staging Device Disconnect
+ Detects when a device disconnects from Device Cloud and fails to reconnected within the specified time
+ true
+ 1
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ }
+ end
+
+ context 'with a known almtId' do
+ let(:almtId) { 2 }
+ it { should be_a(DeviceCloud::DeviceDisconnectAlarm) }
+ end
+
+ context 'with an unknown almtId' do
+ let(:almtId) { 26 }
+ it { should be_a(DeviceCloud::Alarm)}
+ end
+ end
+
+ context 'when result is not found' do
+ let(:response_body) do
+ %{
+
+ GET AlarmTemplate error. Error reading AlarmTemplate entity id='212'
+ }
+ end
+
+ it { should be_nil }
+ end
+ end
+
+ describe '#persist!' do
+ subject { DeviceCloud::Alarm.new }
+
+ it 'raises NotImplementedError' do
+ expect { subject.persist! }.to raise_error(NotImplementedError)
+ end
+ end
+
+ describe '#destroy!' do
+ context 'when almId is nil' do
+ its(:destroy!) { should be_false }
+ end
+
+ context 'when almId is not nil' do
+ let(:existing_alarm) { DeviceCloud::Alarm.new almId: 12345 }
+ before(:each) do
+ stub_request(:delete, "https://foouser:barpass@my.idigi.com/ws/Alarm/12345").
+ with(:headers => {'Accept'=>'*/*', 'User-Agent'=>'Ruby'}).
+ to_return(:status => response_status, :body => response_body, :headers => {})
+ end
+
+ subject { existing_alarm.destroy! }
+
+ context 'when successful' do
+ let(:response_body) { "\n\n 1 items deleted\n" }
+ let(:response_status) { 200 }
+
+ it { should be_true }
+ end
+
+ context 'when unsuccessful' do
+ let(:response_body) { "\n\n DELETE Alarm error. Invalid request. For input string: \"gigo\"\n" }
+ let(:response_status) { 400 }
+
+ it { should be_false }
+ end
+ end
+ end
+end
diff --git a/spec/device_cloud/alarm_template_spec.rb b/spec/device_cloud/alarm_template_spec.rb
new file mode 100644
index 0000000..3f270d9
--- /dev/null
+++ b/spec/device_cloud/alarm_template_spec.rb
@@ -0,0 +1,161 @@
+require 'spec_helper'
+
+describe DeviceCloud::AlarmTemplate do
+
+ its(:almtId) { should be_nil }
+ its(:almtName) { should be_nil }
+ its(:almtDescription) { should be_nil }
+ its(:grpId) { should be_nil }
+ its(:almtTopic) { should be_nil }
+ its(:almtScopeOptions) { should be_nil }
+ its(:almtRules) { should be_nil }
+ its(:almtResourceList) { should be_nil }
+
+ context 'when attributes given' do
+ let(:attributes) do
+ {
+ almtId: 'foo',
+ almtName: 'foo',
+ almtDescription: 'foo',
+ grpId: 'foo',
+ almtTopic: 'foo',
+ almtScopeOptions: 'foo',
+ almtRules: 'foo',
+ almtResourceList: 'foo'
+ }
+ end
+
+ subject { DeviceCloud::AlarmTemplate.new attributes }
+
+ its(:almtId) { should eq 'foo' }
+ its(:almtName) { should eq 'foo' }
+ its(:almtDescription) { should eq 'foo' }
+ its(:grpId) { should eq 'foo' }
+ its(:almtTopic) { should eq 'foo' }
+ its(:almtScopeOptions) { should eq 'foo' }
+ its(:almtRules) { should eq 'foo' }
+ its(:almtResourceList) { should eq 'foo' }
+ end
+
+ describe '::all' do
+ before(:each) do
+ stub_request(:get, "https://foouser:barpass@my.idigi.com/ws/AlarmTemplate").
+ with(:headers => {'Accept'=>'*/*', 'User-Agent'=>'Ruby'}).
+ to_return(:status => 200, :body => response_body, :headers => {})
+ end
+
+ subject { DeviceCloud::AlarmTemplate.all }
+
+ context 'when results are found' do
+ let(:response_body) do
+ %{
+
+ 1
+ 0
+ 1
+ 1000
+ 0
+
+ 2
+ Device Offline
+ Detects when a device disconnects from Device Cloud and fails to reconnected within the specified time
+ 1
+ Alarm.DeviceOffline
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ DeviceCore,AlarmStatus
+
+ }
+ end
+
+ it { should be_a(Array) }
+ its(:first) { should be_a(DeviceCloud::AlarmTemplate) }
+ its(:size) { should eq 1 }
+ end
+
+ context 'when results are not found' do
+ let(:response_body) do
+ %{
+
+ 0
+ 0
+ 0
+ 1000
+ 0
+ }
+ end
+
+ it { should eq [] }
+ end
+ end
+
+ describe '::find' do
+ before(:each) do
+ stub_request(:get, "https://foouser:barpass@my.idigi.com/ws/AlarmTemplate/2").
+ with(:headers => {'Accept'=>'*/*', 'User-Agent'=>'Ruby'}).
+ to_return(:status => 200, :body => response_body, :headers => {})
+ end
+
+ subject { DeviceCloud::AlarmTemplate.find 2 }
+
+ context 'when result is found' do
+ let(:response_body) do
+ %{
+
+ 1
+ 0
+ 1
+ 1000
+ 0
+
+ 2
+ Device Offline
+ Detects when a device disconnects from Device Cloud and fails to reconnected within the specified time
+ 1
+ Alarm.DeviceOffline
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ DeviceCore,AlarmStatus
+
+ }
+ end
+
+ it { should be_a(DeviceCloud::AlarmTemplate) }
+ end
+
+ context 'when result is not found' do
+ let(:response_body) do
+ %{
+
+ GET AlarmTemplate error. Error reading AlarmTemplate entity id='212'
+ }
+ end
+
+ it { should be_nil }
+ end
+ end
+end
diff --git a/spec/device_cloud/device_disconnect_alarm_spec.rb b/spec/device_cloud/device_disconnect_alarm_spec.rb
new file mode 100644
index 0000000..2c97a91
--- /dev/null
+++ b/spec/device_cloud/device_disconnect_alarm_spec.rb
@@ -0,0 +1,5 @@
+require 'spec_helper'
+
+describe DeviceCloud::DeviceDisconnectAlarm do
+ pending 'Add specs'
+end
diff --git a/spec/device_cloud/group_spec.rb b/spec/device_cloud/group_spec.rb
new file mode 100644
index 0000000..5107152
--- /dev/null
+++ b/spec/device_cloud/group_spec.rb
@@ -0,0 +1,112 @@
+require 'spec_helper'
+
+describe DeviceCloud::Group do
+ describe '::all' do
+ before(:each) do
+ stub_request(:get, authenticated_host + '/ws/Group/.json').
+ with(:headers => {'Accept'=>'*/*', 'User-Agent'=>'Ruby'}).
+ to_return(:status => 200, :body => groups_json, :headers => {})
+ end
+
+ subject { DeviceCloud::Group.all }
+
+ context 'with results' do
+ let(:groups_json) do
+ "{\"resultTotalRows\": \"2\",\"requestedStartRow\": \"0\",\"resultSize\": \"2\",\"requestedSize\": \"1000\",\"remainingSize\": \"0\",\"items\": [{ \"grpId\": \"4946\", \"grpName\": \"Your_Company\", \"grpDescription\": \"Your_Company root group\", \"grpPath\": \"/Your_Company/\", \"grpParentId\": \"1\"},{ \"grpId\": \"9769\", \"grpName\": \"Sub_Group\", \"grpPath\": \"/Your_Company/Sub_Group/\", \"grpParentId\": \"4946\"}] }"
+ end
+
+ it { should be_a(Array) }
+ its(:size) { should eq 2 }
+ its(:first) { should be_a(DeviceCloud::Group) }
+ end
+
+ context 'with no results' do
+ let(:groups_json) do
+ "{\"resultTotalRows\": \"0\",\"requestedStartRow\": \"0\",\"resultSize\": \"0\",\"requestedSize\": \"1000\",\"remainingSize\": \"0\",\"items\": [] }"
+ end
+
+ it { should eq [] }
+ end
+ end
+
+ describe '::find' do
+ before(:each) do
+ stub_request(:get, authenticated_host + '/ws/Group/123.json').
+ with(:headers => {'Accept'=>'*/*', 'User-Agent'=>'Ruby'}).
+ to_return(:status => 200, :body => group_json, :headers => {})
+ end
+
+ subject { DeviceCloud::Group.find 123 }
+
+ context 'with result' do
+ let(:group_result) do
+ {"resultTotalRows"=>"1",
+ "requestedStartRow"=>"0",
+ "resultSize"=>"1",
+ "requestedSize"=>"1000",
+ "remainingSize"=>"0",
+ "items"=>
+ [{"grpId"=>"9769",
+ "grpDescription"=>"Describing this group.",
+ "grpName"=>"Your_Company",
+ "grpPath"=>"/Your_Company/Your_Group/",
+ "grpParentId"=>"4946"}]}
+ end
+ let(:group_json) { group_result.to_json }
+
+ it { should be_a(DeviceCloud::Group) }
+ its(:grpId) { should eq group_result['items'].first['grpId'] }
+ its(:grpDescription) { should eq group_result['items'].first['grpDescription'] }
+ its(:grpName) { should eq group_result['items'].first['grpName'] }
+ its(:grpPath) { should eq group_result['items'].first['grpPath'] }
+ its(:grpParentId) { should eq group_result['items'].first['grpParentId'] }
+ end
+
+ context 'with no results' do
+ let(:group_json) do
+ {"error"=>["GET Group error. Error reading Group entity id='12123'"]}.to_json
+ end
+
+ it { should be_nil }
+ end
+ end
+
+ describe '::find_all_by_parent_id' do
+ before(:each) do
+ stub_request(:get, authenticated_host + '/ws/Group/.json?condition=grpParentId=\'1\'').
+ with(:headers => {'Accept'=>'*/*', 'User-Agent'=>'Ruby'}).
+ to_return(:status => 200, :body => group_json, :headers => {})
+ end
+
+ subject { DeviceCloud::Group.find_all_by_parent_id 1 }
+
+ context 'with result' do
+ let(:group_result) do
+ {"resultTotalRows"=>"1",
+ "requestedStartRow"=>"0",
+ "resultSize"=>"1",
+ "requestedSize"=>"1000",
+ "remainingSize"=>"0",
+ "items"=>
+ [{"grpId"=>"9769",
+ "grpDescription"=>"Describing this group.",
+ "grpName"=>"Your_Company",
+ "grpPath"=>"/Your_Company/Your_Group/",
+ "grpParentId"=>"1"}]}
+ end
+ let(:group_json) { group_result.to_json }
+
+ it { should be_a(Array) }
+ its(:first) { should be_a(DeviceCloud::Group) }
+ its(:size) { should eq 1 }
+ end
+
+ context 'with no results' do
+ let(:group_json) do
+ "{\"resultTotalRows\": \"0\",\"requestedStartRow\": \"0\",\"resultSize\": \"0\",\"requestedSize\": \"1000\",\"remainingSize\": \"0\",\"items\": [] }"
+ end
+
+ it { should eq [] }
+ end
+ end
+end