testdroid-api-client 0.2.2 → 0.5.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.
Files changed (121) hide show
  1. checksums.yaml +5 -5
  2. data/.gitignore +5 -0
  3. data/.travis.yml +11 -0
  4. data/Gemfile.lock +65 -37
  5. data/README.md +30 -41
  6. data/lib/testdroid-api-client.rb +25 -9
  7. data/lib/testdroid-api-filter-builder.rb +145 -0
  8. data/lib/testdroid_api/admin.rb +25 -0
  9. data/lib/testdroid_api/admin_device_models.rb +10 -0
  10. data/lib/testdroid_api/admin_device_problems.rb +9 -0
  11. data/lib/testdroid_api/admin_device_statuses.rb +12 -0
  12. data/lib/testdroid_api/admin_devices.rb +10 -0
  13. data/lib/testdroid_api/apikey_client.rb +120 -0
  14. data/lib/testdroid_api/client.rb +158 -123
  15. data/lib/testdroid_api/cloud_list_resource.rb +69 -70
  16. data/lib/testdroid_api/cloud_resource.rb +83 -71
  17. data/lib/testdroid_api/device_groups.rb +9 -9
  18. data/lib/testdroid_api/device_session_connections.rb +10 -0
  19. data/lib/testdroid_api/device_sessions.rb +21 -12
  20. data/lib/testdroid_api/devices.rb +8 -11
  21. data/lib/testdroid_api/files.rb +60 -58
  22. data/lib/testdroid_api/frameworks.rb +11 -0
  23. data/lib/testdroid_api/label_groups.rb +9 -10
  24. data/lib/testdroid_api/labels.rb +9 -10
  25. data/lib/testdroid_api/projects.rb +9 -16
  26. data/lib/testdroid_api/properties.rb +13 -0
  27. data/lib/testdroid_api/runs.rb +22 -12
  28. data/lib/testdroid_api/services.rb +18 -0
  29. data/lib/testdroid_api/user.rb +11 -6
  30. data/sample/BitbarSampleApp.apk +0 -0
  31. data/sample/BitbarSampleAppTest.apk +0 -0
  32. data/sample/sample.rb +23 -23
  33. data/spec/client_spec.rb +7 -7
  34. data/spec/device_groups_spec.rb +30 -17
  35. data/spec/files_spec.rb +40 -20
  36. data/spec/fixtures/apk.apk +0 -0
  37. data/spec/fixtures/cassettes/device_groups_authorize.json +1 -0
  38. data/spec/fixtures/cassettes/device_groups_create.json +1 -0
  39. data/spec/fixtures/cassettes/device_groups_delete.json +1 -0
  40. data/spec/fixtures/cassettes/device_groups_get_all.json +1 -0
  41. data/spec/fixtures/cassettes/device_groups_get_one.json +1 -0
  42. data/spec/fixtures/cassettes/files_authorize.json +1 -0
  43. data/spec/fixtures/cassettes/files_delete.json +1 -0
  44. data/spec/fixtures/cassettes/files_get_all.json +1 -0
  45. data/spec/fixtures/cassettes/files_get_one.json +1 -0
  46. data/spec/fixtures/cassettes/files_upload.json +1 -0
  47. data/spec/fixtures/cassettes/files_upload_with_wait.json +1 -0
  48. data/spec/fixtures/cassettes/label_groups_authorize.json +1 -0
  49. data/spec/fixtures/cassettes/label_groups_create.json +1 -0
  50. data/spec/fixtures/cassettes/label_groups_delete.json +1 -0
  51. data/spec/fixtures/cassettes/label_groups_get_all.json +1 -0
  52. data/spec/fixtures/cassettes/label_groups_get_labels.json +1 -0
  53. data/spec/fixtures/cassettes/label_groups_get_one.json +1 -0
  54. data/spec/fixtures/cassettes/projects_authorize.json +1 -0
  55. data/spec/fixtures/cassettes/projects_create.json +1 -0
  56. data/spec/fixtures/cassettes/projects_delete.json +1 -0
  57. data/spec/fixtures/cassettes/projects_get_all.json +1 -0
  58. data/spec/fixtures/cassettes/projects_get_one.json +1 -0
  59. data/spec/fixtures/cassettes/runs_abort_run.json +1 -0
  60. data/spec/fixtures/cassettes/runs_authorize.json +1 -0
  61. data/spec/fixtures/cassettes/runs_get_project_runs.json +1 -0
  62. data/spec/fixtures/cassettes/runs_start_run.json +1 -0
  63. data/spec/fixtures/data.txt +1 -0
  64. data/spec/fixtures/data2.txt +1 -0
  65. data/spec/label_groups_spec.rb +35 -42
  66. data/spec/projects_spec.rb +41 -0
  67. data/spec/runs_spec.rb +41 -0
  68. data/spec/spec_helper.rb +3 -4
  69. data/testdroid-api-client.gemspec +13 -11
  70. metadata +92 -134
  71. data/lib/testdroid_api/config.rb +0 -7
  72. data/lib/testdroid_api/device_runs.rb +0 -20
  73. data/lib/testdroid_api/file_sets.rb +0 -12
  74. data/spec/device_runs_spec.rb +0 -25
  75. data/spec/file_sets_spec.rb +0 -47
  76. data/spec/fixtures/cassettes/dg_all_device_groups.json +0 -1
  77. data/spec/fixtures/cassettes/dg_device_group_4165.json +0 -1
  78. data/spec/fixtures/cassettes/dg_oauth2_auth_device_groups.json +0 -1
  79. data/spec/fixtures/cassettes/dr_all_run_171221_device_runs.json +0 -1
  80. data/spec/fixtures/cassettes/dr_device_run_33044722.json +0 -1
  81. data/spec/fixtures/cassettes/dr_oauth2_auth_device_runs.json +0 -1
  82. data/spec/fixtures/cassettes/dr_run_33044722_device_runs.json +0 -1
  83. data/spec/fixtures/cassettes/f_add_file_set.json +0 -1
  84. data/spec/fixtures/cassettes/f_android_app_file.json +0 -1
  85. data/spec/fixtures/cassettes/f_file_sets.json +0 -1
  86. data/spec/fixtures/cassettes/f_oauth2_auth_files.json +0 -1
  87. data/spec/fixtures/cassettes/f_upload_files.json +0 -1
  88. data/spec/fixtures/cassettes/fs_add_file_set.json +0 -1
  89. data/spec/fixtures/cassettes/fs_add_file_to_fileset.json +0 -1
  90. data/spec/fixtures/cassettes/fs_delete_file_set.json +0 -1
  91. data/spec/fixtures/cassettes/fs_file_sets.json +0 -1
  92. data/spec/fixtures/cassettes/fs_get_file_set.json +0 -1
  93. data/spec/fixtures/cassettes/fs_oauth2_auth_files.json +0 -1
  94. data/spec/fixtures/cassettes/fs_update_file_set.json +0 -1
  95. data/spec/fixtures/cassettes/fu_oauth2_auth_files.json +0 -1
  96. data/spec/fixtures/cassettes/lg_all_label_groups.json +0 -1
  97. data/spec/fixtures/cassettes/lg_get_resources_by_label.json +0 -1
  98. data/spec/fixtures/cassettes/lg_label_group_1058800.json +0 -1
  99. data/spec/fixtures/cassettes/lg_labels_of_group_1058800.json +0 -1
  100. data/spec/fixtures/cassettes/lg_oauth2_auth_label_groups.json +0 -1
  101. data/spec/fixtures/cassettes/p_all_projects.json +0 -1
  102. data/spec/fixtures/cassettes/p_create_project.json +0 -1
  103. data/spec/fixtures/cassettes/p_get_run_devices.json +0 -1
  104. data/spec/fixtures/cassettes/p_oauth2_auth.json +0 -1
  105. data/spec/fixtures/cassettes/p_oauth2_local.json +0 -1
  106. data/spec/fixtures/cassettes/p_project_id_33029366.json +0 -1
  107. data/spec/fixtures/cassettes/p_run_project.json +0 -1
  108. data/spec/fixtures/cassettes/pc_get_current.json +0 -1
  109. data/spec/fixtures/cassettes/pc_oauth2_auth_config.json +0 -1
  110. data/spec/fixtures/cassettes/pc_set_current_config.json +0 -1
  111. data/spec/fixtures/cassettes/pc_validate_config.json +0 -1
  112. data/spec/fixtures/cassettes/r_all_project_33029366_runs.json +0 -1
  113. data/spec/fixtures/cassettes/r_delete_test_run.json +0 -1
  114. data/spec/fixtures/cassettes/r_oauth2_auth_runs.json +0 -1
  115. data/spec/fixtures/cassettes/r_run_171221.json +0 -1
  116. data/spec/fixtures/cassettes/r_run_project.json +0 -1
  117. data/spec/fixtures/cassettes/upload_files.json +0 -1
  118. data/spec/fixtures/project.json +0 -8
  119. data/spec/project_config_spec.rb +0 -36
  120. data/spec/project_spec.rb +0 -56
  121. data/spec/run_spec.rb +0 -33
