testdroid-api-client 0.2.3 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,126 +1,169 @@
1
1
  module TestdroidAPI
2
2
 
3
- class Client
4
- attr_reader :config
5
- attr_accessor :logger
6
- attr_reader :token
7
-
8
- API_VERSION = 'api/v2'
9
- CLOUD_ENDPOINT='https://cloud.testdroid.com'
10
- ACCEPT_HEADERS={'Accept' => 'application/json'}
11
-
12
- def initialize(username, password, cloud_url = CLOUD_ENDPOINT, logger = nil)
13
- # Instance variables
14
- @username = username
15
- @password = password
16
- @cloud_url = cloud_url
17
- @logger = logger
18
-
19
- if @logger.nil?
20
- @logger = Logger.new(STDOUT)
21
- @logger.info("Logger is not defined => output to STDOUT")
22
- end
23
- end
24
- def label_groups
25
- label_groups = TestdroidAPI::LabelGroups.new( "/#{API_VERSION}/label-groups", self )
26
- label_groups.list
27
- label_groups
28
- end
29
- def devices
30
- devices = TestdroidAPI::Devices.new( "/#{API_VERSION}/devices", self )
31
- devices.list
32
- devices
33
- end
34
- def authorize
35
-
36
- @client = OAuth2::Client.new('testdroid-cloud-api', nil, :site => @cloud_url, :authorize_url => 'oauth/authorize',
37
- :token_url => 'oauth/token', :headers => ACCEPT_HEADERS) do |faraday|
38
- faraday.request :multipart
39
- faraday.request :url_encoded
40
- faraday.response :logger, @logger
41
- faraday.adapter Faraday.default_adapter
42
- end
43
-
44
- @token = @client.password.get_token(@username, @password, :headers => ACCEPT_HEADERS)
45
-
46
- if (@cloud_user.nil?)
47
- @cloud_user = TestdroidAPI::User.new( "/#{API_VERSION}/me", self ).refresh
48
- @cloud_user = TestdroidAPI::User.new( "/#{API_VERSION}/users/#{@cloud_user.id}", self ).refresh
49
-
50
- end
51
- @cloud_user
52
- end
53
- def upload(uri, filename, file_type)
54
- begin
55
- @token = @token.refresh!(:headers => ACCEPT_HEADERS) if @token.expired?
56
- connection = @token.client.connection
57
- payload = {:file => Faraday::UploadIO.new(filename, file_type) }
58
- headers = ACCEPT_HEADERS.merge(@token.headers)
59
- response = connection.post(@cloud_url+"#{uri}",payload, headers)
60
- rescue => e
61
- @logger.error e
62
- return nil
63
- end
64
- JSON.parse(response.body)
65
- end
66
- def post(uri, params)
67
-
68
- @token = @token.refresh!(:headers => ACCEPT_HEADERS) if @token.expired?
69
-
70
- begin
71
- resp = @token.post("#{@cloud_url}#{uri}", params.merge(:headers => ACCEPT_HEADERS))
72
- rescue => e
73
- @logger.error "Failed to post resource #{uri} #{e}"
74
- return nil
75
- end
76
-
77
- if resp.body.nil? || resp.body.length == 0
78
- return nil
79
- end
80
-
81
- JSON.parse(resp.body)
82
- end
83
- def get(uri, params={})
84
-
85
- @token = @token.refresh!(:headers => ACCEPT_HEADERS) if @token.expired?
86
-
87
- begin
88
- resp = @token.get(@cloud_url+"#{uri}", params.merge(:headers => ACCEPT_HEADERS))
89
- rescue => e
90
- @logger.error "Failed to get resource #{uri} #{e}"
91
- return nil
92
- end
93
- JSON.parse(resp.body)
94
- end
95
- def delete(uri)
96
-
97
- @token = @token.refresh!(:headers => ACCEPT_HEADERS) if @token.expired?
98
-
99
- begin
100
- resp = @token.delete(@cloud_url+"#{uri}", :headers => ACCEPT_HEADERS )
101
- rescue => e
102
- @logger.error "Failed to delete resource #{uri} #{e}"
103
- return nil
104
- end
105
-
106
- if (resp.status != 204)
107
- @logger.error "Failed to delete resource #{uri} #{e}"
108
- return nil
109
- else
110
- @logger.info "response: #{resp.status}"
111
- end
112
- end
113
- def download(uri, file_name)
114
- begin
115
- @token = @token.refresh!(:headers => ACCEPT_HEADERS) if @token.expired?
116
- File.open(file_name, "w+b") do |file|
117
- resp = @token.get("#{@cloud_url}/#{uri}", :headers => ACCEPT_HEADERS)
118
- file.write(resp.body)
119
- end
120
- rescue => e
121
- @logger.error "Failed to get resource #{uri} #{e}"
122
- return nil
123
- end
124
- end
125
- end
3
+ class Client
4
+ attr_reader :config
5
+ attr_accessor :logger
6
+ attr_reader :token
7
+
8
+ API_VERSION = 'api/v2'
9
+ CLOUD_ENDPOINT='https://cloud.testdroid.com'
10
+ ACCEPT_HEADERS={'Accept' => 'application/json'}
11
+
12
+ def initialize(username, password, cloud_url = CLOUD_ENDPOINT, logger = nil)
13
+ # Instance variables
14
+ @username = username
15
+ @password = password
16
+ @cloud_url = cloud_url
17
+ @logger = logger
18
+
19
+ if @logger.nil?
20
+ @logger = Logger.new(STDOUT)
21
+ @logger.info("Logger is not defined => output to STDOUT")
22
+ end
23
+ end
24
+ def label_groups
25
+ label_groups = TestdroidAPI::LabelGroups.new( "/#{API_VERSION}/label-groups", self )
26
+ label_groups.list
27
+ label_groups
28
+ end
29
+ def devices
30
+ devices = TestdroidAPI::Devices.new( "/#{API_VERSION}/devices", self )
31
+ devices.list
32
+ devices
33
+ end
34
+ def authorize
35
+
36
+ @client = OAuth2::Client.new('testdroid-cloud-api', nil, :site => @cloud_url, :authorize_url => 'oauth/authorize',
37
+ :token_url => 'oauth/token', :headers => ACCEPT_HEADERS) do |faraday|
38
+ faraday.request :multipart
39
+ faraday.request :url_encoded
40
+ faraday.response :logger, @logger
41
+ faraday.adapter Faraday.default_adapter
42
+ end
43
+
44
+ @token = @client.password.get_token(@username, @password, :headers => ACCEPT_HEADERS)
45
+
46
+ if (@cloud_user.nil?)
47
+ @cloud_user = TestdroidAPI::User.new( "/#{API_VERSION}/me", self ).refresh
48
+ @cloud_user = TestdroidAPI::User.new( "/#{API_VERSION}/users/#{@cloud_user.id}", self ).refresh
49
+
50
+ end
51
+ @cloud_user
52
+ end
53
+
54
+ def mime_for(path)
55
+ mime = MIME::Types.type_for path
56
+ mime.empty? ? 'text/plain' : mime[0].content_type
57
+ end
58
+
59
+ def upload(uri, filename)
60
+ begin
61
+ @token = @token.refresh!(:headers => ACCEPT_HEADERS) if @token.expired?
62
+ connection = @token.client.connection
63
+ payload = {:file => Faraday::UploadIO.new(filename, mime_for(filename)) }
64
+ headers = ACCEPT_HEADERS.merge(@token.headers)
65
+ response = connection.post(@cloud_url+"#{uri}",payload, headers)
66
+ rescue => e
67
+ @logger.error e
68
+ return nil
69
+ end
70
+ JSON.parse(response.body)
71
+ end
72
+ def post(uri, params)
73
+
74
+ @token = @token.refresh!(:headers => ACCEPT_HEADERS) if @token.expired?
75
+
76
+ begin
77
+ resp = @token.post("#{@cloud_url}#{uri}", params.merge(:headers => ACCEPT_HEADERS))
78
+ rescue => e
79
+ @logger.error "Failed to post resource #{uri} #{e}"
80
+ return nil
81
+ end
82
+
83
+ if resp.body.nil? || resp.body.length == 0
84
+ return nil
85
+ end
86
+
87
+ JSON.parse(resp.body)
88
+ end
89
+ def get(uri, params={})
90
+
91
+ @token = @token.refresh!(:headers => ACCEPT_HEADERS) if @token.expired?
92
+
93
+ begin
94
+ resp = @token.get(@cloud_url+"#{uri}", params.merge(:headers => ACCEPT_HEADERS))
95
+ rescue => e
96
+ @logger.error "Failed to get resource #{uri} #{e}"
97
+ return nil
98
+ end
99
+ JSON.parse(resp.body)
100
+ end
101
+ def delete(uri)
102
+
103
+ @token = @token.refresh!(:headers => ACCEPT_HEADERS) if @token.expired?
104
+
105
+ begin
106
+ resp = @token.delete(@cloud_url+"#{uri}", :headers => ACCEPT_HEADERS )
107
+ rescue => e
108
+ @logger.error "Failed to delete resource #{uri} #{e}"
109
+ return nil
110
+ end
111
+
112
+ if (resp.status != 204)
113
+ @logger.error "Failed to delete resource #{uri} #{e}"
114
+ return nil
115
+ else
116
+ @logger.info "response: #{resp.status}"
117
+ end
118
+ end
119
+ def download(uri, file_name)
120
+ begin
121
+ @token = @token.refresh!(:headers => ACCEPT_HEADERS) if @token.expired?
122
+ File.open(file_name, "w+b") do |file|
123
+ resp = @token.get("#{@cloud_url}/#{uri}", :headers => ACCEPT_HEADERS)
124
+ file.write(resp.body)
125
+ end
126
+ rescue => e
127
+ @logger.error "Failed to get resource #{uri} #{e}"
128
+ return nil
129
+ end
130
+ end
131
+
132
+ # Resources
133
+
134
+ # public read-only
135
+
136
+ def info
137
+ TestdroidAPI::CloudResource.new("/#{API_VERSION}/info", self, "info")
138
+ end
139
+
140
+ def devices
141
+ TestdroidAPI::Devices.new("/#{API_VERSION}/devices", self)
142
+ end
143
+
144
+ def label_groups
145
+ TestdroidAPI::LabelGroups.new("/#{API_VERSION}/label-groups", self)
146
+ end
147
+
148
+ # user read-write
149
+
150
+ def me
151
+ TestdroidAPI::User.new("/#{API_VERSION}/me", self).load
152
+ end
153
+
154
+ def properties
155
+ TestdroidAPI::Properties.new("/#{API_VERSION}/properties", self)
156
+ end
157
+
158
+ def device_session_connections
159
+ TestdroidAPI::DeviceSessionConnections.new("/#{API_VERSION}/device-session-connections", self)
160
+ end
161
+
162
+ # admin only
163
+
164
+ def admin
165
+ TestdroidAPI::Admin.new("/#{API_VERSION}/admin", self)
166
+ end
167
+
168
+ end
126
169
  end
