af-addon-tester 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore ADDED
@@ -0,0 +1,5 @@
1
+ *.gem
2
+ .bundle
3
+ Gemfile.lock
4
+ pkg/*
5
+ manifest.json
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source "http://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in af-addon-tester.gemspec
4
+ gemspec
data/README.md ADDED
@@ -0,0 +1,45 @@
1
+ af-addon-tester
2
+ ===============
3
+
4
+ <img src="http://appfog.com/images/logo.png" />
5
+
6
+ Allows developers to test App Fog add-ons
7
+
8
+ ## Setup ##
9
+
10
+ 1) Clone
11
+
12
+ $ git clone git@github.com:tsantef/af-addon-tester.git
13
+
14
+ 2) Create a manifest.json that points to a test addon
15
+
16
+ Example
17
+
18
+ {
19
+ "id":"myaddon",
20
+ "api":{
21
+ "plans":[
22
+ {"id":"free"}
23
+ ],
24
+ "config_vars": {
25
+ "MYADDON_URL":"http://some.url.com",
26
+ "MYADDON_VAR1":"cats",
27
+ "MYADDON_VAR2":"dogs"
28
+ },
29
+ "test":"http://localhost:4567/myaddon/resources",
30
+ "password":"cavef6azebRewruvecuch",
31
+ "sso_salt":"8ouy3ayLEyOA7HLAKO2Yo"
32
+ }
33
+ }
34
+
35
+
36
+ ## Usage ##
37
+
38
+ $ af-addon-tester <path to manifest>
39
+
40
+
41
+ ## Meta ##
42
+
43
+ Maintained by Tim Santeford.
44
+
45
+ Released under the MIT license.
data/Rakefile ADDED
@@ -0,0 +1 @@
1
+ require "bundler/gem_tasks"
@@ -0,0 +1,23 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require "af-addon-tester/version"
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = "af-addon-tester"
7
+ s.version = AppFog::AddonTester::VERSION
8
+ s.default_executable = %q{af-addon-tester}
9
+ s.authors = ["Tim Santeford"]
10
+ s.email = ["tim@phpfog.com"]
11
+ s.homepage = "http://www.appfog.com"
12
+ s.summary = %q{Tests App Fog Add-ons}
13
+ s.description = %q{Allows developers to test App Fog add-ons}
14
+
15
+ s.rubyforge_project = "af-addon-tester"
16
+
17
+ s.files = `git ls-files`.split("\n")
18
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
19
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
20
+ s.require_paths = ["lib"]
21
+
22
+ s.add_runtime_dependency 'json'
23
+ end
@@ -0,0 +1,183 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ lib = File.expand_path(File.dirname(__FILE__) + '/../lib')
4
+ $LOAD_PATH.unshift(lib) if File.directory?(lib) && !$LOAD_PATH.include?(lib)
5
+
6
+ require 'rubygems'
7
+ require 'json'
8
+ require 'digest/sha1'
9
+ require 'af-addon-tester'
10
+
11
+ manifest_path = ARGV.first
12
+
13
+ begin
14
+ manifest_file = File.open(File.expand_path(manifest_path), 'r')
15
+ manifest_json = manifest_file.readlines.to_s
16
+ manifest = JSON.parse(manifest_json)
17
+
18
+ raise "Missing id" if manifest['id'].nil?
19
+ raise "Missing api section" if manifest['api'].nil?
20
+ raise "Missing api password" if manifest['api']['password'].nil?
21
+ raise "Missing apt test url" if manifest['api']['test'].nil?
22
+ raise "Manifest must have atleast one plan" if manifest['api']['plans'].nil? || manifest['api']['plans'][0].nil? || manifest['api']['plans'][0]['id'].nil?
23
+ raise "missing api config_vars" if manifest['api']['config_vars'].nil?
24
+ raise "Missing api sso_salt" if manifest['api']['sso_salt'].nil?
25
+
26
+ rescue Exception => e
27
+ puts bwhite "#{e.message}. Please specify a valid manifest file."
28
+ exit
29
+ end
30
+
31
+ callback_url = 'http://localhost:9990'
32
+ config_prefix = manifest['id'].gsub('-','_').upcase + '_'
33
+ bad_user = 'bad_user'
34
+ bad_password = 'bad_pass'
35
+
36
+ addon = Rest.new(manifest['api']['test'], manifest['id'], manifest['api']['password'])
37
+ resp = nil
38
+
39
+ validate "Provisioning" do
40
+ params = {}
41
+ payload = { 'customer_id' => manifest['id'], 'plan' => manifest['api']['plans'][0]['id'], 'callback_url' => callback_url, 'options' => '{}' }
42
+ resp = addon.post(manifest['api']['test'], params, JSON.generate(payload))
43
+ failed("response code: #{resp.code} - #{resp.message}") if resp.code != "200"
44
+ passed
45
+ end
46
+
47
+ if resp.code == "200"
48
+ provision_info = nil
49
+ validate "Valid JSON response" do
50
+ begin
51
+ provision_info = JSON.parse(resp.body)
52
+ rescue Exception => e
53
+ failed e.message
54
+ end
55
+ passed
56
+ end
57
+
58
+ unless provision_info.nil?
59
+ validate "Response params" do
60
+ begin
61
+ failed("Missing 'id'") if provision_info['id'].nil? || provision_info['id'] == ""
62
+ rescue Exception => e
63
+ failed e.message
64
+ end
65
+ passed
66
+ end
67
+
68
+ unless provision_info['config'].nil?
69
+ validate "All config keys are in manifest" do
70
+ provision_info['config'].each do |key, value|
71
+ unless manifest['api']['config_vars'].include? key; failed "#{key} not found in config"; end
72
+ end
73
+ end
74
+
75
+ validate "All manifest config keys are in response" do
76
+ manifest['api']['config_vars'].each do |key, value|
77
+ unless provision_info['config'].include? key; failed "#{key} not found in manifest"; end
78
+ end
79
+ end
80
+
81
+ validate "All config keys are prefixed with addon name" do
82
+ provision_info['config'].each do |key, value|
83
+ unless key.start_with? config_prefix; failed "#{key} does not begin with #{config_prefix}"; end
84
+ end
85
+ passed
86
+ end
87
+ end
88
+
89
+ resource_id = provision_info['id']
90
+ unless resource_id.nil?
91
+ validate "Update resource" do
92
+ params = {}
93
+ payload = { 'plan' => 'paid', 'callback_url' => callback_url, 'options' => '{}' }
94
+ resp = addon.put(manifest['api']['test'] + "/#{resource_id}", params, JSON.generate(payload))
95
+ failed("response code: #{resp.code}") if resp.code != "200"
96
+ passed
97
+ end
98
+
99
+ READLEN = 1024 * 10
100
+ reader, writer = IO.pipe
101
+ out = nil
102
+ validate "Callback" do
103
+ child = fork do
104
+ reader.close
105
+ server = TCPServer.open(9990)
106
+ client = server.accept
107
+ writer.write(client.readpartial(READLEN))
108
+ client.write("HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n")
109
+ client.close
110
+ writer.close
111
+ end
112
+ sleep(1)
113
+ out = reader.readpartial(READLEN)
114
+ passed
115
+ end
116
+
117
+ callback_info = nil
118
+ isValidCallback = false
119
+ validate "Valid callback response" do
120
+ _, json = out.split("\r\n\r\n")
121
+ begin
122
+ callback_info = JSON.parse(json)
123
+ rescue Exception => e
124
+ failed e.message
125
+ end
126
+ isValidCallback = true
127
+ passed
128
+ end
129
+
130
+ if isValidCallback
131
+ validate "All callback config keys are in manifest" do
132
+ callback_info['config'].each do |key, value|
133
+ unless manifest['api']['config_vars'].include? key; failed "#{key} not found in config"; end
134
+ end
135
+ end
136
+
137
+ validate "All callback manifest config keys are in response" do
138
+ manifest['api']['config_vars'].each do |key, value|
139
+ unless callback_info['config'].include? key; failed "#{key} not found in manifest"; end
140
+ end
141
+ end
142
+
143
+ validate "All callback config keys are prefixed with addon name" do
144
+ callback_info['config'].each do |key, value|
145
+ unless key.start_with? config_prefix; failed "#{key} does not begin with #{config_prefix}"; end
146
+ end
147
+ passed
148
+ end
149
+ end
150
+
151
+ validate "SSO link" do
152
+ timestamp = Time.now.to_i
153
+ authstring = resource_id.to_s + ':' + manifest['api']['sso_salt'] + ':' + timestamp.to_s
154
+ token = Digest::SHA1.hexdigest(authstring)
155
+ resp = addon.get(manifest['api']['test'] + "/#{resource_id}?token=#{token}&timestamp=#{timestamp}")
156
+ passed unless resp.code != "200"
157
+ end
158
+
159
+ validate "Deprovision" do
160
+ params = {}
161
+ payload = { 'customer_id' => manifest['id'], 'plan' => manifest['api']['plans'][0]['id'], 'callback_url' => callback_url, 'options' => '{}' }
162
+ resp = addon.delete(manifest['api']['test'] + "/#{resource_id}", params, JSON.generate(payload))
163
+ failed("response code: #{resp.code}") if resp.code != "200"
164
+ passed
165
+ end
166
+
167
+ end
168
+ end
169
+
170
+ else
171
+ false
172
+ end
173
+
174
+ validate "Bad credentials test" do
175
+ params = {}
176
+ payload = { 'customer_id' => manifest['id'], 'plan' => manifest['api']['plans'][0]['id'], 'callback_url' => callback_url, 'options' => '{}' }
177
+
178
+ addon_bad_auth = Rest.new(manifest['api']['test'], bad_user, bad_password)
179
+ resp = addon.post(manifest['api']['test'], params, JSON.generate(payload))
180
+
181
+ failed if resp.code == "200"
182
+ passed
183
+ end
@@ -0,0 +1,16 @@
1
+ {
2
+ "id":"myaddon",
3
+ "api":{
4
+ "plans":[
5
+ {"id":"free"}
6
+ ],
7
+ "config_vars": {
8
+ "MYADDON_URL":"http://some.url.com",
9
+ "MYADDON_VAR1":"cats",
10
+ "MYADDON_VAR2":"dogs"
11
+ },
12
+ "test":"http://localhost:4567/myaddon/resources",
13
+ "password":"cavef6azebRewruvecuch",
14
+ "sso_salt":"8ouy3ayLEyOA7HLAKO2Yo"
15
+ }
16
+ }
@@ -0,0 +1,58 @@
1
+ def colorize(str, beginColor, endColor = 0)
2
+ "\e[#{beginColor}m#{str}\e[#{endColor}m"
3
+ end
4
+
5
+ #30 Black
6
+ def black(str, endColor = 0)
7
+ colorize(str, "30", endColor)
8
+ end
9
+
10
+ #31 Red
11
+ def red(str, endColor = 0)
12
+ colorize(str, "31", endColor)
13
+ end
14
+
15
+ #32 Green
16
+ def green(str, endColor = 0)
17
+ colorize(str, "32", endColor)
18
+ end
19
+
20
+ #32 Bright Green
21
+ def bgreen(str, endColor = 0)
22
+ colorize(str, "1;32", endColor)
23
+ end
24
+
25
+ #33 Yellow
26
+ def yellow(str, endColor = 0)
27
+ colorize(str, "33", endColor)
28
+ end
29
+
30
+ #34 Blue
31
+ def blue(str, endColor = 0)
32
+ colorize(str, "34", endColor)
33
+ end
34
+
35
+ #35 Magenta
36
+ def magenta(str, endColor = 0)
37
+ colorize(str, "35", endColor)
38
+ end
39
+
40
+ #36 Cyan
41
+ def cyan(str, endColor = 0)
42
+ colorize(str, "36", endColor)
43
+ end
44
+
45
+ #36 Bright Cyan
46
+ def bcyan(str, endColor = 0)
47
+ colorize(str, "1;36", endColor)
48
+ end
49
+
50
+ #37 White
51
+ def white(str, endColor = 0)
52
+ colorize(str, "37", endColor)
53
+ end
54
+
55
+ #37 Bright White
56
+ def bwhite(str, endColor = 0)
57
+ colorize(str, "1;37", endColor)
58
+ end
@@ -0,0 +1,106 @@
1
+ require 'net/http'
2
+ require 'net/https'
3
+ require 'uri'
4
+ require 'cgi'
5
+
6
+ class Rest
7
+
8
+ $user = nil
9
+ $password = nil
10
+ $http = nil
11
+ $cookies = {}
12
+ $last_resp = nil
13
+ $last_params = nil
14
+
15
+ $useragent = ''
16
+
17
+ def initialize(url, user = nil, password = nil)
18
+ $user = user
19
+ $password = password
20
+
21
+ uri = URI(url)
22
+ $http = Net::HTTP.new(uri.host, uri.port)
23
+
24
+ if uri.scheme == 'https'
25
+ $http.use_ssl = true
26
+ $http.verify_mode = OpenSSL::SSL::VERIFY_NONE
27
+ else
28
+ $http.use_ssl = false
29
+ end
30
+ end
31
+
32
+ def get(url, params = nil, additional_header = nil)
33
+ header = { 'Cookie' => cookie_to_s, 'User-Agent' => $useragent }
34
+ header = header.merge(additional_header) unless additional_header.nil?
35
+ req = Net::HTTP::Get.new(url, header)
36
+ make_request(req, params)
37
+ end
38
+
39
+ def post(url, params, payload = nil, additional_header = nil)
40
+ header = { 'Cookie' => cookie_to_s, 'User-Agent' => $useragent }
41
+ header = header.merge(additional_header) unless additional_header.nil?
42
+ req = Net::HTTP::Post.new(url, { 'Cookie' => cookie_to_s, 'User-Agent' => $useragent })
43
+ make_request(req, params, payload)
44
+ end
45
+
46
+ def put(url, params, payload = nil)
47
+ req = Net::HTTP::Put.new(url, { 'Cookie' => cookie_to_s, 'User-Agent' => $useragent })
48
+ make_request(req, params, payload)
49
+ end
50
+
51
+ def delete(url, params = nil, payload = nil)
52
+ req = Net::HTTP::Delete.new(url, { 'Cookie' => cookie_to_s, 'User-Agent' => $useragent })
53
+ make_request(req, params, payload)
54
+ end
55
+
56
+ def cookies
57
+ $cookies
58
+ end
59
+ def cookies=(dough)
60
+ $cookies = dough
61
+ end
62
+
63
+ def inspect
64
+ puts "#{bwhite(resp.code)} - #{$last_resp.message}"
65
+ puts $last_params.inspect
66
+ puts "Cookies: " + $cookies.inspect
67
+ puts $last_resp.body
68
+ end
69
+
70
+ private
71
+
72
+ def cookie_to_s
73
+ cookiestr = ''
74
+ $cookies.each do |key, value|
75
+ cookiestr += "#{key}=#{value}, "
76
+ end
77
+ cookiestr[0..-2]
78
+ end
79
+
80
+ def make_request(req, params = nil, payload = nil)
81
+ $last_params = params
82
+ req.basic_auth($user, $password) unless $user.nil?
83
+ req.set_form_data(params, ';') unless params.nil?
84
+
85
+ unless payload.nil?
86
+ req.body = payload
87
+ req.set_content_type('multipart/form-data')
88
+ end
89
+
90
+ begin
91
+ $last_resp = $http.request(req)
92
+
93
+ unless $last_resp['set-cookie'].nil?
94
+ $last_resp['set-cookie'].split(', ').each do |cookie|
95
+ key, value = cookie.split('=')
96
+ $cookies[key] = value
97
+ end
98
+ end
99
+ rescue NoMethodError
100
+ return Net::HTTPInternalServerError.new '1.1', '500', 'Internal server error'
101
+ end
102
+
103
+ $last_resp
104
+ end
105
+
106
+ end
@@ -0,0 +1,22 @@
1
+ class ValidationFailed < StandardError ; end
2
+
3
+ def validate(msg)
4
+ print "#{msg}: "
5
+ begin
6
+ if yield
7
+ puts "[ " + bgreen("Pass") + " ]"
8
+ else
9
+ raise ValidationFailed, ''
10
+ end
11
+ rescue ValidationFailed => fail
12
+ puts "[ " + red("Failed") + " ] " + bwhite(fail.message)
13
+ end
14
+ end
15
+
16
+ def passed(msg = nil)
17
+ true
18
+ end
19
+
20
+ def failed(msg = '')
21
+ raise ValidationFailed, msg
22
+ end
@@ -0,0 +1,5 @@
1
+ module AppFog
2
+ module AddonTester
3
+ VERSION = "0.0.1"
4
+ end
5
+ end
@@ -0,0 +1,4 @@
1
+ require "af-addon-tester/version"
2
+ require "af-addon-tester/colorize"
3
+ require "af-addon-tester/test"
4
+ require "af-addon-tester/rest"
metadata ADDED
@@ -0,0 +1,85 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: af-addon-tester
3
+ version: !ruby/object:Gem::Version
4
+ prerelease: false
5
+ segments:
6
+ - 0
7
+ - 0
8
+ - 1
9
+ version: 0.0.1
10
+ platform: ruby
11
+ authors:
12
+ - Tim Santeford
13
+ autorequire:
14
+ bindir: bin
15
+ cert_chain: []
16
+
17
+ date: 2012-01-12 00:00:00 -08:00
18
+ default_executable: af-addon-tester
19
+ dependencies:
20
+ - !ruby/object:Gem::Dependency
21
+ name: json
22
+ prerelease: false
23
+ requirement: &id001 !ruby/object:Gem::Requirement
24
+ requirements:
25
+ - - ">="
26
+ - !ruby/object:Gem::Version
27
+ segments:
28
+ - 0
29
+ version: "0"
30
+ type: :runtime
31
+ version_requirements: *id001
32
+ description: Allows developers to test App Fog add-ons
33
+ email:
34
+ - tim@phpfog.com
35
+ executables:
36
+ - af-addon-tester
37
+ extensions: []
38
+
39
+ extra_rdoc_files: []
40
+
41
+ files:
42
+ - .gitignore
43
+ - Gemfile
44
+ - README.md
45
+ - Rakefile
46
+ - af-addon-tester.gemspec
47
+ - bin/af-addon-tester
48
+ - config/manifest.example.json
49
+ - lib/af-addon-tester.rb
50
+ - lib/af-addon-tester/colorize.rb
51
+ - lib/af-addon-tester/rest.rb
52
+ - lib/af-addon-tester/test.rb
53
+ - lib/af-addon-tester/version.rb
54
+ has_rdoc: true
55
+ homepage: http://www.appfog.com
56
+ licenses: []
57
+
58
+ post_install_message:
59
+ rdoc_options: []
60
+
61
+ require_paths:
62
+ - lib
63
+ required_ruby_version: !ruby/object:Gem::Requirement
64
+ requirements:
65
+ - - ">="
66
+ - !ruby/object:Gem::Version
67
+ segments:
68
+ - 0
69
+ version: "0"
70
+ required_rubygems_version: !ruby/object:Gem::Requirement
71
+ requirements:
72
+ - - ">="
73
+ - !ruby/object:Gem::Version
74
+ segments:
75
+ - 0
76
+ version: "0"
77
+ requirements: []
78
+
79
+ rubyforge_project: af-addon-tester
80
+ rubygems_version: 1.3.6
81
+ signing_key:
82
+ specification_version: 3
83
+ summary: Tests App Fog Add-ons
84
+ test_files: []
85
+