rest-object 0.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.
- data/lib/rest-object.rb +59 -0
- data/lib/rest-object/gree_err.rb +93 -0
- data/lib/rest-object/gree_json.rb +79 -0
- data/lib/rest-object/gree_logger.rb +101 -0
- data/lib/rest-object/gree_ruby_extensions.rb +73 -0
- metadata +49 -0
data/lib/rest-object.rb
ADDED
@@ -0,0 +1,59 @@
|
|
1
|
+
# Module to be included for REST Object
|
2
|
+
#
|
3
|
+
require_relative 'rest-object/gree_json.rb'
|
4
|
+
|
5
|
+
module RestObject
|
6
|
+
|
7
|
+
# response is a Net:HTTPResponse object returned from REST call
|
8
|
+
attr_reader :response, :code, :body
|
9
|
+
|
10
|
+
def initialize(response)
|
11
|
+
@response = response
|
12
|
+
@code = response.code
|
13
|
+
@body = response.body
|
14
|
+
end
|
15
|
+
|
16
|
+
def is_restful?
|
17
|
+
begin
|
18
|
+
return (JSON.parse(@body).class == Hash)
|
19
|
+
rescue
|
20
|
+
return false
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
# Verify if @code is 200
|
25
|
+
def is_successful?
|
26
|
+
@code == "200"
|
27
|
+
end
|
28
|
+
|
29
|
+
# Verify if @code is 4xx
|
30
|
+
def is_client_error?
|
31
|
+
end
|
32
|
+
|
33
|
+
# Verify if @code is 5xx
|
34
|
+
def is_server_error?
|
35
|
+
end
|
36
|
+
|
37
|
+
# Verify API response body
|
38
|
+
def verify_rest_body(expected, content_type = :json)
|
39
|
+
if content_type == :json
|
40
|
+
GreeJson.check_json_response(expected, @body)
|
41
|
+
else
|
42
|
+
return (@body == expected)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
# Verify API response header
|
47
|
+
def verify_rest_header(expected)
|
48
|
+
end
|
49
|
+
|
50
|
+
end
|
51
|
+
|
52
|
+
|
53
|
+
# Unit test
|
54
|
+
if __FILE__ == $0
|
55
|
+
GreeLog.level = Logger::INFO
|
56
|
+
GreeLog.echo_to_screen = true
|
57
|
+
|
58
|
+
end
|
59
|
+
|
@@ -0,0 +1,93 @@
|
|
1
|
+
# convenience functions for dealing with errors and exceptions
|
2
|
+
|
3
|
+
require 'pp'
|
4
|
+
|
5
|
+
require_relative 'gree_ruby_extensions.rb'
|
6
|
+
require_relative 'gree_logger.rb'
|
7
|
+
|
8
|
+
module GreeErr
|
9
|
+
|
10
|
+
# Construct an error message string saying 2 things are not identical
|
11
|
+
def self.msg_not_identical(value_name, var1, var2)
|
12
|
+
return "#{value_name} is not identical: #1 = #{value_1}, #2 = #{value_2}"
|
13
|
+
end
|
14
|
+
|
15
|
+
# Construct an error message string saying something has an unsupported value
|
16
|
+
def self.msg_unsupported(value_name, value)
|
17
|
+
return "Unsupported #{value_name}: '#{value}'"
|
18
|
+
end
|
19
|
+
|
20
|
+
# Raise a RuntimeError when 2 things are not identical
|
21
|
+
def self.not_identical_raise(value_name, value_1, value_2)
|
22
|
+
raise RuntimeError, self.msg_not_identical(value_name, value_1, value_2), caller
|
23
|
+
end
|
24
|
+
|
25
|
+
def self.raise(*args)
|
26
|
+
_log_message = ""
|
27
|
+
# look for a backtrace to include
|
28
|
+
for _arg in args
|
29
|
+
if _arg.respond_to? :backtrace
|
30
|
+
_log_message << " " << _arg.backtrace.join("\n ")
|
31
|
+
end
|
32
|
+
end
|
33
|
+
# if no backtrace found, add generic
|
34
|
+
if _log_message == ""
|
35
|
+
_log_message << " " << caller.join("\n ")
|
36
|
+
end
|
37
|
+
_log_message = "Exception-> " + args.pretty_inspect + _log_message
|
38
|
+
GreeLog.error(previous_function_name + "()") {
|
39
|
+
_log_message
|
40
|
+
}
|
41
|
+
Kernel.raise *args
|
42
|
+
end
|
43
|
+
|
44
|
+
# Raise an ArgumentError when an argument has unsupported value
|
45
|
+
def self.unsupported_raise(value_name, value)
|
46
|
+
raise ArgumentError, self.msg_unsupported(value_name, value), caller
|
47
|
+
end
|
48
|
+
|
49
|
+
# Execute block, ignoring the specified exception type (default: all exceptions)
|
50
|
+
def self.with_ignored_exceptions(exception_types = StandardError)
|
51
|
+
begin
|
52
|
+
yield
|
53
|
+
rescue exception_types => _the_exception
|
54
|
+
# Ignore the exception
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
end
|
59
|
+
|
60
|
+
# ======================
|
61
|
+
# SELF-TEST
|
62
|
+
# ======================
|
63
|
+
|
64
|
+
if $0 == __FILE__
|
65
|
+
def test
|
66
|
+
GreeLog.handler=Logger.new(
|
67
|
+
File.join(File.expand_path(File.dirname(__FILE__)), 'test-' + Time.now.strftime('%Y-%m-%d-%H%M%S') + '.log')
|
68
|
+
)
|
69
|
+
|
70
|
+
begin
|
71
|
+
GreeErr.raise 'this is an error message'
|
72
|
+
rescue
|
73
|
+
end
|
74
|
+
|
75
|
+
begin
|
76
|
+
GreeErr.raise ArgumentError
|
77
|
+
rescue
|
78
|
+
end
|
79
|
+
|
80
|
+
begin
|
81
|
+
GreeErr.raise ArgumentError, 'this is a message for ArgumentError exception'
|
82
|
+
rescue
|
83
|
+
end
|
84
|
+
|
85
|
+
begin
|
86
|
+
GreeErr.raise
|
87
|
+
rescue
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
test
|
92
|
+
|
93
|
+
end
|
@@ -0,0 +1,79 @@
|
|
1
|
+
# Utilities for JSON handling
|
2
|
+
|
3
|
+
require_relative "gree_logger.rb"
|
4
|
+
require 'json'
|
5
|
+
|
6
|
+
module GreeJson
|
7
|
+
|
8
|
+
# Validate a JSON response, comparing to an expected hash
|
9
|
+
# TODO: add strict parm to check for extra keys
|
10
|
+
def self.check_json_response(expected, response)
|
11
|
+
begin
|
12
|
+
result = JSON.parse(response)
|
13
|
+
_validate_json_or_json_array(expected, result)
|
14
|
+
rescue => ex
|
15
|
+
GreeLog.puts "EXCEPTION: #{ex.message}\n"
|
16
|
+
GreeLog.puts "EXPECTED\n#{expected.inspect}\n"
|
17
|
+
GreeLog.puts "ACTUAL\n#{response}\nEND"
|
18
|
+
# rethrow the message to remove the recursive stack trace
|
19
|
+
raise ex.message
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def self._validate_json_or_json_array(expected, actual)
|
24
|
+
if actual.class == Array
|
25
|
+
_validate_json_array(expected, actual, actual.count)
|
26
|
+
else
|
27
|
+
_validate_json(expected, actual)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def self._validate_json(expected, actual)
|
32
|
+
if actual.nil?
|
33
|
+
raise "missing field(s) in response: expected=#{expected} - actual == nil"
|
34
|
+
end
|
35
|
+
expected.each do |k, v|
|
36
|
+
a = actual[k.to_s]
|
37
|
+
#if a.nil?
|
38
|
+
if !actual.has_key?(k.to_s)
|
39
|
+
raise "missing \"#{k}\" property in JSON response, expected: #{v.inspect}"
|
40
|
+
end
|
41
|
+
case v
|
42
|
+
when Hash
|
43
|
+
if a.class != Hash
|
44
|
+
raise "got #{a.class} instead of JSON object for #{k}"
|
45
|
+
end
|
46
|
+
_validate_json(v, a)
|
47
|
+
when Array
|
48
|
+
if a.class != Array
|
49
|
+
raise "got JSON object instead of array for #{k}"
|
50
|
+
end
|
51
|
+
_validate_json_array(v, a, k.to_s)
|
52
|
+
when Regexp
|
53
|
+
a.should match v
|
54
|
+
else
|
55
|
+
a.should == v unless v == :any
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
def self._validate_json_array(expected, actual, k)
|
61
|
+
if actual.class != Array
|
62
|
+
raise "#{k} in response is not an array as expected"
|
63
|
+
end
|
64
|
+
if expected.count != actual.count
|
65
|
+
raise "Error in #{k} array: expected #{expected.count} items, got #{actual.count}"
|
66
|
+
end
|
67
|
+
expected.each_index do |i|
|
68
|
+
_validate_json(expected[i], actual[i])
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
end
|
73
|
+
|
74
|
+
|
75
|
+
# Unit test
|
76
|
+
if __FILE__ == $0
|
77
|
+
|
78
|
+
end
|
79
|
+
|
@@ -0,0 +1,101 @@
|
|
1
|
+
# Utilities for log handling
|
2
|
+
|
3
|
+
require 'logger'
|
4
|
+
require 'pp'
|
5
|
+
|
6
|
+
class GreeLog
|
7
|
+
|
8
|
+
@@logger=nil
|
9
|
+
@@echo_to_screen = false
|
10
|
+
|
11
|
+
def self.close
|
12
|
+
@@logger.close
|
13
|
+
@@logger = nil
|
14
|
+
end
|
15
|
+
|
16
|
+
def self.echo_to_screen
|
17
|
+
return @@echo_to_screen
|
18
|
+
end
|
19
|
+
|
20
|
+
def self.echo_to_screen=(value)
|
21
|
+
@@echo_to_screen=value
|
22
|
+
end
|
23
|
+
|
24
|
+
def self.logger
|
25
|
+
return @@logger
|
26
|
+
end
|
27
|
+
|
28
|
+
def self.logger=(logger_object)
|
29
|
+
@@logger=logger_object
|
30
|
+
end
|
31
|
+
|
32
|
+
def self.logging?
|
33
|
+
return !@@logger.nil?
|
34
|
+
end
|
35
|
+
|
36
|
+
def self.method_missing(method_name, *method_args, &block)
|
37
|
+
if @@echo_to_screen
|
38
|
+
puts "[#{Time.now.strftime('%H:%M:%S')}] #{method_name.to_s.upcase} -- #{previous_function_name}: #{method_args.inspect} #{(block ? '{' + block.to_s + '}' : '')}"
|
39
|
+
end
|
40
|
+
if @@logger
|
41
|
+
@@logger.progname = previous_function_name
|
42
|
+
@@logger.send(method_name, *method_args, &block)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
# print out a message without escaping the the quotes, newlines ...
|
47
|
+
def self.puts(message)
|
48
|
+
if @@echo_to_screen
|
49
|
+
Kernel.puts "#{message}"
|
50
|
+
end
|
51
|
+
if @@logger
|
52
|
+
@@logger.progname = previous_function_name
|
53
|
+
@@logger.send("info", message)
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
# Returns the name of the function from which this method was called, by looking at the call stack. If call stack
|
58
|
+
# is empty, returns "(anonymous)"
|
59
|
+
#
|
60
|
+
# def foo
|
61
|
+
# puts current_function_name
|
62
|
+
# end
|
63
|
+
#
|
64
|
+
# foo -> "foo"
|
65
|
+
#
|
66
|
+
# current_function_name -> "(anonymous)"
|
67
|
+
#
|
68
|
+
# Used for logging and error reporting, so that generic code can record the name of the currently running function.
|
69
|
+
|
70
|
+
def self.current_function_name
|
71
|
+
return caller()[0] =~ /in `([^']+)'/ ? $1 : '(anonymous)'
|
72
|
+
end
|
73
|
+
|
74
|
+
# Returns the name of the function two levels down in the call stack. If call stack
|
75
|
+
# has insufficient depth, returns "(anonymous)"
|
76
|
+
#
|
77
|
+
# def foo
|
78
|
+
# puts previous_function_name
|
79
|
+
# end
|
80
|
+
#
|
81
|
+
# def bar
|
82
|
+
# foo
|
83
|
+
# end
|
84
|
+
#
|
85
|
+
# bar -> "bar"
|
86
|
+
#
|
87
|
+
# foo -> "(anonymous)"
|
88
|
+
#
|
89
|
+
# previous_function_name => "(anonymous)"
|
90
|
+
#
|
91
|
+
# Used for setting up a centralized error handler that calls a centralized logger.
|
92
|
+
|
93
|
+
def self.previous_function_name
|
94
|
+
if caller().length < 2
|
95
|
+
return '(anonymous)'
|
96
|
+
else
|
97
|
+
return caller()[1] =~ /in `([^']+)'/ ? $1 : '(anonymous)'
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
end
|
@@ -0,0 +1,73 @@
|
|
1
|
+
# Gree Ruby Extensions
|
2
|
+
# This file provides various convenient extensions to Ruby's built-in objects and libraries
|
3
|
+
|
4
|
+
unless defined? "INFINITY"
|
5
|
+
INFINITY = 1.0/0
|
6
|
+
end
|
7
|
+
|
8
|
+
unless defined? "NaN"
|
9
|
+
NaN = 0.0/0
|
10
|
+
end
|
11
|
+
|
12
|
+
class Array
|
13
|
+
# Same as <tt>Array.detect</tt>, but scans from end of array to beginning.
|
14
|
+
def reverse_detect(&block)
|
15
|
+
self.reverse_each {|_element|
|
16
|
+
if block.call(_element)
|
17
|
+
return _element
|
18
|
+
end
|
19
|
+
}
|
20
|
+
return nil
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
class Hash
|
25
|
+
def hash_value_missing?(key)
|
26
|
+
# test if key is missing, or key value is nil or empty string
|
27
|
+
return !self.has_key?(key) || self[key]=="" || self[key].nil?
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
# Returns the name of the function from which this method was called, by looking at the call stack. If call stack
|
32
|
+
# is empty, returns "(anonymous)"
|
33
|
+
#
|
34
|
+
# def foo
|
35
|
+
# puts current_function_name
|
36
|
+
# end
|
37
|
+
#
|
38
|
+
# foo -> "foo"
|
39
|
+
#
|
40
|
+
# current_function_name -> "(anonymous)"
|
41
|
+
#
|
42
|
+
# Used for logging and error reporting, so that generic code can record the name of the currently running function.
|
43
|
+
|
44
|
+
def current_function_name
|
45
|
+
return caller()[0] =~ /in `([^']+)'/ ? $1 : '(anonymous)'
|
46
|
+
end
|
47
|
+
|
48
|
+
# Returns the name of the function two levels down in the call stack. If call stack
|
49
|
+
# has insufficient depth, returns "(anonymous)"
|
50
|
+
#
|
51
|
+
# def foo
|
52
|
+
# puts previous_function_name
|
53
|
+
# end
|
54
|
+
#
|
55
|
+
# def bar
|
56
|
+
# foo
|
57
|
+
# end
|
58
|
+
#
|
59
|
+
# bar -> "bar"
|
60
|
+
#
|
61
|
+
# foo -> "(anonymous)"
|
62
|
+
#
|
63
|
+
# previous_function_name => "(anonymous)"
|
64
|
+
#
|
65
|
+
# Used for setting up a centralized error handler that calls a centralized logger.
|
66
|
+
|
67
|
+
def previous_function_name
|
68
|
+
if caller().length < 2
|
69
|
+
return '(anonymous)'
|
70
|
+
else
|
71
|
+
return caller()[1] =~ /in `([^']+)'/ ? $1 : '(anonymous)'
|
72
|
+
end
|
73
|
+
end
|
metadata
ADDED
@@ -0,0 +1,49 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: rest-object
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Chaoyi Chen
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2012-11-27 00:00:00.000000000 Z
|
13
|
+
dependencies: []
|
14
|
+
description: REST API Object DSL for RESTful API testing
|
15
|
+
email: chaoyi.chen@gree.net
|
16
|
+
executables: []
|
17
|
+
extensions: []
|
18
|
+
extra_rdoc_files: []
|
19
|
+
files:
|
20
|
+
- lib/rest-object.rb
|
21
|
+
- lib/rest-object/gree_logger.rb
|
22
|
+
- lib/rest-object/gree_ruby_extensions.rb
|
23
|
+
- lib/rest-object/gree_json.rb
|
24
|
+
- lib/rest-object/gree_err.rb
|
25
|
+
homepage: http://rubygems.org/gems/hola
|
26
|
+
licenses: []
|
27
|
+
post_install_message:
|
28
|
+
rdoc_options: []
|
29
|
+
require_paths:
|
30
|
+
- lib
|
31
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
32
|
+
none: false
|
33
|
+
requirements:
|
34
|
+
- - ! '>='
|
35
|
+
- !ruby/object:Gem::Version
|
36
|
+
version: '0'
|
37
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
38
|
+
none: false
|
39
|
+
requirements:
|
40
|
+
- - ! '>='
|
41
|
+
- !ruby/object:Gem::Version
|
42
|
+
version: '0'
|
43
|
+
requirements: []
|
44
|
+
rubyforge_project:
|
45
|
+
rubygems_version: 1.8.24
|
46
|
+
signing_key:
|
47
|
+
specification_version: 3
|
48
|
+
summary: REST API Object DSL for RESTful API testing
|
49
|
+
test_files: []
|