heroku-api 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (46) hide show
  1. data/.gitignore +4 -0
  2. data/.travis.yml +14 -0
  3. data/Gemfile +4 -0
  4. data/README.md +120 -0
  5. data/Rakefile +23 -0
  6. data/changelog.txt +4 -0
  7. data/heroku-api.gemspec +23 -0
  8. data/lib/heroku-api.rb +1 -0
  9. data/lib/heroku/api.rb +85 -0
  10. data/lib/heroku/api/addons.rb +47 -0
  11. data/lib/heroku/api/apps.rb +62 -0
  12. data/lib/heroku/api/collaborators.rb +33 -0
  13. data/lib/heroku/api/config_vars.rb +33 -0
  14. data/lib/heroku/api/domains.rb +33 -0
  15. data/lib/heroku/api/errors.rb +9 -0
  16. data/lib/heroku/api/keys.rb +42 -0
  17. data/lib/heroku/api/logs.rb +18 -0
  18. data/lib/heroku/api/mock.rb +176 -0
  19. data/lib/heroku/api/mock/addons.rb +153 -0
  20. data/lib/heroku/api/mock/apps.rb +184 -0
  21. data/lib/heroku/api/mock/cache/get_addons.json +1 -0
  22. data/lib/heroku/api/mock/collaborators.rb +55 -0
  23. data/lib/heroku/api/mock/config_vars.rb +46 -0
  24. data/lib/heroku/api/mock/domains.rb +71 -0
  25. data/lib/heroku/api/mock/keys.rb +46 -0
  26. data/lib/heroku/api/mock/logs.rb +20 -0
  27. data/lib/heroku/api/mock/processes.rb +191 -0
  28. data/lib/heroku/api/mock/releases.rb +124 -0
  29. data/lib/heroku/api/mock/stacks.rb +84 -0
  30. data/lib/heroku/api/processes.rb +77 -0
  31. data/lib/heroku/api/releases.rb +33 -0
  32. data/lib/heroku/api/stacks.rb +22 -0
  33. data/lib/heroku/api/vendor/okjson.rb +559 -0
  34. data/lib/heroku/api/version.rb +5 -0
  35. data/test/test_addons.rb +169 -0
  36. data/test/test_apps.rb +119 -0
  37. data/test/test_collaborators.rb +73 -0
  38. data/test/test_config_vars.rb +54 -0
  39. data/test/test_domains.rb +63 -0
  40. data/test/test_helper.rb +35 -0
  41. data/test/test_keys.rb +39 -0
  42. data/test/test_logs.rb +20 -0
  43. data/test/test_processes.rb +245 -0
  44. data/test/test_releases.rb +91 -0
  45. data/test/test_stacks.rb +49 -0
  46. metadata +134 -0