@@ -0,0 +1,25 @@
1
+ module TestdroidAPI
2
+ class Admin < CloudResource
3
+ def initialize(uri, client, params = {})
4
+ super uri, client, "admin", params
5
+ @uri, @client = uri, client
6
+ end
7
+
8
+ def device_statuses
9
+ AdminDeviceStatuses.new(@uri + "/device/statuses", @client)
10
+ end
11
+
12
+ def device_problems
13
+ AdminDeviceProblems.new(@uri + "/device-problems", @client)
14
+ end
15
+
16
+ def device_models
17
+ AdminDeviceModels.new(@uri + "/device-models", @client)
18
+ end
19
+
20
+ def devices
21
+ AdminDevices.new(@uri + "/devices", @client)
22
+ end
23
+
24
+ end
25
+ end
@@ -0,0 +1,10 @@
1
+ module TestdroidAPI
2
+ class AdminDeviceModels < CloudListResource
3
+ end
4
+ class AdminDeviceModel < CloudResource
5
+ def initialize(uri, client, params = {})
6
+ super uri, client, "adminDeviceModel", params
7
+ @uri, @client = uri, client
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,9 @@
1
+ module TestdroidAPI
2
+ class AdminDeviceProblems < CloudListResource
3
+ end
4
+ class AdminDeviceProblem < CloudResource
5
+ def initialize(uri, client, params = {})
6
+ super uri, client, "adminDeviceProblem", params
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,12 @@
1
+ module TestdroidAPI
2
+ class AdminDeviceStatuses < CloudListResource
3
+ def initialize(uri, client)
4
+ super uri, client, "AdminDeviceStatus"
5
+ end
6
+ end
7
+ class AdminDeviceStatus < CloudResource
8
+ def initialize(uri, client, params = {})
9
+ super uri, client, "adminDeviceStatus", params
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,10 @@
1
+ module TestdroidAPI
2
+ class AdminDevices < CloudListResource
3
+ end
4
+ class AdminDevice < CloudResource
5
+ def initialize(uri, client, params = {})
6
+ super uri, client, "adminDevice", params
7
+ @uri, @client = uri, client
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,120 @@
1
+ module TestdroidAPI
2
+ class ApikeyClient < Client
3
+
4
+ attr_reader :config
5
+ attr_accessor :logger
6
+
7
+ API_VERSION = 'api/v2'
8
+ CLOUD_ENDPOINT = 'https://cloud.bitbar.com'
9
+
10
+ def initialize(api_key, cloud_url = CLOUD_ENDPOINT, logger = nil)
11
+ # Instance variables
12
+ @api_key = api_key
13
+ @cloud_url = cloud_url
14
+ @logger = logger
15
+
16
+ if @logger.nil?
17
+ @logger = Logger.new(STDOUT)
18
+ @logger.info("Logger is not defined => output to STDOUT")
19
+ end
20
+ end
21
+
22
+ def authorize
23
+
24
+ if @cloud_user.nil?
25
+ @cloud_user = TestdroidAPI::User.new("/#{API_VERSION}/me", self).refresh
26
+ @cloud_user = TestdroidAPI::User.new("/#{API_VERSION}/users/#{@cloud_user.id}", self).refresh
27
+
28
+ end
29
+ @cloud_user
30
+ end
31
+
32
+ # Basic methods
33
+
34
+ def request_factory(method, uri, http_params = {}, headers = {})
35
+ default_http_params = {
36
+ :method => method,
37
+ :url => uri,
38
+ :user => @api_key,
39
+ :password => "",
40
+ :headers => headers
41
+ }
42
+ request_http_params = default_http_params.deep_merge!(http_params)
43
+
44
+ RestClient::Request.new(request_http_params)
45
+ end
46
+
47
+ def get(uri, params = {}, http_params = {})
48
+ uri = @cloud_url + uri
49
+ begin
50
+ http_params = http_params.deep_merge({:headers => {:params => params}})
51
+ request = self.request_factory(:get, uri, http_params)
52
+ resp = request.execute
53
+ rescue => e
54
+ @logger.error "Failed to get resource #{uri} #{e}"
55
+ return nil
56
+ end
57
+ JSON.parse(resp.body)
58
+ end
59
+
60
+ def post(uri, params = {}, http_params = {})
61
+ uri = @cloud_url + uri
62
+ begin
63
+ payload = params.fetch(:body, params)
64
+ headers = params.fetch(:headers, {})
65
+ http_params = http_params.deep_merge({:payload => payload})
66
+ request = self.request_factory(:post, uri, http_params, headers)
67
+ resp = request.execute
68
+ rescue => e
69
+ @logger.error "Failed to post resource #{uri} #{e}"
70
+ return nil
71
+ end
72
+
73
+ if resp.body.nil? || resp.body.length == 0
74
+ return nil
75
+ end
76
+
77
+ JSON.parse(resp.body)
78
+ end
79
+
80
+ def delete(uri)
81
+ uri = @cloud_url + uri
82
+ begin
83
+ request = self.request_factory(:delete, uri)
84
+ resp = request.execute
85
+ rescue => e
86
+ @logger.error "Failed to delete resource #{uri} #{e}"
87
+ return nil
88
+ end
89
+
90
+ if resp.code != 204
91
+ @logger.error "Failed to delete resource #{uri} #{e}"
92
+ else
93
+ @logger.info "response: #{resp.code}"
94
+ end
95
+ end
96
+
97
+ def upload(uri, file_name)
98
+ self.post(uri, {
99
+ :multipart => true,
100
+ :file => ::File.new(file_name, 'rb')
101
+ })
102
+ end
103
+
104
+ def download(uri, file_name, params = {}, http_params = {})
105
+ begin
106
+ ::File.open(file_name, "w+b") do |file|
107
+ full_uri = uri.start_with?(@cloud_url) ? uri : @cloud_url + uri
108
+ http_params = http_params.deep_merge({:headers => {:params => params}})
109
+ request = self.request_factory(:get, full_uri, http_params)
110
+ resp = request.execute
111
+ file.write(resp.body)
112
+ end
113
+ rescue => e
114
+ @logger.error "Failed to get resource #{uri} #{e}"
115
+ return nil
116
+ end
117
+ end
118
+
119
+ end
120
+ end
@@ -1,126 +1,161 @@
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.bitbar.com'
10
+
11
+ def initialize(username, password, cloud_url = CLOUD_ENDPOINT, logger = nil)
12
+ # Instance variables
13
+ @username = username
14
+ @password = password
15
+ @cloud_url = cloud_url
16
+ @logger = logger
17
+
18
+ if @logger.nil?
19
+ @logger = Logger.new(STDOUT)
20
+ @logger.info("Logger is not defined => output to STDOUT")
21
+ end
22
+ end
23
+
24
+ def authorize
25
+ @client = OAuth2::Client.new(
26
+ 'testdroid-cloud-api', nil, :site => @cloud_url, :token_url => 'oauth/token') do |faraday|
27
+ faraday.request :multipart
28
+ faraday.request :url_encoded
29
+ faraday.response :logger, @logger
30
+ faraday.adapter Faraday.default_adapter
31
+ end
32
+
33
+ @token = @client.password.get_token(@username, @password)
34
+
35
+ if @cloud_user.nil?
36
+ @cloud_user = TestdroidAPI::User.new("/#{API_VERSION}/me", self).refresh
37
+ @cloud_user = TestdroidAPI::User.new("/#{API_VERSION}/users/#{@cloud_user.id}", self).refresh
38
+
39
+ end
40
+ @cloud_user
41
+ end
42
+
43
+ def mime_for(path)
44
+ mime = MIME::Types.type_for path
45
+ mime.empty? ? 'text/plain' : mime[0].content_type
46
+ end
47
+
48
+ def upload(uri, filename)
49
+ begin
50
+ @token = @token.refresh! if @token.expired?
51
+ connection = @token.client.connection
52
+ payload = {:file => Faraday::UploadIO.new(filename, mime_for(filename))}
53
+ response = connection.post(@cloud_url + "#{uri}", payload, @token.headers)
54
+ rescue => e
55
+ @logger.error e
56
+ return nil
57
+ end
58
+ JSON.parse(response.body)
59
+ end
60
+
61
+ def post(uri, params = {})
62
+
63
+ @token = @token.refresh! if @token.expired?
64
+
65
+ begin
66
+ resp = @token.post("#{@cloud_url}#{uri}", params)
67
+ rescue => e
68
+ @logger.error "Failed to post resource #{uri} #{e}"
69
+ return nil
70
+ end
71
+
72
+ if resp.body.nil? || resp.body.length == 0
73
+ return nil
74
+ end
75
+
76
+ JSON.parse(resp.body)
77
+ end
78
+
79
+ def get(uri, params = {})
80
+
81
+ @token = @token.refresh! if @token.expired?
82
+
83
+ begin
84
+ resp = @token.get(@cloud_url + "#{uri}", :params => params)
85
+ rescue => e
86
+ @logger.error "Failed to get resource #{uri} #{e}"
87
+ return nil
88
+ end
89
+ JSON.parse(resp.body)
90
+ end
91
+
92
+ def delete(uri)
93
+
94
+ @token = @token.refresh! if @token.expired?
95
+
96
+ begin
97
+ resp = @token.delete(@cloud_url + "#{uri}")
98
+ rescue => e
99
+ @logger.error "Failed to delete resource #{uri} #{e}"
100
+ return nil
101
+ end
102
+
103
+ if resp.status != 204
104
+ @logger.error "Failed to delete resource #{uri} #{e}"
105
+ else
106
+ @logger.info "response: #{resp.status}"
107
+ end
108
+ end
109
+
110
+ def download(uri, file_name)
111
+ begin
112
+ @token = @token.refresh! if @token.expired?
113
+ ::File.open(file_name, "w+b") do |file|
114
+ full_uri = uri.start_with?(@cloud_url) ? uri : @cloud_url + uri
115
+ resp = @token.get(full_uri)
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
+
124
+ # Resources
125
+
126
+ # public read-only
127
+
128
+ def info
129
+ TestdroidAPI::CloudResource.new("/#{API_VERSION}/info", self, "info")
130
+ end
131
+
132
+ def devices
133
+ TestdroidAPI::Devices.new("/#{API_VERSION}/devices", self)
134
+ end
135
+
136
+ def label_groups
137
+ TestdroidAPI::LabelGroups.new("/#{API_VERSION}/label-groups", self)
138
+ end
139
+
140
+ # user read-write
141
+
142
+ def me
143
+ TestdroidAPI::User.new("/#{API_VERSION}/me", self).load
144
+ end
145
+
146
+ def properties
147
+ TestdroidAPI::Properties.new("/#{API_VERSION}/properties", self)
148
+ end
149
+
150
+ def device_session_connections
151
+ TestdroidAPI::DeviceSessionConnections.new("/#{API_VERSION}/device-session-connections", self)
152
+ end
153
+
154
+ # admin only
155
+
156
+ def admin
157
+ TestdroidAPI::Admin.new("/#{API_VERSION}/admin", self)
158
+ end
159
+
160
+ end
126
161
  end