Giter VIP home page Giter VIP logo

async-rspec's Introduction

Async::RSpec

Provides useful RSpec.shared_contexts for testing code that builds on top of async.

Development Status

Installation

$ bundle add async-rspec

Then add this require statement to the top of spec/spec_helper.rb

require 'async/rspec'

Usage

Async Reactor

Many specs need to run within a reactor. A shared context is provided which includes all the relevant bits, including the above leaks checks. If your spec fails to run in less than 10 seconds, an Async::TimeoutError raises to prevent your test suite from hanging.

require 'async/io'

RSpec.describe Async::IO do
	include_context Async::RSpec::Reactor
	
	let(:pipe) {IO.pipe}
	let(:input) {Async::IO::Generic.new(pipe.first)}
	let(:output) {Async::IO::Generic.new(pipe.last)}
	
	it "should send and receive data within the same reactor" do
		message = nil
		
		output_task = reactor.async do
			message = input.read(1024)
		end
		
		reactor.async do
			output.write("Hello World")
		end
		
		output_task.wait
		expect(message).to be == "Hello World"
		
		input.close
		output.close
	end
end

Changing Timeout

You can change the timeout by specifying it as an option:

RSpec.describe MySlowThing, timeout: 60 do
	# ...
end

File Descriptor Leaks

Leaking sockets and other kinds of IOs are a problem for long running services. Async::RSpec::Leaks tracks all open sockets both before and after the spec. If any are left open, a RuntimeError is raised and the spec fails.

RSpec.describe "leaky ios" do
	include_context Async::RSpec::Leaks
	
	# The following fails:
	it "leaks io" do
		@input, @output = IO.pipe
	end
end

In some cases, the Ruby garbage collector will close IOs. In the above case, it's possible that just writing IO.pipe will not leak as Ruby will garbage collect the resulting IOs immediately. It's still incorrect to not close IOs, so don't depend on this behaviour.

Allocations

This functionality was moved to rspec-memory.

Contributing

We welcome contributions to this project.

  1. Fork it.
  2. Create your feature branch (git checkout -b my-new-feature).
  3. Commit your changes (git commit -am 'Add some feature').
  4. Push to the branch (git push origin my-new-feature).
  5. Create new Pull Request.

async-rspec's People

Contributors

goos avatar ioquatix avatar janko avatar jeremyjung avatar olleolleolle avatar steap avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

async-rspec's Issues

Track memory usage and limit number of allocations

It would make sense to add.memory limits to specs, e.g. tracking memory usage and limits. It might be similar to the timeout: which can be used on a spec, something like memory:. Ideally, you can express exactly what you've said above - e.g. a constant upper bound for memory usage.

Additionally, it would be interesting to see if we can actually track, for example, the number of string allocations, and add that to a spec, similar to how IO is checked and all must be closed. It should be possible to say something like:

it "should receive chunks of data" do
    expect{
        chunk = body.read
    }.to limit_allocations(String => 1)
end

This would give me confidence that going forward we catch allocation issues. Otherwise, you might go to a lot of effort to implement such a path, but over time it may end up being damaged/broken by other changes. Without appropriate specs to catch such situations, we may loose your valuable contribution to memory usage.

socketry/falcon#8

Consider how we can assert that a block of code can not invoke the scheduler

In some cases, we want to assert that a method cannot possibly be non-blocking.

We should consider introducing a way to determine if the scheduler has been checked or not, so that we can make assertions about the behaviour of the code (non-blocking or not).

expect do
  # ...
end.to_not be_nondeterministic

Test fails on i386 and armhf architectures

While running bundle exec rspec on an i386 architecture, this test fails:

Failures:

  1) RSpec::Memory on supported platform should not exceed specified size limit
     Failure/Error:
       expect do
       	"a" * 100_000
       end.to limit_allocations.of(String, size: 100_001)
     
       exceeded allocation limit: allocated 2 String instances, 99961 bytes, expected exactly 100001 bytes
     # ./spec/async/rspec/memory_spec.rb:82:in `block (3 levels) in <top (required)>'

Finished in 3.34 seconds (files took 0.25602 seconds to load)
19 examples, 1 failure

Failed examples:

rspec ./spec/async/rspec/memory_spec.rb:81 # RSpec::Memory on supported platform should not exceed specified size limit

The same happens on armhf machines.

CI: JRuby fails on installing ruby-prof

This happened in

