webtester 0.0.9 → 0.1.2

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 3f25b4868627a111dfabc038fc4345b82a1c0178
4
- data.tar.gz: 8c98b4a7445d6aa87fd5f92c6197f83dd9543455
3
+ metadata.gz: 32953f9df768bc4a9e53c4c1b636668bd23ff6e4
4
+ data.tar.gz: a823800207767458c00ca5f8a057d80f262bee79
5
5
  SHA512:
6
- metadata.gz: 196f34578cce04f016ced4d755d0087ce60dc751f5f522ddf5ea9c22d0368291715f17b03bb8b10adf3c6245bfdfc847afecb9eeeb802a2967b82ef068b73bbf
7
- data.tar.gz: b0ac7afe1c201a3973978e0d1eb14077a0c4dbba507bed90e0f633280b54c4ab81202dbadf89c1e332a282e28ec8302b032f4ee429d1a51431de3b22e5ba36c0
6
+ metadata.gz: bd7aad2b034dbce9def4f6d9776f962cf124fb529892abe3c9eae54585dd20904cc683058ea8d6386beb0b65ead9feec24d1a3455911837b316e97399531c08e
7
+ data.tar.gz: 45877c9df6c170ceea1585889d86e6dcf1697dfaf0eaefe7d2ca96035b531bdf7ee0acf876804e3a177da95e2819fe14e6e9f0df5188e0fb84f0dbeb186abfc9
data/lib/assertion.rb ADDED
@@ -0,0 +1,235 @@
1
+ module WT
2
+ class Assertion
3
+
4
+ attr_accessor :expected_codes
5
+ attr_accessor :unexpected_codes
6
+ attr_accessor :expected_headers
7
+ attr_accessor :unexpected_headers
8
+ attr_accessor :expected_body
9
+ attr_accessor :unexpected_body
10
+ attr_accessor :expected_body_parts
11
+ attr_accessor :unexpected_body_parts
12
+
13
+ def initialize(expected_codes: '200',
14
+ unexpected_codes: [],
15
+ expected_headers: [],
16
+ unexpected_headers: [],
17
+ expected_body: nil,
18
+ unexpected_body: nil,
19
+ expected_body_parts: nil,
20
+ unexpected_body_parts: nil)
21
+ @expected_codes = expected_codes
22
+ @unexpected_codes = unexpected_codes
23
+ @expected_headers = expected_headers
24
+ @unexpected_headers = unexpected_headers
25
+ @expected_body = expected_body
26
+ @unexpected_body = unexpected_body
27
+ @expected_body_parts = expected_body_parts
28
+ @unexpected_body_parts = unexpected_body_parts
29
+ end
30
+
31
+ def assert(response)
32
+ raise ResponseNotFoundException.new() unless response
33
+ test_code(response)
34
+ test_headers(response)
35
+ test_body(response)
36
+ test_body_part(response)
37
+ end
38
+
39
+ def code_is_equal(code)
40
+
41
+ if code.kind_of?(Array)
42
+ @expected_codes = @expected_codes | code
43
+ else
44
+ @expected_codes << code
45
+ end
46
+
47
+ return self
48
+ end
49
+
50
+ def code_is_not_equal(code)
51
+ if code.kind_of?(Array)
52
+ @unexpected_codes = @unexpected_codes | code
53
+ else
54
+ @unexpected_codes << code
55
+ end
56
+
57
+ return self
58
+ end
59
+
60
+ def contain_headers(headers)
61
+ if headers.kind_of?(Array)
62
+ @expected_headers = @expected_headers | headers
63
+ else
64
+ @expected_headers << headers
65
+ end
66
+
67
+ return self
68
+ end
69
+
70
+ def not_contain_headers(headers)
71
+ if headers.kind_of?(Array)
72
+ @unexpected_headers = @unexpected_headers | headers
73
+ else
74
+ @unexpected_headers << headers
75
+ end
76
+
77
+ return self
78
+ end
79
+
80
+ def body_is_equal(body)
81
+ @expected_body = body
82
+
83
+ return self
84
+ end
85
+
86
+ def body_is_not_equal(body)
87
+ @unexpected_body = body
88
+
89
+ return self
90
+ end
91
+
92
+ def contain_body_part(body_parts)
93
+ if body_part.kind_of?(Array)
94
+ @expected_body_parts = @expected_body_parts | body_parts
95
+ else
96
+ @expected_body_parts << body_parts
97
+ end
98
+
99
+ return self
100
+ end
101
+
102
+ def not_contain_body_part(body_parts)
103
+ if body_parts.kind_of?(Array)
104
+ @unexpected_body_parts = @unexpected_body_parts | body_parts
105
+ else
106
+ @unexpected_body_parts << body_parts
107
+ end
108
+
109
+ return self
110
+ end
111
+
112
+ private
113
+
114
+ def test_code(response)
115
+ raise ExpectedCodeNotFoundException.new(response.code) unless @expected_codes.include?(response.code) or @expected_headers.length == 0
116
+ raise UnexpectedCodeFoundException.new(response.code) if @unexpected_codes.include?(response.code)
117
+ end
118
+
119
+ def test_headers(response)
120
+
121
+ @expected_headers.each do |header|
122
+ h_name = (header[:name]) ? header[:name].downcase : ''
123
+ h_value = (header[:value]) ? header[:value].downcase : ''
124
+
125
+ raise ExpectedHeadersNotFoundException.new(header) unless (response[h_name] and response[h_name] == h_value)
126
+ end
127
+
128
+ @unexpected_headers.each do |header|
129
+ h_name = (header[:name]) ? header[:name].downcase : ''
130
+ h_value = (header[:value]) ? header[:value].downcase : ''
131
+
132
+ raise UnexpectedHeadersFoundException.new(header) if (response[h_name] and response[h_name] == h_value)
133
+ end
134
+ end
135
+
136
+ def test_body(response)
137
+ raise ExpectedBodyNotFoundException.new(response.body) unless response.body == @expected_body or not @expected_body
138
+ raise UnexpectedBodyFoundException.new(response.body) if response.body == @unexpected_body
139
+ end
140
+
141
+ def test_body_part(response)
142
+
143
+ if @expected_body_parts
144
+ @expected_body_parts.each do |part|
145
+ raise ExpectedCodeNotFoundException.new(part) unless response.body.include?(part)
146
+ end
147
+ end
148
+
149
+ if @unexpected_body_parts
150
+ @unexpected_body_parts.each do |part|
151
+ raise UnexpectedBodyPartFoundException.new(part) if response.body.include?(part)
152
+ end
153
+ end
154
+ end
155
+ end
156
+
157
+ class ResponseNotFoundException < Exception
158
+ def initialize
159
+ super("Response not found. Probably there is some connection issue.")
160
+ end
161
+ end
162
+
163
+ class ExpectedCodeNotFoundException < Exception
164
+
165
+ attr_reader :code
166
+
167
+ def initialize(code)
168
+ super("Expected code not found in response.")
169
+ @code = code
170
+ end
171
+ end
172
+
173
+ class UnexpectedCodeFoundException < Exception
174
+ attr_reader :code
175
+
176
+ def initialize(code)
177
+ super("Unexpected response code where found in response.")
178
+ @code = code
179
+ end
180
+ end
181
+
182
+ class ExpectedHeadersNotFoundException < Exception
183
+ attr_reader :header
184
+
185
+ def initialize(header)
186
+ super("Expected header(s) where not found in response.")
187
+ @header = header
188
+ end
189
+ end
190
+
191
+ class UnexpectedHeadersException < Exception
192
+ attr_reader :header
193
+
194
+ def initialize(header)
195
+ super("Unexpected header was found in response.")
196
+ @header = header
197
+ end
198
+ end
199
+
200
+ class ExpectedBodyNotFoundException < Exception
201
+ attr_reader :body
202
+
203
+ def initialize(body)
204
+ super("Expected body was not found in response.")
205
+ @body = body
206
+ end
207
+ end
208
+
209
+ class UnexpectedBodyException < Exception
210
+ attr_reader :body
211
+
212
+ def initialize(body)
213
+ super("Unexpected body was found.")
214
+ @body = body
215
+ end
216
+ end
217
+
218
+ class ExpectedBodyPartNotFoundException < Exception
219
+ attr_reader :body_part
220
+
221
+ def initialize(body_part)
222
+ super("Expected body part was not found in response.")
223
+ @body_part = body_part
224
+ end
225
+ end
226
+
227
+ class UnexpectedBodyPartException < Exception
228
+ attr_reader :body_part
229
+
230
+ def initialize(body_part)
231
+ super("Unexpected body part was found.")
232
+ @body_part = body_part
233
+ end
234
+ end
235
+ end
data/lib/colorize.rb ADDED
@@ -0,0 +1,30 @@
1
+ class String
2
+ # colorization
3
+ def colorize(color_code)
4
+ "\e[#{color_code}m#{self}\e[0m"
5
+ end
6
+
7
+ def red
8
+ colorize(31)
9
+ end
10
+
11
+ def green
12
+ colorize(32)
13
+ end
14
+
15
+ def yellow
16
+ colorize(33)
17
+ end
18
+
19
+ def pink
20
+ colorize(35)
21
+ end
22
+
23
+ def blue
24
+ colorize(36)
25
+ end
26
+
27
+ def white
28
+ colorize(37)
29
+ end
30
+ end
data/lib/log.rb ADDED
@@ -0,0 +1,80 @@
1
+ require 'colorize'
2
+
3
+ module WT
4
+ class Log
5
+
6
+ LOG_ERROR = 0
7
+ LOG_WARN = 1
8
+ LOG_INFO = 2
9
+ LOG_DEBUG = 3
10
+
11
+ @@enabled = false
12
+ @@output = nil
13
+ @@level = LOG_ERROR
14
+
15
+ def self.initialize
16
+ unless @@initialized
17
+ STDOUT.reopen(File.open(WT.log_output, 'a')) if @@output
18
+ @@initialized = true
19
+ end
20
+ end
21
+
22
+ def self.debug(text, *args)
23
+ self.log(LOG_DEBUG, text, *args)
24
+ end
25
+
26
+ def self.info(text, *args)
27
+ self.log(LOG_INFO, text, *args)
28
+ end
29
+
30
+ def self.warn(text, *args)
31
+ self.log(LOG_WARN, text, *args)
32
+ end
33
+
34
+ def self.error(text, *args)
35
+ self.log(LOG_ERROR, text, *args)
36
+ end
37
+
38
+ def self.enable=(value)
39
+ @@enabled = value
40
+ end
41
+
42
+ def self.enabled
43
+ @@enabled
44
+ end
45
+
46
+ def self.level=(lvl)
47
+ @@level = lvl
48
+ end
49
+
50
+ def self.level
51
+ @@level
52
+ end
53
+
54
+ def self.output=(output)
55
+ @@output = output
56
+ end
57
+
58
+ def self.output
59
+ @@output
60
+ end
61
+
62
+ private
63
+
64
+ @@initialized = false
65
+
66
+ def self.log(lvl, text, *args)
67
+ initialize
68
+
69
+ colors = {
70
+ LOG_DEBUG => 36,
71
+ LOG_INFO => 37,
72
+ LOG_WARN => 33,
73
+ LOG_ERROR => 31
74
+ }
75
+
76
+ puts sprintf(text.colorize(colors[lvl]), *args) if @@enabled and @@level >= lvl
77
+ end
78
+ end
79
+
80
+ end
data/lib/request.rb CHANGED
@@ -1,4 +1,5 @@
1
1
  require 'net/http'
2
+ require 'resolv'
2
3
  require 'uri'
3
4
 
4
5
  require 'result'
@@ -10,27 +11,34 @@ module WT
10
11
  attr_accessor :request_type
11
12
  attr_accessor :request_url
12
13
  attr_accessor :request_data
13
- attr_accessor :follow_redirect
14
14
  attr_accessor :headers
15
15
  attr_accessor :proxy_host
16
16
  attr_accessor :proxy_port
17
17
 
18
- def initialize(request_type, request_url, request_data = {}, follow_redirect = true)
18
+ def initialize(request_type, request_url, request_data = {})
19
19
  @request_type = request_type
20
20
  @request_url = request_url
21
21
  @request_data = request_data
22
- @follow_redirect = follow_redirect
23
22
  @headers = {}
24
23
  @proxy_host = nil
25
24
  @proxy_port = 0
26
25
  end
27
26
 
28
27
  def exec
28
+
29
+ WT::Log.debug(">> WT::Request::Exec (#{@request_type}, #{@request_url})")
30
+
31
+ result = nil
32
+
29
33
  if @request_type == "GET"
30
- self.get
34
+ result = self.get
31
35
  elsif @request_type == "POST"
32
- self.post
36
+ result = self.post
33
37
  end
38
+
39
+ WT::Log.debug("<< WT::Request::Exec")
40
+
41
+ return result
34
42
  end
35
43
 
36
44
  def get
@@ -51,6 +59,24 @@ module WT
51
59
 
52
60
  def send(host, port, req)
53
61
 
62
+ WT::Log.debug(">> WT::Request::send(host: #{host}, port: #{port})")
63
+
64
+ host_ip = host;
65
+
66
+ unless host.match(/([0-9]{1,3}){4}/)
67
+ WT::Log.debug("\t* resolving #{host}...")
68
+
69
+ begin
70
+ host_ip = Resolv::DNS.new().getaddress(host).to_s
71
+ rescue Resolv::ResolvError => re
72
+ raise DNSResolvErrorException.new(host)
73
+ end
74
+
75
+ WT::Log.debug("\t\t* success: #{host_ip}")
76
+ else
77
+ WT::Log.debug("\t * no need to resolv. Already in IP format.")
78
+ end
79
+
54
80
  ret = nil
55
81
 
56
82
  begin
@@ -60,30 +86,56 @@ module WT
60
86
  http = nil
61
87
 
62
88
  if @proxy_host
63
- http = Net::HTTP::Proxy(@proxy_host, @proxy_port).new(host, port)
89
+ WT::Log.debug("\t* @proxy_host = #{@proxy_host}")
90
+ http = Net::HTTP::Proxy(@proxy_host, @proxy_port).new(host_ip, port)
64
91
  else
65
- http = Net::HTTP.new(host, port)
92
+ WT::Log.debug("\t* Net::HTTP.new(#{host_ip}, #{port})")
93
+ http = Net::HTTP.new(host_ip, port)
66
94
  end
67
95
 
96
+ WT::Log.debug("\t* http.request(request)")
68
97
  response = http.request(req)
69
98
 
70
- raise "Could not connect to host: #{host}:#{port}" unless response
99
+ raise "Could not connect to host: #{host_ip}:#{port}" unless response
71
100
 
72
- result = WT::Result.new(self, response)
101
+ ret = WT::Result.new(self, response)
73
102
 
74
- if @follow_redirect and (response.code == '301' or response.code == '302')
75
- @request_data = {}
76
- @request_url = response['Location']
77
- ret = self.get
78
- else
79
- ret = result
80
- end
103
+ WT::Log.debug("\t* WT::Result.new(self, response): #{response.code}")
81
104
  rescue Exception => e
105
+ WT::Log.error("\t* Exception: #{e.message}")
82
106
  ret = WT::Result.new self, nil
83
107
  end
84
108
 
109
+ WT::Log.debug("<< WT::Request::send -> #{ret.response.code}")
110
+
85
111
  return ret
86
112
  end
113
+
114
+ def to_s
115
+ "#{self.request_type} #{self.request_url} HTTP/1.1"
116
+ end
117
+ end
118
+
119
+ class NetworkIssueException < Exception
120
+
121
+ attr_reader :host
122
+ attr_reader :port
123
+
124
+
125
+ def initialize(message, host, port = 0)
126
+ super(message)
127
+ end
87
128
  end
88
129
 
130
+ class ConnectionFailedException < NetworkIssueException
131
+ def initialize(host, port = 80)
132
+ super("Could not connect to host: #{host}", host, port)
133
+ end
134
+ end
135
+
136
+ class DNSResolvErrorException < NetworkIssueException
137
+ def initialize(host, port = 53)
138
+ super("Could not resolv name: #{host}", host, port)
139
+ end
140
+ end
89
141
  end
data/lib/test.rb CHANGED
@@ -1,30 +1,55 @@
1
1
  require 'request'
2
2
  require 'cookie'
3
3
  require 'web_session'
4
+ require 'assertion'
4
5
 
5
6
  module WT
6
7
  class Test
7
8
  attr_accessor :name
8
- attr_accessor :requests
9
+ attr_accessor :steps
9
10
 
10
- def initialize(name: 'New Test', requests: [])
11
+ def initialize(name: 'New Test', steps: [])
11
12
  @name = name
12
- @requests = requests
13
+ @steps = steps
13
14
  end
14
15
 
15
- def add_request(request)
16
- @requests << request
16
+ def add_step(request, assertions = [])
17
+
18
+ asserts = assertions
19
+ asserts << WT::Assertion.new().code_is_equal('200') unless asserts.length > 0
20
+
21
+ step = {
22
+ :request => request,
23
+ :assertions => assertions
24
+ }
25
+
26
+ @steps << step
17
27
  end
18
28
 
19
- def exec
29
+ def exec(&block)
30
+ WT::Log.debug(">>> WT::Test::Exec")
31
+
20
32
  session = WT::WebSession.new
21
33
 
22
- @requests.each do |req|
23
- result = session.request(req)
34
+ @steps.each do |step|
35
+ WT::Log.debug("\t * session.request()")
36
+
37
+ error = nil
38
+
39
+ begin
40
+ result = session.request(step[:request], false)
41
+
42
+ step[:assertions].each do |assertion|
43
+ WT::Log.debug("\t * assertion.assert(#{result.response.code})")
44
+ assertion.assert(result.response)
45
+ end
46
+ rescue Exception => ex
47
+ error = ex
48
+ end
24
49
 
25
- yield result;
50
+ block.call(step[:request], result, error)
26
51
 
27
- break unless ['200', '301', '302'].include?(result.response.code)
52
+ break if error
28
53
  end
29
54
  end
30
55
  end
data/lib/web_session.rb CHANGED
@@ -1,5 +1,7 @@
1
1
  require 'request'
2
+ require 'result'
2
3
  require 'cookie'
4
+ require 'log'
3
5
 
4
6
  module WT
5
7
  class WebSession
@@ -17,7 +19,9 @@ module WT
17
19
  block.call(self) if block
18
20
  end
19
21
 
20
- def request(req, &block)
22
+ def request(req, follow_redirect = false, &block)
23
+ WT::Log.debug(">> WT::WebSession::request()")
24
+
21
25
  req.headers['Cookie'] = WT::Cookie.explode(@cookies) if @cookies.length > 0
22
26
 
23
27
  @form_fields.each do |name, value|
@@ -30,18 +34,32 @@ module WT
30
34
 
31
35
  result = req.exec
32
36
 
37
+ WT::Log.debug("\t * result => #{result}")
38
+
33
39
  if result.response != nil
34
40
  all_cookies = result.response['Set-Cookie']
35
41
 
36
42
  if all_cookies
43
+ @cookies = [];
44
+
37
45
  all_cookies.split(',').each do |str_cookie|
38
46
  @cookies << WT::Cookie.parse(str_cookie.strip)
39
47
  end
40
48
  end
41
49
 
42
- @form_fields = find_form_fields(result.response.body)
50
+ if follow_redirect && ['301', '302'].include?(result.response.code)
51
+ req.request_type = "GET"
52
+ req.request_url = result.response['Location']
53
+ req.request_data = {}
54
+
55
+ result = self.request(req, follow_redirect, &block)
56
+ else
57
+ @form_fields = find_form_fields(result.response.body)
58
+ end
43
59
  end
44
60
 
61
+ WT::Log.debug("<< WT::WebSession::request()")
62
+
45
63
  block.call(result) if block
46
64
 
47
65
  return result
@@ -50,6 +68,7 @@ module WT
50
68
  private
51
69
 
52
70
  def find_form_fields(content)
71
+ WT::Log.debug(">> WT::WebSession::find_form_fields()")
53
72
 
54
73
  form_fields = {}
55
74
 
@@ -75,10 +94,14 @@ module WT
75
94
  str = str[eidx, str.length]
76
95
  end
77
96
 
97
+ WT::Log.debug("<< WT::WebSession::find_form_fields()")
98
+
78
99
  return form_fields
79
100
  end
80
101
 
81
102
  def extract_form_field_attrs(str)
103
+ WT::Log.debug(">> WT::WebSession::extract_form_field_attrs()")
104
+
82
105
  attrs = {}
83
106
  regexp=/<input\s+.*(name|value)="([^"]*)".*\s+(name|value)="([^"]*)"\s*.*\/>/
84
107
 
@@ -87,6 +110,8 @@ module WT
87
110
  attrs["#{$3}"] = "#{$4}"
88
111
  end
89
112
 
113
+ WT::Log.debug("<< WT::WebSession::extract_form_field_attrs()")
114
+
90
115
  return attrs
91
116
  end
92
117
  end
data/lib/webtester.rb CHANGED
@@ -3,3 +3,6 @@ require 'web_session'
3
3
  require 'request'
4
4
  require 'result'
5
5
  require 'cookie'
6
+
7
+ module WT
8
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: webtester
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.9
4
+ version: 0.1.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Diego F. Nascimento
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-05-07 00:00:00.000000000 Z
11
+ date: 2015-05-20 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description: " A simple API to create HTTP Request tests. "
14
14
  email: diego.fnascimento@gmail.com
@@ -16,7 +16,10 @@ executables: []
16
16
  extensions: []
17
17
  extra_rdoc_files: []
18
18
  files:
19
+ - lib/assertion.rb
20
+ - lib/colorize.rb
19
21
  - lib/cookie.rb
22
+ - lib/log.rb
20
23
  - lib/request.rb
21
24
  - lib/result.rb
22
25
  - lib/test.rb