@@ -1,83 +1,86 @@
1
-
2
1
  module TestdroidAPI
3
- class CloudListResource
2
+ class CloudListResource
3
+
4
+ def initialize(uri, client, instance_class=nil)
5
+ @uri, @client = uri, client
6
+ resource_name = self.class.name.split('::')[-1]
7
+ @instance_class = TestdroidAPI.const_get( instance_class.nil? ? resource_name.chop : instance_class )
8
+ @list_key, @instance_id_key = resource_name.gsub!(/\b\w/) { $&.downcase }, 'id'
9
+ end
10
+
11
+ def get(resource_id)
12
+ @instance_class.new("#{@uri}/#{resource_id}", @client)
13
+ end
14
+
15
+ def total
16
+
17
+ @client.get(@uri)['total']
18
+ end
4
19
 
5
- def initialize(uri, client)
6
- @uri, @client = uri, client
7
- resource_name = self.class.name.split('::')[-1]
8
- @instance_class = TestdroidAPI.const_get resource_name.chop
9
- @list_key, @instance_id_key = resource_name.gsub!(/\b\w/) { $&.downcase } , 'id'
10
- end
11
- def get(resource_id)
12
- @instance_class.new( "#{@uri}/#{resource_id}", @client)
13
- end
14
- def total
20
+ def create(params={}, http_params={})
21
+ raise "Can't create a resource without a REST Client" unless @client
22
+ response = @client.post @uri, params
23
+ @instance_class.new "#{@uri}/#{response[@instance_id_key]}", @client,
24
+ response
25
+ end
15
26
 
