Permalink
Browse files

adding features (labs) functionality

  • Loading branch information...
1 parent 84e9329 commit 31b226426719a91158cf4afa641043eed383148f @geemus geemus committed May 23, 2012
View
8 Rakefile
@@ -21,6 +21,14 @@ task :cache, [:api_key] do |task, args|
file.write(addons)
end
+ app_name = "heroku-api-#{Time.now.to_i}"
+ app = heroku.post_app('name' => app_name)
+ features = Heroku::API::OkJson.encode(heroku.get_features(app_name).body)
+ File.open("#{File.dirname(__FILE__)}/lib/heroku/api/mock/cache/get_features.json", 'w') do |file|
+ file.write(features)
+ end
+ heroku.delete_app(app_name)
+
user = heroku.get_user.body
user["email"] = "user@example.com"
user["id"] = "123456@users.heroku.com"
View
4 lib/heroku/api.rb
@@ -1,8 +1,7 @@
require "base64"
-require "cgi"
require "excon"
require "securerandom"
-require "stringio"
+require "uri"
require "zlib"
__LIB_DIR__ = File.expand_path(File.join(File.dirname(__FILE__), ".."))
@@ -21,6 +20,7 @@
require "heroku/api/collaborators"
require "heroku/api/config_vars"
require "heroku/api/domains"
+require "heroku/api/features"
require "heroku/api/keys"
require "heroku/api/login"
require "heroku/api/logs"
View
45 lib/heroku/api/features.rb
@@ -0,0 +1,45 @@
+module Heroku
+ class API
+
+ # DELETE /features/:feature
+ def delete_feature(feature, app = nil)
+ request(
+ :expects => 200,
+ :method => :delete,
+ :path => "/features/#{feature}",
+ :query => { 'app' => app }
+ )
+ end
+
+ # GET /features
+ def get_features(app = nil)
+ request(
+ :expects => 200,
+ :method => :get,
+ :path => "/features",
+ :query => { 'app' => app }
+ )
+ end
+
+ # GET /features/:feature
+ def get_feature(feature, app = nil)
+ request(
+ :expects => 200,
+ :method => :get,
+ :path => "/features/#{feature}",
+ :query => { 'app' => app }
+ )
+ end
+
+ # POST /features/:feature
+ def post_feature(feature, app = nil)
+ request(
+ :expects => 200,
+ :method => :post,
+ :path => "/features/#{feature}",
+ :query => { 'app' => app }
+ )
+ end
+
+ end
+end
View
13 lib/heroku/api/mock.rb
@@ -3,6 +3,7 @@
require 'heroku/api/mock/collaborators'
require 'heroku/api/mock/config_vars'
require 'heroku/api/mock/domains'
+require 'heroku/api/mock/features'
require 'heroku/api/mock/keys'
require 'heroku/api/mock/login'
require 'heroku/api/mock/logs'
@@ -25,6 +26,10 @@ module Mock
:collaborators => {},
:config_vars => {},
:domains => {},
+ :features => {
+ :app => Hash.new {|hash,key| hash[key] = []},
+ :user => []
+ },
:keys => [],
:maintenance_mode => [],
:ps => {},
@@ -98,6 +103,14 @@ def self.get_mock_collaborator(mock_data, app, email)
mock_data[:collaborators][app].detect {|collaborator_data| collaborator_data['email'] == email}
end
+ def self.get_mock_feature(mock_data, feature)
+ @features ||= begin
+ data = File.read("#{File.dirname(__FILE__)}/mock/cache/get_features.json")
+ Heroku::API::OkJson.decode(data)
+ end
+ @features.detect {|feature_data| feature_data['name'] == feature}
+ end
+
def self.get_mock_key(mock_data, key)
mock_data[:keys].detect {|key_data| %r{ #{Regexp.escape(key)}$}.match(key_data['contents'])}
end
View
2 lib/heroku/api/mock/cache/get_addons.json
1 addition, 1 deletion not shown because the diff is too large. Please use a local Git client to view these changes.
View
1 lib/heroku/api/mock/cache/get_features.json
@@ -0,0 +1 @@
+[{"kind":"app","name":"sigterm-all","enabled":true,"docs":"http://devcenter.heroku.com/articles/labs-sigterm-all","summary":"When stopping a dyno, send SIGTERM to all processes rather than only to the root process."},{"kind":"user","name":"sumo-rankings","enabled":false,"docs":"http://sumo.heroku.com","summary":"Heroku Sumo ranks and visualizes the scale of your app, and suggests the optimum combination of dynos and add-ons to take it to the next level."},{"kind":"app","name":"user_env_compile","enabled":false,"docs":"http://devcenter.heroku.com/articles/labs-user-env-compile","summary":"Add user config vars to the environment during slug compilation"}]
View
2 lib/heroku/api/mock/cache/get_user.json
@@ -1 +1 @@
-{"name":null,"created_at":"2012/01/16 13:27:23 -0800","verified_at":"2012/01/16 13:30:59 -0800","last_login":"2012/05/18 11:23:50 -0700","confirmed":false,"id":"123456@users.heroku.com","verified":true,"confirmed_at":null,"email":"user@example.com"}
+{"name":null,"created_at":"2012/01/16 13:27:23 -0800","verified_at":"2012/05/18 13:49:16 -0700","last_login":"2012/05/22 15:05:13 -0700","confirmed":false,"id":"123456@users.heroku.com","verified":true,"confirmed_at":null,"email":"user@example.com"}
View
110 lib/heroku/api/mock/features.rb
@@ -0,0 +1,110 @@
+module Heroku
+ class API
+ module Mock
+
+ # stub DELETE /features/:feature
+ Excon.stub(:expects => 200, :method => :delete, :path => %r{^/features/([^/]+)$}) do |params|
+ request_params, mock_data = parse_stub_params(params)
+ app = request_params[:query].has_key?('app') && request_params[:query]['app']
+ feature, _ = request_params[:captures][:path]
+ if !app || get_mock_app(mock_data, app)
+ # app found
+ if feature_data = get_mock_feature(mock_data, feature)
+ feature_data = feature_data.merge('enabled' => true)
+ # feature exists
+ case feature_data['kind']
+ when 'app'
+ mock_data[:features][:app][app].delete(feature_data)
+ {
+ :body => Heroku::API::OkJson.encode(feature_data.merge('enabled' => false)),
+ :status => 200
+ }
+ when 'user'
+ mock_data[:features][:user].delete(feature_data.merge('enabled' => false))
+ {
+ :body => Heroku::API::OkJson.encode(feature_data),
+ :status => 200
+ }
+ end
+ else
+ # feature does not exist
+ {
+ :body => Heroku::API::OkJson.encode({'error' => "Feature not found."}),
+ :status => 404
+ }
+ end
+ else
+ {
+ :body => 'Feature not enabled.',
+ :status => 422
+ }
+ end
+ end
+
+ # stub GET /features
+ Excon.stub(:expects => 200, :method => :get, :path => %r|^/features$|) do |params|
+ request_params, mock_data = parse_stub_params(params)
+ {
+ :body => File.read("#{File.dirname(__FILE__)}/cache/get_features.json"),
+ :status => 200
+ }
+ end
+
+ # stub GET /features/:feature
+ Excon.stub(:expects => 200, :method => :get, :path => %r{^/features/([^/]+)}) do |params|
+ request_params, mock_data = parse_stub_params(params)
+ feature, _ = request_params[:captures][:path]
+ if feature_data = get_mock_feature(mock_data, feature)
+ {
+ :body => Heroku::API::OkJson.encode(feature_data),
+ :status => 200
+ }
+ else
+ # feature does not exist
+ {
+ :body => Heroku::API::OkJson.encode({'error' => "Feature not found."}),
+ :status => 404
+ }
+ end
+ end
+
+ # stub POST /features/:feature
+ Excon.stub(:expects => 200, :method => :post, :path => %r{^/features/([^/]+)$}) do |params|
+ request_params, mock_data = parse_stub_params(params)
+ app = request_params[:query].has_key?('app') && request_params[:query]['app']
+ feature, _ = request_params[:captures][:path]
+ if !app || get_mock_app(mock_data, app)
+ # app found
+ if feature_data = get_mock_feature(mock_data, feature)
+ feature_data = feature_data.merge('enabled' => true)
+ # feature exists
+ case feature_data['kind']
+ when 'app'
+ mock_data[:features][:app][app] << feature_data
+ {
+ :body => Heroku::API::OkJson.encode(feature_data),
+ :status => 200
+ }
+ when 'user'
+ mock_data[:features][:user] << feature_data
+ {
+ :body => '',
+ :status => 200
+ }
+ end
+ else
+ # feature does not exist
+ {
+ :body => Heroku::API::OkJson.encode({'error' => "Feature not found."}),
+ :status => 404
+ }
+ end
+ else
+ # app not found
+ Heroku::API::Mock::APP_NOT_FOUND
+ end
+ end
+
+ end
+ end
+end
View
1 test/test_addons.rb
@@ -39,7 +39,6 @@ def test_delete_addon
end
def test_get_addons
- skip unless MOCK
response = heroku.get_addons
data = File.read("#{File.dirname(__FILE__)}/../lib/heroku/api/mock/cache/get_addons.json")
View
87 test/test_features.rb
@@ -0,0 +1,87 @@
+require File.expand_path("#{File.dirname(__FILE__)}/test_helper")
+
+class TestFeatures < MiniTest::Unit::TestCase
+
+ def setup
+ @feature_data ||= begin
+ data = File.read("#{File.dirname(__FILE__)}/../lib/heroku/api/mock/cache/get_features.json")
+ features_data = Heroku::API::OkJson.decode(data)
+ features_data.detect {|feature| feature['name'] == 'user_env_compile'}
+ end
+ end
+
+ def test_delete_feature
+ with_app do |app_data|
+ heroku.post_feature('user_env_compile', app_data['name'])
+ response = heroku.delete_feature('user_env_compile', app_data['name'])
+
+ assert_equal(200, response.status)
+ assert_equal(@feature_data, response.body)
+ end
+ end
+
+ def test_delete_feature_app_not_found
+ assert_raises(Heroku::API::Errors::RequestFailed) do
+ heroku.delete_feature('user_env_compile', random_name)
+ end
+ end
+
+ def test_delete_feature_feature_not_found
+ with_app do |app_data|
+ assert_raises(Heroku::API::Errors::NotFound) do
+ heroku.delete_feature(random_name, app_data['name'])
+ end
+ end
+ end
+
+ def test_get_features
+ with_app do |app_data|
+ response = heroku.get_features(app_data['name'])
+ data = File.read("#{File.dirname(__FILE__)}/../lib/heroku/api/mock/cache/get_features.json")
+
+ assert_equal(200, response.status)
+ assert_equal(Heroku::API::OkJson.decode(data), response.body)
+ end
+ end
+
+ def test_get_feature
+ with_app do |app_data|
+ response = heroku.get_feature('user_env_compile', app_data['name'])
+
+ assert_equal(200, response.status)
+ assert_equal(@feature_data, response.body)
+ end
+ end
+
+ def test_get_features_feature_not_found
+ with_app do |app_data|
+ assert_raises(Heroku::API::Errors::NotFound) do
+ heroku.get_feature(random_name, app_data['name'])
+ end
+ end
+ end
+
+ def test_post_feature
+ with_app do |app_data|
+ response = heroku.post_feature('user_env_compile', app_data['name'])
+
+ assert_equal(200, response.status)
+ assert_equal(@feature_data.merge('enabled' => true), response.body)
+ end
+ end
+
+ def test_post_feature_app_not_found
+ assert_raises(Heroku::API::Errors::NotFound) do
+ heroku.post_feature('user_env_compile', random_name)
+ end
+ end
+
+ def test_post_feature_feature_not_found
+ with_app do |app_data|
+ assert_raises(Heroku::API::Errors::NotFound) do
+ heroku.post_feature(random_name, app_data['name'])
+ end
+ end
+ end
+
+end

0 comments on commit 31b2264

Please sign in to comment.