jicksta / adhearsion

Open-source framework for writing voice-enabled applications using Ruby.

This URL has Read+Write access

adhearsion / theatre-spec / invocation_spec.rb
100644 169 lines (138 sloc) 5.473 kb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
require File.dirname(__FILE__) + "/spec_helper"
 
GUID_REGEXP = /^[a-z0-9]{8}-[a-z0-9]{4}-[a-z0-9]{4}-[a-z0-9]{4}-[a-z0-9]{12}$/i
 
describe "The lifecycle of an Invocation" do
 
  include InvocationTestHelper
  
  before :all do
    @block = lambda {}
    @payload = 123
    @namespace = "/some/namespace"
  end
  
  it "should have an initial state of :new" do
    new_invocation.current_state.should eql(:new)
  end
  
  it "should not have a @queued_time until state becomes :queued" do
    invocation = new_invocation
    invocation.queued_time.should eql(nil)
    invocation.queued
    invocation.queued_time.should be_instance_of(Time)
    invocation.current_state.should eql(:queued)
  end
  
  it "should have a valid guid when instantiated" do
    new_invocation.unique_id.should =~ GUID_REGEXP
  end
  
  it "should execute the callback when moving to the 'start' state" do
    flexmock(@block).should_receive(:call).once
    invocation = new_invocation
    invocation.queued
    invocation.start
  end
  
end
 
describe "Using Invocations that've been ran through the Theatre" do
  
  it "should pass the payload to the callback" do
    destined_payload = [:i_feel_so_pretty, :OH, :SO, :PRETTY!]
    expecting_callback = lambda do |payload|
      payload.should equal(destined_payload)
    end
    invocation = Theatre::Invocation.new("/namespace/whatever", expecting_callback, destined_payload)
    invocation.queued
    invocation.start
  end
  
  it "should have a status of :error if an exception was raised and set the #error property" do
    errorful_callback = lambda { raise ArgumentError, "this error is intentional" } # Simulate logic error
    invocation = Theatre::Invocation.new("/namespace/whatever", errorful_callback)
    invocation.queued
    invocation.start
    invocation.current_state.should equal(:error)
    invocation.should be_error
    invocation.error.should be_instance_of(ArgumentError)
  end
 
  it "should have a status of :success if no expection was raised" do
    callback = lambda { "No errors raised here!" }
    invocation = Theatre::Invocation.new("/namespace/whatever", callback)
    invocation.queued
    invocation.start
    invocation.current_state.should equal(:success)
    invocation.should be_success
  end
  
  it "should set the #returned_value property to the returned value callback when a payload was given" do
    doubler = lambda { |num| num * 2 }
    invocation = Theatre::Invocation.new('/foo/bar', doubler, 5)
    invocation.queued
    invocation.start
    invocation.returned_value.should equal(10)
  end
  
  it "should set the #returned_value property to the returned value callback when a payload was NOT given" do
    doubler = lambda { :ohai }
    invocation = Theatre::Invocation.new('/foo/bar', doubler)
    invocation.queued
    invocation.start
    invocation.returned_value.should equal(:ohai)
  end
  
  it "should set the #finished_time property when a success was encountered" do
    block = lambda {}
    invocation = Theatre::Invocation.new('/foo/bar', block)
    invocation.queued
    
    now = Time.now
    flexmock(Time).should_receive(:now).twice.and_return now
    
    invocation.start
    invocation.should be_success
  end
  
  it "should set the #finished_time property when a failure was encountered" do
    block = lambda { raise LocalJumpError }
    invocation = Theatre::Invocation.new('/foo/bar', block)
    invocation.queued
    
    now = Time.now
    flexmock(Time).should_receive(:now).twice.and_return now
    
    invocation.start
    invocation.should be_error
  end
  
  it "should set the #started_time property after starting" do
    invocation = Theatre::Invocation.new('/foo/bar', lambda { sleep 0.01 } )
    invocation.queued
    invocation.started_time.should be_nil
    invocation.start
    invocation.started_time.should be_kind_of(Time)
  end
  
  it "should properly calculate #execution_duration" do
    time_ago_difference = 60 * 5 # Five minutes
    time_now = Time.now
    time_ago = time_now - time_ago_difference
    
    invocation = Theatre::Invocation.new('/foo/bar', lambda {} )
    invocation.queued
    invocation.start
    
    invocation.send(:instance_variable_set, :@started_time, time_ago)
    invocation.send(:instance_variable_set, :@finished_time, time_now)
    
    invocation.execution_duration.should be_close(time_ago_difference.to_f, 0.01)
  end
  
  it "should return the set value of returned_value when one has been set to a non-nil value" do
    return_nil = lambda { 123 }
    invocation = Theatre::Invocation.new("/namespace/whatever", return_nil)
    invocation.queued
    invocation.start
    invocation.returned_value.should eql(123)
  end
  
  it "should return nil for returned_value when it has been set to nil" do
    return_nil = lambda { nil }
    invocation = Theatre::Invocation.new("/namespace/whatever", return_nil)
    invocation.queued
    invocation.start
    invocation.returned_value.should eql(nil)
  end
  
  it "waiting on an Invocation should execute properly" do
    wait_on_invocation = lambda { 123 }
    invocation = Theatre::Invocation.new("/namespace/whatever", wait_on_invocation)
    Thread.new do
      invocation.queued
      invocation.start
    end
    invocation.wait.should eql(123)
    invocation.success?.should eql(true)
  end
  
end
 
BEGIN {
  module InvocationTestHelper
    def new_invocation(payload=@payload)
      Theatre::Invocation.new(@namespace, @block, @payload)
    end
  end
}