test/unit/server_tests.rb in sanford-0.15.1 vs test/unit/server_tests.rb in sanford-0.16.0

- old
+ new

@@ -1,13 +1,12 @@ require 'assert' require 'sanford/server' require 'dat-tcp/server_spy' +require 'much-plugin' require 'ns-options/assert_macros' require 'sanford/route' -require 'sanford-protocol/fake_connection' -require 'test/support/fake_server_connection' module Sanford::Server class UnitTests < Assert::Context desc "Sanford::Server" @@ -19,16 +18,21 @@ subject{ @server_class } should have_imeths :configuration should have_imeths :name, :ip, :port, :pid_file should have_imeths :receives_keep_alive + should have_imeths :worker_class, :worker_params + should have_imeths :num_workers, :workers should have_imeths :verbose_logging, :logger + should have_imeths :shutdown_timeout should have_imeths :init, :error - should have_imeths :on_worker_start, :on_worker_shutdown - should have_imeths :on_worker_sleep, :on_worker_wakeup should have_imeths :router, :template_source + should "use much-plugin" do + assert_includes MuchPlugin, Sanford::Server + end + should "know its configuration" do config = subject.configuration assert_instance_of Configuration, config assert_same config, subject.configuration end @@ -55,22 +59,50 @@ end should "allow reading/writing its configuration pid file" do new_pid_file = Factory.string subject.pid_file(new_pid_file) - expected = Pathname.new(new_pid_file) - assert_equal expected, subject.configuration.pid_file - assert_equal expected, subject.pid_file + exp = Pathname.new(new_pid_file) + assert_equal exp, subject.configuration.pid_file + assert_equal exp, subject.pid_file end should "allow reading/writing its configuration receives keep alive" do new_keep_alive = Factory.boolean subject.receives_keep_alive(new_keep_alive) assert_equal new_keep_alive, subject.configuration.receives_keep_alive assert_equal new_keep_alive, subject.receives_keep_alive end + should "allow reading/writing its configuration worker class" do + new_worker_class = Class.new + subject.worker_class(new_worker_class) + assert_equal new_worker_class, subject.configuration.worker_class + assert_equal new_worker_class, subject.worker_class + end + + should "allow reading/writing its configuration worker params" do + new_worker_params = { Factory.string => Factory.string } + subject.worker_params(new_worker_params) + assert_equal new_worker_params, subject.configuration.worker_params + assert_equal new_worker_params, subject.worker_params + end + + should "allow reading/writing its configuration num workers" do + new_num_workers = Factory.integer + subject.num_workers(new_num_workers) + assert_equal new_num_workers, subject.configuration.num_workers + assert_equal new_num_workers, subject.num_workers + end + + should "alias workers as num workers" do + new_workers = Factory.integer + subject.workers(new_workers) + assert_equal new_workers, subject.configuration.num_workers + assert_equal new_workers, subject.workers + end + should "allow reading/writing its configuration verbose logging" do new_verbose = Factory.boolean subject.verbose_logging(new_verbose) assert_equal new_verbose, subject.configuration.verbose_logging assert_equal new_verbose, subject.verbose_logging @@ -81,10 +113,17 @@ subject.logger(new_logger) assert_equal new_logger, subject.configuration.logger assert_equal new_logger, subject.logger end + should "allow reading/writing its configuration shutdown timeout" do + new_shutdown_timeout = Factory.integer + subject.shutdown_timeout(new_shutdown_timeout) + assert_equal new_shutdown_timeout, subject.configuration.shutdown_timeout + assert_equal new_shutdown_timeout, subject.shutdown_timeout + end + should "allow adding init procs to its configuration" do new_init_proc = proc{ Factory.string } subject.init(&new_init_proc) assert_includes new_init_proc, subject.configuration.init_procs end @@ -93,26 +132,10 @@ new_error_proc = proc{ Factory.string } subject.error(&new_error_proc) assert_includes new_error_proc, subject.configuration.error_procs end - should "allow reading/writing its configuration worker procs" do - p = proc{} - - subject.on_worker_start(&p) - assert_equal [p], subject.configuration.worker_start_procs - - subject.on_worker_shutdown(&p) - assert_equal [p], subject.configuration.worker_shutdown_procs - - subject.on_worker_sleep(&p) - assert_equal [p], subject.configuration.worker_sleep_procs - - subject.on_worker_wakeup(&p) - assert_equal [p], subject.configuration.worker_wakeup_procs - end - should "allow reading/writing its configuration router" do new_router = Factory.string subject.router(new_router) assert_equal new_router, subject.configuration.router assert_equal new_router, subject.router @@ -140,32 +163,24 @@ desc "when init" setup do @server_class.name Factory.string @server_class.ip Factory.string @server_class.port Factory.integer + @server_class.num_workers Factory.integer + @server_class.worker_params(Factory.string => Factory.string) + @server_class.shutdown_timeout Factory.integer @error_procs = Factory.integer(3).times.map{ proc{} } @error_procs.each{ |p| @server_class.error(&p) } - @start_procs = Factory.integer(3).times.map{ proc{} } - @shutdown_procs = Factory.integer(3).times.map{ proc{} } - @sleep_procs = Factory.integer(3).times.map{ proc{} } - @wakeup_procs = Factory.integer(3).times.map{ proc{} } - @start_procs.each { |p| @server_class.on_worker_start(&p) } - @shutdown_procs.each { |p| @server_class.on_worker_shutdown(&p) } - @sleep_procs.each { |p| @server_class.on_worker_sleep(&p) } - @wakeup_procs.each { |p| @server_class.on_worker_wakeup(&p) } - @server_class.router do service Factory.string, TestHandler.to_s end - @dat_tcp_server_spy = nil - Assert.stub(DatTCP::Server, :new) do |&block| - @dat_tcp_server_spy = DatTCP::ServerSpy.new - @dat_tcp_server_spy.serve_proc = block - @dat_tcp_server_spy + @dtcp_spy = nil + Assert.stub(DatTCP::Server, :new) do |*args| + @dtcp_spy = DatTCP::ServerSpy.new(*args) end @server = @server_class.new end subject{ @server } @@ -182,38 +197,40 @@ assert_true subject.class.configuration.valid? end should "know its server data" do configuration = subject.class.configuration - sd = subject.server_data + data = subject.server_data - assert_instance_of Sanford::ServerData, sd - assert_equal configuration.name, sd.name - assert_equal configuration.ip, sd.ip - assert_equal configuration.port, sd.port - assert_equal configuration.verbose_logging, sd.verbose_logging - assert_equal configuration.receives_keep_alive, sd.receives_keep_alive - assert_equal configuration.error_procs, sd.error_procs - assert_equal configuration.worker_start_procs, sd.worker_start_procs - assert_equal configuration.worker_shutdown_procs, sd.worker_shutdown_procs - assert_equal configuration.worker_sleep_procs, sd.worker_sleep_procs - assert_equal configuration.worker_wakeup_procs, sd.worker_wakeup_procs - assert_equal configuration.routes, sd.routes.values + assert_instance_of Sanford::ServerData, data + assert_equal configuration.name, data.name + assert_equal configuration.ip, data.ip + assert_equal configuration.port, data.port + assert_equal configuration.worker_class, data.worker_class + assert_equal configuration.worker_params, data.worker_params + assert_equal configuration.verbose_logging, data.verbose_logging + assert_equal configuration.receives_keep_alive, data.receives_keep_alive + assert_equal configuration.error_procs, data.error_procs + assert_equal configuration.routes, data.routes.values - assert_instance_of configuration.logger.class, sd.logger + assert_instance_of configuration.logger.class, data.logger end should "know its dat tcp server" do - assert_not_nil @dat_tcp_server_spy - assert_not_nil @dat_tcp_server_spy.serve_proc + data = subject.server_data - assert_equal @start_procs, @dat_tcp_server_spy.worker_start_procs - assert_equal @shutdown_procs, @dat_tcp_server_spy.worker_shutdown_procs - assert_equal @sleep_procs, @dat_tcp_server_spy.worker_sleep_procs - assert_equal @wakeup_procs, @dat_tcp_server_spy.worker_wakeup_procs + assert_not_nil @dtcp_spy + assert_equal data.worker_class, @dtcp_spy.worker_class + assert_equal data.num_workers, @dtcp_spy.num_workers + assert_equal data.dtcp_logger, @dtcp_spy.logger + assert_equal data.shutdown_timeout, @dtcp_spy.shutdown_timeout + exp = data.worker_params.merge({ + :sanford_server_data => data + }) + assert_equal exp, @dtcp_spy.worker_params - assert_equal @dat_tcp_server_spy, subject.dat_tcp_server + assert_equal @dtcp_spy, subject.dat_tcp_server end should "demeter its server data" do assert_equal subject.server_data.name, subject.name assert_equal subject.server_data.ip, subject.configured_ip @@ -227,17 +244,17 @@ assert_equal subject.server_data.template_source, subject.template_source end should "call listen on its dat tcp server using `listen`" do subject.listen - assert_true @dat_tcp_server_spy.listen_called + assert_true @dtcp_spy.listen_called end should "use its configured ip and port by default when listening" do subject.listen - assert_equal subject.server_data.ip, @dat_tcp_server_spy.ip - assert_equal subject.server_data.port, @dat_tcp_server_spy.port + assert_equal subject.server_data.ip, @dtcp_spy.ip + assert_equal subject.server_data.port, @dtcp_spy.port end should "write its ip and port back to its server data" do ip = Factory.string port = Factory.integer @@ -249,64 +266,64 @@ end should "pass any args to its dat tcp server using `listen`" do ip, port = Factory.string, Factory.integer subject.listen(ip, port) - assert_equal ip, @dat_tcp_server_spy.ip - assert_equal port, @dat_tcp_server_spy.port + assert_equal ip, @dtcp_spy.ip + assert_equal port, @dtcp_spy.port file_descriptor = Factory.integer subject.listen(file_descriptor) - assert_equal file_descriptor, @dat_tcp_server_spy.file_descriptor + assert_equal file_descriptor, @dtcp_spy.file_descriptor end should "know its ip, port and file descriptor" do - assert_equal @dat_tcp_server_spy.ip, subject.ip - assert_equal @dat_tcp_server_spy.port, subject.port + assert_equal @dtcp_spy.ip, subject.ip + assert_equal @dtcp_spy.port, subject.port subject.listen - assert_equal @dat_tcp_server_spy.ip, subject.ip - assert_equal @dat_tcp_server_spy.port, subject.port + assert_equal @dtcp_spy.ip, subject.ip + assert_equal @dtcp_spy.port, subject.port - assert_equal @dat_tcp_server_spy.file_descriptor, subject.file_descriptor + assert_equal @dtcp_spy.file_descriptor, subject.file_descriptor subject.listen(Factory.integer) - assert_equal @dat_tcp_server_spy.file_descriptor, subject.file_descriptor + assert_equal @dtcp_spy.file_descriptor, subject.file_descriptor end should "call start on its dat tcp server using `start`" do - client_fds = [ Factory.integer ] + client_fds = [Factory.integer] subject.start(client_fds) - assert_true @dat_tcp_server_spy.start_called - assert_equal client_fds, @dat_tcp_server_spy.client_file_descriptors + assert_true @dtcp_spy.start_called + assert_equal client_fds, @dtcp_spy.client_file_descriptors end should "know its client file descriptors" do - expected = @dat_tcp_server_spy.client_file_descriptors - assert_equal expected, subject.client_file_descriptors - subject.start([ Factory.integer ]) - expected = @dat_tcp_server_spy.client_file_descriptors - assert_equal expected, subject.client_file_descriptors + exp = @dtcp_spy.client_file_descriptors + assert_equal exp, subject.client_file_descriptors + subject.start([Factory.integer]) + exp = @dtcp_spy.client_file_descriptors + assert_equal exp, subject.client_file_descriptors end should "call pause on its dat tcp server using `pause`" do wait = Factory.boolean subject.pause(wait) - assert_true @dat_tcp_server_spy.pause_called - assert_equal wait, @dat_tcp_server_spy.waiting_for_pause + assert_true @dtcp_spy.pause_called + assert_equal wait, @dtcp_spy.waiting_for_pause end should "call stop on its dat tcp server using `stop`" do wait = Factory.boolean subject.stop(wait) - assert_true @dat_tcp_server_spy.stop_called - assert_equal wait, @dat_tcp_server_spy.waiting_for_stop + assert_true @dtcp_spy.stop_called + assert_equal wait, @dtcp_spy.waiting_for_stop end should "call halt on its dat tcp server using `halt`" do wait = Factory.boolean subject.halt(wait) - assert_true @dat_tcp_server_spy.halt_called - assert_equal wait, @dat_tcp_server_spy.waiting_for_halt + assert_true @dtcp_spy.halt_called + assert_equal wait, @dtcp_spy.waiting_for_halt end should "know if its been paused" do assert_false subject.paused? subject.listen @@ -321,121 +338,25 @@ class ConfigureTCPServerTests < InitTests desc "configuring its tcp server" setup do @tcp_server = TCPServerSpy.new - Assert.stub(@dat_tcp_server_spy, :listen) do |*args, &block| + Assert.stub(@dtcp_spy, :listen) do |*args, &block| @configure_tcp_server_proc = block end @server.listen @configure_tcp_server_proc.call(@tcp_server) end subject{ @tcp_server } should "set the TCP_NODELAY option" do - expected = [ ::Socket::IPPROTO_TCP, ::Socket::TCP_NODELAY, true ] - assert_includes expected, @tcp_server.set_socket_option_calls + exp = [ ::Socket::IPPROTO_TCP, ::Socket::TCP_NODELAY, true ] + assert_includes exp, @tcp_server.set_socket_option_calls end end - class ServeTests < InitTests - desc "serve" - setup do - @socket = Factory.binary - - @connection = FakeServerConnection.new - Assert.stub(Connection, :new).with(@socket){ @connection } - - @connection_handler_spy = ConnectionHandlerSpy.new - Assert.stub(Sanford::ConnectionHandler, :new).tap do |s| - s.with(@server.server_data, @connection){ @connection_handler_spy } - end - - @serve_proc = @dat_tcp_server_spy.serve_proc - end - subject{ @serve_proc } - - should "run a connection_handler when called with a socket" do - Assert.stub(@server.server_data, :receives_keep_alive){ false } - @connection.read_data = Factory.boolean - assert_false @connection_handler_spy.run_called - subject.call(@socket) - assert_true @connection_handler_spy.run_called - end - - should "not run a keep-alive connection when configured to receive them" do - Assert.stub(@server.server_data, :receives_keep_alive){ true } - @connection.read_data = nil # nothing to read makes it a keep-alive - assert_false @connection_handler_spy.run_called - subject.call(@socket) - assert_false @connection_handler_spy.run_called - end - - should "run a keep-alive connection when configured to receive them" do - Assert.stub(@server.server_data, :receives_keep_alive){ false } - @connection.read_data = nil # nothing to read makes it a keep-alive - assert_false @connection_handler_spy.run_called - subject.call(@socket) - assert_true @connection_handler_spy.run_called - end - - end - - class ConnectionTests < UnitTests - desc "Connection" - setup do - fake_socket = Factory.string - @protocol_conn = Sanford::Protocol::FakeConnection.new(Factory.binary) - Assert.stub(Sanford::Protocol::Connection, :new).with(fake_socket) do - @protocol_conn - end - @connection = Connection.new(fake_socket) - end - subject{ @connection } - - should have_imeths :read_data, :write_data, :peek_data - should have_imeths :close_write - - should "default its timeout" do - assert_equal 1.0, subject.timeout - end - - should "allowing reading from the protocol connection" do - result = subject.read_data - assert_equal @protocol_conn.read_data, result - assert_equal @protocol_conn.read_timeout, subject.timeout - end - - should "allowing writing to the protocol connection" do - data = Factory.binary - subject.write_data(data) - assert_equal @protocol_conn.write_data, data - end - - should "allowing peeking from the protocol connection" do - result = subject.peek_data - assert_equal @protocol_conn.peek_data, result - assert_equal @protocol_conn.peek_timeout, subject.timeout - end - - should "allow closing the write stream on the protocol connection" do - assert_false @protocol_conn.closed_write - subject.close_write - assert_true @protocol_conn.closed_write - end - - end - - class TCPCorkTests < UnitTests - desc "TCPCork" - subject{ TCPCork } - - should have_imeths :apply, :remove - - end - class ConfigurationTests < UnitTests include NsOptions::AssertMacros desc "Configuration" setup do @@ -450,21 +371,25 @@ should have_options :name, :ip, :port, :pid_file should have_options :receives_keep_alive should have_options :verbose_logging, :logger should have_options :template_source should have_accessors :init_procs, :error_procs + should have_accessors :worker_class, :worker_params, :num_workers + should have_accessors :shutdown_timeout should have_accessors :router - should have_readers :worker_start_procs, :worker_shutdown_procs - should have_readers :worker_sleep_procs, :worker_wakeup_procs should have_imeths :routes should have_imeths :to_hash should have_imeths :valid?, :validate! should "be an ns-options proxy" do assert_includes NsOptions::Proxy, subject.class end + should "know its default num workers" do + assert_equal 4, Configuration::DEFAULT_NUM_WORKERS + end + should "default its options" do config = Configuration.new assert_nil config.name assert_equal '0.0.0.0', config.ip assert_nil config.port @@ -474,18 +399,19 @@ assert_true config.verbose_logging assert_instance_of Sanford::NullLogger, config.logger assert_instance_of Sanford::NullTemplateSource, config.template_source + assert_equal DefaultWorker, config.worker_class + assert_nil config.worker_params + assert_equal Configuration::DEFAULT_NUM_WORKERS, config.num_workers + + assert_nil config.shutdown_timeout + assert_equal [], config.init_procs assert_equal [], config.error_procs - assert_equal [], subject.worker_start_procs - assert_equal [], subject.worker_shutdown_procs - assert_equal [], subject.worker_sleep_procs - assert_equal [], subject.worker_wakeup_procs - assert_instance_of Sanford::Router, config.router assert_empty config.router.routes end should "not be valid by default" do @@ -498,18 +424,18 @@ assert_equal subject.router.routes, subject.routes end should "include its procs and router/routes in its `to_hash`" do config_hash = subject.to_hash - assert_equal subject.init_procs, config_hash[:init_procs] - assert_equal subject.error_procs, config_hash[:error_procs] - assert_equal subject.worker_start_procs, config_hash[:worker_start_procs] - assert_equal subject.worker_shutdown_procs, config_hash[:worker_shutdown_procs] - assert_equal subject.worker_sleep_procs, config_hash[:worker_sleep_procs] - assert_equal subject.worker_wakeup_procs, config_hash[:worker_wakeup_procs] - assert_equal subject.router, config_hash[:router] - assert_equal subject.routes, config_hash[:routes] + assert_equal subject.worker_class, config_hash[:worker_class] + assert_equal subject.worker_params, config_hash[:worker_params] + assert_equal subject.num_workers, config_hash[:num_workers] + assert_equal subject.shutdown_timeout, config_hash[:shutdown_timeout] + assert_equal subject.init_procs, config_hash[:init_procs] + assert_equal subject.error_procs, config_hash[:error_procs] + assert_equal subject.router, config_hash[:router] + assert_equal subject.routes, config_hash[:routes] end should "call its init procs when validated" do called = false subject.init_procs << proc{ called = true } @@ -531,10 +457,18 @@ subject.port = Factory.integer assert_nothing_raised{ subject.validate! } end + should "validate its worker class when validated" do + subject.worker_class = Module.new + assert_raises(InvalidError){ subject.validate! } + + subject.worker_class = Class.new + assert_raises(InvalidError){ subject.validate! } + end + should "validate its routes when validated" do subject.router.service(Factory.string, TestHandler.to_s) subject.routes.each{ |route| assert_nil route.handler_class } subject.validate! subject.routes.each{ |route| assert_not_nil route.handler_class } @@ -566,21 +500,9 @@ @set_socket_option_calls = [] end def setsockopt(*args) @set_socket_option_calls << args - end - end - - class ConnectionHandlerSpy - attr_reader :run_called - - def initialize - @run_called = false - end - - def run - @run_called = true end end end