testdroid-api-client 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (59) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +19 -0
  3. data/Gemfile +4 -0
  4. data/Gemfile.lock +23 -0
  5. data/LICENSE +20 -0
  6. data/README.md +39 -0
  7. data/lib/testdroid-api-client.rb +19 -0
  8. data/lib/testdroid_api/client.rb +124 -0
  9. data/lib/testdroid_api/cloud_list_resource.rb +83 -0
  10. data/lib/testdroid_api/cloud_resource.rb +72 -0
  11. data/lib/testdroid_api/device_groups.rb +12 -0
  12. data/lib/testdroid_api/device_runs.rb +20 -0
  13. data/lib/testdroid_api/device_sessions.rb +15 -0
  14. data/lib/testdroid_api/devices.rb +13 -0
  15. data/lib/testdroid_api/files.rb +60 -0
  16. data/lib/testdroid_api/label_groups.rb +13 -0
  17. data/lib/testdroid_api/labels.rb +13 -0
  18. data/lib/testdroid_api/projects.rb +21 -0
  19. data/lib/testdroid_api/runs.rb +11 -0
  20. data/lib/testdroid_api/user.rb +8 -0
  21. data/spec/client_spec.rb +10 -0
  22. data/spec/device_groups_spec.rb +28 -0
  23. data/spec/device_runs_spec.rb +25 -0
  24. data/spec/files_spec.rb +33 -0
  25. data/spec/fixtures/apk.apk +0 -0
  26. data/spec/fixtures/cassettes/dg_all_device_groups.json +1 -0
  27. data/spec/fixtures/cassettes/dg_device_group_4165.json +1 -0
  28. data/spec/fixtures/cassettes/dg_oauth2_auth_device_groups.json +1 -0
  29. data/spec/fixtures/cassettes/dr_all_run_171221_device_runs.json +1 -0
  30. data/spec/fixtures/cassettes/dr_device_run_33044722.json +1 -0
  31. data/spec/fixtures/cassettes/dr_oauth2_auth_device_runs.json +1 -0
  32. data/spec/fixtures/cassettes/dr_run_33044722_device_runs.json +1 -0
  33. data/spec/fixtures/cassettes/f_android_app_file.json +1 -0
  34. data/spec/fixtures/cassettes/f_oauth2_auth_files.json +1 -0
  35. data/spec/fixtures/cassettes/f_upload_files.json +1 -0
  36. data/spec/fixtures/cassettes/fu_oauth2_auth_files.json +1 -0
  37. data/spec/fixtures/cassettes/lg_all_label_groups.json +1 -0
  38. data/spec/fixtures/cassettes/lg_get_resources_by_label.json +1 -0
  39. data/spec/fixtures/cassettes/lg_label_group_1058800.json +1 -0
  40. data/spec/fixtures/cassettes/lg_labels_of_group_1058800.json +1 -0
  41. data/spec/fixtures/cassettes/lg_oauth2_auth_label_groups.json +1 -0
  42. data/spec/fixtures/cassettes/p_all_projects.json +1 -0
  43. data/spec/fixtures/cassettes/p_get_run_devices.json +1 -0
  44. data/spec/fixtures/cassettes/p_oauth2_auth.json +1 -0
  45. data/spec/fixtures/cassettes/p_project_id_33029366.json +1 -0
  46. data/spec/fixtures/cassettes/p_run_project.json +1 -0
  47. data/spec/fixtures/cassettes/r_all_project_33029366_runs.json +1 -0
  48. data/spec/fixtures/cassettes/r_delete_test_run.json +1 -0
  49. data/spec/fixtures/cassettes/r_oauth2_auth_runs.json +1 -0
  50. data/spec/fixtures/cassettes/r_run_171221.json +1 -0
  51. data/spec/fixtures/cassettes/r_run_project.json +1 -0
  52. data/spec/fixtures/cassettes/upload_files.json +1 -0
  53. data/spec/fixtures/project.json +8 -0
  54. data/spec/label_groups_spec.rb +54 -0
  55. data/spec/project_spec.rb +43 -0
  56. data/spec/run_spec.rb +33 -0
  57. data/spec/spec_helper.rb +33 -0
  58. data/testdroid-api-client.gemspec +35 -0
  59. metadata +265 -0
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 1bd3bc1947d038a2a89a0104bfe1d25d8676c28c
4
+ data.tar.gz: 798caa22a155acb707f6296ac98da4bb4ba9d2a1
5
+ SHA512:
6
+ metadata.gz: 5a168025882c4a54ddcd9afbfd48ca3e57842c014285e5cc6d6979a6a6efd9a835f7ef2b5fafdc3c7988a2d56891867d9c5f50087eec42920d20584f4cf0b2fc
7
+ data.tar.gz: 909681de08be878362a338ddb2f6acc53706c525ffba9d413a446f39578729d7564b3aafa54288525b112a77c83080f28d3e2f3ee57acec2e9209c8d9f83b01f
@@ -0,0 +1,19 @@
1
+
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ coverage
6
+ InstalledFiles
7
+ lib/bundler/man
8
+ pkg
9
+ rdoc
10
+ spec/reports
11
+ test/tmp
12
+ test/version_tmp
13
+ tmp
14
+
15
+ # YARD artifacts
16
+ .yardoc
17
+ _yardoc
18
+ doc/
19
+ .DS_Store
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ # A sample Gemfile
2
+ source "https://rubygems.org"
3
+
4
+ gemspec
@@ -0,0 +1,23 @@
1
+ GEM
2
+ remote: https://rubygems.org/
3
+ specs:
4
+ faraday (0.9.0)
5
+ multipart-post (>= 1.2, < 3)
6
+ jwt (0.1.11)
7
+ multi_json (>= 1.5)
8
+ multi_json (1.9.2)
9
+ multi_xml (0.5.5)
10
+ multipart-post (2.0.0)
11
+ oauth2 (0.9.3)
12
+ faraday (>= 0.8, < 0.10)
13
+ jwt (~> 0.1.8)
14
+ multi_json (~> 1.3)
15
+ multi_xml (~> 0.5)
16
+ rack (~> 1.2)
17
+ rack (1.5.2)
18
+
19
+ PLATFORMS
20
+ ruby
21
+
22
+ DEPENDENCIES
23
+ oauth2
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2013 Sakari Rautiainen
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy of
6
+ this software and associated documentation files (the "Software"), to deal in
7
+ the Software without restriction, including without limitation the rights to
8
+ use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
9
+ the Software, and to permit persons to whom the Software is furnished to do so,
10
+ subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
17
+ FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
18
+ COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
19
+ IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
20
+ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,39 @@
1
+ testdroid-api-client-ruby
2
+ =========================
3
+
4
+ ```
5
+ require 'testdroid-api-client'
6
+ #Authenticate
7
+ client = TestdroidAPI::Client.new('admin@localhost', 'admin')
8
+ @user = client.authorize
9
+ #get Projects
10
+ projects = @user.projects.list
11
+
12
+ #get project by id
13
+ project_id = 123
14
+ project123 = @user.projects.get(project_id)
15
+ #output project name
16
+ p "Project name #{project123.name}"
17
+
18
+ #run project
19
+ test_run = project123.run
20
+
21
+ #check test run status
22
+ p "Project state #{test_run.state}"
23
+
24
+ #download all logs from test run
25
+ test_run.device_runs.list({:params => {:limit => 100}}).each { |drun| drun.download_logs("#{drun.id}_log") }
26
+
27
+ #Get label for android os version 2.1
28
+ lg_android_version_2_1 = client.label_groups.list.detect {|lg| lg.display_name.casecmp("android version") == 0 }
29
+
30
+ os_v2_1 = client.label_groups.get(lg_android_versions.id).labels.list.detect {|l| l.display_name.casecmp("2.1") == 0 }
31
+
32
+ #get all devices with android os level 2.1
33
+ devices = client.label_groups.get(lg_android_versions.id).labels.get(os_v2_1.id).devices
34
+ #get spefici device from devices list
35
+ lenovo_a820 = devices.list.detect {|d| d.display_name == "Lenovo A820"}
36
+
37
+
38
+ ```
39
+ See https://cloud.testdroid.com/swagger/index.html for more details about API V2
@@ -0,0 +1,19 @@
1
+ #!/usr/bin/ruby
2
+ require 'json'
3
+ require 'testdroid_api/client'
4
+ require 'testdroid_api/cloud_resource'
5
+ require 'testdroid_api/cloud_list_resource'
6
+ require 'testdroid_api/user'
7
+ require 'testdroid_api/device_groups'
8
+ require 'testdroid_api/projects'
9
+ require 'testdroid_api/runs'
10
+ require 'testdroid_api/device_runs'
11
+ require 'testdroid_api/label_groups'
12
+ require 'testdroid_api/labels'
13
+ require 'testdroid_api/files'
14
+ require 'testdroid_api/devices'
15
+ require 'testdroid_api/device_sessions'
16
+
17
+
18
+ require 'oauth2'
19
+ require 'logger'
@@ -0,0 +1,124 @@
1
+ module TestdroidAPI
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
+
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 = @client.password.get_token(@username, @password) 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
+ JSON.parse(resp.body)
77
+ end
78
+ def get(uri, params={})
79
+
80
+ @logger.error "token expired" if @token.expired?
81
+
82
+ @token = @client.password.get_token(@username, @password) if @token.expired?
83
+
84
+ begin
85
+ resp = @token.get(@cloud_url+"#{uri}", params.merge(:headers => ACCEPT_HEADERS))
86
+ rescue => e
87
+ @logger.error "Failed to get resource #{uri} #{e}"
88
+ return nil
89
+ end
90
+ JSON.parse(resp.body)
91
+ end
92
+ def delete(uri)
93
+
94
+ @logger.error "token expired" if @token.expired?
95
+
96
+ @token = @client.password.get_token(@username, @password) if @token.expired?
97
+
98
+ begin
99
+ resp = @token.delete(@cloud_url+"#{uri}", :headers => ACCEPT_HEADERS )
100
+ rescue => e
101
+ @logger.error "Failed to delete resource #{uri} #{e}"
102
+ return nil
103
+ end
104
+
105
+ if (resp.status != 204)
106
+ @logger.error "Failed to delete resource #{uri} #{e}"
107
+ return nil
108
+ else
109
+ @logger.info "response: #{resp.status}"
110
+ end
111
+ end
112
+ def download(uri, file_name)
113
+ begin
114
+ File.open(file_name, "w+b") do |file|
115
+ resp = @token.get("#{@cloud_url}/#{uri}", :headers => ACCEPT_HEADERS)
116
+ file.write(resp.body)
117
+ end
118
+ rescue => e
119
+ @logger.error "Failed to get resource #{uri} #{e}"
120
+ return nil
121
+ end
122
+ end
123
+ end
124
+ end
@@ -0,0 +1,83 @@
1
+
2
+ module TestdroidAPI
3
+ class CloudListResource
4
+
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
15
+
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
26
+
27
+ response = @client.get("#{@uri}?limit=355043550", {})
28
+
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|
35
+
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
44
+
45
+ response = @client.get(@uri, params)
46
+
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|
53
+
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
58
+
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']
64
+
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']
72
+
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
83
+ end
@@ -0,0 +1,72 @@
1
+
2
+ module TestdroidAPI
3
+ class CloudResource
4
+ def initialize(uri, client, resource_name=nil, params= {})
5
+
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 set_up_properties_from(hash)
28
+
29
+ eigenclass = class << self; self; end
30
+ hash.each do |p,v|
31
+ property = snake_case_it p
32
+
33
+ unless ['uri', 'client', 'updated'].include? property
34
+ eigenclass.send :define_method, property.to_sym, &lambda {v}
35
+ end
36
+ end
37
+ @updated = !hash.keys.empty?
38
+ end
39
+
40
+ def refresh
41
+ raise "Can't refresh a resource without a REST Client" unless @client
42
+ @updated = false
43
+ set_up_properties_from(@client.get(@uri))
44
+ self
45
+ end
46
+ def download_file(file_resource_name, target_file_name=nil)
47
+ raise "Can't refresh a resource without a REST Client" unless @client
48
+ target_file_name = file_resource_name unless target_file_name
49
+ @client.download("#{@uri}/#{file_resource_name}", target_file_name)
50
+ end
51
+ def camel_case_it(something)
52
+ if something.is_a? Hash
53
+ Hash[*something.to_a.map {|a| [camel_case_it(a[0]).to_sym, a[1]]}.flatten]
54
+ else
55
+ something.to_s.split('_').map do |s|
56
+ [s[0,1].capitalize, s[1..-1]].join
57
+ end.join
58
+ end
59
+ end
60
+ def snake_case_it(something)
61
+ if something.is_a? Hash
62
+ Hash[*something.to_a.map {|pair| [snake_case_it(pair[0]).to_sym, pair[1]]}.flatten]
63
+ else
64
+ something.to_s.gsub(/[A-Z][a-z]*/) {|s| "_#{s.downcase}"}.gsub(/^_/, '')
65
+ end
66
+ end
67
+ def delete
68
+ raise "Can't delete a resource without a REST Client" unless @client
69
+ client.delete(@uri)
70
+ end
71
+ end
72
+ end
@@ -0,0 +1,12 @@
1
+
2
+ module TestdroidAPI
3
+ class DeviceGroups < CloudListResource
4
+ end
5
+ class DeviceGroup < CloudResource
6
+ def initialize(uri, client, params= {})
7
+ super uri, client,"deviceGroup", params
8
+ @uri, @client = uri, client
9
+ end
10
+
11
+ end
12
+ end
@@ -0,0 +1,20 @@
1
+
2
+ module TestdroidAPI
3
+ class DeviceRuns < CloudListResource
4
+ end
5
+ class DeviceRun < CloudResource
6
+ def initialize(uri, client, params= {})
7
+ super uri, client,"deviceRun", params
8
+ @uri, @client = uri, client
9
+ end
10
+ def download_performance(file_name="performance_data.txt")
11
+ @client.download("#{@uri}/performance", file_name)
12
+ end
13
+ def download_junit(file_name="junit.xml")
14
+ @client.download("#{@uri}/junit.xml", file_name)
15
+ end
16
+ def download_logs(file_name="log.txt")
17
+ @client.download("#{@uri}/logs", file_name)
18
+ end
19
+ end
20
+ end