diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..61d670e --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,31 @@ +name: CI + +on: + push: + branches: [master] + pull_request: + branches: [master] + +jobs: + test: + runs-on: ubuntu-latest + + strategy: + fail-fast: false + matrix: + ruby-version: ["4.0"] + + steps: + - uses: actions/checkout@v4 + + - name: Set up Ruby ${{ matrix.ruby-version }} + uses: ruby/setup-ruby@v1 + with: + ruby-version: ${{ matrix.ruby-version }} + bundler-cache: true + + - name: Install dependencies + run: bundle install + + - name: Run tests + run: bundle exec rake test diff --git a/Gemfile b/Gemfile new file mode 100644 index 0000000..c02d10b --- /dev/null +++ b/Gemfile @@ -0,0 +1,10 @@ +# frozen_string_literal: true + +source "https://rubygems.org" + +gemspec + +group :development, :test do + gem "minitest" + gem "rake" +end diff --git a/Gemfile.lock b/Gemfile.lock new file mode 100644 index 0000000..ad909e0 --- /dev/null +++ b/Gemfile.lock @@ -0,0 +1,67 @@ +PATH + remote: . + specs: + mock-server (0.2.0) + puma (>= 7.0) + sinatra (>= 4.0) + +GEM + remote: https://rubygems.org/ + specs: + base64 (0.3.0) + logger (1.7.0) + minitest (6.0.1) + prism (~> 1.5) + mustermann (3.0.4) + ruby2_keywords (~> 0.0.1) + nio4r (2.7.5) + prism (1.9.0) + puma (7.2.0) + nio4r (~> 2.0) + rack (3.2.4) + rack-protection (4.2.1) + base64 (>= 0.1.0) + logger (>= 1.6.0) + rack (>= 3.0.0, < 4) + rack-session (2.1.1) + base64 (>= 0.1.0) + rack (>= 3.0.0) + rake (13.3.1) + ruby2_keywords (0.0.5) + sinatra (4.2.1) + logger (>= 1.6.0) + mustermann (~> 3.0) + rack (>= 3.0.0, < 4) + rack-protection (= 4.2.1) + rack-session (>= 2.0.0, < 3) + tilt (~> 2.0) + tilt (2.7.0) + +PLATFORMS + arm64-darwin-23 + ruby + +DEPENDENCIES + minitest + mock-server! + rake + +CHECKSUMS + base64 (0.3.0) sha256=27337aeabad6ffae05c265c450490628ef3ebd4b67be58257393227588f5a97b + logger (1.7.0) sha256=196edec7cc44b66cfb40f9755ce11b392f21f7967696af15d274dde7edff0203 + minitest (6.0.1) sha256=7854c74f48e2e975969062833adc4013f249a4b212f5e7b9d5c040bf838d54bb + mock-server (0.2.0) + mustermann (3.0.4) sha256=85fadcb6b3c6493a8b511b42426f904b7f27b282835502233dd154daab13aa22 + nio4r (2.7.5) sha256=6c90168e48fb5f8e768419c93abb94ba2b892a1d0602cb06eef16d8b7df1dca1 + prism (1.9.0) sha256=7b530c6a9f92c24300014919c9dcbc055bf4cdf51ec30aed099b06cd6674ef85 + puma (7.2.0) sha256=bf8ef4ab514a4e6d4554cb4326b2004eba5036ae05cf765cfe51aba9706a72a8 + rack (3.2.4) sha256=5d74b6f75082a643f43c1e76b419c40f0e5527fcfee1e669ac1e6b73c0ccb6f6 + rack-protection (4.2.1) sha256=cf6e2842df8c55f5e4d1a4be015e603e19e9bc3a7178bae58949ccbb58558bac + rack-session (2.1.1) sha256=0b6dc07dea7e4b583f58a48e8b806d4c9f1c6c9214ebc202ec94562cbea2e4e9 + rake (13.3.1) sha256=8c9e89d09f66a26a01264e7e3480ec0607f0c497a861ef16063604b1b08eb19c + ruby2_keywords (0.0.5) sha256=ffd13740c573b7301cf7a2e61fc857b2a8e3d3aff32545d6f8300d8bae10e3ef + sinatra (4.2.1) sha256=b7aeb9b11d046b552972ade834f1f9be98b185fa8444480688e3627625377080 + tilt (2.7.0) sha256=0d5b9ba69f6a36490c64b0eee9f6e9aad517e20dcc848800a06eb116f08c6ab3 + +BUNDLED WITH + 4.0.5 diff --git a/Rakefile b/Rakefile new file mode 100644 index 0000000..6d5767d --- /dev/null +++ b/Rakefile @@ -0,0 +1,11 @@ +# frozen_string_literal: true + +require "rake/testtask" + +Rake::TestTask.new(:test) do |t| + t.libs << "test" + t.libs << "lib" + t.test_files = FileList["test/**/*_test.rb"] +end + +task default: :test diff --git a/lib/mock_server.rb b/lib/mock_server.rb index 1c1d8a3..684fbb3 100644 --- a/lib/mock_server.rb +++ b/lib/mock_server.rb @@ -1,8 +1,8 @@ +# frozen_string_literal: true + require "sinatra/base" require "puma" -require "rack/handler/puma" require "socket" -require "logger" Thread.abort_on_exception = true @@ -18,10 +18,11 @@ def initialize(app, host: "0.0.0.0", port: 4000, &block) end def start + @server = Puma::Server.new(@app) + @server.add_tcp_listener(@host, @port) + @thread = Thread.new do - Rack::Handler::Puma.run(@app, { - :Host => @host, :Port => @port, :Silent => true, :AccessLog => [] - }) {|server| @server = server} + @server.run end wait_for_service(@host, @port) @@ -30,7 +31,7 @@ def start end def stop - @server.stop + @server.stop(true) wait_for_shutdown(@host, @port) @@ -46,17 +47,16 @@ def mock_server(**args, &block) end protected + def listening?(host, port) - begin - socket = TCPSocket.new(host, port) - socket.close unless socket.nil? - true - rescue Errno::ECONNREFUSED, - Errno::ECONNRESET, - Errno::EBADF, # Windows - Errno::EADDRNOTAVAIL # Windows - false - end + socket = TCPSocket.new(host, port) + socket.close unless socket.nil? + true + rescue Errno::ECONNREFUSED, + Errno::ECONNRESET, + Errno::EBADF, # Windows + Errno::EADDRNOTAVAIL # Windows + false end def wait_for_service(host, port, timeout = 10) diff --git a/mock-server.gemspec b/mock-server.gemspec index f03101b..a629e7d 100644 --- a/mock-server.gemspec +++ b/mock-server.gemspec @@ -1,11 +1,18 @@ +# frozen_string_literal: true + Gem::Specification.new do |s| s.name = "mock-server" - s.version = "0.1.1" - s.summary = %{A quick way of mocking an external web service you want to consume.} + s.version = "0.2.0" + s.summary = "A quick way of mocking an external web service you want to consume." s.authors = ["Damian Janowski"] s.email = ["djanowski@dimaion.com"] s.homepage = "http://github.com/djanowski/mock-server" - s.files = ["lib/mock_server.rb", "README.markdown", "test/mock_server_test.rb"] + s.license = "MIT" + + s.required_ruby_version = ">= 4.0.0" + + s.files = Dir["lib/**/*.rb", "README.markdown"] - s.add_dependency "sinatra" + s.add_dependency "sinatra", ">= 4.0" + s.add_dependency "puma", ">= 7.0" end diff --git a/mock-server.gemspec.erb b/mock-server.gemspec.erb deleted file mode 100644 index 33c96bf..0000000 --- a/mock-server.gemspec.erb +++ /dev/null @@ -1,11 +0,0 @@ -Gem::Specification.new do |s| - s.name = "mock-server" - s.version = "0.1.1" - s.summary = %{A quick way of mocking an external web service you want to consume.} - s.authors = ["Damian Janowski"] - s.email = ["djanowski@dimaion.com"] - s.homepage = "http://github.com/djanowski/mock-server" - s.files = <%= Dir['lib/**/*.rb', 'README.markdown', 'LICENSE', 'Rakefile', 'rails/**/*', 'test/**/*.*'].inspect %> - - s.add_dependency "sinatra" -end diff --git a/test/mock_server_test.rb b/test/mock_server_test.rb index 63257ec..a16a732 100644 --- a/test/mock_server_test.rb +++ b/test/mock_server_test.rb @@ -1,7 +1,8 @@ -require File.expand_path(File.join(File.dirname(__FILE__), "..", "lib", "mock_server")) +# frozen_string_literal: true -require "test/unit" -require "open-uri" +require "minitest/autorun" +require "net/http" +require_relative "../lib/mock_server" class HelloWorldSinatra < Sinatra::Base get "/" do @@ -9,34 +10,45 @@ class HelloWorldSinatra < Sinatra::Base end end -class MockServerTest < Test::Unit::TestCase +HelloWorldRackBuilder = Rack::Builder.new do + run lambda { |env| + [200, { "content-type" => "text/plain", "content-length" => "7" }, ["Rackup!"]] + } +end + +class MockServerTest < Minitest::Test def setup @server = MockServer.new(HelloWorldSinatra) @server.start end - def test_server - assert_equal "Hello", open("http://localhost:4000").read + def teardown + @server&.stop end -end -HelloWorldRackBuilder = Rack::Builder.new do - run lambda {|env| - [200, {"Content-Type" => "text/plain", "Content-Length" => "7"}, ["Rackup!"]] - } + def test_server_responds_with_hello + response = Net::HTTP.get(URI("http://localhost:4000")) + assert_equal "Hello", response + end end -class MockServerRackBuilderTest < Test::Unit::TestCase +class MockServerRackBuilderTest < Minitest::Test def setup @server = MockServer.new(HelloWorldRackBuilder, port: 4001) @server.start end - def test_server - assert_equal "Rackup!", open("http://localhost:4001").read - end end + def teardown + @server&.stop + end + + def test_rack_builder_app_responds + response = Net::HTTP.get(URI("http://localhost:4001")) + assert_equal "Rackup!", response + end +end -class MockServerMethodsTest < Test::Unit::TestCase +class MockServerMethodsTest < Minitest::Test extend MockServer::Methods mock_server(port: 4002) { @@ -45,24 +57,42 @@ class MockServerMethodsTest < Test::Unit::TestCase end } - def test_server - assert_equal "Goodbye", open("http://localhost:4002").read + def test_mock_server_dsl_works + response = Net::HTTP.get(URI("http://localhost:4002")) + assert_equal "Goodbye", response end end -class MockServerStopTest < Test::Unit::TestCase +class MockServerStopTest < Minitest::Test def setup @server = MockServer.new(HelloWorldSinatra, port: 4003) @server.start end - def test_stop_server - assert_equal "Hello", open("http://localhost:4003").read + def test_stop_server_closes_connection + response = Net::HTTP.get(URI("http://localhost:4003")) + assert_equal "Hello", response @server.stop - assert_raises(Errno::ECONNREFUSED) { - open("http://localhost:4003").read - } + assert_raises(Errno::ECONNREFUSED) do + Net::HTTP.get(URI("http://localhost:4003")) + end + end +end + +class MockServerCustomHostTest < Minitest::Test + def setup + @server = MockServer.new(HelloWorldSinatra, host: "127.0.0.1", port: 4004) + @server.start + end + + def teardown + @server&.stop + end + + def test_custom_host_binding + response = Net::HTTP.get(URI("http://127.0.0.1:4004")) + assert_equal "Hello", response end end