nginx_test_helper 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/.gitignore ADDED
@@ -0,0 +1,19 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ .rvmrc
7
+ .project
8
+ Gemfile.lock
9
+ InstalledFiles
10
+ _yardoc
11
+ coverage
12
+ doc/
13
+ lib/bundler/man
14
+ pkg
15
+ rdoc
16
+ spec/reports
17
+ test/tmp
18
+ test/version_tmp
19
+ tmp
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --color
2
+ --format progress
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in nginx_test_helper.gemspec
4
+ gemspec
data/LICENSE ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2012 Wandenberg Peixoto
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,141 @@
1
+ # NginxTestHelper
2
+
3
+ A collection of helper methods to test your nginx module.
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ gem 'nginx_test_helper'
10
+
11
+ And then execute:
12
+
13
+ $ bundle
14
+
15
+ Or install it yourself as:
16
+
17
+ $ gem install nginx_test_helper
18
+
19
+ ## Usage
20
+
21
+ Create a module called NginxConfiguration with two class methods:
22
+ `default_configuration`, which should return a hash with the default configuration values, and `template_configuration` which should return the Nginx configuration template.
23
+
24
+ You can use the command bellow to generate this file
25
+
26
+ $ nginx_test_helper init
27
+
28
+ The init command also create a example_spec.rb to show how to use the main methods:
29
+
30
+ ### nginx_test_configuration
31
+
32
+ Starts the server with the given configuration and template, stop it and return the `stderr` and `error log` to be possible to check some condition.
33
+
34
+ nginx_test_configuration({:unknown_value => 0}).should include('unknown directive "unknown_directive"')
35
+
36
+ ### nginx_run_server
37
+
38
+ Starts the server, execute the given block inside a `Timeout block` and stop the server.
39
+
40
+ nginx_run_server({:return_code => 422}) do
41
+ uri = URI.parse("http://#{nginx_host}:#{nginx_port}/")
42
+ response = Net::HTTP.get_response(uri)
43
+ response.code.should eql("422")
44
+ end
45
+
46
+ You can customize the timeout value, default 5 seconds, using the second parameter of `nginx_run_server` method.
47
+
48
+ nginx_run_server({}, {:timeout => 1}) do
49
+ sleep 2
50
+ end
51
+
52
+ ### start_server / stop_server
53
+
54
+ If you want to start the server and run many test cases with the same configuration you can use `start_server / stop_server` methods.
55
+
56
+ before(:all) do
57
+ configuration = {} # Your configuration hash
58
+ @config = NginxTestHelper::Config.new("example_config_id", configuration)
59
+ start_server(@config)
60
+ end
61
+
62
+ after(:all) do
63
+ stop_server(@config)
64
+ end
65
+
66
+ ### delete_config_and_log_files
67
+
68
+ You can use this method to delete the files created by configuration.
69
+ One usecase is call it after the test, if it has passed, like:
70
+
71
+ RSpec.configure do |config|
72
+ config.after(:each) do
73
+ NginxTestHelper::Config.delete_config_and_log_files(config_id) if has_passed?
74
+ end
75
+ end
76
+
77
+ ## Environment variables
78
+
79
+ Some default values can be overwriten by environment variables.
80
+ Check the list bellow:
81
+
82
+ 1. NGINX_EXEC - set which nginx executable to be used on tests, default: '/usr/local/nginx/sbin/nginx'
83
+ 2. NGINX_HOST - set the host returned by `nginx_host` method, default: '127.0.0.1'
84
+ 3. NGINX_PORT - set the port returned by `nginx_port` method, default: 9990
85
+ 4. NGINX_WORKERS - set the number of workers returned by `nginx_workers` method, default: 1
86
+ 5. NGINX_TESTS_TMP_DIR - set the dir where temporary files, logs and configuration files, will be stored, default: '/tmp/nginx_tests'
87
+
88
+ ## Easter eggs
89
+
90
+ ### configuration_template
91
+
92
+ You can set a key named `configuration_template` on your configuration with a template different from the one on `template_configuration` method to be used when writing configuration file.
93
+
94
+ ### disable_start_stop_server
95
+
96
+ You can set a key named `disable_start_stop_server` on your configuration with `true` value to avoid the start and stop server steps. This can be useful when debugging how a test is failing.
97
+
98
+ ### write_directive
99
+
100
+ You can use the method `write_directive` on your configuration template to be easier to deal with null values.
101
+
102
+ write_directive("directive_name", value)
103
+
104
+ with value = nil results in
105
+ #directive_name "";
106
+
107
+ with value != nil, 10 as example, results in
108
+ directive_name "10";
109
+
110
+ There is a third optional parameter which is used as comment to directive.
111
+
112
+ write_directive("directive_name", 10, "directive comment")
113
+
114
+ #directive comment
115
+ directive_name "10";
116
+
117
+ ## Matchers
118
+
119
+ There are two available mathers.
120
+
121
+ ### be_in_the_interval
122
+
123
+ To check if the value is in a range, `>= min` and `<= max`
124
+
125
+ 10.5.should be_in_the_interval(10.3, 10.6) # true
126
+ 10.5.should be_in_the_interval(10.6, 10.8) # false
127
+
128
+ ### match_the_pattern
129
+
130
+ To check if the value match the given pattern
131
+
132
+ "foo".should match_the_pattern(/O/i) # true
133
+ "foo".should match_the_pattern(/A/i) # false
134
+
135
+ ## Contributing
136
+
137
+ 1. Fork it
138
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
139
+ 3. Commit your changes (`git commit -am 'Added some feature'`)
140
+ 4. Push to the branch (`git push origin my-new-feature`)
141
+ 5. Create new Pull Request
data/Rakefile ADDED
@@ -0,0 +1,11 @@
1
+ #!/usr/bin/env rake
2
+ require "bundler/gem_tasks"
3
+ require "rspec/core/rake_task"
4
+
5
+ desc "Run all examples"
6
+ RSpec::Core::RakeTask.new(:spec) do |t|
7
+ t.rspec_opts = %w[--color --format documentation]
8
+ t.pattern = 'spec/**/*_spec.rb'
9
+ end
10
+
11
+ task :default => [:spec]
@@ -0,0 +1,6 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'rubygems'
4
+ require 'nginx_test_helper'
5
+
6
+ NginxTestHelper::CommandLineTool.new.process ARGV
@@ -0,0 +1,59 @@
1
+ module NginxTestHelper
2
+ class CommandLineTool
3
+ def cwd
4
+ File.expand_path(File.join(File.dirname(__FILE__), '../../'))
5
+ end
6
+
7
+ def expand(*paths)
8
+ File.expand_path(File.join(*paths))
9
+ end
10
+
11
+ def template_path(filepath)
12
+ expand(cwd, File.join("templates", filepath))
13
+ end
14
+
15
+ def dest_path(filepath)
16
+ expand(Dir.pwd, filepath)
17
+ end
18
+
19
+ def copy_unless_exists(relative_path, dest_path = nil)
20
+ unless File.exist?(dest_path(relative_path))
21
+ FileUtils.copy(template_path(relative_path), dest_path(dest_path || relative_path))
22
+ end
23
+ end
24
+
25
+ def process(argv)
26
+ if argv[0] == 'init'
27
+ require 'fileutils'
28
+
29
+ FileUtils.makedirs(dest_path('spec'))
30
+
31
+ copy_unless_exists('spec/nginx_configuration.rb')
32
+ copy_unless_exists('spec/example_spec.rb')
33
+ copy_unless_exists('spec/example2_spec.rb')
34
+
35
+ write_mode = 'w'
36
+ if File.exist?(dest_path('spec/spec_helper.rb'))
37
+ load dest_path('spec/spec_helper.rb')
38
+ write_mode = 'a'
39
+ end
40
+
41
+ unless Object.const_defined?('NginxConfiguration') && write_mode == 'a'
42
+ File.open(dest_path('spec/spec_helper.rb'), write_mode) do |f|
43
+ f.write("\nrequire File.expand_path('nginx_configuration', File.dirname(__FILE__))")
44
+ end
45
+ end
46
+
47
+ File.open(template_path('INSTALL'), 'r').each_line do |line|
48
+ puts line
49
+ end
50
+ elsif argv[0] == "license"
51
+ puts File.new(expand(cwd, "LICENSE")).read
52
+ else
53
+ puts "unknown command #{argv}"
54
+ puts "Usage: nginx_test_helper init"
55
+ puts " license"
56
+ end
57
+ end
58
+ end
59
+ end
@@ -0,0 +1,70 @@
1
+ require "erb"
2
+
3
+ module NginxTestHelper
4
+ class Config
5
+
6
+ include NginxTestHelper::EnvMethods
7
+
8
+ attr_reader :config_id, :configuration
9
+
10
+ def initialize(config_id, configuration)
11
+ @config_id = config_id
12
+ @configuration = NginxConfiguration.default_configuration.merge(configuration).merge(Config.files_and_dirs(config_id))
13
+
14
+ Config.create_dirs
15
+ create_configuration_file
16
+ end
17
+
18
+ def create_configuration_file
19
+ configuration_template = configuration.delete(:configuration_template)
20
+ template = ERB.new configuration_template || NginxConfiguration.template_configuration
21
+ File.open(configuration[:configuration_filename], 'w') {|f| f.write(template.result(get_binding)) }
22
+ end
23
+
24
+ def respond_to?(m)
25
+ super(m) || configuration.has_key?(m.to_sym)
26
+ end
27
+
28
+ def method_missing(m, *args, &block)
29
+ raise NameError, "undefined local variable, method or configuration '#{m}'" unless configuration.has_key?(m.to_sym)
30
+ configuration[m.to_sym]
31
+ end
32
+
33
+ def write_directive(name, value, comment=nil)
34
+ directive = []
35
+ directive << %(##{comment}) unless comment.nil?
36
+ directive << %(#{"#" if value.nil?}#{name} "#{value}";)
37
+ directive.join("\n")
38
+ end
39
+
40
+ def get_binding
41
+ binding
42
+ end
43
+
44
+ class << self
45
+ def create_dirs
46
+ FileUtils.mkdir_p("#{nginx_tests_tmp_dir}/logs") unless File.directory?("#{nginx_tests_tmp_dir}/logs")
47
+ FileUtils.mkdir_p("#{nginx_tests_tmp_dir}/client_body_temp") unless File.directory?("#{nginx_tests_tmp_dir}/client_body_temp")
48
+ end
49
+
50
+ def files_and_dirs(config_id)
51
+ {
52
+ :configuration_filename => File.expand_path("#{nginx_tests_tmp_dir}/#{config_id}.conf"),
53
+ :pid_file => File.expand_path("#{nginx_tests_tmp_dir}/nginx.pid"),
54
+ :access_log => File.expand_path("#{nginx_tests_tmp_dir}/logs/access-#{config_id}.log"),
55
+ :error_log => File.expand_path("#{nginx_tests_tmp_dir}/logs/error-#{config_id}.log"),
56
+ :client_body_temp => File.expand_path("#{nginx_tests_tmp_dir}/client_body_temp")
57
+ }
58
+ end
59
+
60
+ def delete_config_and_log_files(config_id)
61
+ items = files_and_dirs(config_id)
62
+
63
+ File.delete(items[:configuration_filename]) if File.exist?(items[:configuration_filename])
64
+ File.delete(items[:access_log]) if File.exist?(items[:access_log])
65
+ File.delete(items[:error_log]) if File.exist?(items[:error_log])
66
+ FileUtils.rm_rf(items[:client_body_temp]) if File.exist?(items[:client_body_temp])
67
+ end
68
+ end
69
+ end
70
+ end
@@ -0,0 +1,35 @@
1
+ module NginxTestHelper
2
+ module EnvMethods
3
+ module ClassMethods
4
+ def nginx_address
5
+ "http://#{nginx_host}:#{nginx_port}"
6
+ end
7
+
8
+ def nginx_executable
9
+ ENV['NGINX_EXEC'].nil? ? "/usr/local/nginx/sbin/nginx" : ENV['NGINX_EXEC']
10
+ end
11
+
12
+ def nginx_host
13
+ ENV['NGINX_HOST'].nil? ? "127.0.0.1" : ENV['NGINX_HOST']
14
+ end
15
+
16
+ def nginx_port
17
+ ENV['NGINX_PORT'].nil? ? "9990" : ENV['NGINX_PORT']
18
+ end
19
+
20
+ def nginx_workers
21
+ ENV['NGINX_WORKERS'].nil? ? "1" : ENV['NGINX_WORKERS']
22
+ end
23
+
24
+ def nginx_tests_tmp_dir
25
+ ENV['NGINX_TESTS_TMP_DIR'].nil? ? "/tmp/nginx_tests" : ENV['NGINX_TESTS_TMP_DIR']
26
+ end
27
+ end
28
+
29
+ include ClassMethods
30
+
31
+ def self.included(base)
32
+ base.extend ClassMethods
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,41 @@
1
+ if defined?(RSpec)
2
+ RSpec.configure do |config|
3
+ config.include NginxTestHelper
4
+ end
5
+
6
+ RSpec::Matchers.define :be_in_the_interval do |min, max|
7
+ match do |actual|
8
+ (actual >= min) && (actual <= max)
9
+ end
10
+
11
+ failure_message_for_should do |actual|
12
+ "expected that #{actual} would be in the interval from #{min} to #{max}"
13
+ end
14
+
15
+ failure_message_for_should_not do |actual|
16
+ "expected that #{actual} would not be in the interval from #{min} to #{max}"
17
+ end
18
+
19
+ description do
20
+ "be in the interval from #{min} to #{max}"
21
+ end
22
+ end
23
+
24
+ RSpec::Matchers.define :match_the_pattern do |pattern|
25
+ match do |actual|
26
+ actual.match(pattern)
27
+ end
28
+
29
+ failure_message_for_should do |actual|
30
+ "expected that '#{actual}' would match the pattern '#{pattern.inspect}'"
31
+ end
32
+
33
+ failure_message_for_should_not do |actual|
34
+ "expected that '#{actual}' would not match the pattern '#{pattern.inspect}'"
35
+ end
36
+
37
+ description do
38
+ "match the pattern '#{pattern.inspect}'"
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,3 @@
1
+ module NginxTestHelper
2
+ VERSION = "0.0.1"
3
+ end
@@ -0,0 +1,118 @@
1
+ require "nginx_test_helper/version"
2
+ require "nginx_test_helper/env_methods"
3
+ require "nginx_test_helper/config"
4
+ require "nginx_test_helper/rspec_utils"
5
+ require "nginx_test_helper/command_line_tool"
6
+ require "popen4"
7
+ require 'timeout'
8
+
9
+ module NginxTestHelper
10
+ include NginxTestHelper::EnvMethods
11
+
12
+ def nginx_run_server(configuration={}, options={}, &block)
13
+ config = Config.new(config_id, configuration)
14
+ start_server(config)
15
+ Timeout::timeout(options[:timeout] || 5) do
16
+ block.call(config)
17
+ end
18
+ ensure
19
+ stop_server(config) unless config.nil?
20
+ end
21
+
22
+ def nginx_test_configuration(configuration={})
23
+ config = Config.new(config_id, configuration)
24
+ stderr_msg = start_server(config)
25
+ stop_server(config)
26
+ "#{stderr_msg}\n#{File.read(config.error_log) if File.exists?(config.error_log)}"
27
+ end
28
+
29
+ def open_socket(host, port)
30
+ TCPSocket.open(host, port)
31
+ end
32
+
33
+ def get_in_socket(url, socket, wait_for=nil)
34
+ socket.print("GET #{url} HTTP/1.0\r\n\r\n")
35
+ read_response_on_socket(socket, wait_for)
36
+ end
37
+
38
+ def post_in_socket(url, body, socket, wait_for=nil)
39
+ socket.print("POST #{url} HTTP/1.0\r\nContent-Length: #{body.size}\r\n\r\n#{body}")
40
+ read_response_on_socket(socket, wait_for)
41
+ end
42
+
43
+ def read_response_on_socket(socket, wait_for=nil)
44
+ response ||= socket.readpartial(1)
45
+ while (tmp = socket.read_nonblock(256))
46
+ response += tmp
47
+ end
48
+ rescue Errno::EAGAIN => e
49
+ headers, body = (response || "").split("\r\n\r\n", 2)
50
+ if !wait_for.nil? && (body.nil? || body.empty? || !body.include?(wait_for))
51
+ IO.select([socket])
52
+ retry
53
+ end
54
+ ensure
55
+ fail("Any response") if response.nil?
56
+ headers, body = response.split("\r\n\r\n", 2)
57
+ return headers, body
58
+ end
59
+
60
+ def time_diff_milli(start, finish)
61
+ ((finish - start) * 1000.0).to_i
62
+ end
63
+
64
+ def time_diff_sec(start, finish)
65
+ (finish - start).to_i
66
+ end
67
+
68
+ def headers
69
+ {'accept' => 'text/html'}
70
+ end
71
+
72
+ def start_server(config)
73
+ error_message = ""
74
+ unless config.configuration[:disable_start_stop_server]
75
+ status = POpen4::popen4("#{ config.nginx_executable } -c #{ config.configuration_filename }") do |stdout, stderr, stdin, pid|
76
+ error_message = stderr.read.strip unless stderr.eof
77
+ return error_message unless error_message.nil?
78
+ end
79
+ fail("Server doesn't started - #{error_message}") unless status.exitstatus == 0
80
+ end
81
+ error_message
82
+ end
83
+
84
+ def stop_server(config)
85
+ error_message = ""
86
+ unless config.configuration[:disable_start_stop_server]
87
+ status = POpen4::popen4("#{ config.nginx_executable } -c #{ config.configuration_filename } -s stop") do |stdout, stderr, stdin, pid|
88
+ error_message = stderr.read.strip unless stderr.eof
89
+ return error_message unless error_message.nil?
90
+ end
91
+ fail("Server doesn't stoped - #{error_message}") unless status.exitstatus == 0
92
+ end
93
+ error_message
94
+ end
95
+
96
+ private
97
+ def config_id
98
+ if self.respond_to?(:example) && !self.example.nil? &&
99
+ self.example.respond_to?(:metadata) && !self.example.metadata.nil? &&
100
+ !self.example.metadata[:location].nil?
101
+ (self.example.metadata[:location].split('/') - [".", "spec"]).join('_').gsub(/[\.\:]/, '_')
102
+ elsif self.respond_to?('method_name')
103
+ self.method_name
104
+ else
105
+ self.__name__
106
+ end
107
+ end
108
+
109
+ def has_passed?
110
+ if self.respond_to?(:example) && !self.example.nil? && self.example.instance_variable_defined?(:@exception)
111
+ self.example.exception.nil?
112
+ elsif !@test_passed.nil?
113
+ @test_passed
114
+ else
115
+ @passed
116
+ end
117
+ end
118
+ end
@@ -0,0 +1,23 @@
1
+ # -*- encoding: utf-8 -*-
2
+ require File.expand_path('../lib/nginx_test_helper/version', __FILE__)
3
+
4
+ Gem::Specification.new do |gem|
5
+ gem.authors = ["Wandenberg Peixoto"]
6
+ gem.email = ["wandenberg@gmail.com"]
7
+ gem.description = %q{A collection of helper methods to test your nginx module.}
8
+ gem.summary = %q{A collection of helper methods to test your nginx module.}
9
+ gem.homepage = ""
10
+
11
+ gem.files = `git ls-files`.split($\)
12
+ gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
13
+ gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
14
+ gem.name = "nginx_test_helper"
15
+ gem.require_paths = ["lib"]
16
+ gem.version = NginxTestHelper::VERSION
17
+
18
+ gem.add_dependency "popen4"
19
+
20
+ gem.add_development_dependency(%q<rspec>, [">= 2.10.0"])
21
+ gem.add_development_dependency(%q<debugger>, [">= 1.1.3"])
22
+ gem.add_development_dependency(%q<simplecov>, [">= 0.0.1"]) if RUBY_VERSION > "1.9.0"
23
+ end
@@ -0,0 +1,47 @@
1
+ require 'spec_helper'
2
+
3
+ describe NginxTestHelper::CommandLineTool do
4
+ before do
5
+ $stdout.stub!(:puts)
6
+ Dir.stub!(:pwd).and_return('tmp')
7
+ FileUtils.mkdir_p('tmp/spec')
8
+ end
9
+
10
+ after do
11
+ FileUtils.rm_rf('tmp')
12
+ end
13
+
14
+ it "should list available options" do
15
+ $stdout.should_receive(:puts).with(/init/)
16
+ $stdout.should_receive(:puts).with(/license/)
17
+ NginxTestHelper::CommandLineTool.new.process []
18
+ end
19
+
20
+ it "should list the gem license" do
21
+ $stdout.should_receive(:puts).with(/MIT License/)
22
+ NginxTestHelper::CommandLineTool.new.process ["license"]
23
+ end
24
+
25
+ it "should create example files showing how to use the gem" do
26
+ NginxTestHelper::CommandLineTool.new.process ["init"]
27
+ File.exists?('tmp/spec/nginx_configuration.rb').should be_true
28
+ File.exists?('tmp/spec/example_spec.rb').should be_true
29
+ File.exists?('tmp/spec/spec_helper.rb').should be_true
30
+
31
+ File.read('tmp/spec/nginx_configuration.rb').should eql(File.read('templates/spec/nginx_configuration.rb'))
32
+ File.read('tmp/spec/example_spec.rb').should eql(File.read('templates/spec/example_spec.rb'))
33
+ File.read('tmp/spec/spec_helper.rb').should include('nginx_configuration')
34
+ end
35
+
36
+ it "should include require call on spec_helper if NgincConfiguration is not defined" do
37
+ Object.stub!(:const_defined?).with('NginxConfiguration').and_return(false)
38
+ File.open('tmp/spec/spec_helper.rb', 'w') { |f| f.write("#spec_helper content") }
39
+ NginxTestHelper::CommandLineTool.new.process ["init"]
40
+ File.read('tmp/spec/spec_helper.rb').should eql("#spec_helper content\nrequire File.expand_path('nginx_configuration', File.dirname(__FILE__))")
41
+ end
42
+
43
+ it "should print INSTALL file content" do
44
+ $stdout.should_receive(:puts).with(/Nginx Test Helper has been installed with example specs./)
45
+ NginxTestHelper::CommandLineTool.new.process ["init"]
46
+ end
47
+ end