16
- @client.get(@uri)['total']
17
- end
18
- def create(params={})
19
- raise "Can't create a resource without a REST Client" unless @client
20
- response = @client.post @uri, params
21
- @instance_class.new "#{@uri}/#{response[@instance_id_key]}", @client,
22
- response
23
- end
24
- def list_all()
25
- raise "Can't get a resource list without a REST Client" unless @client
27
+ def list_all()
28
+ raise "Can't get a resource list without a REST Client" unless @client
26
29
 
27
- response = @client.get("#{@uri}?limit=355043550", {})
30
+ response = @client.get(@uri, {:limit => 0})
28
31
 
29
- if response['data'].is_a?(Array)
30
- client = @client
31
- class_list = []
32
- list_class = self.class
33
- instance_uri = @uri
34
- response['data'].each do |val|
32
+ if response['data'].is_a?(Array)
33
+ class_list = []
34
+ instance_uri = @uri
35
+ response['data'].each do |val|
36
+ class_list << @instance_class.new("#{instance_uri}/#{val[@instance_id_key]}", @client, val)
37
+ end
38
+ end
39
+ class_list
40
+ end
35
41
 
36
- class_list << @instance_class.new( "#{instance_uri}/#{val[@instance_id_key]}", @client, val)
37
- end
38
- end
39
- class_list
40
- end
41
- def list(params={}, full_uri=false)
42
- raise "Can't get a resource list without a REST Client" unless @client
43
- @uri = full_uri ? @uri.split(@client.instance_variable_get(:@cloud_url))[1] : @uri
42
+ def list(params={}, full_uri=false)
43
+ raise "Can't get a resource list without a REST Client" unless @client
44
+ @uri = full_uri ? @uri.split(@client.instance_variable_get(:@cloud_url))[1] : @uri
44
45
 
