testdroid-api 1.0.1

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.
@@ -0,0 +1,79 @@
1
+ module TestdroidApi
2
+ class Client
3
+ class Project
4
+ class TestRun
5
+
6
+ attr_reader :project_id, :id, :name, :state
7
+ def initialize(client, project, config)
8
+ @client = client
9
+ @project_id = project.id
10
+
11
+ update(config)
12
+ end
13
+
14
+ # Updates test_run information
15
+ def update!
16
+ res_name = "run"
17
+ endpoint = "projects/#{@project_id}/runs/#{id}"
18
+
19
+ config = @client.get_api_request(endpoint, res_name)
20
+
21
+ update(config)
22
+ end
23
+
24
+ def results
25
+ raise NotImplementedError
26
+ end
27
+
28
+ # Returns devices that the run was executed on.
29
+ # @return [Array<TestdroidApi::Client::TestRun::DeviceRun>]
30
+ def device_runs
31
+ res_name = "deviceRuns"
32
+ endpoint = "projects/#{@project_id}/runs/#{id}/device-runs"
33
+
34
+ results = @client.get_api_request(endpoint, res_name)
35
+ results.map{|device_run|
36
+ TestdroidApi::Client::Project::TestRun::DeviceRun.new(@client, self, device_run)
37
+ }
38
+ end
39
+
40
+ # Get test run's screenshots as a zip file.
41
+ def screenshots_zip
42
+ res_name = 'screenshots.zip'
43
+ endpoint = "projects/#{@project_id}/runs/#{id}/screenshots.zip"
44
+
45
+ @client.get_file(endpoint, res_name)
46
+ end
47
+
48
+ # Get test run's junit results as a zip file
49
+ def junit_results_zip
50
+ res_name = 'junits.zip'
51
+ endpoint = "projects/#{@project_id}/runs/#{id}/junits.zip"
52
+
53
+ @client.get_file(endpoint, res_name)
54
+ end
55
+
56
+ # Get test run's logs as a zip file.
57
+ def logs_zip
58
+ res_name = 'logs.zip'
59
+ endpoint = "projects/#{@project_id}/runs/#{id}/logs.zip"
60
+
61
+ @client.get_file(endpoint, res_name)
62
+ end
63
+
64
+ # Did test run finish
65
+ # @return [Boolean]
66
+ def finished?
67
+ state == 'FINISHED'
68
+ end
69
+
70
+ private
71
+ def update(config)
72
+ @id = config['id']
73
+ @name = config['displayName']
74
+ @state = config['groupState']
75
+ end
76
+ end
77
+ end
78
+ end
79
+ end
@@ -0,0 +1,94 @@
1
+ module TestdroidApi
2
+ class Client
3
+ class Project
4
+ class TestRun
5
+ class DeviceRun
6
+
7
+ attr_reader :id, :device_id, :fail_message, :name, :state, :finished
8
+ attr_reader :screenshots_url, :junit_url, :logs_url
9
+
10
+ def initialize(client, run, config)
11
+ @client = client
12
+ @project_id = run.project_id
13
+ @run_id = run.id
14
+
15
+ update(config)
16
+ end
17
+
18
+ # Updates device run information
19
+ def update!
20
+ res_name = 'deviceRun'
21
+ endpoint = "projects/#{@project_id}/runs/#{@run_id}/device-runs/#{id}"
22
+
23
+ config = @client.get_api_request(endpoint, res_name)
24
+
25
+ update(config)
26
+ end
27
+
28
+ # Get device run's test results as JUnit XML
29
+ def junit_results
30
+ res_name = 'junit XML'
31
+ endpoint = "projects/#{@project_id}/runs/#{@run_id}/device-runs/#{id}_junit.xml"
32
+
33
+ @client.get_file(endpoint, res_name)
34
+ end
35
+
36
+ #Get device run's logs
37
+ def logs
38
+ res_name = 'log'
39
+ endpoint = "projects/#{@project_id}/runs/#{@run_id}/device-runs/#{id}_log.txt"
40
+
41
+ @client.get_file(endpoint, res_name)
42
+ end
43
+
44
+ # Get device run's screenshots as a zip file.
45
+ def screenshots_zip
46
+ res_name = 'screenshots.zip'
47
+ endpoint = "projects/#{@project_id}/runs/#{@run_id}/device-runs/#{id}/screenshots.zip"
48
+
49
+ @client.get_file(endpoint, res_name)
50
+ end
51
+
52
+ # Returns screenshots' ids for device run.
53
+ def screenshots
54
+ res_name = 'deviceRunScreenshots'
55
+ endpoint = "projects/#{@project_id}/runs/#{@run_id}/device-runs/#{id}/screenshots"
56
+
57
+ @client.get_api_request(endpoint, res_name)
58
+ end
59
+
60
+ # Get device's run screenshot.
61
+ # @param screenshot_id [Integer] screenshot id
62
+ def screenshot(screenshot_id)
63
+ res_name = 'screenshot'
64
+ endpoint = "projects/#{@project_id}/runs/#{@run_id}/device-runs/#{id}/screenshots/#{screenshot_id}"
65
+
66
+ @client.get_file(endpoint, res_name)
67
+ end
68
+
69
+ # Did test run finish
70
+ def finished?
71
+ finished
72
+ end
73
+
74
+ def results
75
+ raise NotImplementedError
76
+ end
77
+
78
+ private
79
+ def update(config)
80
+ @id = config['id']
81
+ @device_id = config['deviceId']
82
+ @fail_message = config['customerFailureMessage']
83
+ @name = config['deviceName']
84
+ @state = config['groupState']
85
+ @finished = config['finished']
86
+ @screenshots_url = config['screenshotsURI']
87
+ @junit_url = config['junitURI']
88
+ @logs_url = config['logURI']
89
+ end
90
+ end
91
+ end
92
+ end
93
+ end
94
+ end
@@ -0,0 +1,3 @@
1
+ module TestdroidApi
2
+ VERSION = "1.0.1"
3
+ end
@@ -0,0 +1,134 @@
1
+ require 'spec_helper'
2
+
3
+ describe TestdroidApi::Client do
4
+ let(:client_class) { described_class }
5
+ let(:client) {client_class.new("user", "password")}
6
+
7
+ let(:auth_url) {"http://users.testdroid.com/api/v1/authorize"}
8
+ before do
9
+ stub_request(:post, auth_url).
10
+ to_return(:status => 200, :body => {"secretApiKey" => "1"}.to_json, :headers => {})
11
+ end
12
+
13
+ describe '#authenticate' do
14
+ it 'sends the right request' do
15
+ client.authenticate!
16
+
17
+ a_request(:post, auth_url).
18
+ with(:body => {:email => "user", :password => "password" }).
19
+ should have_been_made
20
+ end
21
+
22
+ context 'when successful' do
23
+ it 'stores apiKey' do
24
+ client.authenticate!
25
+
26
+ client.instance_variable_get('@api_key').should == '1'
27
+ end
28
+ end
29
+
30
+ context 'when fails' do
31
+ it 'throws exception' do
32
+ stub_request(:post, "http://users.testdroid.com/api/v1/authorize").
33
+ to_return(:status => 200, :body => {}.to_json, :headers => {})
34
+
35
+ expect { client.authenticate! }.
36
+ to raise_error(RuntimeError, "Could not authenticate, are you sure you have the right credentials?")
37
+ end
38
+ end
39
+ end
40
+
41
+ context 'when authenticated' do
42
+ before do
43
+ client.authenticate!
44
+ end
45
+
46
+ describe '#projects' do
47
+ let(:url) {"https://cloud.testdroid.com/api/v1/projects"}
48
+ let(:response_body) {File.new(File.dirname(__FILE__) + "/fixtures/projects.json").read}
49
+
50
+ before do
51
+ stub_request(:get, url).
52
+ to_return(:body => JSON.parse(response_body).to_json)
53
+ end
54
+
55
+ it 'sends the right request' do
56
+ client.projects
57
+
58
+ a_request(:get, url).should have_been_made
59
+ end
60
+
61
+ context 'without any params' do
62
+ it 'should return array of projects' do
63
+ TestdroidApi::Client::Project.stub(:new).with(any_args).and_return(true)
64
+
65
+ client.projects.should == [true, true]
66
+ end
67
+ end
68
+
69
+ context 'with project names' do
70
+ it 'finds the matching projects' do
71
+ client.projects('Project 1').first.name.should == "Project 1"
72
+ end
73
+ it 'removes unmatched projects' do
74
+ client.projects('Project 1').count.should == 1
75
+ end
76
+ end
77
+ end
78
+
79
+ describe '#create_project' do
80
+ let(:url) {"https://cloud.testdroid.com/api/v1/projects"}
81
+ let(:response_body) {File.new(File.dirname(__FILE__) + "/fixtures/new_project.json").read}
82
+ before do
83
+ stub_request(:post, url).
84
+ to_return(:status => 200, :body => JSON.parse(response_body).to_json, :headers => {})
85
+ end
86
+
87
+ it 'sends the right request' do
88
+ client.create_project("Name", "Description" )
89
+
90
+ a_request(:post, url).
91
+ with(:body => {:name => "Name", :description => "Description"} ).
92
+ should have_been_made
93
+ end
94
+
95
+ it 'returns new project' do
96
+ client.create_project(nil, nil).name.should == "New project name"
97
+ end
98
+ end
99
+
100
+ describe '#device groups' do
101
+ let(:url) {url = "https://cloud.testdroid.com/api/v1/clusters"}
102
+ let(:response_body) {File.new(File.dirname(__FILE__) + "/fixtures/devices.json").read}
103
+ before do
104
+ stub_request(:get, url).
105
+ to_return(:status => 200, :body => JSON.parse(response_body).to_json, :headers => {})
106
+ end
107
+
108
+ it 'sends the right request' do
109
+ client.device_groups
110
+
111
+ a_request(:get, url).
112
+ should have_been_made
113
+ end
114
+
115
+ context 'without params' do
116
+ it 'returns all device groups' do
117
+ client.device_groups("Test devices").first.display_name.should == "Test devices"
118
+ end
119
+
120
+ it 'removes unmatched projects' do
121
+ client.device_groups("Test devices").count.should == 1
122
+ end
123
+ end
124
+
125
+ end
126
+ end
127
+
128
+ context 'when not authenticated' do
129
+ it 'does not allow to fetch projects' do
130
+ expect{client.projects}.
131
+ to raise_error(RuntimeError, "Are you sure you've authenticated?")
132
+ end
133
+ end
134
+ end
@@ -0,0 +1,108 @@
1
+ require 'spec_helper'
2
+
3
+ describe TestdroidApi::Client::Project::TestRun::DeviceRun do
4
+
5
+ let(:auth_url) { "http://users.testdroid.com/api/v1/authorize" }
6
+ let(:client) { TestdroidApi::Client.new('username', 'password') }
7
+ let(:run) { double(TestdroidApi::Client::Project::TestRun) }
8
+ let(:config) { JSON.parse(File.new(File.dirname(__FILE__) + "/fixtures/device_run.json").read)}
9
+ before do
10
+ stub_request(:post, auth_url).
11
+ to_return(:status => 200, :body => {"secretApiKey" => "1"}.to_json, :headers => {})
12
+ client.authenticate!
13
+
14
+ run.stub(:project_id).and_return(1)
15
+ run.stub(:id).and_return(100)
16
+ end
17
+
18
+ context 'when authenticated' do
19
+ let(:device_run) { described_class.new(client, run, config) }
20
+
21
+ describe '#update!' do
22
+ let(:url) { "https://cloud.testdroid.com/api/v1/projects/1/runs/100/device-runs/1000" }
23
+ let(:response_body) {File.new(File.dirname(__FILE__) + "/fixtures/waiting_device_run.json").read}
24
+ before do
25
+ stub_request(:get, url).
26
+ to_return(:status => 200, :body => JSON.parse(response_body).to_json, :headers => {})
27
+ end
28
+
29
+ it 'sends the right request' do
30
+ device_run.update!
31
+
32
+ a_request(:get, url).
33
+ should have_been_made
34
+ end
35
+
36
+ it 'updates run state' do
37
+ device_run.update!
38
+ device_run.state.should == "WAITING"
39
+ end
40
+ end
41
+
42
+
43
+ describe '#finished' do
44
+ let(:url) { "https://cloud.testdroid.com/api/v1/projects/1/runs/100/device-runs/1000" }
45
+ let(:response_body) {File.new(File.dirname(__FILE__) + "/fixtures/waiting_device_run.json").read}
46
+ before do
47
+ stub_request(:get, url).
48
+ to_return(:status => 200, :body => JSON.parse(response_body).to_json, :headers => {})
49
+ end
50
+
51
+ it 'returns true when run is finished' do
52
+ device_run.should be_finished
53
+ end
54
+
55
+ it 'returns false when run it not finished' do
56
+ device_run.update!
57
+ device_run.should_not be_finished
58
+ end
59
+ end
60
+
61
+ describe '#logs_zip' do
62
+ let(:url) { "https://cloud.testdroid.com/api/v1/projects/1/runs/100/device-runs/1000_log.txt" }
63
+ let(:response_body) {File.new(File.dirname(__FILE__) + "/fixtures/logs.txt")}
64
+ before do
65
+ stub_request(:get, url).
66
+ to_return(:status => 200, :body => response_body, :headers => {})
67
+ end
68
+
69
+ it 'sends the right request' do
70
+ device_run.logs
71
+
72
+ a_request(:get, url).should have_been_made
73
+ end
74
+
75
+ end
76
+
77
+ describe '#screenshots_zip' do
78
+ let(:url) { "https://cloud.testdroid.com/api/v1/projects/1/runs/100/device-runs/1000/screenshots/1000" }
79
+
80
+ before do
81
+ stub_request(:get, url).
82
+ to_return(:status => 200, :body => "", :headers => {})
83
+ end
84
+
85
+ it 'sends the right request' do
86
+ device_run.screenshot(1000)
87
+
88
+ a_request(:get, url).should have_been_made
89
+ end
90
+
91
+ end
92
+
93
+ describe '#junit_results' do
94
+ let(:url) { "https://cloud.testdroid.com/api/v1/projects/1/runs/100/device-runs/1000_junit.xml" }
95
+ let(:response_body) {File.new(File.dirname(__FILE__) + "/fixtures/junit.xml")}
96
+ before do
97
+ stub_request(:get, url).
98
+ to_return(:status => 200, :body => response_body, :headers => {})
99
+ end
100
+
101
+ it 'sends the right request' do
102
+ device_run.junit_results
103
+
104
+ a_request(:get, url).should have_been_made
105
+ end
106
+ end
107
+ end
108
+ end
@@ -0,0 +1,96 @@
1
+ {
2
+ "address": "",
3
+ "name": "User Surname",
4
+ "id": 1333333,
5
+ "state": "",
6
+ "country": "DE",
7
+ "displayCountry": "Germany",
8
+ "timeZone": "GMT",
9
+ "username": "132254",
10
+ "displayname": "User user",
11
+ "enabled": true,
12
+ "active": true,
13
+ "code": "",
14
+ "email": "user@soundcloud.com",
15
+ "googleId": null,
16
+ "billing": false,
17
+ "organization": {
18
+ "name": "",
19
+ "id": 1
20
+ },
21
+ "countryDisplayname": "Germany",
22
+ "city": "",
23
+ "phone": "",
24
+ "secretApiKey": "xxxxxxxxxxxxxxxxx",
25
+ "Organization role": "Other",
26
+ "vatID": "",
27
+ "accessible": true,
28
+ "activeRoles": [
29
+ {
30
+ "name": "TEST_RUN_SCREENSHOTS",
31
+ "active": true,
32
+ "timeLimitUsed": false,
33
+ "useLimit": 100,
34
+ "useLimited": true
35
+ },
36
+ {
37
+ "name": "FREE_RUN",
38
+ "active": true,
39
+ "timeLimitUsed": false,
40
+ "useLimit": 115,
41
+ "useLimited": true
42
+ },
43
+ {
44
+ "name": "PRIORITY_GOLD",
45
+ "active": true,
46
+ "timeLimitUsed": true,
47
+ "useLimit": 0,
48
+ "useLimited": false
49
+ },
50
+ {
51
+ "name": "PAID_RUN",
52
+ "active": true,
53
+ "timeLimitUsed": true,
54
+ "useLimit": 0,
55
+ "useLimited": false
56
+ },
57
+ {
58
+ "name": "API_CLIENT",
59
+ "active": true,
60
+ "timeLimitUsed": true,
61
+ "useLimit": 0,
62
+ "useLimited": false
63
+ }
64
+ ],
65
+ "lastLoginTime": 1380651077429,
66
+ "registrationIP": null,
67
+ "purchasedUserServices": [
68
+
69
+ ],
70
+ "creditsLeft": "10000",
71
+ "Heard from": "Other",
72
+ "availableHearFromValues": [
73
+ "COWORKER",
74
+ "EMAIL_CAMPAIGN",
75
+ "EVENT",
76
+ "ONLINE_COMMUNITY",
77
+ "SOCIAL_NETWORK",
78
+ "WEB_SEARCH",
79
+ "OTHER"
80
+ ],
81
+ "availableOrganizationRoleValues": [
82
+ "CEO_OR_OWNER",
83
+ "VP",
84
+ "MANAGER",
85
+ "INDIVIDUAL",
86
+ "QUALITY_ASSURANCE",
87
+ "DEVELOPER",
88
+ "MARKETING",
89
+ "CONSULTANT",
90
+ "OTHER"
91
+ ],
92
+ "admin": false,
93
+ "accountNonExpired": true,
94
+ "accountNonLocked": true,
95
+ "credentialsNonExpired": true
96
+ }