An error occurred while installing ruby-prof (1.4.2), and Bundler cannot
continue.

  Using async-rspec 1.16.1 from source at `.`
  Fetching async-rest 0.12.4
  Installing async-rest 0.12.4
  Fetching covered 0.14.0
  Installing covered 0.14.0
  Gem::Ext::BuildError: ERROR: Failed to build gem native extension.
  
  current directory:
  /home/runner/work/async-rspec/async-rspec/vendor/bundle/jruby/2.6.0/bundler/gems/ruby-prof-2c6a1558c1e9/ext/ruby_prof
  /home/runner/.rubies/jruby-9.3.4.0/bin/jruby -I
  /home/runner/.rubies/jruby-9.3.4.0/lib/ruby/stdlib -r
  ./siteconf20220603-1875-3mfokw.rb extconf.rb
  creating Makefile
  
  current directory:
  /home/runner/work/async-rspec/async-rspec/vendor/bundle/jruby/2.6.0/bundler/gems/ruby-prof-2c6a1558c1e9/ext/ruby_prof
  make DESTDIR\= clean
  
  current directory:
  /home/runner/work/async-rspec/async-rspec/vendor/bundle/jruby/2.6.0/bundler/gems/ruby-prof-2c6a1558c1e9/ext/ruby_prof
  make DESTDIR\=
  make: *** No rule to make target
  '/home/runner/.rubies/jruby-9.3.4.0/lib/ruby/include/ruby/ruby.h', needed by
  'rp_measure_allocations.o'.  Stop.
  
  make failed, exit code 2
  
  Gem files will remain installed in
  /home/runner/work/async-rspec/async-rspec/vendor/bundle/jruby/2.6.0/bundler/gems/ruby-prof-2c6a1558c1e9
  for inspection.
  Results logged to
  /home/runner/work/async-rspec/async-rspec/vendor/bundle/jruby/2.6.0/bundler/gems/extensions/universal-java-11/2.6.0/ruby-prof-2c6a1558c1e9/gem_make.out
  
  /home/runner/.rubies/jruby-9.3.4.0/lib/ruby/stdlib/rubygems/ext/builder.rb:92:in
  `run'
  /home/runner/.rubies/jruby-9.3.4.0/lib/ruby/stdlib/rubygems/ext/builder.rb:43:in
  `block in make'
    org/jruby/RubyArray.java:1865:in `each'
  /home/runner/.rubies/jruby-9.3.4.0/lib/ruby/stdlib/rubygems/ext/builder.rb:35:in
  `make'
  /home/runner/.rubies/jruby-9.3.4.0/lib/ruby/stdlib/rubygems/ext/ext_conf_builder.rb:63:in
  `block in build'
    org/jruby/ext/tempfile/Tempfile.java:242:in `open'
  /home/runner/.rubies/jruby-9.3.4.0/lib/ruby/stdlib/rubygems/ext/ext_conf_builder.rb:26:in
  `build'
  /home/runner/.rubies/jruby-9.3.4.0/lib/ruby/stdlib/rubygems/ext/builder.rb:158:in
  `build_extension'
  /home/runner/.rubies/jruby-9.3.4.0/lib/ruby/stdlib/rubygems/ext/builder.rb:192:in
  `block in build_extensions'
    org/jruby/RubyArray.java:1865:in `each'
  /home/runner/.rubies/jruby-9.3.4.0/lib/ruby/stdlib/rubygems/ext/builder.rb:189:in
  `build_extensions'
  /home/runner/.rubies/jruby-9.3.4.0/lib/ruby/stdlib/rubygems/installer.rb:837:in
  `build_extensions'
  /home/runner/.rubies/jruby-9.3.4.0/lib/ruby/gems/shared/gems/bundler-2.3.15/lib/bundler/rubygems_gem_installer.rb:71:in
  `build_extensions'
  /home/runner/.rubies/jruby-9.3.4.0/lib/ruby/gems/shared/gems/bundler-2.3.15/lib/bundler/source/path/installer.rb:34:in
  `post_install'
  /home/runner/.rubies/jruby-9.3.4.0/lib/ruby/gems/shared/gems/bundler-2.3.15/lib/bundler/source/path.rb:244:in
  `generate_bin'
  /home/runner/.rubies/jruby-9.3.4.0/lib/ruby/gems/shared/gems/bundler-2.3.15/lib/bundler/source/git.rb:194:in
  `install'
  /home/runner/.rubies/jruby-9.3.4.0/lib/ruby/gems/shared/gems/bundler-2.3.15/lib/bundler/installer/gem_installer.rb:54:in
  `install'
  /home/runner/.rubies/jruby-9.3.4.0/lib/ruby/gems/shared/gems/bundler-2.3.15/lib/bundler/installer/gem_installer.rb:16:in
  `install_from_spec'
  /home/runner/.rubies/jruby-9.3.4.0/lib/ruby/gems/shared/gems/bundler-2.3.15/lib/bundler/installer/parallel_installer.rb:186:in
  `do_install'
  /home/runner/.rubies/jruby-9.3.4.0/lib/ruby/gems/shared/gems/bundler-2.3.15/lib/bundler/installer/parallel_installer.rb:177:in
  `block in worker_pool'
  /home/runner/.rubies/jruby-9.3.4.0/lib/ruby/gems/shared/gems/bundler-2.3.15/lib/bundler/worker.rb:62:in
  `apply_func'
  /home/runner/.rubies/jruby-9.3.4.0/lib/ruby/gems/shared/gems/bundler-2.3.15/lib/bundler/worker.rb:57:in
  `block in process_queue'
    org/jruby/RubyKernel.java:1507:in `loop'
  /home/runner/.rubies/jruby-9.3.4.0/lib/ruby/gems/shared/gems/bundler-2.3.15/lib/bundler/worker.rb:54:in
  `process_queue'
  /home/runner/.rubies/jruby-9.3.4.0/lib/ruby/gems/shared/gems/bundler-2.3.15/lib/bundler/worker.rb:91:in
  `block in create_threads'
  
  An error occurred while installing ruby-prof (1.4.2), and Bundler cannot
  continue.
  
  In gems.rb:
    ruby-prof
  Took  33.13 seconds
Error: Error: The process '/home/runner/.rubies/jruby-9.3.4.0/bin/bundle' failed with exit code 5

Perhaps we can omit ruby-prof on... JRuby?

pending and skip do not work in tests that include the reactor context

When trying to use skip or pending inside of examples, the examples do not function as expected. skip results in the call being ignored and the test appearing that it has passed and pending throws an exception. The following script should be able to be used to reproduce:

require 'async/rspec'

RSpec.describe 'test pending and skip' do
	include_context Async::RSpec::Reactor

	it 'should show as pending if skipped' do
		skip 'this should be skipped'
		expect(true).to be false
	end

	it 'should show as pending if pending is called' do
		pending 'this is pending'
		expect(true).to be false
	end
end

When I run it I get the following output:

test pending and skip
  should show as pending if skipped
  should show as pending if pending is called (FAILED - 1)

Failures:

  1) test pending and skip should show as pending if pending is called
     Failure/Error: pending 'this is pending'

     RuntimeError:
       `pending` may not be used outside of examples, such as in before(:context). Maybe you want `skip`?
     # /Users/rdubya/.rvm/gems/jruby-9.1.17.0/gems/rspec-core-3.8.0/lib/rspec/core/pending.rb:94:in `pending'
     # ./spec/test_spec.rb:107:in `block in (root)'
     # org/jruby/RubyBasicObject.java:1728:in `instance_exec'
     # /Users/rdubya/.rvm/gems/jruby-9.1.17.0/gems/rspec-core-3.8.0/lib/rspec/core/example.rb:254:in `block in run'
     # /Users/rdubya/.rvm/gems/jruby-9.1.17.0/gems/rspec-core-3.8.0/lib/rspec/core/example.rb:500:in `block in with_around_and_singleton_context_hooks'
     # /Users/rdubya/.rvm/gems/jruby-9.1.17.0/gems/rspec-core-3.8.0/lib/rspec/core/example.rb:457:in `block in with_around_example_hooks'
     # /Users/rdubya/.rvm/gems/jruby-9.1.17.0/gems/rspec-core-3.8.0/lib/rspec/core/hooks.rb:464:in `block in run'
     # /Users/rdubya/.rvm/gems/jruby-9.1.17.0/gems/rspec-core-3.8.0/lib/rspec/core/hooks.rb:604:in `block in run_around_example_hooks_for'
     # /Users/rdubya/.rvm/gems/jruby-9.1.17.0/gems/rspec-core-3.8.0/lib/rspec/core/example.rb:342:in `call'
     # /Users/rdubya/.rvm/gems/jruby-9.1.17.0/gems/async-rspec-1.12.0/lib/async/rspec/reactor.rb:55:in `block in run_example'
     # /Users/rdubya/.rvm/gems/jruby-9.1.17.0/gems/async-1.15.1/lib/async/task.rb:199:in `block in make_fiber'

Finished in 0.1073 seconds (files took 2.97 seconds to load)
2 examples, 1 failure

Failed examples:

rspec ./spec/test_spec.rb:106 # test pending and skip should show as pending if pending is called

This was ran in the context of a full test suite so there is potentially something else at play, but the basic issue seems to be that RSpec.current_example is nil so it can't be flagged like it should be. The current example is stored on the thread so I'm guessing it has something to do with how the example is being ran in a different thread, but haven't tracked down exactly where the break is.

reactor.with ?

README mentions reactor.with(output) - it's not defined in reactor?

can async tasks persist between rspec tests?

Hi,
Can async task persists between the rspec tests? E.g. a server task that connects to some site that should be tested and keeps the connection open between tests.

I would also need a way to start and stop the server in the RSpec :before_suite and :after_suite hooks.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.