Commit 029daba7 authored by Wandenberg Peixoto's avatar Wandenberg Peixoto

refactoring tests to use nginx_test_helper and rspec gems

parent 67935a78
...@@ -3,49 +3,27 @@ h1(#tests). Tests <a name="tests" href="#">&nbsp;</a> ...@@ -3,49 +3,27 @@ h1(#tests). Tests <a name="tests" href="#">&nbsp;</a>
The tests for this module are written in Ruby, and are acceptance tests. The tests for this module are written in Ruby, and are acceptance tests.
To run them is needed to have an environment with: To run them is needed to have an environment with:
* Basic requirements * ruby >= 1.9.3
** ruby >= 1.8.7 * bundler >= 1.1.4
** rubygems >= 1.6.2
** rake >= 0.8.7
* Required gems
** POpen4 >= 0.1.4
** em-http-request >= 0.2.14
** json >= 1.4.3
** ruby-debug >= 0.10.4
** jasmine >= 1.0.2.1
** nokogiri >= 1.5.0
** jshint >= 0.1.1
You can install these gems with bundler (bundler is required to be installed before, _gem install bundler_)
<pre> and install required gems doing:
cd test/
bundle install --without docs
</pre>
or individually
<pre> <pre>
gem install POpen4 -v 0.1.4 cd misc/
gem install em-http-request -v 0.2.14 bundle install --without docs
gem install json -v 1.4.3
gem install ruby-debug -v 0.10.4
gem install jasmine -v 1.0.2.1
gem install nokogiri -v 1.5.0
gem install jshint -v 0.1.1
</pre> </pre>
Then issue @rake tests@. Then issue @rake spec@.
This command run the tests using nginx *executable* located at _/usr/local/nginx/sbin/nginx_ with _1_ *worker* responding at *host* _localhost_ and *port* _9990_. This command run the tests using nginx *executable* located at _/usr/local/nginx/sbin/nginx_ with _1_ *worker* responding at *host* _127.0.0.1_ and *port* _9990_.
To change this behavior use the commands bellow To change this behavior use the commands bellow
<pre> <pre>
rake tests executable="../build/nginx-1.1.15/objs/nginx" # to change default path for nginx executable NGINX_EXEC="../build/nginx-1.1.15/objs/nginx" rake spec # to change default path for nginx executable
rake tests host=my_machine # to change default hostname NGINX_HOST="my_machine" rake spec # to change default hostname
rake tests port=9889 # to change default port NGINX_PORT=9889 rake spec # to change default port
rake tests workers=2 # to change dafault number of workers used NGINX_WORKERS=2 rake spec # to change dafault number of workers used
and can combine any of these parameters, like: and can combine any of these parameters, like:
rake tests port=9889 executable="../build/nginx-1.1.15/objs/nginx" NGINX_PORT=9889 NGINX_EXEC="../build/nginx-1.1.15/objs/nginx" rake spec
</pre> </pre>
rvm ruby-1.9.3-p194@nginx-push-stream-module --create
source "https://rubygems.org"
gem 'rake', '~> 10.0.3'
group :test do
gem 'rspec', '~> 2.12.0'
gem 'em-http-request', '~> 1.0.3'
gem 'nginx_test_helper', '~> 0.0.1'
gem 'jshintrb', '~> 0.2.1'
gem 'therubyracer', '~> 0.11.3'
gem 'jasmine', '~> 1.3.1'
gem 'listen', '~> 0.7.2'
gem 'rb-inotify', '~> 0.8.8'
gem 'json', '~> 1.7.6'
gem 'debugger', '~> 1.3.1'
end
group :docs do
gem 'github-markup', '~> 0.7.5', :require => 'github/markup'
gem 'RedCloth', '~> 4.2.9'
gem 'nokogiri', '~> 1.5.6'
end
GEM
remote: https://rubygems.org/
specs:
Platform (0.4.0)
RedCloth (4.2.9)
addressable (2.3.2)
childprocess (0.3.8)
ffi (~> 1.0, >= 1.0.11)
columnize (0.3.6)
cookiejar (0.3.0)
debugger (1.3.1)
columnize (>= 0.3.1)
debugger-linecache (~> 1.1.1)
debugger-ruby_core_source (~> 1.1.8)
debugger-linecache (1.1.2)
debugger-ruby_core_source (>= 1.1.1)
debugger-ruby_core_source (1.1.8)
diff-lcs (1.1.3)
em-http-request (1.0.3)
addressable (>= 2.2.3)
cookiejar
em-socksify
eventmachine (>= 1.0.0.beta.4)
http_parser.rb (>= 0.5.3)
em-socksify (0.2.1)
eventmachine (>= 1.0.0.beta.4)
eventmachine (1.0.0)
execjs (1.4.0)
multi_json (~> 1.0)
ffi (1.3.1)
github-markup (0.7.5)
http_parser.rb (0.5.3)
jasmine (1.3.1)
jasmine-core (~> 1.3.1)
rack (~> 1.0)
rspec (>= 1.3.1)
selenium-webdriver (>= 0.1.3)
jasmine-core (1.3.1)
jshintrb (0.2.1)
execjs
multi_json (>= 1.3)
rake
json (1.7.6)
libv8 (3.11.8.13)
listen (0.7.2)
multi_json (1.5.0)
nginx_test_helper (0.0.1)
popen4
nokogiri (1.5.6)
open4 (1.3.0)
popen4 (0.1.2)
Platform (>= 0.4.0)
open4 (>= 0.4.0)
rack (1.5.2)
rake (10.0.3)
rb-inotify (0.8.8)
ffi (>= 0.5.0)
ref (1.0.2)
rspec (2.12.0)
rspec-core (~> 2.12.0)
rspec-expectations (~> 2.12.0)
rspec-mocks (~> 2.12.0)
rspec-core (2.12.2)
rspec-expectations (2.12.1)
diff-lcs (~> 1.1.3)
rspec-mocks (2.12.2)
rubyzip (0.9.9)
selenium-webdriver (2.29.0)
childprocess (>= 0.2.5)
multi_json (~> 1.0)
rubyzip
websocket (~> 1.0.4)
therubyracer (0.11.3)
libv8 (~> 3.11.8.12)
ref
websocket (1.0.7)
PLATFORMS
ruby
DEPENDENCIES
RedCloth (~> 4.2.9)
debugger (~> 1.3.1)
em-http-request (~> 1.0.3)
github-markup (~> 0.7.5)
jasmine (~> 1.3.1)
jshintrb (~> 0.2.1)
json (~> 1.7.6)
listen (~> 0.7.2)
nginx_test_helper (~> 0.0.1)
nokogiri (~> 1.5.6)
rake (~> 10.0.3)
rb-inotify (~> 0.8.8)
rspec (~> 2.12.0)
therubyracer (~> 0.11.3)
base_dir = File.expand_path('..', File.dirname(__FILE__)) project_dir = File.expand_path('..', File.dirname(__FILE__))
javascript_dir = File.expand_path(Dir["#{project_dir}/**/js"].first)
require 'rubygems'
# Set up gems listed in the Gemfile.
ENV['BUNDLE_GEMFILE'] ||= File.expand_path('./Gemfile', File.dirname(__FILE__))
require 'bundler/setup' if File.exists?(ENV['BUNDLE_GEMFILE'])
Bundler.require(:default, :test) if defined?(Bundler)
begin
require "rspec/core/rake_task"
desc "Run all examples"
RSpec::Core::RakeTask.new(:spec) do |t|
t.rspec_opts = %w[--color --debug]
t.pattern = '**/*_spec.rb'
end
rescue LoadError
task :spec do
abort "RSpec is not available. In order to run rspec, you must: (sudo) gem install rspec"
end
end
begin
load 'jasmine/tasks/jasmine.rake'
task "jasmine:require" => ["jshint", "configure_jasmine", "monitor_js"]
task :configure_jasmine do
Jasmine.configure do |config|
config.spec_dir = project_dir
config.spec_files = lambda { Dir["#{project_dir}/misc/spec/javascripts/helpers/**/*.js"] + Dir["#{project_dir}/misc/**/*[sS]pec.js"] }
js_tmp_dir = File.expand_path('pushstream/js', Dir.tmpdir)
config.src_dir = js_tmp_dir
config.src_files = lambda { Dir["#{js_tmp_dir}/**/*.js"] }
end
end
task :monitor_js do
copy_inner_js = Proc.new do |modified, added, removed|
modified.each do |file|
destiny_path = File.dirname(file).gsub(/.*\/js\/?/, File.expand_path('pushstream/js', Dir.tmpdir))
FileUtils.mkdir_p(destiny_path)
content = File.read file
content.gsub!('(function (window, document, undefined) {', '')
content.gsub!('if (window.PushStream) { return; }', '')
content.gsub!('})(window, document);', '')
File.open(File.join(destiny_path, File.basename(file)), 'w') {|f| f.write content }
end
end
copy_inner_js.call([[File.expand_path('misc/js/pushstream.js', project_dir)], [], []])
listener = Listen.to(File.expand_path('misc/js', project_dir), :filter => /\.js$/)
listener.change(&copy_inner_js)
listener.start(false)
end
rescue LoadError
desc "Run javascript tests"
task :jasmine do
abort "Jasmine is not available. In order to run jasmine, you must: (sudo) gem install jasmine"
end
end
begin
require "jshintrb/jshinttask"
Jshintrb::JshintTask.new :jshint do |t|
t.pattern = "#{javascript_dir}/pushstream.js"
t.options = :defaults
end
rescue LoadError
desc "Run jshint on js"
task :jshint do
abort "Jshintrb is not available. In order to run jshint, you must: (sudo) gem install jshintrb"
end
end
namespace :docs do namespace :docs do
begin
Bundler.require(:default, :docs) if defined?(Bundler)
task :get_static_files do
base_path = File.expand_path('pushstream/docs/preview', Dir.tmpdir)
FileUtils.mkdir_p("#{base_path}/css")
download_file("https://a248.e.akamai.net/assets.github.com/assets/github-00f65189aa131d891441bde58bf26d999ab4d29c.css", "#{base_path}/css/github.css") unless File.exists?("#{base_path}/css/github.css")
download_file("https://a248.e.akamai.net/assets.github.com/assets/github2-90ff47ca514fab587fdf9f40626c56af77a8fa6b.css", "#{base_path}/css/github2.css") unless File.exists?("#{base_path}/css/github2.css")
end
desc "Generates docs files to preview." desc "Generates docs files to preview."
task :generate do task :generate => :get_static_files do
require 'erb' require 'erb'
require 'github/markup' template = ERB.new File.read("#{project_dir}/misc/github_template.html.erb")
template = ERB.new File.read("#{base_dir}/misc/github_template.html.erb") base_path = File.expand_path('pushstream/docs/preview', Dir.tmpdir)
Dir.glob("#{base_dir}/**/*.textile").each do |file| Dir.glob("#{project_dir}/**/*.textile").each do |file|
filename = File.basename(file) filename = File.basename(file)
content = GitHub::Markup.render(file, File.read(file)) content = GitHub::Markup.render(file, File.read(file))
rendered = template.result(binding) rendered = template.result(binding)
output = file.gsub(base_dir, "#{base_dir}/misc").gsub(".textile", ".html") output = file.gsub(project_dir, File.expand_path('pushstream/docs/preview', Dir.tmpdir)).gsub(".textile", ".html")
output_dir = File.dirname(output) output_dir = File.dirname(output)
FileUtils.mkdir_p(output_dir) unless File.exists?(output_dir) FileUtils.mkdir_p(output_dir)
File.open(output, 'w') {|f| f.write(rendered) } File.open(output, 'w') {|f| f.write(rendered) }
puts "Preview rendered to #{output}" puts "Preview rendered to #{output}"
end end
...@@ -22,22 +108,42 @@ namespace :docs do ...@@ -22,22 +108,42 @@ namespace :docs do
desc "Convert docs to Nginx wiki format." desc "Convert docs to Nginx wiki format."
task :convert_to_wiki do task :convert_to_wiki do
require 'redcloth' Dir.glob("#{project_dir}/**/*.textile").each do |file|
require 'nokogiri'
Dir.glob("#{base_dir}/**/*.textile").each do |file|
filename = File.basename(file) filename = File.basename(file)
content = File.read(file) content = File.read(file)
output = file.gsub(base_dir, "#{base_dir}/misc").gsub(".textile", ".html") output = file.gsub(project_dir, File.expand_path('pushstream/docs/html', Dir.tmpdir)).gsub(".textile", ".html")
output_wiki = file.gsub(base_dir, "#{base_dir}/misc").gsub(".textile", ".wiki") output_wiki = file.gsub(project_dir, File.expand_path('pushstream/docs/wiki', Dir.tmpdir)).gsub(".textile", ".wiki")
output_dir = File.dirname(output) FileUtils.mkdir_p(File.dirname(output))
FileUtils.mkdir_p(output_dir) unless File.exists?(output_dir) FileUtils.mkdir_p(File.dirname(output_wiki))
File.open(output, 'w') {|f| f.write(RedCloth.new(content).to_html) } File.open(output, 'w') {|f| f.write(RedCloth.new(content).to_html) }
File.open(output_wiki, 'w') {|f| f.write(convert_to_wiki_syntax(content)) } File.open(output_wiki, 'w') {|f| f.write(convert_to_wiki_syntax(content)) }
puts "Wiki converted to #{output_wiki}" puts "Wiki converted to #{output_wiki}"
end end
end end
rescue LoadError
desc "Generates docs files to preview."
task :generate do
abort "github-markup is not available. In order to run docs:generate, you must: (sudo) gem install github-markup"
end
desc "Convert docs to Nginx wiki format."
task :convert_to_wiki do
abort "RedCloth or nokogiri is not available. In order to run docs:convert_to_wiki, you must: (sudo) gem install RedCloth nokogiri"
end
end
def download_file(url, output_file)
EventMachine.run do
http = EventMachine::HttpRequest.new(url).get
http.errback { EM.stop }
http.callback do
File.open(output_file, "w") { |f| f.write(http.response) } if (http.response_header.status == 200)
EM.stop
end
end
end
def convert_to_wiki_syntax(text) def convert_to_wiki_syntax(text)
doc = Nokogiri::HTML(RedCloth.new(text).to_html) doc = Nokogiri::HTML(RedCloth.new(text).to_html)
...@@ -99,65 +205,4 @@ namespace :docs do ...@@ -99,65 +205,4 @@ namespace :docs do
"<#{tag}>#{text}</#{tag}>" "<#{tag}>#{text}</#{tag}>"
end end
end end
end
desc "Run all tests."
task :tests, :executable, :host, :port, :workers, :tests_tmp_dir do |t, args|
ENV['NGINX_EXEC'] ||= args[:executable] || nil
ENV['NGINX_HOST'] ||= args[:host] || nil
ENV['NGINX_PORT'] ||= args[:port] || nil
ENV['NGINX_WORKERS'] ||= args[:workers] || nil
ENV['NGINX_TESTS_TMP_DIR'] ||= args[:tests_tmp_dir] || nil
require 'test/unit'
Dir.glob('test_*.rb').each do|f|
test_case = "#{base_dir}/test/#{f}".gsub('.rb', '')
require test_case
end
end
begin
require 'listen'
require 'jasmine'
load 'jasmine/tasks/jasmine.rake'
task "jasmine:require" => "monitor_js"
task :monitor_js do
copy_inner_js = Proc.new do |modified, added, removed|
modified.each do |file|
destiny_path = File.dirname(file).gsub('misc/js', 'test/tmp/js')
FileUtils.mkdir_p(destiny_path)
content = File.read file
content.gsub!('(function (window, document, undefined) {', '')
content.gsub!('if (window.PushStream) { return; }', '')
content.gsub!('})(window, document);', '')
File.open(File.join(destiny_path, File.basename(file)), 'w') {|f| f.write content }
end
end
copy_inner_js.call([File.expand_path('misc/js/pushstream.js', base_dir)])
listener = Listen.to(File.expand_path('misc/js', base_dir), :filter => /\.js$/)
listener.change(&copy_inner_js)
listener.start(false)
end
rescue LoadError
task :jasmine do
abort "Jasmine is not available. In order to run jasmine, you must: (sudo) gem install jasmine"
end
end
begin
require "jshintrb/jshinttask"
Jshintrb::JshintTask.new :jshint do |t|
t.pattern = '../misc/js/pushstream.js'
t.options = :defaults
end
rescue LoadError
task :jshint do
abort "Jshintrb is not available. In order to run jshint, you must: (sudo) gem install jshintrb"
end
end end
...@@ -4,11 +4,10 @@ ...@@ -4,11 +4,10 @@
<meta http-equiv="content-type" content="text/html; charset=UTF-8"> <meta http-equiv="content-type" content="text/html; charset=UTF-8">
<meta charset="utf-8"> <meta charset="utf-8">
<title><%= filename %> - Preview to GitHub</title> <title><%= filename %> - Preview to GitHub</title>
<base href="file://<%= base_path %>/" />
<link href="https://a248.e.akamai.net/assets.github.com/stylesheets/bundles/github-fe72294c0899f9951f2200f65bc4cf1f7880f77d.css" media="screen" rel="stylesheet" type="text/css" /> <link href="css/github.css" media="screen" rel="stylesheet" type="text/css" />
<link href="https://a248.e.akamai.net/assets.github.com/stylesheets/bundles/github2-cb54f8b424bab1addc65760cf760d406bcc92480.css" media="screen" rel="stylesheet" type="text/css" /> <link href="css/github2.css" media="screen" rel="stylesheet" type="text/css" />
<script src="https://a248.e.akamai.net/assets.github.com/javascripts/bundles/jquery-1ff4761a0d9866a948321eac8d969db3dc12938e.js" type="text/javascript"></script>
<script src="https://a248.e.akamai.net/assets.github.com/javascripts/bundles/github-18a50b3d097d5e6f5686d2be4c43a5fc49547aa5.js" type="text/javascript"></script>
<style> <style>
#preview-content .markdown-body, #preview-content .plain { #preview-content .markdown-body, #preview-content .plain {
background-color: #FFFFFF; background-color: #FFFFFF;
......
...@@ -35,12 +35,12 @@ ...@@ -35,12 +35,12 @@
var valueToTwoDigits = function (value) { var valueToTwoDigits = function (value) {
return ((value < 10) ? '0' : '') + value; return ((value < 10) ? '0' : '') + value;
} };
var dateToUTCString = function (date) { var dateToUTCString = function (date) {
var time = valueToTwoDigits(date.getUTCHours()) + ':' + valueToTwoDigits(date.getUTCMinutes()) + ':' + valueToTwoDigits(date.getUTCSeconds()); var time = valueToTwoDigits(date.getUTCHours()) + ':' + valueToTwoDigits(date.getUTCMinutes()) + ':' + valueToTwoDigits(date.getUTCSeconds());
return days[date.getUTCDay()] + ', ' + valueToTwoDigits(date.getUTCDate()) + ' ' + months[date.getUTCMonth()] + ' ' + date.getUTCFullYear() + ' ' + time + ' GMT'; return days[date.getUTCDay()] + ', ' + valueToTwoDigits(date.getUTCDate()) + ' ' + months[date.getUTCMonth()] + ' ' + date.getUTCFullYear() + ' ' + time + ' GMT';
} };
var extend = function () { var extend = function () {
var object = arguments[0] || {}; var object = arguments[0] || {};
......
beforeEach(function() { beforeEach(function() {
this.addMatchers({ this.addMatchers({
}) });
}); });
require 'spec_helper'
describe "Broadcast Properties" do
let(:config) do
{
:authorized_channels_only => "on",
:header_template => 'connected',
:broadcast_channel_prefix => "XXX_"
}
end
it "should identify broadcast channels by prefix" do
channel = 'ch_test_broadcast_channel_prefix'
channel_broad = 'XXX_123'
channel_broad_fail = 'YYY_123'
body = 'broadcast channel prefix'
nginx_run_server(config, :timeout => 5) do |conf|
EventMachine.run do
pub = EventMachine::HttpRequest.new(nginx_address + '/pub?id=' + channel.to_s ).post :head => headers, :body => body, :timeout => 30
pub.callback do
sub_1 = EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel.to_s + '/' + channel_broad_fail).get :head => headers, :timeout => 60
sub_1.callback do |chunk|
sub_1.response_header.status.should eql(403)
sub_2 = EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel.to_s + '/' + channel_broad).get :head => headers, :timeout => 60
sub_2.stream do |chunk2|
chunk2.should eql("#{conf.header_template}\r\n")
EventMachine.stop
end
end
end
end
end
end
it "should limit the number of broadcast channels in the same request" do
channel = 'ch_test_broadcast_channel_max_qtd'
channel_broad1 = 'XXX_123'
channel_broad2 = 'XXX_321'
channel_broad3 = 'XXX_213'
body = 'broadcast channel prefix'
nginx_run_server(config.merge(:broadcast_channel_max_qtd => 2), :timeout => 5) do |conf|
EventMachine.run do
pub = EventMachine::HttpRequest.new(nginx_address + '/pub?id=' + channel.to_s ).post :head => headers, :body => body, :timeout => 30
pub.callback do
sub_1 = EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel.to_s + '/' + channel_broad1 + '/' + channel_broad2 + '/' + channel_broad3).get :head => headers, :timeout => 60
sub_1.callback do |chunk|
sub_1.response_header.status.should eql(403)
sub_2 = EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel.to_s + '/' + channel_broad1 + '/' + channel_broad2).get :head => headers, :timeout => 60
sub_2.stream do
EventMachine.stop
end
end
end
end
end
end
end
require 'spec_helper'
describe "Channel Statistics" do
let(:config) do
{}
end
it "should return 404 for a nonexistent channel" do
channel = 'ch_test_get_channel_statistics_whithout_created_channel'
nginx_run_server(config, :timeout => 5) do |conf|
EventMachine.run do
pub_1 = EventMachine::HttpRequest.new(nginx_address + '/channels-stats?id=' + channel.to_s).get :head => headers, :timeout => 30
pub_1.callback do
pub_1.response_header.status.should eql(404)
pub_1.response_header.content_length.should eql(0)
EventMachine.stop
end
end
end
end
it "should return channels statistics for an existent channel" do
channel = 'ch_test_get_channel_statistics_to_existing_channel'
body = 'body'
nginx_run_server(config, :timeout => 5) do |conf|
#create channel
publish_message(channel, headers, body)
EventMachine.run do
pub_2 = EventMachine::HttpRequest.new(nginx_address + '/channels-stats?id=' + channel.to_s).get :head => headers, :timeout => 30
pub_2.callback do
pub_2.response_header.status.should eql(200)
pub_2.response_header.content_length.should_not eql(0)
response = JSON.parse(pub_2.response)
response["channel"].to_s.should eql(channel)
response["published_messages"].to_i.should eql(1)
response["stored_messages"].to_i.should eql(1)
response["subscribers"].to_i.should eql(0)
EventMachine.stop
end
end
end
end
it "should return channels statistics for an existent channel with subscriber" do
channel = 'ch_test_get_channel_statistics_to_existing_channel_with_subscriber'
body = 'body'
nginx_run_server(config, :timeout => 5) do |conf|
create_channel_by_subscribe(channel, headers) do
pub_1 = EventMachine::HttpRequest.new(nginx_address + '/channels-stats?id=' + channel.to_s).get :head => headers, :timeout => 30
pub_1.callback do
pub_1.response_header.status.should eql(200)
pub_1.response_header.content_length.should_not eql(0)
response = JSON.parse(pub_1.response)
response["channel"].to_s.should eql(channel)
response["published_messages"].to_i.should eql(0)
response["stored_messages"].to_i.should eql(0)
response["subscribers"].to_i.should eql(1)
EventMachine.stop
end
end
end
end
it "should return detailed channels statistics without existing channels" do
nginx_run_server(config, :timeout => 5) do |conf|
EventMachine.run do
pub_2 = EventMachine::HttpRequest.new(nginx_address + '/channels-stats?id=ALL').get :head => headers, :timeout => 30
pub_2.callback do
pub_2.response_header.status.should eql(200)
pub_2.response_header.content_length.should_not eql(0)
response = JSON.parse(pub_2.response)
response["infos"].length.should eql(0)
EventMachine.stop
end
end
end
end
it "should return detailed channels statistics for an existent channel" do
channel = 'ch_test_get_detailed_channels_statistics_to_existing_channel'
body = 'body'
nginx_run_server(config, :timeout => 5) do |conf|
#create channel
publish_message(channel, headers, body)
EventMachine.run do
pub_2 = EventMachine::HttpRequest.new(nginx_address + '/channels-stats?id=ALL').get :head => headers, :timeout => 30
pub_2.callback do
pub_2.response_header.status.should eql(200)
pub_2.response_header.content_length.should_not eql(0)
response = JSON.parse(pub_2.response)
response["infos"].length.should eql(1)
response["infos"][0]["channel"].to_s.should eql(channel)
response["infos"][0]["published_messages"].to_i.should eql(1)
response["infos"][0]["stored_messages"].to_i.should eql(1)
response["infos"][0]["subscribers"].to_i.should eql(0)
EventMachine.stop
end
end
end
end
it "should return detailed channels statistics for an existent broadcast channel" do
channel = 'bd_test_get_detailed_channels_statistics_to_existing_broadcast_channel'
body = 'body'
nginx_run_server(config.merge(:broadcast_channel_prefix => 'bd_', :broadcast_channel_max_qtd => 1), :timeout => 5) do |conf|
#create channel
publish_message(channel, headers, body)
EventMachine.run do
pub_2 = EventMachine::HttpRequest.new(nginx_address + '/channels-stats?id=ALL').get :head => headers, :timeout => 30
pub_2.callback do
pub_2.response_header.status.should eql(200)
pub_2.response_header.content_length.should_not eql(0)
response = JSON.parse(pub_2.response)
response["infos"].length.should eql(1)
response["channels"].to_i.should eql(0)
response["broadcast_channels"].to_i.should eql(1)
response["infos"][0]["channel"].to_s.should eql(channel)
response["infos"][0]["published_messages"].to_i.should eql(1)
response["infos"][0]["stored_messages"].to_i.should eql(1)
response["infos"][0]["subscribers"].to_i.should eql(0)
EventMachine.stop
end
end
end
end
it "should return detailed channels statistics for an existent channel with subscriber" do
channel = 'ch_test_detailed_channels_statistics_to_existing_channel_with_subscriber'
body = 'body'
nginx_run_server(config, :timeout => 5) do |conf|
create_channel_by_subscribe(channel, headers) do
pub_1 = EventMachine::HttpRequest.new(nginx_address + '/channels-stats?id=ALL').get :head => headers, :timeout => 30
pub_1.callback do
pub_1.response_header.status.should eql(200)
pub_1.response_header.content_length.should_not eql(0)
response = JSON.parse(pub_1.response)
response["infos"].length.should eql(1)
response["infos"][0]["channel"].to_s.should eql(channel)
response["infos"][0]["published_messages"].to_i.should eql(0)
response["infos"][0]["stored_messages"].to_i.should eql(0)
response["infos"][0]["subscribers"].to_i.should eql(1)
EventMachine.stop
end
end
end
end
it "should return summarized channels statistics for a nonexistent channel" do
nginx_run_server(config, :timeout => 5) do |conf|
EventMachine.run do
pub_1 = EventMachine::HttpRequest.new(nginx_address + '/channels-stats').get :head => headers, :timeout => 30
pub_1.callback do
pub_1.response_header.status.should eql(200)
pub_1.response_header.content_length.should_not eql(0)
response = JSON.parse(pub_1.response)
response.has_key?("channels").should be_true
response["channels"].to_i.should eql(0)
EventMachine.stop
end
end
end
end
it "should return summarized channels statistics for an existent channel" do
channel = 'ch_test_get_summarized_channels_statistics_to_existing_channel'
body = 'body'
nginx_run_server(config, :timeout => 5) do |conf|
#create channel
publish_message(channel, headers, body)
EventMachine.run do
pub_2 = EventMachine::HttpRequest.new(nginx_address + '/channels-stats').get :head => headers, :timeout => 30
pub_2.callback do
pub_2.response_header.status.should eql(200)
pub_2.response_header.content_length.should_not eql(0)
response = JSON.parse(pub_2.response)
response.has_key?("channels").should be_true
response["channels"].to_i.should eql(1)
response["published_messages"].to_i.should eql(1)
response["subscribers"].to_i.should eql(0)
EventMachine.stop
end
end
end
end
it "should return summarized channels statistics for an existent broadcast channel" do
channel = 'bd_test_get_summarized_channels_statistics_to_existing_broadcast_channel'
body = 'body'
nginx_run_server(config.merge(:broadcast_channel_prefix => 'bd_', :broadcast_channel_max_qtd => 1), :timeout => 5) do |conf|
#create channel
publish_message(channel, headers, body)
EventMachine.run do
pub_2 = EventMachine::HttpRequest.new(nginx_address + '/channels-stats').get :head => headers, :timeout => 30
pub_2.callback do
pub_2.response_header.status.should eql(200)
pub_2.response_header.content_length.should_not eql(0)
response = JSON.parse(pub_2.response)
response.has_key?("channels").should be_true
response["channels"].to_i.should eql(0)
response["broadcast_channels"].to_i.should eql(1)
response["published_messages"].to_i.should eql(1)
response["subscribers"].to_i.should eql(0)
EventMachine.stop
end
end
end
end
it "should return summarized channels statistics for an existent channel with subscriber" do
channel = 'ch_test_summarized_channels_statistics_to_existing_channel_with_subscriber'
body = 'body'
nginx_run_server(config, :timeout => 5) do |conf|
create_channel_by_subscribe(channel, headers) do
pub_1 = EventMachine::HttpRequest.new(nginx_address + '/channels-stats').get :head => headers, :timeout => 30
pub_1.callback do
pub_1.response_header.status.should eql(200)
pub_1.response_header.content_length.should_not eql(0)
response = JSON.parse(pub_1.response)
response.has_key?("channels").should be_true
response["channels"].to_i.should eql(1)
response["published_messages"].to_i.should eql(0)
response["subscribers"].to_i.should eql(1)
EventMachine.stop
end
end
end
end
it "should check accepted methods" do
nginx_run_server(config, :timeout => 5) do |conf|
EventMachine.run do
multi = EventMachine::MultiRequest.new
multi.add(:a, EventMachine::HttpRequest.new(nginx_address + '/channels-stats').get)
multi.add(:b, EventMachine::HttpRequest.new(nginx_address + '/channels-stats').put(:body => 'body'))
multi.add(:c, EventMachine::HttpRequest.new(nginx_address + '/channels-stats').post)
multi.add(:d, EventMachine::HttpRequest.new(nginx_address + '/channels-stats').delete)
multi.add(:e, EventMachine::HttpRequest.new(nginx_address + '/channels-stats').head)
multi.callback do
multi.responses[:callback].length.should eql(5)
multi.responses[:callback][:a].response_header.status.should_not eql(405)
multi.responses[:callback][:a].req.method.should eql("GET")
multi.responses[:callback][:b].response_header.status.should eql(405)
multi.responses[:callback][:b].req.method.should eql("PUT")
multi.responses[:callback][:c].response_header.status.should eql(405)
multi.responses[:callback][:c].req.method.should eql("POST")
multi.responses[:callback][:d].response_header.status.should eql(405)
multi.responses[:callback][:d].req.method.should eql("DELETE")
multi.responses[:callback][:e].response_header.status.should eql(405)
multi.responses[:callback][:e].req.method.should eql("HEAD")
EventMachine.stop
end
end
end
end
it "should check accepted content types" do
channel = 'ch_test_accepted_content_types'
body = 'body'
nginx_run_server(config, :timeout => 5) do |conf|
#create channel
publish_message(channel, headers, body)
EventMachine.run do
multi = EventMachine::MultiRequest.new
multi.add(:a, EventMachine::HttpRequest.new(nginx_address + '/channels-stats').get) # default content_type
multi.add(:b, EventMachine::HttpRequest.new(nginx_address + '/channels-stats').get(:head => {'accept' => 'text/plain'}))
multi.add(:c, EventMachine::HttpRequest.new(nginx_address + '/channels-stats').get(:head => {'accept' => 'application/json'}))
multi.add(:d, EventMachine::HttpRequest.new(nginx_address + '/channels-stats').get(:head => {'accept' => 'application/yaml'}))
multi.add(:e, EventMachine::HttpRequest.new(nginx_address + '/channels-stats').get(:head => {'accept' => 'application/xml'}))
multi.add(:f, EventMachine::HttpRequest.new(nginx_address + '/channels-stats').get(:head => {'accept' => 'text/x-json'}))
multi.add(:g, EventMachine::HttpRequest.new(nginx_address + '/channels-stats').get(:head => {'accept' => 'text/x-yaml'}))
multi.callback do
multi.responses[:callback].length.should eql(7)
multi.responses[:callback][:a].response_header.status.should eql(200)
multi.responses[:callback][:a].req.method.should eql("GET")
multi.responses[:callback][:a].response_header["CONTENT_TYPE"].should eql("application/json")
multi.responses[:callback][:b].response_header.status.should eql(200)
multi.responses[:callback][:b].req.method.should eql("GET")
multi.responses[:callback][:b].response_header["CONTENT_TYPE"].should eql("text/plain")
multi.responses[:callback][:c].response_header.status.should eql(200)
multi.responses[:callback][:c].req.method.should eql("GET")
multi.responses[:callback][:c].response_header["CONTENT_TYPE"].should eql("application/json")
multi.responses[:callback][:d].response_header.status.should eql(200)
multi.responses[:callback][:d].req.method.should eql("GET")
multi.responses[:callback][:d].response_header["CONTENT_TYPE"].should eql("application/yaml")
multi.responses[:callback][:e].response_header.status.should eql(200)
multi.responses[:callback][:e].req.method.should eql("GET")
multi.responses[:callback][:e].response_header["CONTENT_TYPE"].should eql("application/xml")
multi.responses[:callback][:f].response_header.status.should eql(200)
multi.responses[:callback][:f].req.method.should eql("GET")
multi.responses[:callback][:f].response_header["CONTENT_TYPE"].should eql("text/x-json")
multi.responses[:callback][:g].response_header.status.should eql(200)
multi.responses[:callback][:g].req.method.should eql("GET")
multi.responses[:callback][:g].response_header["CONTENT_TYPE"].should eql("text/x-yaml")
EventMachine.stop
end
end
end
end
it "should return detailed channels statistics for many channels" do
channel = 'ch_test_get_detailed_channels_statistics_to_many_channels_'
body = 'body'
number_of_channels = 20000
nginx_run_server(config.merge(:shared_memory_size => '200m', :keepalive => "on"), :timeout => 10) do |conf|
#create channels
0.step(number_of_channels - 1, 1000) do |i|
socket = open_socket(nginx_host, nginx_port)
1.upto(1000) do |j|
headers, body = post_in_socket("/pub?id=#{channel}#{i + j}", body, socket, "}\r\n")
headers.should include("HTTP/1.1 200 OK")
end
socket.close
end
EventMachine.run do
pub_2 = EventMachine::HttpRequest.new(nginx_address + '/channels-stats?id=ALL').get :head => headers, :timeout => 30
pub_2.callback do
pub_2.response_header.status.should eql(200)
pub_2.response_header.content_length.should_not eql(0)
response = JSON.parse(pub_2.response)
response["infos"].length.should eql(number_of_channels)
EventMachine.stop
end
end
end
end
it "should return detailed channels statistics for a nonexistent channel using prefix id" do
nginx_run_server(config, :timeout => 5) do |conf|
EventMachine.run do
pub_2 = EventMachine::HttpRequest.new(nginx_address + '/channels-stats?id=prefix_*').get :head => headers, :timeout => 30
pub_2.callback do
pub_2.response_header.status.should eql(200)
pub_2.response_header.content_length.should_not eql(0)
response = JSON.parse(pub_2.response)
response["infos"].length.should eql(0)
EventMachine.stop
end
end
end
end
it "should return detailed channels statistics for an existent channel using prefix id" do
channel = 'ch_test_get_detailed_channels_statistics_to_existing_channel_using_prefix'
channel_1 = 'another_ch_test_get_detailed_channels_statistics_to_existing_channel_using_prefix'
body = 'body'
nginx_run_server(config, :timeout => 5) do |conf|
#create channels
publish_message(channel, headers, body)
publish_message(channel_1, headers, body)
EventMachine.run do
pub_2 = EventMachine::HttpRequest.new(nginx_address + '/channels-stats?id=ch_test_*').get :head => headers, :timeout => 30
pub_2.callback do
pub_2.response_header.status.should eql(200)
pub_2.response_header.content_length.should_not eql(0)
response = JSON.parse(pub_2.response)
response["infos"].length.should eql(1)
response["infos"][0]["channel"].to_s.should eql(channel)
response["infos"][0]["published_messages"].to_i.should eql(1)
response["infos"][0]["stored_messages"].to_i.should eql(1)
response["infos"][0]["subscribers"].to_i.should eql(0)
EventMachine.stop
end
end
end
end
it "should return detailed channels statistics using prefix id with same behavior as ALL" do
channel = 'ch_test_get_detailed_channels_statistics_using_prefix_as_same_behavior_ALL'
channel_1 = 'another_ch_test_get_detailed_channels_statistics_using_prefix_as_same_behavior_ALL'
body = 'body'
nginx_run_server(config, :timeout => 5) do |conf|
#create channels
publish_message(channel, headers, body)
publish_message(channel_1, headers, body)
EventMachine.run do
pub_2 = EventMachine::HttpRequest.new(nginx_address + '/channels-stats?id=*').get :head => headers, :timeout => 30
pub_2.callback do
pub_2.response_header.status.should eql(200)
pub_2.response_header.content_length.should_not eql(0)
response = JSON.parse(pub_2.response)
response["infos"].length.should eql(2)
response["infos"][0]["channel"].to_s.should eql(channel)
response["infos"][0]["published_messages"].to_i.should eql(1)
response["infos"][0]["stored_messages"].to_i.should eql(1)
response["infos"][0]["subscribers"].to_i.should eql(0)
response["infos"][1]["channel"].to_s.should eql(channel_1)
response["infos"][1]["published_messages"].to_i.should eql(1)
response["infos"][1]["stored_messages"].to_i.should eql(1)
response["infos"][1]["subscribers"].to_i.should eql(0)
EventMachine.stop
end
end
end
end
it "should return detailed channels statistics for an existent broadcast channel using prefix id" do
channel = 'bd_test_get_detailed_channels_statistics_to_existing_broadcast_channel_using_prefix'
body = 'body'
nginx_run_server(config.merge(:broadcast_channel_prefix => 'bd_', :broadcast_channel_max_qtd => 1), :timeout => 5) do |conf|
#create channels
publish_message(channel, headers, body)
EventMachine.run do
pub_2 = EventMachine::HttpRequest.new(nginx_address + '/channels-stats?id=bd_test_*').get :head => headers, :timeout => 30
pub_2.callback do
pub_2.response_header.status.should eql(200)
pub_2.response_header.content_length.should_not eql(0)
response = JSON.parse(pub_2.response)
response["infos"].length.should eql(1)
response["channels"].to_i.should eql(0)
response["broadcast_channels"].to_i.should eql(1)
response["infos"][0]["channel"].to_s.should eql(channel)
response["infos"][0]["published_messages"].to_i.should eql(1)
response["infos"][0]["stored_messages"].to_i.should eql(1)
response["infos"][0]["subscribers"].to_i.should eql(0)
EventMachine.stop
end
end
end
end
it "should return detailed channels statistics for an existent channel using prefix id with subscriber" do
channel = 'ch_test_detailed_channels_statistics_to_existing_channel_with_subscriber_using_prefix'
body = 'body'
nginx_run_server(config, :timeout => 5) do |conf|
create_channel_by_subscribe(channel, headers) do
pub_1 = EventMachine::HttpRequest.new(nginx_address + '/channels-stats?id=ch_test_*').get :head => headers, :timeout => 30
pub_1.callback do
pub_1.response_header.status.should eql(200)
pub_1.response_header.content_length.should_not eql(0)
response = JSON.parse(pub_1.response)
response["infos"].length.should eql(1)
response["infos"][0]["channel"].to_s.should eql(channel)
response["infos"][0]["published_messages"].to_i.should eql(0)
response["infos"][0]["stored_messages"].to_i.should eql(0)
response["infos"][0]["subscribers"].to_i.should eql(1)
EventMachine.stop
end
end
end
end
it "should return detailed channels statistics for many channels using prefix id" do
channel = 'ch_test_get_detailed_channels_statistics_to_many_channels_using_prefix_'
body = 'body'
number_of_channels = 20000
nginx_run_server(config.merge(:shared_memory_size => '200m', :keepalive => "on"), :timeout => 10) do |conf|
#create channels
0.step(number_of_channels - 1, 1000) do |i|
socket = open_socket(nginx_host, nginx_port)
1.upto(1000) do |j|
headers, body = post_in_socket("/pub?id=#{channel}#{i + j}", body, socket, "}\r\n")
headers.should include("HTTP/1.1 200 OK")
end
socket.close
end
EventMachine.run do
pub_2 = EventMachine::HttpRequest.new(nginx_address + '/channels-stats?id=ch_test_get_detailed_channels_statistics_to_many_channels_using_prefix_10*').get :head => headers, :timeout => 30
pub_2.callback do
pub_2.response_header.status.should eql(200)
pub_2.response_header.content_length.should_not eql(0)
response = JSON.parse(pub_2.response)
response["infos"].length.should eql(1111)
EventMachine.stop
end
end
end
end
it "should return uptime in detailed channels statistics" do
channel = 'ch_test_get_uptime_in_detailed_channels_statistics'
body = 'body'
nginx_run_server(config, :timeout => 5) do |conf|
#create channel
publish_message(channel, headers, body)
EventMachine.run do
pub_2 = EventMachine::HttpRequest.new(nginx_address + '/channels-stats?id=ALL').get :head => headers, :timeout => 30
pub_2.callback do
pub_2.response_header.status.should eql(200)
pub_2.response_header.content_length.should_not eql(0)
response = JSON.parse(pub_2.response)
response["hostname"].to_s.should_not be_empty
response["time"].to_s.should_not be_empty
response["channels"].to_s.should_not be_empty
response["broadcast_channels"].to_s.should_not be_empty
response["uptime"].to_s.should_not be_empty
response["infos"].to_s.should_not be_empty
sleep(2)
pub_3 = EventMachine::HttpRequest.new(nginx_address + '/channels-stats?id=ALL').get :head => headers, :timeout => 30
pub_3.callback do
pub_3.response_header.status.should eql(200)
pub_3.response_header.content_length.should_not eql(0)
response = JSON.parse(pub_3.response)
response["uptime"].to_i.should be_in_the_interval(2, 3)
EventMachine.stop
end
end
end
end
end
it "should return uptime in summarized channels statistics" do
channel = 'ch_test_get_uptime_in_summarized_channels_statistics'
body = 'body'
nginx_run_server(config, :timeout => 5) do |conf|
#create channel
publish_message(channel, headers, body)
EventMachine.run do
pub_2 = EventMachine::HttpRequest.new(nginx_address + '/channels-stats').get :head => headers, :timeout => 30
pub_2.callback do
pub_2.response_header.status.should eql(200)
pub_2.response_header.content_length.should_not eql(0)
response = JSON.parse(pub_2.response)
response["hostname"].to_s.should_not be_empty
response["time"].to_s.should_not be_empty
response["channels"].to_s.should_not be_empty
response["broadcast_channels"].to_s.should_not be_empty
response["subscribers"].to_s.should_not be_empty
response["uptime"].to_s.should_not be_empty
response["by_worker"].to_s.should_not be_empty
response["by_worker"][0]["pid"].to_s.should_not be_empty
response["by_worker"][0]["subscribers"].to_s.should_not be_empty
response["by_worker"][0]["uptime"].to_s.should_not be_empty
sleep(2)
pub_3 = EventMachine::HttpRequest.new(nginx_address + '/channels-stats').get :head => headers, :timeout => 30
pub_3.callback do
pub_3.response_header.status.should eql(200)
pub_3.response_header.content_length.should_not eql(0)
response = JSON.parse(pub_3.response)
response["uptime"].to_i.should be_in_the_interval(2, 3)
response["by_worker"][0]["uptime"].to_i.should be_in_the_interval(2, 3)
EventMachine.stop
end
end
end
end
end
end
require 'spec_helper'
describe "Cleanup Memory" do
workers = 1
old_cld_trap = nil
before do
workers = ENV['NGINX_WORKERS']
ENV['NGINX_WORKERS'] = '1'
old_cld_trap = Signal.trap("CLD", "IGNORE")
end
after do
ENV['NGINX_WORKERS'] = workers
Signal.trap("CLD", old_cld_trap)
end
shared_examples_for "executing on normal conditions" do
it "should cleanup memory used for published message" do
channel = 'ch_test_message_cleanup'
body = 'message to create a channel'
nginx_run_server(config.merge(:max_messages_stored_per_channel => 100), :timeout => test_timeout) do |conf|
stored_messages_setp_1 = 0
published_messages_setp_1 = 0
published_messages_setp_2 = 0
EventMachine.run do
# ensure channel will not be cleaned up
sub_1 = EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel.to_s).get :head => headers, :timeout => 60
fill_memory_timer = EventMachine::PeriodicTimer.new(0.001) do
publish_message_inline_with_callbacks(channel, headers, body, {
:error => Proc.new do |status, content|
fill_memory_timer.cancel
pub_2 = EventMachine::HttpRequest.new(nginx_address + '/channels-stats?id=' + channel.to_s).get :head => headers, :timeout => 60
pub_2.callback do
fail("Don't received the stats") if (pub_2.response_header.status != 200) || (pub_2.response_header.content_length == 0)
result = JSON.parse(pub_2.response)
stored_messages_setp_1 = result["stored_messages"].to_i
published_messages_setp_1 = result["published_messages"].to_i
stored_messages_setp_1.should eql(conf.max_messages_stored_per_channel)
published_messages_setp_1.should be > (conf.max_messages_stored_per_channel)
stored_messages_setp_1.should_not eql(0)
EM.add_timer(45) do
pub_3 = EventMachine::HttpRequest.new(nginx_address + '/channels-stats?id=' + channel.to_s).get :head => headers, :timeout => 60
pub_3.callback do
fail("Don't received the stats") if (pub_3.response_header.status != 200) || (pub_3.response_header.content_length == 0)
JSON.parse(pub_3.response)["stored_messages"].to_i.should eql(0)
execute_changes_on_environment(conf) do
# connect a subscriber on new worker
sub_1 = EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel.to_s).get :head => headers, :timeout => 60
EM.add_timer(35) do
fill_memory_timer = EventMachine::PeriodicTimer.new(0.001) do
publish_message_inline_with_callbacks(channel, headers, body, {
:error => Proc.new do |status2, content2|
fill_memory_timer.cancel
pub_2 = EventMachine::HttpRequest.new(nginx_address + '/channels-stats?id=' + channel.to_s).get :head => headers, :timeout => 60
pub_2.callback do
fail("Don't received the stats") if (pub_2.response_header.status != 200) || (pub_2.response_header.content_length == 0)
published_messages_setp_2 = JSON.parse(pub_2.response)["published_messages"].to_i
fail("Don't publish more messages") if published_messages_setp_1 == published_messages_setp_2
EM.add_timer(50) do
pub_3 = EventMachine::HttpRequest.new(nginx_address + '/channels-stats?id=' + channel.to_s).get :head => headers, :timeout => 60
pub_3.callback do
fail("Don't received the stats") if (pub_3.response_header.status != 200) || (pub_3.response_header.content_length == 0)
JSON.parse(pub_3.response)["stored_messages"].to_i.should eql(0)
fill_memory_timer = EventMachine::PeriodicTimer.new(0.001) do
publish_message_inline_with_callbacks(channel, headers, body, {
:error => Proc.new do |status3, content3|
fill_memory_timer.cancel
pub_4 = EventMachine::HttpRequest.new(nginx_address + '/channels-stats?id=' + channel.to_s).get :head => headers, :timeout => 60
pub_4.callback do
fail("Don't received the stats") if (pub_4.response_header.status != 200) || (pub_4.response_header.content_length == 0)
result = JSON.parse(pub_4.response)
result["stored_messages"].to_i.should eql(stored_messages_setp_1)
(result["published_messages"].to_i - published_messages_setp_2).should eql(published_messages_setp_1)
EventMachine.stop
end
end
})
end
end
end
end
end
})
end
end
end
end
end
end
end
})
end
end
end
end
it "should discard old messages" do
channel = 'ch_test_discard_old_messages'
body = 'message to create a channel'
messages_to_publish = 10
count = 0
stored_messages_setp_1 = 0
nginx_run_server(config, :timeout => test_timeout) do |conf|
EventMachine.run do
fill_memory_timer = EventMachine::PeriodicTimer.new(messages_to_publish / 12.to_f) do # publish messages before cleanup timer be executed
if (count < messages_to_publish)
publish_message_inline(channel, headers, body)
elsif (count == messages_to_publish)
pub_1 = EventMachine::HttpRequest.new(nginx_address + '/channels-stats?id=' + channel.to_s).get :head => headers, :timeout => 60
pub_1.callback do
fill_memory_timer.cancel
fail("Don't received the stats") if (pub_1.response_header.status != 200) || (pub_1.response_header.content_length == 0)
stored_messages_setp_1 = JSON.parse(pub_1.response)["stored_messages"].to_i
stored_messages_setp_1.should eql(messages_to_publish)
execute_changes_on_environment(conf) do
EM.add_timer(5) do # wait cleanup timer to be executed one time
pub_2 = EventMachine::HttpRequest.new(nginx_address + '/channels-stats?id=' + channel.to_s).get :head => headers, :timeout => 60
pub_2.callback do
fail("Don't received the stats") if (pub_2.response_header.status != 200) || (pub_2.response_header.content_length == 0)
stored_messages_setp_2 = JSON.parse(pub_2.response)["stored_messages"].to_i
stored_messages_setp_2.should be <= stored_messages_setp_1
stored_messages_setp_2.should be > 0
EventMachine.stop
end
end
end
end
end
count += 1
end
end
end
end
it "should cleanup message memory without max messages stored per channelXXX" do
channel = 'ch_test_message_cleanup_without_max_messages_stored_per_chann'
body = 'message to create a channel'
nginx_run_server(config, :timeout => test_timeout) do |conf|
stored_messages_setp_1 = 0
published_messages_setp_1 = 0
published_messages_setp_2 = 0
EventMachine.run do
# ensure channel will not be cleaned up
sub_1 = EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel.to_s).get :head => headers, :timeout => 60
fill_memory_timer = EventMachine::PeriodicTimer.new(0.001) do
publish_message_inline_with_callbacks(channel, headers, body, {
:error => Proc.new do |status, content|
fill_memory_timer.cancel
pub_2 = EventMachine::HttpRequest.new(nginx_address + '/channels-stats?id=' + channel.to_s).get :head => headers, :timeout => 60
pub_2.callback do
fail("Don't received the stats") if (pub_2.response_header.status != 200) || (pub_2.response_header.content_length == 0)
result = JSON.parse(pub_2.response)
stored_messages_setp_1 = result["stored_messages"].to_i
published_messages_setp_1 = result["published_messages"].to_i
fail("Limited the number of stored messages") if stored_messages_setp_1 <= 100
fail("Don't create any message") if stored_messages_setp_1 == 0
execute_changes_on_environment(conf) do
# connect a subscriber on new worker
sub_1 = EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel.to_s).get :head => headers, :timeout => 60
EM.add_timer(50) do
fill_memory_timer = EventMachine::PeriodicTimer.new(0.001) do
publish_message_inline_with_callbacks(channel, headers, body, {
:error => Proc.new do |status2, content2|
fill_memory_timer.cancel
pub_2 = EventMachine::HttpRequest.new(nginx_address + '/channels-stats?id=' + channel.to_s).get :head => headers, :timeout => 60
pub_2.callback do
fail("Don't received the stats") if (pub_2.response_header.status != 200) || (pub_2.response_header.content_length == 0)
published_messages_setp_2 = JSON.parse(pub_2.response)["published_messages"].to_i
fail("Don't publish more messages") if published_messages_setp_1 == published_messages_setp_2
EM.add_timer(60) do
pub_3 = EventMachine::HttpRequest.new(nginx_address + '/channels-stats?id=' + channel.to_s).get :head => headers, :timeout => 60
pub_3.callback do
fail("Don't received the stats") if (pub_3.response_header.status != 200) || (pub_3.response_header.content_length == 0)
JSON.parse(pub_3.response)["stored_messages"].to_i.should eql(0)
fill_memory_timer = EventMachine::PeriodicTimer.new(0.001) do
publish_message_inline_with_callbacks(channel, headers, body, {
:error => Proc.new do |status3, content3|
pub_4 = EventMachine::HttpRequest.new(nginx_address + '/channels-stats?id=' + channel.to_s).get :head => headers, :timeout => 60
pub_4.callback do
fail("Don't received the stats") if (pub_4.response_header.status != 200) || (pub_4.response_header.content_length == 0)
result = JSON.parse(pub_4.response)
result["stored_messages"].to_i.should eql(stored_messages_setp_1)
(result["published_messages"].to_i - published_messages_setp_2).should eql(published_messages_setp_1)
EventMachine.stop
end
end
})
end
end
end
end
end
})
end
end
end
end
end
})
end
end
end
end
it "should cleanup memory used for create channels" do
channel = 'ch_test_channel_cleanup_'
body = 'message to create a channel'
nginx_run_server(config.merge(:message_ttl => '2s'), :timeout => test_timeout) do |conf|
channels_setp_1 = 0
channels_setp_2 = 0
published_messages_setp_1 = 0
EventMachine.run do
i = 0
fill_memory_timer = EventMachine::PeriodicTimer.new(0.001) do
publish_message_inline_with_callbacks(channel + i.to_s, headers, body, {
:error => Proc.new do |status, content|
fill_memory_timer.cancel
pub_2 = EventMachine::HttpRequest.new(nginx_address + '/channels-stats').get :head => headers, :timeout => 60
pub_2.callback do
fail("Don't received the stats") if (pub_2.response_header.status != 200) || (pub_2.response_header.content_length == 0)
channels_setp_1 = JSON.parse(pub_2.response)["channels"].to_i
fail("Don't create any channel") if channels_setp_1 == 0
execute_changes_on_environment(conf) do
EM.add_timer(35) do
j = 0
fill_memory_timer = EventMachine::PeriodicTimer.new(0.001) do
publish_message_inline_with_callbacks(channel + j.to_s, headers, body, {
:error => Proc.new do |status2, content2|
fill_memory_timer.cancel
pub_2 = EventMachine::HttpRequest.new(nginx_address + '/channels-stats').get :head => headers, :timeout => 60
pub_2.callback do
fail("Don't received the stats") if (pub_2.response_header.status != 200) || (pub_2.response_header.content_length == 0)
fail("Don't create more channel") if published_messages_setp_1 == JSON.parse(pub_2.response)["published_messages"].to_i
EM.add_timer(40) do
pub_3 = EventMachine::HttpRequest.new(nginx_address + '/channels-stats').get :head => headers, :timeout => 60
pub_3.callback do
fail("Don't received the stats") if (pub_3.response_header.status != 200) || (pub_3.response_header.content_length == 0)
channels = JSON.parse(pub_3.response)["channels"].to_i
channels.should eql(0)
EM.add_timer(35) do
i = 0
fill_memory_timer = EventMachine::PeriodicTimer.new(0.001) do
publish_message_inline_with_callbacks(channel + i.to_s, headers, body, {
:error => Proc.new do |status3, content3|
fill_memory_timer.cancel
pub_4 = EventMachine::HttpRequest.new(nginx_address + '/channels-stats').get :head => headers, :timeout => 60
pub_4.callback do
fail("Don't received the stats") if (pub_4.response_header.status != 200) || (pub_4.response_header.content_length == 0)
channels_setp_2 = JSON.parse(pub_4.response)["channels"].to_i
channels_setp_2.should eql(channels_setp_1)
EventMachine.stop
end
end
})
i += 1
end
end
end
end
end
end
})
j += 1
end
end
end
end
end
})
i += 1
end
end
end
end
it "should cleanup memory used for publish messages with store 'off' and with subscriber" do
channel = 'ch_test_message_cleanup_with_store_off_with_subscriber'
body = 'message to create a channel'
nginx_run_server(config.merge(:store_messages => 'off'), :timeout => test_timeout) do |conf|
published_messages_setp_1 = 0
published_messages_setp_2 = 0
EventMachine.run do
# ensure channel will not be cleaned up
sub_1 = EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel.to_s).get :head => headers, :timeout => 60
fill_memory_timer = EventMachine::PeriodicTimer.new(0.001) do
publish_message_inline_with_callbacks(channel, headers, body, {
:error => Proc.new do |status, content|
fill_memory_timer.cancel
pub_2 = EventMachine::HttpRequest.new(nginx_address + '/channels-stats?id=' + channel.to_s).get :head => headers, :timeout => 60
pub_2.callback do
fail("Don't received the stats") if (pub_2.response_header.status != 200) || (pub_2.response_header.content_length == 0)
result = JSON.parse(pub_2.response)
published_messages_setp_1 = result["published_messages"].to_i
execute_changes_on_environment(conf) do
# connect a subscriber on new worker
sub_1 = EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel.to_s).get :head => headers, :timeout => 60
EM.add_timer(35) do
fill_memory_timer = EventMachine::PeriodicTimer.new(0.001) do
publish_message_inline_with_callbacks(channel, headers, body, {
:error => Proc.new do |status2, content2|
fill_memory_timer.cancel
pub_2 = EventMachine::HttpRequest.new(nginx_address + '/channels-stats?id=' + channel.to_s).get :head => headers, :timeout => 60
pub_2.callback do
fail("Don't received the stats") if (pub_2.response_header.status != 200) || (pub_2.response_header.content_length == 0)
published_messages_setp_2 = JSON.parse(pub_2.response)["published_messages"].to_i
published_messages_setp_2.should_not eql(published_messages_setp_1)
EM.add_timer(35) do
pub_3 = EventMachine::HttpRequest.new(nginx_address + '/channels-stats?id=' + channel.to_s).get :head => headers, :timeout => 60
pub_3.callback do
fail("Don't received the stats") if (pub_3.response_header.status != 200) || (pub_3.response_header.content_length == 0)
JSON.parse(pub_3.response)["channels"].to_i.should eql(0)
fill_memory_timer = EventMachine::PeriodicTimer.new(0.001) do
publish_message_inline_with_callbacks(channel, headers, body, {
:error => Proc.new do |status3, content3|
pub_4 = EventMachine::HttpRequest.new(nginx_address + '/channels-stats?id=' + channel.to_s).get :head => headers, :timeout => 60
pub_4.callback do
fail("Don't received the stats") if (pub_4.response_header.status != 200) || (pub_4.response_header.content_length == 0)
result = JSON.parse(pub_4.response)
(result["published_messages"].to_i - published_messages_setp_2).should eql(published_messages_setp_1)
EventMachine.stop
end
end
})
end
end
end
end
end
})
end
end
end
end
end
})
end
end
end
end
it "should cleanup memory used for publish messages with store 'off' and without subscriber" do
channel = 'ch_test_message_cleanup_with_store_off_without_subscriber'
body = 'message to create a channel'
nginx_run_server(config.merge(:store_messages => 'off'), :timeout => test_timeout) do |conf|
published_messages_setp_1 = 0
published_messages_setp_2 = 0
EventMachine.run do
i = 0
fill_memory_timer = EventMachine::PeriodicTimer.new(0.001) do
publish_message_inline_with_callbacks(channel + i.to_s, headers, body, {
:error => Proc.new do |status, content|
fill_memory_timer.cancel
pub_2 = EventMachine::HttpRequest.new(nginx_address + '/channels-stats').get :head => headers, :timeout => 60
pub_2.callback do
fail("Don't received the stats") if (pub_2.response_header.status != 200) || (pub_2.response_header.content_length == 0)
result = JSON.parse(pub_2.response)
published_messages_setp_1 = result["published_messages"].to_i
execute_changes_on_environment(conf) do
EM.add_timer(35) do
j = 0
fill_memory_timer = EventMachine::PeriodicTimer.new(0.001) do
publish_message_inline_with_callbacks(channel + j.to_s, headers, body, {
:error => Proc.new do |status2, content2|
fill_memory_timer.cancel
pub_2 = EventMachine::HttpRequest.new(nginx_address + '/channels-stats').get :head => headers, :timeout => 60
pub_2.callback do
fail("Don't received the stats") if (pub_2.response_header.status != 200) || (pub_2.response_header.content_length == 0)
published_messages_setp_2 = JSON.parse(pub_2.response)["published_messages"].to_i
fail("Don't create more channel") if published_messages_setp_1 == published_messages_setp_2
EM.add_timer(35) do
pub_3 = EventMachine::HttpRequest.new(nginx_address + '/channels-stats').get :head => headers, :timeout => 60
pub_3.callback do
fail("Don't received the stats") if (pub_3.response_header.status != 200) || (pub_3.response_header.content_length == 0)
JSON.parse(pub_3.response)["channels"].to_i.should eql(0)
EM.add_timer(35) do
fill_memory_timer = EventMachine::PeriodicTimer.new(0.001) do
publish_message_inline_with_callbacks(channel + i.to_s, headers, body, {
:error => Proc.new do |status3, content3|
pub_4 = EventMachine::HttpRequest.new(nginx_address + '/channels-stats').get :head => headers, :timeout => 60
pub_4.callback do
fail("Don't received the stats") if (pub_4.response_header.status != 200) || (pub_4.response_header.content_length == 0)
result = JSON.parse(pub_4.response)
(result["published_messages"].to_i - published_messages_setp_2).should eql(published_messages_setp_1)
EventMachine.stop
end
end
})
i += 1
end
end
end
end
end
end
})
j += 1
end
end
end
end
end
})
i += 1
end
end
end
end
it "should cleanup memory used after delete created channels" do
channel = 'ch_test_channel_cleanup_after_delete'
body = 'message to create a channel'
nginx_run_server(config.merge(:publisher_mode => 'admin'), :timeout => test_timeout) do |conf|
published_messages_setp_1 = 0
EventMachine.run do
i = 0
fill_memory_timer = EventMachine::PeriodicTimer.new(0.001) do
pub_1 = EventMachine::HttpRequest.new(nginx_address + '/pub?id=' + channel.to_s + i.to_s).post :body => body, :head => headers, :timeout => 30
pub_1.callback do
if pub_1.response_header.status == 500
fill_memory_timer.cancel
i.times do |j|
pub = EventMachine::HttpRequest.new(nginx_address + '/pub?id=' + channel.to_s + j.to_s).delete :head => headers, :timeout => 30
end
pub_2 = EventMachine::HttpRequest.new(nginx_address + '/channels-stats').get :head => headers, :timeout => 60
pub_2.callback do
fail("Don't received the stats") if (pub_2.response_header.status != 200) || (pub_2.response_header.content_length == 0)
result = JSON.parse(pub_2.response)
published_messages_setp_1 = result["published_messages"].to_i
fail("Don't create any message") if published_messages_setp_1 == 0
execute_changes_on_environment(conf) do
EM.add_timer(45) do
i = 0
fill_memory_timer = EventMachine::PeriodicTimer.new(0.001) do
pub_1 = EventMachine::HttpRequest.new(nginx_address + '/pub?id=' + channel.to_s + i.to_s).post :body => body, :head => headers, :timeout => 30
pub_1.callback do
if pub_1.response_header.status == 500
fill_memory_timer.cancel
pub_2 = EventMachine::HttpRequest.new(nginx_address + '/channels-stats').get :head => headers, :timeout => 60
pub_2.callback do
fail("Don't received the stats") if (pub_2.response_header.status != 200) || (pub_2.response_header.content_length == 0)
result = JSON.parse(pub_2.response)
(result["published_messages"].to_i / 2).should eql(published_messages_setp_1)
EventMachine.stop
end
end
end
i += 1
end
end
end
end
end
end
i += 1
end
end
end
end
it "should cleanup memory used after delete created channels with same id" do
channel = 'ch_test_channel_cleanup_after_delete_same_id'
body = 'message to create a channel'
nginx_run_server(config.merge(:publisher_mode => 'admin'), :timeout => test_timeout) do |conf|
published_messages_setp_1 = 0
EventMachine.run do
create_and_delete_channel_in_loop(channel, body, headers) do
pub_2 = EventMachine::HttpRequest.new(nginx_address + '/channels-stats').get :head => headers, :timeout => 60
pub_2.callback do
fail("Don't received the stats") if (pub_2.response_header.status != 200) || (pub_2.response_header.content_length == 0)
result = JSON.parse(pub_2.response)
published_messages_setp_1 = result["published_messages"].to_i
fail("Don't create any message") if published_messages_setp_1 == 0
execute_changes_on_environment(conf) do
EM.add_timer(40) do
create_and_delete_channel_in_loop(channel, body, headers) do
pub_2 = EventMachine::HttpRequest.new(nginx_address + '/channels-stats').get :head => headers, :timeout => 60
pub_2.callback do
fail("Don't received the stats") if (pub_2.response_header.status != 200) || (pub_2.response_header.content_length == 0)
result = JSON.parse(pub_2.response)
(result["published_messages"].to_i / 2).should eql(published_messages_setp_1)
EventMachine.stop
end
end
end
end
end
end
end
end
end
end
def create_and_delete_channel(channel, body, headers, &block)
pub_1 = EventMachine::HttpRequest.new(nginx_address + '/pub?id=' + channel.to_s).post :body => body, :head => headers, :timeout => 30
pub_1.callback do
if pub_1.response_header.status == 200
pub = EventMachine::HttpRequest.new(nginx_address + '/pub?id=' + channel.to_s).delete :head => headers, :timeout => 30
pub.callback do
block.call((pub.response_header.status == 200) ? :success : :error)
end
else
block.call(:error)
end
end
end
def create_and_delete_channel_in_loop(channel, body, headers, &block)
create_and_delete_channel(channel, body, headers) do |status|
if status == :success
create_and_delete_channel_in_loop(channel, body, headers) do
yield
end
else
block.call unless block.nil?
end
end
end
let(:test_timeout) { 260 }
let(:config) do
{
:master_process => 'on',
:daemon => 'on',
:shared_memory_cleanup_objects_ttl => '30s',
:shared_memory_size => "129k",
:message_ttl => '10s',
:max_messages_stored_per_channel => nil
}
end
let(:headers) do
{'accept' => 'text/html'}
end
context "when nothing strange occur" do
def execute_changes_on_environment(conf, &block)
#nothing strange happens
block.call
end
it_should_behave_like "executing on normal conditions"
end
context "when a worker is killed" do
def execute_changes_on_environment(conf, &block)
pub = EventMachine::HttpRequest.new(nginx_address + '/channels-stats').get :timeout => 30
pub.callback do
fail("Don't received the stats") if (pub.response_header.status != 200) || (pub.response_header.content_length == 0)
resp_1 = JSON.parse(pub.response)
resp_1["by_worker"].count.should eql(1)
pid = resp_1["by_worker"][0]['pid'].to_i
# send kill signal
`kill -9 #{ pid } > /dev/null 2>&1`
while `ps -p #{ pid } > /dev/null 2>&1; echo $?`.to_i == 0
sleep(0.1)
end
block.call unless block.nil?
end
end
it_should_behave_like "executing on normal conditions"
end
context "when the server is reloaded" do
def execute_changes_on_environment(conf, &block)
pub = EventMachine::HttpRequest.new(nginx_address + '/channels-stats').get :timeout => 30
pub.callback do
fail("Don't received the stats") if (pub.response_header.status != 200) || (pub.response_header.content_length == 0)
resp_1 = JSON.parse(pub.response)
resp_1["by_worker"].count.should eql(1)
pid = resp_1["by_worker"][0]['pid'].to_i
# send reload signal
`#{ nginx_executable } -c #{ conf.configuration_filename } -s reload > /dev/null 2>&1`
while `ps -p #{ pid } > /dev/null 2>&1; echo $?`.to_i == 0
sleep(0.1)
end
block.call unless block.nil?
end
end
it_should_behave_like "executing on normal conditions"
end
end
require 'spec_helper'
describe "Keepalive" do
let(:config) do
{
:shared_memory_size => '256m',
:keepalive => "on",
:header_template => '',
:message_template => '~text~',
:footer_template => ''
}
end
it "should create many channels on the same socket" do
channel = 'ch_test_create_many_channels_'
body = 'channel started'
channels_to_be_created = 4000
nginx_run_server(config, :timeout => 25) do |conf|
0.step(channels_to_be_created - 1, 500) do |i|
socket = open_socket(nginx_host, nginx_port)
1.upto(500) do |j|
headers, body = post_in_socket("/pub?id=#{channel}#{i + j}", body, socket, "}\r\n")
headers.should include("HTTP/1.1 200 OK")
end
socket.close
end
end
end
it "should execute different operations using the same socket" do
channel = 'ch_test_different_operation_with_keepalive'
content = 'message to be sent'
nginx_run_server(config, :timeout => 5) do |conf|
socket = open_socket(nginx_host, nginx_port)
headers, body = get_in_socket("/pub", socket)
body.should eql("")
headers.should include("No channel id provided.")
headers, body = post_in_socket("/pub?id=#{channel}", content, socket, "}\r\n")
body.should eql("{\"channel\": \"#{channel}\", \"published_messages\": \"1\", \"stored_messages\": \"1\", \"subscribers\": \"0\"}\r\n")
headers, body = get_in_socket("/channels-stats", socket)
body.should match_the_pattern(/"channels": "1", "broadcast_channels": "0", "published_messages": "1", "subscribers": "0", "uptime": "[0-9]*", "by_worker": \[\r\n/)
body.should match_the_pattern(/\{"pid": "[0-9]*", "subscribers": "0", "uptime": "[0-9]*"\}/)
headers, body = get_in_socket("/pub?id=#{channel}", socket)
body.should eql("{\"channel\": \"#{channel}\", \"published_messages\": \"1\", \"stored_messages\": \"1\", \"subscribers\": \"0\"}\r\n")
socket.close
end
end
end
require 'spec_helper'
describe "Measure Memory" do
let(:config) do
{
:shared_memory_size => "2m",
:shared_memory_cleanup_objects_ttl => "60m",
:message_ttl => "60m",
:max_messages_stored_per_channel => nil,
:keepalive => "on",
:header_template => nil,
:message_template => nil,
:footer_template => nil,
:ping_message_interval => nil
}
end
message_estimate_size = 174
channel_estimate_size = 536
subscriber_estimate_size = 200
subscriber_estimate_system_size = 6560
it "should check message size" do
channel = 'ch_test_message_size'
body = '1'
nginx_run_server(config, :timeout => 5) do |conf|
shared_size = conf.shared_memory_size.to_i * 1024 * 1024
post_channel_message = "POST /pub?id=#{channel} HTTP/1.0\r\nContent-Length: #{body.size}\r\n\r\n#{body}"
socket = open_socket(nginx_host, nginx_port)
while (true) do
socket.print(post_channel_message)
resp_headers, resp_body = read_response_on_socket(socket, "}\r\n")
break unless resp_headers.match(/200 OK/)
end
socket.close
EventMachine.run do
pub_2 = EventMachine::HttpRequest.new(nginx_address + '/channels-stats').get
pub_2.callback do
pub_2.response_header.status.should eql(200)
pub_2.response_header.content_length.should_not eql(0)
resp = JSON.parse(pub_2.response)
expected_message = shared_size / (message_estimate_size + body.size)
resp["published_messages"].to_i.should be_within(20).of(expected_message)
EventMachine.stop
end
end
end
end
it "should check channel size" do
body = '1'
nginx_run_server(config, :timeout => 1500) do |conf|
shared_size = conf.shared_memory_size.to_i * 1024 * 1024
socket = open_socket(nginx_host, nginx_port)
channel = 1000
while (true) do
post_channel_message = "POST /pub?id=#{channel} HTTP/1.0\r\nContent-Length: #{body.size}\r\n\r\n#{body}"
socket.print(post_channel_message)
resp_headers, resp_body = read_response_on_socket(socket, "}\r\n")
break unless resp_headers.match(/200 OK/)
channel += 1
end
socket.close
EventMachine.run do
pub_2 = EventMachine::HttpRequest.new(nginx_address + '/channels-stats').get
pub_2.callback do
pub_2.response_header.status.should eql(200)
pub_2.response_header.content_length.should_not eql(0)
resp = JSON.parse(pub_2.response)
expected_channel = (shared_size - ((body.size + message_estimate_size) * resp["published_messages"].to_i)) / (channel_estimate_size + 4) # 4 channel id size
resp["channels"].to_i.should be_within(10).of(expected_channel)
EventMachine.stop
end
end
end
end
it "should check subscriber size" do
nginx_run_server(config.merge({:shared_memory_size => "300k", :header_template => "H"}), :timeout => 5) do |conf|
shared_size = conf.shared_memory_size.to_i * 1024 #shm size is in kbytes for this test
EventMachine.run do
subscriber_in_loop(1000, headers) do
pub_2 = EventMachine::HttpRequest.new(nginx_address + '/channels-stats').get :head => headers
pub_2.callback do
pub_2.response_header.status.should eql(200)
pub_2.response_header.content_length.should_not eql(0)
resp = JSON.parse(pub_2.response)
expected_subscriber = (shared_size - ((channel_estimate_size + 4) * resp["channels"].to_i)) / subscriber_estimate_size # 4 channel id size
resp["subscribers"].to_i.should be_within(10).of(expected_subscriber)
EventMachine.stop
end
end
end
end
end
it "should check subscriber system size" do
channel = 'ch_test_subscriber_system_size'
body = '1'
nginx_run_server(config.merge({:header_template => "H"}), :timeout => 15) do |conf|
#warming up
EventMachine.run do
sub = EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel.to_i.to_s).get :head => headers, :body => body
sub.stream do |chunk|
EventMachine.stop
end
end
per_subscriber = 0
EventMachine.run do
memory_1 = `ps -eo rss,cmd | grep -E 'ngin[xX] -c '`.split(' ')[0].to_i
subscriber_in_loop_with_limit(channel, headers, body, 1000, 1499) do
sleep(1)
memory_2 = `ps -eo rss,cmd | grep -E 'ngin[xX] -c '`.split(' ')[0].to_i
per_subscriber = ((memory_2 - memory_1).to_f / 500) * 1000
EventMachine.stop
end
end
per_subscriber.should be_within(10).of(subscriber_estimate_system_size)
end
end
end
def subscriber_in_loop(channel, headers, &block)
sub = EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel.to_i.to_s).get :head => headers
sub.stream do |chunk|
subscriber_in_loop(channel.to_i + 1, headers) do
yield block
end
end
sub.callback do
block.call
end
end
def subscriber_in_loop_with_limit(channel, headers, body, start, limit, &block)
sub = EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel.to_i.to_s).get :head => headers, :body => body
sub.stream do |chunk|
if start == limit
block.call
EventMachine.stop
end
subscriber_in_loop_with_limit(channel, headers, body, start + 1, limit) do
yield block
end
end
sub.callback do
block.call
end
end
require 'spec_helper'
describe "Send Signals" do
workers = 1
old_cld_trap = nil
before do
workers = ENV['NGINX_WORKERS']
ENV['NGINX_WORKERS'] = '1'
old_cld_trap = Signal.trap("CLD", "IGNORE")
end
after do
ENV['NGINX_WORKERS'] = workers
Signal.trap("CLD", old_cld_trap)
end
let(:config) do
{
:master_process => 'on',
:daemon => 'on',
:header_template => 'HEADER',
:shared_memory_cleanup_objects_ttl => '40s',
:message_ttl => '60s',
:subscriber_connection_ttl => '65s'
}
end
it "should reload normaly when receives HUP signal" do
channel = 'ch_test_send_hup_signal'
body = 'body'
response = response2 = ''
pid = pid2 = 0
nginx_run_server(config, :timeout => 60) do |conf|
EventMachine.run do
# create subscriber
sub_1 = EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel.to_s).get :head => headers, :timeout => 30
sub_1.stream do |chunk|
response = response + chunk
if response.strip == conf.header_template
# check statistics
pub_1 = EventMachine::HttpRequest.new(nginx_address + '/channels-stats').get :head => headers, :timeout => 30
pub_1.callback do
pub_1.response_header.status.should eql(200)
pub_1.response_header.content_length.should_not eql(0)
resp_1 = JSON.parse(pub_1.response)
resp_1.has_key?("channels").should be_true
resp_1["channels"].to_i.should eql(1)
resp_1["by_worker"].count.should eql(1)
pid = resp_1["by_worker"][0]['pid'].to_i
# send reload signal
`#{ nginx_executable } -c #{ conf.configuration_filename } -s reload > /dev/null 2>&1`
end
end
end
conectted_after_reloaded = false
i = 0
# check if first worker die
EM.add_periodic_timer(0.5) do
# check statistics again
pub_4 = EventMachine::HttpRequest.new(nginx_address + '/channels-stats').get :head => headers, :timeout => 30
pub_4.callback do
resp_3 = JSON.parse(pub_4.response)
resp_3.has_key?("by_worker").should be_true
if resp_3["by_worker"].count == 2 && !conectted_after_reloaded
conectted_after_reloaded = true
# publish a message
pub_2 = EventMachine::HttpRequest.new(nginx_address + '/pub?id=' + channel.to_s).post :head => headers, :body => body, :timeout => 30
pub_2.callback do
# add new subscriber
sub_2 = EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel.to_s + '.b1').get :head => headers, :timeout => 30
sub_2.stream do |chunk|
response2 = response2 + chunk
if response2.strip == conf.header_template
# check statistics again
pub_3 = EventMachine::HttpRequest.new(nginx_address + '/channels-stats').get :head => headers, :timeout => 30
pub_3.callback do
resp_2 = JSON.parse(pub_3.response)
resp_2.has_key?("channels").should be_true
resp_2["channels"].to_i.should eql(1)
resp_2["published_messages"].to_i.should eql(1)
resp_2["subscribers"].to_i.should eql(2)
resp_2["by_worker"].count.should eql(2)
end
end
end
end
end
if resp_3["by_worker"].count == 1 && conectted_after_reloaded
resp_3["channels"].to_i.should eql(1)
resp_3["published_messages"].to_i.should eql(1)
resp_3["subscribers"].to_i.should eql(1)
resp_3["by_worker"].count.should eql(1)
pid2 = resp_3["by_worker"][0]['pid'].to_i
pid.should_not eql(pid2)
EventMachine.stop
end
i = i + 1
if i == 120
fail("Worker didn't die in 60 seconds")
EventMachine.stop
end
end
end
end
end
end
it "should ignore changes on shared memory size when doing a reload" do
channel = 'ch_test_reload_with_different_shared_memory_size'
body = 'body'
response = response2 = ''
pid = pid2 = 0
nginx_run_server(config, :timeout => 10) do |conf|
EventMachine.run do
publish_message_inline(channel, {}, body)
# check statistics
pub_1 = EventMachine::HttpRequest.new(nginx_address + '/channels-stats').get :head => headers, :timeout => 30
pub_1.callback do
pub_1.response_header.status.should eql(200)
pub_1.response_header.content_length.should_not eql(0)
resp_1 = JSON.parse(pub_1.response)
resp_1.has_key?("channels").should be_true
resp_1["channels"].to_i.should eql(1)
resp_1["published_messages"].to_i.should eql(1)
conf.configuration[:shared_memory_size] = '20m'
conf.create_configuration_file
# send reload signal
`#{ nginx_executable } -c #{ conf.configuration_filename } -s reload > /dev/null 2>&1`
sleep 5
pub_2 = EventMachine::HttpRequest.new(nginx_address + '/channels-stats').get :head => headers, :timeout => 30
pub_2.callback do
pub_2.response_header.status.should eql(200)
pub_2.response_header.content_length.should_not eql(0)
resp_2 = JSON.parse(pub_2.response)
resp_2.has_key?("channels").should be_true
resp_2["channels"].to_i.should eql(1)
resp_2["published_messages"].to_i.should eql(1)
error_log = File.read(conf.error_log)
error_log.should include("Cannot change memory area size without restart, ignoring change")
EventMachine.stop
end
end
end
end
end
end
require 'spec_helper'
describe "Setup Parameters" do
it "should not accept '0' as ping message interval" do
nginx_test_configuration({:ping_message_interval => 0}).should include("push_stream_ping_message_interval cannot be zero")
end
it "should not accept a blank message template" do
nginx_test_configuration({:message_template => ""}).should include("push_stream_message_template cannot be blank")
end
it "should not accept '0' as subscriber connection ttl" do
nginx_test_configuration({:subscriber_connection_ttl => 0}).should include("push_stream_subscriber_connection_ttl cannot be zero")
end
it "should not accept '0' as long polling subscriber connection ttl" do
nginx_test_configuration({:longpolling_connection_ttl => 0}).should include("push_stream_longpolling_connection_ttl cannot be zero")
end
it "should not accept '0' as max channel id length" do
nginx_test_configuration({:max_channel_id_length => 0}).should include("push_stream_max_channel_id_length cannot be zero")
end
it "should not accept '0' as message ttl" do
nginx_test_configuration({:message_ttl => 0}).should include("push_stream_message_ttl cannot be zero")
end
it "should not accept '0' as max subscribers per channel" do
nginx_test_configuration({:max_subscribers_per_channel => 0}).should include("push_stream_max_subscribers_per_channel cannot be zero")
end
it "should not accept '0' as max messages stored per channel" do
nginx_test_configuration({:max_messages_stored_per_channel => 0}).should include("push_stream_max_messages_stored_per_channel cannot be zero")
end
it "should not accept '0' as max number of channels" do
nginx_test_configuration({:max_number_of_channels => 0}).should include("push_stream_max_number_of_channels cannot be zero")
end
it "should not accept '0' as max number of broadcast channels" do
nginx_test_configuration({:max_number_of_broadcast_channels => 0}).should include("push_stream_max_number_of_broadcast_channels cannot be zero")
end
it "should not accept '0' as max broadcast channels" do
nginx_test_configuration({:broadcast_channel_max_qtd => 0}).should include("push_stream_broadcast_channel_max_qtd cannot be zero")
end
it "should not set max broadcast channels without set boadcast channel prefix" do
nginx_test_configuration({:broadcast_channel_max_qtd => 1, :broadcast_channel_prefix => ""}).should include("cannot set broadcast channel max qtd if push_stream_broadcast_channel_prefix is not set or blank")
end
it "should not accept '0' as max number of broadcast channels" do
config = {:max_number_of_broadcast_channels => 3, :broadcast_channel_max_qtd => 4, :broadcast_channel_prefix => "broad_"}
nginx_test_configuration(config).should include("max number of broadcast channels cannot be smaller than value in push_stream_broadcast_channel_max_qtd")
end
it "should not accept a value less than '30s' as shared memory cleanup objects ttl" do
nginx_test_configuration({:shared_memory_cleanup_objects_ttl => '15s'}).should include("memory cleanup objects ttl cannot't be less than 30.")
end
it "should accept a configuration without http block" do
config = {
:configuration_template => %q{
pid <%= pid_file %>;
error_log <%= error_log %> debug;
# Development Mode
master_process off;
daemon off;
worker_processes <%= nginx_workers %>;
events {
worker_connections 1024;
use <%= (RUBY_PLATFORM =~ /darwin/) ? 'kqueue' : 'epoll' %>;
}
}
}
nginx_test_configuration(config).should include("ngx_http_push_stream_module will not be used with this configuration.")
end
it "should not accept an invalid push mode" do
nginx_test_configuration({:subscriber_mode => "unknown"}).should include("invalid push_stream_subscriber mode value: unknown, accepted values (streaming, polling, long-polling)")
end
it "should accept the known push modes" do
nginx_test_configuration({:subscriber_mode => ""}).should_not include("invalid push_stream_subscriber mode value")
nginx_test_configuration({:subscriber_mode => "streaming"}).should_not include("invalid push_stream_subscriber mode value")
nginx_test_configuration({:subscriber_mode => "polling"}).should_not include("invalid push_stream_subscriber mode value")
nginx_test_configuration({:subscriber_mode => "long-polling"}).should_not include("invalid push_stream_subscriber mode value")
end
it "should not accept an invalid publisher mode" do
nginx_test_configuration({:publisher_mode => "unknown"}).should include("invalid push_stream_publisher mode value: unknown, accepted values (normal, admin)")
end
it "should accept the known publisher modes" do
nginx_test_configuration({:publisher_mode => ""}).should_not include("invalid push_stream_publisher mode value")
nginx_test_configuration({:publisher_mode => "normal"}).should_not include("invalid push_stream_publisher mode value")
nginx_test_configuration({:publisher_mode => "admin"}).should_not include("invalid push_stream_publisher mode value")
end
it "should not accept enable event source on publisher location" do
config = {
:extra_location => %q{
location ~ /test/ {
push_stream_publisher;
push_stream_eventsource_support on;
}
}
}
nginx_test_configuration(config).should include("event source support is only available on subscriber location")
end
it "should not accept enable event source on statistics location" do
config = {
:extra_location => %q{
location ~ /test/ {
push_stream_channels_statistics;
push_stream_eventsource_support on;
}
}
}
nginx_test_configuration(config).should include("event source support is only available on subscriber location")
end
it "should not accept enable event source on websocket location" do
config = {
:extra_location => %q{
location ~ /test/ {
push_stream_websocket;
push_stream_eventsource_support on;
}
}
}
nginx_test_configuration(config).should include("event source support is only available on subscriber location")
end
it "should not accept an invalid pattern for padding by user agent" do
nginx_test_configuration({:padding_by_user_agent => "user_agent,as,df"}).should include("padding pattern not match the value user_agent,as,df")
nginx_test_configuration({:padding_by_user_agent => "user_agent;10;0"}).should include("padding pattern not match the value user_agent;10;0")
nginx_test_configuration({:padding_by_user_agent => "user_agent,10,0:other_user_agent;20;0:another_user_agent,30,0"}).should include("error applying padding pattern to other_user_agent;20;0:another_user_agent,30,0")
end
end
module NginxConfiguration
def self.default_configuration
{
:disable_start_stop_server => false,
:master_process => 'off',
:daemon => 'off',
:content_type => 'text/html; charset=utf-8',
:keepalive => 'off',
:ping_message_interval => '10s',
:header_template => %{<html><head><meta http-equiv=\\"Content-Type\\" content=\\"text/html; charset=utf-8\\">\\r\\n<meta http-equiv=\\"Cache-Control\\" content=\\"no-store\\">\\r\\n<meta http-equiv=\\"Cache-Control\\" content=\\"no-cache\\">\\r\\n<meta http-equiv=\\"Expires\\" content=\\"Thu, 1 Jan 1970 00:00:00 GMT\\">\\r\\n<script type=\\"text/javascript\\">\\r\\nwindow.onError = null;\\r\\ndocument.domain = \\'<%= nginx_host %>\\';\\r\\nparent.PushStream.register(this);\\r\\n</script>\\r\\n</head>\\r\\n<body onload=\\"try { parent.PushStream.reset(this) } catch (e) {}\\">},
:message_template => "<script>p(~id~,'~channel~','~text~');</script>",
:footer_template => "</body></html>",
:store_messages => 'on',
:subscriber_connection_ttl => nil,
:longpolling_connection_ttl => nil,
:message_ttl => '50m',
:max_channel_id_length => 200,
:max_subscribers_per_channel => nil,
:max_messages_stored_per_channel => 20,
:max_number_of_channels => nil,
:max_number_of_broadcast_channels => nil,
:broadcast_channel_max_qtd => 3,
:broadcast_channel_prefix => 'broad_',
:shared_memory_cleanup_objects_ttl => '5m',
:subscriber_mode => nil,
:publisher_mode => nil,
:padding_by_user_agent => nil,
:shared_memory_size => '10m',
:channel_deleted_message_text => nil,
:ping_message_text => nil,
:last_received_message_time => nil,
:last_received_message_tag => nil,
:user_agent => nil,
:authorized_channels_only => 'off',
:allowed_origins => nil,
:eventsource_support => 'off',
:client_max_body_size => '32k',
:client_body_buffer_size => '32k',
:extra_location => ''
}
end
def self.template_configuration
%(
pid <%= pid_file %>;
error_log <%= error_log %> debug;
# Development Mode
master_process <%= master_process %>;
daemon <%= daemon %>;
worker_processes <%= nginx_workers %>;
events {
worker_connections 1024;
use <%= (RUBY_PLATFORM =~ /darwin/) ? 'kqueue' : 'epoll' %>;
}
http {
default_type application/octet-stream;
access_log <%= access_log %>;
tcp_nopush on;
tcp_nodelay on;
keepalive_timeout 100;
send_timeout 10;
client_body_timeout 10;
client_header_timeout 10;
sendfile on;
client_header_buffer_size 1k;
large_client_header_buffers 2 4k;
client_max_body_size 1k;
client_body_buffer_size 1k;
ignore_invalid_headers on;
client_body_in_single_buffer on;
client_body_temp_path <%= client_body_temp %>;
<%= write_directive("push_stream_ping_message_interval", ping_message_interval, "ping frequency") %>
<%= write_directive("push_stream_message_template", message_template, "message template") %>
<%= write_directive("push_stream_subscriber_connection_ttl", subscriber_connection_ttl, "timeout for subscriber connections") %>
<%= write_directive("push_stream_longpolling_connection_ttl", longpolling_connection_ttl, "timeout for long polling connections") %>
<%= write_directive("push_stream_header_template", header_template, "header to be sent when receiving new subscriber connection") %>
<%= write_directive("push_stream_message_ttl", message_ttl, "message ttl") %>
<%= write_directive("push_stream_footer_template", footer_template, "footer to be sent when finishing subscriber connection") %>
<%= write_directive("push_stream_max_channel_id_length", max_channel_id_length) %>
<%= write_directive("push_stream_max_subscribers_per_channel", max_subscribers_per_channel, "max subscribers per channel") %>
<%= write_directive("push_stream_max_messages_stored_per_channel", max_messages_stored_per_channel, "max messages to store in memory") %>
<%= write_directive("push_stream_max_number_of_channels", max_number_of_channels) %>
<%= write_directive("push_stream_max_number_of_broadcast_channels", max_number_of_broadcast_channels) %>
<%= write_directive("push_stream_broadcast_channel_max_qtd", broadcast_channel_max_qtd) %>
<%= write_directive("push_stream_broadcast_channel_prefix", broadcast_channel_prefix) %>
<%= write_directive("push_stream_shared_memory_cleanup_objects_ttl", shared_memory_cleanup_objects_ttl) %>
<%= write_directive("push_stream_padding_by_user_agent", padding_by_user_agent) %>
<%= write_directive("push_stream_authorized_channels_only", authorized_channels_only, "subscriber may create channels on demand or only authorized (publisher) may do it?") %>
<%= write_directive("push_stream_shared_memory_size", shared_memory_size) %>
<%= write_directive("push_stream_user_agent", user_agent) %>
<%= write_directive("push_stream_allowed_origins", allowed_origins) %>
<%= write_directive("push_stream_last_received_message_time", last_received_message_time) %>
<%= write_directive("push_stream_last_received_message_tag", last_received_message_tag) %>
<%= write_directive("push_stream_channel_deleted_message_text", channel_deleted_message_text) %>
<%= write_directive("push_stream_ping_message_text", ping_message_text) %>
server {
listen <%= nginx_port %>;
server_name <%= nginx_host %>;
location /channels-stats {
# activate channels statistics mode for this location
push_stream_channels_statistics;
# query string based channel id
set $push_stream_channel_id $arg_id;
<%= write_directive("push_stream_keepalive", keepalive, "keepalive") %>
}
location /pub {
# activate publisher mode for this location
push_stream_publisher <%= publisher_mode unless publisher_mode.nil? || publisher_mode == "normal" %>;
# query string based channel id
set $push_stream_channel_id $arg_id;
<%= write_directive("push_stream_store_messages", store_messages, "store messages") %>
<%= write_directive("push_stream_keepalive", keepalive, "keepalive") %>
# client_max_body_size MUST be equal to client_body_buffer_size or
# you will be sorry.
client_max_body_size <%= client_max_body_size %>;
client_body_buffer_size <%= client_body_buffer_size %>;
}
location ~ /sub/(.*)? {
# activate subscriber mode for this location
push_stream_subscriber <%= subscriber_mode unless subscriber_mode.nil? || subscriber_mode == "streaming" %>;
<%= write_directive("push_stream_eventsource_support", eventsource_support, "activate event source support for this location") %>
# positional channel path
set $push_stream_channels_path $1;
<%= write_directive("push_stream_content_type", content_type, "content-type") %>
<%= write_directive("push_stream_keepalive", keepalive, "keepalive") %>
}
<%= extra_location %>
}
}
)
end
end
require 'spec_helper'
describe "Publisher Channel id collision" do
it "should create and retrieve channels with ids that collide" do
channels = ["A", "plumless", "buckeroo", "B", "fc0591", "123rainerbommert", "C", "a1sellers", "advertees", "D"]
nginx_run_server do |conf|
channels.each do |channel|
EventMachine.run do
pub = EventMachine::HttpRequest.new(nginx_address + '/pub?id=' + channel).post :body => 'x', :timeout => 30
pub.callback do
pub.response_header.status.should eql(200)
EventMachine.stop
end
end
end
channels.each do |channel|
EventMachine.run do
pub = EventMachine::HttpRequest.new(nginx_address + '/channels-stats?id=' + channel).get :timeout => 30
pub.callback do
pub.response_header.status.should eql(200)
EventMachine.stop
end
end
end
end
end
end
require 'spec_helper'
describe "Publisher Properties" do
shared_examples_for "publisher location" do
it "should not accept access without a channel id" do
nginx_run_server(config, :timeout => 5) do |conf|
EventMachine.run do
pub = EventMachine::HttpRequest.new(nginx_address + '/pub?id=').get :head => headers
pub.callback do
pub.response_header.content_length.should eql(0)
pub.response_header.status.should eql(400)
pub.response_header['X_NGINX_PUSHSTREAM_EXPLAIN'].should eql("No channel id provided.")
EventMachine.stop
end
end
end
end
it "should not accept 'get' access to a nonexistent channel" do
channel_1 = 'ch_test_access_whith_channel_id_to_absent_channel_1'
channel_2 = 'ch_test_access_whith_channel_id_to_absent_channel_2'
body = 'body'
nginx_run_server(config, :timeout => 5) do |conf|
EventMachine.run do
pub_1 = EventMachine::HttpRequest.new(nginx_address + '/pub?id=' + channel_1.to_s).get :head => headers
pub_1.callback do
pub_1.response_header.status.should eql(404)
pub_1.response_header.content_length.should eql(0)
EventMachine.stop
end
end
EventMachine.run do
pub_2 = EventMachine::HttpRequest.new(nginx_address + '/pub?id=' + channel_2.to_s ).post :head => headers, :body => body
pub_2.callback do
pub_2.response_header.status.should eql(200)
pub_2.response_header.content_length.should_not eql(0)
response = JSON.parse(pub_2.response)
response["channel"].to_s.should eql(channel_2)
EventMachine.stop
end
end
end
end
it "should accept 'get' access to an existent channel" do
channel = 'ch_test_access_whith_channel_id_to_existing_channel'
body = 'body'
nginx_run_server(config, :timeout => 5) do |conf|
#create channel
EventMachine.run do
pub_1 = EventMachine::HttpRequest.new(nginx_address + '/pub?id=' + channel.to_s).post :head => headers, :body => body
pub_1.callback do
pub_1.response_header.status.should eql(200)
pub_1.response_header.content_length.should_not eql(0)
response = JSON.parse(pub_1.response)
response["channel"].to_s.should eql(channel)
EventMachine.stop
end
end
EventMachine.run do
pub_2 = EventMachine::HttpRequest.new(nginx_address + '/pub?id=' + channel.to_s).get :head => headers
pub_2.callback do
pub_2.response_header.status.should eql(200)
pub_2.response_header.content_length.should_not eql(0)
response = JSON.parse(pub_2.response)
response["channel"].to_s.should eql(channel)
EventMachine.stop
end
end
end
end
it "should check accepted methods" do
nginx_run_server(config, :timeout => 5) do |conf|
EventMachine.run do
multi = EventMachine::MultiRequest.new
multi.add(:a, EventMachine::HttpRequest.new(nginx_address + '/pub?id=ch_test_accepted_methods_1').get)
multi.add(:b, EventMachine::HttpRequest.new(nginx_address + '/pub?id=ch_test_accepted_methods_2').put(:body => 'body'))
multi.add(:c, EventMachine::HttpRequest.new(nginx_address + '/pub?id=ch_test_accepted_methods_3').post)
multi.add(:d, EventMachine::HttpRequest.new(nginx_address + '/pub?id=ch_test_accepted_methods_4').delete)
multi.add(:e, EventMachine::HttpRequest.new(nginx_address + '/pub?id=ch_test_accepted_methods_5').head)
multi.callback do
multi.responses[:callback].length.should eql(5)
multi.responses[:callback][:a].response_header.status.should_not eql(405)
multi.responses[:callback][:a].req.method.should eql("GET")
multi.responses[:callback][:b].response_header.status.should eql(405)
multi.responses[:callback][:b].response_header['ALLOW'].should eql(accepted_methods)
multi.responses[:callback][:b].req.method.should eql("PUT")
multi.responses[:callback][:c].response_header.status.should_not eql(405)
multi.responses[:callback][:c].req.method.should eql("POST")
multi.responses[:callback][:d].req.method.should eql("DELETE")
if conf.publisher_mode == 'admin'
multi.responses[:callback][:d].response_header.status.should_not eql(405)
else
multi.responses[:callback][:d].response_header.status.should eql(405)
multi.responses[:callback][:d].response_header['ALLOW'].should eql(accepted_methods)
end
multi.responses[:callback][:e].response_header.status.should eql(405)
multi.responses[:callback][:e].req.method.should eql("HEAD")
multi.responses[:callback][:e].response_header['ALLOW'].should eql(accepted_methods)
EventMachine.stop
end
end
end
end
it "should not accept create a channel with id 'ALL'" do
channel = 'ALL'
body = 'body'
nginx_run_server(config, :timeout => 5) do |conf|
EventMachine.run do
pub_1 = EventMachine::HttpRequest.new(nginx_address + '/pub?id=' + channel.to_s).post :head => headers, :body => body
pub_1.callback do
pub_1.response_header.status.should eql(403)
pub_1.response_header.content_length.should eql(0)
pub_1.response_header['X_NGINX_PUSHSTREAM_EXPLAIN'].should eql("Channel id not authorized for this method.")
EventMachine.stop
end
end
end
end
it "should not accept create a channel with id containing wildcard" do
channel_1 = 'abcd*efgh'
channel_2 = '*abcdefgh'
channel_3 = 'abcdefgh*'
body = 'body'
nginx_run_server(config, :timeout => 5) do |conf|
EventMachine.run do
multi = EventMachine::MultiRequest.new
multi.add(:a, EventMachine::HttpRequest.new(nginx_address + '/pub?id=' + channel_1).post(:head => headers, :body => body))
multi.add(:b, EventMachine::HttpRequest.new(nginx_address + '/pub?id=' + channel_2).post(:head => headers, :body => body))
multi.add(:c, EventMachine::HttpRequest.new(nginx_address + '/pub?id=' + channel_3).post(:head => headers, :body => body))
multi.callback do
multi.responses[:callback].length.should eql(3)
multi.responses[:callback].each do |name, response|
response.response_header.status.should eql(403)
response.response_header.content_length.should eql(0)
response.response_header['X_NGINX_PUSHSTREAM_EXPLAIN'].should eql("Channel id not authorized for this method.")
end
EventMachine.stop
end
end
end
end
it "should not accept a message larger than max body size" do
channel = 'ch_test_post_message_larger_than_max_body_size_should_be_rejected'
body = '^'
(1..40).each do |n|
body += '0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789|'
end
body += '$'
nginx_run_server(config.merge(:client_max_body_size => '2k', :client_body_buffer_size => '1k'), :timeout => 5) do |conf|
EventMachine.run do
pub_1 = EventMachine::HttpRequest.new(nginx_address + '/pub?id=' + channel.to_s).post :head => headers, :body => body
pub_1.callback do
pub_1.response_header.status.should eql(413)
EventMachine.stop
end
end
end
end
it "should accept a message larger than max buffer size and smaller than max body size" do
channel = 'ch_test_post_message_larger_than_body_buffer_size_should_be_accepted'
body = '^'
(1..80).each do |n|
body += '0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789|'
end
body += '$'
nginx_run_server(config.merge(:client_max_body_size => '10k', :client_body_buffer_size => '1k'), :timeout => 5) do |conf|
EventMachine.run do
pub_1 = EventMachine::HttpRequest.new(nginx_address + '/pub?id=' + channel.to_s).post :head => headers, :body => body
pub_1.callback do
pub_1.response_header.status.should eql(200)
fail("Let a file on client body temp dir") unless Dir.entries(conf.client_body_temp).select {|f| f if File.file?(File.expand_path(f, conf.client_body_temp)) }.empty?
EventMachine.stop
end
end
end
end
it "should accept a message smaller than max body size" do
channel = 'ch_test_post_message_shorter_than_body_buffer_size_should_be_accepted'
body = '^'
(1..40).each do |n|
body += '0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789|'
end
body += '$'
nginx_run_server(config.merge(:client_max_body_size => '10k', :client_body_buffer_size => '6k'), :timeout => 5) do |conf|
EventMachine.run do
pub_1 = EventMachine::HttpRequest.new(nginx_address + '/pub?id=' + channel.to_s).post :head => headers, :body => body
pub_1.callback do
pub_1.response_header.status.should eql(200)
fail("Let a file on client body temp dir") unless Dir.entries(conf.client_body_temp).select {|f| f if File.file?(File.expand_path(f, conf.client_body_temp)) }.empty?
EventMachine.stop
end
end
end
end
it "should store messages" do
body = 'published message'
channel = 'ch_test_stored_messages'
nginx_run_server(config.merge(:store_messages => "on"), :timeout => 5) do |conf|
EventMachine.run do
pub_1 = EventMachine::HttpRequest.new(nginx_address + '/pub?id=' + channel.to_s ).post :head => headers, :body => body
pub_1.callback do
response = JSON.parse(pub_1.response)
response["stored_messages"].to_i.should eql(1)
pub_2 = EventMachine::HttpRequest.new(nginx_address + '/pub?id=' + channel.to_s ).post :head => headers, :body => body
pub_2.callback do
response = JSON.parse(pub_2.response)
response["stored_messages"].to_i.should eql(2)
EventMachine.stop
end
end
end
end
end
it "should not store messages when it is 'off'" do
body = 'published message'
channel = 'ch_test_not_stored_messages'
nginx_run_server(config.merge(:store_messages => "off"), :timeout => 5) do |conf|
EventMachine.run do
pub = EventMachine::HttpRequest.new(nginx_address + '/pub?id=' + channel.to_s ).post :head => headers, :body => body
pub.callback do
response = JSON.parse(pub.response)
response["stored_messages"].to_i.should eql(0)
EventMachine.stop
end
end
end
end
it "should limit the number of stored messages" do
body_prefix = 'published message '
channel = 'ch_test_max_stored_messages'
messagens_to_publish = 10
nginx_run_server(config.merge(:store_messages => "on", :max_messages_stored_per_channel => 4), :timeout => 5) do |conf|
EventMachine.run do
i = 0
stored_messages = 0
EM.add_periodic_timer(0.001) do
i += 1
if i <= messagens_to_publish
pub = EventMachine::HttpRequest.new(nginx_address + '/pub?id=' + channel.to_s ).post :head => headers, :body => body_prefix + i.to_s
pub.callback do
response = JSON.parse(pub.response)
stored_messages = response["stored_messages"].to_i
end
else
stored_messages.should eql(conf.max_messages_stored_per_channel)
EventMachine.stop
end
end
end
end
end
it "should limit the size of channel id" do
body = 'published message'
channel = '123456'
nginx_run_server(config.merge(:max_channel_id_length => 5), :timeout => 5) do |conf|
EventMachine.run do
pub = EventMachine::HttpRequest.new(nginx_address + '/pub?id=' + channel.to_s ).post :head => headers, :body => body
pub.callback do
pub.response_header.content_length.should eql(0)
pub.response_header.status.should eql(400)
pub.response_header['X_NGINX_PUSHSTREAM_EXPLAIN'].should eql("Channel id is too large.")
EventMachine.stop
end
end
end
end
it "should limit the number of channels" do
body = 'published message'
channel = 'ch_test_max_number_of_channels_'
nginx_run_server(config.merge(:max_number_of_channels => 1), :timeout => 5) do |conf|
EventMachine.run do
pub = EventMachine::HttpRequest.new(nginx_address + '/pub?id=' + channel.to_s + 1.to_s).post :head => headers, :body => body
pub.callback do
pub.response_header.status.should eql(200)
pub.response_header.content_length.should_not eql(0)
EventMachine.stop
end
end
EventMachine.run do
pub = EventMachine::HttpRequest.new(nginx_address + '/pub?id=' + channel.to_s + 2.to_s).post :head => headers, :body => body
pub.callback do
pub.response_header.status.should eql(403)
pub.response_header.content_length.should eql(0)
pub.response_header['X_NGINX_PUSHSTREAM_EXPLAIN'].should eql("Number of channels were exceeded.")
EventMachine.stop
end
end
end
end
it "should limit the number of broadcast channels" do
body = 'published message'
channel = 'bd_test_max_number_of_broadcast_channels_'
nginx_run_server(config.merge(:max_number_of_broadcast_channels => 1, :broadcast_channel_prefix => 'bd_', :broadcast_channel_max_qtd => 1), :timeout => 5) do |conf|
EventMachine.run do
pub = EventMachine::HttpRequest.new(nginx_address + '/pub?id=' + channel.to_s + 1.to_s).post :head => headers, :body => body
pub.callback do
pub.response_header.status.should eql(200)
pub.response_header.content_length.should_not eql(0)
EventMachine.stop
end
end
EventMachine.run do
pub = EventMachine::HttpRequest.new(nginx_address + '/pub?id=' + channel.to_s + 2.to_s).post :head => headers, :body => body
pub.callback do
pub.response_header.status.should eql(403)
pub.response_header.content_length.should eql(0)
pub.response_header['X_NGINX_PUSHSTREAM_EXPLAIN'].should eql("Number of channels were exceeded.")
EventMachine.stop
end
end
end
end
it "should set a default access control allow orgin header" do
channel = 'test_default_access_control_allow_origin_header'
nginx_run_server(config, :timeout => 5) do |conf|
EventMachine.run do
pub = EventMachine::HttpRequest.new(nginx_address + '/pub?id=' + channel).get :head => headers
pub.callback do
pub.response_header['ACCESS_CONTROL_ALLOW_ORIGIN'].should eql("*")
EventMachine.stop
end
end
end
end
it "should set a custom access control allow orgin header" do
channel = 'test_custom_access_control_allow_origin_header'
nginx_run_server(config.merge(:allowed_origins => "custom.domain.com"), :timeout => 5) do |conf|
EventMachine.run do
pub = EventMachine::HttpRequest.new(nginx_address + '/pub?id=' + channel).get :head => headers
pub.callback do
pub.response_header['ACCESS_CONTROL_ALLOW_ORIGIN'].should eql("custom.domain.com")
EventMachine.stop
end
end
end
end
end
context "when is on normal mode" do
let(:config) do
{}
end
let(:headers) do
{'accept' => 'text/html'}
end
let(:accepted_methods) do
"GET, POST"
end
it_should_behave_like "publisher location"
end
context "when is on admin mode" do
let(:config) do
{:publisher_mode => 'admin'}
end
let(:headers) do
{'accept' => 'text/html'}
end
let(:accepted_methods) { "GET, POST, DELETE" }
it_should_behave_like "publisher location"
it "should delete a channel without subscribers" do
channel = 'test_delete_channel_whithout_subscribers'
body = 'published message'
nginx_run_server(config, :timeout => 5) do |conf|
publish_message(channel, headers, body)
EventMachine.run do
pub = EventMachine::HttpRequest.new(nginx_address + '/pub?id=' + channel.to_s).delete :head => headers, :timeout => 30
pub.callback do
pub.response_header.status.should eql(200)
pub.response_header.content_length.should eql(0)
pub.response_header['X_NGINX_PUSHSTREAM_EXPLAIN'].should eql("Channel deleted.")
stats = EventMachine::HttpRequest.new(nginx_address + '/channels-stats').get :head => headers, :timeout => 30
stats.callback do
stats.response_header.status.should eql(200)
stats.response_header.content_length.should_not eql(0)
response = JSON.parse(stats.response)
response["channels"].to_s.should_not be_empty
response["channels"].to_i.should eql(0)
EventMachine.stop
end
end
end
end
end
it "should delete a channel with subscriber" do
channel = 'test_delete_channel_whith_subscriber_in_one_channel'
body = 'published message'
configuration = config.merge({
:header_template => " ", # send a space as header to has a chunk received
:footer_template => nil,
:ping_message_interval => nil,
:message_template => '{\"id\":\"~id~\", \"channel\":\"~channel~\", \"text\":\"~text~\"}'
})
resp = ""
nginx_run_server(configuration, :timeout => 5) do |conf|
EventMachine.run do
sub_1 = EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel.to_s).get :head => headers, :timeout => 30
sub_1.stream do |chunk|
resp = resp + chunk
if resp.strip.empty?
stats = EventMachine::HttpRequest.new(nginx_address + '/channels-stats').get :head => {'accept' => 'application/json'}, :timeout => 30
stats.callback do
stats.response_header.status.should eql(200)
stats.response_header.content_length.should_not eql(0)
response = JSON.parse(stats.response)
response["subscribers"].to_i.should eql(1)
response["channels"].to_i.should eql(1)
pub = EventMachine::HttpRequest.new(nginx_address + '/pub?id=' + channel.to_s).delete :head => headers, :timeout => 30
pub.callback do
pub.response_header.status.should eql(200)
pub.response_header.content_length.should eql(0)
pub.response_header['X_NGINX_PUSHSTREAM_EXPLAIN'].should eql("Channel deleted.")
end
end
else
response = JSON.parse(resp)
response["channel"].should eql(channel)
response["id"].to_i.should eql(-2)
response["text"].should eql("Channel deleted")
stats = EventMachine::HttpRequest.new(nginx_address + '/channels-stats').get :head => {'accept' => 'application/json'}, :timeout => 30
stats.callback do
stats.response_header.status.should eql(200)
stats.response_header.content_length.should_not eql(0)
response = JSON.parse(stats.response)
response["subscribers"].to_i.should eql(0)
response["channels"].to_i.should eql(0)
end
EventMachine.stop
end
end
end
end
end
it "should delete a channel with subscriber in two channels" do
channel_1 = 'test_delete_channel_whith_subscriber_in_two_channels_1'
channel_2 = 'test_delete_channel_whith_subscriber_in_two_channels_2'
stage1_complete = stage2_complete = false
body = 'published message'
configuration = config.merge({
:header_template => " ", # send a space as header to has a chunk received
:footer_template => nil,
:ping_message_interval => nil,
:message_template => '{\"id\":\"~id~\", \"channel\":\"~channel~\", \"text\":\"~text~\"}'
})
resp = ""
nginx_run_server(configuration, :timeout => 5) do |conf|
EventMachine.run do
sub_1 = EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel_1.to_s + '/' + channel_2.to_s).get :head => headers, :timeout => 30
sub_1.stream do |chunk|
resp = resp + chunk
if resp.strip.empty?
stats = EventMachine::HttpRequest.new(nginx_address + '/channels-stats').get :head => {'accept' => 'application/json'}, :timeout => 30
stats.callback do
stats.response_header.status.should eql(200)
stats.response_header.content_length.should_not eql(0)
response = JSON.parse(stats.response)
response["subscribers"].to_i.should eql(1)
response["channels"].to_i.should eql(2)
pub = EventMachine::HttpRequest.new(nginx_address + '/pub?id=' + channel_1.to_s).delete :head => headers, :timeout => 30
pub.callback do
pub.response_header.status.should eql(200)
pub.response_header.content_length.should eql(0)
pub.response_header['X_NGINX_PUSHSTREAM_EXPLAIN'].should eql("Channel deleted.")
end
end
else
if !stage1_complete
stage1_complete = true
response = JSON.parse(resp)
response["channel"].should eql(channel_1)
response["id"].to_i.should eql(-2)
response["text"].should eql("Channel deleted")
stats = EventMachine::HttpRequest.new(nginx_address + '/channels-stats').get :head => {'accept' => 'application/json'}, :timeout => 30
stats.callback do
stats.response_header.status.should eql(200)
stats.response_header.content_length.should_not eql(0)
response = JSON.parse(stats.response)
response["subscribers"].to_i.should eql(1)
response["channels"].to_i.should eql(1)
pub = EventMachine::HttpRequest.new(nginx_address + '/pub?id=' + channel_2.to_s).post :head => headers, :body=> body, :timeout => 30
pub.callback do
pub.response_header.status.should eql(200)
end
end
elsif !stage2_complete
stage2_complete = true
response = JSON.parse(resp.split("\r\n")[2])
response["channel"].should eql(channel_2)
response["id"].to_i.should eql(1)
response["text"].should eql(body)
pub = EventMachine::HttpRequest.new(nginx_address + '/pub?id=' + channel_2.to_s).delete :head => headers, :timeout => 30
pub.callback do
pub.response_header.status.should eql(200)
pub.response_header.content_length.should eql(0)
pub.response_header['X_NGINX_PUSHSTREAM_EXPLAIN'].should eql("Channel deleted.")
end
else
response = JSON.parse(resp.split("\r\n")[3])
response["channel"].should eql(channel_2)
response["id"].to_i.should eql(-2)
response["text"].should eql("Channel deleted")
stats = EventMachine::HttpRequest.new(nginx_address + '/channels-stats').get :head => {'accept' => 'application/json'}, :timeout => 30
stats.callback do
stats.response_header.status.should eql(200)
stats.response_header.content_length.should_not eql(0)
response = JSON.parse(stats.response)
response["subscribers"].to_i.should eql(0)
response["channels"].to_i.should eql(0)
EventMachine.stop
end
end
end
end
end
end
end
it "should delete channels with subscribers" do
channel_1 = 'test_delete_channels_whith_subscribers_1'
channel_2 = 'test_delete_channels_whith_subscribers_2'
body = 'published message'
configuration = config.merge({
:header_template => nil,
:footer_template => "FOOTER",
:ping_message_interval => nil,
:shared_memory_cleanup_objects_ttl => nil,
:message_template => '{\"id\":\"~id~\", \"channel\":\"~channel~\", \"text\":\"~text~\"}'
})
nginx_run_server(configuration, :timeout => 10) do |conf|
EventMachine.run do
resp_1 = ""
sub_1 = EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel_1.to_s).get :head => headers, :timeout => 30
sub_1.stream do |chunk|
resp_1 += chunk
end
sub_1.callback do
resp_1.should eql("{\"id\":\"-2\", \"channel\":\"test_delete_channels_whith_subscribers_1\", \"text\":\"Channel deleted\"}\r\nFOOTER\r\n")
end
resp_2 = ""
sub_2 = EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel_2.to_s).get :head => headers, :timeout => 30
sub_2.stream do |chunk|
resp_2 += chunk
end
sub_2.callback do
resp_2.should eql("{\"id\":\"-2\", \"channel\":\"test_delete_channels_whith_subscribers_2\", \"text\":\"Channel deleted\"}\r\nFOOTER\r\n")
end
stats = EventMachine::HttpRequest.new(nginx_address + '/channels-stats').get :head => {'accept' => 'application/json'}, :timeout => 30
stats.callback do
stats.response_header.status.should eql(200)
stats.response_header.content_length.should_not eql(0)
response = JSON.parse(stats.response)
response["subscribers"].to_i.should eql(2)
response["channels"].to_i.should eql(2)
end
pub_1 = EventMachine::HttpRequest.new(nginx_address + '/pub?id=' + channel_1.to_s).delete :head => headers, :timeout => 30
pub_1.callback do
pub_1.response_header.status.should eql(200)
pub_1.response_header.content_length.should eql(0)
pub_1.response_header['X_NGINX_PUSHSTREAM_EXPLAIN'].should eql("Channel deleted.")
end
pub_2 = EventMachine::HttpRequest.new(nginx_address + '/pub?id=' + channel_2.to_s).delete :head => headers, :timeout => 30
pub_2.callback do
pub_2.response_header.status.should eql(200)
pub_2.response_header.content_length.should eql(0)
pub_2.response_header['X_NGINX_PUSHSTREAM_EXPLAIN'].should eql("Channel deleted.")
end
EM.add_timer(5) do
stats_2 = EventMachine::HttpRequest.new(nginx_address + '/channels-stats').get :head => {'accept' => 'application/json'}, :timeout => 30
stats_2.callback do
stats_2.response_header.status.should eql(200)
stats_2.response_header.content_length.should_not eql(0)
response = JSON.parse(stats_2.response)
response["subscribers"].to_i.should eql(0)
response["channels"].to_i.should eql(0)
EventMachine.stop
end
end
end
end
end
it "should receive footer template when channel is deleted" do
channel = 'ch_test_receive_footer_template_when_channel_is_deleted'
body = 'published message'
configuration = config.merge({
:header_template => "HEADER_TEMPLATE",
:footer_template => "FOOTER_TEMPLATE",
:ping_message_interval => nil,
:message_template => '~text~'
})
resp = ""
nginx_run_server(configuration, :timeout => 5) do |conf|
EventMachine.run do
sub_1 = EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel.to_s).get :head => headers, :timeout => 30
sub_1.stream do |chunk|
resp = resp + chunk
if resp == "#{conf.header_template}\r\n"
pub = EventMachine::HttpRequest.new(nginx_address + '/pub?id=' + channel.to_s).delete :head => headers, :timeout => 30
pub.callback do
pub.response_header.status.should eql(200)
pub.response_header.content_length.should eql(0)
pub.response_header['X_NGINX_PUSHSTREAM_EXPLAIN'].should eql("Channel deleted.")
end
end
end
sub_1.callback do
resp.should eql("#{conf.header_template}\r\nChannel deleted\r\n#{conf.footer_template}\r\n")
EventMachine.stop
end
end
end
end
it "should receive different header and footer template by location when channel is deleted" do
channel = 'ch_test_different_header_and_footer_template_by_location'
body = 'published message'
configuration = config.merge({
:header_template => "HEADER_TEMPLATE",
:footer_template => "FOOTER_TEMPLATE",
:ping_message_interval => nil,
:message_template => '~text~',
:extra_location => %{
location ~ /sub2/(.*)? {
# activate subscriber mode for this location
push_stream_subscriber;
# positional channel path
set $push_stream_channels_path $1;
push_stream_header_template "<html><body>";
push_stream_footer_template "</body></html>";
push_stream_message_template "|~text~|";
}
}
})
resp = ""
resp2 = ""
nginx_run_server(configuration, :timeout => 5) do |conf|
EventMachine.run do
sub_1 = EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel.to_s).get :head => headers, :timeout => 30
sub_1.stream do |chunk|
resp = resp + chunk
end
sub_2 = EventMachine::HttpRequest.new(nginx_address + '/sub2/' + channel.to_s).get :head => headers, :timeout => 30
sub_2.stream do |chunk|
resp2 = resp2 + chunk
end
EM.add_timer(1) do
pub = EventMachine::HttpRequest.new(nginx_address + '/pub?id=' + channel.to_s).delete :head => headers, :timeout => 30
pub.callback do
pub.response_header.status.should eql(200)
pub.response_header.content_length.should eql(0)
pub.response_header['X_NGINX_PUSHSTREAM_EXPLAIN'].should eql("Channel deleted.")
end
end
EM.add_timer(2) do
resp.should eql("#{conf.header_template}\r\nChannel deleted\r\n#{conf.footer_template}\r\n")
resp2.should eql("<html><body>\r\n|Channel deleted|\r\n</body></html>\r\n")
EventMachine.stop
end
end
end
end
it "should receive custom delete message text when channel is deleted" do
channel = 'test_custom_channel_deleted_message_text'
body = 'published message'
configuration = config.merge({
:header_template => " ", # send a space as header to has a chunk received
:footer_template => nil,
:ping_message_interval => nil,
:message_template => '{\"id\":\"~id~\", \"channel\":\"~channel~\", \"text\":\"~text~\"}',
:channel_deleted_message_text => "Channel has gone away."
})
resp = ""
nginx_run_server(configuration, :timeout => 5) do |conf|
EventMachine.run do
sub_1 = EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel.to_s).get :head => headers, :timeout => 30
sub_1.stream do |chunk|
resp = resp + chunk
if resp.strip.empty?
pub = EventMachine::HttpRequest.new(nginx_address + '/pub?id=' + channel.to_s).delete :head => headers, :timeout => 30
pub.callback do
pub.response_header.status.should eql(200)
pub.response_header.content_length.should eql(0)
pub.response_header['X_NGINX_PUSHSTREAM_EXPLAIN'].should eql("Channel deleted.")
end
else
response = JSON.parse(resp)
response["channel"].should eql(channel)
response["id"].to_i.should eql(-2)
response["text"].should eql(conf.channel_deleted_message_text)
EventMachine.stop
end
end
end
end
end
end
end
require 'spec_helper'
describe "Publisher Publishing Messages" do
let(:config) do
{
:header_template => nil,
:message_template => "~text~",
:footer_template => nil,
:ping_message_interval => nil
}
end
it "should receive the published message" do
body = 'published unique message'
channel = 'ch_test_publish_messages'
nginx_run_server(config, :timeout => 5) do |conf|
EventMachine.run do
sub = EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel.to_s).get :head => headers
sub.stream do |chunk|
chunk.should eql(body + "\r\n")
EventMachine.stop
end
pub = EventMachine::HttpRequest.new(nginx_address + '/pub?id=' + channel.to_s ).post :head => headers, :body => body, :timeout => 30
end
end
end
it "should accept messages with different bytes" do
channel = 'ch_test_publish_messages_with_different_bytes'
nginx_run_server(config.merge(:client_max_body_size => '130k', :client_body_buffer_size => '130k', :subscriber_connection_ttl => "1s"), :timeout => 5) do |conf|
ranges = [1..255]
ranges.each do |range|
bytes = []
range.each do |i|
1.upto(255) do |j|
bytes << "%s%s" % [i.chr, j.chr]
end
end
body = bytes.join('')
response = ''
EventMachine.run do
sub = EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel.to_s).get :head => headers
sub.stream do |chunk|
response += chunk
end
sub.callback do
response.bytes.to_a.should eql("#{body}\r\n".bytes.to_a)
EventMachine.stop
end
pub = EventMachine::HttpRequest.new(nginx_address + '/pub?id=' + channel.to_s ).post :head => headers, :body => body, :timeout => 30
end
end
end
end
it "should receive large messages" do
channel = 'ch_test_publish_large_messages'
body = "|123456789" * 102400 + "|"
response = ''
nginx_run_server(config.merge(:client_max_body_size => '2000k', :client_body_buffer_size => '2000k', :subscriber_connection_ttl => '2s'), :timeout => 15) do |conf|
EventMachine.run do
start = Time.now
sub = EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel.to_s).get :head => headers
sub.stream do |chunk|
response += chunk
end
sub.callback do
(Time.now - start).should be < 2 #should be disconnect right after receive the large message
response.should eql(body + "\r\n")
response = ''
start = Time.now
sub_1 = EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel.to_s + ".b1").get :head => headers
sub_1.stream do |chunk|
response += chunk
end
sub_1.callback do
(Time.now - start).should be > 2 #should be disconnected only when timeout happens
response.should eql(body + "\r\n")
EventMachine.stop
end
end
pub = EventMachine::HttpRequest.new(nginx_address + '/pub?id=' + channel.to_s ).post :head => headers, :body => body, :timeout => 30
end
end
end
it "should publish many messages in the same channel" do
body_prefix = 'published message '
channel = 'ch_test_publish_many_messages_in_the_same_channel'
messagens_to_publish = 1500
response = ""
nginx_run_server(config.merge(:max_reserved_memory => "256m", :keepalive => "on"), :timeout => 5) do |conf|
EventMachine.run do
sub = EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel.to_s).get :head => headers
sub.stream do |chunk|
response += chunk
recieved_messages = response.split("\r\n")
if recieved_messages.length == messagens_to_publish
recieved_messages.last.should eql(body_prefix + messagens_to_publish.to_s)
EventMachine.stop
end
end
EM.add_timer(0.5) do
0.step(messagens_to_publish - 1, 500) do |i|
socket = open_socket(nginx_host, nginx_port)
1.upto(500) do |j|
resp_headers, body = post_in_socket("/pub?id=#{channel}", body_prefix + (i+j).to_s, socket, "}\r\n")
fail("Message was not published: " + body_prefix + (i+j).to_s) unless resp_headers.include?("HTTP/1.1 200 OK")
end
socket.close
end
end
end
end
end
it "should set an event id to the message through header parameter" do
event_id = 'event_id_with_generic_text_01'
body = 'test message'
channel = 'ch_test_set_an_event_id_to_the_message_through_header_parameter'
response = ''
nginx_run_server(config.merge(:message_template => '{\"id\": \"~id~\", \"channel\": \"~channel~\", \"text\": \"~text~\", \"event_id\": \"~event-id~\"}'), :timeout => 5) do |conf|
EventMachine.run do
sub = EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel.to_s).get
sub.stream do |chunk|
response = JSON.parse(chunk)
response["id"].to_i.should eql(1)
response["channel"].should eql(channel)
response["text"].should eql(body)
response["event_id"].should eql(event_id)
EventMachine.stop
end
pub = EventMachine::HttpRequest.new(nginx_address + '/pub?id=' + channel.to_s ).post :head => headers.merge('Event-Id' => event_id), :body => body, :timeout => 30
end
end
end
it "should set an event type to the message through header parameter" do
event_type = 'event_type_with_generic_text_01'
body = 'test message'
channel = 'ch_test_set_an_event_type_to_the_message_through_header_parameter'
response = ''
nginx_run_server(config.merge(:message_template => '{\"id\": \"~id~\", \"channel\": \"~channel~\", \"text\": \"~text~\", \"event_type\": \"~event-type~\"}'), :timeout => 5) do |conf|
EventMachine.run do
sub = EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel.to_s).get
sub.stream do |chunk|
response = JSON.parse(chunk)
response["id"].to_i.should eql(1)
response["channel"].should eql(channel)
response["text"].should eql(body)
response["event_type"].should eql(event_type)
EventMachine.stop
end
pub = EventMachine::HttpRequest.new(nginx_address + '/pub?id=' + channel.to_s ).post :head => headers.merge('Event-type' => event_type), :body => body, :timeout => 30
end
end
end
it "should ignore event id header parameter which not match exactly" do
event_id = 'event_id_with_generic_text_01'
body = 'test message'
channel = 'ch_test_set_an_event_id_to_the_message_through_header_parameter'
response = ''
nginx_run_server(config.merge(:message_template => '{\"id\": \"~id~\", \"channel\": \"~channel~\", \"text\": \"~text~\", \"event_id\": \"~event-id~\"}'), :timeout => 5) do |conf|
EventMachine.run do
sub = EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel.to_s).get
sub.stream do |chunk|
response = JSON.parse(chunk)
response["id"].to_i.should eql(1)
response["channel"].should eql(channel)
response["text"].should eql(body)
response["event_id"].should eql("")
EventMachine.stop
end
pub = EventMachine::HttpRequest.new(nginx_address + '/pub?id=' + channel.to_s ).post :head => headers.merge('Event-Ids' => event_id), :body => body, :timeout => 30
end
EventMachine.run do
sub = EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel.to_s).get
sub.stream do |chunk|
response = JSON.parse(chunk)
response["id"].to_i.should eql(2)
response["channel"].should eql(channel)
response["text"].should eql(body)
response["event_id"].should eql("")
EventMachine.stop
end
pub = EventMachine::HttpRequest.new(nginx_address + '/pub?id=' + channel.to_s ).post :head => headers.merge('Event-I' => event_id), :body => body, :timeout => 30
end
end
end
it "should expose message publish time through message template" do
body = 'test message'
channel = 'ch_test_expose_message_publish_time_through_message_template'
response = ''
now = nil
nginx_run_server(config.merge(:message_template => '{\"id\": \"~id~\", \"channel\": \"~channel~\", \"text\": \"~text~\", \"publish_time\": \"~time~\"}'), :timeout => 5) do |conf|
EventMachine.run do
sub = EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel.to_s).get
sub.stream do |chunk|
response = JSON.parse(chunk)
response["id"].to_i.should eql(1)
response["channel"].should eql(channel)
response["text"].should eql(body)
response["publish_time"].size.should eql(29)
publish_time = Time.parse(response["publish_time"])
publish_time.to_i.should be_in_the_interval(now.to_i, now.to_i + 1)
EventMachine.stop
end
now = Time.now
pub = EventMachine::HttpRequest.new(nginx_address + '/pub?id=' + channel.to_s ).post :head => headers, :body => body, :timeout => 30
end
end
end
it "should expose message tag through message template" do
body = 'test message'
channel = 'ch_test_expose_message_tag_through_message_template'
response = ''
nginx_run_server(config.merge(:message_template => '{\"id\": \"~id~\", \"channel\": \"~channel~\", \"text\": \"~text~\", \"tag\": \"~tag~\"}'), :timeout => 5) do |conf|
EventMachine.run do
sub = EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel.to_s).get
sub.stream do |chunk|
response += chunk
lines = response.split('\r\n')
if lines.size > 1
lines.each_with_index do |line, i|
resp = JSON.parse(line)
resp["id"].to_i.should eql(i + 1)
resp["channel"].should eql(channel)
resp["text"].should eql(body)
resp["tag"].to_i.should eql(i)
end
end
EventMachine.stop
end
pub = EventMachine::HttpRequest.new(nginx_address + '/pub?id=' + channel.to_s ).post :head => headers, :body => body, :timeout => 30
pub = EventMachine::HttpRequest.new(nginx_address + '/pub?id=' + channel.to_s ).post :head => headers, :body => body, :timeout => 30
end
end
end
end
require 'rubygems'
# Set up gems listed in the Gemfile.
ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../Gemfile', __FILE__)
require 'bundler/setup' if File.exists?(ENV['BUNDLE_GEMFILE'])
Bundler.require(:default, :test) if defined?(Bundler)
require 'nginx_configuration'
RSpec.configure do |config|
config.after(:each) do
NginxTestHelper::Config.delete_config_and_log_files(config_id) if has_passed?
end
config.order = "random"
end
def publish_message_inline(channel, headers, body, &block)
pub = EventMachine::HttpRequest.new(nginx_address + '/pub?id=' + channel.to_s).post :head => headers, :body => body, :timeout => 30
pub.callback do
fail("Request was not accepted") if pub.response_header.status != 200
block.call unless block.nil?
end
pub
end
def publish_message(channel, headers, body)
EventMachine.run do
pub = publish_message_inline(channel, headers, body) do
pub.response_header.content_length.should_not eql(0)
response = JSON.parse(pub.response)
response["channel"].to_s.should eql(channel)
EventMachine.stop
end
end
end
def create_channel_by_subscribe(channel, headers, timeout=60, &block)
EventMachine.run do
sub_1 = EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel.to_s).get :head => headers, :timeout => timeout
sub_1.stream do |chunk|
block.call
end
sub_1.callback do
EventMachine.stop
end
end
end
def publish_message_inline_with_callbacks(channel, headers, body, callbacks = {})
pub = EventMachine::HttpRequest.new(nginx_address + '/pub?id=' + channel.to_s).post :head => headers, :body => body, :timeout => 30
pub.callback do
if pub.response_header.status == 200
callbacks[:success].call(pub.response_header.status, pub.response) unless callbacks[:success].nil?
else
callbacks[:error].call(pub.response_header.status, pub.response) unless callbacks[:error].nil?
end
end
pub
end
require 'spec_helper'
describe "Comunication Properties" do
let(:config) do
{
:authorized_channels_only => "off",
:header_template => "connected",
:message_ttl => "12s",
:message_template => "~text~",
:ping_message_interval => "1s"
}
end
it "should not block to connected to a nonexistent channel" do
channel = 'ch_test_all_authorized'
nginx_run_server(config, :timeout => 5) do |conf|
EventMachine.run do
sub = EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel.to_s).get :head => headers, :timeout => 60
sub.stream do |chunk|
chunk.should eql("#{conf.header_template}\r\n")
EventMachine.stop
end
end
end
end
it "should block to connected to a nonexistent channel when authorized only is 'on'" do
channel = 'ch_test_only_authorized'
body = 'message to create a channel'
nginx_run_server(config.merge(:authorized_channels_only => "on"), :timeout => 5) do |conf|
EventMachine.run do
sub_1 = EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel.to_s).get :head => headers, :timeout => 60
sub_1.callback do |chunk|
sub_1.response_header.status.should eql(403)
sub_1.response_header.content_length.should eql(0)
sub_1.response_header['X_NGINX_PUSHSTREAM_EXPLAIN'].should eql("Subscriber could not create channels.")
pub = EventMachine::HttpRequest.new(nginx_address + '/pub?id=' + channel.to_s ).post :head => headers, :body => body, :timeout => 30
pub.callback do
sub_2 = EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel.to_s).get :head => headers, :timeout => 60
sub_2.stream do |chunk2|
chunk2.should eql("#{conf.header_template}\r\n")
EventMachine.stop
end
end
end
end
end
end
it "should discard messages published a more time than the value configured to message ttl" do
channel = 'ch_test_message_ttl'
body = 'message to test buffer timeout '
response_1 = response_2 = response_3 = ""
sub_1 = sub_2 = sub_3 = nil
nginx_run_server(config, :timeout => 20) do |conf|
EventMachine.run do
pub = EventMachine::HttpRequest.new(nginx_address + '/pub?id=' + channel.to_s ).post :head => headers, :body => body, :timeout => 30
time_2 = EM.add_timer(2) do
sub_1 = EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel.to_s + '.b1').get :head => headers, :timeout => 60
sub_1.stream do |chunk|
response_1 += chunk unless response_1.include?(body)
sub_1.close if response_1.include?(body)
end
end
EM.add_timer(6) do
sub_2 = EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel.to_s + '.b1').get :head => headers, :timeout => 60
sub_2.stream do |chunk|
response_2 += chunk unless response_2.include?(body)
sub_2.close if response_2.include?(body)
end
end
#message will be certainly expired at 15 seconds
EM.add_timer(16) do
sub_3 = EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel.to_s + '.b1').get :head => headers, :timeout => 60
sub_3.stream do |chunk|
response_3 += chunk unless response_3.include?(body)
sub_3.close if response_3.include?(body)
end
end
EM.add_timer(17) do
response_1.should eql("#{conf.header_template}\r\n#{body}\r\n")
response_2.should eql("#{conf.header_template}\r\n#{body}\r\n")
response_3.should eql("#{conf.header_template}\r\n")
EventMachine.stop
end
end
end
end
it "should apply the message template to published message with the available keyworkds" do
channel = 'ch_test_message_template'
body = 'message to create a channel'
response = ""
nginx_run_server(config.merge(:message_template => '{\"duplicated\":\"~channel~\", \"channel\":\"~channel~\", \"message\":\"~text~\", \"message_id\":\"~id~\"}'), :timeout => 5) do |conf|
publish_message(channel, headers, body)
EventMachine.run do
sub = EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel.to_s + '.b1').get :head => headers, :timeout => 60
sub.stream do |chunk|
response += chunk
lines = response.split("\r\n")
if lines.length >= 3
lines[0].should eql("#{conf.header_template}")
lines[1].should eql("{\"duplicated\":\"#{channel}\", \"channel\":\"#{channel}\", \"message\":\"#{body}\", \"message_id\":\"1\"}")
lines[2].should eql("{\"duplicated\":\"\", \"channel\":\"\", \"message\":\"\", \"message_id\":\"-1\"}")
EventMachine.stop
end
end
end
end
end
it "should not be in loop when channel or published message contains one of the keywords" do
channel = 'ch_test_message_and_channel_with_same_pattern_of_the_template~channel~~channel~~channel~~text~~text~~text~'
body = '~channel~~channel~~channel~~text~~text~~text~'
response = ""
nginx_run_server(config.merge(:message_template => '{\"channel\":\"~channel~\", \"message\":\"~text~\", \"message_id\":\"~id~\"}'), :timeout => 5) do |conf|
publish_message(channel, headers, body)
EventMachine.run do
sub = EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel.to_s + '.b1').get :head => headers, :timeout => 60
sub.stream do |chunk|
response += chunk
lines = response.split("\r\n")
if lines.length >= 3
lines[0].should eql("#{conf.header_template}")
lines[1].should eql("{\"channel\":\"ch_test_message_and_channel_with_same_pattern_of_the_template~channel~~channel~~channel~~channel~~channel~~channel~~text~~text~~text~~channel~~channel~~channel~~text~~text~~text~~channel~~channel~~channel~~text~~text~~text~\", \"message\":\"~channel~~channel~~channel~~text~~text~~text~\", \"message_id\":\"1\"}")
lines[2].should eql("{\"channel\":\"\", \"message\":\"\", \"message_id\":\"-1\"}")
EventMachine.stop
end
end
end
end
end
end
require 'spec_helper'
describe "Subscriber Connection Cleanup" do
let(:config) do
{
:subscriber_connection_ttl => '17s',
:header_template => 'HEADER_TEMPLATE',
:footer_template => 'FOOTER_TEMPLATE',
:ping_message_interval => '3s'
}
end
it "should disconnect the subscriber after the configured connection ttl be reached" do
channel = 'ch_test_subscriber_connection_timeout'
nginx_run_server(config.merge(:ping_message_interval => nil), :timeout => 25) do |conf|
start = Time.now
response = ''
EventMachine.run do
sub = EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel.to_s, :inactivity_timeout => 20).get :head => headers
sub.stream do |chunk|
response += chunk
response.should include(conf.header_template)
end
sub.callback do
stop = Time.now
time_diff_sec(start, stop).should be_in_the_interval(17, 17.5)
response.should include(conf.footer_template)
EventMachine.stop
end
end
end
end
it "should disconnect the subscriber after the configured connection ttl be reached with ping message" do
channel = 'ch_test_subscriber_connection_timeout_with_ping_message'
nginx_run_server(config.merge(:header_template => nil, :footer_template => nil), :timeout => 25) do |conf|
start = Time.now
chunks_received = 0
EventMachine.run do
sub = EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel.to_s).get :head => headers
sub.stream do |chunk|
chunks_received += 1
end
sub.callback do
stop = Time.now
time_diff_sec(start, stop).should be_in_the_interval(17, 17.5)
chunks_received.should be_eql(5)
EventMachine.stop
end
end
end
end
it "should disconnect each subscriber after the configured connection ttl be reached starting when it connects" do
channel = 'ch_test_multiple_subscribers_connection_timeout'
nginx_run_server(config.merge(:subscriber_connection_ttl => '5s', :ping_message_interval => nil), :timeout => 25) do |conf|
EventMachine.run do
response_1 = ''
sub_1 = EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel.to_s).get :head => headers
sub_1.stream do |chunk|
response_1 += chunk
response_1.should include(conf.header_template)
end
sub_1.callback do
response_1.should include(conf.footer_template)
end
sleep(2)
response_2 = ''
sub_2 = EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel.to_s).get :head => headers
sub_2.stream do |chunk|
response_2 += chunk
response_2.should include(conf.header_template)
end
sub_2.callback do
response_2.should include(conf.footer_template)
response_4 = ''
sub_4 = EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel.to_s).get :head => headers
sub_4.stream do |chunk|
response_4 += chunk
response_4.should include(conf.header_template)
end
sub_4.callback do
response_4.should include(conf.footer_template)
EventMachine.stop
end
end
sleep(6)
response_3 = ''
sub_3 = EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel.to_s).get :head => headers
sub_3.stream do |chunk|
response_3 += chunk
response_3.should include(conf.header_template)
end
sub_3.callback do
response_3.should include(conf.footer_template)
end
end
end
end
end
require 'spec_helper'
describe "Subscriber Event Source" do
let(:config) do
{
:eventsource_support => 'on',
:header_template => nil,
:message_template => nil,
:footer_template => nil,
:ping_message_interval => nil
}
end
it "should use content type as 'event stream'" do
channel = 'ch_test_content_type_should_be_event_stream'
nginx_run_server(config.merge(:header_template => "header"), :timeout => 5) do |conf|
EventMachine.run do
sub = EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel.to_s).get
sub.stream do |chunk|
sub.response_header["CONTENT_TYPE"].should eql("text/event-stream; charset=utf-8")
EventMachine.stop
end
end
end
end
it "should split header lines and prefix them by a colon" do
channel = 'ch_test_each_line_on_header_template_should_be_prefixed_by_a_colon'
nginx_run_server(config.merge(:header_template => "header line 1\nheader line 2\rheader line 3\r\nheader line 4"), :timeout => 5) do |conf|
EventMachine.run do
sub = EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel.to_s).get
sub.stream do |chunk|
chunk.should eql(": header line 1\r\n: header line 2\r\n: header line 3\r\n: header line 4\r\n\r\n")
EventMachine.stop
end
end
end
end
it "should treat escaped new lines on header as single lines" do
channel = 'ch_test_escaped_new_lines_on_header_template_should_be_treated_as_single_line'
nginx_run_server(config.merge(:header_template => "header line 1\\\\nheader line 2"), :timeout => 5) do |conf|
EventMachine.run do
sub = EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel.to_s).get
sub.stream do |chunk|
chunk.should eql(": header line 1\\nheader line 2\r\n\r\n")
EventMachine.stop
end
end
end
end
it "should split footer lines and prefix them by a colon" do
channel = 'ch_test_each_line_on_footer_template_should_be_prefixed_by_a_colon'
response = ''
nginx_run_server(config.merge(:subscriber_connection_ttl => '1s', :footer_template => "footer line 1\nfooter line 2\rfooter line 3\r\nfooter line 4"), :timeout => 5) do |conf|
EventMachine.run do
sub = EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel.to_s).get
sub.stream do |chunk|
response += chunk
end
sub.callback do
response.should eql(":\r\n: footer line 1\r\n: footer line 2\r\n: footer line 3\r\n: footer line 4\r\n\r\n")
EventMachine.stop
end
end
end
end
it "should treat escaped new lines on footer as single lines" do
channel = 'ch_test_escaped_new_lines_on_footer_template_should_be_treated_as_single_line'
response = ''
nginx_run_server(config.merge(:subscriber_connection_ttl => '1s', :footer_template => "footer line 1\\\\nfooter line 2"), :timeout => 5) do |conf|
EventMachine.run do
sub = EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel.to_s).get
sub.stream do |chunk|
response += chunk
end
sub.callback do
response.should eql(":\r\n: footer line 1\\nfooter line 2\r\n\r\n")
EventMachine.stop
end
end
end
end
it "should use default message template without event id" do
body = 'test message'
channel = 'ch_test_default_message_template_without_event_id'
response = ''
nginx_run_server(config, :timeout => 5) do |conf|
EventMachine.run do
sub = EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel.to_s).get
sub.stream do |chunk|
response += chunk
if response.include?("\r\n\r\n")
response.should eql(":\r\ndata: #{body}\r\n\r\n")
EventMachine.stop
end
end
publish_message_inline(channel, headers, body)
end
end
end
it "should use default message template without event type" do
body = 'test message'
channel = 'ch_test_default_message_template_without_event_type'
response = ''
nginx_run_server(config, :timeout => 5) do |conf|
EventMachine.run do
sub = EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel.to_s).get
sub.stream do |chunk|
response += chunk
if response.include?("\r\n\r\n")
response.should eql(":\r\ndata: #{body}\r\n\r\n")
EventMachine.stop
end
end
publish_message_inline(channel, headers, body)
end
end
end
it "should use default message template with event id" do
event_id = 'event_id_with_generic_text_01'
body = 'test message'
channel = 'ch_test_default_message_template_with_event_id'
response = ''
nginx_run_server(config, :timeout => 5) do |conf|
EventMachine.run do
sub = EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel.to_s).get
sub.stream do |chunk|
response += chunk
if response.include?("\r\n\r\n")
response.should eql(":\r\nid: #{event_id}\r\ndata: #{body}\r\n\r\n")
EventMachine.stop
end
end
publish_message_inline(channel, headers.merge('Event-Id' => event_id), body)
end
end
end
it "should use default message template with event type" do
event_type = 'event_type_with_generic_text_01'
body = 'test message'
channel = 'ch_test_default_message_template_with_event_type'
response = ''
nginx_run_server(config, :timeout => 5) do |conf|
EventMachine.run do
sub = EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel.to_s).get
sub.stream do |chunk|
response += chunk
if response.include?("\r\n\r\n")
response.should eql(":\r\nevent: #{event_type}\r\ndata: #{body}\r\n\r\n")
EventMachine.stop
end
end
publish_message_inline(channel, headers.merge('Event-type' => event_type), body)
end
end
end
it "should use custom message template without event id" do
body = 'test message'
channel = 'ch_test_custom_message_template_without_event_id'
response = ''
nginx_run_server(config.merge(:message_template => '{\"id\":\"~id~\", \"message\":\"~text~\"}'), :timeout => 5) do |conf|
EventMachine.run do
sub = EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel.to_s).get
sub.stream do |chunk|
response += chunk
if response.include?("\r\n\r\n")
response.should eql(%(:\r\ndata: {"id":"1", "message":"#{body}"}\r\n\r\n))
EventMachine.stop
end
end
publish_message_inline(channel, headers, body)
end
end
end
it "should use custom message template without event type" do
body = 'test message'
channel = 'ch_test_custom_message_template_without_event_type'
response = ''
nginx_run_server(config.merge(:message_template => '{\"id\":\"~id~\", \"message\":\"~text~\"}'), :timeout => 5) do |conf|
EventMachine.run do
sub = EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel.to_s).get
sub.stream do |chunk|
response += chunk
if response.include?("\r\n\r\n")
response.should eql(%(:\r\ndata: {"id":"1", "message":"#{body}"}\r\n\r\n))
EventMachine.stop
end
end
publish_message_inline(channel, headers, body)
end
end
end
it "should use custom message template with event id" do
event_id = 'event_id_with_generic_text_01'
body = 'test message'
channel = 'ch_test_custom_message_template_with_event_id'
response = ''
nginx_run_server(config.merge(:message_template => '{\"id\":\"~id~\", \"message\":\"~text~\"}'), :timeout => 5) do |conf|
EventMachine.run do
sub = EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel.to_s).get
sub.stream do |chunk|
response += chunk
if response.include?("\r\n\r\n")
response.should eql(%(:\r\nid: #{event_id}\r\ndata: {"id":"1", "message":"#{body}"}\r\n\r\n))
EventMachine.stop
end
end
publish_message_inline(channel, headers.merge('Event-Id' => event_id), body)
end
end
end
it "should use custom message template with event type" do
event_type = 'event_type_with_generic_text_01'
body = 'test message'
channel = 'ch_test_custom_message_template_with_event_type'
response = ''
nginx_run_server(config.merge(:message_template => '{\"id\":\"~id~\", \"message\":\"~text~\"}'), :timeout => 5) do |conf|
EventMachine.run do
sub = EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel.to_s).get
sub.stream do |chunk|
response += chunk
if response.include?("\r\n\r\n")
response.should eql(%(:\r\nevent: #{event_type}\r\ndata: {"id":"1", "message":"#{body}"}\r\n\r\n))
EventMachine.stop
end
end
publish_message_inline(channel, headers.merge('Event-type' => event_type), body)
end
end
end
it "should apply the message template to each line on posted message" do
body = "line 1\nline 2\rline 3\r\nline 4"
channel = 'ch_test_each_line_on_posted_message_should_be_applied_to_template'
nginx_run_server(config, :timeout => 5) do |conf|
EventMachine.run do
sub = EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel.to_s).get
sub.stream do |chunk|
if chunk.include?("line 4")
chunk.should eql("data: line 1\r\ndata: line 2\r\ndata: line 3\r\ndata: line 4\r\n\r\n")
EventMachine.stop
end
end
publish_message_inline(channel, headers, body)
end
end
end
it "should treat escaped new lines on posted message as single lines" do
body = "line 1\\nline 2"
channel = 'ch_test_escaped_new_lines_on_posted_message_should_be_treated_as_single_line'
nginx_run_server(config, :timeout => 5) do |conf|
EventMachine.run do
sub = EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel.to_s).get
sub.stream do |chunk|
if chunk.include?("line 2")
chunk.should eql("data: line 1\\nline 2\r\n\r\n")
EventMachine.stop
end
end
publish_message_inline(channel, headers, body)
end
end
end
it "should receive ping message" do
channel = 'ch_test_ping_message_on_event_source'
nginx_run_server(config.merge(:ping_message_interval => '1s', :message_template => '{\"id\":\"~id~\", \"message\":\"~text~\"}'), :timeout => 5) do |conf|
EventMachine.run do
sub = EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel.to_s).get
sub.stream do |chunk|
if chunk.include?("-1")
chunk.should eql(": -1\r\n")
EventMachine.stop
end
end
end
end
end
it "should get old messages by last event id" do
channel = 'ch_test_get_old_messages_by_last_event_id'
response = ''
nginx_run_server(config, :timeout => 5) do |conf|
EventMachine.run do
publish_message_inline(channel, headers.merge({'Event-Id' => 'event 1'}), 'msg 1')
publish_message_inline(channel, headers.merge({'Event-Id' => 'event 2'}), 'msg 2')
publish_message_inline(channel, headers, 'msg 3')
publish_message_inline(channel, headers.merge({'Event-Id' => 'event 3'}), 'msg 4')
sub = EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel.to_s).get :head => {'Last-Event-Id' => 'event 2' }
sub.stream do |chunk|
response += chunk
if response.include?("msg 4")
response.should eql(":\r\ndata: msg 3\r\n\r\nid: event 3\r\ndata: msg 4\r\n\r\n")
EventMachine.stop
end
end
end
end
end
it "should get old messages by last event id without found an event" do
channel = 'ch_test_get_old_messages_by_last_event_id_without_found_event'
response = ''
nginx_run_server(config.merge(:ping_message_interval => '1s'), :timeout => 5) do |conf|
EventMachine.run do
publish_message_inline(channel, headers.merge({'Event-Id' => 'event 1'}), 'msg 1')
publish_message_inline(channel, headers.merge({'Event-Id' => 'event 2'}), 'msg 2')
publish_message_inline(channel, headers, 'msg 3')
publish_message_inline(channel, headers.merge({'Event-Id' => 'event 3'}), 'msg 4')
sub = EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel.to_s).get :head => {'Last-Event-Id' => 'event_not_found' }
sub.stream do |chunk|
if chunk.include?("-1")
chunk.should eql(": -1\r\n")
EventMachine.stop
end
end
end
end
end
end
require 'spec_helper'
describe "Subscriber Properties" do
shared_examples_for "long polling location" do
it "should disconnect after receive a message" do
channel = 'ch_test_disconnect_after_receive_a_message_when_longpolling_is_on'
body = 'body'
response = ""
nginx_run_server(config, :timeout => 5) do |conf|
EventMachine.run do
sub_1 = EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel.to_s).get :head => headers
sub_1.stream do |chunk|
response += chunk
end
sub_1.callback do |chunk|
response.should eql("#{body}\r\n")
sent_headers = headers.merge({'If-Modified-Since' => sub_1.response_header['LAST_MODIFIED'], 'If-None-Match' => sub_1.response_header['ETAG']})
response = ""
sub_2 = EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel.to_s).get :head => sent_headers
sub_2.stream do |chunk2|
response += chunk2
end
sub_2.callback do
response.should eql("#{body} 1\r\n")
EventMachine.stop
end
publish_message_inline(channel, {}, body + " 1")
end
publish_message_inline(channel, {}, body)
end
end
end
it "should disconnect after receive old messages by backtrack" do
channel = 'ch_test_disconnect_after_receive_old_messages_by_backtrack_when_longpolling_is_on'
response = ""
nginx_run_server(config, :timeout => 5) do |conf|
EventMachine.run do
publish_message_inline(channel, {}, 'msg 1')
publish_message_inline(channel, {}, 'msg 2')
publish_message_inline(channel, {}, 'msg 3')
publish_message_inline(channel, {}, 'msg 4')
sub = EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel.to_s + '.b2').get :head => headers
sub.stream do |chunk|
response += chunk
end
sub.callback do |chunk|
response.should eql("msg 3\r\nmsg 4\r\n")
response = ''
sub_1 = EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel.to_s).get :head => headers.merge({'If-Modified-Since' => sub.response_header['LAST_MODIFIED'], 'If-None-Match' => sub.response_header['ETAG']})
sub_1.stream do |chunk2|
response += chunk2
end
sub_1.callback do
response.should eql("msg 5\r\n")
EventMachine.stop
end
publish_message_inline(channel, {}, 'msg 5')
end
end
end
end
it "should disconnect after receive old messages by 'last_event_id'" do
channel = 'ch_test_disconnect_after_receive_old_messages_by_last_event_id_when_longpolling_is_on'
response = ""
nginx_run_server(config, :timeout => 5) do |conf|
EventMachine.run do
publish_message_inline(channel, {'Event-Id' => 'event 1'}, 'msg 1')
publish_message_inline(channel, {'Event-Id' => 'event 2'}, 'msg 2')
publish_message_inline(channel, {}, 'msg 3')
publish_message_inline(channel, {'Event-Id' => 'event 3'}, 'msg 4')
sub = EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel.to_s).get :head => headers.merge({'Last-Event-Id' => 'event 2'})
sub.stream do |chunk|
response += chunk
end
sub.callback do |chunk|
response.should eql("msg 3\r\nmsg 4\r\n")
EventMachine.stop
end
end
end
end
it "should disconnect after receive old messages from different channels" do
channel_1 = 'ch_test_receive_old_messages_from_different_channels_1'
channel_2 = 'ch_test_receive_old_messages_from_different_channels_2'
body = 'body'
response = ""
nginx_run_server(config, :timeout => 5) do |conf|
EventMachine.run do
publish_message_inline(channel_1, {}, body + "_1")
publish_message_inline(channel_2, {}, body + "_2")
sub_1 = EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel_2.to_s + '/' + channel_1.to_s).get :head => headers
sub_1.callback do
sub_1.response_header.status.should eql(200)
sub_1.response_header['LAST_MODIFIED'].to_s.should_not eql("")
sub_1.response_header['ETAG'].to_s.should_not eql("")
sub_1.response.should eql("#{body}_2\r\n#{body}_1\r\n")
sent_headers = headers.merge({'If-Modified-Since' => sub_1.response_header['LAST_MODIFIED'], 'If-None-Match' => sub_1.response_header['ETAG']})
sub_2 = EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel_2.to_s + '/' + channel_1.to_s).get :head => sent_headers
sub_2.callback do
sub_2.response_header.status.should eql(200)
sub_2.response_header['LAST_MODIFIED'].to_s.should_not eql(sub_1.response_header['LAST_MODIFIED'])
sub_2.response_header['ETAG'].to_s.should eql("0")
sub_2.response.should eql("#{body}1_1\r\n")
sent_headers = headers.merge({'If-Modified-Since' => sub_2.response_header['LAST_MODIFIED'], 'If-None-Match' => sub_2.response_header['ETAG']})
sub_3 = EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel_2.to_s + '/' + channel_1.to_s).get :head => sent_headers
sub_3.callback do
sub_3.response_header.status.should eql(200)
sub_3.response_header['LAST_MODIFIED'].to_s.should_not eql(sub_2.response_header['LAST_MODIFIED'])
sub_3.response_header['ETAG'].to_s.should eql("0")
sub_3.response.should eql("#{body}1_2\r\n")
EventMachine.stop
end
sleep(1) # to publish the second message in a different second from the first
publish_message_inline(channel_2, {}, body + "1_2")
end
sleep(1) # to publish the second message in a different second from the first
publish_message_inline(channel_1, {}, body + "1_1")
end
end
end
end
it "should disconnect after timeout is reached" do
channel = 'ch_test_disconnect_long_polling_subscriber_when_longpolling_timeout_is_set'
start = Time.now
nginx_run_server(config.merge(:subscriber_connection_ttl => "10s"), :timeout => 30) do |conf|
EventMachine.run do
sub = EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel.to_s).get :head => headers
sub.callback do
stop = Time.now
time_diff_sec(start, stop).should be_in_the_interval(10, 10.5)
sub.response_header.status.should eql(304)
Time.parse(sub.response_header['LAST_MODIFIED'].to_s).utc.to_i.should be_in_the_interval(Time.now.utc.to_i-1, Time.now.utc.to_i)
sub.response_header['ETAG'].to_s.should eql("0")
sub.response_header.content_length.should eql(0)
EventMachine.stop
end
end
end
end
it "should overwrite subscriber timeout with long polling timeout" do
channel = 'ch_test_disconnect_long_polling_subscriber_when_longpolling_timeout_is_set'
start = Time.now
nginx_run_server(config.merge(:subscriber_connection_ttl => "10s", :longpolling_connection_ttl => "5s"), :timeout => 10) do |conf|
EventMachine.run do
sub = EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel.to_s).get :head => headers
sub.callback do
stop = Time.now
time_diff_sec(start, stop).should be_in_the_interval(5, 5.5)
sub.response_header.status.should eql(304)
Time.parse(sub.response_header['LAST_MODIFIED'].to_s).utc.to_i.should be_in_the_interval(Time.now.utc.to_i-1, Time.now.utc.to_i)
sub.response_header['ETAG'].to_s.should eql("0")
sub.response_header.content_length.should eql(0)
EventMachine.stop
end
end
end
end
it "should disconnet after timeout be reached when only long polling timeout is set" do
channel = 'ch_test_disconnect_long_polling_subscriber_when_only_longpolling_timeout_is_set'
start = Time.now
nginx_run_server(config.merge(:subscriber_connection_ttl => nil, :longpolling_connection_ttl => "3s"), :timeout => 5) do |conf|
EventMachine.run do
sub = EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel.to_s).get :head => headers
sub.callback do
stop = Time.now
time_diff_sec(start, stop).should be_in_the_interval(3, 3.5)
sub.response_header.status.should eql(304)
Time.parse(sub.response_header['LAST_MODIFIED'].to_s).utc.to_i.should be_in_the_interval(Time.now.utc.to_i-1, Time.now.utc.to_i)
sub.response_header['ETAG'].to_s.should eql("0")
sub.response_header.content_length.should eql(0)
EventMachine.stop
end
end
end
end
it "should not receive ping message" do
channel = 'ch_test_not_receive_ping_message'
start = Time.now
nginx_run_server(config.merge(:subscriber_connection_ttl => "5s", :ping_message_interval => "1s"), :timeout => 10) do |conf|
EventMachine.run do
sub = EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel.to_s).get :head => headers
sub.callback do
stop = Time.now
time_diff_sec(start, stop).should be_in_the_interval(5, 5.5)
sub.response_header.status.should eql(304)
sub.response_header.content_length.should eql(0)
EventMachine.stop
end
end
end
end
it "should receive messages with etag greather than recent message" do
channel = 'ch_test_receiving_messages_with_etag_greather_than_recent_message'
body_prefix = 'published message '
messagens_to_publish = 10
nginx_run_server(config.merge(:store_messages => "on", :message_template => '{\"id\":\"~id~\", \"message\":\"~text~\"}'), :timeout => 5) do |conf|
EventMachine.run do
i = 0
stored_messages = 0
EM.add_periodic_timer(0.001) do
if i < messagens_to_publish
i += 1
publish_message_inline(channel.to_s, headers, body_prefix + i.to_s)
else
end
end
EM.add_timer(1) do
pub = EventMachine::HttpRequest.new(nginx_address + '/pub?id=' + channel.to_s ).post :head => headers, :body => body_prefix + i.to_s
pub.callback do
response = JSON.parse(pub.response)
stored_messages = response["stored_messages"].to_i
end
end
EM.add_timer(2) do
sub = EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel.to_s).get :head => headers.merge({'If-Modified-Since' => 'Thu, 1 Jan 1970 00:00:00 GMT', 'If-None-Match' => 0})
sub.callback do
sub.response_header.status.should eql(200)
stored_messages.should eql(messagens_to_publish + 1)
messages = sub.response.split("\r\n")
messages.count.should eql(messagens_to_publish + 1)
messages.each_with_index do |content, index|
message = JSON.parse(content)
message["id"].to_i.should eql(index + 1)
end
EventMachine.stop
end
end
end
end
end
it "should receive messages when connected in more than one channel" do
channel_1 = 'ch_test_receiving_messages_when_connected_in_more_then_one_channel_1'
channel_2 = 'ch_test_receiving_messages_when_connected_in_more_then_one_channel_2'
body = 'published message'
nginx_run_server(config.merge(:store_messages => "on", :message_template => '{\"id\":\"~id~\", \"message\":\"~text~\", \"channel\":\"~channel~\"}'), :timeout => 5) do |conf|
EventMachine.run do
sub_1 = EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel_1.to_s + '/' + channel_2.to_s).get :head => headers.merge({'If-Modified-Since' => 'Thu, 1 Jan 1970 00:00:00 GMT', 'If-None-Match' => 0})
sub_1.callback do
sub_1.response_header.status.should eql(200)
response = JSON.parse(sub_1.response)
response["channel"].should eql(channel_1)
sub_2 = EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel_1.to_s + '/' + channel_2.to_s).get :head => headers.merge({'If-Modified-Since' => sub_1.response_header['LAST_MODIFIED'], 'If-None-Match' => sub_1.response_header['ETAG']})
sub_2.callback do
sub_2.response_header.status.should eql(200)
response = JSON.parse(sub_2.response)
response["channel"].should eql(channel_2)
sub_2.response_header['ETAG'].to_i.should eql(sub_1.response_header['ETAG'].to_i + 1)
EventMachine.stop
end
end
publish_message_inline(channel_1.to_s, headers, body)
publish_message_inline(channel_2.to_s, headers, body)
end
end
end
it "should accept delete a channel with a long polling subscriber" do
channel = 'ch_test_delete_channel_with_long_polling_subscriber'
body = 'published message'
resp = ""
nginx_run_server(config.merge(:publisher_mode => 'admin', :message_template => '{\"id\":\"~id~\", \"message\":\"~text~\", \"channel\":\"~channel~\"}'), :timeout => 5) do |conf|
EventMachine.run do
sub_1 = EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel.to_s).get :head => headers
sub_1.callback do
sub_1.response_header.status.should eql(200)
response = JSON.parse(sub_1.response)
response["channel"].should eql(channel)
response["id"].to_i.should eql(-2)
EventMachine.stop
end
pub = EventMachine::HttpRequest.new(nginx_address + '/pub?id=' + channel.to_s).delete :head => headers
pub.callback do
pub.response_header.status.should eql(200)
pub.response_header.content_length.should eql(0)
pub.response_header['X_NGINX_PUSHSTREAM_EXPLAIN'].should eql("Channel deleted.")
end
end
end
end
it "should accept send modified since and none match values without using header" do
channel = 'ch_test_send_modified_since_and_none_match_values_not_using_headers'
body = 'body'
response = ""
nginx_run_server(config.merge(:last_received_message_time => "$arg_time", :last_received_message_tag => "$arg_tag"), :timeout => 5) do |conf|
EventMachine.run do
sub_1 = EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel.to_s).get :head => headers
sub_1.stream do |chunk|
response += chunk
end
sub_1.callback do |chunk|
response.should eql("#{body}\r\n")
time = sub_1.response_header['LAST_MODIFIED']
tag = sub_1.response_header['ETAG']
response = ""
sub_2 = EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel.to_s + '?time=' + time + '&tag=' + tag).get :head => headers
sub_2.stream do |chunk2|
response += chunk2
end
sub_2.callback do
response.should eql("#{body} 1\r\n")
EventMachine.stop
end
publish_message_inline(channel, {}, body + " 1")
end
publish_message_inline(channel, {}, body)
end
end
end
it "should accept a callback parameter to be used with JSONP" do
channel = 'ch_test_return_message_using_function_name_specified_in_callback_parameter'
body = 'body'
response = ""
callback_function_name = "callback_function"
nginx_run_server(config, :timeout => 5) do |conf|
EventMachine.run do
sub_1 = EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel.to_s + '?callback=' + callback_function_name).get :head => headers
sub_1.callback do
sub_1.response.should eql("#{callback_function_name}\r\n([#{body}\r\n]);\r\n")
EventMachine.stop
end
publish_message_inline(channel, {}, body)
end
end
end
it "should return old messages using function name specified in callback parameter grouping in one answer" do
channel = 'ch_test_return_old_messages_using_function_name_specified_in_callback_parameter_grouping_in_one_answer'
body = 'body'
response = ""
callback_function_name = "callback_function"
nginx_run_server(config, :timeout => 5) do |conf|
EventMachine.run do
publish_message_inline(channel, {}, body)
publish_message_inline(channel, {}, body + "1")
sub_1 = EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel.to_s + '.b2' + '?callback=' + callback_function_name).get :head => headers
sub_1.callback do
sub_1.response.should eql("#{callback_function_name}\r\n([#{body}\r\n,#{body + "1"}\r\n,]);\r\n")
EventMachine.stop
end
end
end
end
it "should force content_type to be application/javascript when using function name specified in callback parameter" do
channel = 'test_force_content_type_to_be_application_javascript_when_using_function_name_specified_in_callback_parameter_when_polling'
body = 'body'
response = ""
callback_function_name = "callback_function"
nginx_run_server(config.merge({:content_type => "anything/value"}), :timeout => 5) do |conf|
EventMachine.run do
sent_headers = headers.merge({'accept' => 'otherknown/value'})
sub_1 = EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel.to_s + '?callback=' + callback_function_name).get :head => sent_headers
sub_1.callback do
sub_1.response_header['CONTENT_TYPE'].should eql('application/javascript')
EventMachine.stop
end
publish_message_inline(channel, {}, body)
end
end
end
end
context "when using subscriber push mode config" do
let(:config) do
{
:ping_message_interval => nil,
:header_template => nil,
:footer_template => nil,
:message_template => nil,
:subscriber_mode => 'long-polling'
}
end
let(:headers) do
{'accept' => 'text/html'}
end
it_should_behave_like "long polling location"
end
context "when using push mode header" do
let(:config) do
{
:ping_message_interval => nil,
:header_template => nil,
:footer_template => nil,
:message_template => nil,
:subscriber_mode => nil
}
end
let(:headers) do
{'accept' => 'text/html', 'X-Nginx-PushStream-Mode' => 'long-polling'}
end
it_should_behave_like "long polling location"
end
end
require 'spec_helper'
describe "Subscriber Padding by user agent" do
let(:config) do
{
:padding_by_user_agent => "[T|t]est 1,1024,508:[T|t]est 2,4097,0",
:user_agent => nil,
:subscriber_connection_ttl => '1s',
:header_template => nil,
:message_template => nil,
:footer_template => nil
}
end
it "should apply a padding to the header" do
channel = 'ch_test_header_padding'
nginx_run_server(config.merge(:header_template => "0123456789"), :timeout => 5) do |conf|
EventMachine.run do
sub_1 = EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel.to_s).get :head => headers.merge("User-Agent" => "Test 1"), :timeout => 30
sub_1.callback do
sub_1.response_header.status.should eql(200)
sub_1.response.size.should eql(1100 + conf.header_template.size + 4)
sub_2 = EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel.to_s).get :head => headers.merge("User-Agent" => "Test 2"), :timeout => 30
sub_2.callback do
sub_2.response_header.status.should eql(200)
sub_2.response.size.should eql(4097 + conf.header_template.size + 4)
sub_3 = EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel.to_s).get :head => headers.merge("User-Agent" => "Test 3"), :timeout => 30
sub_3.callback do
sub_3.response_header.status.should eql(200)
sub_3.response.size.should eql(conf.header_template.size + 2)
EventMachine.stop
end
end
end
end
end
end
it "should apply a padding to the message" do
channel = 'ch_test_message_padding'
body = "0123456789"
nginx_run_server(config, :timeout => 5) do |conf|
EventMachine.run do
sub_1 = EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel.to_s).get :head => headers.merge("User-Agent" => "Test 1"), :timeout => 30
sub_1.callback {
sub_1.response_header.status.should eql(200)
sub_1.response.size.should eql(500 + body.size + 4)
sub_2 = EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel.to_s).get :head => headers.merge("User-Agent" => "Test 2"), :timeout => 30
sub_2.callback {
sub_2.response_header.status.should eql(200)
sub_2.response.size.should eql(body.size + 2)
sub_3 = EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel.to_s).get :head => headers.merge("User-Agent" => "Test 3"), :timeout => 30
sub_3.callback {
sub_3.response_header.status.should eql(200)
sub_3.response.size.should eql(body.size + 2)
EventMachine.stop
}
publish_message_inline(channel, headers, body)
}
publish_message_inline(channel, headers, body)
}
publish_message_inline(channel, headers, body)
end
end
end
it "should apply a padding to the message with different sizes" do
channel = 'ch_test_message_padding_with_different_sizes'
nginx_run_server(config.merge(:padding_by_user_agent => "[T|t]est 1,0,545"), :timeout => 10) do |conf|
EventMachine.run do
i = 1
expected_padding = 545
sub_1 = EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel.to_s).get :head => headers.merge("User-Agent" => "Test 1"), :timeout => 30
sub_1.callback do
sub_1.response_header.status.should eql(200)
sub_1.response.size.should eql(expected_padding + i + 4)
i = 105
expected_padding = 600 - ((i/100).to_i * 100)
sub_1 = EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel.to_s).get :head => headers.merge("User-Agent" => "Test 1"), :timeout => 30
sub_1.callback do
sub_1.response_header.status.should eql(200)
sub_1.response.size.should eql(expected_padding + i + 4)
i = 221
expected_padding = 600 - ((i/100).to_i * 100)
sub_1 = EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel.to_s).get :head => headers.merge("User-Agent" => "Test 1"), :timeout => 30
sub_1.callback do
sub_1.response_header.status.should eql(200)
sub_1.response.size.should eql(expected_padding + i + 4)
i = 331
expected_padding = 600 - ((i/100).to_i * 100)
sub_1 = EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel.to_s).get :head => headers.merge("User-Agent" => "Test 1"), :timeout => 30
sub_1.callback do
sub_1.response_header.status.should eql(200)
sub_1.response.size.should eql(expected_padding + i + 4)
i = 435
expected_padding = 600 - ((i/100).to_i * 100)
sub_1 = EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel.to_s).get :head => headers.merge("User-Agent" => "Test 1"), :timeout => 30
sub_1.callback do
sub_1.response_header.status.should eql(200)
sub_1.response.size.should eql(expected_padding + i + 4)
i = 502
expected_padding = 600 - ((i/100).to_i * 100)
sub_1 = EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel.to_s).get :head => headers.merge("User-Agent" => "Test 1"), :timeout => 30
sub_1.callback do
sub_1.response_header.status.should eql(200)
sub_1.response.size.should eql(expected_padding + i + 4)
i = 550
sub_1 = EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel.to_s).get :head => headers.merge("User-Agent" => "Test 1"), :timeout => 30
sub_1.callback do
sub_1.response_header.status.should eql(200)
sub_1.response.size.should eql(i + 2)
EventMachine.stop
end
publish_message_inline(channel, headers, "_" * i)
end
publish_message_inline(channel, headers, "_" * i)
end
publish_message_inline(channel, headers, "_" * i)
end
publish_message_inline(channel, headers, "_" * i)
end
publish_message_inline(channel, headers, "_" * i)
end
publish_message_inline(channel, headers, "_" * i)
end
publish_message_inline(channel, headers, "_" * i)
end
end
end
it "should accept the user agent set by a complex value" do
channel = 'ch_test_user_agent_by_complex_value'
nginx_run_server(config.merge(:padding_by_user_agent => "[T|t]est 1,1024,512", :user_agent => "$arg_ua", :header_template => "0123456789"), :timeout => 10) do |conf|
EventMachine.run do
sub_1 = EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel.to_s + '?ua=test 1').get :head => headers, :timeout => 30
sub_1.callback do
sub_1.response_header.status.should eql(200)
sub_1.response.size.should eql(1024 + conf.header_template.size + 4)
sub_2 = EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel.to_s + '?ua=test 2').get :head => headers, :timeout => 30
sub_2.callback do
sub_2.response_header.status.should eql(200)
sub_2.response.size.should eql(conf.header_template.size + 2)
EventMachine.stop
end
end
end
end
end
end
require 'spec_helper'
describe "Subscriber Properties" do
shared_examples_for "polling location" do
describe "when has no messages" do
it "should receive a 304" do
channel = 'ch_test_receive_a_304_when_has_no_messages'
nginx_run_server(config, :timeout => 5) do |conf|
EventMachine.run do
sub_1 = EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel.to_s).get :head => headers
sub_1.callback do
sub_1.response_header.status.should eql(304)
sub_1.response_header['LAST_MODIFIED'].to_s.should eql("")
sub_1.response_header['ETAG'].to_s.should eql("")
sub_1.response_header.content_length.should eql(0)
EventMachine.stop
end
end
end
end
it "should receive a 304 keeping sent headers" do
channel = 'ch_test_receive_a_304_when_has_no_messages_keeping_headers'
sent_headers = headers.merge({'If-Modified-Since' => Time.now.utc.strftime("%a, %d %b %Y %T %Z"), 'If-None-Match' => '3'})
nginx_run_server(config, :timeout => 5) do |conf|
EventMachine.run do
sub_1 = EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel.to_s).get :head => sent_headers
sub_1.callback do
sub_1.response_header.status.should eql(304)
Time.parse(sub_1.response_header['LAST_MODIFIED'].to_s).should eql(Time.parse(sent_headers['If-Modified-Since']))
sub_1.response_header['ETAG'].to_s.should eql(sent_headers['If-None-Match'])
sub_1.response_header.content_length.should eql(0)
EventMachine.stop
end
end
end
end
end
describe "when has messages" do
it "should receive specific headers" do
channel = 'ch_test_receive_specific_headers_when_has_messages'
body = 'body'
nginx_run_server(config, :timeout => 5) do |conf|
EventMachine.run do
publish_message_inline(channel, {}, body)
sub_1 = EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel.to_s).get :head => headers
sub_1.callback do
sub_1.response_header.status.should eql(200)
sub_1.response_header['LAST_MODIFIED'].to_s.should_not eql("")
sub_1.response_header['ETAG'].to_s.should eql("0")
sub_1.response.should eql("#{body}\r\n")
EventMachine.stop
end
end
end
end
it "should receive old messages by if_modified_since header" do
channel = 'ch_test_getting_messages_by_if_modified_since_header'
body = 'body'
nginx_run_server(config, :timeout => 5) do |conf|
EventMachine.run do
publish_message_inline(channel, {}, body)
sub_1 = EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel.to_s).get :head => headers
sub_1.callback do
sub_1.response_header.status.should eql(200)
sub_1.response_header['LAST_MODIFIED'].to_s.should_not eql("")
sub_1.response_header['ETAG'].to_s.should_not eql("")
sub_1.response.should eql("#{body}\r\n")
sent_headers = headers.merge({'If-Modified-Since' => sub_1.response_header['LAST_MODIFIED'], 'If-None-Match' => sub_1.response_header['ETAG']})
sub_2 = EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel.to_s).get :head => sent_headers
sub_2.callback do
sub_2.response_header.status.should eql(304)
sub_2.response_header.content_length.should eql(0)
sub_2.response_header['LAST_MODIFIED'].to_s.should eql(sub_1.response_header['LAST_MODIFIED'])
sub_2.response_header['ETAG'].to_s.should eql(sub_1.response_header['ETAG'])
sleep(1) # to publish the second message in a different second from the first
publish_message_inline(channel, {}, body + "1")
sent_headers = headers.merge({'If-Modified-Since' => sub_2.response_header['LAST_MODIFIED'], 'If-None-Match' => sub_2.response_header['ETAG']})
sub_3 = EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel.to_s).get :head => sent_headers
sub_3.callback do
sub_3.response_header.status.should eql(200)
sub_3.response_header['LAST_MODIFIED'].to_s.should_not eql(sub_2.response_header['LAST_MODIFIED'])
sub_3.response_header['ETAG'].to_s.should eql("0")
sub_3.response.should eql("#{body}1\r\n")
EventMachine.stop
end
end
end
end
end
end
it "should receive old messages by backtrack" do
channel = 'ch_test_getting_messages_by_backtrack'
body = 'body'
nginx_run_server(config, :timeout => 5) do |conf|
EventMachine.run do
publish_message_inline(channel, {}, body)
publish_message_inline(channel, {}, body + "1")
publish_message_inline(channel, {}, body + "2")
sub_1 = EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel.to_s + '.b1').get :head => headers
sub_1.callback do
sub_1.response_header.status.should eql(200)
sub_1.response_header['LAST_MODIFIED'].to_s.should_not eql("")
sub_1.response_header['ETAG'].to_s.should eql("2")
sub_1.response.should eql("#{body}2\r\n")
sent_headers = headers.merge({'If-Modified-Since' => sub_1.response_header['LAST_MODIFIED'], 'If-None-Match' => sub_1.response_header['ETAG']})
sub_2 = EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel.to_s).get :head => sent_headers
sub_2.callback do
sub_2.response_header.status.should eql(304)
sub_2.response_header.content_length.should eql(0)
sub_2.response_header['LAST_MODIFIED'].to_s.should eql(sub_1.response_header['LAST_MODIFIED'])
sub_2.response_header['ETAG'].to_s.should eql(sub_1.response_header['ETAG'])
sleep(1) # to publish the second message in a different second from the first
publish_message_inline(channel, {}, body + "3")
sent_headers = headers.merge({'If-Modified-Since' => sub_2.response_header['LAST_MODIFIED'], 'If-None-Match' => sub_2.response_header['ETAG']})
sub_3 = EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel.to_s).get :head => sent_headers
sub_3.callback do
sub_3.response_header.status.should eql(200)
sub_3.response_header['LAST_MODIFIED'].to_s.should_not eql(sub_2.response_header['LAST_MODIFIED'])
sub_3.response_header['ETAG'].to_s.should eql("0")
sub_3.response.should eql("#{body}3\r\n")
EventMachine.stop
end
end
end
end
end
end
it "should receive old messages by last_event_id header" do
channel = 'ch_test_getting_messages_by_last_event_id_header'
body = 'body'
nginx_run_server(config, :timeout => 5) do |conf|
EventMachine.run do
publish_message_inline(channel, {'Event-Id' => 'event 1'}, 'msg 1')
publish_message_inline(channel, {'Event-Id' => 'event 2'}, 'msg 2')
publish_message_inline(channel, {}, 'msg 3')
publish_message_inline(channel, {'Event-Id' => 'event 3'}, 'msg 4')
sent_headers = headers.merge({'Last-Event-Id' => 'event 2'})
sub_1 = EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel.to_s).get :head => sent_headers
sub_1.callback do
sub_1.response_header.status.should eql(200)
sub_1.response_header['LAST_MODIFIED'].to_s.should_not eql("")
sub_1.response_header['ETAG'].to_s.should eql("3")
sub_1.response.should eql("msg 3\r\nmsg 4\r\n")
sent_headers = headers.merge({'If-Modified-Since' => sub_1.response_header['LAST_MODIFIED'], 'If-None-Match' => sub_1.response_header['ETAG']})
sub_2 = EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel.to_s).get :head => sent_headers
sub_2.callback do
sub_2.response_header.status.should eql(304)
sub_2.response_header.content_length.should eql(0)
sub_2.response_header['LAST_MODIFIED'].to_s.should eql(sub_1.response_header['LAST_MODIFIED'])
sub_2.response_header['ETAG'].to_s.should eql(sub_1.response_header['ETAG'])
sleep(1) # to publish the second message in a different second from the first
publish_message_inline(channel, {}, body + "3")
sent_headers = headers.merge({'If-Modified-Since' => sub_2.response_header['LAST_MODIFIED'], 'If-None-Match' => sub_2.response_header['ETAG']})
sub_3 = EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel.to_s).get :head => sent_headers
sub_3.callback do
sub_3.response_header.status.should eql(200)
sub_3.response_header['LAST_MODIFIED'].to_s.should_not eql(sub_2.response_header['LAST_MODIFIED'])
sub_3.response_header['ETAG'].to_s.should eql("0")
sub_3.response.should eql("#{body}3\r\n")
EventMachine.stop
end
end
end
end
end
end
it "should receive old messages from different channels" do
channel_1 = 'ch_test_receive_old_messages_from_different_channels_1'
channel_2 = 'ch_test_receive_old_messages_from_different_channels_2'
body = 'body'
nginx_run_server(config, :timeout => 5) do |conf|
EventMachine.run do
publish_message_inline(channel_1, {}, body + "_1")
publish_message_inline(channel_2, {}, body + "_2")
sub_1 = EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel_2.to_s + '/' + channel_1.to_s).get :head => headers
sub_1.callback do
sub_1.response_header.status.should eql(200)
sub_1.response_header['LAST_MODIFIED'].to_s.should_not eql("")
sub_1.response_header['ETAG'].to_s.should_not eql("")
sub_1.response.should eql("#{body}_2\r\n#{body}_1\r\n")
sent_headers = headers.merge({'If-Modified-Since' => sub_1.response_header['LAST_MODIFIED'], 'If-None-Match' => sub_1.response_header['ETAG']})
sub_2 = EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel_2.to_s + '/' + channel_1.to_s).get :head => sent_headers
sub_2.callback do
sub_2.response_header.status.should eql(304)
sub_2.response_header.content_length.should eql(0)
sub_2.response_header['LAST_MODIFIED'].to_s.should eql(sub_1.response_header['LAST_MODIFIED'])
sub_2.response_header['ETAG'].to_s.should eql(sub_1.response_header['ETAG'])
sleep(1) # to publish the second message in a different second from the first
publish_message_inline(channel_1, {}, body + "1_1")
sent_headers = headers.merge({'If-Modified-Since' => sub_2.response_header['LAST_MODIFIED'], 'If-None-Match' => sub_2.response_header['ETAG']})
sub_3 = EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel_2.to_s + '/' + channel_1.to_s).get :head => sent_headers
sub_3.callback do
sub_3.response_header.status.should eql(200)
sub_3.response_header['LAST_MODIFIED'].to_s.should_not eql(sub_2.response_header['LAST_MODIFIED'])
sub_3.response_header['ETAG'].to_s.should eql("0")
sub_3.response.should eql("#{body}1_1\r\n")
sent_headers = headers.merge({'If-Modified-Since' => sub_3.response_header['LAST_MODIFIED'], 'If-None-Match' => sub_3.response_header['ETAG']})
sub_4 = EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel_2.to_s + '/' + channel_1.to_s).get :head => sent_headers
sub_4.callback do
sub_4.response_header.status.should eql(304)
sub_4.response_header.content_length.should eql(0)
sub_4.response_header['LAST_MODIFIED'].to_s.should eql(sub_3.response_header['LAST_MODIFIED'])
sub_4.response_header['ETAG'].to_s.should eql(sub_3.response_header['ETAG'])
sleep(1) # to publish the second message in a different second from the first
publish_message_inline(channel_2, {}, body + "1_2")
sent_headers = headers.merge({'If-Modified-Since' => sub_4.response_header['LAST_MODIFIED'], 'If-None-Match' => sub_4.response_header['ETAG']})
sub_5 = EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel_2.to_s + '/' + channel_1.to_s).get :head => sent_headers
sub_5.callback do
sub_5.response_header.status.should eql(200)
sub_5.response_header['LAST_MODIFIED'].to_s.should_not eql(sub_4.response_header['LAST_MODIFIED'])
sub_5.response_header['ETAG'].to_s.should eql("0")
sub_5.response.should eql("#{body}1_2\r\n")
EventMachine.stop
end
end
end
end
end
end
end
end
it "should accept modified since and none match values not using headers when polling" do
channel = 'ch_test_send_modified_since_and_none_match_values_not_using_headers_when_polling'
body = 'body'
nginx_run_server(config.merge(:last_received_message_time => "$arg_time", :last_received_message_tag => "$arg_tag"), :timeout => 5) do |conf|
EventMachine.run do
publish_message_inline(channel, {}, body)
sub_1 = EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel.to_s).get :head => headers
sub_1.callback do
sub_1.response.should eql("#{body}\r\n")
time = sub_1.response_header['LAST_MODIFIED']
tag = sub_1.response_header['ETAG']
publish_message_inline(channel, {}, body + " 1")
response = ""
sub_2 = EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel.to_s + '?time=' + time + '&tag=' + tag).get :head => headers
sub_2.callback do
sub_2.response.should eql("#{body} 1\r\n")
EventMachine.stop
end
end
end
end
end
it "should accept a callback parameter to works with JSONP" do
channel = 'ch_test_return_message_using_function_name_specified_in_callback_parameter_when_polling'
body = 'body'
response = ""
callback_function_name = "callback_function"
nginx_run_server(config, :timeout => 5) do |conf|
EventMachine.run do
publish_message_inline(channel, {}, body)
sub_1 = EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel.to_s + '?callback=' + callback_function_name).get :head => headers
sub_1.callback do
sub_1.response.should eql("#{callback_function_name}\r\n([#{body}\r\n,]);\r\n")
EventMachine.stop
end
end
end
end
it "should return old messages using function name specified in callback parameter grouping in one answer" do
channel = 'ch_test_return_old_messages_using_function_name_specified_in_callback_parameter_grouping_in_one_answer'
body = 'body'
response = ""
callback_function_name = "callback_function"
nginx_run_server(config, :timeout => 5) do |conf|
EventMachine.run do
publish_message_inline(channel, {}, body)
publish_message_inline(channel, {}, body + "1")
sub_1 = EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel.to_s + '.b2' + '?callback=' + callback_function_name).get :head => headers
sub_1.callback do
sub_1.response.should eql("#{callback_function_name}\r\n([#{body}\r\n,#{body + "1"}\r\n,]);\r\n")
EventMachine.stop
end
end
end
end
it "should force content_type to be application/javascript when using function name specified in callback parameter" do
channel = 'test_force_content_type_to_be_application_javascript_when_using_function_name_specified_in_callback_parameter_when_polling'
body = 'body'
response = ""
callback_function_name = "callback_function"
nginx_run_server(config.merge({:content_type => "anything/value"}), :timeout => 5) do |conf|
EventMachine.run do
publish_message_inline(channel, {}, body)
sent_headers = headers.merge({'accept' => 'otherknown/value'})
sub_1 = EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel.to_s + '?callback=' + callback_function_name).get :head => sent_headers
sub_1.callback do
sub_1.response_header['CONTENT_TYPE'].should eql('application/javascript')
EventMachine.stop
end
end
end
end
end
end
context "when using subscriber push mode config" do
let(:config) do
{
:ping_message_interval => nil,
:header_template => nil,
:footer_template => nil,
:message_template => nil,
:subscriber_mode => 'polling'
}
end
let(:headers) do
{'accept' => 'text/html'}
end
it_should_behave_like "polling location"
end
context "when using push mode header" do
let(:config) do
{
:ping_message_interval => nil,
:header_template => nil,
:footer_template => nil,
:message_template => nil,
:subscriber_mode => nil
}
end
let(:headers) do
{'accept' => 'text/html', 'X-Nginx-PushStream-Mode' => 'polling'}
end
it_should_behave_like "polling location"
end
end
require 'spec_helper'
describe "Subscriber Properties" do
let(:config) do
{
:authorized_channels_only => "off",
:header_template => "HEADER\r\nTEMPLATE\r\n1234\r\n",
:content_type => "custom content type",
:subscriber_connection_ttl => "1s",
:ping_message_interval => "2s"
}
end
it "should not accept access without a channel path" do
nginx_run_server(config, :timeout => 5) do |conf|
EventMachine.run do
sub = EventMachine::HttpRequest.new(nginx_address + '/sub/').get :head => headers, :timeout => 30
sub.callback do
sub.response_header.content_length.should eql(0)
sub.response_header.status.should eql(400)
sub.response_header['X_NGINX_PUSHSTREAM_EXPLAIN'].should eql("No channel id provided.")
EventMachine.stop
end
end
end
end
it "should check accepted methods" do
nginx_run_server(config, :timeout => 5) do |conf|
# testing OPTIONS method, EventMachine::HttpRequest does not have support to it
socket = open_socket(nginx_host, nginx_port)
socket.print("OPTIONS /sub/ch_test_accepted_methods_0 HTTP/1.0\r\n\r\n")
headers, body = read_response_on_socket(socket)
headers.should match_the_pattern(/HTTP\/1\.1 200 OK/)
headers.should match_the_pattern(/Content-Length: 0/)
EventMachine.run do
multi = EventMachine::MultiRequest.new
multi.add(:a, EventMachine::HttpRequest.new(nginx_address + '/sub/ch_test_accepted_methods_1').head)
multi.add(:b, EventMachine::HttpRequest.new(nginx_address + '/sub/ch_test_accepted_methods_2').put(:body => 'body'))
multi.add(:c, EventMachine::HttpRequest.new(nginx_address + '/sub/ch_test_accepted_methods_3').post)
multi.add(:d, EventMachine::HttpRequest.new(nginx_address + '/sub/ch_test_accepted_methods_4').delete)
multi.add(:e, EventMachine::HttpRequest.new(nginx_address + '/sub/ch_test_accepted_methods_5').get)
multi.callback do
multi.responses[:callback].length.should eql(5)
multi.responses[:callback][:a].response_header.status.should eql(405)
multi.responses[:callback][:a].req.method.should eql("HEAD")
multi.responses[:callback][:a].response_header['ALLOW'].should eql("GET")
multi.responses[:callback][:b].response_header.status.should eql(405)
multi.responses[:callback][:b].req.method.should eql("PUT")
multi.responses[:callback][:b].response_header['ALLOW'].should eql("GET")
multi.responses[:callback][:c].response_header.status.should eql(405)
multi.responses[:callback][:c].req.method.should eql("POST")
multi.responses[:callback][:c].response_header['ALLOW'].should eql("GET")
multi.responses[:callback][:d].response_header.status.should eql(405)
multi.responses[:callback][:d].req.method.should eql("DELETE")
multi.responses[:callback][:d].response_header['ALLOW'].should eql("GET")
multi.responses[:callback][:e].response_header.status.should_not eql(405)
multi.responses[:callback][:e].req.method.should eql("GET")
EventMachine.stop
end
end
end
end
it "should not accept access to a channel with id 'ALL'" do
channel = 'ALL'
nginx_run_server(config, :timeout => 5) do |conf|
EventMachine.run do
sub_1 = EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel.to_s).get :head => headers, :timeout => 30
sub_1.callback do
sub_1.response_header.status.should eql(403)
sub_1.response_header.content_length.should eql(0)
sub_1.response_header['X_NGINX_PUSHSTREAM_EXPLAIN'].should eql("Channel id not authorized for this method.")
EventMachine.stop
end
end
end
end
it "should not accept access to a channel with id containing wildcard" do
channel_1 = 'abcd*efgh'
channel_2 = '*abcdefgh'
channel_3 = 'abcdefgh*'
nginx_run_server(config, :timeout => 5) do |conf|
EventMachine.run do
multi = EventMachine::MultiRequest.new
multi.add(:a, EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel_1).get(:head => headers, :timeout => 30))
multi.add(:b, EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel_2).get(:head => headers, :timeout => 30))
multi.add(:c, EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel_3).get(:head => headers, :timeout => 30))
multi.callback do
multi.responses[:callback].length.should eql(3)
multi.responses[:callback].each do |name, response|
response.response_header.status.should eql(403)
response.response_header.content_length.should eql(0)
response.response_header['X_NGINX_PUSHSTREAM_EXPLAIN'].should eql("Channel id not authorized for this method.")
end
EventMachine.stop
end
end
end
end
it "should accept access to multiple channels" do
nginx_run_server(config, :timeout => 5) do |conf|
EventMachine.run do
multi = EventMachine::MultiRequest.new
multi.add(:a, EventMachine::HttpRequest.new(nginx_address + '/sub/ch_multi_channels_1').get)
multi.add(:b, EventMachine::HttpRequest.new(nginx_address + '/sub/ch_multi_channels_1.b10').get)
multi.add(:c, EventMachine::HttpRequest.new(nginx_address + '/sub/ch_multi_channels_2/ch_multi_channels_3').get)
multi.add(:d, EventMachine::HttpRequest.new(nginx_address + '/sub/ch_multi_channels_2.b2/ch_multi_channels_3').get)
multi.add(:e, EventMachine::HttpRequest.new(nginx_address + '/sub/ch_multi_channels_2/ch_multi_channels_3.b3').get)
multi.add(:f, EventMachine::HttpRequest.new(nginx_address + '/sub/ch_multi_channels_2.b2/ch_multi_channels_3.b3').get)
multi.add(:g, EventMachine::HttpRequest.new(nginx_address + '/sub/ch_multi_channels_4.b').get)
multi.callback do
multi.responses[:callback].length.should eql(7)
multi.responses[:callback].each do |name, response|
response.response_header.status.should eql(200)
end
EventMachine.stop
end
end
end
end
it "should not accept access with a big channel id" do
channel = '123456'
nginx_run_server(config.merge(:max_channel_id_length => 5), :timeout => 5) do |conf|
EventMachine.run do
sub = EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel.to_s ).get :head => headers, :timeout => 30
sub.callback do
sub.response_header.content_length.should eql(0)
sub.response_header.status.should eql(400)
sub.response_header['X_NGINX_PUSHSTREAM_EXPLAIN'].should eql("Channel id is too large.")
EventMachine.stop
end
end
end
end
it "should not accept access to a broadcast channel without a normal channel" do
nginx_run_server(config.merge(:broadcast_channel_prefix => "bd_"), :timeout => 5) do |conf|
EventMachine.run do
multi = EventMachine::MultiRequest.new
multi.add(:a, EventMachine::HttpRequest.new(nginx_address + '/sub/bd_test_broadcast_channels_without_common_channel').get)
multi.add(:b, EventMachine::HttpRequest.new(nginx_address + '/sub/bd_').get)
multi.add(:c, EventMachine::HttpRequest.new(nginx_address + '/sub/bd1').get)
multi.add(:d, EventMachine::HttpRequest.new(nginx_address + '/sub/bd').get)
multi.callback do
multi.responses[:callback].length.should eql(4)
multi.responses[:callback][:a].response_header.content_length.should eql(0)
multi.responses[:callback][:a].response_header.status.should eql(403)
multi.responses[:callback][:a].response_header['X_NGINX_PUSHSTREAM_EXPLAIN'].should eql("Subscribed too much broadcast channels.")
multi.responses[:callback][:a].req.uri.to_s.should eql(nginx_address + '/sub/bd_test_broadcast_channels_without_common_channel')
multi.responses[:callback][:b].response_header.content_length.should eql(0)
multi.responses[:callback][:b].response_header.status.should eql(403)
multi.responses[:callback][:b].response_header['X_NGINX_PUSHSTREAM_EXPLAIN'].should eql("Subscribed too much broadcast channels.")
multi.responses[:callback][:b].req.uri.to_s.should eql(nginx_address + '/sub/bd_')
multi.responses[:callback][:c].response_header.status.should eql(200)
multi.responses[:callback][:c].req.uri.to_s.should eql(nginx_address + '/sub/bd1')
multi.responses[:callback][:d].response_header.status.should eql(200)
multi.responses[:callback][:d].req.uri.to_s.should eql(nginx_address + '/sub/bd')
EventMachine.stop
end
end
end
end
it "should accept access to a broadcast channel with a normal channel" do
nginx_run_server(config.merge(:broadcast_channel_prefix => "bd_", :broadcast_channel_max_qtd => 2, :authorized_channels_only => "off"), :timeout => 5) do |conf|
EventMachine.run do
multi = EventMachine::MultiRequest.new
multi.add(:a, EventMachine::HttpRequest.new(nginx_address + '/sub/bd1/bd2/bd3/bd4/bd_1/bd_2/bd_3').get)
multi.add(:b, EventMachine::HttpRequest.new(nginx_address + '/sub/bd1/bd2/bd_1/bd_2').get)
multi.add(:c, EventMachine::HttpRequest.new(nginx_address + '/sub/bd1/bd_1').get)
multi.add(:d, EventMachine::HttpRequest.new(nginx_address + '/sub/bd1/bd2').get)
multi.callback do
multi.responses[:callback].length.should eql(4)
multi.responses[:callback][:a].response_header.content_length.should eql(0)
multi.responses[:callback][:a].response_header.status.should eql(403)
multi.responses[:callback][:a].response_header['X_NGINX_PUSHSTREAM_EXPLAIN'].should eql("Subscribed too much broadcast channels.")
multi.responses[:callback][:a].req.uri.to_s.should eql(nginx_address + '/sub/bd1/bd2/bd3/bd4/bd_1/bd_2/bd_3')
multi.responses[:callback][:b].response_header.status.should eql(200)
multi.responses[:callback][:b].req.uri.to_s.should eql(nginx_address + '/sub/bd1/bd2/bd_1/bd_2')
multi.responses[:callback][:c].response_header.status.should eql(200)
multi.responses[:callback][:c].req.uri.to_s.should eql(nginx_address + '/sub/bd1/bd_1')
multi.responses[:callback][:d].response_header.status.should eql(200)
multi.responses[:callback][:d].req.uri.to_s.should eql(nginx_address + '/sub/bd1/bd2')
EventMachine.stop
end
end
end
end
it "should not accept access to an nonexistent channel with authorized only 'on'" do
channel = 'ch_test_subscribe_an_absent_channel_with_authorized_only_on'
nginx_run_server(config.merge(:authorized_channels_only => 'on'), :timeout => 5) do |conf|
EventMachine.run do
sub_1 = EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel.to_s).get :head => headers, :timeout => 30
sub_1.callback do
sub_1.response_header.status.should eql(403)
sub_1.response_header.content_length.should eql(0)
sub_1.response_header['X_NGINX_PUSHSTREAM_EXPLAIN'].should eql("Subscriber could not create channels.")
EventMachine.stop
end
end
end
end
it "should accept access to an existent channel with authorized channel only 'on'" do
channel = 'ch_test_subscribe_an_existing_channel_with_authorized_only_on'
body = 'body'
nginx_run_server(config.merge(:authorized_channels_only => 'on'), :timeout => 5) do |conf|
#create channel
publish_message(channel, headers, body)
EventMachine.run do
sub_1 = EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel.to_s).get :head => headers, :timeout => 30
sub_1.callback do
sub_1.response_header.status.should eql(200)
EventMachine.stop
end
end
end
end
it "should accept access to an existing channel and a nonexistent broadcast channel with authorized only 'on'" do
channel = 'ch_test_subscribe_an_existing_channel_and_absent_broadcast_channel_with_authorized_only_on'
broadcast_channel = 'bd_test_subscribe_an_existing_channel_and_absent_broadcast_channel_with_authorized_only_on'
body = 'body'
nginx_run_server(config.merge(:authorized_channels_only => 'on', :broadcast_channel_prefix => "bd_", :broadcast_channel_max_qtd => 1), :timeout => 5) do |conf|
#create channel
publish_message(channel, headers, body)
EventMachine.run do
sub_1 = EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel.to_s + '/' + broadcast_channel.to_s).get :head => headers, :timeout => 30
sub_1.callback do
sub_1.response_header.status.should eql(200)
EventMachine.stop
end
end
end
end
it "should not accept access to an existing channel without messages with authorized only 'on'" do
channel = 'ch_test_subscribe_an_existing_channel_without_messages_and_with_authorized_only_on'
body = 'body'
nginx_run_server(config.merge(:authorized_channels_only => 'on', :message_ttl => "1s"), :timeout => 10) do |conf|
#create channel
publish_message(channel, headers, body)
sleep(5) #to ensure message was gone
EventMachine.run do
sub_1 = EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel.to_s).get :head => headers, :timeout => 30
sub_1.callback do
sub_1.response_header.status.should eql(403)
sub_1.response_header.content_length.should eql(0)
sub_1.response_header['X_NGINX_PUSHSTREAM_EXPLAIN'].should eql("Subscriber could not create channels.")
EventMachine.stop
end
end
end
end
it "should not accept access to an existing channel without messages and an nonexistent broadcast channel with authorized only 'on'" do
channel = 'ch_test_subscribe_an_existing_channel_without_messages_and_absent_broadcast_channel_and_with_authorized_only_on_should_fail'
broadcast_channel = 'bd_test_subscribe_an_existing_channel_without_messages_and_absent_broadcast_channel_and_with_authorized_only_on_should_fail'
body = 'body'
nginx_run_server(config.merge(:authorized_channels_only => 'on', :message_ttl => "1s", :broadcast_channel_prefix => "bd_", :broadcast_channel_max_qtd => 1), :timeout => 10) do |conf|
#create channel
publish_message(channel, headers, body)
sleep(5) #to ensure message was gone
EventMachine.run do
sub_1 = EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel.to_s + '/' + broadcast_channel.to_s).get :head => headers, :timeout => 30
sub_1.callback do
sub_1.response_header.status.should eql(403)
sub_1.response_header.content_length.should eql(0)
sub_1.response_header['X_NGINX_PUSHSTREAM_EXPLAIN'].should eql("Subscriber could not create channels.")
EventMachine.stop
end
end
end
end
it "should receive old messages in multi channel subscriber" do
channel_1 = 'ch_test_retreive_old_messages_in_multichannel_subscribe_1'
channel_2 = 'ch_test_retreive_old_messages_in_multichannel_subscribe_2'
channel_3 = 'ch_test_retreive_old_messages_in_multichannel_subscribe_3'
body = 'body'
response = ""
nginx_run_server(config.merge(:header_template => 'HEADER', :message_template => '{\"channel\":\"~channel~\", \"id\":\"~id~\", \"message\":\"~text~\"}'), :timeout => 5) do |conf|
#create channels with some messages
1.upto(3) do |i|
publish_message(channel_1, headers, body + i.to_s)
publish_message(channel_2, headers, body + i.to_s)
publish_message(channel_3, headers, body + i.to_s)
end
EventMachine.run do
sub_1 = EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel_1.to_s + '/' + channel_2.to_s + '.b5' + '/' + channel_3.to_s + '.b2').get :head => headers, :timeout => 30
sub_1.stream do |chunk|
response += chunk
lines = response.split("\r\n")
if lines.length >= 6
lines[0].should eql('HEADER')
line = JSON.parse(lines[1])
line['channel'].should eql(channel_2.to_s)
line['message'].should eql('body1')
line['id'].to_i.should eql(1)
line = JSON.parse(lines[2])
line['channel'].should eql(channel_2.to_s)
line['message'].should eql('body2')
line['id'].to_i.should eql(2)
line = JSON.parse(lines[3])
line['channel'].should eql(channel_2.to_s)
line['message'].should eql('body3')
line['id'].to_i.should eql(3)
line = JSON.parse(lines[4])
line['channel'].should eql(channel_3.to_s)
line['message'].should eql('body2')
line['id'].to_i.should eql(2)
line = JSON.parse(lines[5])
line['channel'].should eql(channel_3.to_s)
line['message'].should eql('body3')
line['id'].to_i.should eql(3)
EventMachine.stop
end
end
end
end
end
it "should receive new messages in a multi channel subscriber" do
channel_1 = 'test_retreive_new_messages_in_multichannel_subscribe_1'
channel_2 = 'test_retreive_new_messages_in_multich_subscribe_2'
channel_3 = 'test_retreive_new_messages_in_multchannel_subscribe_3'
channel_4 = 'test_retreive_new_msgs_in_multichannel_subscribe_4'
channel_5 = 'test_retreive_new_messages_in_multichannel_subs_5'
channel_6 = 'test_retreive_new_msgs_in_multichannel_subs_6'
body = 'body'
response = ""
nginx_run_server(config.merge(:header_template => nil, :message_template => '{\"channel\":\"~channel~\", \"id\":\"~id~\", \"message\":\"~text~\"}'), :timeout => 5) do |conf|
EventMachine.run do
sub_1 = EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel_1.to_s + '/' + channel_2.to_s + '/' + channel_3.to_s + '/' + channel_4.to_s + '/' + channel_5.to_s + '/' + channel_6.to_s).get :head => headers, :timeout => 30
sub_1.stream do |chunk|
response += chunk
lines = response.split("\r\n")
if lines.length >= 6
line = JSON.parse(lines[0])
line['channel'].should eql(channel_1.to_s)
line['message'].should eql('body' + channel_1.to_s)
line['id'].to_i.should eql(1)
line = JSON.parse(lines[1])
line['channel'].should eql(channel_2.to_s)
line['message'].should eql('body' + channel_2.to_s)
line['id'].to_i.should eql(1)
line = JSON.parse(lines[2])
line['channel'].should eql(channel_3.to_s)
line['message'].should eql('body' + channel_3.to_s)
line['id'].to_i.should eql(1)
line = JSON.parse(lines[3])
line['channel'].should eql(channel_4.to_s)
line['message'].should eql('body' + channel_4.to_s)
line['id'].to_i.should eql(1)
line = JSON.parse(lines[4])
line['channel'].should eql(channel_5.to_s)
line['message'].should eql('body' + channel_5.to_s)
line['id'].to_i.should eql(1)
line = JSON.parse(lines[5])
line['channel'].should eql(channel_6.to_s)
line['message'].should eql('body' + channel_6.to_s)
line['id'].to_i.should eql(1)
EventMachine.stop
end
end
publish_message_inline(channel_1, headers, body + channel_1.to_s)
publish_message_inline(channel_2, headers, body + channel_2.to_s)
publish_message_inline(channel_3, headers, body + channel_3.to_s)
publish_message_inline(channel_4, headers, body + channel_4.to_s)
publish_message_inline(channel_5, headers, body + channel_5.to_s)
publish_message_inline(channel_6, headers, body + channel_6.to_s)
end
end
end
it "should receive old messages in a multi channel subscriber using 'if_modified_since' header" do
channel_1 = 'ch_test_retreive_old_messages_in_multichannel_subscribe_using_if_modified_since_header_1'
channel_2 = 'ch_test_retreive_old_messages_in_multichannel_subscribe_using_if_modified_since_header_2'
channel_3 = 'ch_test_retreive_old_messages_in_multichannel_subscribe_using_if_modified_since_header_3'
body = 'body'
nginx_run_server(config.merge(:header_template => 'HEADER', :message_template => '{\"channel\":\"~channel~\", \"id\":\"~id~\", \"message\":\"~text~\"}'), :timeout => 40) do |conf|
#create channels with some messages with progressive interval (2,4,6,10,14,18,24,30,36 seconds)
1.upto(3) do |i|
sleep(i * 2)
publish_message(channel_1, headers, body + i.to_s)
sleep(i * 2)
publish_message(channel_2, headers, body + i.to_s)
sleep(i * 2)
publish_message(channel_3, headers, body + i.to_s)
end
#get messages published less then 20 seconds ago
t = Time.now
t = t - 20
sent_headers = headers.merge({'If-Modified-Since' => t.utc.strftime("%a, %d %b %Y %T %Z")})
response = ""
EventMachine.run do
sub_1 = EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel_1.to_s + '/' + channel_2.to_s + '/' + channel_3.to_s).get :head => sent_headers, :timeout => 30
sub_1.stream do |chunk|
response += chunk
lines = response.split("\r\n")
if lines.length >= 5
lines[0].should eql('HEADER')
line = JSON.parse(lines[1])
line['channel'].should eql(channel_1.to_s)
line['message'].should eql('body3')
line['id'].to_i.should eql(3)
line = JSON.parse(lines[2])
line['channel'].should eql(channel_2.to_s)
line['message'].should eql('body3')
line['id'].to_i.should eql(3)
line = JSON.parse(lines[3])
line['channel'].should eql(channel_3.to_s)
line['message'].should eql('body2')
line['id'].to_i.should eql(2)
line = JSON.parse(lines[4])
line['channel'].should eql(channel_3.to_s)
line['message'].should eql('body3')
line['id'].to_i.should eql(3)
EventMachine.stop
end
end
end
end
end
it "should receive old messages in a multi channel subscriber using 'if_modified_since' header and backtrack mixed" do
channel_1 = 'ch_test_retreive_old_messages_in_multichannel_subscribe_using_if_modified_since_header_and_backtrack_mixed_1'
channel_2 = 'ch_test_retreive_old_messages_in_multichannel_subscribe_using_if_modified_since_header_and_backtrack_mixed_2'
channel_3 = 'ch_test_retreive_old_messages_in_multichannel_subscribe_using_if_modified_since_header_and_backtrack_mixed_3'
body = 'body'
nginx_run_server(config.merge(:header_template => 'HEADER', :message_template => '{\"channel\":\"~channel~\", \"id\":\"~id~\", \"message\":\"~text~\"}'), :timeout => 40) do |conf|
#create channels with some messages with progressive interval (2,4,6,10,14,18,24,30,36 seconds)
1.upto(3) do |i|
sleep(i * 2)
publish_message(channel_1, headers, body + i.to_s)
sleep(i * 2)
publish_message(channel_2, headers, body + i.to_s)
sleep(i * 2)
publish_message(channel_3, headers, body + i.to_s)
end
#get messages published less then 20 seconds ago
t = Time.now
t = t - 20
sent_headers = headers.merge({'If-Modified-Since' => t.utc.strftime("%a, %d %b %Y %T %Z")})
response = ""
EventMachine.run do
sub_1 = EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel_1.to_s + '/' + channel_2.to_s + '.b5' + '/' + channel_3.to_s).get :head => sent_headers, :timeout => 30
sub_1.stream do |chunk|
response += chunk
lines = response.split("\r\n")
if lines.length >= 7
lines[0].should eql('HEADER')
line = JSON.parse(lines[1])
line['channel'].should eql(channel_1.to_s)
line['message'].should eql('body3')
line['id'].to_i.should eql(3)
line = JSON.parse(lines[2])
line['channel'].should eql(channel_2.to_s)
line['message'].should eql('body1')
line['id'].to_i.should eql(1)
line = JSON.parse(lines[3])
line['channel'].should eql(channel_2.to_s)
line['message'].should eql('body2')
line['id'].to_i.should eql(2)
line = JSON.parse(lines[4])
line['channel'].should eql(channel_2.to_s)
line['message'].should eql('body3')
line['id'].to_i.should eql(3)
line = JSON.parse(lines[5])
line['channel'].should eql(channel_3.to_s)
line['message'].should eql('body2')
line['id'].to_i.should eql(2)
line = JSON.parse(lines[6])
line['channel'].should eql(channel_3.to_s)
line['message'].should eql('body3')
line['id'].to_i.should eql(3)
EventMachine.stop
end
end
end
end
end
it "should limit the number of channels" do
channel = 'ch_test_max_number_of_channels_'
nginx_run_server(config.merge(:max_number_of_channels => 1), :timeout => 5) do |conf|
EventMachine.run do
sub_1 = EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel.to_s + 1.to_s).get :head => headers, :timeout => 30
sub_1.stream do
sub_1.response_header.status.should eql(200)
sub_1.response_header.content_length.should_not eql(0)
sub_2 = EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel.to_s + 2.to_s).get :head => headers, :timeout => 30
sub_2.callback do
sub_2.response_header.status.should eql(403)
sub_2.response_header.content_length.should eql(0)
sub_2.response_header['X_NGINX_PUSHSTREAM_EXPLAIN'].should eql("Number of channels were exceeded.")
EventMachine.stop
end
end
end
end
end
it "should limit the number of broadcast channels" do
channel = 'bd_test_max_number_of_broadcast_channels_'
nginx_run_server(config.merge(:max_number_of_broadcast_channels => 1, :broadcast_channel_prefix => 'bd_', :broadcast_channel_max_qtd => 1), :timeout => 5) do |conf|
EventMachine.run do
sub_1 = EventMachine::HttpRequest.new(nginx_address + '/sub/ch1/' + channel.to_s + 1.to_s).get :head => headers, :timeout => 30
sub_1.stream do
sub_1.response_header.status.should eql(200)
sub_1.response_header.content_length.should_not eql(0)
sub_2 = EventMachine::HttpRequest.new(nginx_address + '/sub/ch1/' + channel.to_s + 2.to_s).get :head => headers, :timeout => 30
sub_2.callback do
sub_2.response_header.status.should eql(403)
sub_2.response_header.content_length.should eql(0)
sub_2.response_header['X_NGINX_PUSHSTREAM_EXPLAIN'].should eql("Number of channels were exceeded.")
EventMachine.stop
end
end
end
end
end
it "should accept different message templates in each location" do
configuration = config.merge({
:message_template => '{\"text\":\"~text~\"}',
:header_template => nil,
:extra_location => %q{
location ~ /sub2/(.*)? {
# activate subscriber mode for this location
push_stream_subscriber;
# positional channel path
set $push_stream_channels_path $1;
# message template
push_stream_message_template "{\"msg\":\"~text~\"}";
}
}
})
channel = 'ch_test_different_message_templates'
body = 'body'
nginx_run_server(configuration, :timeout => 5) do |conf|
EventMachine.run do
sub_1 = EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel.to_s).get :head => headers, :timeout => 30
sub_1.stream do |chunk|
response = JSON.parse(chunk)
response['msg'].should be_nil
response['text'].should eql(body)
EventMachine.stop
end
sub_2 = EventMachine::HttpRequest.new(nginx_address + '/sub2/' + channel.to_s + '.b1').get :head => headers, :timeout => 30
sub_2.stream do |chunk|
response = JSON.parse(chunk)
response['text'].should be_nil
response['msg'].should eql(body)
EventMachine.stop
end
#publish a message
publish_message_inline(channel, headers, body)
end
EventMachine.run do
sub_3 = EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel.to_s + '.b1').get :head => headers, :timeout => 30
sub_3.stream do |chunk|
response = JSON.parse(chunk)
response['msg'].should be_nil
response['text'].should eql(body)
EventMachine.stop
end
end
EventMachine.run do
sub_4 = EventMachine::HttpRequest.new(nginx_address + '/sub2/' + channel.to_s + '.b1').get :head => headers, :timeout => 30
sub_4.stream do |chunk|
response = JSON.parse(chunk)
response['text'].should be_nil
response['msg'].should eql(body)
EventMachine.stop
end
end
end
end
it "should use default message template" do
channel = 'ch_test_default_message_template'
body = 'body'
nginx_run_server(config.merge(:message_template => nil, :header_template => nil), :timeout => 5) do |conf|
EventMachine.run do
sub_1 = EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel.to_s).get :head => headers, :timeout => 30
sub_1.stream do |chunk|
chunk.should eql("#{body}\r\n")
EventMachine.stop
end
#publish a message
publish_message_inline(channel, headers, body)
end
end
end
it "should receive default ping message with default message template" do
channel = 'ch_test_default_ping_message_with_default_message_template'
body = 'body'
nginx_run_server(config.merge(:subscriber_connection_ttl => nil, :message_template => nil, :header_template => nil, :ping_message_interval => '1s', :ping_message_text => nil), :timeout => 5) do |conf|
EventMachine.run do
sub_1 = EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel.to_s).get :head => headers, :timeout => 30
sub_1.stream do |chunk|
chunk.should eql("\r\n")
EventMachine.stop
end
end
end
end
it "should receive custom ping message with default message template" do
channel = 'ch_test_custom_ping_message_with_default_message_template'
body = 'body'
nginx_run_server(config.merge(:subscriber_connection_ttl => nil, :message_template => nil, :header_template => nil, :ping_message_interval => '1s', :ping_message_text => "pinging you!!!"), :timeout => 5) do |conf|
EventMachine.run do
sub_1 = EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel.to_s).get :head => headers, :timeout => 30
sub_1.stream do |chunk|
chunk.should eql("#{conf.ping_message_text}\r\n")
EventMachine.stop
end
end
end
end
it "should receive default ping message with custom message template" do
channel = 'ch_test_default_ping_message_with_custom_message_template'
body = 'body'
nginx_run_server(config.merge(:subscriber_connection_ttl => nil, :message_template => "~id~:~text~", :header_template => nil, :ping_message_interval => '1s', :ping_message_text => nil), :timeout => 5) do |conf|
EventMachine.run do
sub_1 = EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel.to_s).get :head => headers, :timeout => 30
sub_1.stream do |chunk|
chunk.should eql("-1:\r\n")
EventMachine.stop
end
end
end
end
it "should receive custom ping message with custom message template" do
channel = 'ch_test_custom_ping_message_with_default_message_template'
body = 'body'
nginx_run_server(config.merge(:subscriber_connection_ttl => nil, :message_template => "~id~:~text~", :header_template => nil, :ping_message_interval => '1s', :ping_message_text => "pinging you!!!"), :timeout => 5) do |conf|
EventMachine.run do
sub_1 = EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel.to_s).get :head => headers, :timeout => 30
sub_1.stream do |chunk|
chunk.should eql("-1:#{conf.ping_message_text}\r\n")
EventMachine.stop
end
end
end
end
it "should receive transfer enconding as 'chunked'" do
channel = 'ch_test_transfer_encoding_chuncked'
nginx_run_server(config, :timeout => 5) do |conf|
EventMachine.run do
sub_1 = EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel.to_s).get :head => headers, :timeout => 30
sub_1.stream do |chunk|
sub_1.response_header['TRANSFER_ENCODING'].should eql("chunked")
EventMachine.stop
end
end
end
end
it "should limit the number of subscribers to one channel" do
channel = 'ch_test_cannot_add_more_subscriber_to_one_channel_than_allowed'
other_channel = 'ch_test_cannot_add_more_subscriber_to_one_channel_than_allowed_2'
nginx_run_server(config.merge(:max_subscribers_per_channel => 3, :subscriber_connection_ttl => "3s"), :timeout => 5) do |conf|
EventMachine.run do
sub_1 = EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel.to_s).get :head => headers, :timeout => 30
sub_2 = EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel.to_s).get :head => headers, :timeout => 30
sub_3 = EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel.to_s).get :head => headers, :timeout => 30
sub_4 = EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel.to_s).get :head => headers, :timeout => 30
sub_4.callback do
sub_4.response_header.status.should eql(403)
sub_4.response_header.content_length.should eql(0)
sub_4.response_header['X_NGINX_PUSHSTREAM_EXPLAIN'].should eql("Subscribers limit per channel has been exceeded.")
end
sub_5 = EventMachine::HttpRequest.new(nginx_address + '/sub/' + other_channel.to_s).get :head => headers, :timeout => 30
sub_5.callback do
sub_5.response_header.status.should eql(200)
EventMachine.stop
end
end
end
end
it "should accept channels with '.b' in the name" do
channel = 'room.b18.beautiful'
response = ''
nginx_run_server(config.merge(:ping_message_interval => nil, :header_template => nil, :footer_template => nil, :message_template => nil), :timeout => 5) do |conf|
EventMachine.run do
publish_message_inline(channel, {'accept' => 'text/html'}, 'msg 1')
publish_message_inline(channel, {'accept' => 'text/html'}, 'msg 2')
publish_message_inline(channel, {'accept' => 'text/html'}, 'msg 3')
publish_message_inline(channel, {'accept' => 'text/html'}, 'msg 4')
sub = EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel.to_s + '.b3').get
sub.stream do |chunk|
response += chunk
end
sub.callback do
response.should eql("msg 2\r\nmsg 3\r\nmsg 4\r\n")
response = ''
sub_1 = EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel.to_s).get
sub_1.stream do |chunk|
response += chunk
end
sub_1.callback do
response.should eql("msg 5\r\n")
EventMachine.stop
end
publish_message_inline(channel, {'accept' => 'text/html'}, 'msg 5')
end
end
end
end
it "should receive acess control allow headers" do
channel = 'test_access_control_allow_headers'
nginx_run_server(config, :timeout => 5) do |conf|
EventMachine.run do
sub_1 = EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel.to_s).get :head => headers, :timeout => 30
sub_1.stream do |chunk|
sub_1.response_header['ACCESS_CONTROL_ALLOW_ORIGIN'].should eql("*")
sub_1.response_header['ACCESS_CONTROL_ALLOW_METHODS'].should eql("GET")
sub_1.response_header['ACCESS_CONTROL_ALLOW_HEADERS'].should eql("If-Modified-Since,If-None-Match")
EventMachine.stop
end
end
end
end
it "should set a default access control allow orgin header" do
channel = 'test_default_access_control_allow_origin_header'
nginx_run_server(config, :timeout => 5) do |conf|
EventMachine.run do
sub_1 = EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel.to_s).get :head => headers, :timeout => 30
sub_1.stream do |chunk|
sub_1.response_header['ACCESS_CONTROL_ALLOW_ORIGIN'].should eql("*")
EventMachine.stop
end
end
end
end
it "should set a custom access control allow orgin header" do
channel = 'test_custom_access_control_allow_origin_header'
nginx_run_server(config.merge(:allowed_origins => "custom.domain.com"), :timeout => 5) do |conf|
EventMachine.run do
sub_1 = EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel.to_s).get :head => headers, :timeout => 30
sub_1.stream do |chunk|
sub_1.response_header['ACCESS_CONTROL_ALLOW_ORIGIN'].should eql("custom.domain.com")
EventMachine.stop
end
end
end
end
it "should receive the configured header template" do
channel = 'ch_test_header_template'
nginx_run_server(config, :timeout => 5) do |conf|
EventMachine.run do
sub = EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel.to_s).get :head => headers, :timeout => 60
sub.stream do |chunk|
chunk.should eql("#{conf.header_template}\r\n")
EventMachine.stop
end
end
end
end
it "should receive the configured content type" do
channel = 'ch_test_content_type'
nginx_run_server(config, :timeout => 5) do |conf|
EventMachine.run do
sub = EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel.to_s).get :head => headers, :timeout => 60
sub.stream do |chunk|
sub.response_header['CONTENT_TYPE'].should eql(conf.content_type)
EventMachine.stop
end
end
end
end
it "should receive ping message on the configured ping message interval" do
channel = 'ch_test_ping_message_interval'
step1 = step2 = step3 = step4 = nil
chunks_received = 0
nginx_run_server(config.merge(:subscriber_connection_ttl => nil), :timeout => 10) do |conf|
EventMachine.run do
sub = EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel.to_s).get :head => headers, :timeout => 60
sub.stream do |chunk|
chunks_received += 1;
step1 = Time.now if chunks_received == 1
step2 = Time.now if chunks_received == 2
step3 = Time.now if chunks_received == 3
step4 = Time.now if chunks_received == 4
EventMachine.stop if chunks_received == 4
end
sub.callback do
chunks_received.should eql(4)
time_diff_sec(step2, step1).round.should eql(time_diff_sec(step4, step3).round)
end
end
end
end
end
require 'spec_helper'
describe "Subscriber WebSocket" do
let(:config) do
{
:header_template => nil,
:message_template => nil,
:footer_template => nil,
:extra_location => %q{
location ~ /ws/(.*)? {
# activate websocket mode for this location
push_stream_websocket;
# positional channel path
set $push_stream_channels_path $1;
}
}
}
end
it "should check accepted methods" do
nginx_run_server(config, :timeout => 5) do |conf|
EventMachine.run do
multi = EventMachine::MultiRequest.new
multi.add(:a, EventMachine::HttpRequest.new(nginx_address + '/ws/ch_test_accepted_methods_1').head)
multi.add(:b, EventMachine::HttpRequest.new(nginx_address + '/ws/ch_test_accepted_methods_2').put(:body => 'body'))
multi.add(:c, EventMachine::HttpRequest.new(nginx_address + '/ws/ch_test_accepted_methods_3').post)
multi.add(:d, EventMachine::HttpRequest.new(nginx_address + '/ws/ch_test_accepted_methods_4').delete)
multi.add(:e, EventMachine::HttpRequest.new(nginx_address + '/ws/ch_test_accepted_methods_5').get)
multi.callback do
multi.responses[:callback].length.should eql(5)
multi.responses[:callback][:a].response_header.status.should eql(405)
multi.responses[:callback][:a].req.method.should eql("HEAD")
multi.responses[:callback][:a].response_header['ALLOW'].should eql("GET")
multi.responses[:callback][:b].response_header.status.should eql(405)
multi.responses[:callback][:b].req.method.should eql("PUT")
multi.responses[:callback][:b].response_header['ALLOW'].should eql("GET")
multi.responses[:callback][:c].response_header.status.should eql(405)
multi.responses[:callback][:c].req.method.should eql("POST")
multi.responses[:callback][:c].response_header['ALLOW'].should eql("GET")
multi.responses[:callback][:d].response_header.status.should eql(405)
multi.responses[:callback][:d].req.method.should eql("DELETE")
multi.responses[:callback][:d].response_header['ALLOW'].should eql("GET")
multi.responses[:callback][:e].response_header.status.should_not eql(405)
multi.responses[:callback][:e].req.method.should eql("GET")
EventMachine.stop
end
end
end
end
it "should check mandatory headers" do
channel = 'ch_test_check_mandatory_headers'
request = "GET /ws/#{channel}.b1 HTTP/1.0\r\n"
nginx_run_server(config, :timeout => 5) do |conf|
socket = open_socket(nginx_host, nginx_port)
socket.print("#{request}\r\n")
headers, body = read_response_on_socket(socket)
body.should eql("")
headers.should match_the_pattern(/Don't have at least one of the mandatory headers: Connection, Upgrade, Sec-WebSocket-Key and Sec-WebSocket-Version/)
request << "Connection: Upgrade\r\n"
socket = open_socket(nginx_host, nginx_port)
socket.print("#{request}\r\n")
headers, body = read_response_on_socket(socket)
body.should eql("")
headers.should match_the_pattern(/Don't have at least one of the mandatory headers: Connection, Upgrade, Sec-WebSocket-Key and Sec-WebSocket-Version/)
request << "Sec-WebSocket-Key: /mQoZf6pRiv8+6o72GncLQ==\r\n"
socket = open_socket(nginx_host, nginx_port)
socket.print("#{request}\r\n")
headers, body = read_response_on_socket(socket)
body.should eql("")
headers.should match_the_pattern(/Don't have at least one of the mandatory headers: Connection, Upgrade, Sec-WebSocket-Key and Sec-WebSocket-Version/)
request << "Upgrade: websocket\r\n"
socket = open_socket(nginx_host, nginx_port)
socket.print("#{request}\r\n")
headers, body = read_response_on_socket(socket)
body.should eql("")
headers.should match_the_pattern(/Don't have at least one of the mandatory headers: Connection, Upgrade, Sec-WebSocket-Key and Sec-WebSocket-Version/)
request << "Sec-WebSocket-Version: 8\r\n"
socket = open_socket(nginx_host, nginx_port)
socket.print("#{request}\r\n")
headers, body = read_response_on_socket(socket)
body.should eql("")
headers.should_not match_the_pattern(/Don't have at least one of the mandatory headers: Connection, Upgrade, Sec-WebSocket-Key and Sec-WebSocket-Version/)
headers.should match_the_pattern(/HTTP\/1\.1 101 Switching Protocols/)
end
end
it "should check supported versions" do
channel = 'ch_test_supported_versions'
request = "GET /ws/#{channel}.b1 HTTP/1.0\r\nConnection: Upgrade\r\nSec-WebSocket-Key: /mQoZf6pRiv8+6o72GncLQ==\r\nUpgrade: websocket\r\n"
nginx_run_server(config, :timeout => 5) do |conf|
socket = open_socket(nginx_host, nginx_port)
socket.print("#{request}Sec-WebSocket-Version: 7\r\n\r\n")
headers, body = read_response_on_socket(socket)
body.should eql("")
headers.should match_the_pattern(/Sec-WebSocket-Version: 8, 13/)
headers.should match_the_pattern(/X-Nginx-PushStream-Explain: Version not supported. Supported versions: 8, 13/)
socket = open_socket(nginx_host, nginx_port)
socket.print("#{request}Sec-WebSocket-Version: 8\r\n\r\n")
headers, body = read_response_on_socket(socket)
body.should eql("")
headers.should_not match_the_pattern(/Sec-WebSocket-Version: 8, 13/)
headers.should_not match_the_pattern(/X-Nginx-PushStream-Explain: Version not supported. Supported versions: 8, 13/)
socket = open_socket(nginx_host, nginx_port)
socket.print("#{request}Sec-WebSocket-Version: 13\r\n\r\n")
headers, body = read_response_on_socket(socket)
body.should eql("")
headers.should_not match_the_pattern(/Sec-WebSocket-Version: 8, 13/)
headers.should_not match_the_pattern(/X-Nginx-PushStream-Explain: Version not supported. Supported versions: 8, 13/)
end
end
it "should check response headers" do
channel = 'ch_test_response_headers'
request = "GET /ws/#{channel}.b1 HTTP/1.0\r\nConnection: Upgrade\r\nSec-WebSocket-Key: /mQoZf6pRiv8+6o72GncLQ==\r\nUpgrade: websocket\r\nSec-WebSocket-Version: 8\r\n"
nginx_run_server(config, :timeout => 5) do |conf|
socket = open_socket(nginx_host, nginx_port)
socket.print("#{request}\r\n")
headers, body = read_response_on_socket(socket)
body.should eql("")
headers.should match_the_pattern(/HTTP\/1\.1 101 Switching Protocols/)
headers.should match_the_pattern(/Sec-WebSocket-Accept: RaIOIcQ6CBoc74B9EKdH0avYZnw=/)
headers.should match_the_pattern(/Upgrade: WebSocket/)
headers.should match_the_pattern(/Connection: Upgrade/)
end
end
it "should receive header template" do
channel = 'ch_test_receive_header_template'
request = "GET /ws/#{channel}.b1 HTTP/1.0\r\nConnection: Upgrade\r\nSec-WebSocket-Key: /mQoZf6pRiv8+6o72GncLQ==\r\nUpgrade: websocket\r\nSec-WebSocket-Version: 8\r\n"
nginx_run_server(config.merge(:header_template => "HEADER_TEMPLATE"), :timeout => 5) do |conf|
socket = open_socket(nginx_host, nginx_port)
socket.print("#{request}\r\n")
sleep(0.5)
headers, body = read_response_on_socket(socket, 'TEMPLATE')
body.should eql("\201\017HEADER_TEMPLATE")
end
end
it "should receive ping frame" do
channel = 'ch_test_receive_ping_frame'
request = "GET /ws/#{channel}.b1 HTTP/1.0\r\nConnection: Upgrade\r\nSec-WebSocket-Key: /mQoZf6pRiv8+6o72GncLQ==\r\nUpgrade: websocket\r\nSec-WebSocket-Version: 8\r\n"
nginx_run_server(config.merge(:ping_message_interval => '1s'), :timeout => 5) do |conf|
socket = open_socket(nginx_host, nginx_port)
socket.print("#{request}\r\n")
headers, body = read_response_on_socket(socket)
#wait for ping message
sleep(1)
body, dummy = read_response_on_socket(socket)
body.should eql("\211\000")
end
end
it "should receive close frame" do
channel = 'ch_test_receive_close_frame'
request = "GET /ws/#{channel}.b1 HTTP/1.0\r\nConnection: Upgrade\r\nSec-WebSocket-Key: /mQoZf6pRiv8+6o72GncLQ==\r\nUpgrade: websocket\r\nSec-WebSocket-Version: 8\r\n"
nginx_run_server(config.merge(:subscriber_connection_ttl => '1s'), :timeout => 5) do |conf|
socket = open_socket(nginx_host, nginx_port)
socket.print("#{request}\r\n")
headers, body = read_response_on_socket(socket)
#wait for disconnect
sleep(1)
body, dummy = read_response_on_socket(socket, "\210\000")
body.should eql("\210\000")
end
end
it "should receive footer template" do
channel = 'ch_test_receive_footer_template'
request = "GET /ws/#{channel}.b1 HTTP/1.0\r\nConnection: Upgrade\r\nSec-WebSocket-Key: /mQoZf6pRiv8+6o72GncLQ==\r\nUpgrade: websocket\r\nSec-WebSocket-Version: 8\r\n"
nginx_run_server(config.merge(:subscriber_connection_ttl => '1s', :footer_template => "FOOTER_TEMPLATE"), :timeout => 5) do |conf|
socket = open_socket(nginx_host, nginx_port)
socket.print("#{request}\r\n")
headers, body = read_response_on_socket(socket)
#wait for disconnect
sleep(1.5)
body, dummy = read_response_on_socket(socket, "\210\000")
body.should eql("\201\017FOOTER_TEMPLATE\210\000")
end
end
it "should check frames for messages with less than 125 bytes" do
channel = 'ch_test_receive_message_length_less_than_125'
request = "GET /ws/#{channel}.b1 HTTP/1.0\r\nConnection: Upgrade\r\nSec-WebSocket-Key: /mQoZf6pRiv8+6o72GncLQ==\r\nUpgrade: websocket\r\nSec-WebSocket-Version: 8\r\n"
nginx_run_server(config, :timeout => 5) do |conf|
socket = open_socket(nginx_host, nginx_port)
socket.print("#{request}\r\n")
headers, body = read_response_on_socket(socket)
publish_message(channel, {}, "Hello")
body, dummy = read_response_on_socket(socket, "Hello")
body.should eql("\201\005Hello")
end
end
it "should check frames for messages with more than 125 and less than 65535 bytes" do
message = ""
channel = 'ch_test_receive_message_length_more_than_125_less_then_65535'
request = "GET /ws/#{channel}.b1 HTTP/1.0\r\nConnection: Upgrade\r\nSec-WebSocket-Key: /mQoZf6pRiv8+6o72GncLQ==\r\nUpgrade: websocket\r\nSec-WebSocket-Version: 8\r\n"
65535.times { message << "a" }
nginx_run_server(config.merge(:client_max_body_size => '65k', :client_body_buffer_size => '65k'), :timeout => 5) do |conf|
publish_message(channel, {}, message)
socket = open_socket(nginx_host, nginx_port)
socket.print("#{request}\r\n")
headers, body = read_response_on_socket(socket, "aaa")
body.should match_the_pattern(/^\201~\377\377aaa/)
end
end
it "should check frames for messages with more than 65535 bytes" do
message = ""
channel = 'ch_test_receive_message_length_more_than_65535'
request = "GET /ws/#{channel}.b1 HTTP/1.0\r\nConnection: Upgrade\r\nSec-WebSocket-Key: /mQoZf6pRiv8+6o72GncLQ==\r\nUpgrade: websocket\r\nSec-WebSocket-Version: 8\r\n"
65536.times { message << "a" }
nginx_run_server(config.merge(:client_max_body_size => '70k', :client_body_buffer_size => '70k'), :timeout => 5) do |conf|
publish_message(channel, {}, message)
socket = open_socket(nginx_host, nginx_port)
socket.print("#{request}\r\n")
headers, body = read_response_on_socket(socket, "aaa")
body.should match_the_pattern(/^\201\177\000\000\000\000\000\001\000\000aaa/)
end
end
it "should accept same message template in different locations" do
channel = 'ch_test_same_message_template_different_locations'
body = 'body'
nginx_run_server(config.merge(:message_template => '{\"text\":\"~text~\"}', :subscriber_connection_ttl => '1s'), :timeout => 5) do |conf|
publish_message(channel, {}, body)
request_1 = "GET /ws/#{channel}.b1 HTTP/1.0\r\nConnection: Upgrade\r\nSec-WebSocket-Key: /mQoZf6pRiv8+6o72GncLQ==\r\nUpgrade: websocket\r\nSec-WebSocket-Version: 8\r\n"
request_2 = "GET /sub/#{channel}.b1 HTTP/1.0\r\n"
socket_1 = open_socket(nginx_host, nginx_port)
socket_1.print("#{request_1}\r\n")
headers_1, body_1 = read_response_on_socket(socket_1, '}')
body_1.should eql("\201\017{\"text\":\"#{body}\"}")
socket_2 = open_socket(nginx_host, nginx_port)
socket_2.print("#{request_2}\r\n")
headers_2, body_2 = read_response_on_socket(socket_2, '}')
body_2.should eql("11\r\n{\"text\":\"#{body}\"}\r\n\r\n")
end
end
it "should accept publish message on same stream" do
configuration = config.merge({
:message_template => '{\"channel\":\"~channel~\", \"id\":\"~id~\", \"message\":\"~text~\"}',
:extra_location => %q{
location ~ /ws/(.*)? {
# activate websocket mode for this location
push_stream_websocket;
# positional channel path
set $push_stream_channels_path $1;
# allow subscriber to publish
push_stream_websocket_allow_publish on;
# store messages
push_stream_store_messages on;
}
}
})
channel = 'ch_test_publish_message_same_stream'
frame = "%c%c%c%c%c%c%c%c%c%c%c" % [0x81, 0x85, 0xBD, 0xD0, 0xE5, 0x2A, 0xD5, 0xB5, 0x89, 0x46, 0xD2] #send 'hello' text
request = "GET /ws/#{channel}.b1 HTTP/1.0\r\nConnection: Upgrade\r\nSec-WebSocket-Key: /mQoZf6pRiv8+6o72GncLQ==\r\nUpgrade: websocket\r\nSec-WebSocket-Version: 8\r\n"
nginx_run_server(configuration, :timeout => 5) do |conf|
socket = open_socket(nginx_host, nginx_port)
socket.print("#{request}\r\n")
headers, body = read_response_on_socket(socket)
socket.print(frame)
EventMachine.run do
pub = EventMachine::HttpRequest.new(nginx_address + '/channels-stats?id=' + channel.to_s).get :timeout => 30
pub.callback do
pub.response_header.status.should eql(200)
pub.response_header.content_length.should_not eql(0)
response = JSON.parse(pub.response)
response["channel"].to_s.should eql(channel)
response["published_messages"].to_i.should eql(1)
response["stored_messages"].to_i.should eql(1)
response["subscribers"].to_i.should eql(1)
EventMachine.stop
end
end
EventMachine.run do
sub = EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel.to_s + '.b1').get :timeout => 30
sub.stream do |chunk|
line = JSON.parse(chunk.split("\r\n")[0])
line['channel'].should eql(channel.to_s)
line['message'].should eql('hello')
line['id'].to_i.should eql(1)
EventMachine.stop
end
end
end
end
it "should accept pong message" do
channel = 'ch_test_accept_pong_message'
frame = "%c%c%c%c%c%c" % [0x8A, 0x80, 0xBD, 0xD0, 0xE5, 0x2A] #send 'pong' frame
request = "GET /ws/#{channel}.b1 HTTP/1.0\r\nConnection: Upgrade\r\nSec-WebSocket-Key: /mQoZf6pRiv8+6o72GncLQ==\r\nUpgrade: websocket\r\nSec-WebSocket-Version: 8\r\n"
nginx_run_server(config, :timeout => 5) do |conf|
socket = open_socket(nginx_host, nginx_port)
socket.print("#{request}\r\n")
headers, body = read_response_on_socket(socket)
socket.print(frame)
EventMachine.run do
pub = EventMachine::HttpRequest.new(nginx_address + '/channels-stats?id=' + channel.to_s).get :timeout => 30
pub.callback do
pub.response_header.status.should eql(200)
pub.response_header.content_length.should_not eql(0)
response = JSON.parse(pub.response)
response["channel"].to_s.should eql(channel)
response["published_messages"].to_i.should eql(0)
response["stored_messages"].to_i.should eql(0)
response["subscribers"].to_i.should eql(1)
EventMachine.stop
end
end
end
end
it "should accept close message" do
channel = 'ch_test_accept_close_message'
frame = "%c%c%c%c%c%c" % [0x88, 0x80, 0xBD, 0xD0, 0xE5, 0x2A] #send 'close' frame
request = "GET /ws/#{channel}.b1 HTTP/1.0\r\nConnection: Upgrade\r\nSec-WebSocket-Key: /mQoZf6pRiv8+6o72GncLQ==\r\nUpgrade: websocket\r\nSec-WebSocket-Version: 8\r\n"
nginx_run_server(config, :timeout => 5) do |conf|
socket = open_socket(nginx_host, nginx_port)
socket.print("#{request}\r\n")
headers, body = read_response_on_socket(socket)
socket.print(frame)
EventMachine.run do
pub = EventMachine::HttpRequest.new(nginx_address + '/channels-stats?id=' + channel.to_s).get :timeout => 30
pub.callback do
pub.response_header.status.should eql(200)
pub.response_header.content_length.should_not eql(0)
response = JSON.parse(pub.response)
response["channel"].to_s.should eql(channel)
response["published_messages"].to_i.should eql(0)
response["stored_messages"].to_i.should eql(0)
response["subscribers"].to_i.should eql(0)
EventMachine.stop
end
end
end
end
end
rvm ruby-1.8.7-p302@nginx-push-stream-module --create
source 'http://rubygems.org'
gem 'rake'
group :test do
gem 'POpen4', '0.1.4'
gem 'em-http-request', '1.0.3'
gem 'json', '1.4.3'
gem 'jasmine', '1.0.2.1'
gem 'jshintrb'
gem 'therubyracer'
gem 'listen'
platforms :mri_18 do
gem "ruby-debug"
end
platforms :mri_19 do
gem "ruby-debug19"
end
end
group :docs do
gem 'github-markup'
gem 'RedCloth'
gem 'nokogiri'
end
GEM
remote: http://rubygems.org/
specs:
POpen4 (0.1.4)
Platform (>= 0.4.0)
open4
Platform (0.4.0)
RedCloth (4.2.7)
addressable (2.3.2)
archive-tar-minitar (0.5.2)
childprocess (0.2.0)
ffi (~> 1.0.6)
columnize (0.3.2)
cookiejar (0.3.0)
diff-lcs (1.1.2)
em-http-request (1.0.3)
addressable (>= 2.2.3)
cookiejar
em-socksify
eventmachine (>= 1.0.0.beta.4)
http_parser.rb (>= 0.5.3)
em-socksify (0.2.1)
eventmachine (>= 1.0.0.beta.4)
eventmachine (1.0.0)
execjs (1.4.0)
multi_json (~> 1.0)
ffi (1.0.9)
github-markup (0.7.1)
http_parser.rb (0.5.3)
jasmine (1.0.2.1)
json_pure (>= 1.4.3)
rack (>= 1.1)
rspec (>= 1.3.1)
selenium-webdriver (>= 0.1.3)
jshintrb (0.2.1)
execjs
multi_json (>= 1.3)
rake
json (1.4.3)
json_pure (1.5.3)
libv8 (3.3.10.4)
linecache (0.43)
linecache19 (0.5.11)
ruby_core_source (>= 0.1.4)
listen (0.5.3)
multi_json (1.3.7)
nokogiri (1.5.0)
open4 (1.0.1)
rack (1.3.2)
rake (0.8.7)
rspec (2.6.0)
rspec-core (~> 2.6.0)
rspec-expectations (~> 2.6.0)
rspec-mocks (~> 2.6.0)
rspec-core (2.6.4)
rspec-expectations (2.6.0)
diff-lcs (~> 1.1.2)
rspec-mocks (2.6.0)
ruby-debug (0.10.4)
columnize (>= 0.1)
ruby-debug-base (~> 0.10.4.0)
ruby-debug-base (0.10.4)
linecache (>= 0.3)
ruby-debug-base19 (0.11.24)
columnize (>= 0.3.1)
linecache19 (>= 0.5.11)
ruby_core_source (>= 0.1.4)
ruby-debug19 (0.11.6)
columnize (>= 0.3.1)
linecache19 (>= 0.5.11)
ruby-debug-base19 (>= 0.11.19)
ruby_core_source (0.1.4)
archive-tar-minitar (>= 0.5.2)
rubyzip (0.9.4)
selenium-webdriver (2.3.2)
childprocess (>= 0.1.9)
ffi (>= 1.0.7)
json_pure
rubyzip
therubyracer (0.10.2)
libv8 (~> 3.3.10)
PLATFORMS
ruby
DEPENDENCIES
POpen4 (= 0.1.4)
RedCloth
em-http-request (= 1.0.3)
github-markup
jasmine (= 1.0.2.1)
jshintrb
json (= 1.4.3)
listen
nokogiri
rake
ruby-debug
ruby-debug19
therubyracer
require 'rubygems'
require 'popen4'
require 'erb'
require 'fileutils'
require 'ruby-debug'
require 'test/unit'
require 'eventmachine'
require 'em-http'
require 'json'
require 'socket'
module BaseTestCase
def setup
create_dirs
config_log_and_pid_file
default_configuration
@test_config_file = "#{method_name_for_test}.conf"
config_test_name = "config_#{method_name_for_test}"
self.send(config_test_name) if self.respond_to?(config_test_name)
self.create_config_file
unless @disable_start_stop_server
self.start_server
end
end
def teardown
old_cld_trap = Signal.trap("CLD", "IGNORE") unless @disable_ignore_childs
unless @disable_start_stop_server
self.stop_server
end
self.delete_config_and_log_files
Signal.trap("CLD", old_cld_trap) unless @disable_ignore_childs
end
def nginx_executable
if is_to_use_memory_check
return "valgrind --show-reachable=yes --trace-children=yes --time-stamp=yes --leak-check=full --log-file=mld_#{method_name_for_test}.log #{ENV['NGINX_EXEC'].nil? ? "/usr/local/nginx/sbin/nginx" : ENV['NGINX_EXEC']}"
else
return ENV['NGINX_EXEC'].nil? ? "/usr/local/nginx/sbin/nginx" : ENV['NGINX_EXEC']
end
end
def is_to_use_memory_check
!ENV['CHECK_MEMORY'].nil? and !`which valgrind`.empty?
end
def nginx_address
return "http://#{nginx_host}:#{nginx_port}"
end
def nginx_host
return ENV['NGINX_HOST'].nil? ? "127.0.0.1" : ENV['NGINX_HOST']
end
def nginx_port
return ENV['NGINX_PORT'].nil? ? "9990" : ENV['NGINX_PORT']
end
def nginx_workers
return ENV['NGINX_WORKERS'].nil? ? "1" : ENV['NGINX_WORKERS']
end
def nginx_tests_tmp_dir
return ENV['NGINX_TESTS_TMP_DIR'].nil? ? "tmp" : ENV['NGINX_TESTS_TMP_DIR']
end
def start_server
error_message = ""
status = POpen4::popen4("#{ nginx_executable } -c #{ config_filename }") do |stdout, stderr, stdin, pid|
error_message = stderr.read.strip unless stderr.eof
return error_message unless error_message.nil?
end
assert_equal(0, status.exitstatus, "Server doesn't started - #{error_message}")
end
def stop_server
error_message = ""
status = POpen4::popen4("#{ nginx_executable } -c #{ config_filename } -s stop") do |stdout, stderr, stdin, pid|
error_message = stderr.read.strip unless stderr.eof
return error_message unless error_message.nil?
end
assert_equal(0, status.exitstatus, "Server doesn't stop - #{error_message}")
end
def create_config_file
template = ERB.new @config_template || @@config_template
config_content = template.result(binding)
File.open(config_filename, 'w') {|f| f.write(config_content) }
File.open(mime_types_filename, 'w') {|f| f.write(@@mime_tipes_template) }
end
def delete_config_and_log_files
if has_passed?
File.delete(config_filename) if File.exist?(config_filename)
File.delete(mime_types_filename) if File.exist?(mime_types_filename)
File.delete(@main_error_log) if File.exist?(@main_error_log)
File.delete(@access_log) if File.exist?(@access_log)
File.delete(@error_log) if File.exist?(@error_log)
FileUtils.rm_rf(@client_body_temp) if File.exist?(@client_body_temp)
end
end
def create_dirs
FileUtils.mkdir(nginx_tests_tmp_dir) unless File.exist?(nginx_tests_tmp_dir) and File.directory?(nginx_tests_tmp_dir)
FileUtils.mkdir("#{nginx_tests_tmp_dir}/client_body_temp") unless File.exist?("#{nginx_tests_tmp_dir}/client_body_temp") and File.directory?("#{nginx_tests_tmp_dir}/client_body_temp")
FileUtils.mkdir("#{nginx_tests_tmp_dir}/logs") unless File.exist?("#{nginx_tests_tmp_dir}/logs") and File.directory?("#{nginx_tests_tmp_dir}/logs")
end
def has_passed?
@test_passed.nil? ? @passed : @test_passed
end
def config_log_and_pid_file
@client_body_temp = File.expand_path("#{nginx_tests_tmp_dir}/client_body_temp")
@pid_file = File.expand_path("#{nginx_tests_tmp_dir}/logs/nginx.pid")
@main_error_log = File.expand_path("#{nginx_tests_tmp_dir}/logs/nginx-main_error-#{method_name_for_test}.log")
@access_log = File.expand_path("#{nginx_tests_tmp_dir}/logs/nginx-http_access-#{method_name_for_test}.log")
@error_log = File.expand_path("#{nginx_tests_tmp_dir}/logs/nginx-http_error-#{method_name_for_test}.log")
end
def config_filename
File.expand_path("#{nginx_tests_tmp_dir}/#{ @test_config_file }")
end
def mime_types_filename
File.expand_path("#{nginx_tests_tmp_dir}/mime.types")
end
def method_name_for_test
self.respond_to?('method_name') ? self.method_name : self.__name__
end
def time_diff_milli(start, finish)
(finish - start) * 1000.0
end
def time_diff_sec(start, finish)
(finish - start)
end
def default_configuration
@master_process = 'off'
@daemon = 'off'
@max_reserved_memory = '10m'
@authorized_channels_only = 'off'
@broadcast_channel_max_qtd = 3
@broadcast_channel_prefix = 'broad_'
@content_type = 'text/html; charset=utf-8'
@header_template = %{<html><head><meta http-equiv=\\"Content-Type\\" content=\\"text/html; charset=utf-8\\">\\r\\n<meta http-equiv=\\"Cache-Control\\" content=\\"no-store\\">\\r\\n<meta http-equiv=\\"Cache-Control\\" content=\\"no-cache\\">\\r\\n<meta http-equiv=\\"Expires\\" content=\\"Thu, 1 Jan 1970 00:00:00 GMT\\">\\r\\n<script type=\\"text/javascript\\">\\r\\nwindow.onError = null;\\r\\ndocument.domain = \\'#{nginx_host}\\';\\r\\nparent.PushStream.register(this);\\r\\n</script>\\r\\n</head>\\r\\n<body onload=\\"try { parent.PushStream.reset(this) } catch (e) {}\\">}
@footer_template = %{</body></html>}
@max_channel_id_length = 200
@max_message_buffer_length = 20
@max_subscribers_per_channel = nil
@max_number_of_broadcast_channels = nil
@max_number_of_channels = nil
@message_template = %{<script>p(~id~,\\'~channel~\\',\\'~text~\\');</script>}
@min_message_buffer_timeout = '50m'
@ping_message_interval = '10s'
@store_messages = 'on'
@subscriber_connection_timeout = nil
@longpolling_connection_timeout = nil
@memory_cleanup_timeout = '5m'
@config_template = nil
@keepalive = 'off'
@channel_deleted_message_text = nil
@ping_message_text = nil
@subscriber_eventsource = 'off'
@subscriber_mode = nil
@publisher_mode = nil
@last_received_message_time = nil
@last_received_message_tag = nil
@user_agent = nil
@padding_by_user_agent = nil
self.send(:global_configuration) if self.respond_to?(:global_configuration)
end
def publish_message_inline_with_callbacks(channel, headers, body, callbacks = {})
pub = EventMachine::HttpRequest.new(nginx_address + '/pub?id=' + channel.to_s).post :head => headers, :body => body, :timeout => 30
pub.callback do
if pub.response_header.status == 200
callbacks[:success].call(pub.response_header.status, pub.response) unless callbacks[:success].nil?
else
callbacks[:error].call(pub.response_header.status, pub.response) unless callbacks[:error].nil?
end
end
pub
end
def publish_message(channel, headers, body)
EventMachine.run {
pub = publish_message_inline(channel, headers, body) do
assert_not_equal(0, pub.response_header.content_length, "Empty response was received")
response = JSON.parse(pub.response)
assert_equal(channel, response["channel"].to_s, "Channel was not recognized")
EventMachine.stop
end
add_test_timeout
}
end
def publish_message_inline(channel, headers, body, &block)
pub = EventMachine::HttpRequest.new(nginx_address + '/pub?id=' + channel.to_s).post :head => headers, :body => body, :timeout => 30
pub.callback {
fail("Request was not accepted") if pub.response_header.status != 200
block.call unless block.nil?
}
pub
end
def publish_message_in_socket(channel, body, socket)
post_channel_message = "POST /pub?id=#{channel} HTTP/1.0\r\nContent-Length: #{body.size}\r\n\r\n#{body}"
socket.print(post_channel_message)
read_response(socket)
end
def create_channel_by_subscribe(channel, headers, timeout=60, &block)
EventMachine.run {
sub_1 = EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel.to_s).get :head => headers, :timeout => timeout
sub_1.stream { |chunk|
block.call
}
sub_1.callback {
EventMachine.stop
}
}
end
def add_test_timeout(timeout=5)
EM.add_timer(timeout) do
fail("Test timeout reached")
EventMachine.stop
end
end
def open_socket
TCPSocket.open(nginx_host, nginx_port)
end
def read_response(socket, wait_for=nil)
response ||= socket.readpartial(1)
while (tmp = socket.read_nonblock(256))
response += tmp
end
rescue Errno::EAGAIN => e
headers, body = (response || "").split("\r\n\r\n", 2)
if !wait_for.nil? && (body.nil? || body.empty? || !body.include?(wait_for))
IO.select([socket])
retry
end
ensure
fail("Any response") if response.nil?
headers, body = response.split("\r\n\r\n", 2)
return headers, body
end
@@config_template = %q{
pid <%= @pid_file %>;
error_log <%= @main_error_log %> debug;
# Development Mode
master_process <%=@master_process%>;
daemon <%=@daemon%>;
worker_processes <%=nginx_workers%>;
events {
worker_connections 1024;
use <%= (RUBY_PLATFORM =~ /darwin/) ? 'kqueue' : 'epoll' %>;
}
http {
include mime.types;
default_type application/octet-stream;
access_log <%= @access_log %>;
error_log <%= @error_log %> debug;
tcp_nopush on;
tcp_nodelay on;
keepalive_timeout 10;
send_timeout 10;
client_body_timeout 10;
client_header_timeout 10;
sendfile on;
client_header_buffer_size 1k;
large_client_header_buffers 2 4k;
client_max_body_size 1k;
client_body_buffer_size 1k;
ignore_invalid_headers on;
client_body_in_single_buffer on;
client_body_temp_path <%= @client_body_temp %>;
<%= "push_stream_shared_memory_size #{@max_reserved_memory};" unless @max_reserved_memory.nil? %>
<%= "push_stream_shared_memory_cleanup_objects_ttl #{@memory_cleanup_timeout};" unless @memory_cleanup_timeout.nil? %>
<%= %{push_stream_channel_deleted_message_text "#{@channel_deleted_message_text}";} unless @channel_deleted_message_text.nil? %>
<%= %{push_stream_ping_message_text "#{@ping_message_text}";} unless @ping_message_text.nil? %>
<%= %{push_stream_broadcast_channel_prefix "#{@broadcast_channel_prefix}";} unless @broadcast_channel_prefix.nil? %>
<%= "push_stream_max_number_of_channels #{@max_number_of_channels};" unless @max_number_of_channels.nil? %>
<%= "push_stream_max_number_of_broadcast_channels #{@max_number_of_broadcast_channels};" unless @max_number_of_broadcast_channels.nil? %>
<%= "push_stream_last_received_message_time #{@last_received_message_time};" unless @last_received_message_time.nil? %>
<%= "push_stream_last_received_message_tag #{@last_received_message_tag};" unless @last_received_message_tag.nil? %>
<%= "push_stream_user_agent #{@user_agent};" unless @user_agent.nil? %>
<%= "push_stream_padding_by_user_agent '#{@padding_by_user_agent}';" unless @padding_by_user_agent.nil? %>
# max subscribers per channel
<%= "push_stream_max_subscribers_per_channel #{@max_subscribers_per_channel};" unless @max_subscribers_per_channel.nil? %>
# max messages to store in memory
<%= "push_stream_max_messages_stored_per_channel #{@max_message_buffer_length};" unless @max_message_buffer_length.nil? %>
# message ttl
<%= "push_stream_message_ttl #{@min_message_buffer_timeout};" unless @min_message_buffer_timeout.nil? %>
<%= "push_stream_max_channel_id_length #{@max_channel_id_length};" unless @max_channel_id_length.nil? %>
# ping frequency
<%= "push_stream_ping_message_interval #{@ping_message_interval};" unless @ping_message_interval.nil? %>
# connection ttl to enable recycle
<%= "push_stream_subscriber_connection_ttl #{@subscriber_connection_timeout};" unless @subscriber_connection_timeout.nil? %>
# timeout for long polling connections
<%= "push_stream_longpolling_connection_ttl #{@longpolling_connection_ttl};" unless @longpolling_connection_ttl.nil? %>
# header to be sent when receiving new subscriber connection
<%= %{push_stream_header_template "#{@header_template}";} unless @header_template.nil? %>
# message template
<%= %{push_stream_message_template "#{@message_template}";} unless @message_template.nil? %>
# footer to be sent when finishing subscriber connection
<%= %{push_stream_footer_template "#{@footer_template}";} unless @footer_template.nil? %>
# subscriber may create channels on demand or only authorized
# (publisher) may do it?
<%= "push_stream_authorized_channels_only #{@authorized_channels_only};" unless @authorized_channels_only.nil? %>
<%= "push_stream_broadcast_channel_max_qtd #{@broadcast_channel_max_qtd};" unless @broadcast_channel_max_qtd.nil? %>
<%= "push_stream_allowed_origins #{@allowed_origins};" unless @allowed_origins.nil? %>
server {
listen <%=nginx_port%>;
server_name <%=nginx_host%>;
location /channels-stats {
# activate channels statistics mode for this location
push_stream_channels_statistics;
# query string based channel id
set $push_stream_channel_id $arg_id;
# keepalive
<%= "push_stream_keepalive #{@keepalive};" unless @keepalive.nil? %>
}
location /pub {
# activate publisher mode for this location
push_stream_publisher <%= @publisher_mode unless @publisher_mode.nil? || @publisher_mode == "normal" %>;
# query string based channel id
set $push_stream_channel_id $arg_id;
# store messages
<%= "push_stream_store_messages #{@store_messages};" unless @store_messages.nil? %>
# keepalive
<%= "push_stream_keepalive #{@keepalive};" unless @keepalive.nil? %>
# client_max_body_size MUST be equal to client_body_buffer_size or
# you will be sorry.
client_max_body_size <%= @client_max_body_size.nil? ? '32k' : @client_max_body_size %>;
client_body_buffer_size <%= @client_body_buffer_size.nil? ? '32k' : @client_body_buffer_size %>;
}
location ~ /sub/(.*)? {
# activate subscriber mode for this location
push_stream_subscriber <%= @subscriber_mode unless @subscriber_mode.nil? || @subscriber_mode == "streaming" %>;
# activate event source support for this location
<%= "push_stream_eventsource_support #{@subscriber_eventsource};" unless @subscriber_eventsource.nil? %>
# positional channel path
set $push_stream_channels_path $1;
# content-type
<%= %{push_stream_content_type "#{@content_type}";} unless @content_type.nil? %>
}
<%= @extra_location %>
}
}
}
@@mime_tipes_template = %q{
types {
text/html html htm shtml;
text/css css;
text/xml xml;
image/gif gif;
image/jpeg jpeg jpg;
application/x-javascript js;
application/atom+xml atom;
application/rss+xml rss;
text/mathml mml;
text/plain txt;
text/vnd.sun.j2me.app-descriptor jad;
text/vnd.wap.wml wml;
text/x-component htc;
image/png png;
image/tiff tif tiff;
image/vnd.wap.wbmp wbmp;
image/x-icon ico;
image/x-jng jng;
image/x-ms-bmp bmp;
image/svg+xml svg;
application/java-archive jar war ear;
application/mac-binhex40 hqx;
application/msword doc;
application/pdf pdf;
application/postscript ps eps ai;
application/rtf rtf;
application/vnd.ms-excel xls;
application/vnd.ms-powerpoint ppt;
application/vnd.wap.wmlc wmlc;
application/vnd.wap.xhtml+xml xhtml;
application/vnd.google-earth.kml+xml kml;
application/vnd.google-earth.kmz kmz;
application/x-cocoa cco;
application/x-java-archive-diff jardiff;
application/x-java-jnlp-file jnlp;
application/x-makeself run;
application/x-perl pl pm;
application/x-pilot prc pdb;
application/x-rar-compressed rar;
application/x-redhat-package-manager rpm;
application/x-sea sea;
application/x-shockwave-flash swf;
application/x-stuffit sit;
application/x-tcl tcl tk;
application/x-x509-ca-cert der pem crt;
application/x-xpinstall xpi;
application/zip zip;
application/octet-stream bin exe dll;
application/octet-stream deb;
application/octet-stream dmg;
application/octet-stream eot;
application/octet-stream iso img;
application/octet-stream msi msp msm;
audio/midi mid midi kar;
audio/mpeg mp3;
audio/x-realaudio ra;
video/3gpp 3gpp 3gp;
video/mpeg mpeg mpg;
video/quicktime mov;
video/x-flv flv;
video/x-mng mng;
video/x-ms-asf asx asf;
video/x-ms-wmv wmv;
video/x-msvideo avi;
}
}
end
# src_files
#
# Return an array of filepaths relative to src_dir to include before jasmine specs.
# Default: []
#
# EXAMPLE:
#
# src_files:
# - lib/source1.js
# - lib/source2.js
# - dist/**/*.js
#
src_files:
- test/tmp/js/pushstream.js
# stylesheets
#
# Return an array of stylesheet filepaths relative to src_dir to include before jasmine specs.
# Default: []
#
# EXAMPLE:
#
# stylesheets:
# - css/style.css
# - stylesheets/*.css
#
stylesheets:
# helpers
#
# Return an array of filepaths relative to spec_dir to include before jasmine specs.
# Default: ["helpers/**/*.js"]
#
# EXAMPLE:
#
# helpers:
# - helpers/**/*.js
#
helpers:
# spec_files
#
# Return an array of filepaths relative to spec_dir to include.
# Default: ["**/*[sS]pec.js"]
#
# EXAMPLE:
#
# spec_files:
# - **/*[sS]pec.js
#
spec_files:
# src_dir
#
# Source directory path. Your src_files must be returned relative to this path. Will use root if left blank.
# Default: project root
#
# EXAMPLE:
#
# src_dir: public
#
src_dir:
../
# spec_dir
#
# Spec directory path. Your spec_files must be returned relative to this path.
# Default: spec/javascripts
#
# EXAMPLE:
#
# spec_dir: spec/javascripts
#
spec_dir:
module Jasmine
class Config
# Add your overrides or custom config code here
end
end
# Note - this is necessary for rspec2, which has removed the backtrace
module Jasmine
class SpecBuilder
def declare_spec(parent, spec)
me = self
example_name = spec["name"]
@spec_ids << spec["id"]
backtrace = @example_locations[parent.description + " " + example_name]
parent.it example_name, {} do
me.report_spec(spec["id"])
end
end
end
end
$:.unshift(ENV['JASMINE_GEM_PATH']) if ENV['JASMINE_GEM_PATH'] # for gem testing purposes
require 'rubygems'
require 'jasmine'
jasmine_config_overrides = File.expand_path(File.join(File.dirname(__FILE__), 'jasmine_config.rb'))
require jasmine_config_overrides if File.exist?(jasmine_config_overrides)
if Jasmine::rspec2?
require 'rspec'
else
require 'spec'
end
jasmine_config = Jasmine::Config.new
spec_builder = Jasmine::SpecBuilder.new(jasmine_config)
should_stop = false
if Jasmine::rspec2?
RSpec.configuration.after(:suite) do
spec_builder.stop if should_stop
end
else
Spec::Runner.configure do |config|
config.after(:suite) do
spec_builder.stop if should_stop
end
end
end
spec_builder.start
should_stop = true
spec_builder.declare_suites
\ No newline at end of file
require File.expand_path('base_test_case', File.dirname(__FILE__))
class TestBroadcastProperties < Test::Unit::TestCase
include BaseTestCase
def config_test_broadcast_channel_prefix
@authorized_channels_only = "on"
@header_template = "connected"
@broadcast_channel_prefix = "XXX_"
end
def test_broadcast_channel_prefix
channel = 'ch_test_broadcast_channel_prefix'
channel_broad = 'XXX_123'
channel_broad_fail = 'YYY_123'
headers = {'accept' => 'text/html'}
body = 'broadcast channel prefix'
EventMachine.run {
pub = EventMachine::HttpRequest.new(nginx_address + '/pub?id=' + channel.to_s ).post :head => headers, :body => body, :timeout => 30
pub.callback {
sub_1 = EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel.to_s + '/' + channel_broad_fail).get :head => headers, :timeout => 60
sub_1.callback { |chunk|
assert_equal(403, sub_1.response_header.status, "Subscriber was not forbidden")
sub_2 = EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel.to_s + '/' + channel_broad).get :head => headers, :timeout => 60
sub_2.stream { |chunk|
assert_equal("#{@header_template}\r\n", chunk, "Didn't received header template")
EventMachine.stop
}
}
}
}
end
def config_test_broadcast_channel_max_qtd
@authorized_channels_only = "on"
@header_template = "connected"
@broadcast_channel_prefix = "XXX_"
@broadcast_channel_max_qtd = 2
end
def test_broadcast_channel_max_qtd
channel = 'ch_test_broadcast_channel_max_qtd'
channel_broad1 = 'XXX_123'
channel_broad2 = 'XXX_321'
channel_broad3 = 'XXX_213'
headers = {'accept' => 'text/html'}
body = 'broadcast channel prefix'
EventMachine.run {
pub = EventMachine::HttpRequest.new(nginx_address + '/pub?id=' + channel.to_s ).post :head => headers, :body => body, :timeout => 30
pub.callback {
sub_1 = EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel.to_s + '/' + channel_broad1 + '/' + channel_broad2 + '/' + channel_broad3).get :head => headers, :timeout => 60
sub_1.callback { |chunk|
assert_equal(403, sub_1.response_header.status, "Subscriber was not forbidden")
sub_2 = EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel.to_s + '/' + channel_broad1 + '/' + channel_broad2).get :head => headers, :timeout => 60
sub_2.stream { |chunk|
EventMachine.stop
}
}
}
}
end
end
require File.expand_path('base_test_case', File.dirname(__FILE__))
class TestChannelIdCollision < Test::Unit::TestCase
include BaseTestCase
def test_create_and_retrieve_channels_with_ids_that_collide
channels = ["A", "plumless", "buckeroo", "B", "fc0591", "123rainerbommert", "C", "a1sellers", "advertees", "D"]
channels.each do |channel|
EventMachine.run {
pub = EventMachine::HttpRequest.new(nginx_address + '/pub?id=' + channel).post :body => 'x', :timeout => 30
pub.callback {
assert_equal(200, pub.response_header.status, "Channel '#{channel}' was not created")
EventMachine.stop
}
}
end
channels.each do |channel|
EventMachine.run {
pub = EventMachine::HttpRequest.new(nginx_address + '/channels-stats?id=' + channel).get :timeout => 30
pub.callback {
assert_equal(200, pub.response_header.status, "Channel '#{channel}' was not founded")
EventMachine.stop
}
}
end
end
end
require File.expand_path('base_test_case', File.dirname(__FILE__))
class TestChannelStatistics < Test::Unit::TestCase
include BaseTestCase
def test_get_channel_statistics_whithout_created_channel
headers = {'accept' => 'application/json'}
channel = 'ch_test_get_channel_statistics_whithout_created_channel'
EventMachine.run {
pub_1 = EventMachine::HttpRequest.new(nginx_address + '/channels-stats?id=' + channel.to_s).get :head => headers, :timeout => 30
pub_1.callback {
assert_equal(404, pub_1.response_header.status, "Channel was founded")
assert_equal(0, pub_1.response_header.content_length, "Recieved a non empty response")
EventMachine.stop
}
}
end
def test_get_channel_statistics_to_existing_channel
headers = {'accept' => 'application/json'}
channel = 'ch_test_get_channel_statistics_to_existing_channel'
body = 'body'
#create channel
publish_message(channel, headers, body)
EventMachine.run {
pub_2 = EventMachine::HttpRequest.new(nginx_address + '/channels-stats?id=' + channel.to_s).get :head => headers, :timeout => 30
pub_2.callback {
assert_equal(200, pub_2.response_header.status, "Request was not accepted")
assert_not_equal(0, pub_2.response_header.content_length, "Empty response was received")
response = JSON.parse(pub_2.response)
assert_equal(channel, response["channel"].to_s, "Channel was not recognized")
assert_equal(1, response["published_messages"].to_i, "Message was not published")
assert_equal(1, response["stored_messages"].to_i, "Message was not stored")
assert_equal(0, response["subscribers"].to_i, "Wrong number for subscribers")
EventMachine.stop
}
}
end
def test_get_channel_statistics_to_existing_channel_with_subscriber
headers = {'accept' => 'application/json'}
channel = 'ch_test_get_channel_statistics_to_existing_channel_with_subscriber'
body = 'body'
create_channel_by_subscribe(channel, headers) do
pub_1 = EventMachine::HttpRequest.new(nginx_address + '/channels-stats?id=' + channel.to_s).get :head => headers, :timeout => 30
pub_1.callback {
assert_equal(200, pub_1.response_header.status, "Request was not accepted")
assert_not_equal(0, pub_1.response_header.content_length, "Empty response was received")
response = JSON.parse(pub_1.response)
assert_equal(channel, response["channel"].to_s, "Channel was not recognized")
assert_equal(0, response["published_messages"].to_i, "Wrong number for published messages")
assert_equal(0, response["stored_messages"].to_i, "Wrong number for stored messages")
assert_equal(1, response["subscribers"].to_i, "Wrong number for subscribers")
EventMachine.stop
}
end
end
def test_get_detailed_channels_statistics_whithout_created_channels
headers = {'accept' => 'application/json'}
EventMachine.run {
pub_2 = EventMachine::HttpRequest.new(nginx_address + '/channels-stats?id=ALL').get :head => headers, :timeout => 30
pub_2.callback {
assert_equal(200, pub_2.response_header.status, "Request was not accepted")
assert_not_equal(0, pub_2.response_header.content_length, "Empty response was received")
response = JSON.parse(pub_2.response)
assert_equal(0, response["infos"].length, "Received info whithout_created_channels")
EventMachine.stop
}
}
end
def test_get_detailed_channels_statistics_to_existing_channel
headers = {'accept' => 'application/json'}
channel = 'ch_test_get_detailed_channels_statistics_to_existing_channel'
body = 'body'
#create channel
publish_message(channel, headers, body)
EventMachine.run {
pub_2 = EventMachine::HttpRequest.new(nginx_address + '/channels-stats?id=ALL').get :head => headers, :timeout => 30
pub_2.callback {
assert_equal(200, pub_2.response_header.status, "Request was not accepted")
assert_not_equal(0, pub_2.response_header.content_length, "Empty response was received")
response = JSON.parse(pub_2.response)
assert_equal(1, response["infos"].length, "Didn't received info about the only created channel")
assert_equal(channel, response["infos"][0]["channel"].to_s, "Channel was not recognized")
assert_equal(1, response["infos"][0]["published_messages"].to_i, "Message was not published")
assert_equal(1, response["infos"][0]["stored_messages"].to_i, "Message was not stored")
assert_equal(0, response["infos"][0]["subscribers"].to_i, "Wrong number for subscribers")
EventMachine.stop
}
}
end
def config_test_get_detailed_channels_statistics_to_existing_broadcast_channel
@broadcast_channel_prefix = 'bd_'
@broadcast_channel_max_qtd = 1
end
def test_get_detailed_channels_statistics_to_existing_broadcast_channel
headers = {'accept' => 'application/json'}
channel = 'bd_test_get_detailed_channels_statistics_to_existing_broadcast_channel'
body = 'body'
#create channel
publish_message(channel, headers, body)
EventMachine.run {
pub_2 = EventMachine::HttpRequest.new(nginx_address + '/channels-stats?id=ALL').get :head => headers, :timeout => 30
pub_2.callback {
assert_equal(200, pub_2.response_header.status, "Request was not accepted")
assert_not_equal(0, pub_2.response_header.content_length, "Empty response was received")
response = JSON.parse(pub_2.response)
assert_equal(1, response["infos"].length, "Didn't received info about the only created channel")
assert_equal(0, response["channels"].to_i, "Channel was not recognized")
assert_equal(1, response["broadcast_channels"].to_i, "Channel was not recognized")
assert_equal(channel, response["infos"][0]["channel"].to_s, "Channel was not recognized")
assert_equal(1, response["infos"][0]["published_messages"].to_i, "Message was not published")
assert_equal(1, response["infos"][0]["stored_messages"].to_i, "Message was not stored")
assert_equal(0, response["infos"][0]["subscribers"].to_i, "Wrong number for subscribers")
EventMachine.stop
}
}
end
def test_detailed_channels_statistics_to_existing_channel_with_subscriber
headers = {'accept' => 'application/json'}
channel = 'ch_test_detailed_channels_statistics_to_existing_channel_with_subscriber'
body = 'body'
create_channel_by_subscribe(channel, headers) do
pub_1 = EventMachine::HttpRequest.new(nginx_address + '/channels-stats?id=ALL').get :head => headers, :timeout => 30
pub_1.callback {
assert_equal(200, pub_1.response_header.status, "Request was not accepted")
assert_not_equal(0, pub_1.response_header.content_length, "Empty response was received")
response = JSON.parse(pub_1.response)
assert_equal(1, response["infos"].length, "Didn't received info about the only created channel")
assert_equal(channel, response["infos"][0]["channel"].to_s, "Channel was not recognized")
assert_equal(0, response["infos"][0]["published_messages"].to_i, "Wrong number for published messages")
assert_equal(0, response["infos"][0]["stored_messages"].to_i, "Wrong number for stored messages")
assert_equal(1, response["infos"][0]["subscribers"].to_i, "Wrong number for subscribers")
EventMachine.stop
}
end
end
def test_get_summarized_channels_statistics_whithout_created_channels
headers = {'accept' => 'application/json'}
EventMachine.run {
pub_1 = EventMachine::HttpRequest.new(nginx_address + '/channels-stats').get :head => headers, :timeout => 30
pub_1.callback {
assert_equal(200, pub_1.response_header.status, "Don't get channels statistics")
assert_not_equal(0, pub_1.response_header.content_length, "Don't received channels statistics")
begin
response = JSON.parse(pub_1.response)
assert(response.has_key?("channels"), "Didn't received the correct answer with channels info")
assert_equal(0, response["channels"].to_i, "Returned values with channels created")
rescue JSON::ParserError
fail("Didn't receive a valid response")
end
EventMachine.stop
}
}
end
def test_get_summarized_channels_statistics_to_existing_channel
headers = {'accept' => 'application/json'}
channel = 'ch_test_get_summarized_channels_statistics_to_existing_channel'
body = 'body'
#create channel
publish_message(channel, headers, body)
EventMachine.run {
pub_2 = EventMachine::HttpRequest.new(nginx_address + '/channels-stats').get :head => headers, :timeout => 30
pub_2.callback {
assert_equal(200, pub_2.response_header.status, "Don't get channels statistics")
assert_not_equal(0, pub_2.response_header.content_length, "Don't received channels statistics")
begin
response = JSON.parse(pub_2.response)
assert(response.has_key?("channels"), "Didn't received the correct answer with channels info")
assert_equal(1, response["channels"].to_i, "Don't returned values with created channel")
assert_equal(1, response["published_messages"].to_i, "Message was not published")
assert_equal(0, response["subscribers"].to_i, "Wrong number for subscribers")
rescue JSON::ParserError
fail("Didn't receive a valid response")
end
EventMachine.stop
}
}
end
def config_test_get_summarized_channels_statistics_to_existing_broadcast_channel
@broadcast_channel_prefix = 'bd_'
@broadcast_channel_max_qtd = 1
end
def test_get_summarized_channels_statistics_to_existing_broadcast_channel
headers = {'accept' => 'application/json'}
channel = 'bd_test_get_summarized_channels_statistics_to_existing_broadcast_channel'
body = 'body'
#create channel
publish_message(channel, headers, body)
EventMachine.run {
pub_2 = EventMachine::HttpRequest.new(nginx_address + '/channels-stats').get :head => headers, :timeout => 30
pub_2.callback {
assert_equal(200, pub_2.response_header.status, "Don't get channels statistics")
assert_not_equal(0, pub_2.response_header.content_length, "Don't received channels statistics")
begin
response = JSON.parse(pub_2.response)
assert(response.has_key?("channels"), "Didn't received the correct answer with channels info")
assert_equal(0, response["channels"].to_i, "Don't returned values with created channel")
assert_equal(1, response["broadcast_channels"].to_i, "Don't returned values with created channel")
assert_equal(1, response["published_messages"].to_i, "Message was not published")
assert_equal(0, response["subscribers"].to_i, "Wrong number for subscribers")
rescue JSON::ParserError
fail("Didn't receive a valid response")
end
EventMachine.stop
}
}
end
def test_summarized_channels_statistics_to_existing_channel_with_subscriber
headers = {'accept' => 'application/json'}
channel = 'ch_test_summarized_channels_statistics_to_existing_channel_with_subscriber'
body = 'body'
create_channel_by_subscribe(channel, headers) do
pub_1 = EventMachine::HttpRequest.new(nginx_address + '/channels-stats').get :head => headers, :timeout => 30
pub_1.callback {
assert_equal(200, pub_1.response_header.status, "Request was not accepted")
assert_not_equal(0, pub_1.response_header.content_length, "Empty response was received")
response = JSON.parse(pub_1.response)
assert(response.has_key?("channels"), "Didn't received the correct answer with channels info")
assert_equal(1, response["channels"].to_i, "Don't returned values with created channel")
assert_equal(0, response["published_messages"].to_i, "Wrong number for published messages")
assert_equal(1, response["subscribers"].to_i, "Wrong number for subscribers")
EventMachine.stop
}
end
end
def test_accepted_methods_channel_statistics
EventMachine.run {
multi = EventMachine::MultiRequest.new
multi.add(:a, EventMachine::HttpRequest.new(nginx_address + '/channels-stats').get)
multi.add(:b, EventMachine::HttpRequest.new(nginx_address + '/channels-stats').put(:body => 'body'))
multi.add(:c, EventMachine::HttpRequest.new(nginx_address + '/channels-stats').post)
multi.add(:d, EventMachine::HttpRequest.new(nginx_address + '/channels-stats').delete)
multi.add(:e, EventMachine::HttpRequest.new(nginx_address + '/channels-stats').head)
multi.callback {
assert_equal(5, multi.responses[:callback].length)
assert_not_equal(405, multi.responses[:callback][:a].response_header.status, "Statistics does accept GET")
assert_equal("GET", multi.responses[:callback][:a].req.method, "Array is with wrong order")
assert_equal(405, multi.responses[:callback][:b].response_header.status, "Statistics does not accept PUT")
assert_equal("PUT", multi.responses[:callback][:b].req.method, "Array is with wrong order")
assert_equal(405, multi.responses[:callback][:c].response_header.status, "Statistics does not accept POST")
assert_equal("POST", multi.responses[:callback][:c].req.method, "Array is with wrong order")
assert_equal(405, multi.responses[:callback][:d].response_header.status, "Statistics does not accept DELETE")
assert_equal("DELETE", multi.responses[:callback][:d].req.method, "Array is with wrong order")
assert_equal(405, multi.responses[:callback][:e].response_header.status, "Statistics does not accept HEAD")
assert_equal("HEAD", multi.responses[:callback][:e].req.method, "Array is with wrong order")
EventMachine.stop
}
}
end
def test_accepted_content_types
headers = {'accept' => 'application/json'}
channel = 'ch_test_accepted_content_types'
body = 'body'
#create channel
publish_message(channel, headers, body)
EventMachine.run {
multi = EventMachine::MultiRequest.new
multi.add(:a, EventMachine::HttpRequest.new(nginx_address + '/channels-stats').get) # default content_type
multi.add(:b, EventMachine::HttpRequest.new(nginx_address + '/channels-stats').get(:head => {'accept' => 'text/plain'}))
multi.add(:c, EventMachine::HttpRequest.new(nginx_address + '/channels-stats').get(:head => {'accept' => 'application/json'}))
multi.add(:d, EventMachine::HttpRequest.new(nginx_address + '/channels-stats').get(:head => {'accept' => 'application/yaml'}))
multi.add(:e, EventMachine::HttpRequest.new(nginx_address + '/channels-stats').get(:head => {'accept' => 'application/xml'}))
multi.add(:f, EventMachine::HttpRequest.new(nginx_address + '/channels-stats').get(:head => {'accept' => 'text/x-json'}))
multi.add(:g, EventMachine::HttpRequest.new(nginx_address + '/channels-stats').get(:head => {'accept' => 'text/x-yaml'}))
multi.callback {
assert_equal(7, multi.responses[:callback].length)
assert_equal(200, multi.responses[:callback][:a].response_header.status, "Statistics does accept GET")
assert_equal("GET", multi.responses[:callback][:a].req.method, "Array is with wrong order")
assert_equal("application/json", multi.responses[:callback][:a].response_header["CONTENT_TYPE"], "wrong content-type")
assert_equal(200, multi.responses[:callback][:b].response_header.status, "Statistics does accept GET")
assert_equal("GET", multi.responses[:callback][:b].req.method, "Array is with wrong order")
assert_equal("text/plain", multi.responses[:callback][:b].response_header["CONTENT_TYPE"], "wrong content-type")
assert_equal(200, multi.responses[:callback][:c].response_header.status, "Statistics does accept GET")
assert_equal("GET", multi.responses[:callback][:c].req.method, "Array is with wrong order")
assert_equal("application/json", multi.responses[:callback][:c].response_header["CONTENT_TYPE"], "wrong content-type")
assert_equal(200, multi.responses[:callback][:d].response_header.status, "Statistics does accept GET")
assert_equal("GET", multi.responses[:callback][:d].req.method, "Array is with wrong order")
assert_equal("application/yaml", multi.responses[:callback][:d].response_header["CONTENT_TYPE"], "wrong content-type")
assert_equal(200, multi.responses[:callback][:e].response_header.status, "Statistics does accept GET")
assert_equal("GET", multi.responses[:callback][:e].req.method, "Array is with wrong order")
assert_equal("application/xml", multi.responses[:callback][:e].response_header["CONTENT_TYPE"], "wrong content-type")
assert_equal(200, multi.responses[:callback][:f].response_header.status, "Statistics does accept GET")
assert_equal("GET", multi.responses[:callback][:f].req.method, "Array is with wrong order")
assert_equal("text/x-json", multi.responses[:callback][:f].response_header["CONTENT_TYPE"], "wrong content-type")
assert_equal(200, multi.responses[:callback][:g].response_header.status, "Statistics does accept GET")
assert_equal("GET", multi.responses[:callback][:g].req.method, "Array is with wrong order")
assert_equal("text/x-yaml", multi.responses[:callback][:g].response_header["CONTENT_TYPE"], "wrong content-type")
EventMachine.stop
}
}
end
def config_test_get_detailed_channels_statistics_to_many_channels
@max_reserved_memory = '200m'
@keepalive = "on"
end
def test_get_detailed_channels_statistics_to_many_channels
headers = {'accept' => 'application/json'}
channel = 'ch_test_get_detailed_channels_statistics_to_many_channels_'
body = 'body'
number_of_channels = 20000
#create channels
0.step(number_of_channels - 1, 10) do |i|
socket = open_socket
1.upto(10) do |j|
channel_name = "#{channel}#{i + j}"
headers, body = publish_message_in_socket(channel_name, body, socket)
fail("Don't create the channel") unless headers.include?("HTTP/1.1 200 OK")
end
socket.close
end
EventMachine.run {
pub_2 = EventMachine::HttpRequest.new(nginx_address + '/channels-stats?id=ALL').get :head => headers, :timeout => 30
pub_2.callback {
assert_equal(200, pub_2.response_header.status, "Request was not accepted")
assert_not_equal(0, pub_2.response_header.content_length, "Empty response was received")
response = JSON.parse(pub_2.response)
assert_equal(number_of_channels, response["infos"].length, "Didn't received info about the created channels")
EventMachine.stop
}
}
end
def test_get_detailed_channels_statistics_whithout_created_channels_using_prefix
headers = {'accept' => 'application/json'}
EventMachine.run {
pub_2 = EventMachine::HttpRequest.new(nginx_address + '/channels-stats?id=prefix_*').get :head => headers, :timeout => 30
pub_2.callback {
assert_equal(200, pub_2.response_header.status, "Request was not accepted")
assert_not_equal(0, pub_2.response_header.content_length, "Empty response was received")
response = JSON.parse(pub_2.response)
assert_equal(0, response["infos"].length, "Received info whithout_created_channels")
EventMachine.stop
}
}
end
def test_get_detailed_channels_statistics_to_existing_channel_using_prefix
headers = {'accept' => 'application/json'}
channel = 'ch_test_get_detailed_channels_statistics_to_existing_channel_using_prefix'
channel_1 = 'another_ch_test_get_detailed_channels_statistics_to_existing_channel_using_prefix'
body = 'body'
#create channels
publish_message(channel, headers, body)
publish_message(channel_1, headers, body)
EventMachine.run {
pub_2 = EventMachine::HttpRequest.new(nginx_address + '/channels-stats?id=ch_test_*').get :head => headers, :timeout => 30
pub_2.callback {
assert_equal(200, pub_2.response_header.status, "Request was not accepted")
assert_not_equal(0, pub_2.response_header.content_length, "Empty response was received")
response = JSON.parse(pub_2.response)
assert_equal(1, response["infos"].length, "Didn't received info about the only created channel")
assert_equal(channel, response["infos"][0]["channel"].to_s, "Channel was not recognized")
assert_equal(1, response["infos"][0]["published_messages"].to_i, "Message was not published")
assert_equal(1, response["infos"][0]["stored_messages"].to_i, "Message was not stored")
assert_equal(0, response["infos"][0]["subscribers"].to_i, "Wrong number for subscribers")
EventMachine.stop
}
}
end
def test_get_detailed_channels_statistics_using_prefix_as_same_behavior_ALL
headers = {'accept' => 'application/json'}
channel = 'ch_test_get_detailed_channels_statistics_using_prefix_as_same_behavior_ALL'
channel_1 = 'another_ch_test_get_detailed_channels_statistics_using_prefix_as_same_behavior_ALL'
body = 'body'
#create channels
publish_message(channel, headers, body)
publish_message(channel_1, headers, body)
EventMachine.run {
pub_2 = EventMachine::HttpRequest.new(nginx_address + '/channels-stats?id=*').get :head => headers, :timeout => 30
pub_2.callback {
assert_equal(200, pub_2.response_header.status, "Request was not accepted")
assert_not_equal(0, pub_2.response_header.content_length, "Empty response was received")
response = JSON.parse(pub_2.response)
assert_equal(2, response["infos"].length, "Didn't received info about the only created channel")
assert_equal(channel, response["infos"][0]["channel"].to_s, "Channel was not recognized")
assert_equal(1, response["infos"][0]["published_messages"].to_i, "Message was not published")
assert_equal(1, response["infos"][0]["stored_messages"].to_i, "Message was not stored")
assert_equal(0, response["infos"][0]["subscribers"].to_i, "Wrong number for subscribers")
assert_equal(channel_1, response["infos"][1]["channel"].to_s, "Channel was not recognized")
assert_equal(1, response["infos"][1]["published_messages"].to_i, "Message was not published")
assert_equal(1, response["infos"][1]["stored_messages"].to_i, "Message was not stored")
assert_equal(0, response["infos"][1]["subscribers"].to_i, "Wrong number for subscribers")
EventMachine.stop
}
}
end
def config_test_get_detailed_channels_statistics_to_existing_broadcast_channel_using_prefix
@broadcast_channel_prefix = 'bd_'
@broadcast_channel_max_qtd = 1
end
def test_get_detailed_channels_statistics_to_existing_broadcast_channel_using_prefix
headers = {'accept' => 'application/json'}
channel = 'bd_test_get_detailed_channels_statistics_to_existing_broadcast_channel_using_prefix'
body = 'body'
#create channel
publish_message(channel, headers, body)
EventMachine.run {
pub_2 = EventMachine::HttpRequest.new(nginx_address + '/channels-stats?id=bd_test_*').get :head => headers, :timeout => 30
pub_2.callback {
assert_equal(200, pub_2.response_header.status, "Request was not accepted")
assert_not_equal(0, pub_2.response_header.content_length, "Empty response was received")
response = JSON.parse(pub_2.response)
assert_equal(1, response["infos"].length, "Didn't received info about the only created channel")
assert_equal(0, response["channels"].to_i, "Channel was not recognized")
assert_equal(1, response["broadcast_channels"].to_i, "Channel was not recognized")
assert_equal(channel, response["infos"][0]["channel"].to_s, "Channel was not recognized")
assert_equal(1, response["infos"][0]["published_messages"].to_i, "Message was not published")
assert_equal(1, response["infos"][0]["stored_messages"].to_i, "Message was not stored")
assert_equal(0, response["infos"][0]["subscribers"].to_i, "Wrong number for subscribers")
EventMachine.stop
}
}
end
def test_detailed_channels_statistics_to_existing_channel_with_subscriber_using_prefix
headers = {'accept' => 'application/json'}
channel = 'ch_test_detailed_channels_statistics_to_existing_channel_with_subscriber_using_prefix'
body = 'body'
create_channel_by_subscribe(channel, headers) do
pub_1 = EventMachine::HttpRequest.new(nginx_address + '/channels-stats?id=ch_test_*').get :head => headers, :timeout => 30
pub_1.callback {
assert_equal(200, pub_1.response_header.status, "Request was not accepted")
assert_not_equal(0, pub_1.response_header.content_length, "Empty response was received")
response = JSON.parse(pub_1.response)
assert_equal(1, response["infos"].length, "Didn't received info about the only created channel")
assert_equal(channel, response["infos"][0]["channel"].to_s, "Channel was not recognized")
assert_equal(0, response["infos"][0]["published_messages"].to_i, "Wrong number for published messages")
assert_equal(0, response["infos"][0]["stored_messages"].to_i, "Wrong number for stored messages")
assert_equal(1, response["infos"][0]["subscribers"].to_i, "Wrong number for subscribers")
EventMachine.stop
}
end
end
def config_test_get_detailed_channels_statistics_to_many_channels_using_prefix
@max_reserved_memory = '200m'
@keepalive = "on"
end
def test_get_detailed_channels_statistics_to_many_channels_using_prefix
headers = {'accept' => 'application/json'}
channel = 'ch_test_get_detailed_channels_statistics_to_many_channels_using_prefix_'
body = 'body'
number_of_channels = 20000
#create channels
0.step(number_of_channels - 1, 10) do |i|
socket = open_socket
1.upto(10) do |j|
channel_name = "#{channel}#{i + j}"
headers, body = publish_message_in_socket(channel_name, body, socket)
fail("Don't create the channel") unless headers.include?("HTTP/1.1 200 OK")
end
socket.close
end
EventMachine.run {
pub_2 = EventMachine::HttpRequest.new(nginx_address + '/channels-stats?id=ch_test_get_detailed_channels_statistics_to_many_channels_using_prefix_10*').get :head => headers, :timeout => 30
pub_2.callback {
assert_equal(200, pub_2.response_header.status, "Request was not accepted")
assert_not_equal(0, pub_2.response_header.content_length, "Empty response was received")
response = JSON.parse(pub_2.response)
assert_equal(1111, response["infos"].length, "Didn't received info about the created channels")
EventMachine.stop
}
}
end
def test_get_uptime_in_detailed_channels_statistics
headers = {'accept' => 'application/json'}
channel = 'ch_test_get_uptime_in_detailed_channels_statistics'
body = 'body'
#create channel
publish_message(channel, headers, body)
EventMachine.run {
pub_2 = EventMachine::HttpRequest.new(nginx_address + '/channels-stats?id=ALL').get :head => headers, :timeout => 30
pub_2.callback {
assert_equal(200, pub_2.response_header.status, "Request was not accepted")
assert_not_equal(0, pub_2.response_header.content_length, "Empty response was received")
response = JSON.parse(pub_2.response)
assert(response.has_key?("hostname") && !response["hostname"].empty?, "Hasn't a key hostname")
assert(response.has_key?("time") && !response["time"].empty?, "Hasn't a key time")
assert(response.has_key?("channels") && !response["channels"].empty?, "Hasn't a key channels")
assert(response.has_key?("broadcast_channels") && !response["broadcast_channels"].empty?, "Hasn't a key broadcast_channels")
assert(response.has_key?("uptime") && !response["uptime"].empty?, "Hasn't a key uptime")
assert(response.has_key?("infos") && !response["infos"].empty?, "Hasn't a key infos")
sleep(2)
pub_3 = EventMachine::HttpRequest.new(nginx_address + '/channels-stats?id=ALL').get :head => headers, :timeout => 30
pub_3.callback {
assert_equal(200, pub_3.response_header.status, "Request was not accepted")
assert_not_equal(0, pub_3.response_header.content_length, "Empty response was received")
response = JSON.parse(pub_3.response)
assert(response["uptime"].to_i >= 2, "Don't get server uptime")
EventMachine.stop
}
}
}
end
def test_get_uptime_in_summarized_channels_statistics
headers = {'accept' => 'application/json'}
channel = 'ch_test_get_uptime_in_summarized_channels_statistics'
body = 'body'
#create channel
publish_message(channel, headers, body)
EventMachine.run {
pub_2 = EventMachine::HttpRequest.new(nginx_address + '/channels-stats').get :head => headers, :timeout => 30
pub_2.callback {
assert_equal(200, pub_2.response_header.status, "Request was not accepted")
assert_not_equal(0, pub_2.response_header.content_length, "Empty response was received")
response = JSON.parse(pub_2.response)
assert(response.has_key?("hostname") && !response["hostname"].empty?, "Hasn't a key hostname")
assert(response.has_key?("time") && !response["time"].empty?, "Hasn't a key time")
assert(response.has_key?("channels") && !response["channels"].empty?, "Hasn't a key channels")
assert(response.has_key?("broadcast_channels") && !response["broadcast_channels"].empty?, "Hasn't a key broadcast_channels")
assert(response.has_key?("published_messages") && !response["published_messages"].empty?, "Hasn't a key published_messages")
assert(response.has_key?("subscribers") && !response["subscribers"].empty?, "Hasn't a key subscribers")
assert(response.has_key?("uptime") && !response["uptime"].empty?, "Hasn't a key uptime")
assert(response.has_key?("by_worker") && !response["by_worker"].empty?, "Hasn't a key by_worker")
assert(response["by_worker"][0].has_key?("pid") && !response["by_worker"][0]["pid"].empty?, "Hasn't a key pid on worker info")
assert(response["by_worker"][0].has_key?("subscribers") && !response["by_worker"][0]["subscribers"].empty?, "Hasn't a key subscribers on worker info")
assert(response["by_worker"][0].has_key?("uptime") && !response["by_worker"][0]["uptime"].empty?, "Hasn't a key uptime on worker info")
sleep(2)
pub_3 = EventMachine::HttpRequest.new(nginx_address + '/channels-stats').get :head => headers, :timeout => 30
pub_3.callback {
assert_equal(200, pub_3.response_header.status, "Request was not accepted")
assert_not_equal(0, pub_3.response_header.content_length, "Empty response was received")
response = JSON.parse(pub_3.response)
assert(response["uptime"].to_i >= 2, "Don't get server uptime")
assert(response["by_worker"][0]["uptime"].to_i >= 2, "Don't get worker uptime")
EventMachine.stop
}
}
}
end
end
require File.expand_path('base_test_case', File.dirname(__FILE__))
class TestCleanupMemory < Test::Unit::TestCase
include BaseTestCase
def global_configuration
ENV['NGINX_WORKERS'] = '1'
@disable_ignore_childs = true
@master_process = 'on'
@daemon = 'on'
end
def config_test_channel_cleanup_after_delete
@memory_cleanup_timeout = '30s'
@max_reserved_memory = "129k"
@min_message_buffer_timeout = '10s'
@max_message_buffer_length = nil
@publisher_mode = 'admin'
end
def test_channel_cleanup_after_delete
channel = 'ch_test_channel_cleanup'
headers = {'accept' => 'text/html'}
body = 'message to create a channel'
published_messages_setp_1 = 0
EventMachine.run do
i = 0
fill_memory_timer = EventMachine::PeriodicTimer.new(0.001) do
pub_1 = EventMachine::HttpRequest.new(nginx_address + '/pub?id=' + channel.to_s + i.to_s).post :body => body, :head => headers, :timeout => 30
pub_1.callback do
if pub_1.response_header.status == 500
fill_memory_timer.cancel
i.times do |j|
pub = EventMachine::HttpRequest.new(nginx_address + '/pub?id=' + channel.to_s + j.to_s).delete :head => headers, :timeout => 30
end
pub_2 = EventMachine::HttpRequest.new(nginx_address + '/channels-stats').get :head => headers, :timeout => 60
pub_2.callback do
fail("Don't received the stats") if (pub_2.response_header.status != 200) || (pub_2.response_header.content_length == 0)
result = JSON.parse(pub_2.response)
published_messages_setp_1 = result["published_messages"].to_i
fail("Don't create any message") if published_messages_setp_1 == 0
EM.add_timer(35) do
i = 0
fill_memory_timer = EventMachine::PeriodicTimer.new(0.001) do
pub_1 = EventMachine::HttpRequest.new(nginx_address + '/pub?id=' + channel.to_s + i.to_s).post :body => body, :head => headers, :timeout => 30
pub_1.callback do
if pub_1.response_header.status == 500
fill_memory_timer.cancel
pub_2 = EventMachine::HttpRequest.new(nginx_address + '/channels-stats').get :head => headers, :timeout => 60
pub_2.callback do
fail("Don't received the stats") if (pub_2.response_header.status != 200) || (pub_2.response_header.content_length == 0)
result = JSON.parse(pub_2.response)
assert_equal(published_messages_setp_1, result["published_messages"].to_i / 2, "Don't cleaned all memory")
EventMachine.stop
end
end
end
i += 1
end
end
end
end
end
i += 1
end
add_test_timeout(45)
end
end
def create_and_delete_channel(channel, body, headers, &block)
pub_1 = EventMachine::HttpRequest.new(nginx_address + '/pub?id=' + channel.to_s).post :body => body, :head => headers, :timeout => 30
pub_1.callback do
if pub_1.response_header.status == 200
pub = EventMachine::HttpRequest.new(nginx_address + '/pub?id=' + channel.to_s).delete :head => headers, :timeout => 30
pub.callback do
block.call((pub.response_header.status == 200) ? :success : :error)
end
else
block.call(:error)
end
end
end
def create_and_delete_channel_in_loop(channel, body, headers, &block)
create_and_delete_channel(channel, body, headers) do |status|
if status == :success
create_and_delete_channel_in_loop(channel, body, headers) do
yield
end
else
block.call unless block.nil?
end
end
end
def config_test_channel_cleanup_after_delete_same_id
@memory_cleanup_timeout = '30s'
@max_reserved_memory = "129k"
@min_message_buffer_timeout = '10s'
@max_message_buffer_length = nil
@publisher_mode = 'admin'
end
def test_channel_cleanup_after_delete_same_id
channel = 'ch_test_channel_cleanup'
headers = {'accept' => 'text/html'}
body = 'message to create a channel'
published_messages_setp_1 = 0
EventMachine.run do
create_and_delete_channel_in_loop(channel, body, headers) do
pub_2 = EventMachine::HttpRequest.new(nginx_address + '/channels-stats').get :head => headers, :timeout => 60
pub_2.callback do
fail("Don't received the stats") if (pub_2.response_header.status != 200) || (pub_2.response_header.content_length == 0)
result = JSON.parse(pub_2.response)
published_messages_setp_1 = result["published_messages"].to_i
fail("Don't create any message") if published_messages_setp_1 == 0
EM.add_timer(40) do
create_and_delete_channel_in_loop(channel, body, headers) do
pub_2 = EventMachine::HttpRequest.new(nginx_address + '/channels-stats').get :head => headers, :timeout => 60
pub_2.callback do
fail("Don't received the stats") if (pub_2.response_header.status != 200) || (pub_2.response_header.content_length == 0)
result = JSON.parse(pub_2.response)
assert_equal(published_messages_setp_1, result["published_messages"].to_i / 2, "Don't cleaned all memory")
EventMachine.stop
end
end
end
end
end
add_test_timeout(50)
end
end
def config_test_message_cleanup
@memory_cleanup_timeout = '30s'
@max_reserved_memory = "129k"
@min_message_buffer_timeout = '10s'
@max_message_buffer_length = 100
end
def test_message_cleanup
channel = 'ch_test_message_cleanup'
headers = {'accept' => 'text/html'}
body = 'message to create a channel'
stored_messages_setp_1 = 0
published_messages_setp_1 = 0
EventMachine.run do
# ensure channel will not be cleaned up
sub_1 = EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel.to_s).get :head => headers, :timeout => 60
fill_memory_timer = EventMachine::PeriodicTimer.new(0.001) do
publish_message_inline_with_callbacks(channel, headers, body, {
:error => Proc.new do |status, content|
fill_memory_timer.cancel
pub_2 = EventMachine::HttpRequest.new(nginx_address + '/channels-stats?id=' + channel.to_s).get :head => headers, :timeout => 60
pub_2.callback do
fail("Don't received the stats") if (pub_2.response_header.status != 200) || (pub_2.response_header.content_length == 0)
result = JSON.parse(pub_2.response)
stored_messages_setp_1 = result["stored_messages"].to_i
published_messages_setp_1 = result["published_messages"].to_i
assert_equal(@max_message_buffer_length, stored_messages_setp_1, "Don't limit stored messages")
fail("Don't reached the limit of stored messages") if result["published_messages"].to_i <= @max_message_buffer_length
fail("Don't create any message") if stored_messages_setp_1 == 0
EM.add_timer(45) do
pub_3 = EventMachine::HttpRequest.new(nginx_address + '/channels-stats?id=' + channel.to_s).get :head => headers, :timeout => 60
pub_3.callback do
fail("Don't received the stats") if (pub_3.response_header.status != 200) || (pub_3.response_header.content_length == 0)
assert_equal(0, JSON.parse(pub_3.response)["stored_messages"].to_i, "Don't cleaned all messages")
fill_memory_timer = EventMachine::PeriodicTimer.new(0.001) do
publish_message_inline_with_callbacks(channel, headers, body, {
:error => Proc.new do |status2, content2|
pub_4 = EventMachine::HttpRequest.new(nginx_address + '/channels-stats?id=' + channel.to_s).get :head => headers, :timeout => 60
pub_4.callback do
fail("Don't received the stats") if (pub_4.response_header.status != 200) || (pub_4.response_header.content_length == 0)
result = JSON.parse(pub_4.response)
assert_equal(stored_messages_setp_1, result["stored_messages"].to_i, "Don't cleaned all messages")
assert_equal(published_messages_setp_1, result["published_messages"].to_i / 2, "Don't cleaned all memory")
EventMachine.stop
end
end
})
end
end
end
end
end
})
end
add_test_timeout(55)
end
end
def config_test_discard_old_messages
@memory_cleanup_timeout = '30s'
@max_reserved_memory = "129k"
@min_message_buffer_timeout = '10s'
@max_message_buffer_length = nil
end
def test_discard_old_messages
channel = 'ch_test_discard_old_messages'
headers = {'accept' => 'text/html'}
body = 'message to create a channel'
messages_to_publish = 10
count = 0
stored_messages_setp_1 = 0
EventMachine.run do
fill_memory_timer = EventMachine::PeriodicTimer.new(messages_to_publish / 12.to_f) do # publish messages before cleanup timer be executed
if (count < messages_to_publish)
publish_message_inline(channel, headers, body)
elsif (count == messages_to_publish)
pub_1 = EventMachine::HttpRequest.new(nginx_address + '/channels-stats?id=' + channel.to_s).get :head => headers, :timeout => 60
pub_1.callback do
fill_memory_timer.cancel
fail("Don't received the stats") if (pub_1.response_header.status != 200) || (pub_1.response_header.content_length == 0)
stored_messages_setp_1 = JSON.parse(pub_1.response)["stored_messages"].to_i
assert_equal(messages_to_publish, stored_messages_setp_1, "Don't store messages")
EM.add_timer(5) do # wait cleanup timer to be executed one time
pub_2 = EventMachine::HttpRequest.new(nginx_address + '/channels-stats?id=' + channel.to_s).get :head => headers, :timeout => 60
pub_2.callback do
fail("Don't received the stats") if (pub_2.response_header.status != 200) || (pub_2.response_header.content_length == 0)
stored_messages_setp_2 = JSON.parse(pub_2.response)["stored_messages"].to_i
assert(stored_messages_setp_1 > stored_messages_setp_2, "Don't clear messages")
assert(stored_messages_setp_2 > 0, "Cleared all messages")
EventMachine.stop
end
end
end
end
count += 1
end
add_test_timeout(20)
end
end
def config_test_message_cleanup_without_max_messages_stored_per_channel
@memory_cleanup_timeout = '30s'
@max_reserved_memory = "129k"
@min_message_buffer_timeout = '10s'
@max_message_buffer_length = nil
end
def test_message_cleanup_without_max_messages_stored_per_channel
channel = 'ch_test_message_cleanup_without_max_messages_stored_per_chann'
headers = {'accept' => 'text/html'}
body = 'message to create a channel'
stored_messages_setp_1 = 0
published_messages_setp_1 = 0
EventMachine.run do
# ensure channel will not be cleaned up
sub_1 = EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel.to_s).get :head => headers, :timeout => 60
fill_memory_timer = EventMachine::PeriodicTimer.new(0.001) do
publish_message_inline_with_callbacks(channel, headers, body, {
:error => Proc.new do |status, content|
fill_memory_timer.cancel
pub_2 = EventMachine::HttpRequest.new(nginx_address + '/channels-stats?id=' + channel.to_s).get :head => headers, :timeout => 60
pub_2.callback do
fail("Don't received the stats") if (pub_2.response_header.status != 200) || (pub_2.response_header.content_length == 0)
result = JSON.parse(pub_2.response)
stored_messages_setp_1 = result["stored_messages"].to_i
published_messages_setp_1 = result["published_messages"].to_i
fail("Limited the number of stored messages") if stored_messages_setp_1 <= 100
fail("Don't create any message") if stored_messages_setp_1 == 0
EM.add_timer(45) do
pub_3 = EventMachine::HttpRequest.new(nginx_address + '/channels-stats?id=' + channel.to_s).get :head => headers, :timeout => 60
pub_3.callback do
fail("Don't received the stats") if (pub_3.response_header.status != 200) || (pub_3.response_header.content_length == 0)
assert_equal(0, JSON.parse(pub_3.response)["stored_messages"].to_i, "Don't cleaned all messages")
fill_memory_timer = EventMachine::PeriodicTimer.new(0.001) do
publish_message_inline_with_callbacks(channel, headers, body, {
:error => Proc.new do |status2, content2|
pub_4 = EventMachine::HttpRequest.new(nginx_address + '/channels-stats?id=' + channel.to_s).get :head => headers, :timeout => 60
pub_4.callback do
fail("Don't received the stats") if (pub_4.response_header.status != 200) || (pub_4.response_header.content_length == 0)
result = JSON.parse(pub_4.response)
assert_equal(stored_messages_setp_1, result["stored_messages"].to_i, "Don't cleaned all messages")
assert_equal(published_messages_setp_1, result["published_messages"].to_i / 2, "Don't cleaned all memory")
EventMachine.stop
end
end
})
end
end
end
end
end
})
end
add_test_timeout(55)
end
end
def config_test_channel_cleanup
@memory_cleanup_timeout = '30s'
@max_reserved_memory = "129k"
@min_message_buffer_timeout = '2s'
@max_message_buffer_length = nil
end
def test_channel_cleanup
channel = 'ch_test_channel_cleanup_'
headers = {'accept' => 'text/html'}
body = 'message to create a channel'
channels_setp_1 = 0
channels_setp_2 = 0
EventMachine.run do
i = 0
fill_memory_timer = EventMachine::PeriodicTimer.new(0.001) do
publish_message_inline_with_callbacks(channel + i.to_s, headers, body, {
:error => Proc.new do |status, content|
fill_memory_timer.cancel
pub_2 = EventMachine::HttpRequest.new(nginx_address + '/channels-stats').get :head => headers, :timeout => 60
pub_2.callback do
fail("Don't received the stats") if (pub_2.response_header.status != 200) || (pub_2.response_header.content_length == 0)
channels_setp_1 = JSON.parse(pub_2.response)["channels"].to_i
fail("Don't create any channel") if channels_setp_1 == 0
EM.add_timer(40) do
pub_3 = EventMachine::HttpRequest.new(nginx_address + '/channels-stats').get :head => headers, :timeout => 60
pub_3.callback do
fail("Don't received the stats") if (pub_3.response_header.status != 200) || (pub_3.response_header.content_length == 0)
channels = JSON.parse(pub_3.response)["channels"].to_i
assert_equal(0, channels, "Don't removed all channels")
EventMachine.stop unless (channels == 0)
EM.add_timer(35) do
i = 0
fill_memory_timer = EventMachine::PeriodicTimer.new(0.001) do
publish_message_inline_with_callbacks(channel + i.to_s, headers, body, {
:error => Proc.new do |status2, content2|
fill_memory_timer.cancel
pub_4 = EventMachine::HttpRequest.new(nginx_address + '/channels-stats').get :head => headers, :timeout => 60
pub_4.callback do
fail("Don't received the stats") if (pub_4.response_header.status != 200) || (pub_4.response_header.content_length == 0)
channels_setp_2 = JSON.parse(pub_4.response)["channels"].to_i
assert_equal(channels_setp_1, channels_setp_2, "Don't released all memory")
EventMachine.stop
end
end
})
i += 1
end
end
end
end
end
end
})
i += 1
end
add_test_timeout(85)
end
end
def config_test_message_cleanup_with_store_off_with_subscriber
@store_messages = 'off'
@memory_cleanup_timeout = '30s'
@max_reserved_memory = "129k"
@min_message_buffer_timeout = nil
@max_message_buffer_length = nil
end
def test_message_cleanup_with_store_off_with_subscriber
channel = 'ch_test_message_cleanup_with_store_off_with_subscriber'
headers = {'accept' => 'text/html'}
body = 'message to create a channel'
published_messages_setp_1 = 0
EventMachine.run do
# ensure channel will not be cleaned up
sub_1 = EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel.to_s).get :head => headers, :timeout => 60
fill_memory_timer = EventMachine::PeriodicTimer.new(0.001) do
publish_message_inline_with_callbacks(channel, headers, body, {
:error => Proc.new do |status, content|
fill_memory_timer.cancel
pub_2 = EventMachine::HttpRequest.new(nginx_address + '/channels-stats?id=' + channel.to_s).get :head => headers, :timeout => 60
pub_2.callback do
fail("Don't received the stats") if (pub_2.response_header.status != 200) || (pub_2.response_header.content_length == 0)
result = JSON.parse(pub_2.response)
published_messages_setp_1 = result["published_messages"].to_i
EM.add_timer(40) do
pub_3 = EventMachine::HttpRequest.new(nginx_address + '/channels-stats?id=' + channel.to_s).get :head => headers, :timeout => 60
pub_3.callback do
fail("Don't received the stats") if (pub_3.response_header.status != 200) || (pub_3.response_header.content_length == 0)
assert_equal(0, JSON.parse(pub_3.response)["channels"].to_i, "Don't cleaned all messages/channels")
fill_memory_timer = EventMachine::PeriodicTimer.new(0.001) do
publish_message_inline_with_callbacks(channel, headers, body, {
:error => Proc.new do |status2, content2|
pub_4 = EventMachine::HttpRequest.new(nginx_address + '/channels-stats?id=' + channel.to_s).get :head => headers, :timeout => 60
pub_4.callback do
fail("Don't received the stats") if (pub_4.response_header.status != 200) || (pub_4.response_header.content_length == 0)
result = JSON.parse(pub_4.response)
assert_equal(published_messages_setp_1, result["published_messages"].to_i / 2, "Don't cleaned all memory")
EventMachine.stop
end
end
})
end
end
end
end
end
})
end
add_test_timeout(45)
end
end
def config_test_message_cleanup_with_store_off_without_subscriber
@store_messages = 'off'
@memory_cleanup_timeout = '30s'
@max_reserved_memory = "129k"
@min_message_buffer_timeout = nil
@max_message_buffer_length = nil
end
def test_message_cleanup_with_store_off_without_subscriber
channel = 'ch_test_message_cleanup_with_store_off_without_subscriber'
headers = {'accept' => 'text/html'}
body = 'message to create a channel'
published_messages_setp_1 = 0
EventMachine.run do
i = 0
fill_memory_timer = EventMachine::PeriodicTimer.new(0.001) do
publish_message_inline_with_callbacks(channel + i.to_s, headers, body, {
:error => Proc.new do |status, content|
fill_memory_timer.cancel
pub_2 = EventMachine::HttpRequest.new(nginx_address + '/channels-stats').get :head => headers, :timeout => 60
pub_2.callback do
fail("Don't received the stats") if (pub_2.response_header.status != 200) || (pub_2.response_header.content_length == 0)
result = JSON.parse(pub_2.response)
published_messages_setp_1 = result["published_messages"].to_i
EM.add_timer(35) do
pub_3 = EventMachine::HttpRequest.new(nginx_address + '/channels-stats').get :head => headers, :timeout => 60
pub_3.callback do
fail("Don't received the stats") if (pub_3.response_header.status != 200) || (pub_3.response_header.content_length == 0)
assert_equal(0, JSON.parse(pub_3.response)["channels"].to_i, "Don't cleaned all messages/channels")
EM.add_timer(35) do
fill_memory_timer = EventMachine::PeriodicTimer.new(0.001) do
publish_message_inline_with_callbacks(channel + i.to_s, headers, body, {
:error => Proc.new do |status2, content2|
pub_4 = EventMachine::HttpRequest.new(nginx_address + '/channels-stats').get :head => headers, :timeout => 60
pub_4.callback do
fail("Don't received the stats") if (pub_4.response_header.status != 200) || (pub_4.response_header.content_length == 0)
result = JSON.parse(pub_4.response)
assert_equal(published_messages_setp_1, result["published_messages"].to_i / 2, "Don't cleaned all memory")
EventMachine.stop
end
end
})
i += 1
end
end
end
end
end
end
})
i += 1
end
add_test_timeout(85)
end
end
end
require File.expand_path('base_test_case', File.dirname(__FILE__))
class TestCleanupMemoryAfterKill < Test::Unit::TestCase
include BaseTestCase
@@timeout = 130
def global_configuration
ENV['NGINX_WORKERS'] = '1'
@disable_ignore_childs = true
@master_process = 'on'
@daemon = 'on'
end
def kill_worker(&block)
pub = EventMachine::HttpRequest.new(nginx_address + '/channels-stats').get :timeout => 30
pub.callback do
fail("Don't received the stats") if (pub.response_header.status != 200) || (pub.response_header.content_length == 0)
resp_1 = JSON.parse(pub.response)
assert_equal(1, resp_1["by_worker"].count, "Didn't return infos by_worker")
pid = resp_1["by_worker"][0]['pid'].to_i
sleep(1)
# send kill signal
`kill -9 #{ pid } > /dev/null 2>&1`
block.call unless block.nil?
end
end
def config_test_message_cleanup_after_kill
@memory_cleanup_timeout = '30s'
@max_reserved_memory = "129k"
@min_message_buffer_timeout = '10s'
@max_message_buffer_length = 100
end
def test_message_cleanup_after_kill
channel = 'ch_test_message_cleanup_after_kill'
headers = {'accept' => 'text/html'}
body = 'message to create a channel'
stored_messages_setp_1 = 0
published_messages_setp_1 = 0
published_messages_setp_2 = 0
EventMachine.run do
# ensure channel will not be cleaned up
sub_1 = EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel.to_s).get :head => headers, :timeout => 60
fill_memory_timer = EventMachine::PeriodicTimer.new(0.001) do
publish_message_inline_with_callbacks(channel, headers, body, {
:error => Proc.new do |status, content|
fill_memory_timer.cancel
pub_2 = EventMachine::HttpRequest.new(nginx_address + '/channels-stats?id=' + channel.to_s).get :head => headers, :timeout => 60
pub_2.callback do
fail("Don't received the stats") if (pub_2.response_header.status != 200) || (pub_2.response_header.content_length == 0)
result = JSON.parse(pub_2.response)
stored_messages_setp_1 = result["stored_messages"].to_i
published_messages_setp_1 = result["published_messages"].to_i
assert_equal(@max_message_buffer_length, stored_messages_setp_1, "Don't limit stored messages")
fail("Don't reached the limit of stored messages") if result["published_messages"].to_i <= @max_message_buffer_length
fail("Don't create any message") if stored_messages_setp_1 == 0
kill_worker do
sleep(1)
# connect a subscriber on new worker
sub_1 = EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel.to_s).get :head => headers, :timeout => 60
EM.add_timer(35) do
fill_memory_timer = EventMachine::PeriodicTimer.new(0.001) do
publish_message_inline_with_callbacks(channel, headers, body, {
:error => Proc.new do |status2, content2|
fill_memory_timer.cancel
pub_2 = EventMachine::HttpRequest.new(nginx_address + '/channels-stats?id=' + channel.to_s).get :head => headers, :timeout => 60
pub_2.callback do
fail("Don't received the stats") if (pub_2.response_header.status != 200) || (pub_2.response_header.content_length == 0)
published_messages_setp_2 = JSON.parse(pub_2.response)["published_messages"].to_i
fail("Don't publish more messages") if published_messages_setp_1 == published_messages_setp_2
EM.add_timer(50) do
pub_3 = EventMachine::HttpRequest.new(nginx_address + '/channels-stats?id=' + channel.to_s).get :head => headers, :timeout => 60
pub_3.callback do
fail("Don't received the stats") if (pub_3.response_header.status != 200) || (pub_3.response_header.content_length == 0)
assert_equal(0, JSON.parse(pub_3.response)["stored_messages"].to_i, "Don't cleaned all messages")
fill_memory_timer = EventMachine::PeriodicTimer.new(0.001) do
publish_message_inline_with_callbacks(channel, headers, body, {
:error => Proc.new do |status3, content3|
pub_4 = EventMachine::HttpRequest.new(nginx_address + '/channels-stats?id=' + channel.to_s).get :head => headers, :timeout => 60
pub_4.callback do
fail("Don't received the stats") if (pub_4.response_header.status != 200) || (pub_4.response_header.content_length == 0)
result = JSON.parse(pub_4.response)
assert_equal(stored_messages_setp_1, result["stored_messages"].to_i, "Don't cleaned all messages")
assert_equal(published_messages_setp_1, (result["published_messages"].to_i - published_messages_setp_2), "Don't cleaned all memory")
EventMachine.stop
end
end
})
end
end
end
end
end
})
end
end
end
end
end
})
end
add_test_timeout(@@timeout)
end
end
def config_test_discard_old_messages_after_kill
@memory_cleanup_timeout = '30s'
@max_reserved_memory = "129k"
@min_message_buffer_timeout = '10s'
@max_message_buffer_length = nil
end
def test_discard_old_messages_after_kill
channel = 'ch_test_discard_old_messages_after_kill'
headers = {'accept' => 'text/html'}
body = 'message to create a channel'
messages_to_publish = 10
count = 0
stored_messages_setp_1 = 0
EventMachine.run do
fill_memory_timer = EventMachine::PeriodicTimer.new(messages_to_publish / 12.to_f) do # publish messages before cleanup timer be executed
if (count < messages_to_publish)
publish_message_inline(channel, headers, body)
elsif (count == messages_to_publish)
pub_1 = EventMachine::HttpRequest.new(nginx_address + '/channels-stats?id=' + channel.to_s).get :head => headers, :timeout => 60
pub_1.callback do
fill_memory_timer.cancel
fail("Don't received the stats") if (pub_1.response_header.status != 200) || (pub_1.response_header.content_length == 0)
stored_messages_setp_1 = JSON.parse(pub_1.response)["stored_messages"].to_i
assert_equal(messages_to_publish, stored_messages_setp_1, "Don't store messages")
kill_worker do
EM.add_timer(5) do # wait cleanup timer to be executed one time
pub_2 = EventMachine::HttpRequest.new(nginx_address + '/channels-stats?id=' + channel.to_s).get :head => headers, :timeout => 60
pub_2.callback do
fail("Don't received the stats") if (pub_2.response_header.status != 200) || (pub_2.response_header.content_length == 0)
stored_messages_setp_2 = JSON.parse(pub_2.response)["stored_messages"].to_i
assert(stored_messages_setp_1 > stored_messages_setp_2, "Don't clear messages")
assert(stored_messages_setp_2 > 0, "Cleared all messages")
EventMachine.stop
end
end
end
end
end
count += 1
end
add_test_timeout(20)
end
end
def config_test_message_cleanup_without_max_messages_stored_per_channel_after_kill
@memory_cleanup_timeout = '30s'
@max_reserved_memory = "129k"
@min_message_buffer_timeout = '10s'
@max_message_buffer_length = nil
end
def test_message_cleanup_without_max_messages_stored_per_channel_after_kill
channel = 'ch_test_message_cleanup_without_max_messages_stored_after_kill'
headers = {'accept' => 'text/html'}
body = 'message to create a channel'
stored_messages_setp_1 = 0
published_messages_setp_1 = 0
published_messages_setp_2 = 0
EventMachine.run do
# ensure channel will not be cleaned up
sub_1 = EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel.to_s).get :head => headers, :timeout => 60
fill_memory_timer = EventMachine::PeriodicTimer.new(0.001) do
publish_message_inline_with_callbacks(channel, headers, body, {
:error => Proc.new do |status, content|
fill_memory_timer.cancel
pub_2 = EventMachine::HttpRequest.new(nginx_address + '/channels-stats?id=' + channel.to_s).get :head => headers, :timeout => 60
pub_2.callback do
fail("Don't received the stats") if (pub_2.response_header.status != 200) || (pub_2.response_header.content_length == 0)
result = JSON.parse(pub_2.response)
stored_messages_setp_1 = result["stored_messages"].to_i
published_messages_setp_1 = result["published_messages"].to_i
fail("Limited the number of stored messages") if stored_messages_setp_1 <= 100
fail("Don't create any message") if stored_messages_setp_1 == 0
kill_worker do
sleep(1)
# connect a subscriber on new worker
sub_1 = EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel.to_s).get :head => headers, :timeout => 60
EM.add_timer(40) do
fill_memory_timer = EventMachine::PeriodicTimer.new(0.001) do
publish_message_inline_with_callbacks(channel, headers, body, {
:error => Proc.new do |status2, content2|
fill_memory_timer.cancel
pub_2 = EventMachine::HttpRequest.new(nginx_address + '/channels-stats?id=' + channel.to_s).get :head => headers, :timeout => 60
pub_2.callback do
fail("Don't received the stats") if (pub_2.response_header.status != 200) || (pub_2.response_header.content_length == 0)
published_messages_setp_2 = JSON.parse(pub_2.response)["published_messages"].to_i
fail("Don't publish more messages") if published_messages_setp_1 == published_messages_setp_2
EM.add_timer(50) do
pub_3 = EventMachine::HttpRequest.new(nginx_address + '/channels-stats?id=' + channel.to_s).get :head => headers, :timeout => 60
pub_3.callback do
fail("Don't received the stats") if (pub_3.response_header.status != 200) || (pub_3.response_header.content_length == 0)
assert_equal(0, JSON.parse(pub_3.response)["stored_messages"].to_i, "Don't cleaned all messages")
fill_memory_timer = EventMachine::PeriodicTimer.new(0.001) do
publish_message_inline_with_callbacks(channel, headers, body, {
:error => Proc.new do |status3, content3|
pub_4 = EventMachine::HttpRequest.new(nginx_address + '/channels-stats?id=' + channel.to_s).get :head => headers, :timeout => 60
pub_4.callback do
fail("Don't received the stats") if (pub_4.response_header.status != 200) || (pub_4.response_header.content_length == 0)
result = JSON.parse(pub_4.response)
assert_equal(stored_messages_setp_1, result["stored_messages"].to_i, "Don't cleaned all messages")
assert_equal(published_messages_setp_1, (result["published_messages"].to_i - published_messages_setp_2), "Don't cleaned all memory")
EventMachine.stop
end
end
})
end
end
end
end
end
})
end
end
end
end
end
})
end
add_test_timeout(@@timeout)
end
end
def config_test_channel_cleanup_after_kill
@memory_cleanup_timeout = '30s'
@max_reserved_memory = "129k"
@min_message_buffer_timeout = '2s'
@max_message_buffer_length = nil
end
def test_channel_cleanup_after_kill
channel = 'ch_test_channel_cleanup_after_kill'
headers = {'accept' => 'text/html'}
body = 'message to create a channel'
channels_setp_1 = 0
channels_setp_2 = 0
published_messages_setp_1 = 0
EventMachine.run do
i = 0
fill_memory_timer = EventMachine::PeriodicTimer.new(0.001) do
publish_message_inline_with_callbacks(channel + i.to_s, headers, body, {
:error => Proc.new do |status, content|
fill_memory_timer.cancel
pub_2 = EventMachine::HttpRequest.new(nginx_address + '/channels-stats').get :head => headers, :timeout => 60
pub_2.callback do
fail("Don't received the stats") if (pub_2.response_header.status != 200) || (pub_2.response_header.content_length == 0)
result = JSON.parse(pub_2.response)
channels_setp_1 = result["channels"].to_i
published_messages_setp_1 = result["published_messages"].to_i
fail("Don't create any channel") if channels_setp_1 == 0
kill_worker do
EM.add_timer(35) do
j = 0
fill_memory_timer = EventMachine::PeriodicTimer.new(0.001) do
publish_message_inline_with_callbacks(channel + j.to_s, headers, body, {
:error => Proc.new do |status2, content2|
fill_memory_timer.cancel
pub_2 = EventMachine::HttpRequest.new(nginx_address + '/channels-stats').get :head => headers, :timeout => 60
pub_2.callback do
fail("Don't received the stats") if (pub_2.response_header.status != 200) || (pub_2.response_header.content_length == 0)
fail("Don't create more channel") if published_messages_setp_1 == JSON.parse(pub_2.response)["published_messages"].to_i
EM.add_timer(40) do
pub_3 = EventMachine::HttpRequest.new(nginx_address + '/channels-stats').get :head => headers, :timeout => 60
pub_3.callback do
fail("Don't received the stats") if (pub_3.response_header.status != 200) || (pub_3.response_header.content_length == 0)
channels = JSON.parse(pub_3.response)["channels"].to_i
assert_equal(0, channels, "Don't removed all channels")
EventMachine.stop unless (channels == 0)
EM.add_timer(35) do
i = 0
fill_memory_timer = EventMachine::PeriodicTimer.new(0.001) do
publish_message_inline_with_callbacks(channel + i.to_s, headers, body, {
:error => Proc.new do |status3, content3|
fill_memory_timer.cancel
pub_4 = EventMachine::HttpRequest.new(nginx_address + '/channels-stats').get :head => headers, :timeout => 60
pub_4.callback do
fail("Don't received the stats") if (pub_4.response_header.status != 200) || (pub_4.response_header.content_length == 0)
channels_setp_2 = JSON.parse(pub_4.response)["channels"].to_i
assert_equal(channels_setp_1, channels_setp_2, "Don't released all memory")
EventMachine.stop
end
end
})
i += 1
end
end
end
end
end
end
})
j += 1
end
end
end
end
end
})
i += 1
end
add_test_timeout(@@timeout)
end
end
def config_test_message_cleanup_with_store_off_with_subscriber_after_kill
@store_messages = 'off'
@memory_cleanup_timeout = '30s'
@max_reserved_memory = "129k"
@min_message_buffer_timeout = nil
@max_message_buffer_length = nil
end
def test_message_cleanup_with_store_off_with_subscriber_after_kill
channel = 'ch_test_message_cleanup_with_store_off_with_subscriber_after_kill'
headers = {'accept' => 'text/html'}
body = 'message to create a channel'
published_messages_setp_1 = 0
published_messages_setp_2 = 0
EventMachine.run do
# ensure channel will not be cleaned up
sub_1 = EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel.to_s).get :head => headers, :timeout => 60
fill_memory_timer = EventMachine::PeriodicTimer.new(0.001) do
publish_message_inline_with_callbacks(channel, headers, body, {
:error => Proc.new do |status, content|
fill_memory_timer.cancel
pub_2 = EventMachine::HttpRequest.new(nginx_address + '/channels-stats?id=' + channel.to_s).get :head => headers, :timeout => 60
pub_2.callback do
fail("Don't received the stats") if (pub_2.response_header.status != 200) || (pub_2.response_header.content_length == 0)
result = JSON.parse(pub_2.response)
published_messages_setp_1 = result["published_messages"].to_i
kill_worker do
sleep(1)
# connect a subscriber on new worker
sub_1 = EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel.to_s).get :head => headers, :timeout => 60
EM.add_timer(35) do
fill_memory_timer = EventMachine::PeriodicTimer.new(0.001) do
publish_message_inline_with_callbacks(channel, headers, body, {
:error => Proc.new do |status2, content2|
fill_memory_timer.cancel
pub_2 = EventMachine::HttpRequest.new(nginx_address + '/channels-stats?id=' + channel.to_s).get :head => headers, :timeout => 60
pub_2.callback do
fail("Don't received the stats") if (pub_2.response_header.status != 200) || (pub_2.response_header.content_length == 0)
published_messages_setp_2 = JSON.parse(pub_2.response)["published_messages"].to_i
fail("Don't publish more messages") if published_messages_setp_1 == published_messages_setp_2
EM.add_timer(35) do
pub_3 = EventMachine::HttpRequest.new(nginx_address + '/channels-stats?id=' + channel.to_s).get :head => headers, :timeout => 60
pub_3.callback do
fail("Don't received the stats") if (pub_3.response_header.status != 200) || (pub_3.response_header.content_length == 0)
assert_equal(0, JSON.parse(pub_3.response)["channels"].to_i, "Don't cleaned all messages/channels")
fill_memory_timer = EventMachine::PeriodicTimer.new(0.001) do
publish_message_inline_with_callbacks(channel, headers, body, {
:error => Proc.new do |status3, content3|
pub_4 = EventMachine::HttpRequest.new(nginx_address + '/channels-stats?id=' + channel.to_s).get :head => headers, :timeout => 60
pub_4.callback do
fail("Don't received the stats") if (pub_4.response_header.status != 200) || (pub_4.response_header.content_length == 0)
result = JSON.parse(pub_4.response)
assert_equal(published_messages_setp_1, (result["published_messages"].to_i - published_messages_setp_2), "Don't cleaned all memory")
EventMachine.stop
end
end
})
end
end
end
end
end
})
end
end
end
end
end
})
end
add_test_timeout(@@timeout)
end
end
def config_test_message_cleanup_with_store_off_without_subscriber_after_kill
@store_messages = 'off'
@memory_cleanup_timeout = '30s'
@max_reserved_memory = "129k"
@min_message_buffer_timeout = nil
@max_message_buffer_length = nil
end
def test_message_cleanup_with_store_off_without_subscriber_after_kill
channel = 'ch_test_message_cleanup_with_store_off_without_subscriber_after_kill'
headers = {'accept' => 'text/html'}
body = 'message to create a channel'
published_messages_setp_1 = 0
published_messages_setp_2 = 0
EventMachine.run do
i = 0
fill_memory_timer = EventMachine::PeriodicTimer.new(0.001) do
publish_message_inline_with_callbacks(channel + i.to_s, headers, body, {
:error => Proc.new do |status, content|
fill_memory_timer.cancel
pub_2 = EventMachine::HttpRequest.new(nginx_address + '/channels-stats').get :head => headers, :timeout => 60
pub_2.callback do
fail("Don't received the stats") if (pub_2.response_header.status != 200) || (pub_2.response_header.content_length == 0)
result = JSON.parse(pub_2.response)
published_messages_setp_1 = result["published_messages"].to_i
kill_worker do
EM.add_timer(35) do
j = 0
fill_memory_timer = EventMachine::PeriodicTimer.new(0.001) do
publish_message_inline_with_callbacks(channel + j.to_s, headers, body, {
:error => Proc.new do |status2, content2|
fill_memory_timer.cancel
pub_2 = EventMachine::HttpRequest.new(nginx_address + '/channels-stats').get :head => headers, :timeout => 60
pub_2.callback do
fail("Don't received the stats") if (pub_2.response_header.status != 200) || (pub_2.response_header.content_length == 0)
published_messages_setp_2 = JSON.parse(pub_2.response)["published_messages"].to_i
fail("Don't create more channel") if published_messages_setp_1 == published_messages_setp_2
EM.add_timer(35) do
pub_3 = EventMachine::HttpRequest.new(nginx_address + '/channels-stats').get :head => headers, :timeout => 60
pub_3.callback do
fail("Don't received the stats") if (pub_3.response_header.status != 200) || (pub_3.response_header.content_length == 0)
assert_equal(0, JSON.parse(pub_3.response)["channels"].to_i, "Don't cleaned all messages/channels")
EM.add_timer(35) do
fill_memory_timer = EventMachine::PeriodicTimer.new(0.001) do
publish_message_inline_with_callbacks(channel + i.to_s, headers, body, {
:error => Proc.new do |status3, content3|
pub_4 = EventMachine::HttpRequest.new(nginx_address + '/channels-stats').get :head => headers, :timeout => 60
pub_4.callback do
fail("Don't received the stats") if (pub_4.response_header.status != 200) || (pub_4.response_header.content_length == 0)
result = JSON.parse(pub_4.response)
assert_equal(published_messages_setp_1, (result["published_messages"].to_i - published_messages_setp_2), "Don't cleaned all memory")
EventMachine.stop
end
end
})
i += 1
end
end
end
end
end
end
})
j += 1
end
end
end
end
end
})
i += 1
end
add_test_timeout(@@timeout)
end
end
end
require File.expand_path('base_test_case', File.dirname(__FILE__))
class TestCleanupMemoryAfterReload < Test::Unit::TestCase
include BaseTestCase
@@timeout = 130
def global_configuration
ENV['NGINX_WORKERS'] = '1'
@disable_ignore_childs = true
@master_process = 'on'
@daemon = 'on'
end
def reload_worker
sleep(1)
# send reload signal
`#{ nginx_executable } -c #{ config_filename } -s reload > /dev/null 2>&1`
end
def config_test_message_cleanup_after_reload
@memory_cleanup_timeout = '30s'
@max_reserved_memory = "129k"
@min_message_buffer_timeout = '10s'
@max_message_buffer_length = 100
end
def test_message_cleanup_after_reload
channel = 'ch_test_message_cleanup_after_reload'
headers = {'accept' => 'text/html'}
body = 'message to create a channel'
stored_messages_setp_1 = 0
published_messages_setp_1 = 0
published_messages_setp_2 = 0
EventMachine.run do
# ensure channel will not be cleaned up
sub_1 = EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel.to_s).get :head => headers, :timeout => 60
fill_memory_timer = EventMachine::PeriodicTimer.new(0.001) do
publish_message_inline_with_callbacks(channel, headers, body, {
:error => Proc.new do |status, content|
fill_memory_timer.cancel
pub_2 = EventMachine::HttpRequest.new(nginx_address + '/channels-stats?id=' + channel.to_s).get :head => headers, :timeout => 60
pub_2.callback do
fail("Don't received the stats") if (pub_2.response_header.status != 200) || (pub_2.response_header.content_length == 0)
result = JSON.parse(pub_2.response)
stored_messages_setp_1 = result["stored_messages"].to_i
published_messages_setp_1 = result["published_messages"].to_i
assert_equal(@max_message_buffer_length, stored_messages_setp_1, "Don't limit stored messages")
fail("Don't reached the limit of stored messages") if result["published_messages"].to_i <= @max_message_buffer_length
fail("Don't create any message") if stored_messages_setp_1 == 0
reload_worker
sleep(1)
# connect a subscriber on new worker
sub_1 = EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel.to_s).get :head => headers, :timeout => 60
EM.add_timer(35) do
fill_memory_timer = EventMachine::PeriodicTimer.new(0.001) do
publish_message_inline_with_callbacks(channel, headers, body, {
:error => Proc.new do |status2, content2|
fill_memory_timer.cancel
pub_2 = EventMachine::HttpRequest.new(nginx_address + '/channels-stats?id=' + channel.to_s).get :head => headers, :timeout => 60
pub_2.callback do
fail("Don't received the stats") if (pub_2.response_header.status != 200) || (pub_2.response_header.content_length == 0)
published_messages_setp_2 = JSON.parse(pub_2.response)["published_messages"].to_i
fail("Don't publish more messages") if published_messages_setp_1 == published_messages_setp_2
EM.add_timer(50) do
pub_3 = EventMachine::HttpRequest.new(nginx_address + '/channels-stats?id=' + channel.to_s).get :head => headers, :timeout => 60
pub_3.callback do
fail("Don't received the stats") if (pub_3.response_header.status != 200) || (pub_3.response_header.content_length == 0)
assert_equal(0, JSON.parse(pub_3.response)["stored_messages"].to_i, "Don't cleaned all messages")
fill_memory_timer = EventMachine::PeriodicTimer.new(0.001) do
publish_message_inline_with_callbacks(channel, headers, body, {
:error => Proc.new do |status3, content3|
pub_4 = EventMachine::HttpRequest.new(nginx_address + '/channels-stats?id=' + channel.to_s).get :head => headers, :timeout => 60
pub_4.callback do
fail("Don't received the stats") if (pub_4.response_header.status != 200) || (pub_4.response_header.content_length == 0)
result = JSON.parse(pub_4.response)
assert_equal(stored_messages_setp_1, result["stored_messages"].to_i, "Don't cleaned all messages")
assert_equal(published_messages_setp_1, (result["published_messages"].to_i - published_messages_setp_2), "Don't cleaned all memory")
EventMachine.stop
end
end
})
end
end
end
end
end
})
end
end
end
end
})
end
add_test_timeout(@@timeout)
end
end
def config_test_discard_old_messages_after_reload
@memory_cleanup_timeout = '30s'
@max_reserved_memory = "129k"
@min_message_buffer_timeout = '10s'
@max_message_buffer_length = nil
end
def test_discard_old_messages_after_reload
channel = 'ch_test_discard_old_messages_after_reload'
headers = {'accept' => 'text/html'}
body = 'message to create a channel'
messages_to_publish = 10
count = 0
stored_messages_setp_1 = 0
EventMachine.run do
fill_memory_timer = EventMachine::PeriodicTimer.new(messages_to_publish / 12.to_f) do # publish messages before cleanup timer be executed
if (count < messages_to_publish)
publish_message_inline(channel, headers, body)
elsif (count == messages_to_publish)
pub_1 = EventMachine::HttpRequest.new(nginx_address + '/channels-stats?id=' + channel.to_s).get :head => headers, :timeout => 60
pub_1.callback do
fill_memory_timer.cancel
fail("Don't received the stats") if (pub_1.response_header.status != 200) || (pub_1.response_header.content_length == 0)
stored_messages_setp_1 = JSON.parse(pub_1.response)["stored_messages"].to_i
assert_equal(messages_to_publish, stored_messages_setp_1, "Don't store messages")
reload_worker
EM.add_timer(5) do # wait cleanup timer to be executed one time
pub_2 = EventMachine::HttpRequest.new(nginx_address + '/channels-stats?id=' + channel.to_s).get :head => headers, :timeout => 60
pub_2.callback do
fail("Don't received the stats") if (pub_2.response_header.status != 200) || (pub_2.response_header.content_length == 0)
stored_messages_setp_2 = JSON.parse(pub_2.response)["stored_messages"].to_i
assert(stored_messages_setp_1 > stored_messages_setp_2, "Don't clear messages")
assert(stored_messages_setp_2 > 0, "Cleared all messages")
EventMachine.stop
end
end
end
end
count += 1
end
add_test_timeout(20)
end
end
def config_test_message_cleanup_without_max_messages_stored_per_channel_after_reload
@memory_cleanup_timeout = '30s'
@max_reserved_memory = "129k"
@min_message_buffer_timeout = '10s'
@max_message_buffer_length = nil
end
def test_message_cleanup_without_max_messages_stored_per_channel_after_reload
channel = 'ch_test_message_cleanup_without_max_messages_stored_per_channel_after_reload'
headers = {'accept' => 'text/html'}
body = 'message to create a channel'
stored_messages_setp_1 = 0
published_messages_setp_1 = 0
published_messages_setp_2 = 0
EventMachine.run do
# ensure channel will not be cleaned up
sub_1 = EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel.to_s).get :head => headers, :timeout => 60
fill_memory_timer = EventMachine::PeriodicTimer.new(0.001) do
publish_message_inline_with_callbacks(channel, headers, body, {
:error => Proc.new do |status, content|
fill_memory_timer.cancel
pub_2 = EventMachine::HttpRequest.new(nginx_address + '/channels-stats?id=' + channel.to_s).get :head => headers, :timeout => 60
pub_2.callback do
fail("Don't received the stats") if (pub_2.response_header.status != 200) || (pub_2.response_header.content_length == 0)
result = JSON.parse(pub_2.response)
stored_messages_setp_1 = result["stored_messages"].to_i
published_messages_setp_1 = result["published_messages"].to_i
fail("Limited the number of stored messages") if stored_messages_setp_1 <= 100
fail("Don't create any message") if stored_messages_setp_1 == 0
reload_worker
sleep(1)
# connect a subscriber on new worker
sub_1 = EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel.to_s).get :head => headers, :timeout => 60
EM.add_timer(40) do
fill_memory_timer = EventMachine::PeriodicTimer.new(0.001) do
publish_message_inline_with_callbacks(channel, headers, body, {
:error => Proc.new do |status2, content2|
fill_memory_timer.cancel
pub_2 = EventMachine::HttpRequest.new(nginx_address + '/channels-stats?id=' + channel.to_s).get :head => headers, :timeout => 60
pub_2.callback do
fail("Don't received the stats") if (pub_2.response_header.status != 200) || (pub_2.response_header.content_length == 0)
published_messages_setp_2 = JSON.parse(pub_2.response)["published_messages"].to_i
fail("Don't publish more messages") if published_messages_setp_1 == published_messages_setp_2
EM.add_timer(50) do
pub_3 = EventMachine::HttpRequest.new(nginx_address + '/channels-stats?id=' + channel.to_s).get :head => headers, :timeout => 60
pub_3.callback do
fail("Don't received the stats") if (pub_3.response_header.status != 200) || (pub_3.response_header.content_length == 0)
assert_equal(0, JSON.parse(pub_3.response)["stored_messages"].to_i, "Don't cleaned all messages")
fill_memory_timer = EventMachine::PeriodicTimer.new(0.001) do
publish_message_inline_with_callbacks(channel, headers, body, {
:error => Proc.new do |status3, content3|
pub_4 = EventMachine::HttpRequest.new(nginx_address + '/channels-stats?id=' + channel.to_s).get :head => headers, :timeout => 60
pub_4.callback do
fail("Don't received the stats") if (pub_4.response_header.status != 200) || (pub_4.response_header.content_length == 0)
result = JSON.parse(pub_4.response)
assert_equal(stored_messages_setp_1, result["stored_messages"].to_i, "Don't cleaned all messages")
assert_equal(published_messages_setp_1, (result["published_messages"].to_i - published_messages_setp_2), "Don't cleaned all memory")
EventMachine.stop
end
end
})
end
end
end
end
end
})
end
end
end
end
})
end
add_test_timeout(@@timeout)
end
end
def config_test_channel_cleanup_after_reload
@memory_cleanup_timeout = '30s'
@max_reserved_memory = "129k"
@min_message_buffer_timeout = '2s'
@max_message_buffer_length = nil
end
def test_channel_cleanup_after_reload
channel = 'ch_test_channel_cleanup_after_reload'
headers = {'accept' => 'text/html'}
body = 'message to create a channel'
channels_setp_1 = 0
channels_setp_2 = 0
published_messages_setp_1 = 0
EventMachine.run do
i = 0
fill_memory_timer = EventMachine::PeriodicTimer.new(0.001) do
publish_message_inline_with_callbacks(channel + i.to_s, headers, body, {
:error => Proc.new do |status, content|
fill_memory_timer.cancel
pub_2 = EventMachine::HttpRequest.new(nginx_address + '/channels-stats').get :head => headers, :timeout => 60
pub_2.callback do
fail("Don't received the stats") if (pub_2.response_header.status != 200) || (pub_2.response_header.content_length == 0)
result = JSON.parse(pub_2.response)
channels_setp_1 = result["channels"].to_i
published_messages_setp_1 = result["published_messages"].to_i
fail("Don't create any channel") if channels_setp_1 == 0
reload_worker
EM.add_timer(35) do
j = 0
fill_memory_timer = EventMachine::PeriodicTimer.new(0.001) do
publish_message_inline_with_callbacks(channel + j.to_s, headers, body, {
:error => Proc.new do |status2, content2|
fill_memory_timer.cancel
pub_2 = EventMachine::HttpRequest.new(nginx_address + '/channels-stats').get :head => headers, :timeout => 60
pub_2.callback do
fail("Don't received the stats") if (pub_2.response_header.status != 200) || (pub_2.response_header.content_length == 0)
fail("Don't create more channel") if published_messages_setp_1 == JSON.parse(pub_2.response)["published_messages"].to_i
EM.add_timer(40) do
pub_3 = EventMachine::HttpRequest.new(nginx_address + '/channels-stats').get :head => headers, :timeout => 60
pub_3.callback do
fail("Don't received the stats") if (pub_3.response_header.status != 200) || (pub_3.response_header.content_length == 0)
channels = JSON.parse(pub_3.response)["channels"].to_i
assert_equal(0, channels, "Don't removed all channels")
EventMachine.stop unless (channels == 0)
EM.add_timer(35) do
i = 0
fill_memory_timer = EventMachine::PeriodicTimer.new(0.001) do
publish_message_inline_with_callbacks(channel + i.to_s, headers, body, {
:error => Proc.new do |status3, content3|
fill_memory_timer.cancel
pub_4 = EventMachine::HttpRequest.new(nginx_address + '/channels-stats').get :head => headers, :timeout => 60
pub_4.callback do
fail("Don't received the stats") if (pub_4.response_header.status != 200) || (pub_4.response_header.content_length == 0)
channels_setp_2 = JSON.parse(pub_4.response)["channels"].to_i
assert_equal(channels_setp_1, channels_setp_2, "Don't released all memory")
EventMachine.stop
end
end
})
i += 1
end
end
end
end
end
end
})
j += 1
end
end
end
end
})
i += 1
end
add_test_timeout(@@timeout)
end
end
def config_test_message_cleanup_with_store_off_with_subscriber_after_reload
@store_messages = 'off'
@memory_cleanup_timeout = '30s'
@max_reserved_memory = "129k"
@min_message_buffer_timeout = nil
@max_message_buffer_length = nil
end
def test_message_cleanup_with_store_off_with_subscriber_after_reload
channel = 'ch_test_message_cleanup_with_store_off_with_subscriber_after_reload'
headers = {'accept' => 'text/html'}
body = 'message to create a channel'
published_messages_setp_1 = 0
published_messages_setp_2 = 0
EventMachine.run do
# ensure channel will not be cleaned up
sub_1 = EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel.to_s).get :head => headers, :timeout => 60
fill_memory_timer = EventMachine::PeriodicTimer.new(0.001) do
publish_message_inline_with_callbacks(channel, headers, body, {
:error => Proc.new do |status, content|
fill_memory_timer.cancel
pub_2 = EventMachine::HttpRequest.new(nginx_address + '/channels-stats?id=' + channel.to_s).get :head => headers, :timeout => 60
pub_2.callback do
fail("Don't received the stats") if (pub_2.response_header.status != 200) || (pub_2.response_header.content_length == 0)
result = JSON.parse(pub_2.response)
published_messages_setp_1 = result["published_messages"].to_i
reload_worker
sleep(1)
# connect a subscriber on new worker
sub_1 = EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel.to_s).get :head => headers, :timeout => 60
EM.add_timer(35) do
fill_memory_timer = EventMachine::PeriodicTimer.new(0.001) do
publish_message_inline_with_callbacks(channel, headers, body, {
:error => Proc.new do |status2, content2|
fill_memory_timer.cancel
pub_2 = EventMachine::HttpRequest.new(nginx_address + '/channels-stats?id=' + channel.to_s).get :head => headers, :timeout => 60
pub_2.callback do
fail("Don't received the stats") if (pub_2.response_header.status != 200) || (pub_2.response_header.content_length == 0)
published_messages_setp_2 = JSON.parse(pub_2.response)["published_messages"].to_i
fail("Don't publish more messages") if published_messages_setp_1 == published_messages_setp_2
EM.add_timer(35) do
pub_3 = EventMachine::HttpRequest.new(nginx_address + '/channels-stats?id=' + channel.to_s).get :head => headers, :timeout => 60
pub_3.callback do
fail("Don't received the stats") if (pub_3.response_header.status != 200) || (pub_3.response_header.content_length == 0)
assert_equal(0, JSON.parse(pub_3.response)["channels"].to_i, "Don't cleaned all messages/channels")
fill_memory_timer = EventMachine::PeriodicTimer.new(0.001) do
publish_message_inline_with_callbacks(channel, headers, body, {
:error => Proc.new do |status3, content3|
pub_4 = EventMachine::HttpRequest.new(nginx_address + '/channels-stats?id=' + channel.to_s).get :head => headers, :timeout => 60
pub_4.callback do
fail("Don't received the stats") if (pub_4.response_header.status != 200) || (pub_4.response_header.content_length == 0)
result = JSON.parse(pub_4.response)
assert_equal(published_messages_setp_1, (result["published_messages"].to_i - published_messages_setp_2), "Don't cleaned all memory")
EventMachine.stop
end
end
})
end
end
end
end
end
})
end
end
end
end
})
end
add_test_timeout(@@timeout)
end
end
def config_test_message_cleanup_with_store_off_without_subscriber_after_reload
@store_messages = 'off'
@memory_cleanup_timeout = '30s'
@max_reserved_memory = "129k"
@min_message_buffer_timeout = nil
@max_message_buffer_length = nil
end
def test_message_cleanup_with_store_off_without_subscriber_after_reload
channel = 'ch_test_message_cleanup_with_store_off_without_subscriber_after_reload'
headers = {'accept' => 'text/html'}
body = 'message to create a channel'
published_messages_setp_1 = 0
published_messages_setp_2 = 0
EventMachine.run do
i = 0
fill_memory_timer = EventMachine::PeriodicTimer.new(0.001) do
publish_message_inline_with_callbacks(channel + i.to_s, headers, body, {
:error => Proc.new do |status, content|
fill_memory_timer.cancel
pub_2 = EventMachine::HttpRequest.new(nginx_address + '/channels-stats').get :head => headers, :timeout => 60
pub_2.callback do
fail("Don't received the stats") if (pub_2.response_header.status != 200) || (pub_2.response_header.content_length == 0)
result = JSON.parse(pub_2.response)
published_messages_setp_1 = result["published_messages"].to_i
reload_worker
EM.add_timer(35) do
j = 0
fill_memory_timer = EventMachine::PeriodicTimer.new(0.001) do
publish_message_inline_with_callbacks(channel + j.to_s, headers, body, {
:error => Proc.new do |status2, content2|
fill_memory_timer.cancel
pub_2 = EventMachine::HttpRequest.new(nginx_address + '/channels-stats').get :head => headers, :timeout => 60
pub_2.callback do
fail("Don't received the stats") if (pub_2.response_header.status != 200) || (pub_2.response_header.content_length == 0)
published_messages_setp_2 = JSON.parse(pub_2.response)["published_messages"].to_i
fail("Don't create more channel") if published_messages_setp_1 == published_messages_setp_2
EM.add_timer(35) do
pub_3 = EventMachine::HttpRequest.new(nginx_address + '/channels-stats').get :head => headers, :timeout => 60
pub_3.callback do
fail("Don't received the stats") if (pub_3.response_header.status != 200) || (pub_3.response_header.content_length == 0)
assert_equal(0, JSON.parse(pub_3.response)["channels"].to_i, "Don't cleaned all messages/channels")
EM.add_timer(35) do
fill_memory_timer = EventMachine::PeriodicTimer.new(0.001) do
publish_message_inline_with_callbacks(channel + i.to_s, headers, body, {
:error => Proc.new do |status3, content3|
pub_4 = EventMachine::HttpRequest.new(nginx_address + '/channels-stats').get :head => headers, :timeout => 60
pub_4.callback do
fail("Don't received the stats") if (pub_4.response_header.status != 200) || (pub_4.response_header.content_length == 0)
result = JSON.parse(pub_4.response)
assert_equal(published_messages_setp_1, (result["published_messages"].to_i - published_messages_setp_2), "Don't cleaned all memory")
EventMachine.stop
end
end
})
i += 1
end
end
end
end
end
end
})
j += 1
end
end
end
end
})
i += 1
end
add_test_timeout(@@timeout)
end
end
end
require File.expand_path('base_test_case', File.dirname(__FILE__))
class TestComunicationProperties < Test::Unit::TestCase
include BaseTestCase
def config_test_all_authorized
@authorized_channels_only = "off"
@header_template = "connected"
end
def test_all_authorized
channel = 'ch_test_all_authorized'
headers = {'accept' => 'text/html'}
EventMachine.run {
sub = EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel.to_s).get :head => headers, :timeout => 60
sub.stream { |chunk|
assert_equal("#{@header_template}\r\n", chunk, "Didn't received header template")
EventMachine.stop
}
}
end
def config_test_only_authorized
@authorized_channels_only = "on"
@header_template = "connected"
end
def test_only_authorized
channel = 'ch_test_only_authorized'
headers = {'accept' => 'text/html'}
body = 'message to create a channel'
EventMachine.run {
sub_1 = EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel.to_s).get :head => headers, :timeout => 60
sub_1.callback { |chunk|
assert_equal(403, sub_1.response_header.status, "Subscriber was not forbidden")
assert_equal(0, sub_1.response_header.content_length, "Should response only with headers")
assert_equal("Subscriber could not create channels.", sub_1.response_header['X_NGINX_PUSHSTREAM_EXPLAIN'], "Didn't receive the right error message")
pub = EventMachine::HttpRequest.new(nginx_address + '/pub?id=' + channel.to_s ).post :head => headers, :body => body, :timeout => 30
pub.callback {
sub_2 = EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel.to_s).get :head => headers, :timeout => 60
sub_2.stream { |chunk2|
assert_equal("#{@header_template}\r\n", chunk2, "Didn't received header template")
EventMachine.stop
}
}
}
}
end
def config_test_message_buffer_timeout
@authorized_channels_only = "off"
@header_template = "connected"
@message_template = "~text~"
@min_message_buffer_timeout = "12s"
end
def test_message_buffer_timeout
channel = 'ch_test_message_buffer_timeout'
headers = {'accept' => 'text/html'}
body = 'message to test buffer timeout '
response_1 = response_2 = response_3 = ""
sub_1 = sub_2 = sub_3 = nil
EventMachine.run {
pub = EventMachine::HttpRequest.new(nginx_address + '/pub?id=' + channel.to_s ).post :head => headers, :body => body, :timeout => 30
EM.add_timer(2) do
sub_1 = EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel.to_s + '.b1').get :head => headers, :timeout => 60
sub_1.stream { |chunk|
response_1 += chunk
sub_1.close if response_1.include?(body)
}
end
EM.add_timer(6) do
sub_2 = EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel.to_s + '.b1').get :head => headers, :timeout => 60
sub_2.stream { |chunk|
response_2 += chunk
sub_2.close if response_2.include?(body)
}
end
#message will be certainly expired at 15 seconds
EM.add_timer(16) do
sub_3 = EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel.to_s + '.b1').get :head => headers, :timeout => 60
sub_3.stream { |chunk|
response_3 += chunk
sub_3.close if response_3.include?(body)
}
end
EM.add_timer(17) do
assert_equal("#{@header_template}\r\n#{body}\r\n\r\n", response_1, "Didn't received header and message")
assert_equal("#{@header_template}\r\n#{body}\r\n\r\n", response_2, "Didn't received header and message")
assert_equal("#{@header_template}\r\n", response_3, "Didn't received header")
EventMachine.stop
end
}
end
def config_test_message_template
@authorized_channels_only = "off"
@header_template = "header"
@message_template = '{\"duplicated\":\"~channel~\", \"channel\":\"~channel~\", \"message\":\"~text~\", \"message_id\":\"~id~\"}'
@ping_message_interval = "1s"
end
def test_message_template
channel = 'ch_test_message_template'
headers = {'accept' => 'text/html'}
body = 'message to create a channel'
publish_message(channel, headers, body)
response = ""
EventMachine.run {
chunksReceived = 0
sub = EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel.to_s + '.b1').get :head => headers, :timeout => 60
sub.stream { |chunk|
response += chunk
lines = response.split("\r\n")
if lines.length >= 3
assert_equal("#{@header_template}", lines[0], "Didn't received header template")
assert_equal("{\"duplicated\":\"#{channel}\", \"channel\":\"#{channel}\", \"message\":\"#{body}\", \"message_id\":\"1\"}", lines[1], "Didn't received message formatted: #{lines[1]}")
assert_equal("{\"duplicated\":\"\", \"channel\":\"\", \"message\":\"\", \"message_id\":\"-1\"}", lines[2], "Didn't received ping message: #{lines[2]}")
EventMachine.stop
end
}
add_test_timeout(20)
}
end
def config_test_message_and_channel_with_same_pattern_of_the_template
@authorized_channels_only = "off"
@header_template = "header"
@message_template = '{\"channel\":\"~channel~\", \"message\":\"~text~\", \"message_id\":\"~id~\"}'
@ping_message_interval = "1s"
end
def test_message_and_channel_with_same_pattern_of_the_template
channel = 'ch_test_message_and_channel_with_same_pattern_of_the_template~channel~~channel~~channel~~text~~text~~text~'
headers = {'accept' => 'text/html'}
body = '~channel~~channel~~channel~~text~~text~~text~'
publish_message(channel, headers, body)
response = ""
EventMachine.run {
chunksReceived = 0
sub = EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel.to_s + '.b1').get :head => headers, :timeout => 60
sub.stream { |chunk|
response += chunk
lines = response.split("\r\n")
if lines.length >= 3
assert_equal("#{@header_template}", lines[0], "Didn't received header template")
assert_equal("{\"channel\":\"ch_test_message_and_channel_with_same_pattern_of_the_template~channel~~channel~~channel~~channel~~channel~~channel~~text~~text~~text~~channel~~channel~~channel~~text~~text~~text~~channel~~channel~~channel~~text~~text~~text~\", \"message\":\"~channel~~channel~~channel~~text~~text~~text~\", \"message_id\":\"1\"}", lines[1], "Didn't received message formatted: #{lines[1]}")
assert_equal("{\"channel\":\"\", \"message\":\"\", \"message_id\":\"-1\"}", lines[2], "Didn't received ping message: #{lines[2]}")
EventMachine.stop
end
}
add_test_timeout(20)
}
end
end
require File.expand_path('base_test_case', File.dirname(__FILE__))
class TestCreateManyChannels < Test::Unit::TestCase
include BaseTestCase
def config_test_create_many_channels
@max_reserved_memory = "256m"
@keepalive = "on"
end
def test_create_many_channels
headers = {'accept' => 'application/json'}
body = 'channel started'
channels_to_be_created = 4000
channel = 'ch_test_create_many_channels_'
0.step(channels_to_be_created - 1, 10) do |i|
socket = open_socket
1.upto(10) do |j|
channel_name = "#{channel}#{i + j}"
headers, body = publish_message_in_socket(channel_name, body, socket)
fail("Don't create the channel") unless headers.include?("HTTP/1.1 200 OK")
end
socket.close
end
end
end
require File.expand_path('base_test_case', File.dirname(__FILE__))
class TestKeepalive < Test::Unit::TestCase
include BaseTestCase
def config_test_different_operation_with_keepalive
@keepalive = 'on'
end
def test_different_operation_with_keepalive
channel = 'ch_test_different_operation_with_keepalive'
body = 'message to be sent'
get_without_channel_id = "GET /pub HTTP/1.0\r\n\r\n"
post_channel_message = "POST /pub?id=#{channel} HTTP/1.0\r\nContent-Length: #{body.size}\r\n\r\n#{body}"
get_channels_stats = "GET /channels-stats HTTP/1.0\r\n\r\n"
get_channel_stats = "GET /pub?id=#{channel} HTTP/1.0\r\n\r\n"
socket = TCPSocket.open(nginx_host, nginx_port)
socket.print(get_without_channel_id)
headers, body = read_response(socket)
assert_equal("", body, "Wrong response")
assert(headers.match(/No channel id provided\./), "Didn't receive error message")
socket.print(post_channel_message)
headers, body = read_response(socket)
assert_equal("{\"channel\": \"#{channel}\", \"published_messages\": \"1\", \"stored_messages\": \"1\", \"subscribers\": \"0\"}\r\n", body, "Wrong response")
socket.print(get_channels_stats)
headers, body = read_response(socket)
assert(body.match(/"channels": "1", "broadcast_channels": "0", "published_messages": "1", "subscribers": "0", "uptime": "[0-9]*", "by_worker": \[\r\n/), "Didn't receive message")
assert(body.match(/\{"pid": "[0-9]*", "subscribers": "0", "uptime": "[0-9]*"\}/), "Didn't receive message")
socket.print(get_channel_stats)
headers, body = read_response(socket)
assert_equal("{\"channel\": \"#{channel}\", \"published_messages\": \"1\", \"stored_messages\": \"1\", \"subscribers\": \"0\"}\r\n", body, "Wrong response")
end
end
require File.expand_path('base_test_case', File.dirname(__FILE__))
class TestMeasureMemory < Test::Unit::TestCase
include BaseTestCase
@@message_estimate_size = 174
@@channel_estimate_size = 536
@@subscriber_estimate_size = 230
@@subscriber_estimate_system_size = 6860
def global_configuration
@max_reserved_memory = "2m"
@memory_cleanup_timeout = "60m"
@min_message_buffer_timeout = "60m"
@max_message_buffer_length = nil
@keepalive = "on"
@header_template = nil
@message_template = nil
@footer_template = nil
@ping_message_interval = nil
end
def test_message_size
channel = 'ch_test_message_size'
headers = {'accept' => 'text/html'}
body = '1'
shared_size = @max_reserved_memory.to_i * 1024 * 1024
expected_message = shared_size / (@@message_estimate_size + body.size)
post_channel_message = "POST /pub?id=#{channel} HTTP/1.0\r\nContent-Length: #{body.size}\r\n\r\n#{body}"
socket = TCPSocket.open(nginx_host, nginx_port)
while (true) do
socket.print(post_channel_message)
headers, body = read_response(socket)
break unless headers.match(/200 OK/)
end
EventMachine.run {
pub_2 = EventMachine::HttpRequest.new(nginx_address + '/channels-stats?id=' + channel.to_s).get :head => headers, :timeout => 60
pub_2.callback {
assert_equal(200, pub_2.response_header.status, "Don't get channels statistics")
assert_not_equal(0, pub_2.response_header.content_length, "Don't received channels statistics")
published_messages = JSON.parse(pub_2.response)["published_messages"].to_i
assert(((expected_message - 20) <= published_messages) && (published_messages <= (expected_message + 20)), "Message size is far from %d bytes (expected: %d, published: %d)" % ([@@message_estimate_size, expected_message, published_messages]))
EventMachine.stop
}
add_test_timeout
}
end
def test_channel_size
headers = {'accept' => 'text/html'}
body = '1'
shared_size = @max_reserved_memory.to_i * 1024 * 1024
expected_channel = shared_size / (@@message_estimate_size + body.size + @@channel_estimate_size + 4) # 4 channel id size
EventMachine.run {
publish_message_in_loop(1000, headers, body)
add_test_timeout(25)
}
EventMachine.run {
pub_2 = EventMachine::HttpRequest.new(nginx_address + '/channels-stats').get :head => headers, :timeout => 60
pub_2.callback {
assert_equal(200, pub_2.response_header.status, "Don't get channels statistics")
assert_not_equal(0, pub_2.response_header.content_length, "Don't received channels statistics")
created_channels = JSON.parse(pub_2.response)["channels"].to_i
assert(((expected_channel - 10) <= created_channels) && (created_channels <= (expected_channel + 10)), "Channel size is far from %d bytes (expected: %d, created: %d)" % ([@@channel_estimate_size, expected_channel, created_channels]))
EventMachine.stop
}
add_test_timeout
}
end
def config_test_subscriber_size
@max_reserved_memory = "300k"
@header_template = "H"
end
def test_subscriber_size
headers = {'accept' => 'text/html'}
body = '1'
shared_size = @max_reserved_memory.to_i * 1024
expected_subscriber = shared_size / (@@subscriber_estimate_size + @@channel_estimate_size + 4)
EventMachine.run {
subscriber_in_loop(1000, headers, body) do
pub_2 = EventMachine::HttpRequest.new(nginx_address + '/channels-stats').get :head => headers, :timeout => 60
pub_2.callback {
assert_equal(200, pub_2.response_header.status, "Don't get channels statistics")
assert_not_equal(0, pub_2.response_header.content_length, "Don't received channels statistics")
created_subscriber = JSON.parse(pub_2.response)["subscribers"].to_i
assert(((expected_subscriber - 20) <= created_subscriber) && (created_subscriber <= (expected_subscriber + 20)), "Subscriber size is far from %d bytes (expected: %d, created: %d)" % ([@@subscriber_estimate_size, expected_subscriber, created_subscriber]))
EventMachine.stop
}
end
add_test_timeout(30)
}
end
def config_test_subscriber_system_size
@header_template = "H"
end
def test_subscriber_system_size
headers = {'accept' => 'text/html'}
body = '1'
channel = 'ch_test_subscriber_system_size'
#warming up
EventMachine.run {
sub = EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel.to_i.to_s).get :head => headers, :body => body, :timeout => 30
sub.stream { |chunk|
EventMachine.stop
}
add_test_timeout
}
EventMachine.run {
memory_1 = `ps -eo rss,cmd | grep -E 'ngin[xX] -c '`.split(' ')[0].to_i
subscriber_in_loop_with_limit(channel, headers, body, 1000, 1399) do
memory_2 = `ps -eo rss,cmd | grep -E 'ngin[xX] -c '`.split(' ')[0].to_i
per_subscriber = ((memory_2 - memory_1).to_f / 400) * 1000
assert(((@@subscriber_estimate_system_size - 15) < per_subscriber) && (per_subscriber < (@@subscriber_estimate_system_size + 15)), "Subscriber system size is far from %d bytes (measured: %d)" % ([@@subscriber_estimate_system_size, per_subscriber]))
EventMachine.stop
end
add_test_timeout(25)
}
end
def subscriber_in_loop(channel, headers, body, &block)
sub = EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel.to_i.to_s).get :head => headers, :body => body, :timeout => 30
sub.stream { |chunk|
subscriber_in_loop(channel.to_i + 1, headers, body) do
yield block
end
}
sub.callback {
block.call
}
end
def subscriber_in_loop_with_limit(channel, headers, body, start, limit, &block)
sub = EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel.to_i.to_s).get :head => headers, :body => body, :timeout => 30
sub.stream { |chunk|
if start == limit
block.call
EventMachine.stop
end
subscriber_in_loop_with_limit(channel, headers, body, start + 1, limit) do
yield block
end
}
sub.callback {
block.call
}
end
def publish_message_in_loop(channel, headers, body)
pub = EventMachine::HttpRequest.new(nginx_address + '/pub?id=' + channel.to_s).post :head => headers, :body => body, :timeout => 30
pub.callback {
EventMachine.stop if pub.response_header.status != 200
publish_message_in_loop(channel.to_i + 1, headers, body)
}
end
end
require File.expand_path('base_test_case', File.dirname(__FILE__))
class TestPaddingByUserAgent < Test::Unit::TestCase
include BaseTestCase
def global_configuration
@padding_by_user_agent = "[T|t]est 1,1024,512:[T|t]est 2,4097,0"
@user_agent = nil
@subscriber_connection_timeout = '1s'
@header_template = nil
@message_template = nil
@footer_template = nil
end
def config_test_header_padding
@header_template = "0123456789"
end
def test_header_padding
headers = {'accept' => 'application/json'}
channel = 'ch_test_header_padding'
EventMachine.run {
sub_1 = EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel.to_s).get :head => headers.merge("User-Agent" => "Test 1"), :timeout => 30
sub_1.callback {
assert_equal(200, sub_1.response_header.status, "Channel was founded")
assert_equal(1100 + @header_template.size + 4, sub_1.response.size, "Didn't received headder with padding")
sub_2 = EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel.to_s).get :head => headers.merge("User-Agent" => "Test 2"), :timeout => 30
sub_2.callback {
assert_equal(200, sub_2.response_header.status, "Channel was founded")
assert_equal(4097 + @header_template.size + 4, sub_2.response.size, "Didn't received headder with padding")
sub_3 = EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel.to_s).get :head => headers.merge("User-Agent" => "Test 3"), :timeout => 30
sub_3.callback {
assert_equal(200, sub_3.response_header.status, "Channel was founded")
assert_equal(@header_template.size + 2, sub_3.response.size, "Didn't received headder with padding")
EventMachine.stop
}
}
}
add_test_timeout
}
end
def test_message_padding
headers = {'accept' => 'application/json'}
channel = 'ch_test_message_padding'
body = "0123456789"
EventMachine.run {
sub_1 = EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel.to_s).get :head => headers.merge("User-Agent" => "Test 1"), :timeout => 30
sub_1.callback {
assert_equal(200, sub_1.response_header.status, "Channel was founded")
assert_equal(500 + body.size + 4, sub_1.response.size, "Didn't received headder with padding")
sub_2 = EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel.to_s).get :head => headers.merge("User-Agent" => "Test 2"), :timeout => 30
sub_2.callback {
assert_equal(200, sub_2.response_header.status, "Channel was founded")
assert_equal(body.size + 2, sub_2.response.size, "Didn't received headder with padding")
sub_3 = EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel.to_s).get :head => headers.merge("User-Agent" => "Test 3"), :timeout => 30
sub_3.callback {
assert_equal(200, sub_3.response_header.status, "Channel was founded")
assert_equal(body.size + 2, sub_3.response.size, "Didn't received headder with padding")
EventMachine.stop
}
publish_message_inline(channel, headers, body)
}
publish_message_inline(channel, headers, body)
}
publish_message_inline(channel, headers, body)
add_test_timeout
}
end
def config_test_message_padding_with_different_sizes
@padding_by_user_agent = "[T|t]est 1,0,545"
end
def test_message_padding_with_different_sizes
headers = {'accept' => 'application/json'}
channel = 'ch_test_message_padding_with_different_sizes'
EventMachine.run {
i = 1
expected_padding = 545
sub_1 = EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel.to_s).get :head => headers.merge("User-Agent" => "Test 1"), :timeout => 30
sub_1.callback {
assert_equal(200, sub_1.response_header.status, "Channel was founded")
assert_equal(expected_padding + i + 4, sub_1.response.size, "Didn't received headder with padding")
i = 105
expected_padding = 600 - ((i/100).to_i * 100)
sub_1 = EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel.to_s).get :head => headers.merge("User-Agent" => "Test 1"), :timeout => 30
sub_1.callback {
assert_equal(200, sub_1.response_header.status, "Channel was founded")
assert_equal(expected_padding + i + 4, sub_1.response.size, "Didn't received headder with padding")
i = 221
expected_padding = 600 - ((i/100).to_i * 100)
sub_1 = EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel.to_s).get :head => headers.merge("User-Agent" => "Test 1"), :timeout => 30
sub_1.callback {
assert_equal(200, sub_1.response_header.status, "Channel was founded")
assert_equal(expected_padding + i + 4, sub_1.response.size, "Didn't received headder with padding")
i = 331
expected_padding = 600 - ((i/100).to_i * 100)
sub_1 = EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel.to_s).get :head => headers.merge("User-Agent" => "Test 1"), :timeout => 30
sub_1.callback {
assert_equal(200, sub_1.response_header.status, "Channel was founded")
assert_equal(expected_padding + i + 4, sub_1.response.size, "Didn't received headder with padding")
i = 435
expected_padding = 600 - ((i/100).to_i * 100)
sub_1 = EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel.to_s).get :head => headers.merge("User-Agent" => "Test 1"), :timeout => 30
sub_1.callback {
assert_equal(200, sub_1.response_header.status, "Channel was founded")
assert_equal(expected_padding + i + 4, sub_1.response.size, "Didn't received headder with padding")
i = 502
expected_padding = 600 - ((i/100).to_i * 100)
sub_1 = EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel.to_s).get :head => headers.merge("User-Agent" => "Test 1"), :timeout => 30
sub_1.callback {
assert_equal(200, sub_1.response_header.status, "Channel was founded")
assert_equal(expected_padding + i + 4, sub_1.response.size, "Didn't received headder with padding")
i = 550
sub_1 = EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel.to_s).get :head => headers.merge("User-Agent" => "Test 1"), :timeout => 30
sub_1.callback {
assert_equal(200, sub_1.response_header.status, "Channel was founded")
assert_equal(i + 2, sub_1.response.size, "Didn't received headder with padding")
EventMachine.stop
}
publish_message_inline(channel, headers, "_" * i)
}
publish_message_inline(channel, headers, "_" * i)
}
publish_message_inline(channel, headers, "_" * i)
}
publish_message_inline(channel, headers, "_" * i)
}
publish_message_inline(channel, headers, "_" * i)
}
publish_message_inline(channel, headers, "_" * i)
}
publish_message_inline(channel, headers, "_" * i)
add_test_timeout(10)
}
end
def config_test_user_agent_by_complex_value
@padding_by_user_agent = "[T|t]est 1,1024,512"
@user_agent = "$arg_ua"
@header_template = "0123456789"
end
def test_user_agent_by_complex_value
headers = {'accept' => 'application/json'}
channel = 'ch_test_user_agent_by_complex_value'
EventMachine.run {
sub_1 = EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel.to_s + '?ua=test 1').get :head => headers, :timeout => 30
sub_1.callback {
assert_equal(200, sub_1.response_header.status, "Channel was founded")
assert_equal(1024 + @header_template.size + 4, sub_1.response.size, "Didn't received headder with padding")
sub_2 = EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel.to_s + '?ua=test 2').get :head => headers, :timeout => 30
sub_2.callback {
assert_equal(200, sub_2.response_header.status, "Channel was founded")
assert_equal(@header_template.size + 2, sub_2.response.size, "Didn't received headder with padding")
EventMachine.stop
}
}
add_test_timeout
}
end
end
require File.expand_path('base_test_case', File.dirname(__FILE__))
require 'time'
class TestPublishMessages < Test::Unit::TestCase
include BaseTestCase
def config_test_publish_messages
@header_template = nil
@message_template = "~text~"
end
def test_publish_messages
headers = {'accept' => 'text/html'}
body = 'published unique message'
channel = 'ch_test_publish_messages'
EventMachine.run {
sub = EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel.to_s).get :head => headers
sub.stream { | chunk |
assert_equal(body + "\r\n", chunk, "The published message was not received correctly")
EventMachine.stop
}
pub = EventMachine::HttpRequest.new(nginx_address + '/pub?id=' + channel.to_s ).post :head => headers, :body => body, :timeout => 30
}
end
def config_test_publish_messages_with_different_bytes
@header_template = nil
@message_template = "~text~"
@ping_message_interval = nil
@client_max_body_size = '65k'
@client_body_buffer_size = '65k'
end
def test_publish_messages_with_different_bytes
headers = {'accept' => 'text/html'}
channel = 'ch_test_publish_messages_with_different_bytes'
ranges = [1..63, 64..127, 128..191, 192..255]
ranges.each do |range|
bytes = []
range.each do |i|
1.upto(255) do |j|
bytes << "%s%s" % [i.chr, j.chr]
end
end
body = bytes.join('')
response = ''
EventMachine.run {
sub = EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel.to_s).get :head => headers
sub.stream { | chunk |
response += chunk
if response.include?(body)
assert_equal(body + "\r\n", response, "The published message was not received correctly")
EventMachine.stop
end
}
pub = EventMachine::HttpRequest.new(nginx_address + '/pub?id=' + channel.to_s ).post :head => headers, :body => body, :timeout => 30
add_test_timeout
}
end
end
def config_test_publish_large_messages
@header_template = nil
@footer_template = nil
@message_template = "~text~"
@ping_message_interval = nil
@client_max_body_size = '2000k'
@client_body_buffer_size = '2000k'
@subscriber_connection_timeout = '5s'
end
def test_publish_large_messages
headers = {'accept' => 'text/html'}
channel = 'ch_test_publish_large_messages'
body = "|123456789" * 102400 + "|"
response = ''
EventMachine.run {
sub = EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel.to_s).get :head => headers
sub.stream { | chunk |
response += chunk
if response.include?(body)
assert_equal(body + "\r\n", response, "The published message was not received correctly")
end
}
sub.callback {
response = ''
sub_1 = EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel.to_s + ".b1").get :head => headers
sub_1.stream { | chunk |
response += chunk
if response.include?(body)
assert_equal(body + "\r\n", response, "The published message was not received correctly")
EventMachine.stop
end
}
sub_1.callback {
EventMachine.stop
}
}
pub = EventMachine::HttpRequest.new(nginx_address + '/pub?id=' + channel.to_s ).post :head => headers, :body => body, :timeout => 30
add_test_timeout(15)
}
end
def config_test_publish_many_messages_in_the_same_channel
@header_template = nil
@message_template = "~text~"
@max_reserved_memory = "256m"
@ping_message_interval = nil
@keepalive = "on"
end
def test_publish_many_messages_in_the_same_channel
headers = {'accept' => 'text/html'}
body_prefix = 'published message '
channel = 'ch_test_publish_many_messages_in_the_same_channel'
messagens_to_publish = 1500
response = ""
EventMachine.run {
sub = EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel.to_s).get :head => headers
sub.stream { | chunk |
response += chunk
recieved_messages = response.split("\r\n")
if recieved_messages.length == messagens_to_publish
assert_equal(body_prefix + messagens_to_publish.to_s, recieved_messages.last, "Didn't receive all messages")
EventMachine.stop
end
}
EM.add_timer(0.05) do
0.step(messagens_to_publish - 1, 10) do |i|
socket = open_socket
1.upto(10) do |j|
resp_headers, body = publish_message_in_socket(channel, body_prefix + (i+j).to_s, socket)
fail("Message was not published: " + body_prefix + (i+j).to_s) unless resp_headers.include?("HTTP/1.1 200 OK")
end
socket.close
end
end
add_test_timeout
}
end
def config_test_set_an_event_id_to_the_message_through_header_parameter
@header_template = nil
@message_template = '{\"id\": \"~id~\", \"channel\": \"~channel~\", \"text\": \"~text~\", \"event_id\": \"~event-id~\"}'
end
def test_set_an_event_id_to_the_message_through_header_parameter
event_id = 'event_id_with_generic_text_01'
headers = {'accept' => 'text/html', 'Event-Id' => event_id }
body = 'test message'
channel = 'ch_test_set_an_event_id_to_the_message_through_header_parameter'
response = ''
EventMachine.run {
sub = EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel.to_s).get
sub.stream { | chunk |
response = JSON.parse(chunk)
assert_equal(1, response["id"].to_i, "Wrong data received")
assert_equal(channel, response["channel"], "Wrong data received")
assert_equal(body, response["text"], "Wrong data received")
assert_equal(event_id, response["event_id"], "Wrong data received")
EventMachine.stop
}
pub = EventMachine::HttpRequest.new(nginx_address + '/pub?id=' + channel.to_s ).post :head => headers, :body => body, :timeout => 30
add_test_timeout
}
end
def config_test_set_an_event_type_to_the_message_through_header_parameter
@header_template = nil
@message_template = '{\"id\": \"~id~\", \"channel\": \"~channel~\", \"text\": \"~text~\", \"event_type\": \"~event-type~\"}'
end
def test_set_an_event_type_to_the_message_through_header_parameter
event_type = 'event_type_with_generic_text_01'
headers = {'accept' => 'text/html', 'Event-type' => event_type }
body = 'test message'
channel = 'ch_test_set_an_event_type_to_the_message_through_header_parameter'
response = ''
EventMachine.run {
sub = EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel.to_s).get
sub.stream { | chunk |
response = JSON.parse(chunk)
assert_equal(1, response["id"].to_i, "Wrong data received")
assert_equal(channel, response["channel"], "Wrong data received")
assert_equal(body, response["text"], "Wrong data received")
assert_equal(event_type, response["event_type"], "Wrong data received")
EventMachine.stop
}
pub = EventMachine::HttpRequest.new(nginx_address + '/pub?id=' + channel.to_s ).post :head => headers, :body => body, :timeout => 30
add_test_timeout
}
end
def config_test_ignore_event_id_header_parameter_with_not_match_exactly
@header_template = nil
@message_template = '{\"id\": \"~id~\", \"channel\": \"~channel~\", \"text\": \"~text~\", \"event_id\": \"~event-id~\"}'
end
def test_ignore_event_id_header_parameter_with_not_match_exactly
event_id = 'event_id_with_generic_text_01'
headers = {'accept' => 'text/html'}
body = 'test message'
channel = 'ch_test_set_an_event_id_to_the_message_through_header_parameter'
response = ''
EventMachine.run {
sub = EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel.to_s).get
sub.stream { | chunk |
response = JSON.parse(chunk)
assert_equal(1, response["id"].to_i, "Wrong data received")
assert_equal(channel, response["channel"], "Wrong data received")
assert_equal(body, response["text"], "Wrong data received")
assert_equal("", response["event_id"], "Wrong data received")
EventMachine.stop
}
pub = EventMachine::HttpRequest.new(nginx_address + '/pub?id=' + channel.to_s ).post :head => headers.merge('Event-Ids' => event_id), :body => body, :timeout => 30
add_test_timeout
}
EventMachine.run {
sub = EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel.to_s).get
sub.stream { | chunk |
response = JSON.parse(chunk)
assert_equal(2, response["id"].to_i, "Wrong data received")
assert_equal(channel, response["channel"], "Wrong data received")
assert_equal(body, response["text"], "Wrong data received")
assert_equal("", response["event_id"], "Wrong data received")
EventMachine.stop
}
pub = EventMachine::HttpRequest.new(nginx_address + '/pub?id=' + channel.to_s ).post :head => headers.merge('Event-I' => event_id), :body => body, :timeout => 30
add_test_timeout
}
end
def config_test_expose_message_publish_time_through_message_template
@header_template = nil
@message_template = '{\"id\": \"~id~\", \"channel\": \"~channel~\", \"text\": \"~text~\", \"publish_time\": \"~time~\"}'
end
def test_expose_message_publish_time_through_message_template
headers = {'accept' => 'text/html'}
body = 'test message'
channel = 'ch_test_expose_message_publish_time_through_message_template'
response = ''
now = nil
EventMachine.run {
sub = EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel.to_s).get
sub.stream { | chunk |
response = JSON.parse(chunk)
assert_equal(1, response["id"].to_i, "Wrong data received")
assert_equal(channel, response["channel"], "Wrong data received")
assert_equal(body, response["text"], "Wrong data received")
assert_equal(29, response["publish_time"].size, "Wrong data received")
publish_time = Time.parse(response["publish_time"])
assert_equal(now.to_i, publish_time.to_i, "Didn't receive the correct publish time")
EventMachine.stop
}
now = Time.now
pub = EventMachine::HttpRequest.new(nginx_address + '/pub?id=' + channel.to_s ).post :head => headers, :body => body, :timeout => 30
add_test_timeout
}
end
def config_test_expose_message_tag_through_message_template
@header_template = nil
@message_template = '{\"id\": \"~id~\", \"channel\": \"~channel~\", \"text\": \"~text~\", \"tag\": \"~tag~\"}'
end
def test_expose_message_tag_through_message_template
headers = {'accept' => 'text/html'}
body = 'test message'
channel = 'ch_test_expose_message_tag_through_message_template'
response = ''
EventMachine.run {
sub = EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel.to_s).get
sub.stream { | chunk |
response += chunk
lines = response.split('\r\n')
if lines.size > 1
lines.each_with_index do |line, i|
resp = JSON.parse(line)
assert_equal(i + 1, resp["id"].to_i, "Wrong data received")
assert_equal(channel, resp["channel"], "Wrong data received")
assert_equal(body, resp["text"], "Wrong data received")
assert_equal(i, resp["tag"].to_i, "Wrong data received")
end
end
EventMachine.stop
}
pub = EventMachine::HttpRequest.new(nginx_address + '/pub?id=' + channel.to_s ).post :head => headers, :body => body, :timeout => 30
pub = EventMachine::HttpRequest.new(nginx_address + '/pub?id=' + channel.to_s ).post :head => headers, :body => body, :timeout => 30
add_test_timeout
}
end
end
require File.expand_path('base_test_case', File.dirname(__FILE__))
class TestPublisher < Test::Unit::TestCase
include BaseTestCase
def test_access_whithout_channel_id
headers = {'accept' => 'application/json'}
EventMachine.run {
pub = EventMachine::HttpRequest.new(nginx_address + '/pub?id=').get :head => headers, :timeout => 30
pub.callback {
assert_equal(0, pub.response_header.content_length, "Should response only with headers")
assert_equal(400, pub.response_header.status, "Request was not understood as a bad request")
assert_equal("No channel id provided.", pub.response_header['X_NGINX_PUSHSTREAM_EXPLAIN'], "Didn't receive the right error message")
EventMachine.stop
}
}
end
def test_access_whith_channel_id_to_absent_channel
headers = {'accept' => 'application/json'}
channel_1 = 'ch_test_access_whith_channel_id_to_absent_channel_1'
channel_2 = 'ch_test_access_whith_channel_id_to_absent_channel_2'
body = 'body'
EventMachine.run {
pub_1 = EventMachine::HttpRequest.new(nginx_address + '/pub?id=' + channel_1.to_s).get :head => headers, :timeout => 30
pub_1.callback {
assert_equal(404, pub_1.response_header.status, "Channel was founded")
assert_equal(0, pub_1.response_header.content_length, "Recieved a non empty response")
EventMachine.stop
}
}
EventMachine.run {
pub_2 = EventMachine::HttpRequest.new(nginx_address + '/pub?id=' + channel_2.to_s ).post :head => headers, :body => body, :timeout => 30
pub_2.callback {
assert_equal(200, pub_2.response_header.status, "Request was not accepted")
assert_not_equal(0, pub_2.response_header.content_length, "Empty response was received")
response = JSON.parse(pub_2.response)
assert_equal(channel_2, response["channel"].to_s, "Channel was not recognized")
EventMachine.stop
}
}
end
def test_access_whith_channel_id_to_existing_channel
headers = {'accept' => 'application/json'}
channel = 'ch_test_access_whith_channel_id_to_existing_channel'
body = 'body'
#create channel
EventMachine.run {
pub_1 = EventMachine::HttpRequest.new(nginx_address + '/pub?id=' + channel.to_s).post :head => headers, :body => body, :timeout => 30
pub_1.callback {
assert_equal(200, pub_1.response_header.status, "Request was not accepted")
assert_not_equal(0, pub_1.response_header.content_length, "Empty response was received")
response = JSON.parse(pub_1.response)
assert_equal(channel, response["channel"].to_s, "Channel was not recognized")
EventMachine.stop
}
}
EventMachine.run {
pub_2 = EventMachine::HttpRequest.new(nginx_address + '/pub?id=' + channel.to_s).get :head => headers, :timeout => 30
pub_2.callback {
assert_equal(200, pub_2.response_header.status, "Request was not accepted")
assert_not_equal(0, pub_2.response_header.content_length, "Empty response was received")
response = JSON.parse(pub_2.response)
assert_equal(channel, response["channel"].to_s, "Channel was not recognized")
EventMachine.stop
}
}
end
def test_accepted_methods
EventMachine.run {
multi = EventMachine::MultiRequest.new
multi.add(:a, EventMachine::HttpRequest.new(nginx_address + '/pub?id=ch_test_accepted_methods_1').get)
multi.add(:b, EventMachine::HttpRequest.new(nginx_address + '/pub?id=ch_test_accepted_methods_2').put(:body => 'body'))
multi.add(:c, EventMachine::HttpRequest.new(nginx_address + '/pub?id=ch_test_accepted_methods_3').post)
multi.add(:d, EventMachine::HttpRequest.new(nginx_address + '/pub?id=ch_test_accepted_methods_4').delete)
multi.add(:e, EventMachine::HttpRequest.new(nginx_address + '/pub?id=ch_test_accepted_methods_5').head)
multi.callback {
assert_equal(5, multi.responses[:callback].length)
assert_not_equal(405, multi.responses[:callback][:a].response_header.status, "Publisher does accept GET")
assert_equal("GET", multi.responses[:callback][:a].req.method, "Array is with wrong order")
assert_equal(405, multi.responses[:callback][:b].response_header.status, "Publisher does not accept PUT")
assert_equal("GET, POST", multi.responses[:callback][:b].response_header['ALLOW'], "Didn't receive the right error message")
assert_equal("PUT", multi.responses[:callback][:b].req.method, "Array is with wrong order")
assert_not_equal(405, multi.responses[:callback][:c].response_header.status, "Publisher does accept POST")
assert_equal("POST", multi.responses[:callback][:c].req.method, "Array is with wrong order")
assert_equal(405, multi.responses[:callback][:d].response_header.status, "Publisher does not accept DELETE")
assert_equal("DELETE", multi.responses[:callback][:d].req.method, "Array is with wrong order")
assert_equal("GET, POST", multi.responses[:callback][:d].response_header['ALLOW'], "Didn't receive the right error message")
assert_equal(405, multi.responses[:callback][:e].response_header.status, "Publisher does not accept HEAD")
assert_equal("HEAD", multi.responses[:callback][:e].req.method, "Array is with wrong order")
assert_equal("GET, POST", multi.responses[:callback][:e].response_header['ALLOW'], "Didn't receive the right error message")
EventMachine.stop
}
}
end
def test_cannot_create_a_channel_with_id_ALL
headers = {'accept' => 'application/json'}
channel = 'ALL'
body = 'body'
EventMachine.run {
pub_1 = EventMachine::HttpRequest.new(nginx_address + '/pub?id=' + channel.to_s).post :head => headers, :body => body, :timeout => 30
pub_1.callback {
assert_equal(403, pub_1.response_header.status, "Channel was created")
assert_equal(0, pub_1.response_header.content_length, "Received response for creating channel with id ALL")
assert_equal("Channel id not authorized for this method.", pub_1.response_header['X_NGINX_PUSHSTREAM_EXPLAIN'], "Didn't receive the right error message")
EventMachine.stop
}
}
end
def test_cannot_create_a_channel_with_id_containing_wildcard
headers = {'accept' => 'application/json'}
body = 'body'
channel_1 = 'abcd*efgh'
channel_2 = '*abcdefgh'
channel_3 = 'abcdefgh*'
EventMachine.run {
multi = EventMachine::MultiRequest.new
multi.add(:a, EventMachine::HttpRequest.new(nginx_address + '/pub?id=' + channel_1).post(:head => headers, :body => body, :timeout => 30))
multi.add(:b, EventMachine::HttpRequest.new(nginx_address + '/pub?id=' + channel_2).post(:head => headers, :body => body, :timeout => 30))
multi.add(:c, EventMachine::HttpRequest.new(nginx_address + '/pub?id=' + channel_3).post(:head => headers, :body => body, :timeout => 30))
multi.callback {
assert_equal(3, multi.responses[:callback].length)
multi.responses[:callback].each do |name, response|
assert_equal(403, response.response_header.status, "Channel was created")
assert_equal(0, response.response_header.content_length, "Received response for creating channel with id containing wildcard")
assert_equal("Channel id not authorized for this method.", response.response_header['X_NGINX_PUSHSTREAM_EXPLAIN'], "Didn't receive the right error message")
end
EventMachine.stop
}
}
end
def config_test_post_message_larger_than_max_body_size_should_be_rejected
@client_max_body_size = '2k'
@client_body_buffer_size = '1k'
end
def test_post_message_larger_than_max_body_size_should_be_rejected
headers = {'accept' => 'application/json'}
channel = 'ch_test_post_message_larger_than_max_body_size_should_be_rejected'
body = '^'
(1..40).each do |n|
body += '0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789|'
end
body += '$'
EventMachine.run {
pub_1 = EventMachine::HttpRequest.new(nginx_address + '/pub?id=' + channel.to_s).post :head => headers, :body => body, :timeout => 30
pub_1.callback {
assert_equal(413, pub_1.response_header.status, "Request was accepted")
EventMachine.stop
}
}
end
def config_test_post_message_larger_than_body_buffer_size_should_be_accepted
@client_max_body_size = '10k'
@client_body_buffer_size = '1k'
end
def test_post_message_larger_than_body_buffer_size_should_be_accepted
headers = {'accept' => 'application/json'}
channel = 'ch_test_post_message_larger_than_body_buffer_size_should_be_accepted'
body = '^'
(1..80).each do |n|
body += '0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789|'
end
body += '$'
EventMachine.run {
pub_1 = EventMachine::HttpRequest.new(nginx_address + '/pub?id=' + channel.to_s).post :head => headers, :body => body, :timeout => 30
pub_1.callback {
assert_equal(200, pub_1.response_header.status, "Request was not accepted")
fail("Let a file on client body temp dir") unless Dir.entries(@client_body_temp).select {|f| f if File.file?(File.expand_path(f, @client_body_temp)) }.empty?
EventMachine.stop
}
}
end
def config_test_post_message_shorter_than_body_buffer_size_should_be_accepted
@client_max_body_size = '10k'
@client_body_buffer_size = '6k'
end
def test_post_message_shorter_than_body_buffer_size_should_be_accepted
headers = {'accept' => 'application/json'}
channel = 'ch_test_post_message_shorter_than_body_buffer_size_should_be_accepted'
body = '^'
(1..40).each do |n|
body += '0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789|'
end
body += '$'
EventMachine.run {
pub_1 = EventMachine::HttpRequest.new(nginx_address + '/pub?id=' + channel.to_s).post :head => headers, :body => body, :timeout => 30
pub_1.callback {
assert_equal(200, pub_1.response_header.status, "Request was not accepted")
fail("Let a file on client body temp dir") unless Dir.entries(@client_body_temp).select {|f| f if File.file?(File.expand_path(f, @client_body_temp)) }.empty?
EventMachine.stop
}
}
end
def config_test_stored_messages
@store_messages = "on"
end
def test_stored_messages
headers = {'accept' => 'application/json'}
body = 'published message'
channel = 'ch_test_stored_messages'
EventMachine.run {
pub_1 = EventMachine::HttpRequest.new(nginx_address + '/pub?id=' + channel.to_s ).post :head => headers, :body => body, :timeout => 30
pub_1.callback {
response = JSON.parse(pub_1.response)
assert_equal(1, response["stored_messages"].to_i, "Not stored messages")
pub_2 = EventMachine::HttpRequest.new(nginx_address + '/pub?id=' + channel.to_s ).post :head => headers, :body => body, :timeout => 30
pub_2.callback {
response = JSON.parse(pub_2.response)
assert_equal(2, response["stored_messages"].to_i, "Not stored messages")
EventMachine.stop
}
}
}
end
def config_test_not_stored_messages
@store_messages = "off"
end
def test_not_stored_messages
headers = {'accept' => 'application/json'}
body = 'published message'
channel = 'ch_test_not_stored_messages'
EventMachine.run {
pub = EventMachine::HttpRequest.new(nginx_address + '/pub?id=' + channel.to_s ).post :head => headers, :body => body, :timeout => 30
pub.callback {
response = JSON.parse(pub.response)
assert_equal(0, response["stored_messages"].to_i, "Stored messages")
EventMachine.stop
}
}
end
def config_test_max_stored_messages
@store_messages = "on"
@max_message_buffer_length = 4
end
def test_max_stored_messages
headers = {'accept' => 'application/json'}
body_prefix = 'published message '
channel = 'ch_test_max_stored_messages'
messagens_to_publish = 10
EventMachine.run {
i = 0
stored_messages = 0
EM.add_periodic_timer(0.001) do
i += 1
if i <= messagens_to_publish
pub = EventMachine::HttpRequest.new(nginx_address + '/pub?id=' + channel.to_s ).post :head => headers, :body => body_prefix + i.to_s, :timeout => 30
pub.callback {
response = JSON.parse(pub.response)
stored_messages = response["stored_messages"].to_i
}
else
EventMachine.stop
assert(stored_messages == @max_message_buffer_length, "Stored more messages then configured")
end
end
}
end
def config_test_max_channel_id_length
@max_channel_id_length = 5
end
def test_max_channel_id_length
headers = {'accept' => 'application/json'}
body = 'published message'
channel = '123456'
EventMachine.run {
pub = EventMachine::HttpRequest.new(nginx_address + '/pub?id=' + channel.to_s ).post :head => headers, :body => body, :timeout => 30
pub.callback {
assert_equal(0, pub.response_header.content_length, "Should response only with headers")
assert_equal(400, pub.response_header.status, "Request was not understood as a bad request")
assert_equal("Channel id is too large.", pub.response_header['X_NGINX_PUSHSTREAM_EXPLAIN'], "Didn't receive the right error message")
EventMachine.stop
}
}
end
def config_test_max_number_of_channels
@max_number_of_channels = 1
end
def test_max_number_of_channels
headers = {'accept' => 'application/json'}
body = 'published message'
channel = 'ch_test_max_number_of_channels_'
EventMachine.run {
pub = EventMachine::HttpRequest.new(nginx_address + '/pub?id=' + channel.to_s + 1.to_s).post :head => headers, :body => body, :timeout => 30
pub.callback {
assert_equal(200, pub.response_header.status, "Channel was not created")
assert_not_equal(0, pub.response_header.content_length, "Should response channel info")
EventMachine.stop
}
}
EventMachine.run {
pub = EventMachine::HttpRequest.new(nginx_address + '/pub?id=' + channel.to_s + 2.to_s).post :head => headers, :body => body, :timeout => 30
pub.callback {
assert_equal(403, pub.response_header.status, "Request was not forbidden")
assert_equal(0, pub.response_header.content_length, "Should response only with headers")
assert_equal("Number of channels were exceeded.", pub.response_header['X_NGINX_PUSHSTREAM_EXPLAIN'], "Didn't receive the right error message")
EventMachine.stop
}
}
end
def config_test_max_number_of_broadcast_channels
@max_number_of_broadcast_channels = 1
@broadcast_channel_prefix = 'bd_'
@broadcast_channel_max_qtd = 1
end
def test_max_number_of_broadcast_channels
headers = {'accept' => 'application/json'}
body = 'published message'
channel = 'bd_test_max_number_of_broadcast_channels_'
EventMachine.run {
pub = EventMachine::HttpRequest.new(nginx_address + '/pub?id=' + channel.to_s + 1.to_s).post :head => headers, :body => body, :timeout => 30
pub.callback {
assert_equal(200, pub.response_header.status, "Channel was not created")
assert_not_equal(0, pub.response_header.content_length, "Should response channel info")
EventMachine.stop
}
}
EventMachine.run {
pub = EventMachine::HttpRequest.new(nginx_address + '/pub?id=' + channel.to_s + 2.to_s).post :head => headers, :body => body, :timeout => 30
pub.callback {
assert_equal(403, pub.response_header.status, "Request was not forbidden")
assert_equal(0, pub.response_header.content_length, "Should response only with headers")
assert_equal("Number of channels were exceeded.", pub.response_header['X_NGINX_PUSHSTREAM_EXPLAIN'], "Didn't receive the right error message")
EventMachine.stop
}
}
end
def test_default_access_control_allow_origin_header
headers = {'accept' => 'application/json'}
channel = 'test_default_access_control_allow_origin_header'
EventMachine.run {
pub = EventMachine::HttpRequest.new(nginx_address + '/pub?id=' + channel).get :head => headers, :timeout => 30
pub.callback {
assert_equal("*", pub.response_header['ACCESS_CONTROL_ALLOW_ORIGIN'], "Didn't receive the right header")
EventMachine.stop
}
}
end
def config_test_custom_access_control_allow_origin_header
@allowed_origins = "custom.domain.com"
end
def test_custom_access_control_allow_origin_header
headers = {'accept' => 'application/json'}
channel = 'test_custom_access_control_allow_origin_header'
EventMachine.run {
pub = EventMachine::HttpRequest.new(nginx_address + '/pub?id=' + channel).get :head => headers, :timeout => 30
pub.callback {
assert_equal("custom.domain.com", pub.response_header['ACCESS_CONTROL_ALLOW_ORIGIN'], "Didn't receive the right header")
EventMachine.stop
}
}
end
end
require File.expand_path('base_test_case', File.dirname(__FILE__))
class TestPublisherAdmin < Test::Unit::TestCase
include BaseTestCase
def global_configuration
@publisher_mode = 'admin'
end
def test_admin_access_whithout_channel_id
headers = {'accept' => 'application/json'}
EventMachine.run {
pub = EventMachine::HttpRequest.new(nginx_address + '/pub?id=').get :head => headers, :timeout => 30
pub.callback {
assert_equal(0, pub.response_header.content_length, "Should response only with headers")
assert_equal(400, pub.response_header.status, "Request was not understood as a bad request")
assert_equal("No channel id provided.", pub.response_header['X_NGINX_PUSHSTREAM_EXPLAIN'], "Didn't receive the right error message")
EventMachine.stop
}
}
end
def test_admin_access_whith_channel_id_to_absent_channel
headers = {'accept' => 'application/json'}
channel_1 = 'ch_test_admin_access_whith_channel_id_to_absent_channel_1'
channel_2 = 'ch_test_admin_access_whith_channel_id_to_absent_channel_2'
body = 'body'
EventMachine.run {
pub_1 = EventMachine::HttpRequest.new(nginx_address + '/pub?id=' + channel_1.to_s).get :head => headers, :timeout => 30
pub_1.callback {
assert_equal(404, pub_1.response_header.status, "Channel was founded")
assert_equal(0, pub_1.response_header.content_length, "Recieved a non empty response")
EventMachine.stop
}
}
EventMachine.run {
pub_2 = EventMachine::HttpRequest.new(nginx_address + '/pub?id=' + channel_2.to_s ).post :head => headers, :body => body, :timeout => 30
pub_2.callback {
assert_equal(200, pub_2.response_header.status, "Request was not accepted")
assert_not_equal(0, pub_2.response_header.content_length, "Empty response was received")
response = JSON.parse(pub_2.response)
assert_equal(channel_2, response["channel"].to_s, "Channel was not recognized")
EventMachine.stop
}
}
end
def test_admin_access_whith_channel_id_to_existing_channel
headers = {'accept' => 'application/json'}
channel = 'ch_test_admin_access_whith_channel_id_to_existing_channel'
body = 'body'
#create channel
EventMachine.run {
pub_1 = EventMachine::HttpRequest.new(nginx_address + '/pub?id=' + channel.to_s).post :head => headers, :body => body, :timeout => 30
pub_1.callback {
assert_equal(200, pub_1.response_header.status, "Request was not accepted")
assert_not_equal(0, pub_1.response_header.content_length, "Empty response was received")
response = JSON.parse(pub_1.response)
assert_equal(channel, response["channel"].to_s, "Channel was not recognized")
EventMachine.stop
}
}
EventMachine.run {
pub_2 = EventMachine::HttpRequest.new(nginx_address + '/pub?id=' + channel.to_s).get :head => headers, :timeout => 30
pub_2.callback {
assert_equal(200, pub_2.response_header.status, "Request was not accepted")
assert_not_equal(0, pub_2.response_header.content_length, "Empty response was received")
response = JSON.parse(pub_2.response)
assert_equal(channel, response["channel"].to_s, "Channel was not recognized")
EventMachine.stop
}
}
end
def test_admin_accepted_methods
EventMachine.run {
multi = EventMachine::MultiRequest.new
multi.add(:a, EventMachine::HttpRequest.new(nginx_address + '/pub?id=ch_test_admin_accepted_methods_1').get)
multi.add(:b, EventMachine::HttpRequest.new(nginx_address + '/pub?id=ch_test_admin_accepted_methods_2').put(:body => 'body'))
multi.add(:c, EventMachine::HttpRequest.new(nginx_address + '/pub?id=ch_test_admin_accepted_methods_3').post)
multi.add(:d, EventMachine::HttpRequest.new(nginx_address + '/pub?id=ch_test_admin_accepted_methods_4').delete)
multi.add(:e, EventMachine::HttpRequest.new(nginx_address + '/pub?id=ch_test_admin_accepted_methods_5').head)
multi.callback {
assert_equal(5, multi.responses[:callback].length)
assert_not_equal(405, multi.responses[:callback][:a].response_header.status, "Publisher does accept GET")
assert_equal("GET", multi.responses[:callback][:a].req.method, "Array is with wrong order")
assert_equal(405, multi.responses[:callback][:b].response_header.status, "Publisher does not accept PUT")
assert_equal("GET, POST, DELETE", multi.responses[:callback][:b].response_header['ALLOW'], "Didn't receive the right error message")
assert_equal("PUT", multi.responses[:callback][:b].req.method, "Array is with wrong order")
assert_not_equal(405, multi.responses[:callback][:c].response_header.status, "Publisher does accept POST")
assert_equal("POST", multi.responses[:callback][:c].req.method, "Array is with wrong order")
assert_not_equal(405, multi.responses[:callback][:d].response_header.status, "Publisher does accept DELETE")
assert_equal("DELETE", multi.responses[:callback][:d].req.method, "Array is with wrong order")
assert_equal(405, multi.responses[:callback][:e].response_header.status, "Publisher does not accept HEAD")
assert_equal("HEAD", multi.responses[:callback][:e].req.method, "Array is with wrong order")
assert_equal("GET, POST, DELETE", multi.responses[:callback][:e].response_header['ALLOW'], "Didn't receive the right error message")
EventMachine.stop
}
}
end
def test_admin_cannot_create_a_channel_with_id_ALL
headers = {'accept' => 'application/json'}
channel = 'ALL'
body = 'body'
EventMachine.run {
pub_1 = EventMachine::HttpRequest.new(nginx_address + '/pub?id=' + channel.to_s).post :head => headers, :body => body, :timeout => 30
pub_1.callback {
assert_equal(403, pub_1.response_header.status, "Channel was created")
assert_equal(0, pub_1.response_header.content_length, "Received response for creating channel with id ALL")
assert_equal("Channel id not authorized for this method.", pub_1.response_header['X_NGINX_PUSHSTREAM_EXPLAIN'], "Didn't receive the right error message")
EventMachine.stop
}
}
end
def test_cannot_create_a_channel_with_id_containing_wildcard
headers = {'accept' => 'application/json'}
body = 'body'
channel_1 = 'abcd*efgh'
channel_2 = '*abcdefgh'
channel_3 = 'abcdefgh*'
EventMachine.run {
multi = EventMachine::MultiRequest.new
multi.add(:a, EventMachine::HttpRequest.new(nginx_address + '/pub?id=' + channel_1).post(:head => headers, :body => body, :timeout => 30))
multi.add(:b, EventMachine::HttpRequest.new(nginx_address + '/pub?id=' + channel_2).post(:head => headers, :body => body, :timeout => 30))
multi.add(:c, EventMachine::HttpRequest.new(nginx_address + '/pub?id=' + channel_3).post(:head => headers, :body => body, :timeout => 30))
multi.callback {
assert_equal(3, multi.responses[:callback].length)
multi.responses[:callback].each do |name, response|
assert_equal(403, response.response_header.status, "Channel was created")
assert_equal(0, response.response_header.content_length, "Received response for creating channel with id containing wildcard")
assert_equal("Channel id not authorized for this method.", response.response_header['X_NGINX_PUSHSTREAM_EXPLAIN'], "Didn't receive the right error message")
end
EventMachine.stop
}
}
end
def config_test_admin_post_message_larger_than_max_body_size_should_be_rejected
@client_max_body_size = '2k'
@client_body_buffer_size = '1k'
end
def test_admin_post_message_larger_than_max_body_size_should_be_rejected
headers = {'accept' => 'application/json'}
channel = 'ch_test_admin_post_message_larger_than_max_body_size_should_be_rejected'
body = '^'
(1..40).each do |n|
body += '0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789|'
end
body += '$'
EventMachine.run {
pub_1 = EventMachine::HttpRequest.new(nginx_address + '/pub?id=' + channel.to_s).post :head => headers, :body => body, :timeout => 30
pub_1.callback {
assert_equal(413, pub_1.response_header.status, "Request was accepted")
EventMachine.stop
}
}
end
def config_test_admin_post_message_larger_than_body_buffer_size_should_be_accepted
@client_max_body_size = '10k'
@client_body_buffer_size = '1k'
end
def test_admin_post_message_larger_than_body_buffer_size_should_be_accepted
headers = {'accept' => 'application/json'}
channel = 'ch_test_admin_post_message_larger_than_body_buffer_size_should_be_accepted'
body = '^'
(1..80).each do |n|
body += '0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789|'
end
body += '$'
EventMachine.run {
pub_1 = EventMachine::HttpRequest.new(nginx_address + '/pub?id=' + channel.to_s).post :head => headers, :body => body, :timeout => 30
pub_1.callback {
assert_equal(200, pub_1.response_header.status, "Request was not accepted")
fail("Let a file on client body temp dir") unless Dir.entries(@client_body_temp).select {|f| f if File.file?(File.expand_path(f, @client_body_temp)) }.empty?
EventMachine.stop
}
}
end
def config_test_admin_post_message_shorter_than_body_buffer_size_should_be_accepted
@client_max_body_size = '10k'
@client_body_buffer_size = '6k'
end
def test_admin_post_message_shorter_than_body_buffer_size_should_be_accepted
headers = {'accept' => 'application/json'}
channel = 'ch_test_admin_post_message_shorter_than_body_buffer_size_should_be_accepted'
body = '^'
(1..40).each do |n|
body += '0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789|'
end
body += '$'
EventMachine.run {
pub_1 = EventMachine::HttpRequest.new(nginx_address + '/pub?id=' + channel.to_s).post :head => headers, :body => body, :timeout => 30
pub_1.callback {
assert_equal(200, pub_1.response_header.status, "Request was not accepted")
fail("Let a file on client body temp dir") unless Dir.entries(@client_body_temp).select {|f| f if File.file?(File.expand_path(f, @client_body_temp)) }.empty?
EventMachine.stop
}
}
end
def config_test_admin_stored_messages
@store_messages = "on"
end
def test_admin_stored_messages
headers = {'accept' => 'application/json'}
body = 'published message'
channel = 'ch_test_admin_stored_messages'
EventMachine.run {
pub_1 = EventMachine::HttpRequest.new(nginx_address + '/pub?id=' + channel.to_s ).post :head => headers, :body => body, :timeout => 30
pub_1.callback {
response = JSON.parse(pub_1.response)
assert_equal(1, response["stored_messages"].to_i, "Not stored messages")
pub_2 = EventMachine::HttpRequest.new(nginx_address + '/pub?id=' + channel.to_s ).post :head => headers, :body => body, :timeout => 30
pub_2.callback {
response = JSON.parse(pub_2.response)
assert_equal(2, response["stored_messages"].to_i, "Not stored messages")
EventMachine.stop
}
}
}
end
def config_test_admin_not_stored_messages
@store_messages = "off"
end
def test_admin_not_stored_messages
headers = {'accept' => 'application/json'}
body = 'published message'
channel = 'ch_test_admin_not_stored_messages'
EventMachine.run {
pub = EventMachine::HttpRequest.new(nginx_address + '/pub?id=' + channel.to_s ).post :head => headers, :body => body, :timeout => 30
pub.callback {
response = JSON.parse(pub.response)
assert_equal(0, response["stored_messages"].to_i, "Stored messages")
EventMachine.stop
}
}
end
def config_test_admin_max_stored_messages
@store_messages = "on"
@max_message_buffer_length = 4
end
def test_admin_max_stored_messages
headers = {'accept' => 'application/json'}
body_prefix = 'published message '
channel = 'ch_test_admin_max_stored_messages'
messagens_to_publish = 10
EventMachine.run {
i = 0
stored_messages = 0
EM.add_periodic_timer(0.001) do
i += 1
if i <= messagens_to_publish
pub = EventMachine::HttpRequest.new(nginx_address + '/pub?id=' + channel.to_s ).post :head => headers, :body => body_prefix + i.to_s, :timeout => 30
pub.callback {
response = JSON.parse(pub.response)
stored_messages = response["stored_messages"].to_i
}
else
EventMachine.stop
assert(stored_messages == @max_message_buffer_length, "Stored more messages then configured")
end
end
}
end
def config_test_admin_max_channel_id_length
@max_channel_id_length = 5
end
def test_admin_max_channel_id_length
headers = {'accept' => 'application/json'}
body = 'published message'
channel = '123456'
EventMachine.run {
pub = EventMachine::HttpRequest.new(nginx_address + '/pub?id=' + channel.to_s ).post :head => headers, :body => body, :timeout => 30
pub.callback {
assert_equal(0, pub.response_header.content_length, "Should response only with headers")
assert_equal(400, pub.response_header.status, "Request was not understood as a bad request")
assert_equal("Channel id is too large.", pub.response_header['X_NGINX_PUSHSTREAM_EXPLAIN'], "Didn't receive the right error message")
EventMachine.stop
}
}
end
def config_test_admin_max_number_of_channels
@max_number_of_channels = 1
end
def test_admin_max_number_of_channels
headers = {'accept' => 'application/json'}
body = 'published message'
channel = 'ch_test_admin_max_number_of_channels_'
EventMachine.run {
pub = EventMachine::HttpRequest.new(nginx_address + '/pub?id=' + channel.to_s + 1.to_s).post :head => headers, :body => body, :timeout => 30
pub.callback {
assert_equal(200, pub.response_header.status, "Channel was not created")
assert_not_equal(0, pub.response_header.content_length, "Should response channel info")
EventMachine.stop
}
}
EventMachine.run {
pub = EventMachine::HttpRequest.new(nginx_address + '/pub?id=' + channel.to_s + 2.to_s).post :head => headers, :body => body, :timeout => 30
pub.callback {
assert_equal(403, pub.response_header.status, "Request was not forbidden")
assert_equal(0, pub.response_header.content_length, "Should response only with headers")
assert_equal("Number of channels were exceeded.", pub.response_header['X_NGINX_PUSHSTREAM_EXPLAIN'], "Didn't receive the right error message")
EventMachine.stop
}
}
end
def config_test_admin_max_number_of_broadcast_channels
@max_number_of_broadcast_channels = 1
@broadcast_channel_prefix = 'bd_'
@broadcast_channel_max_qtd = 1
end
def test_admin_max_number_of_broadcast_channels
headers = {'accept' => 'application/json'}
body = 'published message'
channel = 'bd_test_admin_max_number_of_broadcast_channels_'
EventMachine.run {
pub = EventMachine::HttpRequest.new(nginx_address + '/pub?id=' + channel.to_s + 1.to_s).post :head => headers, :body => body, :timeout => 30
pub.callback {
assert_equal(200, pub.response_header.status, "Channel was not created")
assert_not_equal(0, pub.response_header.content_length, "Should response channel info")
EventMachine.stop
}
}
EventMachine.run {
pub = EventMachine::HttpRequest.new(nginx_address + '/pub?id=' + channel.to_s + 2.to_s).post :head => headers, :body => body, :timeout => 30
pub.callback {
assert_equal(403, pub.response_header.status, "Request was not forbidden")
assert_equal(0, pub.response_header.content_length, "Should response only with headers")
assert_equal("Number of channels were exceeded.", pub.response_header['X_NGINX_PUSHSTREAM_EXPLAIN'], "Didn't receive the right error message")
EventMachine.stop
}
}
end
def test_delete_channel_whithout_subscribers
headers = {'accept' => 'application/json'}
body = 'published message'
channel = 'test_delete_channel_whithout_subscribers'
publish_message(channel, headers, body)
EventMachine.run {
pub = EventMachine::HttpRequest.new(nginx_address + '/pub?id=' + channel.to_s).delete :head => headers, :timeout => 30
pub.callback {
assert_equal(200, pub.response_header.status, "Request was not received")
assert_equal(0, pub.response_header.content_length, "Should response only with headers")
assert_equal("Channel deleted.", pub.response_header['X_NGINX_PUSHSTREAM_EXPLAIN'], "Didn't receive the right error message")
stats = EventMachine::HttpRequest.new(nginx_address + '/channels-stats').get :head => headers, :timeout => 30
stats.callback {
assert_equal(200, stats.response_header.status, "Don't get channels statistics")
assert_not_equal(0, stats.response_header.content_length, "Don't received channels statistics")
begin
response = JSON.parse(stats.response)
assert(response.has_key?("channels"), "Didn't received the correct answer with channels info")
assert_equal(0, response["channels"].to_i, "Returned values with channels created")
rescue JSON::ParserError
fail("Didn't receive a valid response")
end
EventMachine.stop
}
}
}
end
def config_test_delete_channel_whith_subscriber_in_one_channel
@header_template = " " # send a space as header to has a chunk received
@footer_template = nil
@ping_message_interval = nil
@message_template = '{\"id\":\"~id~\", \"channel\":\"~channel~\", \"text\":\"~text~\"}'
end
def test_delete_channel_whith_subscriber_in_one_channel
headers = {'accept' => 'application/json'}
body = 'published message'
channel = 'test_delete_channel_whith_subscriber_in_one_channel'
resp = ""
EventMachine.run {
sub_1 = EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel.to_s).get :head => headers, :timeout => 30
sub_1.stream { |chunk|
resp = resp + chunk
if resp.strip.empty?
stats = EventMachine::HttpRequest.new(nginx_address + '/channels-stats').get :head => {'accept' => 'application/json'}, :timeout => 30
stats.callback {
assert_equal(200, stats.response_header.status, "Don't get channels statistics")
assert_not_equal(0, stats.response_header.content_length, "Don't received channels statistics")
begin
response = JSON.parse(stats.response)
assert_equal(1, response["subscribers"].to_i, "Subscriber was not created")
assert_equal(1, response["channels"].to_i, "Channel was not created")
pub = EventMachine::HttpRequest.new(nginx_address + '/pub?id=' + channel.to_s).delete :head => headers, :timeout => 30
pub.callback {
assert_equal(200, pub.response_header.status, "Request was not received")
assert_equal(0, pub.response_header.content_length, "Should response only with headers")
assert_equal("Channel deleted.", pub.response_header['X_NGINX_PUSHSTREAM_EXPLAIN'], "Didn't receive the right error message")
}
rescue JSON::ParserError
fail("Didn't receive a valid response")
end
}
else
begin
response = JSON.parse(resp)
assert_equal(channel, response["channel"], "Wrong channel")
assert_equal(-2, response["id"].to_i, "Wrong message id")
assert_equal("Channel deleted", response["text"], "Wrong message text")
stats = EventMachine::HttpRequest.new(nginx_address + '/channels-stats').get :head => {'accept' => 'application/json'}, :timeout => 30
stats.callback {
assert_equal(200, stats.response_header.status, "Don't get channels statistics")
assert_not_equal(0, stats.response_header.content_length, "Don't received channels statistics")
response = JSON.parse(stats.response)
assert_equal(0, response["subscribers"].to_i, "Subscriber was not deleted")
assert_equal(0, response["channels"].to_i, "Channel was not deleted")
}
rescue JSON::ParserError
fail("Didn't receive a valid response")
end
EventMachine.stop
end
}
add_test_timeout
}
end
def config_test_delete_channel_whith_subscriber_in_two_channels
@header_template = " " # send a space as header to has a chunk received
@footer_template = nil
@ping_message_interval = nil
@message_template = '{\"id\":\"~id~\", \"channel\":\"~channel~\", \"text\":\"~text~\"}'
end
def test_delete_channel_whith_subscriber_in_two_channels
headers = {'accept' => 'application/json'}
body = 'published message'
channel_1 = 'test_delete_channel_whith_subscriber_in_two_channels_1'
channel_2 = 'test_delete_channel_whith_subscriber_in_two_channels_2'
stage1_complete = false
stage2_complete = false
resp = ""
EventMachine.run {
sub_1 = EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel_1.to_s + '/' + channel_2.to_s).get :head => headers, :timeout => 30
sub_1.stream { |chunk|
resp = resp + chunk
if resp.strip.empty?
stats = EventMachine::HttpRequest.new(nginx_address + '/channels-stats').get :head => {'accept' => 'application/json'}, :timeout => 30
stats.callback {
assert_equal(200, stats.response_header.status, "Don't get channels statistics")
assert_not_equal(0, stats.response_header.content_length, "Don't received channels statistics")
begin
response = JSON.parse(stats.response)
assert_equal(1, response["subscribers"].to_i, "Subscriber was not created")
assert_equal(2, response["channels"].to_i, "Channel was not created")
pub = EventMachine::HttpRequest.new(nginx_address + '/pub?id=' + channel_1.to_s).delete :head => headers, :timeout => 30
pub.callback {
assert_equal(200, pub.response_header.status, "Request was not received")
assert_equal(0, pub.response_header.content_length, "Should response only with headers")
assert_equal("Channel deleted.", pub.response_header['X_NGINX_PUSHSTREAM_EXPLAIN'], "Didn't receive the right error message")
}
rescue JSON::ParserError
fail("Didn't receive a valid response")
end
}
else
begin
if !stage1_complete
stage1_complete = true
response = JSON.parse(resp)
assert_equal(channel_1, response["channel"], "Wrong channel")
assert_equal(-2, response["id"].to_i, "Wrong message id")
assert_equal("Channel deleted", response["text"], "Wrong message text")
stats = EventMachine::HttpRequest.new(nginx_address + '/channels-stats').get :head => {'accept' => 'application/json'}, :timeout => 30
stats.callback {
assert_equal(200, stats.response_header.status, "Don't get channels statistics")
assert_not_equal(0, stats.response_header.content_length, "Don't received channels statistics")
response = JSON.parse(stats.response)
assert_equal(1, response["subscribers"].to_i, "Subscriber was not deleted")
assert_equal(1, response["channels"].to_i, "Channel was not deleted")
pub = EventMachine::HttpRequest.new(nginx_address + '/pub?id=' + channel_2.to_s).post :head => headers, :body=> body, :timeout => 30
pub.callback {
assert_equal(200, pub.response_header.status, "Request was not received")
}
}
elsif !stage2_complete
stage2_complete = true
response = JSON.parse(resp.split("\r\n")[2])
assert_equal(channel_2, response["channel"], "Wrong channel")
assert_equal(1, response["id"].to_i, "Wrong message id")
assert_equal(body, response["text"], "Wrong message id")
pub = EventMachine::HttpRequest.new(nginx_address + '/pub?id=' + channel_2.to_s).delete :head => headers, :timeout => 30
pub.callback {
assert_equal(200, pub.response_header.status, "Request was not received")
assert_equal(0, pub.response_header.content_length, "Should response only with headers")
assert_equal("Channel deleted.", pub.response_header['X_NGINX_PUSHSTREAM_EXPLAIN'], "Didn't receive the right error message")
}
else
response = JSON.parse(resp.split("\r\n")[3])
assert_equal(channel_2, response["channel"], "Wrong channel")
assert_equal(-2, response["id"].to_i, "Wrong message id")
assert_equal("Channel deleted", response["text"], "Wrong message text")
stats = EventMachine::HttpRequest.new(nginx_address + '/channels-stats').get :head => {'accept' => 'application/json'}, :timeout => 30
stats.callback {
assert_equal(200, stats.response_header.status, "Don't get channels statistics")
assert_not_equal(0, stats.response_header.content_length, "Don't received channels statistics")
response = JSON.parse(stats.response)
assert_equal(0, response["subscribers"].to_i, "Subscriber was not deleted")
assert_equal(0, response["channels"].to_i, "Channel was not deleted")
EventMachine.stop
}
end
rescue JSON::ParserError
EventMachine.stop
fail("Didn't receive a valid response")
end
end
}
add_test_timeout
}
end
def config_test_delete_channels_whith_subscribers
@header_template = nil
@footer_template = "FOOTER"
@ping_message_interval = nil
@memory_cleanup_timeout = nil
@message_template = '{\"id\":\"~id~\", \"channel\":\"~channel~\", \"text\":\"~text~\"}'
end
def test_delete_channels_whith_subscribers
headers = {'accept' => 'application/json'}
body = 'published message'
channel_1 = 'test_delete_channels_whith_subscribers_1'
channel_2 = 'test_delete_channels_whith_subscribers_2'
EventMachine.run {
resp_1 = ""
sub_1 = EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel_1.to_s).get :head => headers, :timeout => 30
sub_1.stream { |chunk|
resp_1 += chunk
}
sub_1.callback {
assert_equal("{\"id\":\"-2\", \"channel\":\"test_delete_channels_whith_subscribers_1\", \"text\":\"Channel deleted\"}\r\nFOOTER\r\n", resp_1, "Subscriber was not created")
}
resp_2 = ""
sub_2 = EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel_2.to_s).get :head => headers, :timeout => 30
sub_2.stream { |chunk|
resp_2 += chunk
}
sub_2.callback {
assert_equal("{\"id\":\"-2\", \"channel\":\"test_delete_channels_whith_subscribers_2\", \"text\":\"Channel deleted\"}\r\nFOOTER\r\n", resp_2, "Subscriber was not created")
}
stats = EventMachine::HttpRequest.new(nginx_address + '/channels-stats').get :head => {'accept' => 'application/json'}, :timeout => 30
stats.callback {
assert_equal(200, stats.response_header.status, "Don't get channels statistics")
assert_not_equal(0, stats.response_header.content_length, "Don't received channels statistics")
begin
response = JSON.parse(stats.response)
assert_equal(2, response["subscribers"].to_i, "Subscriber was not created")
assert_equal(2, response["channels"].to_i, "Channel was not created")
rescue JSON::ParserError
fail("Didn't receive a valid response")
end
}
pub_1 = EventMachine::HttpRequest.new(nginx_address + '/pub?id=' + channel_1.to_s).delete :head => headers, :timeout => 30
pub_1.callback {
assert_equal(200, pub_1.response_header.status, "Request was not received")
assert_equal(0, pub_1.response_header.content_length, "Should response only with headers")
assert_equal("Channel deleted.", pub_1.response_header['X_NGINX_PUSHSTREAM_EXPLAIN'], "Didn't receive the right error message")
}
pub_2 = EventMachine::HttpRequest.new(nginx_address + '/pub?id=' + channel_2.to_s).delete :head => headers, :timeout => 30
pub_2.callback {
assert_equal(200, pub_2.response_header.status, "Request was not received")
assert_equal(0, pub_2.response_header.content_length, "Should response only with headers")
assert_equal("Channel deleted.", pub_2.response_header['X_NGINX_PUSHSTREAM_EXPLAIN'], "Didn't receive the right error message")
}
EM.add_timer(5) {
stats_2 = EventMachine::HttpRequest.new(nginx_address + '/channels-stats').get :head => {'accept' => 'application/json'}, :timeout => 30
stats_2.callback {
assert_equal(200, stats_2.response_header.status, "Don't get channels statistics")
assert_not_equal(0, stats_2.response_header.content_length, "Don't received channels statistics")
begin
response = JSON.parse(stats_2.response)
assert_equal(0, response["subscribers"].to_i, "Subscriber was not created")
assert_equal(0, response["channels"].to_i, "Channel was not created")
rescue JSON::ParserError
fail("Didn't receive a valid response")
end
EventMachine.stop
}
}
add_test_timeout(10)
}
end
def config_test_receive_footer_template_when_channel_is_deleted
@header_template = "HEADER_TEMPLATE"
@footer_template = "FOOTER_TEMPLATE"
@ping_message_interval = nil
@message_template = '~text~'
end
def test_receive_footer_template_when_channel_is_deleted
headers = {'accept' => 'application/json'}
body = 'published message'
channel = 'ch_test_receive_footer_template_when_channel_is_deleted'
resp = ""
EventMachine.run {
sub_1 = EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel.to_s).get :head => headers, :timeout => 30
sub_1.stream { |chunk|
resp = resp + chunk
if resp == "#{@header_template}\r\n"
pub = EventMachine::HttpRequest.new(nginx_address + '/pub?id=' + channel.to_s).delete :head => headers, :timeout => 30
pub.callback {
assert_equal(200, pub.response_header.status, "Request was not received")
assert_equal(0, pub.response_header.content_length, "Should response only with headers")
assert_equal("Channel deleted.", pub.response_header['X_NGINX_PUSHSTREAM_EXPLAIN'], "Didn't receive the right error message")
}
end
}
sub_1.callback {
assert_equal("#{@header_template}\r\nChannel deleted\r\n#{@footer_template}\r\n", resp, "Didn't receive complete message")
EventMachine.stop
}
add_test_timeout
}
end
def config_test_different_header_and_footer_template_by_location
@header_template = "HEADER_TEMPLATE"
@footer_template = "FOOTER_TEMPLATE"
@header_template2 = "<html><body>"
@footer_template2 = "</body></html>"
@ping_message_interval = nil
@message_template = '~text~'
@extra_location = %{
location ~ /sub2/(.*)? {
# activate subscriber mode for this location
push_stream_subscriber;
# positional channel path
set $push_stream_channels_path $1;
push_stream_header_template "#{@header_template2}";
push_stream_footer_template "#{@footer_template2}";
push_stream_message_template "|~text~|";
}
}
end
def test_different_header_and_footer_template_by_location
headers = {'accept' => 'application/json'}
body = 'published message'
channel = 'ch_test_different_header_and_footer_template_by_location'
resp = ""
resp2 = ""
EventMachine.run {
sub_1 = EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel.to_s).get :head => headers, :timeout => 30
sub_1.stream { |chunk|
resp = resp + chunk
}
sub_2 = EventMachine::HttpRequest.new(nginx_address + '/sub2/' + channel.to_s).get :head => headers, :timeout => 30
sub_2.stream { |chunk|
resp2 = resp2 + chunk
}
EM.add_timer(1) do
pub = EventMachine::HttpRequest.new(nginx_address + '/pub?id=' + channel.to_s).delete :head => headers, :timeout => 30
pub.callback {
assert_equal(200, pub.response_header.status, "Request was not received")
assert_equal(0, pub.response_header.content_length, "Should response only with headers")
assert_equal("Channel deleted.", pub.response_header['X_NGINX_PUSHSTREAM_EXPLAIN'], "Didn't receive the right error message")
}
end
EM.add_timer(2) do
assert_equal("#{@header_template}\r\nChannel deleted\r\n#{@footer_template}\r\n", resp, "Didn't receive complete message")
assert_equal("#{@header_template2}\r\n|Channel deleted|\r\n#{@footer_template2}\r\n", resp2, "Didn't receive complete message")
EventMachine.stop
end
add_test_timeout
}
end
def config_test_custom_channel_deleted_message_text
@channel_deleted_message_text = "Channel has gone away."
@header_template = " " # send a space as header to has a chunk received
@footer_template = nil
@ping_message_interval = nil
@message_template = '{\"id\":\"~id~\", \"channel\":\"~channel~\", \"text\":\"~text~\"}'
end
def test_custom_channel_deleted_message_text
headers = {'accept' => 'application/json'}
body = 'published message'
channel = 'test_custom_channel_deleted_message_text'
resp = ""
EventMachine.run {
sub_1 = EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel.to_s).get :head => headers, :timeout => 30
sub_1.stream { |chunk|
resp = resp + chunk
if resp.strip.empty?
pub = EventMachine::HttpRequest.new(nginx_address + '/pub?id=' + channel.to_s).delete :head => headers, :timeout => 30
pub.callback {
assert_equal(200, pub.response_header.status, "Request was not received")
assert_equal(0, pub.response_header.content_length, "Should response only with headers")
assert_equal("Channel deleted.", pub.response_header['X_NGINX_PUSHSTREAM_EXPLAIN'], "Didn't receive the right error message")
}
else
begin
response = JSON.parse(resp)
assert_equal(channel, response["channel"], "Wrong channel")
assert_equal(-2, response["id"].to_i, "Wrong message id")
assert_equal(@channel_deleted_message_text, response["text"], "Wrong message text")
rescue JSON::ParserError
fail("Didn't receive a valid response")
end
EventMachine.stop
end
}
add_test_timeout
}
end
end
require File.expand_path('base_test_case', File.dirname(__FILE__))
class TestSendSignals < Test::Unit::TestCase
include BaseTestCase
def global_configuration
ENV['NGINX_WORKERS'] = '1'
@memory_cleanup_timeout = '40s'
@min_message_buffer_timeout = '60s'
@subscriber_connection_timeout = '65s'
@master_process = 'on'
@daemon = 'on'
@header_template = 'HEADER'
@disable_ignore_childs = true
end
def test_send_hup_signal
headers = {'accept' => 'application/json'}
channel = 'ch_test_send_hup_signal'
body = 'body'
response = ''
response2 = ''
pid = 0
pid2 = 0
EventMachine.run {
# create subscriber
sub_1 = EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel.to_s).get :head => headers, :timeout => 30
sub_1.stream { |chunk|
response = response + chunk
if response.strip == @header_template
# check statistics
pub_1 = EventMachine::HttpRequest.new(nginx_address + '/channels-stats').get :head => headers, :timeout => 30
pub_1.callback {
assert_equal(200, pub_1.response_header.status, "Don't get channels statistics")
assert_not_equal(0, pub_1.response_header.content_length, "Don't received channels statistics")
resp_1 = JSON.parse(pub_1.response)
assert(resp_1.has_key?("channels"), "Didn't received the correct answer with channels info")
assert_equal(1, resp_1["channels"].to_i, "Didn't create channel")
assert_equal(1, resp_1["by_worker"].count, "Didn't return infos by_worker")
pid = resp_1["by_worker"][0]['pid'].to_i
# send reload signal
`#{ nginx_executable } -c #{ config_filename } -s reload > /dev/null 2>&1`
}
end
}
conectted_after_reloaded = false
i = 0
# check if first worker die
EM.add_periodic_timer(0.5) do
# check statistics again
pub_4 = EventMachine::HttpRequest.new(nginx_address + '/channels-stats').get :head => headers, :timeout => 30
pub_4.callback {
resp_3 = JSON.parse(pub_4.response)
assert(resp_3.has_key?("by_worker"), "Didn't received the correct answer with channels info")
if resp_3["by_worker"].count == 2 && !conectted_after_reloaded
conectted_after_reloaded = true
# publish a message
pub_2 = EventMachine::HttpRequest.new(nginx_address + '/pub?id=' + channel.to_s).post :head => headers, :body => body, :timeout => 30
pub_2.callback {
# add new subscriber
sub_2 = EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel.to_s + '.b1').get :head => headers, :timeout => 30
sub_2.stream { |chunk|
response2 = response2 + chunk
if response2.strip == @header_template
# check statistics again
pub_3 = EventMachine::HttpRequest.new(nginx_address + '/channels-stats').get :head => headers, :timeout => 30
pub_3.callback {
resp_2 = JSON.parse(pub_3.response)
assert(resp_2.has_key?("channels"), "Didn't received the correct answer with channels info")
assert_equal(1, resp_2["channels"].to_i, "Didn't create channel")
assert_equal(1, resp_2["published_messages"].to_i, "Didn't create messages")
assert_equal(2, resp_2["subscribers"].to_i, "Didn't create subscribers")
assert_equal(2, resp_2["by_worker"].count, "Didn't return infos by_worker")
}
end
}
}
end
if resp_3["by_worker"].count == 1 && conectted_after_reloaded
assert_equal(1, resp_3["channels"].to_i, "Didn't create channel")
assert_equal(1, resp_3["published_messages"].to_i, "Didn't create messages")
assert_equal(1, resp_3["subscribers"].to_i, "Didn't create subscribers")
assert_equal(1, resp_3["by_worker"].count, "Didn't return infos by_worker")
pid2 = resp_3["by_worker"][0]['pid'].to_i
assert_not_equal(pid, pid2, "Didn't recreate worker")
EventMachine.stop
end
i = i + 1
if i == 120
fail("Worker didn't die in 60 seconds")
EventMachine.stop
end
}
end
add_test_timeout(60)
}
end
def test_reload_with_different_shared_memory_size
headers = {'accept' => 'application/json'}
channel = 'ch_test_reload_with_different_shared_memory_size'
body = 'body'
EventMachine.run do
publish_message_inline(channel, headers, body)
# check statistics
pub_1 = EventMachine::HttpRequest.new(nginx_address + '/channels-stats').get :head => headers, :timeout => 30
pub_1.callback do
assert_equal(200, pub_1.response_header.status, "Don't get channels statistics")
assert_not_equal(0, pub_1.response_header.content_length, "Don't received channels statistics")
resp_1 = JSON.parse(pub_1.response)
assert(resp_1.has_key?("channels"), "Didn't received the correct answer with channels info")
assert_equal(1, resp_1["channels"].to_i, "Didn't create channel")
assert_equal(1, resp_1["published_messages"].to_i, "Didn't create messages")
@max_reserved_memory = '20m'
create_config_file
# send reload signal
`#{ nginx_executable } -c #{ config_filename } -s reload > /dev/null 2>&1`
sleep 5
pub_2 = EventMachine::HttpRequest.new(nginx_address + '/channels-stats').get :head => headers, :timeout => 30
pub_2.callback do
assert_equal(200, pub_2.response_header.status, "Don't get channels statistics")
assert_not_equal(0, pub_2.response_header.content_length, "Don't received channels statistics")
resp_2 = JSON.parse(pub_2.response)
assert(resp_2.has_key?("channels"), "Didn't received the correct answer with channels info")
assert_equal(1, resp_2["channels"].to_i, "Didn't create channel")
assert_equal(1, resp_2["published_messages"].to_i, "Didn't create messages")
error_log = File.read(@main_error_log)
assert(error_log.include?("Cannot change memory area size without restart, ignoring change"), "Didn't log error message")
EventMachine.stop
end
end
add_test_timeout(10)
end
end
end
require File.expand_path('base_test_case', File.dirname(__FILE__))
class TestSetuParameters < Test::Unit::TestCase
include BaseTestCase
def global_configuration
@disable_start_stop_server = true
end
def test_ping_message_interval_cannot_be_zero
expected_error_message = "push_stream_ping_message_interval cannot be zero"
@ping_message_interval = 0
self.create_config_file
stderr_msg = self.start_server
assert(stderr_msg.include?(expected_error_message), "Message error not founded: '#{ expected_error_message }' recieved '#{ stderr_msg }'")
end
def test_message_template_cannot_be_blank
expected_error_message = "push_stream_message_template cannot be blank"
@message_template = ""
self.create_config_file
stderr_msg = self.start_server
assert(stderr_msg.include?(expected_error_message), "Message error not founded: '#{ expected_error_message }' recieved '#{ stderr_msg }'")
end
def test_subscriber_connection_timeout_cannot_be_zero
expected_error_message = "push_stream_subscriber_connection_ttl cannot be zero"
@subscriber_connection_timeout = 0
self.create_config_file
stderr_msg = self.start_server
assert(stderr_msg.include?(expected_error_message), "Message error not founded: '#{ expected_error_message }' recieved '#{ stderr_msg }'")
end
def test_longpolling_connection_ttl_cannot_be_zero
expected_error_message = "push_stream_longpolling_connection_ttl cannot be zero"
@longpolling_connection_ttl = 0
self.create_config_file
stderr_msg = self.start_server
assert(stderr_msg.include?(expected_error_message), "Message error not founded: '#{ expected_error_message }' recieved '#{ stderr_msg }'")
end
def test_max_channel_id_length_cannot_be_zero
expected_error_message = "push_stream_max_channel_id_length cannot be zero"
@max_channel_id_length = 0
self.create_config_file
stderr_msg = self.start_server
assert(stderr_msg.include?(expected_error_message), "Message error not founded: '#{ expected_error_message }' recieved '#{ stderr_msg }'")
end
def test_min_message_buffer_timeout_cannot_be_zero
expected_error_message = "push_stream_message_ttl cannot be zero"
@min_message_buffer_timeout = 0
self.create_config_file
stderr_msg = self.start_server
assert(stderr_msg.include?(expected_error_message), "Message error not founded: '#{ expected_error_message }' recieved '#{ stderr_msg }'")
end
def test_max_subscribers_per_channel_cannot_be_zero
expected_error_message = "push_stream_max_subscribers_per_channel cannot be zero"
@max_subscribers_per_channel = 0
self.create_config_file
stderr_msg = self.start_server
assert(stderr_msg.include?(expected_error_message), "Message error not founded: '#{ expected_error_message }' recieved '#{ stderr_msg }'")
end
def test_max_messages_stored_per_channel_cannot_be_zero
expected_error_message = "push_stream_max_messages_stored_per_channel cannot be zero"
@max_message_buffer_length = 0
self.create_config_file
stderr_msg = self.start_server
assert(stderr_msg.include?(expected_error_message), "Message error not founded: '#{ expected_error_message }' recieved '#{ stderr_msg }'")
end
def test_broadcast_channel_max_qtd_cannot_be_zero
expected_error_message = "push_stream_broadcast_channel_max_qtd cannot be zero"
@broadcast_channel_max_qtd = 0
self.create_config_file
stderr_msg = self.start_server
assert(stderr_msg.include?(expected_error_message), "Message error not founded: '#{ expected_error_message }' recieved '#{ stderr_msg }'")
end
def test_broadcast_channel_max_qtd_cannot_be_set_without_broadcast_channel_prefix
expected_error_message = "cannot set broadcast channel max qtd if push_stream_broadcast_channel_prefix is not set or blank"
@broadcast_channel_max_qtd = 1
self.create_config_file
stderr_msg = self.start_server
assert(stderr_msg.include?(expected_error_message), "Message error not founded: '#{ expected_error_message }' recieved '#{ stderr_msg }'")
end
def test_broadcast_channel_max_qtd_cannot_be_set_without_broadcast_channel_prefix
expected_error_message = "cannot set broadcast channel max qtd if push_stream_broadcast_channel_prefix is not set or blank"
@broadcast_channel_max_qtd = 1
@broadcast_channel_prefix = ""
self.create_config_file
stderr_msg = self.start_server
assert(stderr_msg.include?(expected_error_message), "Message error not founded: '#{ expected_error_message }' recieved '#{ stderr_msg }'")
end
def test_max_number_of_channels_cannot_be_zero
expected_error_message = "push_stream_max_number_of_channels cannot be zero"
@max_number_of_channels = 0
self.create_config_file
stderr_msg = self.start_server
assert(stderr_msg.include?(expected_error_message), "Message error not founded: '#{ expected_error_message }' recieved '#{ stderr_msg }'")
end
def test_max_number_of_broadcast_channels_cannot_be_zero
expected_error_message = "push_stream_max_number_of_broadcast_channels cannot be zero"
@max_number_of_broadcast_channels = 0
self.create_config_file
stderr_msg = self.start_server
assert(stderr_msg.include?(expected_error_message), "Message error not founded: '#{ expected_error_message }' recieved '#{ stderr_msg }'")
end
def test_max_number_of_broadcast_channels_cannot_be_smaller_than_broadcast_channel_max_qtd
expected_error_message = "max number of broadcast channels cannot be smaller than value in push_stream_broadcast_channel_max_qtd"
@max_number_of_broadcast_channels = 3
@broadcast_channel_max_qtd = 4
@broadcast_channel_prefix = "broad_"
self.create_config_file
stderr_msg = self.start_server
assert(stderr_msg.include?(expected_error_message), "Message error not founded: '#{ expected_error_message }' recieved '#{ stderr_msg }'")
end
def test_memory_cleanup_timeout
expected_error_message = "memory cleanup objects ttl cannot't be less than 30."
@memory_cleanup_timeout = '15s'
self.create_config_file
stderr_msg = self.start_server
assert(stderr_msg.include?(expected_error_message), "Message error not founded: '#{ expected_error_message }' recieved '#{ stderr_msg }'")
end
def config_test_http_not_configured
@test_config_file = "test_http_not_configured.conf"
@config_template = %q{
pid <%= @pid_file %>;
error_log <%= @main_error_log %> debug;
# Development Mode
master_process off;
daemon off;
worker_processes <%=nginx_workers%>;
events {
worker_connections 1024;
use <%= (RUBY_PLATFORM =~ /darwin/) ? 'kqueue' : 'epoll' %>;
}
}
end
def test_http_not_configured
expected_error_message = "ngx_http_push_stream_module will not be used with this configuration."
self.create_config_file
self.start_server
log_file = File.read(@main_error_log)
assert(log_file.include?(expected_error_message), "Message error not founded: '#{ expected_error_message }' recieved '#{ log_file }'")
ensure
self.stop_server
end
def test_invalid_push_mode
expected_error_message = "invalid push_stream_subscriber mode value: unknown, accepted values (streaming, polling, long-polling)"
@subscriber_mode = "unknown"
self.create_config_file
stderr_msg = self.start_server
assert(stderr_msg.include?(expected_error_message), "Message error not founded: '#{ expected_error_message }' recieved '#{ stderr_msg }'")
end
def test_valid_push_mode
expected_error_message = "invalid push_stream_subscriber mode value"
@subscriber_mode = ""
self.create_config_file
stderr_msg = self.start_server
assert(!stderr_msg.include?(expected_error_message), "Message error founded: '#{ stderr_msg }'")
self.stop_server
@subscriber_mode = "streaming"
self.create_config_file
stderr_msg = self.start_server
assert(!stderr_msg.include?(expected_error_message), "Message error founded: '#{ stderr_msg }'")
self.stop_server
@subscriber_mode = "polling"
self.create_config_file
stderr_msg = self.start_server
assert(!stderr_msg.include?(expected_error_message), "Message error founded: '#{ stderr_msg }'")
self.stop_server
@subscriber_mode = "long-polling"
self.create_config_file
stderr_msg = self.start_server
assert(!stderr_msg.include?(expected_error_message), "Message error founded: '#{ stderr_msg }'")
self.stop_server
end
def test_invalid_publisher_mode
expected_error_message = "invalid push_stream_publisher mode value: unknown, accepted values (normal, admin)"
@publisher_mode = "unknown"
self.create_config_file
stderr_msg = self.start_server
assert(stderr_msg.include?(expected_error_message), "Message error not founded: '#{ expected_error_message }' recieved '#{ stderr_msg }'")
end
def test_valid_publisher_mode
expected_error_message = "invalid push_stream_publisher mode value"
@publisher_mode = ""
self.create_config_file
stderr_msg = self.start_server
assert(!stderr_msg.include?(expected_error_message), "Message error founded: '#{ stderr_msg }'")
self.stop_server
@publisher_mode = "normal"
self.create_config_file
stderr_msg = self.start_server
assert(!stderr_msg.include?(expected_error_message), "Message error founded: '#{ stderr_msg }'")
self.stop_server
@publisher_mode = "admin"
self.create_config_file
stderr_msg = self.start_server
assert(!stderr_msg.include?(expected_error_message), "Message error founded: '#{ stderr_msg }'")
self.stop_server
end
def test_event_source_not_available_on_publisher_statistics_and_websocket_locations
expected_error_message = "push stream module: event source support is only available on subscriber location"
@extra_location = %q{
location ~ /test/ {
push_stream_websocket;
push_stream_eventsource_support on;
}
}
self.create_config_file
stderr_msg = self.start_server
assert(stderr_msg.include?(expected_error_message), "Message error not founded: '#{ expected_error_message }' recieved '#{ stderr_msg }'")
@extra_location = %q{
location ~ /test/ {
push_stream_publisher;
push_stream_eventsource_support on;
}
}
self.create_config_file
stderr_msg = self.start_server
assert(stderr_msg.include?(expected_error_message), "Message error not founded: '#{ expected_error_message }' recieved '#{ stderr_msg }'")
@extra_location = %q{
location ~ /test/ {
push_stream_channels_statistics;
push_stream_eventsource_support on;
}
}
self.create_config_file
stderr_msg = self.start_server
assert(stderr_msg.include?(expected_error_message), "Message error not founded: '#{ expected_error_message }' recieved '#{ stderr_msg }'")
end
def test_padding_by_user_agent_parser
expected_error_message = "push stream module: padding pattern not match the value "
@padding_by_user_agent = "user_agent,as,df"
self.create_config_file
stderr_msg = self.start_server
assert(stderr_msg.include?(expected_error_message + "user_agent,as,df"), "Message error not founded: '#{ expected_error_message + "user_agent,as,df" }' recieved '#{ stderr_msg }'")
@padding_by_user_agent = "user_agent;10;0"
self.create_config_file
stderr_msg = self.start_server
assert(stderr_msg.include?(expected_error_message + "user_agent;10;0"), "Message error not founded: '#{ expected_error_message + "user_agent;10;0" }' recieved '#{ stderr_msg }'")
expected_error_message = "error applying padding pattern to "
@padding_by_user_agent = "user_agent,10,0:other_user_agent;20;0:another_user_agent,30,0"
self.create_config_file
stderr_msg = self.start_server
assert(stderr_msg.include?(expected_error_message + "other_user_agent;20;0:another_user_agent,30,0"), "Message error not founded: '#{ expected_error_message + "other_user_agent;20;0:another_user_agent,30,0" }' recieved '#{ stderr_msg }'")
end
end
require File.expand_path('base_test_case', File.dirname(__FILE__))
class TestSubscriber < Test::Unit::TestCase
include BaseTestCase
def config_test_accepted_methods
@subscriber_connection_timeout = '1s'
end
def test_accepted_methods
# testing OPTIONS method, EventMachine::HttpRequest does not have support to it
socket = TCPSocket.open(nginx_host, nginx_port)
socket.print("OPTIONS /sub/ch_test_accepted_methods_0 HTTP/1.0\r\n\r\n")
headers, body = read_response(socket)
assert(headers.match(/HTTP\/1\.1 200 OK/), "Didn't receive right header")
assert(headers.match(/Content-Length: 0/), "Didn't receive right header")
EventMachine.run {
multi = EventMachine::MultiRequest.new
multi.add(:a, EventMachine::HttpRequest.new(nginx_address + '/sub/ch_test_accepted_methods_1').head)
multi.add(:b, EventMachine::HttpRequest.new(nginx_address + '/sub/ch_test_accepted_methods_2').put(:body => 'body'))
multi.add(:c, EventMachine::HttpRequest.new(nginx_address + '/sub/ch_test_accepted_methods_3').post)
multi.add(:d, EventMachine::HttpRequest.new(nginx_address + '/sub/ch_test_accepted_methods_4').delete)
multi.add(:e, EventMachine::HttpRequest.new(nginx_address + '/sub/ch_test_accepted_methods_5').get)
multi.callback {
assert_equal(5, multi.responses[:callback].length)
assert_equal(405, multi.responses[:callback][:a].response_header.status, "Publisher does not accept HEAD")
assert_equal("HEAD", multi.responses[:callback][:a].req.method, "Array is with wrong order")
assert_equal("GET", multi.responses[:callback][:a].response_header['ALLOW'], "Didn't receive the right error message")
assert_equal(405, multi.responses[:callback][:b].response_header.status, "Publisher does not accept PUT")
assert_equal("PUT", multi.responses[:callback][:b].req.method, "Array is with wrong order")
assert_equal("GET", multi.responses[:callback][:b].response_header['ALLOW'], "Didn't receive the right error message")
assert_equal(405, multi.responses[:callback][:c].response_header.status, "Publisher does accept POST")
assert_equal("POST", multi.responses[:callback][:c].req.method, "Array is with wrong order")
assert_equal("GET", multi.responses[:callback][:b].response_header['ALLOW'], "Didn't receive the right error message")
assert_equal(405, multi.responses[:callback][:d].response_header.status, "Publisher does not accept DELETE")
assert_equal("DELETE", multi.responses[:callback][:d].req.method, "Array is with wrong order")
assert_equal("GET", multi.responses[:callback][:d].response_header['ALLOW'], "Didn't receive the right error message")
assert_not_equal(405, multi.responses[:callback][:e].response_header.status, "Publisher does accept GET")
assert_equal("GET", multi.responses[:callback][:e].req.method, "Array is with wrong order")
EventMachine.stop
}
}
end
def test_access_whithout_channel_path
headers = {'accept' => 'application/json'}
EventMachine.run {
sub = EventMachine::HttpRequest.new(nginx_address + '/sub/').get :head => headers, :timeout => 30
sub.callback {
assert_equal(0, sub.response_header.content_length, "Should response only with headers")
assert_equal(400, sub.response_header.status, "Request was not understood as a bad request")
assert_equal("No channel id provided.", sub.response_header['X_NGINX_PUSHSTREAM_EXPLAIN'], "Didn't receive the right error message")
EventMachine.stop
}
}
end
def config_test_multi_channels
@subscriber_connection_timeout = '1s'
end
def test_multi_channels
EventMachine.run {
multi = EventMachine::MultiRequest.new
multi.add(:a, EventMachine::HttpRequest.new(nginx_address + '/sub/ch_multi_channels_1').get)
multi.add(:b, EventMachine::HttpRequest.new(nginx_address + '/sub/ch_multi_channels_1.b10').get)
multi.add(:c, EventMachine::HttpRequest.new(nginx_address + '/sub/ch_multi_channels_2/ch_multi_channels_3').get)
multi.add(:d, EventMachine::HttpRequest.new(nginx_address + '/sub/ch_multi_channels_2.b2/ch_multi_channels_3').get)
multi.add(:e, EventMachine::HttpRequest.new(nginx_address + '/sub/ch_multi_channels_2/ch_multi_channels_3.b3').get)
multi.add(:f, EventMachine::HttpRequest.new(nginx_address + '/sub/ch_multi_channels_2.b2/ch_multi_channels_3.b3').get)
multi.add(:g, EventMachine::HttpRequest.new(nginx_address + '/sub/ch_multi_channels_4.b').get)
multi.callback {
assert_equal(7, multi.responses[:callback].length)
multi.responses[:callback].each do |name, response|
assert_equal(200, response.response_header.status, "Subscriber not accepted")
end
EventMachine.stop
}
}
end
def config_test_max_channel_id_length
@max_channel_id_length = 5
end
def test_max_channel_id_length
headers = {'accept' => 'application/json'}
channel = '123456'
EventMachine.run {
sub = EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel.to_s ).get :head => headers, :timeout => 30
sub.callback {
assert_equal(0, sub.response_header.content_length, "Should response only with headers")
assert_equal(400, sub.response_header.status, "Request was not understood as a bad request")
assert_equal("Channel id is too large.", sub.response_header['X_NGINX_PUSHSTREAM_EXPLAIN'], "Didn't receive the right error message")
EventMachine.stop
}
}
end
def test_cannot_access_a_channel_with_id_ALL
headers = {'accept' => 'application/json'}
channel = 'ALL'
EventMachine.run {
sub_1 = EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel.to_s).get :head => headers, :timeout => 30
sub_1.callback {
assert_equal(403, sub_1.response_header.status, "Channel was created")
assert_equal(0, sub_1.response_header.content_length, "Received response for creating channel with id ALL")
assert_equal("Channel id not authorized for this method.", sub_1.response_header['X_NGINX_PUSHSTREAM_EXPLAIN'], "Didn't receive the right error message")
EventMachine.stop
}
}
end
def test_cannot_access_a_channel_with_id_containing_wildcard
headers = {'accept' => 'application/json'}
channel_1 = 'abcd*efgh'
channel_2 = '*abcdefgh'
channel_3 = 'abcdefgh*'
EventMachine.run {
multi = EventMachine::MultiRequest.new
multi.add(:a, EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel_1).get(:head => headers, :timeout => 30))
multi.add(:b, EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel_2).get(:head => headers, :timeout => 30))
multi.add(:c, EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel_3).get(:head => headers, :timeout => 30))
multi.callback {
assert_equal(3, multi.responses[:callback].length)
multi.responses[:callback].each do |name, response|
assert_equal(403, response.response_header.status, "Channel was created")
assert_equal(0, response.response_header.content_length, "Received response for creating channel with id containing wildcard")
assert_equal("Channel id not authorized for this method.", response.response_header['X_NGINX_PUSHSTREAM_EXPLAIN'], "Didn't receive the right error message")
end
EventMachine.stop
}
EM.add_timer(5) do
fail("Subscribers didn't disconnect")
EventMachine.stop
end
}
end
def config_test_broadcast_channels_without_common_channel
@subscriber_connection_timeout = '1s'
@broadcast_channel_prefix = "bd_"
end
def test_broadcast_channels_without_common_channel
headers = {'accept' => 'application/json'}
EventMachine.run {
multi = EventMachine::MultiRequest.new
multi.add(:a, EventMachine::HttpRequest.new(nginx_address + '/sub/bd_test_broadcast_channels_without_common_channel').get)
multi.add(:b, EventMachine::HttpRequest.new(nginx_address + '/sub/bd_').get)
multi.add(:c, EventMachine::HttpRequest.new(nginx_address + '/sub/bd1').get)
multi.add(:d, EventMachine::HttpRequest.new(nginx_address + '/sub/bd').get)
multi.callback {
assert_equal(4, multi.responses[:callback].length)
assert_equal(0, multi.responses[:callback][:a].response_header.content_length, "Should response only with headers")
assert_equal(403, multi.responses[:callback][:a].response_header.status, "Request was not understood as a bad request")
assert_equal("Subscribed too much broadcast channels.", multi.responses[:callback][:a].response_header['X_NGINX_PUSHSTREAM_EXPLAIN'], "Didn't receive the right error message")
assert_equal(nginx_address + '/sub/bd_test_broadcast_channels_without_common_channel', multi.responses[:callback][:a].req.uri.to_s, "Array is with wrong order")
assert_equal(0, multi.responses[:callback][:b].response_header.content_length, "Should response only with headers")
assert_equal(403, multi.responses[:callback][:b].response_header.status, "Request was not understood as a bad request")
assert_equal("Subscribed too much broadcast channels.", multi.responses[:callback][:b].response_header['X_NGINX_PUSHSTREAM_EXPLAIN'], "Didn't receive the right error message")
assert_equal(nginx_address + '/sub/bd_', multi.responses[:callback][:b].req.uri.to_s, "Array is with wrong order")
assert_equal(200, multi.responses[:callback][:c].response_header.status, "Channel id starting with different prefix from broadcast was not accept")
assert_equal(nginx_address + '/sub/bd1', multi.responses[:callback][:c].req.uri.to_s, "Array is with wrong order")
assert_equal(200, multi.responses[:callback][:d].response_header.status, "Channel id starting with different prefix from broadcast was not accept")
assert_equal(nginx_address + '/sub/bd', multi.responses[:callback][:d].req.uri.to_s, "Array is with wrong order")
EventMachine.stop
}
}
end
def config_test_broadcast_channels_with_common_channels
@subscriber_connection_timeout = '1s'
@authorized_channels_only = "off"
@broadcast_channel_prefix = "bd_"
@broadcast_channel_max_qtd = 2
end
def test_broadcast_channels_with_common_channels
headers = {'accept' => 'application/json'}
EventMachine.run {
multi = EventMachine::MultiRequest.new
multi.add(:a, EventMachine::HttpRequest.new(nginx_address + '/sub/bd1/bd2/bd3/bd4/bd_1/bd_2/bd_3').get)
multi.add(:b, EventMachine::HttpRequest.new(nginx_address + '/sub/bd1/bd2/bd_1/bd_2').get)
multi.add(:c, EventMachine::HttpRequest.new(nginx_address + '/sub/bd1/bd_1').get)
multi.add(:d, EventMachine::HttpRequest.new(nginx_address + '/sub/bd1/bd2').get)
multi.callback {
assert_equal(4, multi.responses[:callback].length)
assert_equal(0, multi.responses[:callback][:a].response_header.content_length, "Should response only with headers")
assert_equal(403, multi.responses[:callback][:a].response_header.status, "Request was not understood as a bad request")
assert_equal("Subscribed too much broadcast channels.", multi.responses[:callback][:a].response_header['X_NGINX_PUSHSTREAM_EXPLAIN'], "Didn't receive the right error message")
assert_equal(nginx_address + '/sub/bd1/bd2/bd3/bd4/bd_1/bd_2/bd_3', multi.responses[:callback][:a].req.uri.to_s, "Array is with wrong order")
assert_equal(200, multi.responses[:callback][:b].response_header.status, "Request was not understood as a bad request")
assert_equal(nginx_address + '/sub/bd1/bd2/bd_1/bd_2', multi.responses[:callback][:b].req.uri.to_s, "Array is with wrong order")
assert_equal(200, multi.responses[:callback][:c].response_header.status, "Channel id starting with different prefix from broadcast was not accept")
assert_equal(nginx_address + '/sub/bd1/bd_1', multi.responses[:callback][:c].req.uri.to_s, "Array is with wrong order")
assert_equal(200, multi.responses[:callback][:d].response_header.status, "Channel id starting with different prefix from broadcast was not accept")
assert_equal(nginx_address + '/sub/bd1/bd2', multi.responses[:callback][:d].req.uri.to_s, "Array is with wrong order")
EventMachine.stop
}
}
end
def config_test_subscribe_an_absent_channel_with_authorized_only_on
@authorized_channels_only = 'on'
end
def test_subscribe_an_absent_channel_with_authorized_only_on
headers = {'accept' => 'application/json'}
channel = 'ch_test_subscribe_an_absent_channel_with_authorized_only_on'
EventMachine.run {
sub_1 = EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel.to_s).get :head => headers, :timeout => 30
sub_1.callback {
assert_equal(403, sub_1.response_header.status, "Channel was founded")
assert_equal(0, sub_1.response_header.content_length, "Recieved a non empty response")
assert_equal("Subscriber could not create channels.", sub_1.response_header['X_NGINX_PUSHSTREAM_EXPLAIN'], "Didn't receive the right error message")
EventMachine.stop
}
}
end
def config_test_subscribe_an_existing_channel_with_authorized_only_on
@authorized_channels_only = 'on'
@subscriber_connection_timeout = '1s'
end
def test_subscribe_an_existing_channel_with_authorized_only_on
headers = {'accept' => 'application/json'}
channel = 'ch_test_subscribe_an_existing_channel_with_authorized_only_on'
body = 'body'
#create channel
publish_message(channel, headers, body)
EventMachine.run {
sub_1 = EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel.to_s).get :head => headers, :timeout => 30
sub_1.callback {
assert_equal(200, sub_1.response_header.status, "Channel was founded")
EventMachine.stop
}
add_test_timeout
}
end
def config_test_subscribe_an_existing_channel_and_absent_broadcast_channel_with_authorized_only_on
@authorized_channels_only = 'on'
@subscriber_connection_timeout = '1s'
@broadcast_channel_prefix = "bd_"
@broadcast_channel_max_qtd = 1
end
def test_subscribe_an_existing_channel_and_absent_broadcast_channel_with_authorized_only_on
headers = {'accept' => 'application/json'}
channel = 'ch_test_subscribe_an_existing_channel_and_absent_broadcast_channel_with_authorized_only_on'
broadcast_channel = 'bd_test_subscribe_an_existing_channel_and_absent_broadcast_channel_with_authorized_only_on'
body = 'body'
#create channel
publish_message(channel, headers, body)
EventMachine.run {
sub_1 = EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel.to_s + '/' + broadcast_channel.to_s).get :head => headers, :timeout => 30
sub_1.callback {
assert_equal(200, sub_1.response_header.status, "Channel was founded")
EventMachine.stop
}
add_test_timeout
}
end
def config_test_subscribe_an_existing_channel_without_messages_and_with_authorized_only_on
@min_message_buffer_timeout = '1s'
@authorized_channels_only = 'on'
end
def test_subscribe_an_existing_channel_without_messages_and_with_authorized_only_on
headers = {'accept' => 'application/json'}
channel = 'ch_test_subscribe_an_existing_channel_without_messages_and_with_authorized_only_on'
body = 'body'
#create channel
publish_message(channel, headers, body)
sleep(5) #to ensure message was gone
EventMachine.run {
sub_1 = EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel.to_s).get :head => headers, :timeout => 30
sub_1.callback {
assert_equal(403, sub_1.response_header.status, "Channel was founded")
assert_equal(0, sub_1.response_header.content_length, "Recieved a non empty response")
assert_equal("Subscriber could not create channels.", sub_1.response_header['X_NGINX_PUSHSTREAM_EXPLAIN'], "Didn't receive the right error message")
EventMachine.stop
}
add_test_timeout
}
end
def config_test_subscribe_an_existing_channel_without_messages_and_absent_broadcast_channel_and_with_authorized_only_on_should_fail
@min_message_buffer_timeout = '1s'
@authorized_channels_only = 'on'
@broadcast_channel_prefix = "bd_"
@broadcast_channel_max_qtd = 1
end
def test_subscribe_an_existing_channel_without_messages_and_absent_broadcast_channel_and_with_authorized_only_on_should_fail
headers = {'accept' => 'application/json'}
channel = 'ch_test_subscribe_an_existing_channel_without_messages_and_absent_broadcast_channel_and_with_authorized_only_on_should_fail'
broadcast_channel = 'bd_test_subscribe_an_existing_channel_without_messages_and_absent_broadcast_channel_and_with_authorized_only_on_should_fail'
body = 'body'
#create channel
publish_message(channel, headers, body)
sleep(5) #to ensure message was gone
EventMachine.run {
sub_1 = EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel.to_s + '/' + broadcast_channel.to_s).get :head => headers, :timeout => 30
sub_1.callback {
assert_equal(403, sub_1.response_header.status, "Channel was founded")
assert_equal(0, sub_1.response_header.content_length, "Recieved a non empty response")
assert_equal("Subscriber could not create channels.", sub_1.response_header['X_NGINX_PUSHSTREAM_EXPLAIN'], "Didn't receive the right error message")
EventMachine.stop
}
add_test_timeout
}
end
def config_test_retreive_old_messages_in_multichannel_subscribe
@header_template = 'HEADER'
@message_template = '{\"channel\":\"~channel~\", \"id\":\"~id~\", \"message\":\"~text~\"}'
end
def test_retreive_old_messages_in_multichannel_subscribe
headers = {'accept' => 'application/json'}
channel_1 = 'ch_test_retreive_old_messages_in_multichannel_subscribe_1'
channel_2 = 'ch_test_retreive_old_messages_in_multichannel_subscribe_2'
channel_3 = 'ch_test_retreive_old_messages_in_multichannel_subscribe_3'
body = 'body'
#create channels with some messages
1.upto(3) do |i|
publish_message(channel_1, headers, body + i.to_s)
publish_message(channel_2, headers, body + i.to_s)
publish_message(channel_3, headers, body + i.to_s)
end
response = ""
EventMachine.run {
sub_1 = EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel_1.to_s + '/' + channel_2.to_s + '.b5' + '/' + channel_3.to_s + '.b2').get :head => headers, :timeout => 30
sub_1.stream { |chunk|
response += chunk
lines = response.split("\r\n")
if lines.length >= 6
assert_equal('HEADER', lines[0], "Header was not received")
line = JSON.parse(lines[1])
assert_equal(channel_2.to_s, line['channel'], "Wrong channel")
assert_equal('body1', line['message'], "Wrong message")
assert_equal(1, line['id'].to_i, "Wrong message")
line = JSON.parse(lines[2])
assert_equal(channel_2.to_s, line['channel'], "Wrong channel")
assert_equal('body2', line['message'], "Wrong message")
assert_equal(2, line['id'].to_i, "Wrong message")
line = JSON.parse(lines[3])
assert_equal(channel_2.to_s, line['channel'], "Wrong channel")
assert_equal('body3', line['message'], "Wrong message")
assert_equal(3, line['id'].to_i, "Wrong message")
line = JSON.parse(lines[4])
assert_equal(channel_3.to_s, line['channel'], "Wrong channel")
assert_equal('body2', line['message'], "Wrong message")
assert_equal(2, line['id'].to_i, "Wrong message")
line = JSON.parse(lines[5])
assert_equal(channel_3.to_s, line['channel'], "Wrong channel")
assert_equal('body3', line['message'], "Wrong message")
assert_equal(3, line['id'].to_i, "Wrong message")
EventMachine.stop
end
}
add_test_timeout(10)
}
end
def config_test_retreive_new_messages_in_multichannel_subscribe
@header_template = nil
@message_template = '{\"channel\":\"~channel~\", \"id\":\"~id~\", \"message\":\"~text~\"}'
end
def test_retreive_new_messages_in_multichannel_subscribe
headers = {'accept' => 'application/json'}
channel_1 = 'test_retreive_new_messages_in_multichannel_subscribe_1'
channel_2 = 'test_retreive_new_messages_in_multich_subscribe_2'
channel_3 = 'test_retreive_new_messages_in_multchannel_subscribe_3'
channel_4 = 'test_retreive_new_msgs_in_multichannel_subscribe_4'
channel_5 = 'test_retreive_new_messages_in_multichannel_subs_5'
channel_6 = 'test_retreive_new_msgs_in_multichannel_subs_6'
body = 'body'
response = ""
EventMachine.run {
sub_1 = EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel_1.to_s + '/' + channel_2.to_s + '/' + channel_3.to_s + '/' + channel_4.to_s + '/' + channel_5.to_s + '/' + channel_6.to_s).get :head => headers, :timeout => 30
sub_1.stream { |chunk|
response += chunk
lines = response.split("\r\n")
if lines.length >= 6
line = JSON.parse(lines[0])
assert_equal(channel_1.to_s, line['channel'], "Wrong channel")
assert_equal('body' + channel_1.to_s, line['message'], "Wrong message")
assert_equal(1, line['id'].to_i, "Wrong message")
line = JSON.parse(lines[1])
assert_equal(channel_2.to_s, line['channel'], "Wrong channel")
assert_equal('body' + channel_2.to_s, line['message'], "Wrong message")
assert_equal(1, line['id'].to_i, "Wrong message")
line = JSON.parse(lines[2])
assert_equal(channel_3.to_s, line['channel'], "Wrong channel")
assert_equal('body' + channel_3.to_s, line['message'], "Wrong message")
assert_equal(1, line['id'].to_i, "Wrong message")
line = JSON.parse(lines[3])
assert_equal(channel_4.to_s, line['channel'], "Wrong channel")
assert_equal('body' + channel_4.to_s, line['message'], "Wrong message")
assert_equal(1, line['id'].to_i, "Wrong message")
line = JSON.parse(lines[4])
assert_equal(channel_5.to_s, line['channel'], "Wrong channel")
assert_equal('body' + channel_5.to_s, line['message'], "Wrong message")
assert_equal(1, line['id'].to_i, "Wrong message")
line = JSON.parse(lines[5])
assert_equal(channel_6.to_s, line['channel'], "Wrong channel")
assert_equal('body' + channel_6.to_s, line['message'], "Wrong message")
assert_equal(1, line['id'].to_i, "Wrong message")
EventMachine.stop
end
}
publish_message_inline(channel_1, headers, body + channel_1.to_s)
publish_message_inline(channel_2, headers, body + channel_2.to_s)
publish_message_inline(channel_3, headers, body + channel_3.to_s)
publish_message_inline(channel_4, headers, body + channel_4.to_s)
publish_message_inline(channel_5, headers, body + channel_5.to_s)
publish_message_inline(channel_6, headers, body + channel_6.to_s)
add_test_timeout(10)
}
end
def config_test_retreive_old_messages_in_multichannel_subscribe_using_if_modified_since_header
@header_template = 'HEADER'
@message_template = '{\"channel\":\"~channel~\", \"id\":\"~id~\", \"message\":\"~text~\"}'
end
def test_retreive_old_messages_in_multichannel_subscribe_using_if_modified_since_header
headers = {'accept' => 'application/json'}
channel_1 = 'ch_test_retreive_old_messages_in_multichannel_subscribe_using_if_modified_since_header_1'
channel_2 = 'ch_test_retreive_old_messages_in_multichannel_subscribe_using_if_modified_since_header_2'
channel_3 = 'ch_test_retreive_old_messages_in_multichannel_subscribe_using_if_modified_since_header_3'
body = 'body'
#create channels with some messages with progressive interval (2,4,6,10,14,18,24,30,36 seconds)
1.upto(3) do |i|
sleep(i * 2)
publish_message(channel_1, headers, body + i.to_s)
sleep(i * 2)
publish_message(channel_2, headers, body + i.to_s)
sleep(i * 2)
publish_message(channel_3, headers, body + i.to_s)
end
#get messages published less then 20 seconds ago
t = Time.now
t = t - 20
headers = headers.merge({'If-Modified-Since' => t.utc.strftime("%a, %d %b %Y %T %Z")})
response = ""
EventMachine.run {
sub_1 = EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel_1.to_s + '/' + channel_2.to_s + '/' + channel_3.to_s).get :head => headers, :timeout => 30
sub_1.stream { |chunk|
response += chunk
lines = response.split("\r\n")
if lines.length >= 5
assert_equal('HEADER', lines[0], "Header was not received")
line = JSON.parse(lines[1])
assert_equal(channel_1.to_s, line['channel'], "Wrong channel")
assert_equal('body3', line['message'], "Wrong message")
assert_equal(3, line['id'].to_i, "Wrong message")
line = JSON.parse(lines[2])
assert_equal(channel_2.to_s, line['channel'], "Wrong channel")
assert_equal('body3', line['message'], "Wrong message")
assert_equal(3, line['id'].to_i, "Wrong message")
line = JSON.parse(lines[3])
assert_equal(channel_3.to_s, line['channel'], "Wrong channel")
assert_equal('body2', line['message'], "Wrong message")
assert_equal(2, line['id'].to_i, "Wrong message")
line = JSON.parse(lines[4])
assert_equal(channel_3.to_s, line['channel'], "Wrong channel")
assert_equal('body3', line['message'], "Wrong message")
assert_equal(3, line['id'].to_i, "Wrong message")
EventMachine.stop
end
}
add_test_timeout
}
end
def config_test_retreive_old_messages_in_multichannel_subscribe_using_if_modified_since_header_and_backtrack_mixed
@header_template = 'HEADER'
@message_template = '{\"channel\":\"~channel~\", \"id\":\"~id~\", \"message\":\"~text~\"}'
end
def test_retreive_old_messages_in_multichannel_subscribe_using_if_modified_since_header_and_backtrack_mixed
headers = {'accept' => 'application/json'}
channel_1 = 'ch_test_retreive_old_messages_in_multichannel_subscribe_using_if_modified_since_header_and_backtrack_mixed_1'
channel_2 = 'ch_test_retreive_old_messages_in_multichannel_subscribe_using_if_modified_since_header_and_backtrack_mixed_2'
channel_3 = 'ch_test_retreive_old_messages_in_multichannel_subscribe_using_if_modified_since_header_and_backtrack_mixed_3'
body = 'body'
#create channels with some messages with progressive interval (2,4,6,10,14,18,24,30,36 seconds)
1.upto(3) do |i|
sleep(i * 2)
publish_message(channel_1, headers, body + i.to_s)
sleep(i * 2)
publish_message(channel_2, headers, body + i.to_s)
sleep(i * 2)
publish_message(channel_3, headers, body + i.to_s)
end
#get messages published less then 20 seconds ago
t = Time.now
t = t - 20
headers = headers.merge({'If-Modified-Since' => t.utc.strftime("%a, %d %b %Y %T %Z")})
response = ""
EventMachine.run {
sub_1 = EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel_1.to_s + '/' + channel_2.to_s + '.b5' + '/' + channel_3.to_s).get :head => headers, :timeout => 30
sub_1.stream { |chunk|
response += chunk
lines = response.split("\r\n")
if lines.length >= 7
assert_equal('HEADER', lines[0], "Header was not received")
line = JSON.parse(lines[1])
assert_equal(channel_1.to_s, line['channel'], "Wrong channel")
assert_equal('body3', line['message'], "Wrong message")
assert_equal(3, line['id'].to_i, "Wrong message")
line = JSON.parse(lines[2])
assert_equal(channel_2.to_s, line['channel'], "Wrong channel")
assert_equal('body1', line['message'], "Wrong message")
assert_equal(1, line['id'].to_i, "Wrong message")
line = JSON.parse(lines[3])
assert_equal(channel_2.to_s, line['channel'], "Wrong channel")
assert_equal('body2', line['message'], "Wrong message")
assert_equal(2, line['id'].to_i, "Wrong message")
line = JSON.parse(lines[4])
assert_equal(channel_2.to_s, line['channel'], "Wrong channel")
assert_equal('body3', line['message'], "Wrong message")
assert_equal(3, line['id'].to_i, "Wrong message")
line = JSON.parse(lines[5])
assert_equal(channel_3.to_s, line['channel'], "Wrong channel")
assert_equal('body2', line['message'], "Wrong message")
assert_equal(2, line['id'].to_i, "Wrong message")
line = JSON.parse(lines[6])
assert_equal(channel_3.to_s, line['channel'], "Wrong channel")
assert_equal('body3', line['message'], "Wrong message")
assert_equal(3, line['id'].to_i, "Wrong message")
EventMachine.stop
end
}
add_test_timeout
}
end
def config_test_max_number_of_channels
@max_number_of_channels = 1
end
def test_max_number_of_channels
headers = {'accept' => 'application/json'}
channel = 'ch_test_max_number_of_channels_'
EventMachine.run {
sub_1 = EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel.to_s + 1.to_s).get :head => headers, :timeout => 30
sub_1.stream {
assert_equal(200, sub_1.response_header.status, "Channel was not created")
assert_not_equal(0, sub_1.response_header.content_length, "Should response channel info")
sub_2 = EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel.to_s + 2.to_s).get :head => headers, :timeout => 30
sub_2.callback {
assert_equal(403, sub_2.response_header.status, "Request was not forbidden")
assert_equal(0, sub_2.response_header.content_length, "Should response only with headers")
assert_equal("Number of channels were exceeded.", sub_2.response_header['X_NGINX_PUSHSTREAM_EXPLAIN'], "Didn't receive the right error message")
EventMachine.stop
}
}
add_test_timeout(10)
}
end
def config_test_max_number_of_broadcast_channels
@max_number_of_broadcast_channels = 1
@broadcast_channel_prefix = 'bd_'
@broadcast_channel_max_qtd = 1
end
def test_max_number_of_broadcast_channels
headers = {'accept' => 'application/json'}
channel = 'bd_test_max_number_of_broadcast_channels_'
EventMachine.run {
sub_1 = EventMachine::HttpRequest.new(nginx_address + '/sub/ch1/' + channel.to_s + 1.to_s).get :head => headers, :timeout => 30
sub_1.stream {
assert_equal(200, sub_1.response_header.status, "Channel was not created")
assert_not_equal(0, sub_1.response_header.content_length, "Should response channel info")
sub_2 = EventMachine::HttpRequest.new(nginx_address + '/sub/ch1/' + channel.to_s + 2.to_s).get :head => headers, :timeout => 30
sub_2.callback {
assert_equal(403, sub_2.response_header.status, "Request was not forbidden")
assert_equal(0, sub_2.response_header.content_length, "Should response only with headers")
assert_equal("Number of channels were exceeded.", sub_2.response_header['X_NGINX_PUSHSTREAM_EXPLAIN'], "Didn't receive the right error message")
EventMachine.stop
}
}
add_test_timeout
}
end
def config_test_different_message_templates
@message_template = '{\"text\":\"~text~\"}'
@header_template = nil
@subscriber_connection_timeout = '1s'
@extra_location = %q{
location ~ /sub2/(.*)? {
# activate subscriber mode for this location
push_stream_subscriber;
# positional channel path
set $push_stream_channels_path $1;
# message template
push_stream_message_template "{\"msg\":\"~text~\"}";
}
}
end
def test_different_message_templates
headers = {'accept' => 'application/json'}
channel = 'ch_test_different_message_templates'
body = 'body'
EventMachine.run {
sub_1 = EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel.to_s).get :head => headers, :timeout => 30
sub_1.stream { |chunk|
response = JSON.parse(chunk)
assert_equal(true, response.has_key?('text'), "Wrong message template")
assert_equal(false, response.has_key?('msg'), "Wrong message template")
assert_equal(body, response['text'], "Wrong message")
EventMachine.stop
}
sub_2 = EventMachine::HttpRequest.new(nginx_address + '/sub2/' + channel.to_s + '.b1').get :head => headers, :timeout => 30
sub_2.stream { |chunk|
response = JSON.parse(chunk)
assert_equal(false, response.has_key?('text'), "Wrong message template")
assert_equal(true, response.has_key?('msg'), "Wrong message template")
assert_equal(body, response['msg'], "Wrong message")
EventMachine.stop
}
#publish a message
publish_message_inline(channel, headers, body)
add_test_timeout
}
EventMachine.run {
sub_3 = EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel.to_s + '.b1').get :head => headers, :timeout => 30
sub_3.stream { |chunk|
response = JSON.parse(chunk)
assert_equal(true, response.has_key?('text'), "Wrong message template")
assert_equal(false, response.has_key?('msg'), "Wrong message template")
assert_equal(body, response['text'], "Wrong message")
EventMachine.stop
}
add_test_timeout
}
EventMachine.run {
sub_4 = EventMachine::HttpRequest.new(nginx_address + '/sub2/' + channel.to_s + '.b1').get :head => headers, :timeout => 30
sub_4.stream { |chunk|
response = JSON.parse(chunk)
assert_equal(false, response.has_key?('text'), "Wrong message template")
assert_equal(true, response.has_key?('msg'), "Wrong message template")
assert_equal(body, response['msg'], "Wrong message")
EventMachine.stop
}
add_test_timeout
}
end
def config_test_default_message_template
@message_template = nil
@header_template = nil
end
def test_default_message_template
headers = {'accept' => 'application/json'}
channel = 'ch_test_default_message_template'
body = 'body'
EventMachine.run {
sub_1 = EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel.to_s).get :head => headers, :timeout => 30
sub_1.stream { |chunk|
assert_equal("#{body}\r\n", chunk, "Wrong message")
EventMachine.stop
}
#publish a message
publish_message_inline(channel, headers, body)
add_test_timeout
}
end
def config_test_ping_message_with_default_message_template
@message_template = nil
@header_template = nil
@ping_message_interval = '1s'
end
def test_ping_message_with_default_message_template
headers = {'accept' => 'application/json'}
channel = 'ch_test_ping_message_with_default_message_template'
body = 'body'
EventMachine.run {
sub_1 = EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel.to_s).get :head => headers, :timeout => 30
sub_1.stream { |chunk|
assert_equal("\r\n", chunk, "Wrong message")
EventMachine.stop
}
add_test_timeout
}
end
def test_transfer_encoding_chuncked
headers = {'accept' => 'application/json'}
channel = 'ch_test_transfer_encoding_chuncked'
EventMachine.run {
sub_1 = EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel.to_s).get :head => headers, :timeout => 30
sub_1.stream { |chunk|
assert_equal("chunked", sub_1.response_header['TRANSFER_ENCODING'], "Didn't receive the right transfer encoding")
EventMachine.stop
}
add_test_timeout
}
end
def config_test_default_ping_message_with_default_message_template
@header_template = nil
@message_template = nil
@ping_message_text = nil
@ping_message_interval = '1s'
end
def test_default_ping_message_with_default_message_template
headers = {'accept' => 'application/json'}
channel = 'ch_test_default_ping_message_with_default_message_template'
body = 'body'
EventMachine.run {
sub_1 = EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel.to_s).get :head => headers, :timeout => 30
sub_1.stream { |chunk|
assert_equal("\r\n", chunk, "Wrong message")
EventMachine.stop
}
add_test_timeout
}
end
def config_test_custom_ping_message_with_default_message_template
@header_template = nil
@message_template = nil
@ping_message_text = "pinging you!!!"
@ping_message_interval = '1s'
end
def test_custom_ping_message_with_default_message_template
headers = {'accept' => 'application/json'}
channel = 'ch_test_custom_ping_message_with_default_message_template'
body = 'body'
EventMachine.run {
sub_1 = EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel.to_s).get :head => headers, :timeout => 30
sub_1.stream { |chunk|
assert_equal("#{@ping_message_text}\r\n", chunk, "Wrong message")
EventMachine.stop
}
add_test_timeout
}
end
def config_test_default_ping_message_with_custom_message_template
@header_template = nil
@message_template = "~id~:~text~"
@ping_message_text = nil
@ping_message_interval = '1s'
end
def test_default_ping_message_with_custom_message_template
headers = {'accept' => 'application/json'}
channel = 'ch_test_default_ping_message_with_custom_message_template'
body = 'body'
EventMachine.run {
sub_1 = EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel.to_s).get :head => headers, :timeout => 30
sub_1.stream { |chunk|
assert_equal("-1:\r\n", chunk, "Wrong message")
EventMachine.stop
}
add_test_timeout
}
end
def config_test_custom_ping_message_with_default_message_template
@header_template = nil
@message_template = "~id~:~text~"
@ping_message_text = "pinging you!!!"
@ping_message_interval = '1s'
end
def test_custom_ping_message_with_default_message_template
headers = {'accept' => 'application/json'}
channel = 'ch_test_custom_ping_message_with_default_message_template'
body = 'body'
EventMachine.run {
sub_1 = EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel.to_s).get :head => headers, :timeout => 30
sub_1.stream { |chunk|
assert_equal("-1:#{@ping_message_text}\r\n", chunk, "Wrong message")
EventMachine.stop
}
add_test_timeout
}
end
def config_test_cannot_add_more_subscriber_to_one_channel_than_allowed
@max_subscribers_per_channel = 3
@subscriber_connection_timeout = "3s"
end
def test_cannot_add_more_subscriber_to_one_channel_than_allowed
headers = {'accept' => 'application/json'}
channel = 'ch_test_cannot_add_more_subscriber_to_one_channel_than_allowed'
other_channel = 'ch_test_cannot_add_more_subscriber_to_one_channel_than_allowed_2'
EventMachine.run {
sub_1 = EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel.to_s).get :head => headers, :timeout => 30
sub_2 = EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel.to_s).get :head => headers, :timeout => 30
sub_3 = EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel.to_s).get :head => headers, :timeout => 30
sub_4 = EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel.to_s).get :head => headers, :timeout => 30
sub_4.callback {
assert_equal(403, sub_4.response_header.status, "Channel was created")
assert_equal(0, sub_4.response_header.content_length, "Received response for exceed subscriber limit")
assert_equal("Subscribers limit per channel has been exceeded.", sub_4.response_header['X_NGINX_PUSHSTREAM_EXPLAIN'], "Didn't receive the right error message")
}
sub_5 = EventMachine::HttpRequest.new(nginx_address + '/sub/' + other_channel.to_s).get :head => headers, :timeout => 30
sub_5.callback {
assert_equal(200, sub_5.response_header.status, "Channel was not created")
EventMachine.stop
}
add_test_timeout
}
end
def config_test_accept_channels_name_with_dot_b
@subscriber_connection_timeout = "1s"
@ping_message_interval = nil
@header_template = nil
@footer_template = nil
@message_template = nil
end
def test_accept_channels_name_with_dot_b
channel = 'room.b18.beautiful'
response = ''
EventMachine.run {
publish_message_inline(channel, {'accept' => 'text/html'}, 'msg 1')
publish_message_inline(channel, {'accept' => 'text/html'}, 'msg 2')
publish_message_inline(channel, {'accept' => 'text/html'}, 'msg 3')
publish_message_inline(channel, {'accept' => 'text/html'}, 'msg 4')
sub = EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel.to_s + '.b3').get
sub.stream { | chunk |
response += chunk
}
sub.callback {
assert_equal("msg 2\r\nmsg 3\r\nmsg 4\r\n", response, "The published message was not received correctly")
response = ''
sub_1 = EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel.to_s).get
sub_1.stream { | chunk |
response += chunk
}
sub_1.callback { |chunk|
assert_equal("msg 5\r\n", response, "The published message was not received correctly")
EventMachine.stop
}
publish_message_inline(channel, {'accept' => 'text/html'}, 'msg 5')
}
add_test_timeout
}
end
def test_access_control_allow_headers
headers = {'accept' => 'application/json'}
channel = 'test_access_control_allow_headers'
EventMachine.run {
sub_1 = EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel.to_s).get :head => headers, :timeout => 30
sub_1.stream { |chunk|
assert_equal("*", sub_1.response_header['ACCESS_CONTROL_ALLOW_ORIGIN'], "Didn't receive the right header")
assert_equal("GET", sub_1.response_header['ACCESS_CONTROL_ALLOW_METHODS'], "Didn't receive the right header")
assert_equal("If-Modified-Since,If-None-Match", sub_1.response_header['ACCESS_CONTROL_ALLOW_HEADERS'], "Didn't receive the right header")
EventMachine.stop
}
add_test_timeout
}
end
def test_default_access_control_allow_origin_header
headers = {'accept' => 'application/json'}
channel = 'test_default_access_control_allow_origin_header'
EventMachine.run {
sub_1 = EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel.to_s).get :head => headers, :timeout => 30
sub_1.stream { |chunk|
assert_equal("*", sub_1.response_header['ACCESS_CONTROL_ALLOW_ORIGIN'], "Didn't receive the right header")
EventMachine.stop
}
add_test_timeout
}
end
def config_test_custom_access_control_allow_origin_header
@allowed_origins = "custom.domain.com"
end
def test_custom_access_control_allow_origin_header
headers = {'accept' => 'application/json'}
channel = 'test_custom_access_control_allow_origin_header'
EventMachine.run {
sub_1 = EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel.to_s).get :head => headers, :timeout => 30
sub_1.stream { |chunk|
assert_equal("custom.domain.com", sub_1.response_header['ACCESS_CONTROL_ALLOW_ORIGIN'], "Didn't receive the right header")
EventMachine.stop
}
add_test_timeout
}
end
end
require File.expand_path('base_test_case', File.dirname(__FILE__))
class TestSubscriberConnectionCleanup < Test::Unit::TestCase
include BaseTestCase
def config_test_subscriber_connection_timeout
@subscriber_connection_timeout = "37s"
@header_template = "HEADER_TEMPLATE"
@footer_template = "FOOTER_TEMPLATE"
@ping_message_interval = nil
end
def test_subscriber_connection_timeout
channel = 'ch_test_subscriber_connection_timeout'
headers = {'accept' => 'text/html'}
start = Time.now
response = ''
EventMachine.run {
sub = EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel.to_s, :inactivity_timeout => 60).get :head => headers, :timeout => 60
sub.stream { |chunk|
response += chunk
assert(response.include?(@header_template), "Didn't received header template")
}
sub.callback {
stop = Time.now
elapsed = time_diff_sec(start, stop)
assert(elapsed >= 37 && elapsed <= 37.5, "Disconnect was in #{elapsed} seconds")
assert(response.include?(@footer_template), "Didn't received footer template")
EventMachine.stop
}
add_test_timeout(50)
}
end
def config_test_subscriber_connection_timeout_with_ping_message
@subscriber_connection_timeout = "37s"
@ping_message_interval = "5s"
@header_template = nil
@footer_template = nil
end
def test_subscriber_connection_timeout_with_ping_message
channel = 'ch_test_subscriber_connection_timeout_with_ping_message'
headers = {'accept' => 'text/html'}
start = Time.now
chunksReceived = 0
EventMachine.run {
sub = EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel.to_s, :inactivity_timeout => 15).get :head => headers, :timeout => 60
sub.stream { |chunk|
chunksReceived += 1;
}
sub.callback {
stop = Time.now
elapsed = time_diff_sec(start, stop)
assert(elapsed >= 37 && elapsed <= 37.5, "Disconnect was in #{elapsed} seconds")
assert_equal(7, chunksReceived, "Received #{chunksReceived} chunks")
EventMachine.stop
}
add_test_timeout(50)
}
end
def config_test_multiple_subscribers_connection_timeout
@subscriber_connection_timeout = "5s"
@header_template = "HEADER_TEMPLATE"
@footer_template = "FOOTER_TEMPLATE"
@ping_message_interval = nil
end
def test_multiple_subscribers_connection_timeout
channel = 'ch_test_multiple_subscribers_connection_timeout'
headers = {'accept' => 'text/html'}
EventMachine.run {
response_1 = ''
sub_1 = EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel.to_s).get :head => headers, :timeout => 60
sub_1.stream { |chunk|
response_1 += chunk
assert(response_1.include?(@header_template), "Didn't received header template")
}
sub_1.callback {
assert(response_1.include?(@footer_template), "Didn't received footer template")
}
sleep(2)
response_2 = ''
sub_2 = EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel.to_s).get :head => headers, :timeout => 60
sub_2.stream { |chunk|
response_2 += chunk
assert(response_2.include?(@header_template), "Didn't received header template")
}
sub_2.callback {
assert(response_2.include?(@footer_template), "Didn't received footer template")
response_4 = ''
sub_4 = EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel.to_s).get :head => headers, :timeout => 60
sub_4.stream { |chunk|
response_4 += chunk
assert(response_4.include?(@header_template), "Didn't received header template")
}
sub_4.callback {
assert(response_4.include?(@footer_template), "Didn't received footer template")
EventMachine.stop
}
}
sleep(6)
response_3 = ''
sub_3 = EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel.to_s).get :head => headers, :timeout => 60
sub_3.stream { |chunk|
response_3 += chunk
assert(response_3.include?(@header_template), "Didn't received header template")
}
sub_3.callback {
assert(response_3.include?(@footer_template), "Didn't received footer template")
}
add_test_timeout(15)
}
end
end
require File.expand_path('base_test_case', File.dirname(__FILE__))
class TestSubscriberEventSource < Test::Unit::TestCase
include BaseTestCase
def global_configuration
@subscriber_eventsource = 'on'
@header_template = nil
@message_template = nil
@footer_template = nil
@ping_message_interval = nil
end
def config_test_content_type_should_be_event_stream
@header_template = "header"
end
def test_content_type_should_be_event_stream
channel = 'ch_test_content_type_should_be_event_stream'
EventMachine.run {
sub = EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel.to_s).get
sub.stream { | chunk |
assert_equal("text/event-stream; charset=utf-8", sub.response_header["CONTENT_TYPE"], "wrong content-type")
EventMachine.stop
}
add_test_timeout
}
end
def config_test_each_line_on_header_template_should_be_prefixed_by_a_colon
@header_template = "header line 1\nheader line 2\rheader line 3\r\nheader line 4"
end
def test_each_line_on_header_template_should_be_prefixed_by_a_colon
channel = 'ch_test_each_line_on_header_template_should_be_prefixed_by_a_colon'
EventMachine.run {
sub = EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel.to_s).get
sub.stream { | chunk |
assert_equal(": header line 1\r\n: header line 2\r\n: header line 3\r\n: header line 4\r\n\r\n", chunk, "Wrong header")
EventMachine.stop
}
add_test_timeout
}
end
def config_test_escaped_new_lines_on_header_template_should_be_treated_as_single_line
@header_template = "header line 1\\\\nheader line 2"
end
def test_escaped_new_lines_on_header_template_should_be_treated_as_single_line
channel = 'ch_test_escaped_new_lines_on_header_template_should_be_treated_as_single_line'
EventMachine.run {
sub = EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel.to_s).get
sub.stream { | chunk |
assert_equal(": header line 1\\nheader line 2\r\n\r\n", chunk, "Wrong header")
EventMachine.stop
}
add_test_timeout
}
end
def config_test_each_line_on_footer_template_should_be_prefixed_by_a_colon
@footer_template = "footer line 1\nfooter line 2\rfooter line 3\r\nfooter line 4"
@subscriber_connection_timeout = '1s'
end
def test_each_line_on_footer_template_should_be_prefixed_by_a_colon
channel = 'ch_test_each_line_on_footer_template_should_be_prefixed_by_a_colon'
response = ''
EventMachine.run {
sub = EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel.to_s).get
sub.stream { | chunk |
response += chunk
}
sub.callback {
assert_equal(":\r\n: footer line 1\r\n: footer line 2\r\n: footer line 3\r\n: footer line 4\r\n\r\n", response, "Wrong footer")
EventMachine.stop
}
add_test_timeout
}
end
def config_test_escaped_new_lines_on_footer_template_should_be_treated_as_single_line
@footer_template = "footer line 1\\\\nfooter line 2"
@subscriber_connection_timeout = '1s'
end
def test_escaped_new_lines_on_footer_template_should_be_treated_as_single_line
channel = 'ch_test_escaped_new_lines_on_footer_template_should_be_treated_as_single_line'
response = ''
EventMachine.run {
sub = EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel.to_s).get
sub.stream { | chunk |
response += chunk
}
sub.callback {
assert_equal(":\r\n: footer line 1\\nfooter line 2\r\n\r\n", response, "Wrong footer")
EventMachine.stop
}
add_test_timeout
}
end
def test_default_message_template_without_event_id
headers = {'accept' => 'text/html'}
body = 'test message'
channel = 'ch_test_default_message_template_without_event_id'
response = ''
EventMachine.run {
sub = EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel.to_s).get
sub.stream { | chunk |
response += chunk
if response.include?("\r\n\r\n")
assert_equal(":\r\ndata: #{body}\r\n\r\n", response, "The published message was not received correctly")
EventMachine.stop
end
}
publish_message_inline(channel, headers, body)
add_test_timeout
}
end
def test_default_message_template_without_event_type
headers = {'accept' => 'text/html'}
body = 'test message'
channel = 'ch_test_default_message_template_without_event_type'
response = ''
EventMachine.run {
sub = EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel.to_s).get
sub.stream { | chunk |
response += chunk
if response.include?("\r\n\r\n")
assert_equal(":\r\ndata: #{body}\r\n\r\n", response, "The published message was not received correctly")
EventMachine.stop
end
}
publish_message_inline(channel, headers, body)
add_test_timeout
}
end
def test_default_message_template_with_event_id
event_id = 'event_id_with_generic_text_01'
headers = {'accept' => 'text/html', 'Event-Id' => event_id }
body = 'test message'
channel = 'ch_test_default_message_template_with_event_id'
response = ''
EventMachine.run {
sub = EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel.to_s).get
sub.stream { | chunk |
response += chunk
if response.include?("\r\n\r\n")
assert_equal(":\r\nid: #{event_id}\r\ndata: #{body}\r\n\r\n", response, "The published message was not received correctly")
EventMachine.stop
end
}
publish_message_inline(channel, headers, body)
add_test_timeout
}
end
def test_default_message_template_with_event_type
event_type = 'event_type_with_generic_text_01'
headers = {'accept' => 'text/html', 'Event-type' => event_type }
body = 'test message'
channel = 'ch_test_default_message_template_with_event_type'
response = ''
EventMachine.run {
sub = EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel.to_s).get
sub.stream { | chunk |
response += chunk
if response.include?("\r\n\r\n")
assert_equal(":\r\nevent: #{event_type}\r\ndata: #{body}\r\n\r\n", response, "The published message was not received correctly")
EventMachine.stop
end
}
publish_message_inline(channel, headers, body)
add_test_timeout
}
end
def config_test_custom_message_template_without_event_id
@message_template = '{\"id\":\"~id~\", \"message\":\"~text~\"}'
end
def test_custom_message_template_without_event_id
headers = {'accept' => 'text/html'}
body = 'test message'
channel = 'ch_test_custom_message_template_without_event_id'
response = ''
EventMachine.run {
sub = EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel.to_s).get
sub.stream { | chunk |
response += chunk
if response.include?("\r\n\r\n")
assert_equal(%(:\r\ndata: {"id":"1", "message":"#{body}"}\r\n\r\n), response, "The published message was not received correctly")
EventMachine.stop
end
}
publish_message_inline(channel, headers, body)
add_test_timeout
}
end
def config_test_custom_message_template_without_event_type
@message_template = '{\"id\":\"~id~\", \"message\":\"~text~\"}'
end
def test_custom_message_template_without_event_type
headers = {'accept' => 'text/html'}
body = 'test message'
channel = 'ch_test_custom_message_template_without_event_type'
response = ''
EventMachine.run {
sub = EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel.to_s).get
sub.stream { | chunk |
response += chunk
if response.include?("\r\n\r\n")
assert_equal(%(:\r\ndata: {"id":"1", "message":"#{body}"}\r\n\r\n), response, "The published message was not received correctly")
EventMachine.stop
end
}
publish_message_inline(channel, headers, body)
add_test_timeout
}
end
def config_test_custom_message_template_with_event_id
@message_template = '{\"id\":\"~id~\", \"message\":\"~text~\"}'
end
def test_custom_message_template_with_event_id
event_id = 'event_id_with_generic_text_01'
headers = {'accept' => 'text/html', 'Event-Id' => event_id }
body = 'test message'
channel = 'ch_test_custom_message_template_with_event_id'
response = ''
EventMachine.run {
sub = EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel.to_s).get
sub.stream { | chunk |
response += chunk
if response.include?("\r\n\r\n")
assert_equal(%(:\r\nid: #{event_id}\r\ndata: {"id":"1", "message":"#{body}"}\r\n\r\n), response, "The published message was not received correctly")
EventMachine.stop
end
}
publish_message_inline(channel, headers, body)
add_test_timeout
}
end
def config_test_custom_message_template_with_event_type
@message_template = '{\"id\":\"~id~\", \"message\":\"~text~\"}'
end
def test_custom_message_template_with_event_type
event_type = 'event_type_with_generic_text_01'
headers = {'accept' => 'text/html', 'Event-type' => event_type }
body = 'test message'
channel = 'ch_test_custom_message_template_with_event_type'
response = ''
EventMachine.run {
sub = EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel.to_s).get
sub.stream { | chunk |
response += chunk
if response.include?("\r\n\r\n")
assert_equal(%(:\r\nevent: #{event_type}\r\ndata: {"id":"1", "message":"#{body}"}\r\n\r\n), response, "The published message was not received correctly")
EventMachine.stop
end
}
publish_message_inline(channel, headers, body)
add_test_timeout
}
end
def test_each_line_on_posted_message_should_be_applied_to_template
headers = {'accept' => 'text/html'}
body = "line 1\nline 2\rline 3\r\nline 4"
channel = 'ch_test_each_line_on_posted_message_should_be_applied_to_template'
EventMachine.run {
sub = EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel.to_s).get
sub.stream { | chunk |
if chunk.include?("line 4")
assert_equal("data: line 1\r\ndata: line 2\r\ndata: line 3\r\ndata: line 4\r\n\r\n", chunk, "Wrong data message")
EventMachine.stop
end
}
publish_message_inline(channel, headers, body)
add_test_timeout
}
end
def test_escaped_new_lines_on_posted_message_should_be_treated_as_single_line
headers = {'accept' => 'text/html'}
body = "line 1\\nline 2"
channel = 'ch_test_escaped_new_lines_on_posted_message_should_be_treated_as_single_line'
EventMachine.run {
sub = EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel.to_s).get
sub.stream { | chunk |
if chunk.include?("line 2")
assert_equal("data: line 1\\nline 2\r\n\r\n", chunk, "Wrong data message")
EventMachine.stop
end
}
publish_message_inline(channel, headers, body)
add_test_timeout
}
end
def config_test_ping_message_on_event_source
@ping_message_interval = '1s'
@message_template = '{\"id\":\"~id~\", \"message\":\"~text~\"}'
end
def test_ping_message_on_event_source
headers = {'accept' => 'text/html'}
channel = 'ch_test_ping_message_on_event_source'
EventMachine.run {
sub = EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel.to_s).get
sub.stream { | chunk |
if chunk.include?("-1")
assert_equal(": -1\r\n", chunk, "Wrong ping message")
EventMachine.stop
end
}
add_test_timeout
}
end
def test_get_old_messages_by_last_event_id
channel = 'ch_test_get_old_messages_by_last_event_id'
response = ''
EventMachine.run {
publish_message_inline(channel, {'accept' => 'text/html', 'Event-Id' => 'event 1' }, 'msg 1')
publish_message_inline(channel, {'accept' => 'text/html', 'Event-Id' => 'event 2' }, 'msg 2')
publish_message_inline(channel, {'accept' => 'text/html' }, 'msg 3')
publish_message_inline(channel, {'accept' => 'text/html', 'Event-Id' => 'event 3' }, 'msg 4')
sub = EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel.to_s).get :head => {'Last-Event-Id' => 'event 2' }
sub.stream { | chunk |
response += chunk
if response.include?("msg 4")
assert_equal(":\r\ndata: msg 3\r\n\r\nid: event 3\r\ndata: msg 4\r\n\r\n", response, "The published message was not received correctly")
EventMachine.stop
end
}
add_test_timeout
}
end
def config_test_get_old_messages_by_last_event_id_without_found_event
@ping_message_interval = '1s'
end
def test_get_old_messages_by_last_event_id_without_found_event
channel = 'ch_test_get_old_messages_by_last_event_id_without_found_event'
response = ''
EventMachine.run {
publish_message_inline(channel, {'accept' => 'text/html', 'Event-Id' => 'event 1' }, 'msg 1')
publish_message_inline(channel, {'accept' => 'text/html', 'Event-Id' => 'event 2' }, 'msg 2')
publish_message_inline(channel, {'accept' => 'text/html' }, 'msg 3')
publish_message_inline(channel, {'accept' => 'text/html', 'Event-Id' => 'event 3' }, 'msg 4')
sub = EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel.to_s).get :head => {'Last-Event-Id' => 'event_not_found' }
sub.stream { | chunk |
if chunk.include?("-1")
assert_equal(": -1\r\n", chunk, "Received any other message instead of ping")
EventMachine.stop
end
}
add_test_timeout
}
end
end
require File.expand_path('base_test_case', File.dirname(__FILE__))
class TestSubscriberLongPolling < Test::Unit::TestCase
include BaseTestCase
def global_configuration
@ping_message_interval = nil
@header_template = nil
@footer_template = nil
@message_template = nil
@subscriber_mode = 'long-polling'
end
def test_disconnect_after_receive_a_message_when_longpolling_is_on
headers = {'accept' => 'application/json'}
channel = 'ch_test_disconnect_after_receive_a_message_when_longpolling_is_on'
body = 'body'
response = ""
EventMachine.run {
sub_1 = EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel.to_s).get :head => headers, :timeout => 30
sub_1.stream { |chunk|
response += chunk
}
sub_1.callback { |chunk|
assert_equal("#{body}\r\n", response, "Wrong message")
headers.merge!({'If-Modified-Since' => sub_1.response_header['LAST_MODIFIED'], 'If-None-Match' => sub_1.response_header['ETAG']})
response = ""
sub_2 = EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel.to_s).get :head => headers, :timeout => 30
sub_2.stream { |chunk|
response += chunk
}
sub_2.callback { |chunk|
assert_equal("#{body} 1\r\n", response, "Wrong message")
EventMachine.stop
}
publish_message_inline(channel, {'accept' => 'text/html'}, body + " 1")
}
publish_message_inline(channel, {'accept' => 'text/html'}, body)
add_test_timeout
}
end
def test_disconnect_after_receive_old_messages_by_backtrack_when_longpolling_is_on
channel = 'ch_test_disconnect_after_receive_old_messages_by_backtrack_when_longpolling_is_on'
response = ''
EventMachine.run {
publish_message_inline(channel, {'accept' => 'text/html'}, 'msg 1')
publish_message_inline(channel, {'accept' => 'text/html'}, 'msg 2')
publish_message_inline(channel, {'accept' => 'text/html'}, 'msg 3')
publish_message_inline(channel, {'accept' => 'text/html'}, 'msg 4')
sub = EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel.to_s + '.b2').get
sub.stream { | chunk |
response += chunk
}
sub.callback { |chunk|
assert_equal("msg 3\r\nmsg 4\r\n", response, "The published message was not received correctly")
response = ''
sub_1 = EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel.to_s).get :head => {'If-Modified-Since' => sub.response_header['LAST_MODIFIED'], 'If-None-Match' => sub.response_header['ETAG']}
sub_1.stream { | chunk |
response += chunk
}
sub_1.callback { |chunk|
assert_equal("msg 5\r\n", response, "The published message was not received correctly")
EventMachine.stop
}
publish_message_inline(channel, {'accept' => 'text/html'}, 'msg 5')
}
add_test_timeout
}
end
def test_disconnect_after_receive_old_messages_by_last_event_id_when_longpolling_is_on
channel = 'ch_test_disconnect_after_receive_old_messages_by_last_event_id_when_longpolling_is_on'
response = ''
EventMachine.run {
publish_message_inline(channel, {'accept' => 'text/html', 'Event-Id' => 'event 1' }, 'msg 1')
publish_message_inline(channel, {'accept' => 'text/html', 'Event-Id' => 'event 2' }, 'msg 2')
publish_message_inline(channel, {'accept' => 'text/html' }, 'msg 3')
publish_message_inline(channel, {'accept' => 'text/html', 'Event-Id' => 'event 3' }, 'msg 4')
sub = EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel.to_s).get :head => {'Last-Event-Id' => 'event 2' }
sub.stream { | chunk |
response += chunk
}
sub.callback { |chunk|
assert_equal("msg 3\r\nmsg 4\r\n", response, "The published message was not received correctly")
EventMachine.stop
}
add_test_timeout
}
end
def test_receive_old_messages_from_different_channels
headers = {'accept' => 'application/json'}
channel_1 = 'ch_test_receive_old_messages_from_different_channels_1'
channel_2 = 'ch_test_receive_old_messages_from_different_channels_2'
body = 'body'
response = ''
EventMachine.run {
publish_message_inline(channel_1, {'accept' => 'text/html'}, body + "_1")
publish_message_inline(channel_2, {'accept' => 'text/html'}, body + "_2")
sub_1 = EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel_2.to_s + '/' + channel_1.to_s).get :head => headers, :timeout => 30
sub_1.callback {
assert_equal(200, sub_1.response_header.status, "Wrong status")
assert_not_equal("", sub_1.response_header['LAST_MODIFIED'].to_s, "Wrong header")
assert_not_equal("", sub_1.response_header['ETAG'].to_s, "Wrong header")
assert_equal("#{body}_2\r\n#{body}_1\r\n", sub_1.response, "The published message was not received correctly")
headers.merge!({'If-Modified-Since' => sub_1.response_header['LAST_MODIFIED'], 'If-None-Match' => sub_1.response_header['ETAG']})
sub_2 = EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel_2.to_s + '/' + channel_1.to_s).get :head => headers, :timeout => 30
sub_2.callback {
assert_equal(200, sub_2.response_header.status, "Wrong status")
assert_not_equal(sub_1.response_header['LAST_MODIFIED'], sub_2.response_header['LAST_MODIFIED'].to_s, "Wrong header")
assert_equal("0", sub_2.response_header['ETAG'].to_s, "Wrong header")
assert_equal("#{body}1_1\r\n", sub_2.response, "The published message was not received correctly")
headers.merge!({'If-Modified-Since' => sub_2.response_header['LAST_MODIFIED'], 'If-None-Match' => sub_2.response_header['ETAG']})
sub_3 = EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel_2.to_s + '/' + channel_1.to_s).get :head => headers, :timeout => 30
sub_3.callback {
assert_equal(200, sub_3.response_header.status, "Wrong status")
assert_not_equal(sub_2.response_header['LAST_MODIFIED'], sub_3.response_header['LAST_MODIFIED'].to_s, "Wrong header")
assert_equal("0", sub_3.response_header['ETAG'].to_s, "Wrong header")
assert_equal("#{body}1_2\r\n", sub_3.response, "The published message was not received correctly")
EventMachine.stop
}
sleep(1) # to publish the second message in a different second from the first
publish_message_inline(channel_2, {'accept' => 'text/html'}, body + "1_2")
}
sleep(1) # to publish the second message in a different second from the first
publish_message_inline(channel_1, {'accept' => 'text/html'}, body + "1_1")
}
add_test_timeout
}
end
def config_test_disconnect_after_receive_a_message_when_has_header_mode_longpolling
@subscriber_mode = nil
end
def test_disconnect_after_receive_a_message_when_has_header_mode_longpolling
headers = {'accept' => 'application/json', 'X-Nginx-PushStream-Mode' => 'long-polling'}
channel = 'ch_test_disconnect_after_receive_a_message_when_has_header_mode_longpolling'
body = 'body'
response = ""
EventMachine.run {
sub_1 = EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel.to_s).get :head => headers, :timeout => 30
sub_1.stream { |chunk|
response += chunk
}
sub_1.callback { |chunk|
assert_equal("#{body}\r\n", response, "Wrong message")
headers.merge!({'If-Modified-Since' => sub_1.response_header['LAST_MODIFIED'], 'If-None-Match' => sub_1.response_header['ETAG']})
response = ""
sub_2 = EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel.to_s).get :head => headers, :timeout => 30
sub_2.stream { |chunk|
response += chunk
}
sub_2.callback { |chunk|
assert_equal("#{body} 1\r\n", response, "Wrong message")
EventMachine.stop
}
publish_message_inline(channel, {'accept' => 'text/html'}, body + " 1")
}
publish_message_inline(channel, {'accept' => 'text/html'}, body)
add_test_timeout
}
end
def config_test_disconnect_after_receive_old_messages_by_backtrack_when_has_header_mode_longpolling
@subscriber_mode = nil
end
def test_disconnect_after_receive_old_messages_by_backtrack_when_has_header_mode_longpolling
headers = {'accept' => 'application/json', 'X-Nginx-PushStream-Mode' => 'long-polling'}
channel = 'ch_test_disconnect_after_receive_old_messages_by_backtrack_when_has_header_mode_longpolling'
response = ''
EventMachine.run {
publish_message_inline(channel, {'accept' => 'text/html'}, 'msg 1')
publish_message_inline(channel, {'accept' => 'text/html'}, 'msg 2')
publish_message_inline(channel, {'accept' => 'text/html'}, 'msg 3')
publish_message_inline(channel, {'accept' => 'text/html'}, 'msg 4')
sub = EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel.to_s + '.b2').get :head => headers
sub.stream { | chunk |
response += chunk
}
sub.callback { |chunk|
assert_equal("msg 3\r\nmsg 4\r\n", response, "The published message was not received correctly")
headers.merge!({'If-Modified-Since' => sub.response_header['LAST_MODIFIED'], 'If-None-Match' => sub.response_header['ETAG']})
response = ''
sub_1 = EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel.to_s).get :head => headers
sub_1.stream { | chunk |
response += chunk
}
sub_1.callback { |chunk|
assert_equal("msg 5\r\n", response, "The published message was not received correctly")
EventMachine.stop
}
publish_message_inline(channel, {'accept' => 'text/html'}, 'msg 5')
}
add_test_timeout
}
end
def config_test_disconnect_after_receive_old_messages_by_last_event_id_when_has_header_mode_longpolling
@subscriber_mode = nil
end
def test_disconnect_after_receive_old_messages_by_last_event_id_when_has_header_mode_longpolling
channel = 'ch_test_disconnect_after_receive_old_messages_by_last_event_id_when_has_header_mode_longpolling'
response = ''
EventMachine.run {
publish_message_inline(channel, {'accept' => 'text/html', 'Event-Id' => 'event 1' }, 'msg 1')
publish_message_inline(channel, {'accept' => 'text/html', 'Event-Id' => 'event 2' }, 'msg 2')
publish_message_inline(channel, {'accept' => 'text/html' }, 'msg 3')
publish_message_inline(channel, {'accept' => 'text/html', 'Event-Id' => 'event 3' }, 'msg 4')
sub = EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel.to_s).get :head => {'Last-Event-Id' => 'event 2', 'X-Nginx-PushStream-Mode' => 'long-polling' }
sub.stream { | chunk |
response += chunk
}
sub.callback { |chunk|
assert_equal("msg 3\r\nmsg 4\r\n", response, "The published message was not received correctly")
EventMachine.stop
}
add_test_timeout
}
end
def config_test_receive_old_messages_from_different_channels_when_has_header_mode_longpolling
@subscriber_mode = nil
end
def test_receive_old_messages_from_different_channels_when_has_header_mode_longpolling
headers = {'accept' => 'application/json', 'X-Nginx-PushStream-Mode' => 'long-polling'}
channel_1 = 'ch_test_receive_old_messages_from_different_channels_when_has_header_mode_longpolling_1'
channel_2 = 'ch_test_receive_old_messages_from_different_channels_when_has_header_mode_longpolling_2'
body = 'body'
response = ''
EventMachine.run {
publish_message_inline(channel_1, {'accept' => 'text/html'}, body + "_1")
publish_message_inline(channel_2, {'accept' => 'text/html'}, body + "_2")
sub_1 = EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel_2.to_s + '/' + channel_1.to_s).get :head => headers, :timeout => 30
sub_1.callback {
assert_equal(200, sub_1.response_header.status, "Wrong status")
assert_not_equal("", sub_1.response_header['LAST_MODIFIED'].to_s, "Wrong header")
assert_not_equal("", sub_1.response_header['ETAG'].to_s, "Wrong header")
assert_equal("#{body}_2\r\n#{body}_1\r\n", sub_1.response, "The published message was not received correctly")
headers.merge!({'If-Modified-Since' => sub_1.response_header['LAST_MODIFIED'], 'If-None-Match' => sub_1.response_header['ETAG']})
sub_2 = EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel_2.to_s + '/' + channel_1.to_s).get :head => headers, :timeout => 30
sub_2.callback {
assert_equal(200, sub_2.response_header.status, "Wrong status")
assert_not_equal(sub_1.response_header['LAST_MODIFIED'], sub_2.response_header['LAST_MODIFIED'].to_s, "Wrong header")
assert_equal("0", sub_2.response_header['ETAG'].to_s, "Wrong header")
assert_equal("#{body}1_1\r\n", sub_2.response, "The published message was not received correctly")
headers.merge!({'If-Modified-Since' => sub_2.response_header['LAST_MODIFIED'], 'If-None-Match' => sub_2.response_header['ETAG']})
sub_3 = EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel_2.to_s + '/' + channel_1.to_s).get :head => headers, :timeout => 30
sub_3.callback {
assert_equal(200, sub_3.response_header.status, "Wrong status")
assert_not_equal(sub_2.response_header['LAST_MODIFIED'], sub_3.response_header['LAST_MODIFIED'].to_s, "Wrong header")
assert_equal("0", sub_3.response_header['ETAG'].to_s, "Wrong header")
assert_equal("#{body}1_2\r\n", sub_3.response, "The published message was not received correctly")
EventMachine.stop
}
sleep(1) # to publish the second message in a different second from the first
publish_message_inline(channel_2, {'accept' => 'text/html'}, body + "1_2")
}
sleep(1) # to publish the second message in a different second from the first
publish_message_inline(channel_1, {'accept' => 'text/html'}, body + "1_1")
}
add_test_timeout
}
end
def config_test_disconnect_long_polling_subscriber_when_disconnect_timeout_is_set
@subscriber_connection_timeout = "15s"
end
def test_disconnect_long_polling_subscriber_when_disconnect_timeout_is_set
channel = 'ch_test_disconnect_long_polling_subscriber_when_disconnect_timeout_is_set'
start = Time.now
EventMachine.run {
sub = EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel.to_s, :inactivity_timeout => 30).get :timeout => 30
sub.callback {
stop = Time.now
elapsed = time_diff_sec(start, stop)
assert(elapsed >= 15 && elapsed <= 15.5, "Disconnect was in #{elapsed} seconds")
assert_equal(304, sub.response_header.status, "Wrong status")
assert_equal(Time.now.utc.strftime("%a, %d %b %Y %T %Z"), sub.response_header['LAST_MODIFIED'].to_s, "Wrong header")
assert_equal("0", sub.response_header['ETAG'].to_s, "Wrong header")
assert_equal(0, sub.response_header.content_length, "Wrong response")
EventMachine.stop
}
add_test_timeout(20)
}
end
def config_test_disconnect_long_polling_subscriber_when_longpolling_timeout_is_set
@subscriber_connection_timeout = "15s"
@longpolling_connection_ttl = "5s"
end
def test_disconnect_long_polling_subscriber_when_longpolling_timeout_is_set
channel = 'ch_test_disconnect_long_polling_subscriber_when_longpolling_timeout_is_set'
start = Time.now
EventMachine.run {
sub = EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel.to_s).get :timeout => 30
sub.callback {
stop = Time.now
elapsed = time_diff_sec(start, stop)
assert(elapsed >= 5 && elapsed <= 5.5, "Disconnect was in #{elapsed} seconds")
assert_equal(304, sub.response_header.status, "Wrong status")
assert_equal(Time.now.utc.strftime("%a, %d %b %Y %T %Z"), sub.response_header['LAST_MODIFIED'].to_s, "Wrong header")
assert_equal("0", sub.response_header['ETAG'].to_s, "Wrong header")
assert_equal(0, sub.response_header.content_length, "Wrong response")
EventMachine.stop
}
add_test_timeout(20)
}
end
def config_test_disconnect_long_polling_subscriber_when_only_longpolling_timeout_is_set
@longpolling_connection_ttl = "3s"
end
def test_disconnect_long_polling_subscriber_when_only_longpolling_timeout_is_set
channel = 'ch_test_disconnect_long_polling_subscriber_when_only_longpolling_timeout_is_set'
start = Time.now
EventMachine.run {
sub = EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel.to_s).get :timeout => 30
sub.callback {
stop = Time.now
elapsed = time_diff_sec(start, stop)
assert(elapsed >= 3 && elapsed <= 3.5, "Disconnect was in #{elapsed} seconds")
assert_equal(304, sub.response_header.status, "Wrong status")
assert_equal(Time.now.utc.strftime("%a, %d %b %Y %T %Z"), sub.response_header['LAST_MODIFIED'].to_s, "Wrong header")
assert_equal("0", sub.response_header['ETAG'].to_s, "Wrong header")
assert_equal(0, sub.response_header.content_length, "Wrong response")
EventMachine.stop
}
add_test_timeout(20)
}
end
def config_test_not_receive_ping_message
@subscriber_connection_timeout = "5s"
@ping_message_interval = "1s"
end
def test_not_receive_ping_message
channel = 'ch_test_not_receive_ping_message'
EventMachine.run {
sub = EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel.to_s).get :timeout => 30
sub.callback {
assert_equal(304, sub.response_header.status, "Wrong status")
assert_equal(0, sub.response_header.content_length, "Wrong response")
EventMachine.stop
}
add_test_timeout(10)
}
end
def config_test_receiving_messages_with_etag_greather_than_recent_message
@store_messages = "on"
@message_template = '{\"id\":\"~id~\", \"message\":\"~text~\"}'
end
def test_receiving_messages_with_etag_greather_than_recent_message
headers = {'accept' => 'application/json'}
body_prefix = 'published message '
channel = 'ch_test_receiving_messages_with_etag_greather_than_recent_message'
messagens_to_publish = 10
EventMachine.run {
i = 0
stored_messages = 0
EM.add_periodic_timer(0.001) do
if i < messagens_to_publish
i += 1
publish_message_inline(channel.to_s, headers, body_prefix + i.to_s)
else
end
end
EM.add_timer(1) do
pub = EventMachine::HttpRequest.new(nginx_address + '/pub?id=' + channel.to_s ).post :head => headers, :body => body_prefix + i.to_s, :timeout => 30
pub.callback {
response = JSON.parse(pub.response)
stored_messages = response["stored_messages"].to_i
}
end
EM.add_timer(2) do
sub = EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel.to_s).get :head => {'If-Modified-Since' => 'Thu, 1 Jan 1970 00:00:00 GMT', 'If-None-Match' => 0}, :timeout => 30
sub.callback {
assert_equal(200, sub.response_header.status, "Wrong status")
assert(stored_messages == (messagens_to_publish + 1), "Do not stored all published messages")
messages = sub.response.split("\r\n")
assert_equal((messagens_to_publish + 1), messages.count, "Wrong header")
messages.each_with_index do |content, index|
message = JSON.parse(content)
assert_equal((index + 1), message["id"].to_i, "Wrong message order")
end
EventMachine.stop
}
end
add_test_timeout
}
end
def config_test_receiving_messages_when_connected_in_more_then_one_channel
@store_messages = "on"
@message_template = '{\"id\":\"~id~\", \"message\":\"~text~\", \"channel\":\"~channel~\"}'
end
def test_receiving_messages_when_connected_in_more_then_one_channel
headers = {'accept' => 'application/json'}
body = 'published message'
channel_1 = 'ch_test_receiving_messages_when_connected_in_more_then_one_channel_1'
channel_2 = 'ch_test_receiving_messages_when_connected_in_more_then_one_channel_2'
EventMachine.run {
sub_1 = EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel_1.to_s + '/' + channel_2.to_s).get :head => {'If-Modified-Since' => 'Thu, 1 Jan 1970 00:00:00 GMT', 'If-None-Match' => 0}, :timeout => 30
sub_1.callback {
assert_equal(200, sub_1.response_header.status, "Wrong status")
response = JSON.parse(sub_1.response)
assert_equal(channel_1, response["channel"], "Wrong channel")
sub_2 = EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel_1.to_s + '/' + channel_2.to_s).get :head => {'If-Modified-Since' => sub_1.response_header['LAST_MODIFIED'], 'If-None-Match' => sub_1.response_header['ETAG']}, :timeout => 30
sub_2.callback {
assert_equal(200, sub_2.response_header.status, "Wrong status")
response = JSON.parse(sub_2.response)
assert_equal(channel_2, response["channel"], "Wrong channel")
assert_equal(sub_1.response_header['ETAG'].to_i + 1, sub_2.response_header['ETAG'].to_i)
EventMachine.stop
}
}
publish_message_inline(channel_1.to_s, headers, body)
publish_message_inline(channel_2.to_s, headers, body)
add_test_timeout
}
end
def config_test_delete_channel_with_long_polling_subscriber
@publisher_mode = 'admin'
@message_template = '{\"id\":\"~id~\", \"message\":\"~text~\", \"channel\":\"~channel~\"}'
end
def test_delete_channel_with_long_polling_subscriber
headers = {'accept' => 'application/json'}
body = 'published message'
channel = 'ch_test_delete_channel_with_long_polling_subscriber'
resp = ""
EventMachine.run {
sub_1 = EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel.to_s).get :head => headers, :timeout => 30
sub_1.callback {
assert_equal(200, sub_1.response_header.status, "Wrong status")
response = JSON.parse(sub_1.response)
assert_equal(channel, response["channel"], "Wrong channel")
assert_equal(-2, response["id"].to_i, "Wrong channel")
EventMachine.stop
}
pub = EventMachine::HttpRequest.new(nginx_address + '/pub?id=' + channel.to_s).delete :head => headers, :timeout => 30
pub.callback {
assert_equal(200, pub.response_header.status, "Request was not received")
assert_equal(0, pub.response_header.content_length, "Should response only with headers")
assert_equal("Channel deleted.", pub.response_header['X_NGINX_PUSHSTREAM_EXPLAIN'], "Didn't receive the right error message")
}
add_test_timeout
}
end
def config_test_send_modified_since_and_none_match_values_not_using_headers
@last_received_message_time = "$arg_time"
@last_received_message_tag = "$arg_tag"
end
def test_send_modified_since_and_none_match_values_not_using_headers
headers = {'accept' => 'application/json'}
channel = 'ch_test_send_modified_since_and_none_match_values_not_using_headers'
body = 'body'
response = ""
EventMachine.run {
sub_1 = EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel.to_s).get :head => headers, :timeout => 30
sub_1.stream { |chunk|
response += chunk
}
sub_1.callback { |chunk|
assert_equal("#{body}\r\n", response, "Wrong message")
time = sub_1.response_header['LAST_MODIFIED']
tag = sub_1.response_header['ETAG']
response = ""
sub_2 = EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel.to_s + '?time=' + time + '&tag=' + tag).get :head => headers, :timeout => 30
sub_2.stream { |chunk|
response += chunk
}
sub_2.callback { |chunk|
assert_equal("#{body} 1\r\n", response, "Wrong message")
EventMachine.stop
}
publish_message_inline(channel, {'accept' => 'text/html'}, body + " 1")
}
publish_message_inline(channel, {'accept' => 'text/html'}, body)
add_test_timeout
}
end
def test_return_message_using_function_name_specified_in_callback_parameter
headers = {'accept' => 'application/javascript'}
channel = 'ch_test_return_message_using_function_name_specified_in_callback_parameter'
body = 'body'
response = ""
callback_function_name = "callback_function"
EventMachine.run {
sub_1 = EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel.to_s + '?callback=' + callback_function_name).get :head => headers, :timeout => 30
sub_1.callback {
assert_equal("#{callback_function_name}\r\n([#{body}\r\n]);\r\n", sub_1.response, "Wrong message")
EventMachine.stop
}
publish_message_inline(channel, {'accept' => 'text/html'}, body)
add_test_timeout
}
end
def test_return_old_messages_using_function_name_specified_in_callback_parameter_grouping_in_one_answer
headers = {'accept' => 'application/javascript'}
channel = 'ch_test_return_old_messages_using_function_name_specified_in_callback_parameter_grouping_in_one_answer'
body = 'body'
response = ""
callback_function_name = "callback_function"
EventMachine.run {
publish_message_inline(channel, {'accept' => 'text/html'}, body)
publish_message_inline(channel, {'accept' => 'text/html'}, body + "1")
sub_1 = EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel.to_s + '.b2' + '?callback=' + callback_function_name).get :head => headers, :timeout => 30
sub_1.callback {
assert_equal("#{callback_function_name}\r\n([#{body}\r\n,#{body + "1"}\r\n,]);\r\n", sub_1.response, "Wrong message")
EventMachine.stop
}
add_test_timeout
}
end
def config_test_force_content_type_to_be_application_javascript_when_using_function_name_specified_in_callback_parameter
@content_type = "anything/value"
end
def test_force_content_type_to_be_application_javascript_when_using_function_name_specified_in_callback_parameter
headers = {'accept' => 'otherknown/value'}
channel = 'test_force_content_type_to_be_application_javascript_when_using_function_name_specified_in_callback_parameter'
body = 'body'
response = ""
callback_function_name = "callback_function"
EventMachine.run {
sub_1 = EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel.to_s + '?callback=' + callback_function_name).get :head => headers, :timeout => 30
sub_1.callback {
assert_equal('application/javascript', sub_1.response_header['CONTENT_TYPE'], "Didn't receive the right content type")
EventMachine.stop
}
publish_message_inline(channel, {'accept' => 'text/html'}, body)
add_test_timeout
}
end
end
require File.expand_path('base_test_case', File.dirname(__FILE__))
class TestSubscriberPolling < Test::Unit::TestCase
include BaseTestCase
def global_configuration
@ping_message_interval = nil
@header_template = nil
@footer_template = nil
@message_template = nil
@subscriber_mode = 'polling'
end
def test_receive_a_304_when_has_no_messages
headers = {'accept' => 'application/json'}
channel = 'ch_test_receive_a_304_when_has_no_messages'
body = 'body'
EventMachine.run {
sub_1 = EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel.to_s).get :head => headers, :timeout => 30
sub_1.callback {
assert_equal(304, sub_1.response_header.status, "Wrong status")
assert_equal("", sub_1.response_header['LAST_MODIFIED'].to_s, "Wrong header")
assert_equal("", sub_1.response_header['ETAG'].to_s, "Wrong header")
assert_equal(0, sub_1.response_header.content_length, "Wrong response")
EventMachine.stop
}
add_test_timeout
}
end
def test_receive_a_304_when_has_no_messages_keeping_headers
headers = {'accept' => 'application/json'}
channel = 'ch_test_receive_a_304_when_has_no_messages_keeping_headers'
body = 'body'
headers = headers.merge({'If-Modified-Since' => Time.now.utc.strftime("%a, %d %b %Y %T %Z"), 'If-None-Match' => '3'})
EventMachine.run {
sub_1 = EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel.to_s).get :head => headers, :timeout => 30
sub_1.callback {
assert_equal(304, sub_1.response_header.status, "Wrong status")
assert_equal(headers['If-Modified-Since'], sub_1.response_header['LAST_MODIFIED'].to_s, "Wrong header")
assert_equal(headers['If-None-Match'], sub_1.response_header['ETAG'].to_s, "Wrong header")
assert_equal(0, sub_1.response_header.content_length, "Wrong response")
EventMachine.stop
}
add_test_timeout
}
end
def test_receive_specific_headers_when_has_messages
headers = {'accept' => 'application/json'}
channel = 'ch_test_receive_specific_headers_when_has_messages'
body = 'body'
EventMachine.run {
publish_message_inline(channel, {'accept' => 'text/html'}, body)
sub_1 = EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel.to_s).get :head => headers, :timeout => 30
sub_1.callback {
assert_equal(200, sub_1.response_header.status, "Wrong status")
assert_not_equal("", sub_1.response_header['LAST_MODIFIED'].to_s, "Wrong header")
assert_equal("0", sub_1.response_header['ETAG'].to_s, "Wrong header")
assert_equal("#{body}\r\n", sub_1.response, "The published message was not received correctly")
EventMachine.stop
}
add_test_timeout
}
end
def test_receive_old_messages_by_if_modified_since_header
headers = {'accept' => 'application/json'}
channel = 'ch_test_getting_messages_by_if_modified_since_header'
body = 'body'
EventMachine.run {
publish_message_inline(channel, {'accept' => 'text/html'}, body)
sub_1 = EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel.to_s).get :head => headers, :timeout => 30
sub_1.callback {
assert_equal(200, sub_1.response_header.status, "Wrong status")
assert_not_equal("", sub_1.response_header['LAST_MODIFIED'].to_s, "Wrong header")
assert_not_equal("", sub_1.response_header['ETAG'].to_s, "Wrong header")
assert_equal("#{body}\r\n", sub_1.response, "The published message was not received correctly")
headers.merge!({'If-Modified-Since' => sub_1.response_header['LAST_MODIFIED'], 'If-None-Match' => sub_1.response_header['ETAG']})
sub_2 = EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel.to_s).get :head => headers, :timeout => 30
sub_2.callback {
assert_equal(304, sub_2.response_header.status, "Wrong status")
assert_equal(0, sub_2.response_header.content_length, "Wrong response")
assert_equal(sub_1.response_header['LAST_MODIFIED'], sub_2.response_header['LAST_MODIFIED'].to_s, "Wrong header")
assert_equal(sub_1.response_header['ETAG'], sub_2.response_header['ETAG'].to_s, "Wrong header")
sleep(1) # to publish the second message in a different second from the first
publish_message_inline(channel, {'accept' => 'text/html'}, body + "1")
headers.merge!({'If-Modified-Since' => sub_2.response_header['LAST_MODIFIED'], 'If-None-Match' => sub_2.response_header['ETAG']})
sub_3 = EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel.to_s).get :head => headers, :timeout => 30
sub_3.callback {
assert_equal(200, sub_3.response_header.status, "Wrong status")
assert_not_equal(sub_2.response_header['LAST_MODIFIED'], sub_3.response_header['LAST_MODIFIED'].to_s, "Wrong header")
assert_equal("0", sub_3.response_header['ETAG'].to_s, "Wrong header")
assert_equal("#{body}1\r\n", sub_3.response, "The published message was not received correctly")
EventMachine.stop
}
}
}
add_test_timeout
}
end
def test_receive_old_messages_by_backtrack
headers = {'accept' => 'application/json'}
channel = 'ch_test_getting_messages_by_if_modified_since_header'
body = 'body'
EventMachine.run {
publish_message_inline(channel, {'accept' => 'text/html'}, body)
publish_message_inline(channel, {'accept' => 'text/html'}, body + "1")
publish_message_inline(channel, {'accept' => 'text/html'}, body + "2")
sub_1 = EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel.to_s + '.b1').get :head => headers, :timeout => 30
sub_1.callback {
assert_equal(200, sub_1.response_header.status, "Wrong status")
assert_not_equal("", sub_1.response_header['LAST_MODIFIED'].to_s, "Wrong header")
assert_equal("2", sub_1.response_header['ETAG'].to_s, "Wrong header")
assert_equal("#{body}2\r\n", sub_1.response, "The published message was not received correctly")
headers.merge!({'If-Modified-Since' => sub_1.response_header['LAST_MODIFIED'], 'If-None-Match' => sub_1.response_header['ETAG']})
sub_2 = EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel.to_s).get :head => headers, :timeout => 30
sub_2.callback {
assert_equal(304, sub_2.response_header.status, "Wrong status")
assert_equal(0, sub_2.response_header.content_length, "Wrong response")
assert_equal(sub_1.response_header['LAST_MODIFIED'], sub_2.response_header['LAST_MODIFIED'].to_s, "Wrong header")
assert_equal(sub_1.response_header['ETAG'], sub_2.response_header['ETAG'].to_s, "Wrong header")
sleep(1) # to publish the second message in a different second from the first
publish_message_inline(channel, {'accept' => 'text/html'}, body + "3")
headers.merge!({'If-Modified-Since' => sub_2.response_header['LAST_MODIFIED'], 'If-None-Match' => sub_2.response_header['ETAG']})
sub_3 = EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel.to_s).get :head => headers, :timeout => 30
sub_3.callback {
assert_equal(200, sub_3.response_header.status, "Wrong status")
assert_not_equal(sub_2.response_header['LAST_MODIFIED'], sub_3.response_header['LAST_MODIFIED'].to_s, "Wrong header")
assert_equal("0", sub_3.response_header['ETAG'].to_s, "Wrong header")
assert_equal("#{body}3\r\n", sub_3.response, "The published message was not received correctly")
EventMachine.stop
}
}
}
add_test_timeout
}
end
def test_receive_old_messages_by_last_event_id
headers = {'accept' => 'application/json'}
channel = 'ch_test_receive_old_messages_by_last_event_id'
body = 'body'
EventMachine.run {
publish_message_inline(channel, {'accept' => 'text/html', 'Event-Id' => 'event 1' }, 'msg 1')
publish_message_inline(channel, {'accept' => 'text/html', 'Event-Id' => 'event 2' }, 'msg 2')
publish_message_inline(channel, {'accept' => 'text/html' }, 'msg 3')
publish_message_inline(channel, {'accept' => 'text/html', 'Event-Id' => 'event 3' }, 'msg 4')
sub_1 = EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel.to_s).get :head => {'Last-Event-Id' => 'event 2' }
sub_1.callback {
assert_equal(200, sub_1.response_header.status, "Wrong status")
assert_not_equal("", sub_1.response_header['LAST_MODIFIED'].to_s, "Wrong header")
assert_equal("3", sub_1.response_header['ETAG'].to_s, "Wrong header")
assert_equal("msg 3\r\nmsg 4\r\n", sub_1.response, "The published message was not received correctly")
headers.merge!({'If-Modified-Since' => sub_1.response_header['LAST_MODIFIED'], 'If-None-Match' => sub_1.response_header['ETAG']})
sub_2 = EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel.to_s).get :head => headers, :timeout => 30
sub_2.callback {
assert_equal(304, sub_2.response_header.status, "Wrong status")
assert_equal(0, sub_2.response_header.content_length, "Wrong response")
assert_equal(sub_1.response_header['LAST_MODIFIED'], sub_2.response_header['LAST_MODIFIED'].to_s, "Wrong header")
assert_equal(sub_1.response_header['ETAG'], sub_2.response_header['ETAG'].to_s, "Wrong header")
sleep(1) # to publish the second message in a different second from the first
publish_message_inline(channel, {'accept' => 'text/html'}, body + "3")
headers.merge!({'If-Modified-Since' => sub_2.response_header['LAST_MODIFIED'], 'If-None-Match' => sub_2.response_header['ETAG']})
sub_3 = EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel.to_s).get :head => headers, :timeout => 30
sub_3.callback {
assert_equal(200, sub_3.response_header.status, "Wrong status")
assert_not_equal(sub_2.response_header['LAST_MODIFIED'], sub_3.response_header['LAST_MODIFIED'].to_s, "Wrong header")
assert_equal("0", sub_3.response_header['ETAG'].to_s, "Wrong header")
assert_equal("#{body}3\r\n", sub_3.response, "The published message was not received correctly")
EventMachine.stop
}
}
}
add_test_timeout
}
end
def test_receive_old_messages_from_different_channels
headers = {'accept' => 'application/json'}
channel_1 = 'ch_test_receive_old_messages_from_different_channels_1'
channel_2 = 'ch_test_receive_old_messages_from_different_channels_2'
body = 'body'
EventMachine.run {
publish_message_inline(channel_1, {'accept' => 'text/html'}, body + "_1")
publish_message_inline(channel_2, {'accept' => 'text/html'}, body + "_2")
sub_1 = EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel_2.to_s + '/' + channel_1.to_s).get :head => headers, :timeout => 30
sub_1.callback {
assert_equal(200, sub_1.response_header.status, "Wrong status")
assert_not_equal("", sub_1.response_header['LAST_MODIFIED'].to_s, "Wrong header")
assert_not_equal("", sub_1.response_header['ETAG'].to_s, "Wrong header")
assert_equal("#{body}_2\r\n#{body}_1\r\n", sub_1.response, "The published message was not received correctly")
headers.merge!({'If-Modified-Since' => sub_1.response_header['LAST_MODIFIED'], 'If-None-Match' => sub_1.response_header['ETAG']})
sub_2 = EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel_2.to_s + '/' + channel_1.to_s).get :head => headers, :timeout => 30
sub_2.callback {
assert_equal(304, sub_2.response_header.status, "Wrong status")
assert_equal(0, sub_2.response_header.content_length, "Wrong response")
assert_equal(sub_1.response_header['LAST_MODIFIED'], sub_2.response_header['LAST_MODIFIED'].to_s, "Wrong header")
assert_equal(sub_1.response_header['ETAG'], sub_2.response_header['ETAG'].to_s, "Wrong header")
sleep(1) # to publish the second message in a different second from the first
publish_message_inline(channel_1, {'accept' => 'text/html'}, body + "1_1")
headers.merge!({'If-Modified-Since' => sub_2.response_header['LAST_MODIFIED'], 'If-None-Match' => sub_2.response_header['ETAG']})
sub_3 = EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel_2.to_s + '/' + channel_1.to_s).get :head => headers, :timeout => 30
sub_3.callback {
assert_equal(200, sub_3.response_header.status, "Wrong status")
assert_not_equal(sub_2.response_header['LAST_MODIFIED'], sub_3.response_header['LAST_MODIFIED'].to_s, "Wrong header")
assert_equal("0", sub_3.response_header['ETAG'].to_s, "Wrong header")
assert_equal("#{body}1_1\r\n", sub_3.response, "The published message was not received correctly")
headers.merge!({'If-Modified-Since' => sub_3.response_header['LAST_MODIFIED'], 'If-None-Match' => sub_3.response_header['ETAG']})
sub_4 = EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel_2.to_s + '/' + channel_1.to_s).get :head => headers, :timeout => 30
sub_4.callback {
assert_equal(304, sub_4.response_header.status, "Wrong status")
assert_equal(0, sub_4.response_header.content_length, "Wrong response")
assert_equal(sub_3.response_header['LAST_MODIFIED'], sub_4.response_header['LAST_MODIFIED'].to_s, "Wrong header")
assert_equal(sub_3.response_header['ETAG'], sub_4.response_header['ETAG'].to_s, "Wrong header")
sleep(1) # to publish the second message in a different second from the first
publish_message_inline(channel_2, {'accept' => 'text/html'}, body + "1_2")
headers.merge!({'If-Modified-Since' => sub_4.response_header['LAST_MODIFIED'], 'If-None-Match' => sub_4.response_header['ETAG']})
sub_5 = EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel_2.to_s + '/' + channel_1.to_s).get :head => headers, :timeout => 30
sub_5.callback {
assert_equal(200, sub_5.response_header.status, "Wrong status")
assert_not_equal(sub_4.response_header['LAST_MODIFIED'], sub_5.response_header['LAST_MODIFIED'].to_s, "Wrong header")
assert_equal("0", sub_5.response_header['ETAG'].to_s, "Wrong header")
assert_equal("#{body}1_2\r\n", sub_5.response, "The published message was not received correctly")
EventMachine.stop
}
}
}
}
}
add_test_timeout
}
end
def conf_test_receive_a_304_when_has_no_messages_using_push_mode_header
@subscriber_mode = nil
end
def test_receive_a_304_when_has_no_messages_using_push_mode_header
headers = {'accept' => 'application/json', 'X-Nginx-PushStream-Mode' => 'polling'}
channel = 'ch_test_receive_a_304_when_has_no_messages_using_push_mode_header'
body = 'body'
EventMachine.run {
sub_1 = EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel.to_s).get :head => headers, :timeout => 30
sub_1.callback {
assert_equal(304, sub_1.response_header.status, "Wrong status")
assert_equal("", sub_1.response_header['LAST_MODIFIED'].to_s, "Wrong header")
assert_equal("", sub_1.response_header['ETAG'].to_s, "Wrong header")
assert_equal(0, sub_1.response_header.content_length, "Wrong response")
EventMachine.stop
}
add_test_timeout
}
end
def conf_test_receive_a_304_when_has_no_messages_keeping_headers_using_push_mode_header
@subscriber_mode = nil
end
def test_receive_a_304_when_has_no_messages_keeping_headers_using_push_mode_header
headers = {'accept' => 'application/json', 'X-Nginx-PushStream-Mode' => 'polling'}
channel = 'ch_test_receive_a_304_when_has_no_messages_keeping_headers_using_push_mode_header'
body = 'body'
headers = headers.merge({'If-Modified-Since' => Time.now.utc.strftime("%a, %d %b %Y %T %Z"), 'If-None-Match' => '3'})
EventMachine.run {
sub_1 = EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel.to_s).get :head => headers, :timeout => 30
sub_1.callback {
assert_equal(304, sub_1.response_header.status, "Wrong status")
assert_equal(headers['If-Modified-Since'], sub_1.response_header['LAST_MODIFIED'].to_s, "Wrong header")
assert_equal(headers['If-None-Match'], sub_1.response_header['ETAG'].to_s, "Wrong header")
assert_equal(0, sub_1.response_header.content_length, "Wrong response")
EventMachine.stop
}
add_test_timeout
}
end
def conf_test_receive_specific_headers_when_has_messages_using_push_mode_header
@subscriber_mode = nil
end
def test_receive_specific_headers_when_has_messages_using_push_mode_header
headers = {'accept' => 'application/json', 'X-Nginx-PushStream-Mode' => 'polling'}
channel = 'ch_test_receive_specific_headers_when_has_messages_using_push_mode_header'
body = 'body'
EventMachine.run {
publish_message_inline(channel, {'accept' => 'text/html'}, body)
sub_1 = EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel.to_s).get :head => headers, :timeout => 30
sub_1.callback {
assert_equal(200, sub_1.response_header.status, "Wrong status")
assert_not_equal("", sub_1.response_header['LAST_MODIFIED'].to_s, "Wrong header")
assert_equal("0", sub_1.response_header['ETAG'].to_s, "Wrong header")
assert_equal("#{body}\r\n", sub_1.response, "The published message was not received correctly")
EventMachine.stop
}
add_test_timeout
}
end
def conf_test_receive_old_messages_by_if_modified_since_header_using_push_mode_header
@subscriber_mode = nil
end
def test_receive_old_messages_by_if_modified_since_header_using_push_mode_header
headers = {'accept' => 'application/json', 'X-Nginx-PushStream-Mode' => 'polling'}
channel = 'ch_test_getting_messages_by_if_modified_since_header_using_push_mode_header'
body = 'body'
EventMachine.run {
publish_message_inline(channel, {'accept' => 'text/html'}, body)
sub_1 = EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel.to_s).get :head => headers, :timeout => 30
sub_1.callback {
assert_equal(200, sub_1.response_header.status, "Wrong status")
assert_not_equal("", sub_1.response_header['LAST_MODIFIED'].to_s, "Wrong header")
assert_not_equal("", sub_1.response_header['ETAG'].to_s, "Wrong header")
assert_equal("#{body}\r\n", sub_1.response, "The published message was not received correctly")
headers.merge!({'If-Modified-Since' => sub_1.response_header['LAST_MODIFIED'], 'If-None-Match' => sub_1.response_header['ETAG']})
sub_2 = EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel.to_s).get :head => headers, :timeout => 30
sub_2.callback {
assert_equal(304, sub_2.response_header.status, "Wrong status")
assert_equal(0, sub_2.response_header.content_length, "Wrong response")
assert_equal(sub_1.response_header['LAST_MODIFIED'], sub_2.response_header['LAST_MODIFIED'].to_s, "Wrong header")
assert_equal(sub_1.response_header['ETAG'], sub_2.response_header['ETAG'].to_s, "Wrong header")
sleep(1) # to publish the second message in a different second from the first
publish_message_inline(channel, {'accept' => 'text/html'}, body + "1")
headers.merge!({'If-Modified-Since' => sub_2.response_header['LAST_MODIFIED'], 'If-None-Match' => sub_2.response_header['ETAG']})
sub_3 = EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel.to_s).get :head => headers, :timeout => 30
sub_3.callback {
assert_equal(200, sub_3.response_header.status, "Wrong status")
assert_not_equal(sub_2.response_header['LAST_MODIFIED'], sub_3.response_header['LAST_MODIFIED'].to_s, "Wrong header")
assert_equal("0", sub_3.response_header['ETAG'].to_s, "Wrong header")
assert_equal("#{body}1\r\n", sub_3.response, "The published message was not received correctly")
EventMachine.stop
}
}
}
add_test_timeout
}
end
def conf_test_receive_old_messages_by_backtrack_using_push_mode_header
@subscriber_mode = nil
end
def test_receive_old_messages_by_backtrack_using_push_mode_header
headers = {'accept' => 'application/json', 'X-Nginx-PushStream-Mode' => 'polling'}
channel = 'ch_test_getting_messages_by_if_modified_since_header_using_push_mode_header'
body = 'body'
EventMachine.run {
publish_message_inline(channel, {'accept' => 'text/html'}, body)
publish_message_inline(channel, {'accept' => 'text/html'}, body + "1")
publish_message_inline(channel, {'accept' => 'text/html'}, body + "2")
sub_1 = EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel.to_s + '.b1').get :head => headers, :timeout => 30
sub_1.callback {
assert_equal(200, sub_1.response_header.status, "Wrong status")
assert_not_equal("", sub_1.response_header['LAST_MODIFIED'].to_s, "Wrong header")
assert_equal("2", sub_1.response_header['ETAG'].to_s, "Wrong header")
assert_equal("#{body}2\r\n", sub_1.response, "The published message was not received correctly")
headers.merge!({'If-Modified-Since' => sub_1.response_header['LAST_MODIFIED'], 'If-None-Match' => sub_1.response_header['ETAG']})
sub_2 = EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel.to_s).get :head => headers, :timeout => 30
sub_2.callback {
assert_equal(304, sub_2.response_header.status, "Wrong status")
assert_equal(0, sub_2.response_header.content_length, "Wrong response")
assert_equal(sub_1.response_header['LAST_MODIFIED'], sub_2.response_header['LAST_MODIFIED'].to_s, "Wrong header")
assert_equal(sub_1.response_header['ETAG'], sub_2.response_header['ETAG'].to_s, "Wrong header")
sleep(1) # to publish the second message in a different second from the first
publish_message_inline(channel, {'accept' => 'text/html'}, body + "3")
headers.merge!({'If-Modified-Since' => sub_2.response_header['LAST_MODIFIED'], 'If-None-Match' => sub_2.response_header['ETAG']})
sub_3 = EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel.to_s).get :head => headers, :timeout => 30
sub_3.callback {
assert_equal(200, sub_3.response_header.status, "Wrong status")
assert_not_equal(sub_2.response_header['LAST_MODIFIED'], sub_3.response_header['LAST_MODIFIED'].to_s, "Wrong header")
assert_equal("0", sub_3.response_header['ETAG'].to_s, "Wrong header")
assert_equal("#{body}3\r\n", sub_3.response, "The published message was not received correctly")
EventMachine.stop
}
}
}
add_test_timeout
}
end
def conf_test_receive_old_messages_by_last_event_id_using_push_mode_header
@subscriber_mode = nil
end
def test_receive_old_messages_by_last_event_id_using_push_mode_header
headers = {'accept' => 'application/json', 'X-Nginx-PushStream-Mode' => 'polling'}
channel = 'ch_test_receive_old_messages_by_last_event_id_using_push_mode_header'
body = 'body'
EventMachine.run {
publish_message_inline(channel, {'accept' => 'text/html', 'Event-Id' => 'event 1' }, 'msg 1')
publish_message_inline(channel, {'accept' => 'text/html', 'Event-Id' => 'event 2' }, 'msg 2')
publish_message_inline(channel, {'accept' => 'text/html' }, 'msg 3')
publish_message_inline(channel, {'accept' => 'text/html', 'Event-Id' => 'event 3' }, 'msg 4')
sub_1 = EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel.to_s).get :head => headers.merge({'Last-Event-Id' => 'event 2'})
sub_1.callback {
assert_equal(200, sub_1.response_header.status, "Wrong status")
assert_not_equal("", sub_1.response_header['LAST_MODIFIED'].to_s, "Wrong header")
assert_equal("3", sub_1.response_header['ETAG'].to_s, "Wrong header")
assert_equal("msg 3\r\nmsg 4\r\n", sub_1.response, "The published message was not received correctly")
headers.merge!({'If-Modified-Since' => sub_1.response_header['LAST_MODIFIED'], 'If-None-Match' => sub_1.response_header['ETAG']})
sub_2 = EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel.to_s).get :head => headers, :timeout => 30
sub_2.callback {
assert_equal(304, sub_2.response_header.status, "Wrong status")
assert_equal(0, sub_2.response_header.content_length, "Wrong response")
assert_equal(sub_1.response_header['LAST_MODIFIED'], sub_2.response_header['LAST_MODIFIED'].to_s, "Wrong header")
assert_equal(sub_1.response_header['ETAG'], sub_2.response_header['ETAG'].to_s, "Wrong header")
sleep(1) # to publish the second message in a different second from the first
publish_message_inline(channel, {'accept' => 'text/html'}, body + "3")
headers.merge!({'If-Modified-Since' => sub_2.response_header['LAST_MODIFIED'], 'If-None-Match' => sub_2.response_header['ETAG']})
sub_3 = EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel.to_s).get :head => headers, :timeout => 30
sub_3.callback {
assert_equal(200, sub_3.response_header.status, "Wrong status")
assert_not_equal(sub_2.response_header['LAST_MODIFIED'], sub_3.response_header['LAST_MODIFIED'].to_s, "Wrong header")
assert_equal("0", sub_3.response_header['ETAG'].to_s, "Wrong header")
assert_equal("#{body}3\r\n", sub_3.response, "The published message was not received correctly")
EventMachine.stop
}
}
}
add_test_timeout
}
end
def conf_test_receive_old_messages_from_different_channels_using_push_mode_header
@subscriber_mode = nil
end
def test_receive_old_messages_from_different_channels_using_push_mode_header
headers = {'accept' => 'application/json', 'X-Nginx-PushStream-Mode' => 'polling'}
channel_1 = 'ch_test_receive_old_messages_from_different_channels_using_push_mode_header_1'
channel_2 = 'ch_test_receive_old_messages_from_different_channels_using_push_mode_header_2'
body = 'body'
EventMachine.run {
publish_message_inline(channel_1, {'accept' => 'text/html'}, body + "_1")
publish_message_inline(channel_2, {'accept' => 'text/html'}, body + "_2")
sub_1 = EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel_2.to_s + '/' + channel_1.to_s).get :head => headers, :timeout => 30
sub_1.callback {
assert_equal(200, sub_1.response_header.status, "Wrong status")
assert_not_equal("", sub_1.response_header['LAST_MODIFIED'].to_s, "Wrong header")
assert_not_equal("", sub_1.response_header['ETAG'].to_s, "Wrong header")
assert_equal("#{body}_2\r\n#{body}_1\r\n", sub_1.response, "The published message was not received correctly")
headers.merge!({'If-Modified-Since' => sub_1.response_header['LAST_MODIFIED'], 'If-None-Match' => sub_1.response_header['ETAG']})
sub_2 = EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel_2.to_s + '/' + channel_1.to_s).get :head => headers, :timeout => 30
sub_2.callback {
assert_equal(304, sub_2.response_header.status, "Wrong status")
assert_equal(0, sub_2.response_header.content_length, "Wrong response")
assert_equal(sub_1.response_header['LAST_MODIFIED'], sub_2.response_header['LAST_MODIFIED'].to_s, "Wrong header")
assert_equal(sub_1.response_header['ETAG'], sub_2.response_header['ETAG'].to_s, "Wrong header")
sleep(1) # to publish the second message in a different second from the first
publish_message_inline(channel_1, {'accept' => 'text/html'}, body + "1_1")
headers.merge!({'If-Modified-Since' => sub_2.response_header['LAST_MODIFIED'], 'If-None-Match' => sub_2.response_header['ETAG']})
sub_3 = EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel_2.to_s + '/' + channel_1.to_s).get :head => headers, :timeout => 30
sub_3.callback {
assert_equal(200, sub_3.response_header.status, "Wrong status")
assert_not_equal(sub_2.response_header['LAST_MODIFIED'], sub_3.response_header['LAST_MODIFIED'].to_s, "Wrong header")
assert_equal("0", sub_3.response_header['ETAG'].to_s, "Wrong header")
assert_equal("#{body}1_1\r\n", sub_3.response, "The published message was not received correctly")
headers.merge!({'If-Modified-Since' => sub_3.response_header['LAST_MODIFIED'], 'If-None-Match' => sub_3.response_header['ETAG']})
sub_4 = EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel_2.to_s + '/' + channel_1.to_s).get :head => headers, :timeout => 30
sub_4.callback {
assert_equal(304, sub_4.response_header.status, "Wrong status")
assert_equal(0, sub_4.response_header.content_length, "Wrong response")
assert_equal(sub_3.response_header['LAST_MODIFIED'], sub_4.response_header['LAST_MODIFIED'].to_s, "Wrong header")
assert_equal(sub_3.response_header['ETAG'], sub_4.response_header['ETAG'].to_s, "Wrong header")
sleep(1) # to publish the second message in a different second from the first
publish_message_inline(channel_2, {'accept' => 'text/html'}, body + "1_2")
headers.merge!({'If-Modified-Since' => sub_4.response_header['LAST_MODIFIED'], 'If-None-Match' => sub_4.response_header['ETAG']})
sub_5 = EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel_2.to_s + '/' + channel_1.to_s).get :head => headers, :timeout => 30
sub_5.callback {
assert_equal(200, sub_5.response_header.status, "Wrong status")
assert_not_equal(sub_4.response_header['LAST_MODIFIED'], sub_5.response_header['LAST_MODIFIED'].to_s, "Wrong header")
assert_equal("0", sub_5.response_header['ETAG'].to_s, "Wrong header")
assert_equal("#{body}1_2\r\n", sub_5.response, "The published message was not received correctly")
EventMachine.stop
}
}
}
}
}
add_test_timeout
}
end
def config_test_send_modified_since_and_none_match_values_not_using_headers_when_polling
@last_received_message_time = "$arg_time"
@last_received_message_tag = "$arg_tag"
end
def test_send_modified_since_and_none_match_values_not_using_headers_when_polling
headers = {'accept' => 'application/json'}
channel = 'ch_test_send_modified_since_and_none_match_values_not_using_headers_when_polling'
body = 'body'
response = ""
EventMachine.run {
publish_message_inline(channel, {'accept' => 'text/html'}, body)
sub_1 = EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel.to_s).get :head => headers, :timeout => 30
sub_1.callback {
assert_equal("#{body}\r\n", sub_1.response, "Wrong message")
time = sub_1.response_header['LAST_MODIFIED']
tag = sub_1.response_header['ETAG']
publish_message_inline(channel, {'accept' => 'text/html'}, body + " 1")
response = ""
sub_2 = EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel.to_s + '?time=' + time + '&tag=' + tag).get :head => headers, :timeout => 30
sub_2.callback {
assert_equal("#{body} 1\r\n", sub_2.response, "Wrong message")
EventMachine.stop
}
}
add_test_timeout
}
end
def test_return_message_using_function_name_specified_in_callback_parameter_when_polling
headers = {'accept' => 'application/javascript'}
channel = 'ch_test_return_message_using_function_name_specified_in_callback_parameter_when_polling'
body = 'body'
response = ""
callback_function_name = "callback_function"
EventMachine.run {
publish_message_inline(channel, {'accept' => 'text/html'}, body)
sub_1 = EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel.to_s + '?callback=' + callback_function_name).get :head => headers, :timeout => 30
sub_1.callback {
assert_equal("#{callback_function_name}\r\n([#{body}\r\n,]);\r\n", sub_1.response, "Wrong message")
EventMachine.stop
}
add_test_timeout
}
end
def config_test_force_content_type_to_be_application_javascript_when_using_function_name_specified_in_callback_parameter_when_polling
@content_type = "anything/value"
end
def test_force_content_type_to_be_application_javascript_when_using_function_name_specified_in_callback_parameter_when_polling
headers = {'accept' => 'otherknown/value'}
channel = 'test_force_content_type_to_be_application_javascript_when_using_function_name_specified_in_callback_parameter_when_polling'
body = 'body'
response = ""
callback_function_name = "callback_function"
EventMachine.run {
publish_message_inline(channel, {'accept' => 'text/html'}, body)
sub_1 = EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel.to_s + '?callback=' + callback_function_name).get :head => headers, :timeout => 30
sub_1.callback {
assert_equal('application/javascript', sub_1.response_header['CONTENT_TYPE'], "Didn't receive the right content type")
EventMachine.stop
}
add_test_timeout
}
end
end
require File.expand_path('base_test_case', File.dirname(__FILE__))
class TestSubscriberProperties < Test::Unit::TestCase
include BaseTestCase
def config_test_header_template
@header_template = "HEADER\r\nTEMPLATE\r\n1234\r\n"
@authorized_channels_only = "off"
end
def test_header_template
channel = 'ch_test_header_template'
headers = {'accept' => 'text/html'}
EventMachine.run {
sub = EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel.to_s).get :head => headers, :timeout => 60
sub.stream { |chunk|
assert_equal("#{@header_template}\r\n", chunk, "Didn't received header template")
EventMachine.stop
}
}
end
def config_test_content_type
@content_type = "custom content type"
@authorized_channels_only = "off"
end
def test_content_type
channel = 'ch_test_content_type'
headers = {'accept' => 'text/html'}
EventMachine.run {
sub = EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel.to_s).get :head => headers, :timeout => 60
sub.stream { |chunk|
assert_equal(@content_type, sub.response_header['CONTENT_TYPE'], "Didn't received correct content type")
EventMachine.stop
}
}
end
def config_test_ping_message_interval
@subscriber_connection_timeout = nil
@ping_message_interval = "2s"
end
def test_ping_message_interval
channel = 'ch_test_ping_message_interval'
headers = {'accept' => 'text/html'}
step1 = step2 = step3 = step4 = nil
chunksReceived = 0
EventMachine.run {
sub = EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel.to_s).get :head => headers, :timeout => 60
sub.stream { |chunk|
chunksReceived += 1;
step1 = Time.now if chunksReceived == 1
step2 = Time.now if chunksReceived == 2
step3 = Time.now if chunksReceived == 3
step4 = Time.now if chunksReceived == 4
EventMachine.stop if chunksReceived == 4
}
sub.callback {
assert_equal(4, chunksReceived, "Didn't received expected messages")
interval1 = time_diff_sec(step2, step1).round
interval2 = time_diff_sec(step4, step3).round
assert_equal(interval1, interval2, "Wrong #{interval1}, #{interval2} intervals")
}
}
end
end
require File.expand_path('base_test_case', File.dirname(__FILE__))
class TestWebSocket < Test::Unit::TestCase
include BaseTestCase
def global_configuration
@header_template = nil
@message_template = nil
@footer_template = nil
@extra_location = %q{
location ~ /ws/(.*)? {
# activate websocket mode for this location
push_stream_websocket;
# positional channel path
set $push_stream_channels_path $1;
}
}
end
def test_accepted_methods
EventMachine.run {
multi = EventMachine::MultiRequest.new
multi.add(:a, EventMachine::HttpRequest.new(nginx_address + '/ws/ch_test_accepted_methods_1').head)
multi.add(:b, EventMachine::HttpRequest.new(nginx_address + '/ws/ch_test_accepted_methods_2').put(:body => 'body'))
multi.add(:c, EventMachine::HttpRequest.new(nginx_address + '/ws/ch_test_accepted_methods_3').post)
multi.add(:d, EventMachine::HttpRequest.new(nginx_address + '/ws/ch_test_accepted_methods_4').delete)
multi.add(:e, EventMachine::HttpRequest.new(nginx_address + '/ws/ch_test_accepted_methods_5').get)
multi.callback {
assert_equal(5, multi.responses[:callback].length)
assert_equal(405, multi.responses[:callback][:a].response_header.status, "Publisher does not accept HEAD")
assert_equal("HEAD", multi.responses[:callback][:a].req.method, "Array is with wrong order")
assert_equal("GET", multi.responses[:callback][:a].response_header['ALLOW'], "Didn't receive the right error message")
assert_equal(405, multi.responses[:callback][:b].response_header.status, "Publisher does not accept PUT")
assert_equal("PUT", multi.responses[:callback][:b].req.method, "Array is with wrong order")
assert_equal("GET", multi.responses[:callback][:b].response_header['ALLOW'], "Didn't receive the right error message")
assert_equal(405, multi.responses[:callback][:c].response_header.status, "Publisher does accept POST")
assert_equal("POST", multi.responses[:callback][:c].req.method, "Array is with wrong order")
assert_equal("GET", multi.responses[:callback][:b].response_header['ALLOW'], "Didn't receive the right error message")
assert_equal(405, multi.responses[:callback][:d].response_header.status, "Publisher does not accept DELETE")
assert_equal("DELETE", multi.responses[:callback][:d].req.method, "Array is with wrong order")
assert_equal("GET", multi.responses[:callback][:d].response_header['ALLOW'], "Didn't receive the right error message")
assert_not_equal(405, multi.responses[:callback][:e].response_header.status, "Publisher does accept GET")
assert_equal("GET", multi.responses[:callback][:e].req.method, "Array is with wrong order")
EventMachine.stop
}
}
end
def test_check_mandatory_headers
channel = 'ch_test_check_mandatory_headers'
request = "GET /ws/#{channel}.b1 HTTP/1.0\r\n"
socket = TCPSocket.open(nginx_host, nginx_port)
socket.print("#{request}\r\n")
headers, body = read_response(socket)
assert_equal("", body, "Wrong response")
assert(headers.match(/Don't have at least one of the mandatory headers: Connection, Upgrade, Sec-WebSocket-Key and Sec-WebSocket-Version/), "Didn't receive error message")
request << "Connection: Upgrade\r\n"
socket = TCPSocket.open(nginx_host, nginx_port)
socket.print("#{request}\r\n")
headers, body = read_response(socket)
assert_equal("", body, "Wrong response")
assert(headers.match(/Don't have at least one of the mandatory headers: Connection, Upgrade, Sec-WebSocket-Key and Sec-WebSocket-Version/), "Didn't receive error message")
request << "Sec-WebSocket-Key: /mQoZf6pRiv8+6o72GncLQ==\r\n"
socket = TCPSocket.open(nginx_host, nginx_port)
socket.print("#{request}\r\n")
headers, body = read_response(socket)
assert_equal("", body, "Wrong response")
assert(headers.match(/Don't have at least one of the mandatory headers: Connection, Upgrade, Sec-WebSocket-Key and Sec-WebSocket-Version/), "Didn't receive error message")
request << "Upgrade: websocket\r\n"
socket = TCPSocket.open(nginx_host, nginx_port)
socket.print("#{request}\r\n")
headers, body = read_response(socket)
assert_equal("", body, "Wrong response")
assert(headers.match(/Don't have at least one of the mandatory headers: Connection, Upgrade, Sec-WebSocket-Key and Sec-WebSocket-Version/), "Didn't receive error message")
request << "Sec-WebSocket-Version: 8\r\n"
socket = TCPSocket.open(nginx_host, nginx_port)
socket.print("#{request}\r\n")
headers, body = read_response(socket)
assert_equal("", body, "Wrong response")
assert(!headers.match(/Don't have at least one of the mandatory headers: Connection, Upgrade, Sec-WebSocket-Key and Sec-WebSocket-Version/), "Didn't receive error message")
assert(headers.match(/HTTP\/1\.1 101 Switching Protocols/), "Didn't receive 'Switching Protocols' status")
end
def test_supported_versions
channel = 'ch_test_supported_versions'
request = "GET /ws/#{channel}.b1 HTTP/1.0\r\nConnection: Upgrade\r\nSec-WebSocket-Key: /mQoZf6pRiv8+6o72GncLQ==\r\nUpgrade: websocket\r\n"
socket = TCPSocket.open(nginx_host, nginx_port)
socket.print("#{request}Sec-WebSocket-Version: 7\r\n\r\n")
headers, body = read_response(socket)
assert_equal("", body, "Wrong response")
assert(headers.match(/Sec-WebSocket-Version: 8, 13/), "Didn't receive error message")
assert(headers.match(/X-Nginx-PushStream-Explain: Version not supported. Supported versions: 8, 13/), "Didn't receive error message")
socket = TCPSocket.open(nginx_host, nginx_port)
socket.print("#{request}Sec-WebSocket-Version: 8\r\n\r\n")
headers, body = read_response(socket)
assert_equal("", body, "Wrong response")
assert(!headers.match(/Sec-WebSocket-Version: 8, 13/), "Didn't receive error message")
assert(!headers.match(/X-Nginx-PushStream-Explain: Version not supported. Supported versions: 8, 13/), "Didn't receive error message")
socket = TCPSocket.open(nginx_host, nginx_port)
socket.print("#{request}Sec-WebSocket-Version: 13\r\n\r\n")
headers, body = read_response(socket)
assert_equal("", body, "Wrong response")
assert(!headers.match(/Sec-WebSocket-Version: 8, 13/), "Didn't receive error message")
assert(!headers.match(/X-Nginx-PushStream-Explain: Version not supported. Supported versions: 8, 13/), "Didn't receive error message")
end
def test_response_headers
channel = 'ch_test_response_headers'
request = "GET /ws/#{channel}.b1 HTTP/1.0\r\nConnection: Upgrade\r\nSec-WebSocket-Key: /mQoZf6pRiv8+6o72GncLQ==\r\nUpgrade: websocket\r\nSec-WebSocket-Version: 8\r\n"
socket = TCPSocket.open(nginx_host, nginx_port)
socket.print("#{request}\r\n")
headers, body = read_response(socket)
assert_equal("", body, "Wrong response")
assert(headers.match(/HTTP\/1\.1 101 Switching Protocols/), "Didn't receive status header")
assert(headers.match(/Sec-WebSocket-Accept: RaIOIcQ6CBoc74B9EKdH0avYZnw=/), "Didn't receive accept header")
assert(headers.match(/Upgrade: WebSocket/), "Didn't receive upgrade header")
assert(headers.match(/Connection: Upgrade/), "Didn't receive connection header")
end
def config_test_receive_header_template
@header_template = "HEADER_TEMPLATE"
end
def test_receive_header_template
channel = 'ch_test_receive_header_template'
request = "GET /ws/#{channel}.b1 HTTP/1.0\r\nConnection: Upgrade\r\nSec-WebSocket-Key: /mQoZf6pRiv8+6o72GncLQ==\r\nUpgrade: websocket\r\nSec-WebSocket-Version: 8\r\n"
socket = TCPSocket.open(nginx_host, nginx_port)
socket.print("#{request}\r\n")
sleep(0.5)
headers, body = read_response(socket)
assert_equal("\201\017HEADER_TEMPLATE", body, "Wrong response")
end
def config_test_receive_ping_frame
@ping_message_interval = '1s'
end
def test_receive_ping_frame
channel = 'ch_test_receive_ping_frame'
request = "GET /ws/#{channel}.b1 HTTP/1.0\r\nConnection: Upgrade\r\nSec-WebSocket-Key: /mQoZf6pRiv8+6o72GncLQ==\r\nUpgrade: websocket\r\nSec-WebSocket-Version: 8\r\n"
socket = TCPSocket.open(nginx_host, nginx_port)
socket.print("#{request}\r\n")
headers, body = read_response(socket)
#wait for ping message
sleep(1)
body, dummy = read_response(socket)
assert_equal("\211\000", body, "Wrong response")
end
def config_test_receive_close_frame
@subscriber_connection_timeout = '1s'
end
def test_receive_close_frame
channel = 'ch_test_receive_close_frame'
request = "GET /ws/#{channel}.b1 HTTP/1.0\r\nConnection: Upgrade\r\nSec-WebSocket-Key: /mQoZf6pRiv8+6o72GncLQ==\r\nUpgrade: websocket\r\nSec-WebSocket-Version: 8\r\n"
socket = TCPSocket.open(nginx_host, nginx_port)
socket.print("#{request}\r\n")
headers, body = read_response(socket)
#wait for disconnect
sleep(1)
body, dummy = read_response(socket)
assert_equal("\210\000", body, "Wrong response")
end
def config_test_receive_footer_template
@footer_template = "FOOTER_TEMPLATE"
@subscriber_connection_timeout = '1s'
end
def test_receive_footer_template
channel = 'ch_test_receive_footer_template'
request = "GET /ws/#{channel}.b1 HTTP/1.0\r\nConnection: Upgrade\r\nSec-WebSocket-Key: /mQoZf6pRiv8+6o72GncLQ==\r\nUpgrade: websocket\r\nSec-WebSocket-Version: 8\r\n"
socket = TCPSocket.open(nginx_host, nginx_port)
socket.print("#{request}\r\n")
headers, body = read_response(socket)
#wait for disconnect
sleep(1.5)
body, dummy = read_response(socket)
assert_equal("\201\017FOOTER_TEMPLATE\210\000", body, "Wrong response")
end
def test_receive_message_length_less_than_125
channel = 'ch_test_receive_message_length_less_than_125'
request = "GET /ws/#{channel}.b1 HTTP/1.0\r\nConnection: Upgrade\r\nSec-WebSocket-Key: /mQoZf6pRiv8+6o72GncLQ==\r\nUpgrade: websocket\r\nSec-WebSocket-Version: 8\r\n"
socket = TCPSocket.open(nginx_host, nginx_port)
socket.print("#{request}\r\n")
headers, body = read_response(socket)
publish_message(channel, {}, "Hello")
body, dummy = read_response(socket)
assert_equal("\201\005Hello", body, "Wrong response")
end
def config_test_receive_message_length_more_than_125_less_then_65535
@client_max_body_size = '65k'
@client_body_buffer_size = '65k'
end
def test_receive_message_length_more_than_125_less_then_65535
message = ""
channel = 'ch_test_receive_message_length_more_than_125_less_then_65535'
request = "GET /ws/#{channel}.b1 HTTP/1.0\r\nConnection: Upgrade\r\nSec-WebSocket-Key: /mQoZf6pRiv8+6o72GncLQ==\r\nUpgrade: websocket\r\nSec-WebSocket-Version: 8\r\n"
65535.times { message << "a" }
publish_message(channel, {}, message)
socket = TCPSocket.open(nginx_host, nginx_port)
socket.print("#{request}\r\n")
headers, body = read_response(socket, "aaa")
assert(body.start_with?("\201~\377\377aaa"), "Wrong response")
end
def config_test_receive_message_length_more_than_65535
@client_max_body_size = '70k'
@client_body_buffer_size = '70k'
end
def test_receive_message_length_more_than_65535
message = ""
channel = 'ch_test_receive_message_length_more_than_65535'
request = "GET /ws/#{channel}.b1 HTTP/1.0\r\nConnection: Upgrade\r\nSec-WebSocket-Key: /mQoZf6pRiv8+6o72GncLQ==\r\nUpgrade: websocket\r\nSec-WebSocket-Version: 8\r\n"
65536.times { message << "a" }
publish_message(channel, {}, message)
socket = TCPSocket.open(nginx_host, nginx_port)
socket.print("#{request}\r\n")
headers, body = read_response(socket, "aaa")
assert(body.start_with?("\201\177\000\000\000\000\000\001\000\000aaa"), "Wrong response")
end
def config_test_same_message_template_different_locations
@message_template = '{\"text\":\"~text~\"}'
@subscriber_connection_timeout = '1s'
end
def test_same_message_template_different_locations
channel = 'ch_test_same_message_template_different_locations'
body = 'body'
publish_message(channel, {}, body)
request_1 = "GET /ws/#{channel}.b1 HTTP/1.0\r\nConnection: Upgrade\r\nSec-WebSocket-Key: /mQoZf6pRiv8+6o72GncLQ==\r\nUpgrade: websocket\r\nSec-WebSocket-Version: 8\r\n"
request_2 = "GET /sub/#{channel}.b1 HTTP/1.0\r\n"
socket_1 = TCPSocket.open(nginx_host, nginx_port)
socket_1.print("#{request_1}\r\n")
headers_1, body_1 = read_response(socket_1)
assert_equal("\201\017{\"text\":\"#{body}\"}", body_1, "Wrong message")
socket_2 = TCPSocket.open(nginx_host, nginx_port)
socket_2.print("#{request_2}\r\n")
headers_2, body_2 = read_response(socket_2)
assert_equal("11\r\n{\"text\":\"#{body}\"}\r\n\r\n", body_2, "Wrong message")
end
def config_test_publish_message_same_stream
@extra_location = %q{
location ~ /ws/(.*)? {
# activate websocket mode for this location
push_stream_websocket;
# positional channel path
set $push_stream_channels_path $1;
# allow subscriber to publish
push_stream_websocket_allow_publish on;
# store messages
push_stream_store_messages on;
}
}
@message_template = '{\"channel\":\"~channel~\", \"id\":\"~id~\", \"message\":\"~text~\"}'
end
def test_publish_message_same_stream
channel = 'ch_test_publish_message_same_stream'
frame = "%c%c%c%c%c%c%c%c%c%c%c" % [0x81, 0x85, 0xBD, 0xD0, 0xE5, 0x2A, 0xD5, 0xB5, 0x89, 0x46, 0xD2] #send 'hello' text
request = "GET /ws/#{channel}.b1 HTTP/1.0\r\nConnection: Upgrade\r\nSec-WebSocket-Key: /mQoZf6pRiv8+6o72GncLQ==\r\nUpgrade: websocket\r\nSec-WebSocket-Version: 8\r\n"
socket = TCPSocket.open(nginx_host, nginx_port)
socket.print("#{request}\r\n")
headers, body = read_response(socket)
socket.print(frame)
EventMachine.run {
pub = EventMachine::HttpRequest.new(nginx_address + '/channels-stats?id=' + channel.to_s).get :timeout => 30
pub.callback {
assert_equal(200, pub.response_header.status, "Request was not accepted")
assert_not_equal(0, pub.response_header.content_length, "Empty response was received")
response = JSON.parse(pub.response)
assert_equal(channel, response["channel"].to_s, "Channel was not recognized")
assert_equal(1, response["published_messages"].to_i, "Message was not published")
assert_equal(1, response["stored_messages"].to_i, "Message was not stored")
assert_equal(1, response["subscribers"].to_i, "Wrong number for subscribers")
EventMachine.stop
}
}
EventMachine.run {
sub = EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel.to_s + '.b1').get :timeout => 30
sub.stream { |chunk|
line = JSON.parse(chunk.split("\r\n")[0])
assert_equal(channel.to_s, line['channel'], "Wrong channel")
assert_equal('hello', line['message'], "Wrong message")
assert_equal(1, line['id'].to_i, "Wrong message")
EventMachine.stop
}
}
end
def test_accept_pong_message
channel = 'ch_test_accept_pong_message'
frame = "%c%c%c%c%c%c" % [0x8A, 0x80, 0xBD, 0xD0, 0xE5, 0x2A] #send 'pong' frame
request = "GET /ws/#{channel}.b1 HTTP/1.0\r\nConnection: Upgrade\r\nSec-WebSocket-Key: /mQoZf6pRiv8+6o72GncLQ==\r\nUpgrade: websocket\r\nSec-WebSocket-Version: 8\r\n"
socket = TCPSocket.open(nginx_host, nginx_port)
socket.print("#{request}\r\n")
headers, body = read_response(socket)
socket.print(frame)
EventMachine.run {
pub = EventMachine::HttpRequest.new(nginx_address + '/channels-stats?id=' + channel.to_s).get :timeout => 30
pub.callback {
assert_equal(200, pub.response_header.status, "Request was not accepted")
assert_not_equal(0, pub.response_header.content_length, "Empty response was received")
response = JSON.parse(pub.response)
assert_equal(channel, response["channel"].to_s, "Channel was not recognized")
assert_equal(0, response["published_messages"].to_i, "Message was not published")
assert_equal(0, response["stored_messages"].to_i, "Message was not stored")
assert_equal(1, response["subscribers"].to_i, "Wrong number for subscribers")
EventMachine.stop
}
}
end
def test_accept_close_message
channel = 'ch_test_accept_close_message'
frame = "%c%c%c%c%c%c" % [0x88, 0x80, 0xBD, 0xD0, 0xE5, 0x2A] #send 'close' frame
request = "GET /ws/#{channel}.b1 HTTP/1.0\r\nConnection: Upgrade\r\nSec-WebSocket-Key: /mQoZf6pRiv8+6o72GncLQ==\r\nUpgrade: websocket\r\nSec-WebSocket-Version: 8\r\n"
socket = TCPSocket.open(nginx_host, nginx_port)
socket.print("#{request}\r\n")
headers, body = read_response(socket)
socket.print(frame)
EventMachine.run {
pub = EventMachine::HttpRequest.new(nginx_address + '/channels-stats?id=' + channel.to_s).get :timeout => 30
pub.callback {
assert_equal(200, pub.response_header.status, "Request was not accepted")
assert_not_equal(0, pub.response_header.content_length, "Empty response was received")
response = JSON.parse(pub.response)
assert_equal(channel, response["channel"].to_s, "Channel was not recognized")
assert_equal(0, response["published_messages"].to_i, "Message was not published")
assert_equal(0, response["stored_messages"].to_i, "Message was not stored")
assert_equal(0, response["subscribers"].to_i, "Wrong number for subscribers")
EventMachine.stop
}
}
end
end
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment