itg_test 0.0.0

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
+ # Ignore bundler config
2
+ /.bundle
3
+
4
+ # Mac's file index cache
5
+ .DS_Store
data/README.md ADDED
@@ -0,0 +1,69 @@
1
+ # itg_test - simple integration test framework
2
+ ## Description
3
+ For Rails apps that are too complicated to be tested with the
4
+ builtin integration test, such as apps that spawn threads
5
+ that update the same database table.
6
+ itg_test overcomes this obstacle by simply starting a server
7
+ and a client in separate processes.
8
+
9
+ ## Installation
10
+ `gem install itg_test`
11
+
12
+ ## Usage
13
+ * Create a `itg` folder under Rail's default test folder by running
14
+ `mkdir test/itg`.
15
+ Now your `test` directory structure should look something like
16
+
17
+ `$ls test`
18
+
19
+ `fixtures functional integration itg test_helper.rb unit`
20
+
21
+ * Write integration tests as you would with Rail's default
22
+ integration test framework. Remember to place them under
23
+ the `itg` folder instead of Rail's default `integration` folder.
24
+ For example, create `test/itg/your_app_test.rb` with the following contents
25
+ ```
26
+ require 'itg_test'
27
+
28
+ class YourAppTest < ItgTest::TestCase
29
+ test 'a complete test' do
30
+ get '/peanuts'
31
+ assert_select 'h3 p:nth-child(3)', 'very yummy'
32
+ ...
33
+ end
34
+ end
35
+ ```
36
+ * Run your itg_test tests with `rake test:itg`
37
+ * itg_test supports the common Rails integration test helpers,
38
+ including `assert_equal`, `assert_difference` and `assert_select` etc.
39
+ * You might find the following script that runs all
40
+ Rails and itg_test tests in one shot handy
41
+ ```
42
+ desc "all tests"
43
+ task 'test:all' => :environment do
44
+ Rake::Task['test'].invoke
45
+ Rake::Task['test:itg'].invoke
46
+ end
47
+ ```
48
+
49
+ ## CONTRIBUTORS:
50
+
51
+ * awaw fumin (@awawfumin)
52
+
53
+ ## LICENSE:
54
+
55
+ Apache License 2.0
56
+
57
+ Copyright (c) 2011-2012, Cardinal Blue
58
+
59
+ Licensed under the Apache License, Version 2.0 (the "License");
60
+ you may not use this file except in compliance with the License.
61
+ You may obtain a copy of the License at
62
+
63
+ <http://www.apache.org/licenses/LICENSE-2.0>
64
+
65
+ Unless required by applicable law or agreed to in writing, software
66
+ distributed under the License is distributed on an "AS IS" BASIS,
67
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
68
+ See the License for the specific language governing permissions and
69
+ limitations under the License.
data/itg_test.gemspec ADDED
@@ -0,0 +1,21 @@
1
+ Gem::Specification.new do |s|
2
+ s.name = 'itg_test'
3
+ s.version = '0.0.0'
4
+ s.date = '2012-08-29'
5
+ s.summary = "rails integration test"
6
+ s.description = "for rails apps that are too complicated to be tested with builtin integration test"
7
+ s.authors = ["awawfumin"]
8
+ s.email = 'fumin@cardinalblue.com'
9
+ s.files = [
10
+ ".gitignore",
11
+ "lib/itg_test.rb",
12
+ "lib/itg_test/http_client.rb",
13
+ "lib/itg_test/railtie.rb",
14
+ "lib/itg_test/test_case.rb",
15
+ "lib/tasks/test_itg.rake",
16
+ "itg_test.gemspec",
17
+ "README.md"
18
+ ]
19
+ s.homepage = 'http://cardinalblue.com'
20
+ s.add_runtime_dependency "nokogiri", [">= 0"]
21
+ end
@@ -0,0 +1,82 @@
1
+ require 'net/http'
2
+
3
+ # Synopsis
4
+ # c = ItgTest::HTTPClient.new 'http://localhost:3000'
5
+ # c.get '/scheduled_posts/post_due' => <head></head><body>...</body>
6
+
7
+ module ItgTest; end
8
+ class ItgTest::HTTPClient
9
+ attr_accessor :cookie
10
+ def initialize url
11
+ new_url = if %r|^http://.+$| =~ url || %r|^https://.+$| =~ url
12
+ url
13
+ else
14
+ "http://" + url
15
+ end
16
+ @cookie = ""
17
+ @uri = URI(new_url)
18
+ end
19
+
20
+ def session
21
+ Net::HTTP.start(@uri.host, @uri.port, use_ssl: @uri.scheme == 'https')
22
+ rescue Errno::ECONNREFUSED => e
23
+ sleep(1); retry
24
+ end
25
+
26
+ def get path, query=''
27
+ path = path[0...-1] if path[-1] == "/"
28
+ path = "/#{path}" unless path[0] == "/"
29
+ if query == ''
30
+ _get path
31
+ else
32
+ _get "#{path}?#{to_query(query)}"
33
+ end
34
+ end
35
+
36
+ def _get path, limit = 10
37
+ raise ArgumentError, 'too many HTTP redirects' if limit == 0
38
+ res = session.get(path, {'Cookie'=>@cookie})
39
+ cookie_array = res.get_fields('set-cookie')
40
+ @cookie = cookie_array.collect{|ea| ea[/^.*?;/]}.join if cookie_array
41
+ final_res = handle_res res, limit
42
+ JSON.parse final_res
43
+ rescue JSON::ParserError
44
+ final_res
45
+ end
46
+
47
+ def post path, params
48
+ res = session.post path, to_query(params), {'Cookie'=>@cookie}
49
+ handle_res res
50
+ end
51
+
52
+ def to_query params, namespace=nil
53
+ if params.is_a?(Hash)
54
+ params.collect do |key, value|
55
+ to_query(value, namespace ? "#{namespace}[#{key}]" : key)
56
+ end.sort * '&'
57
+ elsif params.is_a?(Array)
58
+ prefix = "#{namespace}[]"
59
+ params.collect { |value| to_query(value, prefix) }.join '&'
60
+ else
61
+ "#{CGI.escape(namespace.to_s)}=#{CGI.escape(params.to_s)}"
62
+ end
63
+ end
64
+
65
+ def handle_res res, limit=10
66
+ case res
67
+ when Net::HTTPRedirection
68
+ location = res['location']
69
+ warn "redirected to #{location}"
70
+ if %r|^http://.+$| =~ location || %r|^https://.+$| =~ location
71
+ @uri = URI(location)
72
+ _get(@uri.path, limit - 1)
73
+ else
74
+ _get(location, limit - 1)
75
+ end
76
+ when Net::HTTPSuccess
77
+ res.body
78
+ else
79
+ res.value
80
+ end
81
+ end
82
+ end
@@ -0,0 +1,11 @@
1
+ require 'itg_test'
2
+ require 'rails'
3
+ module ItgTest
4
+ class Railtie < Rails::Railtie
5
+ railtie_name :itg_test
6
+
7
+ rake_tasks do
8
+ load "tasks/test_itg.rake"
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,68 @@
1
+ require 'itg_test/http_client'
2
+ require 'nokogiri'
3
+
4
+ module Declarative
5
+ def test name, &block
6
+ test_name = "test_#{name.gsub(/\s+/,'_')}".to_sym
7
+ define_method test_name, &block
8
+ end
9
+ end
10
+
11
+ module ItgTest; end
12
+ class ItgTest::TestCase
13
+ extend Declarative
14
+ def run_test
15
+ methods.select{|m| /^test_\w+$/ =~ m.to_s}.each{|m| send(m); print "."}
16
+ puts "\nFinished Tests"
17
+ rescue Exception => e
18
+ puts "#{e.class}: #{e}"
19
+ puts e.backtrace
20
+ ensure
21
+ wait_exit
22
+ end
23
+
24
+ def initialize url, pid
25
+ @pid = pid
26
+ @client = ItgTest::HTTPClient.new url
27
+ end
28
+
29
+ def post path, data
30
+ @response = @client.post path, data
31
+ end
32
+
33
+ def get path
34
+ @response = @client.get path
35
+ end
36
+
37
+ def assert_difference expression, difference=1
38
+ exs = [expression].flatten
39
+ before = exs.map{|e| eval e}
40
+ yield
41
+ exs.each_with_index{ |e, i| assert_equal(before[i] + difference, eval(e), e) }
42
+ end
43
+
44
+ def assert_select selector, content
45
+ unless Nokogiri::HTML(@response).at_css(selector).try(:content) == content
46
+ raise "#{content} doesn't match #{selector} of\n#{@response}"
47
+ end
48
+ end
49
+
50
+ def assert_equal a, b, msg=""
51
+ raise "Expected #{a} == #{b} #{msg}" unless a == b
52
+ end
53
+
54
+ def wait_exit
55
+ child_pids(@pid).each{|p| Process.kill "INT", p} # kill grand_children
56
+ Process.kill "INT", @pid # kill child
57
+ Process.wait
58
+ exit
59
+ end
60
+
61
+ def child_pids pid
62
+ pipe = IO.popen("ps -ef | grep #{pid}")
63
+ pipe.readlines.map do |line|
64
+ parts = line.split(/\s+/)
65
+ parts[2] if parts[3] == pid.to_s and parts[2] != pipe.pid.to_s
66
+ end.compact.map(&:to_i)
67
+ end
68
+ end
data/lib/itg_test.rb ADDED
@@ -0,0 +1,11 @@
1
+ module ItgTest
2
+ require 'itg_test/railtie' if defined?(Rails)
3
+ require 'itg_test/test_case'
4
+ require 'itg_test/http_client'
5
+
6
+ module_function
7
+ def absolute_file_name_to_class_name abs_fn
8
+ fn = abs_fn.match(%r|^/.*/([a-zA-Z_]+)\.rb$|)[1]
9
+ fn.split('_').map{|w| w.capitalize}.join
10
+ end
11
+ end
@@ -0,0 +1,17 @@
1
+
2
+ desc "integration test"
3
+ task 'test:itg' => :environment do
4
+ Rails.env = 'test'
5
+ Rake::Task['db:fixtures:load'].invoke
6
+ pid = Process.fork
7
+ if pid.nil?
8
+ exec('rails s -e test -p 3006')
9
+ exec('rails s -e test -p 3006 > /dev/null 2>&1')
10
+ else
11
+ Dir[Dir.pwd + '/test/itg/*.rb'].each {|file|
12
+ require file
13
+ Object.const_get(ItgTest.absolute_file_name_to_class_name(file)).
14
+ new('http://localhost:3006', pid).run_test
15
+ }
16
+ end
17
+ end
metadata ADDED
@@ -0,0 +1,69 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: itg_test
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.0
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - awawfumin
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2012-08-29 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: nokogiri
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: '0'
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ! '>='
28
+ - !ruby/object:Gem::Version
29
+ version: '0'
30
+ description: for rails apps that are too complicated to be tested with builtin integration
31
+ test
32
+ email: fumin@cardinalblue.com
33
+ executables: []
34
+ extensions: []
35
+ extra_rdoc_files: []
36
+ files:
37
+ - .gitignore
38
+ - lib/itg_test.rb
39
+ - lib/itg_test/http_client.rb
40
+ - lib/itg_test/railtie.rb
41
+ - lib/itg_test/test_case.rb
42
+ - lib/tasks/test_itg.rake
43
+ - itg_test.gemspec
44
+ - README.md
45
+ homepage: http://cardinalblue.com
46
+ licenses: []
47
+ post_install_message:
48
+ rdoc_options: []
49
+ require_paths:
50
+ - lib
51
+ required_ruby_version: !ruby/object:Gem::Requirement
52
+ none: false
53
+ requirements:
54
+ - - ! '>='
55
+ - !ruby/object:Gem::Version
56
+ version: '0'
57
+ required_rubygems_version: !ruby/object:Gem::Requirement
58
+ none: false
59
+ requirements:
60
+ - - ! '>='
61
+ - !ruby/object:Gem::Version
62
+ version: '0'
63
+ requirements: []
64
+ rubyforge_project:
65
+ rubygems_version: 1.8.24
66
+ signing_key:
67
+ specification_version: 3
68
+ summary: rails integration test
69
+ test_files: []