45
- response = @client.get(@uri, params)
46
+ response = @client.get(@uri, params)
46
47
 
47
- if response['data'].is_a?(Array)
48
- client = @client
49
- class_list = []
50
- list_class = self.class
51
- instance_uri = full_uri ? @uri.split('?')[0] : @uri
52
- response['data'].each do |val|
48
+ if response['data'].is_a?(Array)
49
+ client = @client
50
+ class_list = []
51
+ list_class = self.class
52
+ instance_uri = full_uri ? @uri.split('?')[0] : @uri
53
+ response['data'].each do |val|
53
54
 
54
- class_list << @instance_class.new( "#{instance_uri}/#{val[@instance_id_key]}", @client, val)
55
- end
56
- class_list.instance_eval do
57
- eigenclass = class << self; self; end
55
+ class_list << @instance_class.new("#{instance_uri}/#{val[@instance_id_key]}", @client, val)
56
+ end
57
+ class_list.instance_eval do
58
+ eigenclass = class << self;
59
+ self;
60
+ end
58
61
 
59
- eigenclass.send :define_method, :offset, &lambda {response['offset']}
60
- eigenclass.send :define_method, :limit, &lambda {response['limit']}
61
- eigenclass.send :define_method, :total, &lambda {response['total']}
62
- eigenclass.send :define_method, :next_page, &lambda {
63
- if response['next']
62
+ eigenclass.send :define_method, :offset, &lambda { response['offset'] }
63
+ eigenclass.send :define_method, :limit, &lambda { response['limit'] }
64
+ eigenclass.send :define_method, :total, &lambda { response['total'] }
65
+ eigenclass.send :define_method, :next_page, &lambda {
66
+ if response['next']
64
67
 
65
- list_class.new(response['next'], client).list({}, true)
66
- else
67
- []
68
- end
69
- }
70
- eigenclass.send :define_method, :previous_page, &lambda {
71
- if response['previous']
68
+ list_class.new(response['next'], client).list({}, true)
69
+ else
70
+ []
71
+ end
72
+ }
73
+ eigenclass.send :define_method, :previous_page, &lambda {
74
+ if response['previous']
72
75
 
73
- list_class.new(response['previous'], client).list({}, true)
74
- else
75
- []
76
- end
77
- }
78
- end
79
- end
80
- class_list
81
- end
82
- end
76
+ list_class.new(response['previous'], client).list({}, true)
77
+ else
78
+ []
79
+ end
80
+ }
81
+ end
82
+ end
83
+ class_list
84
+ end
85
+ end
83
86
  end
