appurify 0.5

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,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: b7d5bc4ad41dcb6b3ca21b0ac0e94f9a8b9bd03d
4
+ data.tar.gz: de2314d5b7d454c8fe341e27129bf785c4073d79
5
+ SHA512:
6
+ metadata.gz: 33b869fbd81c20d9a7fd3c67b9bf471d74d6446c7b6acb73d698e690f2cb74b95d2d341ad095262b02f4c453971bd5c8d09c3ff2a03814adf0d1e92d9f3d113a
7
+ data.tar.gz: b16cb51f7486e3e0a1f3a0e99618ec54e0ea9b34e1e590b16cdd88e0acafcb1d5fe09dfcb9e7afbb0fb5d03af0617f78e5cfc74698edac6342f6fdf273211d3b
@@ -0,0 +1,54 @@
1
+ # Appurify Gem
2
+
3
+ The official Ruby client for the [Appurify](http://www.appurify.com) API.
4
+
5
+ ### Installation
6
+
7
+ ```
8
+ gem install appurify
9
+ ```
10
+
11
+ ### Configuration
12
+
13
+ ```
14
+ client = Appurify::Client.new(key, secret, options)
15
+ ```
16
+
17
+ ### Listing Device Types
18
+
19
+ ```
20
+ device_types = client.device_types
21
+ device_type_id = client.device_types.first["device_type_id"]
22
+ ```
23
+
24
+ ### Uploading An Application
25
+
26
+ ```
27
+ response = client.upload_app_from_url(app_url)
28
+ application_id = response["app_id"]
29
+ ```
30
+
31
+ ### Uploading A Test
32
+
33
+ ```
34
+ test_type = "uiautomation"
35
+ response = client.upload_test_from_url(test_url, test_type)
36
+ test_id = response["test_id"]
37
+ ```
38
+
39
+ ### Starting A Test Run
40
+
41
+ ```
42
+ response = client.run_test(device_type_id, application_id, test_id)
43
+ test_run_id = response["test_run_id"]
44
+ ```
45
+
46
+ ### Retrieve Test Run Results
47
+
48
+ ```
49
+ response = client.monitor_test(test_run_id)
50
+ ```
51
+
52
+ ### Contribution
53
+
54
+ Found a bug or want to add a much needed feature? Go for it and just send us the Pull Request!
@@ -0,0 +1,10 @@
1
+ require 'open-uri'
2
+ require 'json'
3
+ require 'net/https'
4
+ require 'rest-client'
5
+ require 'appurify/version'
6
+ require 'appurify/client'
7
+
8
+ module Appurify
9
+ HOSTNAME = "live.appurify.com"
10
+ end
@@ -0,0 +1,145 @@
1
+ module Appurify
2
+ class Client
3
+ attr_accessor :scheme, :host, :port, :key, :secret, :request_timeout, :open_timeout, :last_request
4
+
5
+ def initialize(key, secret, options={})
6
+ @key = key
7
+ @secret = secret
8
+
9
+ @scheme, @host, @port, @request_timeout, @open_timeout = {
10
+ scheme: "https",
11
+ host: HOSTNAME,
12
+ port: 443,
13
+ request_timeout: 600,
14
+ open_timeout: 10
15
+ }.merge(options).values
16
+ end
17
+
18
+ def access_token
19
+ unless access_token_active?
20
+ url = build_url("access_token", "generate")
21
+ data = {
22
+ :key => @key,
23
+ :secret => @secret
24
+ }
25
+
26
+ #result = post(url, data, false)
27
+ result = post(url, data)
28
+ @access_token = result["access_token"]
29
+ @access_token_ttl = result["ttl"]
30
+ @access_token_created = Time.now
31
+ end
32
+
33
+ @access_token
34
+ end
35
+
36
+ def device_types
37
+ url = build_url("devices", "list")
38
+ get(url)
39
+ end
40
+
41
+ def network_conditions
42
+ url = build_url("devices", "config/networks/list")
43
+ get(url)
44
+ end
45
+
46
+ def upload_app_from_url(app_url)
47
+ url = build_url("apps", "upload")
48
+ data = {
49
+ :access_token => access_token,
50
+ :source_type => "url",
51
+ :source => app_url
52
+ }
53
+
54
+ post(url, data)
55
+ end
56
+
57
+ def upload_test_from_url(test_url, test_type)
58
+ url = build_url("tests", "upload")
59
+ data = {
60
+ :access_token => access_token,
61
+ :source_type => "url",
62
+ :test_type => test_type,
63
+ :source => test_url
64
+ }
65
+
66
+ post(url, data)
67
+ end
68
+
69
+ def upload_device_conditions(test_id, conditions)
70
+ url = build_url("config", "upload")
71
+ file_data = "[appurify]\n" + conditions.keys.collect{ |k| k.to_s + "=" + conditions[k].to_s }.join("\n")
72
+
73
+ file = StringIO.new(file_data)
74
+ file.class.class_eval { attr_accessor :name }
75
+ file.class.class_eval { attr_accessor :path }
76
+ file.name = "config.cnf"
77
+ file.path = "config.cnf"
78
+
79
+ data = {
80
+ :access_token => access_token,
81
+ :test_id => test_id,
82
+ :source => file
83
+ }
84
+
85
+ post(url, data)
86
+ end
87
+
88
+ def run_test(device_type_id, app_id, test_id, async=1)
89
+ url = build_url("tests", "run")
90
+ data = {
91
+ :access_token => access_token,
92
+ :device_type_id => device_type_id,
93
+ :app_id => app_id,
94
+ :test_id => test_id,
95
+ :async => async
96
+ }
97
+
98
+ post(url, data)
99
+ end
100
+
101
+ def monitor_test(test_run_id)
102
+ url = build_url("tests", "check")
103
+ params = { test_run_id: test_run_id }
104
+ get(url, params)
105
+ end
106
+
107
+ private
108
+
109
+ def access_token_active?
110
+ @access_token && Time.now < @access_token_created + @access_token_ttl
111
+ end
112
+
113
+ def build_url(type, resource)
114
+ @scheme + "://" + [@host, "resource", type, resource].join("/") + "/"
115
+ end
116
+
117
+ def get(url, params={})
118
+ @last_request = {
119
+ url: url,
120
+ request: params
121
+ }
122
+
123
+ query_string_params = params.collect{ |p| "&#{p[0].to_s}=#{p[1].to_s}" }.join
124
+ result = RestClient::Request.execute(:method => :get, :url => "#{url}?access_token=#{access_token}#{query_string_params}", :timeout => @request_timeout, :open_timeout => @open_timeout)
125
+ @last_request[:response] = result
126
+
127
+ JSON.parse(result)["response"]
128
+ end
129
+
130
+ def post(url, data, capture_request=true)
131
+ if capture_request
132
+ @last_request = {
133
+ url: url,
134
+ request: data
135
+ }
136
+ end
137
+
138
+ result = RestClient::Request.execute(:method => :post, :url => url, :payload => data, :timeout => @request_timeout, :open_timeout => @open_timeout)
139
+ @last_request[:response] = result if capture_request
140
+
141
+ JSON.parse(result)["response"]
142
+ end
143
+
144
+ end
145
+ end
@@ -0,0 +1,3 @@
1
+ module Appurify
2
+ VERSION = '0.5'
3
+ end
@@ -0,0 +1,130 @@
1
+ require 'spec_helper'
2
+ require 'fake_web'
3
+ require 'timecop'
4
+
5
+ describe Appurify do
6
+
7
+ let (:key) { "7ks6hmigudkbx3uuipgmqllhcoqmxf5mq" }
8
+ let (:secret) { "270td4563wpj2auoct4yu4tqx5kv4kotp" }
9
+
10
+ before do
11
+ FakeWeb.allow_net_connect = false
12
+ end
13
+
14
+ describe "When configuring an Appurify Client" do
15
+
16
+ it "should correctly configure the key and secret" do
17
+ client = Appurify::Client.new(key, secret)
18
+ client.key.should == key
19
+ client.secret.should == secret
20
+ end
21
+
22
+ it "should correctly configure connection options" do
23
+ options = {
24
+ scheme: "http",
25
+ host: "staging.appurify.com",
26
+ port: 80,
27
+ request_timeout: 5,
28
+ open_timeout: 5
29
+ }
30
+
31
+ client = Appurify::Client.new(key, secret, options)
32
+ client.scheme.should == options[:scheme]
33
+ client.host.should == options[:host]
34
+ client.port.should == options[:port]
35
+ client.request_timeout.should == options[:request_timeout]
36
+ client.open_timeout.should == options[:open_timeout]
37
+ end
38
+
39
+ end
40
+
41
+ describe "When using an Appurify Client" do
42
+
43
+ let (:client) { Appurify::Client.new(key, secret) }
44
+ let (:token) { "e8k3jd64gfrgbtqrunaipx9pl34xkao6c" }
45
+ let (:ttl) { 86400 }
46
+ let (:application_id) { "lvq2g2y6hn0sr36k9i9mrcochh49tbww3" }
47
+ let (:test_id) { "d9yovkaekgg29c3d2nr4guhfppe0jewra" }
48
+ let (:test_type) { "ocunit" }
49
+ let (:device_type) { 1 }
50
+ let (:device_id) { 10 }
51
+ let (:app_url) { "https://www.cisimple.com/builds/1/build_steps/1/artifacts/cisimple.app.zip" }
52
+ let (:test_url) { "https://www.cisimple.com/builds/1/build_steps/1/artifacts/cisimple.octest.zip" }
53
+
54
+ before do
55
+ mock_access_token_response(token, ttl)
56
+ mock_application_upload_response(application_id)
57
+ mock_test_upload_response(test_id, test_type)
58
+ mock_run_test_response
59
+ mock_monitor_test_response(token)
60
+ mock_upload_device_conditions_response
61
+ mock_device_types_response(token)
62
+ mock_network_conditions_response(token)
63
+ end
64
+
65
+ it "should successfully retrieve an access token" do
66
+ client.access_token.should == token
67
+ end
68
+
69
+ it "should cache access tokens" do
70
+ client.access_token
71
+ FakeWeb.clean_registry
72
+ mock_access_token_response
73
+ client.access_token.should == token
74
+ end
75
+
76
+ it "should retrieve a new access token when the current one has expired" do
77
+ client.access_token
78
+ FakeWeb.clean_registry
79
+ expected_token = "2hmiusynojjtgxsnd6eqdop1lreeua56i"
80
+ mock_access_token_response(expected_token)
81
+ Timecop.travel(Time.now + ttl + 1)
82
+ client.access_token.should == expected_token
83
+ end
84
+
85
+ it "should successfully upload an application from a url" do
86
+ response = client.upload_app_from_url(app_url)
87
+ response["id"].should == application_id
88
+ end
89
+
90
+ it "should successfully upload a test from a url" do
91
+ response = client.upload_test_from_url(test_url, test_type)
92
+ response["id"].should == test_id
93
+ response["test_type"].should == test_type
94
+ end
95
+
96
+ it "should successfully start a test on a device" do
97
+ test_run_id = 5
98
+ mock_run_test_response(test_run_id)
99
+ response = client.run_test(device_id, application_id, test_id)
100
+ response["test_run_id"].should == test_run_id
101
+ end
102
+
103
+ it "should successfully monitor a test run" do
104
+ test_run_id = 5
105
+ mock_monitor_test_response(token, test_run_id)
106
+ response = client.monitor_test(test_run_id)
107
+ response["status"].should == "complete"
108
+ end
109
+
110
+ it "should successfully retrieve the list of device types" do
111
+ response = client.device_types
112
+ response.count.should == 2
113
+ end
114
+
115
+ it "should successfully retrieve the list of network conditions" do
116
+ client.network_conditions.count.should == 5
117
+ end
118
+
119
+ it "should be able to execute a test end to end" do
120
+ device_type = client.device_types.first["id"]
121
+ app_id = client.upload_app_from_url(app_url)["id"]
122
+ test_id = client.upload_test_from_url(test_url, test_type)["id"]
123
+ client.upload_device_conditions(test_id, {:memory => 300, :network => 5})
124
+ test_run_id = client.run_test(device_type, app_id, test_id)["test_run_id"]
125
+ client.monitor_test(test_run_id)
126
+ end
127
+
128
+ end
129
+
130
+ end
@@ -0,0 +1,62 @@
1
+ require 'rspec'
2
+ require 'appurify'
3
+
4
+ RSpec.configure do |config|
5
+ config.color_enabled = true
6
+ config.formatter = 'documentation'
7
+ end
8
+
9
+ def mock_access_token_response(token="r895ku94f167udxfukhkbntyclxvwl8sc", ttl=86400)
10
+ url = "https://live.appurify.com/resource/access_token/generate/"
11
+ response ="{\"meta\": {\"code\": 200, \"request_id\": 123.456}, \"response\": {\"access_token\": \"#{token}\", \"ttl\": #{ttl}}}"
12
+ FakeWeb.register_uri(:post, url, :body => response, :status => 200)
13
+ end
14
+
15
+ def mock_application_upload_response(application_id="qxp58i5tbaosgbq8nagosfkf490gs7spd")
16
+ url = "https://live.appurify.com/resource/apps/upload/"
17
+ response = "{\"meta\": {\"code\": 200, \"request_id\": 123}, \"response\": {\"name\": \"cisimple.app.zip\", \"test_type\": null, \"uploaded_on\": \"2013-03-13T21:39:59Z\", \"source_type\": \"url\", \"ttl\": 86400, \"id\": \"#{application_id}\", \"size\": 404423}}"
18
+ FakeWeb.register_uri(:post, url, :body => response, :status => 200)
19
+ end
20
+
21
+ def mock_test_upload_response(test_id="eh4x44nspdqcsva7v2nvabjesvoqvcn89", test_type="ocunit")
22
+ url = "https://live.appurify.com/resource/tests/upload/"
23
+ response = "{\"meta\": {\"code\": 200, \"request_id\": 452}, \"response\": {\"name\": \"cisimpleTests.octest.zip\", \"test_type\": \"#{test_type}\", \"uploaded_on\": \"2013-03-13T22:12:50Z\", \"source_type\": \"url\", \"ttl\": 86400, \"id\": \"#{test_id}\", \"size\": 7764}}"
24
+ FakeWeb.register_uri(:post, url, :body => response, :status => 200)
25
+ end
26
+
27
+ def mock_run_test_response(test_run_id=1)
28
+ url = "https://live.appurify.com/resource/tests/run/"
29
+ response = "{\"meta\": {\"code\": 200, \"request_id\": 123}, \"response\": { \"test_run_id\": #{test_run_id} }}"
30
+ FakeWeb.register_uri(:post, url, :body => response, :status => 200)
31
+ end
32
+
33
+ def mock_upload_device_conditions_response
34
+ url = "https://live.appurify.com/resource/config/upload/"
35
+ response = "{\"meta\": {\"code\": 200, \"request_id\": 123}, \"response\": { }}"
36
+ FakeWeb.register_uri(:post, url, :body => response, :status => 200)
37
+ end
38
+
39
+ def mock_monitor_test_response(access_token, test_run_id=1, status="complete")
40
+ url = "https://live.appurify.com/resource/tests/check/?access_token=#{access_token}&test_run_id=#{test_run_id}"
41
+ response = "{\"meta\": {\"code\": 200, \"request_id\": 123}, \"response\": { \"status\": \"#{status}\" }}"
42
+ FakeWeb.register_uri(:get, url, :body => response, :status => 200)
43
+ end
44
+
45
+ def mock_device_types_response(access_token)
46
+ url = "https://live.appurify.com/resource/devices/list/?access_token=#{access_token}"
47
+ response = "{\"meta\": {\"code\": 200, \"request_id\": 475}, \"response\": [{\"device_type_id\": 1, \"name\": \"4s\", \"battery\": true, \"brand\": \"iPhone\", \"os_name\": \"iOS\", \"os_version\": \"5.1.1\", \"has_available_device\": false, \"carrier\": null}, {\"device_type_id\": 2, \"name\": \"4\", \"battery\": true, \"brand\": \"iPhone\", \"os_name\": \"iOS\", \"os_version\": \"5.1.1\", \"has_available_device\": true, \"carrier\": null}]}"
48
+ FakeWeb.register_uri(:get, url, :body => response, :status => 200)
49
+ end
50
+
51
+
52
+ def mock_network_conditions_response(access_token)
53
+ url = "https://live.appurify.com/resource/devices/config/networks/list/?access_token=#{access_token}"
54
+ response = "{\"meta\": {\"code\": 200, \"request_id\": 9673}, \"response\": [
55
+ {\"network_id\": 29, \"network_group\": \"AT&T\", \"network_name\": \"4G_LTE\"},
56
+ {\"network_id\": 16, \"network_group\": \"AT&T\", \"network_name\": \"3G_4_Bars\"},
57
+ {\"network_id\": 17, \"network_group\": \"AT&T\", \"network_name\": \"3G_3_Bars\"},
58
+ {\"network_id\": 18, \"network_group\": \"AT&T\", \"network_name\": \"3G_2_Bars\"},
59
+ {\"network_id\": 19, \"network_group\": \"AT&T\", \"network_name\": \"3G_1_Bar\"}]}"
60
+ FakeWeb.register_uri(:get, url, :body => response, :status => 200)
61
+ end
62
+
metadata ADDED
@@ -0,0 +1,108 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: appurify
3
+ version: !ruby/object:Gem::Version
4
+ version: '0.5'
5
+ platform: ruby
6
+ authors:
7
+ - Kevin Rohling
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2013-08-20 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rest-client
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ~>
18
+ - !ruby/object:Gem::Version
19
+ version: '1.6'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ~>
25
+ - !ruby/object:Gem::Version
26
+ version: '1.6'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rspec
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ~>
32
+ - !ruby/object:Gem::Version
33
+ version: '2.11'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ~>
39
+ - !ruby/object:Gem::Version
40
+ version: '2.11'
41
+ - !ruby/object:Gem::Dependency
42
+ name: fakeweb
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ~>
46
+ - !ruby/object:Gem::Version
47
+ version: '1.30'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ~>
53
+ - !ruby/object:Gem::Version
54
+ version: '1.30'
55
+ - !ruby/object:Gem::Dependency
56
+ name: timecop
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ~>
60
+ - !ruby/object:Gem::Version
61
+ version: '0.60'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ~>
67
+ - !ruby/object:Gem::Version
68
+ version: '0.60'
69
+ description: API client for Appurify
70
+ email:
71
+ - support@appurify.com
72
+ executables: []
73
+ extensions: []
74
+ extra_rdoc_files: []
75
+ files:
76
+ - README.md
77
+ - lib/appurify.rb
78
+ - lib/appurify/client.rb
79
+ - lib/appurify/version.rb
80
+ - spec/client/client_spec.rb
81
+ - spec/spec_helper.rb
82
+ homepage: https://github.com/appurify/appurify-ruby
83
+ licenses: []
84
+ metadata: {}
85
+ post_install_message:
86
+ rdoc_options:
87
+ - --charset=UTF-8
88
+ require_paths:
89
+ - lib
90
+ required_ruby_version: !ruby/object:Gem::Requirement
91
+ requirements:
92
+ - - '>='
93
+ - !ruby/object:Gem::Version
94
+ version: '0'
95
+ required_rubygems_version: !ruby/object:Gem::Requirement
96
+ requirements:
97
+ - - '>='
98
+ - !ruby/object:Gem::Version
99
+ version: '0'
100
+ requirements: []
101
+ rubyforge_project:
102
+ rubygems_version: 2.0.6
103
+ signing_key:
104
+ specification_version: 4
105
+ summary: Run tests using Appurify's mobile devices.
106
+ test_files:
107
+ - spec/client/client_spec.rb
108
+ - spec/spec_helper.rb