@@ -0,0 +1,33 @@
1
+ module Heroku
2
+ class API
3
+
4
+ # DELETE /apps/:app/domains/:domain
5
+ def delete_domain(app, domain)
6
+ request(
7
+ :expects => 200,
8
+ :method => :delete,
9
+ :path => "/apps/#{app}/domains/#{CGI.escape(domain)}"
10
+ )
11
+ end
12
+
13
+ # GET /apps/:app/domains
14
+ def get_domains(app)
15
+ request(
16
+ :expects => 200,
17
+ :method => :get,
18
+ :path => "/apps/#{app}/domains"
19
+ )
20
+ end
21
+
22
+ # POST /apps/:app/domains
23
+ def post_domain(app, domain)
24
+ request(
25
+ :expects => 201,
26
+ :method => :post,
27
+ :path => "/apps/#{app}/domains",
28
+ :query => {'domain_name[domain]' => domain}
29
+ )
30
+ end
31
+
32
+ end
33
+ end
@@ -0,0 +1,9 @@
1
+ module Heroku
2
+ class API
3
+ module Errors
4
+ class Error < StandardError; end
5
+
6
+ class NotFound < Error; end
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,42 @@
1
+ module Heroku
2
+ class API
3
+
4
+ # DELETE /user/keys/:key
5
+ def delete_key(key)
6
+ request(
7
+ :expects => 200,
8
+ :method => :delete,
9
+ :path => "/user/keys/#{CGI.escape(key).gsub('.','%2E')}"
10
+ )
11
+ end
12
+
13
+ # DELETE /user/keys
14
+ def delete_keys
15
+ request(
16
+ :expects => 200,
17
+ :method => :delete,
18
+ :path => "/user/keys"
19
+ )
20
+ end
21
+
22
+ # GET /user/keys
23
+ def get_keys
24
+ request(
25
+ :expects => 200,
26
+ :method => :get,
27
+ :path => "/user/keys"
28
+ )
29
+ end
30
+
31
+ # POST /user/keys
32
+ def post_key(key)
33
+ request(
34
+ :body => key,
35
+ :expects => 200,
36
+ :method => :post,
37
+ :path => "/user/keys"
38
+ )
39
+ end
40
+
41
+ end
42
+ end
@@ -0,0 +1,18 @@
1
+ module Heroku
2
+ class API
3
+
4
+ # GET /apps/:app/logs
5
+ def get_logs(app, options)
6
+ options = {
7
+ 'logplex' => 'true'
8
+ }.merge(options)
9
+ request(
10
+ :expects => 200,
11
+ :method => :get,
12
+ :path => "/apps/#{app}/logs",
13
+ :query => options
14
+ )
15
+ end
16
+
17
+ end
18
+ end
@@ -0,0 +1,176 @@
1
+ require 'heroku/api/mock/addons'
2
+ require 'heroku/api/mock/apps'
3
+ require 'heroku/api/mock/collaborators'
4
+ require 'heroku/api/mock/config_vars'
5
+ require 'heroku/api/mock/domains'
6
+ require 'heroku/api/mock/keys'
7
+ require 'heroku/api/mock/logs'
8
+ require 'heroku/api/mock/processes'
9
+ require 'heroku/api/mock/releases'
10
+ require 'heroku/api/mock/stacks'
11
+
12
+ module Heroku
13
+ class API
14
+ module Mock
15
+
16
+ APP_NOT_FOUND = { :body => 'App not found.', :status => 404 }
17
+ USER_NOT_FOUND = { :body => 'User not found.', :status => 404 }
18
+
19
+ @mock_data = Hash.new do |hash, key|
20
+ hash[key] = {
21
+ :addons => {},
22
+ :apps => [],
23
+ :collaborators => {},
24
+ :config_vars => {},
25
+ :domains => {},
26
+ :keys => [],
27
+ :maintenance_mode => [],
28
+ :ps => {},
29
+ :releases => {}
30
+ }
31
+ end
32
+
33
+ def self.add_mock_app_addon(mock_data, app, addon)
34
+ addon_data = get_mock_addon(mock_data, addon)
35
+ mock_data[:addons][app] << addon_data.reject {|key, value| !['beta', 'configured', 'description', 'name', 'state', 'url'].include?(key)}
36
+ version = mock_data[:releases][app].map {|release| release['name'][1..-1].to_i}.max || 0
37
+ env = if get_mock_app(mock_data, app)['stack'] == 'cedar'
38
+ {
39
+ 'BUNDLE_WITHOUT' => 'development:test',
40
+ 'DATABASE_URL' => 'postgres://username:password@ec2-123-123-123-123.compute-1.amazonaws.com/username',
41
+ 'LANG' => 'en_US.UTF-8',
42
+ 'RACK_ENV' => 'production',
43
+ 'SHARED_DATABASE_URL' => 'postgres://username:password@ec2-123-123-123-123.compute-1.amazonaws.com/username'
44
+ }
45
+ else
46
+ {}
47
+ end
48
+ mock_data[:releases][app] << {
49
+ 'addons' => mock_data[:addons][app].map {|addon| addon['name']},
50
+ 'commit' => nil,
51
+ 'created_at' => timestamp,
52
+ 'descr' => "Add-on add #{addon_data['name']}",
53
+ 'env' => env,
54
+ 'name' => "v#{version + 1}",
55
+ 'pstable' => { 'web' => '' },
56
+ 'user' => 'email@example.com'
57
+ }
58
+ end
59
+
60
+ def self.get_mock_addon(mock_data, addon)
61
+ @addons ||= begin
62
+ data = File.read("#{File.dirname(__FILE__)}/mock/cache/get_addons.json")
63
+ Heroku::API::OkJson.decode(data)
64
+ end
65
+ @addons.detect {|addon_data| addon_data['name'] == addon}
66
+ end
67
+
68
+ def self.get_mock_addon_price(mock_data, addon)
69
+ addon_data = get_mock_addon(mock_data, addon)
70
+ price_cents = addon_data['price_cents'] || 0
71
+ price = format("$%d/mo", price_cents / 100)
72
+ if price == '$0/mo'
73
+ price = 'free'
74
+ end
75
+ price
76
+ end
77
+
78
+ def self.get_mock_app(mock_data, app)
79
+ mock_data[:apps].detect {|app_data| app_data['name'] == app}
80
+ end
81
+
82
+ def self.get_mock_app_addon(mock_data, app, addon)
83
+ mock_data[:addons][app].detect {|addon_data| addon_data['name'] == addon}
84
+ end
85
+
86
+ def self.get_mock_app_domain(mock_data, app, domain)
87
+ mock_data[:domains][app].detect {|domain_data| domain_data['domain'] == domain}
88
+ end
89
+
90
+ def self.get_mock_collaborator(mock_data, app, email)
91
+ mock_data[:collaborators][app].detect {|collaborator_data| collaborator_data['email'] == email}
92
+ end
93
+
94
+ def self.get_mock_key(mock_data, key)
95
+ mock_data[:keys].detect {|key_data| %r{ #{Regexp.escape(key)}$}.match(key_data['contents'])}
96
+ end
97
+
98
+ def self.get_mock_processes(mock_data, app)
99
+ mock_data[:ps][app].map do |ps|
100
+
101
+ # swap day/month positions for Time.parse
102
+ time_parts = ps['transitioned_at'].split(' ')
103
+ date_parts = time_parts.first.split('/')
104
+ date_parts[1], date_parts[2] = date_parts[2], date_parts[1]
105
+ time_parts[0] = date_parts.join('/')
106
+ munged_time = time_parts.join(' ')
107
+ elapsed = Time.now.to_i - Time.parse(munged_time).to_i
108
+ ps['elapsed'] = elapsed
109
+
110
+ pretty_elapsed = if elapsed < 60
111
+ "#{elapsed}s"
112
+ elsif elapsed < (60 * 60)
113
+ "#{elapsed / 60}m"
114
+ else
115
+ "#{elapsed / 60 / 60}h"
116
+ end
117
+ ps['pretty_state'] = "#{ps['state']} for #{pretty_elapsed}"
118
+
119
+ ps
120
+ end
121
+ end
122
+
123
+ def self.parse_stub_params(params)
124
+ api_key = Base64.decode64(params[:headers]['Authorization']).split(':').last
125
+
126
+ parsed = params.dup
127
+ begin # try to JSON decode
128
+ parsed[:body] &&= Heroku::API::OkJson.decode(parsed[:body])
129
+ rescue # else leave as is
130
+ end
131
+
132
+ [parsed, @mock_data[api_key]]
133
+ end
134
+
135
+ def self.remove_mock_app_addon(mock_data, app, addon)
136
+ addon_data = mock_data[:addons][app].detect {|addon_data| addon_data['name'] == addon}
137
+ mock_data[:addons][app].delete(addon_data)
138
+ version = mock_data[:releases][app].map {|release| release['name'][1..-1].to_i}.max || 0
139
+ env = if get_mock_app(mock_data, app)['stack'] == 'cedar'
140
+ {
141
+ 'BUNDLE_WITHOUT' => 'development:test',
142
+ 'DATABASE_URL' => 'postgres://username:password@ec2-123-123-123-123.compute-1.amazonaws.com/username',
143
+ 'LANG' => 'en_US.UTF-8',
144
+ 'RACK_ENV' => 'production',
145
+ 'SHARED_DATABASE_URL' => 'postgres://username:password@ec2-123-123-123-123.compute-1.amazonaws.com/username'
146
+ }
147
+ else
148
+ {}
149
+ end
150
+ mock_data[:releases][app] << {
151
+ 'addons' => mock_data[:addons][app].map {|addon| addon['name']},
152
+ 'commit' => nil,
153
+ 'created_at' => timestamp,
154
+ 'descr' => "Add-on remove #{addon_data['name']}",
155
+ 'env' => env,
156
+ 'name' => "v#{version + 1}",
157
+ 'pstable' => { 'web' => '' },
158
+ 'user' => 'email@example.com'
159
+ }
160
+ end
161
+
162
+ def self.with_mock_app(mock_data, app, &block)
163
+ if app_data = get_mock_app(mock_data, app)
164
+ yield(app_data)
165
+ else
166
+ APP_NOT_FOUND
167
+ end
168
+ end
169
+
170
+ def self.timestamp
171
+ Time.now.strftime("%G/%d/%m %H:%M:%S %z")
172
+ end
173
+
174
+ end
175
+ end
176
+ end
@@ -0,0 +1,153 @@
1
+ module Heroku
2
+ class API
3
+ module Mock
4
+
5
+ # stub DELETE /apps/:app/addons/:addon
6
+ Excon.stub(:expects => 200, :method => :delete, :path => %r{^/apps/([^/]+)/addons/([^/]+)$}) do |params|
7
+ request_params, mock_data = parse_stub_params(params)
8
+ app, addon, _ = request_params[:captures][:path]
9
+ with_mock_app(mock_data, app) do
10
+ addon_names = mock_data[:addons][app].map {|data| data['name']}
11
+ if addon_data = get_mock_addon(mock_data, addon)
12
+ # addon exists
13
+ if app_addon_data = get_mock_app_addon(mock_data, app, addon)
14
+ # addon is currently installed
15
+ remove_mock_app_addon(mock_data, app, addon)
16
+ {
17
+ :body => Heroku::API::OkJson.encode({
18
+ :message => nil,
19
+ :price => get_mock_addon_price(mock_data, addon),
20
+ :status => 'Uninstalled'
21
+ }),
22
+ :status => 200
23
+ }
24
+ else
25
+ # addon is not currently installed
26
+ {
27
+ :body => Heroku::API::OkJson.encode({'error' => "The add-on #{addon} is not installed for this app. Did you mean:\n\t#{addon_names.join("\n\t")}"}),
28
+ :status => 422
29
+ }
30
+ end
31
+ else
32
+ # addon does not exist
33
+ {
34
+ :body => Heroku::API::OkJson.encode({'error' => "Could not find add-on #{addon}. Did you mean:\n\t#{addon_names.join("\n\t")}"}),
35
+ :status => 422
36
+ }
37
+ end
38
+ end
39
+ end
40
+
41
+ # stub GET /addons
42
+ Excon.stub(:expects => 200, :method => :get, :path => "/addons") do |params|
43
+ request_params, mock_data = parse_stub_params(params)
44
+ {
45
+ :body => File.read("#{File.dirname(__FILE__)}/cache/get_addons.json"),
46
+ :status => 200
47
+ }
48
+ end
49
+
50
+ # stub GET /apps/:app/addons
51
+ Excon.stub(:expects => 200, :method => :get, :path => %r{^/apps/([^/]+)/addons$}) do |params|
52
+ request_params, mock_data = parse_stub_params(params)
53
+ app, _ = request_params[:captures][:path]
54
+ with_mock_app(mock_data, app) do
55
+ {
56
+ :body => Heroku::API::OkJson.encode(mock_data[:addons][app].map {|addon| addon['configured'] = true; addon}),
57
+ :status => 200
58
+ }
59
+ end
60
+ end
61
+
62
+ # stub POST /apps/:app/addons
63
+ Excon.stub(:expects => 200, :method => :post, :path => %r{^/apps/([^/]+)/addons/([^/]+)$}) do |params|
64
+ request_params, mock_data = parse_stub_params(params)
65
+ app, addon, _ = request_params[:captures][:path]
66
+ with_mock_app(mock_data, app) do
67
+ if addon_data = get_mock_addon(mock_data, addon)
68
+ # addon exists
69
+ unless app_addon_type_data = mock_data[:addons][app].detect {|data| data['name'] =~ %r{^#{addon.split(':').first}}}
70
+ # addon of same type does not exist
71
+ unless app_addon_data = get_mock_app_addon(mock_data, app, addon)
72
+ # addon is not currently installed
73
+ add_mock_app_addon(mock_data, app, addon)
74
+ {
75
+ :body => Heroku::API::OkJson.encode({
76
+ :message => nil,
77
+ :price => get_mock_addon_price(mock_data, addon),
78
+ :status => 'Installed'
79
+ }),
80
+ :status => 200
81
+ }
82
+ else
83
+ # addon is currently installed
84
+ {
85
+ :body => Heroku::API::OkJson.encode({'error' => "Add-on already installed."}),
86
+ :status => 422
87
+ }
88
+ end
89
+ else
90
+ # addon of same type exists
91
+ {
92
+ :body => Heroku::API::OkJson.encode({'error' => "#{app_addon_type_data['name']} add-on already added.\nTo upgrade, use addons:upgrade instead.\n"}),
93
+ :status => 422
94
+ }
95
+ end
96
+ else
97
+ # addon does not exist
98
+ {
99
+ :body => Heroku::API::OkJson.encode({'error' => "Add-on not found."}),
100
+ :status => 422
101
+ }
102
+ end
103
+ end
104
+ end
105
+
106
+ # stub PUT /apps/:app/addons
107
+ Excon.stub(:expects => 200, :method => :put, :path => %r{^/apps/([^/]+)/addons/([^/]+)$}) do |params|
108
+ request_params, mock_data = parse_stub_params(params)
109
+ app, addon, _ = request_params[:captures][:path]
110
+ with_mock_app(mock_data, app) do
111
+ if addon_data = get_mock_addon(mock_data, addon)
112
+ # addon exists
113
+ if mock_data[:addons][app].detect {|data| data['name'] =~ %r{^#{addon.split(':').first}}}
114
+ # addon of same type exists
115
+ unless app_addon_data = get_mock_app_addon(mock_data, app, addon)
116
+ # addon is not currently installed
117
+ mock_data[:addons][app].delete(app_addon_data)
118
+ add_mock_app_addon(mock_data, app, addon)
119
+ {
120
+ :body => Heroku::API::OkJson.encode({
121
+ :message => nil,
122
+ :price => get_mock_addon_price(mock_data, addon),
123
+ :status => 'Updated'
124
+ }),
125
+ :status => 200
126
+ }
127
+ else
128
+ # addon is currently installed
129
+ {
130
+ :body => Heroku::API::OkJson.encode({'error' => "Add-on already installed."}),
131
+ :status => 422
132
+ }
133
+ end
134
+ else
135
+ # addon of same type not installed
136
+ {
137
+ :body => Heroku::API::OkJson.encode({'error' => "Can't upgrade, no #{addon.split(':').join(' ')} add-on has been added.\nTo add, use addons:add instead.\n"}),
138
+ :status => 422
139
+ }
140
+ end
141
+ else
142
+ # addon does not exist
143
+ {
144
+ :body => Heroku::API::OkJson.encode({'error' => "Add-on not found."}),
145
+ :status => 422
146
+ }
147
+ end
148
+ end
149
+ end
150
+
151
+ end
152
+ end
153
+ end
@@ -0,0 +1,184 @@
1
+ module Heroku
2
+ class API
3
+ module Mock
4
+
5
+ # stub DELETE /apps/:app
6
+ Excon.stub(:expects => 200, :method => :delete, :path => %r{^/apps/([^/]+)$} ) do |params|
7
+ request_params, mock_data = parse_stub_params(params)
8
+ app, _ = request_params[:captures][:path]
9
+ with_mock_app(mock_data, app) do |app_data|
10
+ mock_data[:addons].delete(app)
11
+ mock_data[:apps].delete(app_data)
12
+ mock_data[:collaborators].delete(app)
13
+ mock_data[:config_vars].delete(app)
14
+ mock_data[:domains].delete(app)
15
+ mock_data[:ps].delete(app)
16
+ mock_data[:releases].delete(app)
17
+ {
18
+ :body => Heroku::API::OkJson.encode({}),
19
+ :status => 200
20
+ }
21
+ end
22
+ end
23
+
24
+ # stub GET /apps/
25
+ Excon.stub(:expects => 200, :method => :get, :path => '/apps') do |params|
26
+ request_params, mock_data = parse_stub_params(params)
27
+ {
28
+ :body => Heroku::API::OkJson.encode(mock_data[:apps]),
29
+ :status => 200
30
+ }
31
+ end
32
+
33
+ # stub GET /apps/:app
34
+ Excon.stub(:expects => 200, :method => :get, :path => %r{^/apps/([^/]+)$} ) do |params|
35
+ request_params, mock_data = parse_stub_params(params)
36
+ app, _ = request_params[:captures][:path]
37
+ with_mock_app(mock_data, app) do |app_data|
38
+ {
39
+ :body => Heroku::API::OkJson.encode(app_data),
40
+ :status => 200
41
+ }
42
+ end
43
+ end
44
+
45
+ # stub POST /apps
46
+ Excon.stub(:expects => 202, :method => :post, :path => '/apps') do |params|
47
+ request_params, mock_data = parse_stub_params(params)
48
+ app = request_params[:query].has_key?('app[name]') && request_params[:query]['app[name]'] || "generated-name-#{rand(999)}"
49
+
50
+ if get_mock_app(mock_data, app)
51
+ {
52
+ :body => Heroku::API::OkJson.encode('error' => 'Name is already taken'),
53
+ :status => 422
54
+ }
55
+ else
56
+ stack = request_params[:query].has_key?('app[stack]') && request_params[:query]['app[stack]'] || 'bamboo-mri-1.9.2'
57
+ app_data = {
58
+ 'created_at' => timestamp,
59
+ 'create_status' => 'complete',
60
+ 'id' => rand(99999),
61
+ 'name' => app,
62
+ 'owner_email' => 'email@example.com',
63
+ 'slug_size' => nil,
64
+ 'stack' => request_params[:query].has_key?('app[stack]') && request_params[:query]['app[stack]'] || 'bamboo-mri-1.9.2',
65
+ 'requested_stack' => nil,
66
+ 'git_url' => "git@heroku.com:#{app}.git",
67
+ 'repo_migrate_status' => 'complete',
68
+ 'repo_size' => nil,
69
+ 'dynos' => 0,
70
+ 'web_url' => "http://#{app}.herokuapp.com/",
71
+ 'workers' => 0
72
+ }
73
+
74
+ mock_data[:addons][app] = []
75
+ mock_data[:apps] << app_data
76
+ mock_data[:collaborators][app] = [{
77
+ 'access' => 'edit',
78
+ 'email' => 'email@example.com'
79
+ }]
80
+ mock_data[:config_vars][app] = {}
81
+ mock_data[:domains][app] = []
82
+ mock_data[:ps][app] = [{
83
+ 'action' => 'up',
84
+ 'app_name' => app,
85
+ 'attached' => false,
86
+ 'command' => nil, # set by stack below
87
+ 'elapsed' => 0,
88
+ 'pretty_state' => 'created for 0s',
89
+ 'process' => 'web.1',
90
+ 'rendezvous_url' => nil,
91
+ 'slug' => 'NONE',
92
+ 'state' => 'created',
93
+ 'transitioned_at' => app_data['created_at'],
94
+ 'type' => nil, # set by stack below
95
+ 'upid' => rand(99999999).to_s
96
+ }]
97
+ mock_data[:releases][app] = []
98
+
99
+ add_mock_app_addon(mock_data, app, 'logging:basic')
100
+ if stack == 'cedar'
101
+ add_mock_app_addon(mock_data, app, 'releases:basic')
102
+ mock_data[:ps][app].first['type'] = 'Ps'
103
+ else
104
+ add_mock_app_addon(mock_data, app, 'shared-database:5mb')
105
+ mock_data[:config_vars][app] = {
106
+ 'BUNDLE_WITHOUT' => 'development:test',
107
+ 'LANG' => 'en_US.UTF-8',
108
+ 'RACK_ENV' => 'production'
109
+ }
110
+ mock_data[:ps][app].first['command'] = 'thin -p $PORT -e $RACK_ENV -R $HEROKU_RACK start'
111
+ mock_data[:ps][app].first['type'] = 'Dyno'
112
+ end
113
+
114
+ {
115
+ :body => Heroku::API::OkJson.encode(app_data),
116
+ :status => 202
117
+ }
118
+ end
119
+ end
120
+
121
+ # stub POST /apps/:app/server/maintenance
122
+ Excon.stub(:expects => 200, :method => :post, :path => %r{^/apps/([^/]+)/server/maintenance$}) do |params|
123
+ request_params, mock_data = parse_stub_params(params)
124
+ app, _ = request_params[:captures][:path].first
125
+
126
+ with_mock_app(mock_data, app) do
127
+ case request_params[:query]['maintenance_mode']
128
+ when '0'
129
+ mock_data[:maintenance_mode] -= [app]
130
+ when '1'
131
+ mock_data[:maintenance_mode] |= [app]
132
+ end
133
+
134
+ {
135
+ :status => 200
136
+ }
137
+ end
138
+ end
139
+
140
+ # stub PUT /apps/:app
141
+ Excon.stub(:expects => 200, :method => :put, :path => %r{^/apps/([^/]+)$}) do |params|
142
+ request_params, mock_data = parse_stub_params(params)
143
+ app, _ = request_params[:captures][:path]
144
+
145
+ with_mock_app(mock_data, app) do |app_data|
146
+ if request_params[:query].has_key?('app[name]')
147
+ app_data['name'] = request_params[:query]['app[name]']
148
+ end
149
+ if request_params[:query].has_key?('app[transfer_owner]')
150
+ email = request_params[:query]['app[transfer_owner]']
151
+ if collaborator = get_mock_collaborator(mock_data, app, email)
152
+ app_data['owner_email'] = email
153
+ end
154
+ end
155
+ if email && !collaborator
156
+ {
157
+ :body => Heroku::API::OkJson.encode('error' => 'Only existing collaborators can receive ownership for an app'),
158
+ :status => 422
159
+ }
160
+ else
161
+ {
162
+ :body => Heroku::API::OkJson.encode('name' => app_data['name']),
163
+ :status => 200
164
+ }
165
+ end
166
+ end
167
+ end
168
+
169
+ # stub PUT /apps/:app/status
170
+ Excon.stub(:method => :put, :path => %r{^/apps/([^/]+)/status}) do |params|
171
+ request_params, mock_data = parse_stub_params(params)
172
+ app, _ = request_params[:captures][:path]
173
+
174
+ with_mock_app(mock_data, app) do |app_data|
175
+ {
176
+ :body => Heroku::API::OkJson.encode({}),
177
+ :status => 201
178
+ }
179
+ end
180
+ end
181
+
182
+ end
183
+ end
184
+ end