@@ -1,77 +1,89 @@
1
-
2
1
  module TestdroidAPI
3
- class CloudResource
4
- def initialize(uri, client, resource_name=nil, params= {})
2
+ class CloudResource
3
+ def initialize(uri, client, resource_name=nil, params= {})
4
+
5
+ @uri, @client, @resource_name = uri, client, resource_name
6
+ set_up_properties_from(params)
7
+ end
8
+
9
+ def inspect # :nodoc:
10
+ "<#{self.class} @uri=#{@uri}>"
11
+ end
12
+
13
+ def sub_items(*items)
14
+ items.each do |item|
15
+ resource = camel_case_it item
16
+ uri = "#{@uri}/#{item.to_s.gsub('_', '-') }"
17
+ resource_class = TestdroidAPI.const_get resource
18
+ new_class = resource_class.new(uri, @client)
19
+ instance_variable_set("@#{item}", new_class)
20
+ end
21
+ self.class.instance_eval { attr_reader *items }
22
+ end
23
+
24
+ def method_missing(method, *args)
25
+ super if @updated
26
+ set_up_properties_from(@client.get(@uri))
27
+ self.send method, *args
28
+ end
29
+
30
+ def update(params = {})
31
+ raise "Can't update a resource without a REST Client" unless @client
32
+ set_up_properties_from(@client.post(@uri, params))
33
+ self
34
+ end
35
+
36
+ def set_up_properties_from(hash)
37
+
38
+ eigenclass = class << self;
39
+ self;
40
+ end
41
+ hash.each do |p, v|
42
+ property = snake_case_it p
43
+
44
+ unless ['uri', 'client', 'updated'].include? property
45
+ eigenclass.send :define_method, property.to_sym, &lambda { v }
46
+ end
47
+ end
48
+ @updated = !hash.keys.empty?
49
+ end
50
+
51
+ def refresh
52
+ raise "Can't refresh a resource without a REST Client" unless @client
53
+ @updated = false
54
+ set_up_properties_from(@client.get(@uri))
55
+ self
56
+ end
57
+
58
+ alias_method :load, :refresh
5
59
 
