I'm starting the 06_performance_monitor exercise in TestFirst Ruby and the failure it lists is in the Rspec that was provided in the materials for TestFirst Ruby tutorial (where it says undefined method 'measure'). From what I've been able to find online, it seems this tutorial was written for Rspec 2 and Ruby 1.9. I currently have Rspec 2.99.0, Ruby 1.9.3, and Rake 0.9.22 installed. I guess my question is, what am I doing wrong/do I need different versions? I don't understand why the provided Rspec doesn't seem to work as it should. This happened in one other exercise for this tutorial but it was only a minor error message that didn't interfere with my testing.
caitlyns-mbp:06_performance_monitor caitlynyu$ rake
(in /Users/caitlynyu/Desktop/learn_ruby)
Run options: include {:focus=>true}
All examples were filtered out; ignoring {:focus=>true}
Performance Monitor
runs a block N times (FAILED - 1)
Failures:
1) Performance Monitor runs a block N times
Failure/Error: measure(4) do
NoMethodError:
undefined method `measure' for #<RSpec::Core::ExampleGroup::Nested_1:0x007fcdc11b8578>
# ./06_performance_monitor/performance_monitor_spec.rb:53:in `block (2 levels) in <top (required)>'
Finished in 0.00081 seconds
1 example, 1 failure
Failed examples:
rspec ./06_performance_monitor/performance_monitor_spec.rb:51 # Performance Monitor runs a block N times
Randomized with seed 2933
/Users/caitlynyu/.rvm/rubies/ruby-1.9.3-p547/bin/ruby -S rspec /Users/caitlynyu/Desktop/learn_ruby/06_performance_monitor/performance_monitor_spec.rb -I/Users/caitlynyu/Desktop/learn_ruby/06_performance_monitor -I/Users/caitlynyu/Desktop/learn_ruby/06_performance_monitor/solution -f documentation -r ./rspec_config failed
caitlyns-mbp:06_performance_monitor caitlynyu$
UPDATE
My code below (I know it doesn't pass any of the tests below, I was just playing around with this first):
def performance_monitor
start = Time.now
yield
return "#{Time.now - start}"
end
I've never used a method called 'measure' that shows up in the Rspec which is below:
# # Topics
#
# * stubs
# * blocks
# * yield
#
# # Performance Monitor
#
# This is (a stripped down version of) an actual useful concept: a
# function that runs a block of code and then tells you how long it
# took to run.
require "performance_monitor"
require "time" # loads up the Time.parse method -- do NOT create time.rb!
describe "Performance Monitor" do
before do
#eleven_am = Time.parse("2011-1-2 11:00:00")
end
it "takes about 0 seconds to run an empty block" do
elapsed_time = measure do
end
elapsed_time.should be_within(0.1).of(0)
end
it "takes exactly 0 seconds to run an empty block (with stubs)" do
Time.stub(:now) { #eleven_am }
elapsed_time = measure do
end
elapsed_time.should == 0
end
it "takes about 1 second to run a block that sleeps for 1 second" do
elapsed_time = measure do
sleep 1
end
elapsed_time.should be_within(0.1).of(1)
end
it "takes exactly 1 second to run a block that sleeps for 1 second (with stubs)" do
fake_time = #eleven_am
Time.stub(:now) { fake_time }
elapsed_time = measure do
fake_time += 60 # adds one minute to fake_time
end
elapsed_time.should == 60
end
it "runs a block N times" do
n = 0
measure(4) do
n += 1
end
n.should == 4
end
it "returns the average time, not the total time, when running multiple times" do
run_times = [8,6,5,7]
fake_time = #eleven_am
Time.stub(:now) { fake_time }
average_time = measure(4) do
fake_time += run_times.pop
end
average_time.should == 6.5
end
it "returns the average time when running a random number of times for random lengths of time" do
fake_time = #eleven_am
Time.stub(:now) { fake_time }
number_of_times = rand(10) + 2
average_time = measure(number_of_times) do
delay = rand(10)
fake_time += delay
end
average_time.should == (fake_time - #eleven_am).to_f/number_of_times
end
end
Related
Ruby 3 introduced Fiber.schedule to dispatch async tasks concurrently.
Similar to what's being asked in this question (which is about threaded concurrency) I would like a way to start multiple concurrent tasks on the fiber scheduler and once they have all been scheduled wait for their combined result, sort of equivalent to Promise.all in JavaScript.
I can come up with this naive way:
require 'async'
def io_work(t)
sleep t
:ok
end
Async do
results = []
[0.1, 0.3, 'cow'].each_with_index do |t, i|
n = i + 1
Fiber.schedule do
puts "Starting fiber #{n}\n"
result = io_work t
puts "Done working for #{t} seconds in fiber #{n}"
results << [n, result]
rescue
puts "Execution failed in fiber #{n}"
results << [n, :error]
end
end
# await combined results
sleep 0.1 until results.size >= 3
puts "Results: #{results}"
end
Is there a simpler construct that will do the same?
Since Async tasks are already scheduled I am not sure you need all of that.
If you just want to wait for all the items to finish you can use an Async::Barrier
Example:
require 'async'
require 'async/barrier'
def io_work(t)
sleep t
:ok
end
Async do
barrier = Async::Barrier.new
results = []
[1, 0.3, 'cow'].each.with_index(1) do |data, idx|
barrier.async do
results << begin
puts "Starting task #{idx}\n"
result = io_work data
puts "Done working for #{data} seconds in task #{idx}"
[idx,result]
rescue
puts "Execution failed in task #{idx}"
[idx, :error]
end
end
end
barrier.wait
puts "Results: #{results}"
end
Based on the sleep values this will output
Starting task 1
Starting task 2
Starting task 3
Execution failed in task 3
Done working for 0.3 seconds in task 2
Done working for 1 seconds in task 1
Results: [[3, :error], [2, :ok], [1, :ok]]
The barrier.wait will wait until all the asynchronous tasks are complete, without it the output would look like
Starting fiber 1
Starting fiber 2
Starting fiber 3
Execution failed in fiber 3
Results: [[3, :error]]
Done working for 0.3 seconds in fiber 2
Done working for 1 seconds in fiber 1
I wasn't too happy with the ergonomics of the solution, so I made the gem fiber-collector to address it.
Disclaimer: I'm describing a library of which I am the author
Example usage in the scenario from the question:
require 'async'
require 'fiber/collector'
def io_work(t)
sleep t
:ok
end
Async do
Fiber::Collector.schedule { io_work(1) }.and { io_work(0.3) }.all
end.wait
# => [:ok, :ok]
Async do
Fiber::Collector.schedule { io_work(1) }.and { io_work(0.3) }.and { io_work('cow') }.all
end.wait
# => raises error
I have a test file, ipca_test.rb:
require "test_helper"
require "matrix" # Does needing to include this here mean I'm doing something wrong?
class IpcaTest < Minitest::Test
def test_that_it_has_a_version_number
refute_nil ::Ipca::VERSION
end
def test_it_does_something_useful
refute false
end
def test_on_a_random_matrix
p = rand(3..10)
n = rand(20..50)
m = Matrix.build(n, p) {|_, _| rand(-10.0..10.0)}
pca = Ipca::Pca.new(m)
eigenvalue, r = pca.first_principal_component
puts "eigenvalue: #{eigenvalue}, r: #{r}"
assert eigenvalue.kind_of? Numeric
assert_equal Vector, r.class
end
end
The program I'm trying to test is ipca.rb:
require "ipca/version"
module Ipca
class Error < StandardError; end
class Pca
def initialize data
#data = data.class == Matrix ? data : Matrix.rows(data)
end
# see https://en.wikipedia.org/wiki/Principal_component_analysis#Iterative_computation
def first_principal_component(c = 100, tolerance = 0.001) # not sure whether defaults are apropos
p = #data.column_vectors.count
r = Vector.elements(Array.new(p) {|_| rand}).normalize
eigenvalue = nil
c.times do
s = Vector.zero(p)
#data.row_vectors.each do |x|
s += x.dot(r)*x
end
eigenvalue = r.dot(s) # ?
error = (eigenvalue*r-s).norm
r = s.normalize
exit if error < tolerance
end
return [eigenvalue, r]
end
end
end
(Git repo of entire tree)
Sometimes the test is successful, but much more often the test never gets to "Finished". In these cases there are zero or more dots representing (I assume) successful assertions. I'm guessing that the tests runs are being halted by some kind of timeout somewhere in my bundle, and that this times out intermittently because the input data for the test is of varying size. But if it's a timeout issue why is there not a message to that effect? Here is a series of test runs:
josie#josie-Inspiron-580:/var/www/html/ruby/ipca$ ruby -Itest
test/ipca_test.rb Run options: --seed 44059
# Running:
..josie#josie-Inspiron-580:/var/www/html/ruby/ipca$ ruby -Itest
test/ipca_test.rb Run options: --seed 57681
# Running:
.josie#josie-Inspiron-580:/var/www/html/ruby/ipca$ ruby -Itest
test/ipca_test.rb Run options: --seed 57222
# Running:
..josie#josie-Inspiron-580:/var/www/html/ruby/ipca$ ruby -Itest
test/ipca_test.rb Run options: --seed 7474
# Running:
..josie#josie-Inspiron-580:/var/www/html/ruby/ipca$ ruby -Itest
test/ipca_test.rb Run options: --seed 1938
# Running:
..josie#josie-Inspiron-580:/var/www/html/ruby/ipca$ ruby -Itest
test/ipca_test.rb Run options: --seed 61325
# Running:
..eigenvalue: 2027.687580111128, r: Vector[0.03288542301229099,
-0.09533529249551115, 0.3033273986606458, 0.07951734565050736, 0.3575555246291426, 0.41614419068773545, 0.4928822662304588, 0.28785088479078025, 0.5144766379975693] .
Finished in 0.037173s, 80.7047 runs/s, 107.6063 assertions/s.
3 runs, 4 assertions, 0 failures, 0 errors, 0 skips
josie#josie-Inspiron-580:/var/www/html/ruby/ipca$
Use break instead of exit:
break if error < tolerance
break exits just the do loop.
exit exits the program itself not giving a chance for minitest to fail the test
Hi I'm completely new to Ruby. I'm trying to run Minitests, it use to work fine until I added a constructor to my CountDown class.
Here is the code:
require 'benchmark'
require 'minitest/autorun'
#! /usr/bin/env ruby
#This is our countdown class
# :reek:DuplicateMethodCall
# :reek:TooManyStatements
class CountDown
def initialize(time)
#time = time
end
def count()
wait_time = #time.to_i
print wait_time.to_s + " seconds left\n"
sleep 1
wait_time = wait_time - 1
wait_time.downto(1).each do |time_left|
sleep 1
print time_left.to_s + " seconds left\n" if (time_left % 60) == 0
end
print "\a"
end
end
#This class is responsible for our test cases
class CountDownTest < Minitest::Test
def setup
#count_down = CountDown.new(10)
end
def testing_lowerbound
time = Benchmark.measure{
#count_down.count
}
assert time.real.to_i == 10
end
end
This my my output:
teamcity[enteredTheMatrix timestamp = '2017-09-28T15:10:11.470-0700']
teamcity[testCount count = '0' timestamp = '2017-09-28T15:10:11.471-0700'] Finished in 0.00038s 0 tests, 0
assertions, 0 failures, 0 errors, 0 skips
Process finished with exit code 0
Any idea what's wrong? It looks fine to me.
Tests should start with the prefix test_ not testing_. Using the wrong prefix makes MiniTest assume they're doing something other than running a test, so it ignores them.
In ruby, is it possible to cause a thread to pause from a different concurrently running thread.
Below is the code that I've written so far. I want the user to be able to type 'pause thread' and the sample500 thread to pause.
#!/usr/bin/env ruby
# Creates a new thread executes the block every intervalSec for durationSec.
def DoEvery(thread, intervalSec, durationSec)
thread = Thread.new do
start = Time.now
timeTakenToComplete = 0
loopCounter = 0
while(timeTakenToComplete < durationSec && loopCounter += 1)
yield
finish = Time.now
timeTakenToComplete = finish - start
sleep(intervalSec*loopCounter - timeTakenToComplete)
end
end
end
# User input loop.
exit = nil
while(!exit)
userInput = gets
case userInput
when "start thread\n"
sample500 = Thread
beginTime = Time.now
DoEvery(sample500, 0.5, 30) {File.open('abc', 'a') {|file| file.write("a\n")}}
when "pause thread\n"
sample500.stop
when "resume thread"
sample500.run
when "exit\n"
exit = TRUE
end
end
Passing Thread object as argument to DoEvery function makes no sense because you immediately overwrite it with Thread.new, check out this modified version:
def DoEvery(intervalSec, durationSec)
thread = Thread.new do
start = Time.now
Thread.current["stop"] = false
timeTakenToComplete = 0
loopCounter = 0
while(timeTakenToComplete < durationSec && loopCounter += 1)
if Thread.current["stop"]
Thread.current["stop"] = false
puts "paused"
Thread.stop
end
yield
finish = Time.now
timeTakenToComplete = finish - start
sleep(intervalSec*loopCounter - timeTakenToComplete)
end
end
thread
end
# User input loop.
exit = nil
while(!exit)
userInput = gets
case userInput
when "start thread\n"
sample500 = DoEvery(0.5, 30) {File.open('abc', 'a') {|file| file.write("a\n")} }
when "pause thread\n"
sample500["stop"] = true
when "resume thread\n"
sample500.run
when "exit\n"
exit = TRUE
end
end
Here DoEvery returns new thread object. Also note that Thread.stop called inside running thread, you can't directly stop one thread from another because it is not safe.
You may be able to better able to accomplish what you are attempting using Ruby Fiber object, and likely achieve better efficiency on the running system.
Fibers are primitives for implementing light weight cooperative
concurrency in Ruby. Basically they are a means of creating code
blocks that can be paused and resumed, much like threads. The main
difference is that they are never preempted and that the scheduling
must be done by the programmer and not the VM.
Keeping in mind the current implementation of MRI Ruby does not offer any concurrent running threads and the best you are able to accomplish is a green threaded program, the following is a nice example:
require "fiber"
f1 = Fiber.new { |f2| f2.resume Fiber.current; while true; puts "A"; f2.transfer; end }
f2 = Fiber.new { |f1| f1.transfer; while true; puts "B"; f1.transfer; end }
f1.resume f2 # =>
# A
# B
# A
# B
# .
# .
# .
'Weight converter'
Trying to get the hang of using stubs but I can't get the format right, what do I have wrong? I know I already have the method in the code in this case but I am trying to learn how to do a stub correctly.
Test:
describe "Convert Pounds to Kilograms" do
it "should convert 3lb to 1kg" do
weight = WeightConverter.stub!(:convert).with(3, 'lbs_to_kgs').and_return(1)
weight.should == 1
end
Code:
class WeightConverter
def self.convert(from, what_to_what)
if what_to_what == 'lbs_to_kgs'
(from / 2.2).truncate
elsif what_to_what == 'kgs_to_lbs'
(from * 2.2).truncate
end
end
end
fyi - this works (without stubs)
it "should convert 91lbs to 41kgs" do
weight = WeightConverter.convert(91, 'lbs_to_kgs')
weight.should == 41
end
Error:
Failures:
1) Convert Pounds to Kilograms should convert 3lb to 1kg
Failure/Error: weight.should == 1
expected: 1
got: #<Proc:0x000000010b0468#/home/durrantm/.rvm/gems/ruby-1.9.3-p125/gems/rspec-mocks-2.10.1/lib/rspec/mocks/message_expectation.rb:459 (lambda)> (using ==)
# ./weight_converter_spec.rb:19:in `block (2 levels) in <top (required)>'
Finished in 0.00513 seconds
7 examples, 1 failure
You don't want to assign to the stub, rather you should be doing something like this:
it "should convert 3lb to 1kg" do
WeightConverter.stub!(:convert).with(3, 'lbs_to_kgs').and_return(1)
weight = WeightConverter.convert(3, 'lbs_to_kgs')
weight.should == 1
end
However, that's a fairly useless test -- the only thing it's testing is that your stub/mock library does what it's supposed to (i.e. it's not actually testing WeightConverter at all). Since you're directly testing the internals of WeightConverter, you don't need to stub it. You should be using actual values like in your second example. However, if WeightConverter depended on another class, you might stub that other class.