6
- @uri, @client, @resource_name = uri, client, resource_name
7
- set_up_properties_from( params )
8
- end
9
- def inspect # :nodoc:
10
- "<#{self.class} @uri=#{@uri}>"
11
- end
12
- def sub_items(*items)
13
- items.each do |item|
14
- resource = camel_case_it item
15
- uri = "#{@uri}/#{item.to_s.gsub('_', '-') }"
16
- resource_class = TestdroidAPI.const_get resource
17
- new_class = resource_class.new(uri, @client)
18
- instance_variable_set( "@#{item}", new_class )
19
- end
20
- self.class.instance_eval {attr_reader *items}
21
- end
22
- def method_missing(method, *args)
23
- super if @updated
24
- set_up_properties_from(@client.get(@uri))
25
- self.send method, *args
26
- end
27
- def update(params = {})
28
- raise "Can't update a resource without a REST Client" unless @client
29
- set_up_properties_from(@client.post(@uri, params))
30
- self
31
- end
32
- def set_up_properties_from(hash)
60
+ def download_file(file_resource_name, target_file_name=nil)
61
+ raise "Can't refresh a resource without a REST Client" unless @client
62
+ target_file_name = file_resource_name unless target_file_name
63
+ @client.download("#{@uri}/#{file_resource_name}", target_file_name)
64
+ end
33
65
 
34
- eigenclass = class << self; self; end
35
- hash.each do |p,v|
36
- property = snake_case_it p
66
+ def camel_case_it(something)
67
+ if something.is_a? Hash
68
+ Hash[*something.to_a.map { |a| [camel_case_it(a[0]).to_sym, a[1]] }.flatten]
69
+ else
70
+ something.to_s.split('_').map do |s|
71
+ [s[0, 1].capitalize, s[1..-1]].join
72
+ end.join
73
+ end
74
+ end
37
75
 
38
- unless ['uri', 'client', 'updated'].include? property
39
- eigenclass.send :define_method, property.to_sym, &lambda {v}
40
- end
41
- end
42
- @updated = !hash.keys.empty?
43
- end
76
+ def snake_case_it(something)
77
+ if something.is_a? Hash
78
+ Hash[*something.to_a.map { |pair| [snake_case_it(pair[0]).to_sym, pair[1]] }.flatten]
79
+ else
80
+ something.to_s.gsub(/[A-Z][a-z]*/) { |s| "_#{s.downcase}" }.gsub(/^_/, '')
81
+ end
82
+ end
44
83
 
45
- def refresh
46
- raise "Can't refresh a resource without a REST Client" unless @client
47
- @updated = false
48
- set_up_properties_from(@client.get(@uri))
49
- self
50
- end
51
- def download_file(file_resource_name, target_file_name=nil)
52
- raise "Can't refresh a resource without a REST Client" unless @client
53
- target_file_name = file_resource_name unless target_file_name
54
- @client.download("#{@uri}/#{file_resource_name}", target_file_name)
55
- end
56
- def camel_case_it(something)
57
- if something.is_a? Hash
58
- Hash[*something.to_a.map {|a| [camel_case_it(a[0]).to_sym, a[1]]}.flatten]
59
- else
60
- something.to_s.split('_').map do |s|
61
- [s[0,1].capitalize, s[1..-1]].join
62
- end.join
63
- end
64
- end
65
- def snake_case_it(something)
66
- if something.is_a? Hash
67
- Hash[*something.to_a.map {|pair| [snake_case_it(pair[0]).to_sym, pair[1]]}.flatten]
68
- else
69
- something.to_s.gsub(/[A-Z][a-z]*/) {|s| "_#{s.downcase}"}.gsub(/^_/, '')
70
- end
71
- end
72
- def delete
73
- raise "Can't delete a resource without a REST Client" unless @client
74
- @client.delete(@uri)
75
- end
76
- end
84
+ def delete
85
+ raise "Can't delete a resource without a REST Client" unless @client
86
+ @client.delete(@uri)
87
+ end
88
+ end
77
89
  end