motel 0.3 → 0.3.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,156 @@
1
+ # callbacks module tests
2
+ #
3
+ # Copyright (C) 2010 Mohammed Morsi <movitto@yahoo.com>
4
+ # Licensed under the AGPLv3+ http://www.gnu.org/licenses/agpl.txt
5
+
6
+ require File.dirname(__FILE__) + '/spec_helper'
7
+
8
+ describe Motel::Callbacks::Movement do
9
+ it "should invoke handler w/out restriction by default" do
10
+ invoked = false
11
+ loc = Location.new :x => 0, :y => 0, :z => 0
12
+ Motel::Callbacks::Movement.new(:handler => lambda { |loc, d, dx, dy, dz|
13
+ invoked = true
14
+ loc.should == loc
15
+ d.should == 0
16
+ dx.should == 0
17
+ dy.should == 0
18
+ dz.should == 0
19
+ }).invoke(loc, 0, 0, 0)
20
+ invoked.should be_true
21
+ end
22
+
23
+ it "should invoke handler only when location moves min distance" do
24
+ invoked = false
25
+ loc = Location.new :x => 0, :y => 0, :z => 0
26
+ cb = Motel::Callbacks::Movement.new :min_distance => 10,
27
+ :handler => lambda { |loc, d, dx, dy, dz|
28
+ invoked = true
29
+ }
30
+ cb.invoke(loc, 0, 0, 0)
31
+ invoked.should be_false
32
+ cb.instance_variable_set(:@orig_x, nil) # XXX ugly hack need to reset orig_x so that new 'old coordinates' get accepted
33
+
34
+ cb.invoke(loc, -5, 0, 0)
35
+ invoked.should be_false
36
+ cb.instance_variable_set(:@orig_x, nil)
37
+
38
+ cb.invoke(loc, 0.5, 1.2, 0.23)
39
+ invoked.should be_false
40
+ cb.instance_variable_set(:@orig_x, nil)
41
+
42
+ cb.invoke(loc, 0, 10, 0)
43
+ invoked.should be_true
44
+ invoked = false
45
+ cb.instance_variable_set(:@orig_x, nil)
46
+
47
+ cb.invoke(loc, 0, 10, -10)
48
+ invoked.should be_true
49
+ invoked = false
50
+ cb.instance_variable_set(:@orig_x, nil)
51
+
52
+ cb.invoke(loc, -10, 0, 0)
53
+ invoked.should be_true
54
+ invoked = false
55
+ cb.instance_variable_set(:@orig_x, nil)
56
+
57
+ cb.invoke(loc, 10, 0, 0)
58
+ invoked.should be_true
59
+ invoked = false
60
+ cb.instance_variable_set(:@orig_x, nil)
61
+
62
+ loc.x = -5 ; loc.y = 5 ; loc.z = 12
63
+ cb.invoke(loc, 0, 0, 0)
64
+ invoked.should be_true
65
+ end
66
+
67
+ it "should invoke handler only when location moves min axis distance" do
68
+ invoked = false
69
+ loc = Location.new :x => 0, :y => 0, :z => 0
70
+ cb = Motel::Callbacks::Movement.new :min_y => 10,
71
+ :handler => lambda { |loc, d, dx, dy, dz|
72
+ invoked = true
73
+ }
74
+ cb.invoke(loc, 0, 0, 0)
75
+ invoked.should be_false
76
+ cb.instance_variable_set(:@orig_x, nil) # XXX ugly hack need to reset orig_x so that new 'old coordinates' get accepted
77
+
78
+ cb.invoke(loc, 0, -6, 0)
79
+ invoked.should be_false
80
+ cb.instance_variable_set(:@orig_x, nil)
81
+
82
+ cb.invoke(loc, 10, 0, 0)
83
+ invoked.should be_false
84
+ cb.instance_variable_set(:@orig_x, nil)
85
+
86
+ cb.invoke(loc, 10, -5, 20)
87
+ invoked.should be_false
88
+ cb.instance_variable_set(:@orig_x, nil)
89
+
90
+ cb.invoke(loc, 0, -10, 0)
91
+ invoked.should be_true
92
+ invoked = false
93
+ cb.instance_variable_set(:@orig_x, nil)
94
+
95
+ cb.invoke(loc, 0, 10, 0)
96
+ invoked.should be_true
97
+ invoked = false
98
+ end
99
+ end
100
+
101
+ describe Motel::Callbacks::Proximity do
102
+ it "should only invoke handler if locations share coordinates by default" do
103
+ invoked = false
104
+ loc1 = Location.new :x => 0, :y => 0, :z => 0
105
+ loc2 = Location.new :x => 10, :y => 0, :z => 0
106
+
107
+ callback = Motel::Callbacks::Proximity.new :to_location => loc1, :handler => lambda { |loc1, loc2|
108
+ invoked = true
109
+ }
110
+ callback.invoke(loc2)
111
+ invoked.should be_false
112
+
113
+ loc2.x = 0
114
+ callback.invoke(loc2)
115
+ invoked.should be_true
116
+ end
117
+
118
+ it "should invoke handler only when locations are within max distance of each other" do
119
+ invoked = false
120
+ loc1 = Location.new :x => 0, :y => 0, :z => 0
121
+ loc2 = Location.new :x => 20, :y => 0, :z => 0
122
+ cb = Motel::Callbacks::Proximity.new :to_location => loc2, :max_distance => 10,
123
+ :handler => lambda { |loc1, loc2|
124
+ invoked = true
125
+ }
126
+ cb.invoke(loc1)
127
+ invoked.should be_false
128
+
129
+ loc1.y = 1.5
130
+ loc1.z = 0.75
131
+ loc2.x = 2.5
132
+ loc2.y = 2.5
133
+ cb = Motel::Callbacks::Proximity.new :to_location => loc2, :max_distance => 10,
134
+ :handler => lambda { |loc1, loc2|
135
+ invoked = true
136
+ }
137
+ cb.invoke(loc1)
138
+ invoked.should be_true
139
+ end
140
+
141
+ it "should invoke handler only when locations are within max axis distance of each other" do
142
+ invoked = false
143
+ loc1 = Location.new :x => 0, :y => 0, :z => 0
144
+ loc2 = Location.new :x => 0, :y => 0, :z => 20
145
+ cb = Motel::Callbacks::Proximity.new :max_z => 10, :to_location => loc1,
146
+ :handler => lambda { |loc1, loc2|
147
+ invoked = true
148
+ }
149
+ cb.invoke(loc2)
150
+ invoked.should be_false
151
+
152
+ loc2.z = 7
153
+ cb.invoke(loc2)
154
+ invoked.should be_true
155
+ end
156
+ end
@@ -16,11 +16,11 @@ describe "Motel::dsl" do
16
16
 
17
17
  # use dsl to connect to server and issue a few requests
18
18
  connect :schema_file => SIMRPC_SPEC do |client|
19
- location_id = 100
20
- client.create_location(location_id).should be(true)
21
- loc = client.get_location(location_id)
22
- loc.should_not be_nil
23
- loc.id.should be(location_id)
19
+ loc = Location.new :id => 500
20
+ client.create_location(loc).id.should == loc.id
21
+ loc2 = client.get_location(loc.id)
22
+ loc2.should_not be_nil
23
+ loc2.id.should be(loc.id)
24
24
  end
25
25
  end
26
26
 
@@ -25,13 +25,6 @@ describe Location do
25
25
  location.movement_strategy.should == ms
26
26
  end
27
27
 
28
- it "should default to origin coordinates" do
29
- loc = Location.new
30
- loc.x.should == 0
31
- loc.y.should == 0
32
- loc.z.should == 0
33
- end
34
-
35
28
  it "should be updatable given another location to copy" do
36
29
  p1 = Location.new
37
30
  p2 = Location.new
@@ -40,8 +33,8 @@ describe Location do
40
33
  new = Location.new :x => 5, :movement_strategy => 'foomoney', :parent_id => 10, :parent => p2
41
34
  orig.update(new)
42
35
  orig.x.should be(5)
43
- orig.y.should be(0)
44
- orig.y.should be(0)
36
+ orig.y.should == 2
37
+ orig.z.should be_nil
45
38
  orig.movement_strategy.should == "foomoney"
46
39
  orig.parent_id.should be(10)
47
40
  orig.parent.should be(p2)
@@ -52,7 +45,13 @@ describe Location do
52
45
  orig.y.should be(6)
53
46
  end
54
47
 
55
- it "retrieve root location" do
48
+ it "should retrieve a location's coordinates" do
49
+ loc = Location.new :x => 10, :y => 20, :z => -30
50
+ coords = loc.coordinates
51
+ coords.should == [10, 20, -30]
52
+ end
53
+
54
+ it "should retrieve root location" do
56
55
  ggp = Location.new
57
56
  gp = Location.new :parent => ggp
58
57
  p = Location.new :parent => gp
@@ -106,4 +105,10 @@ describe Location do
106
105
  child.total_z.should == 42 - 93
107
106
  end
108
107
 
108
+ it "should calculate the distance between two locations" do
109
+ loc1 = Location.new :x => 10, :y => 10, :z => 10
110
+ loc2 = Location.new :x => -5, :y => -7, :z => 30
111
+ ((loc1 - loc2 - 30.2324329156619) < 0.000001).should be_true
112
+ end
113
+
109
114
  end
@@ -8,29 +8,29 @@ require File.dirname(__FILE__) + '/spec_helper'
8
8
  describe Runner do
9
9
 
10
10
  it "manage array of locations to be run" do
11
- loc = Location.new
12
- Runner.instance.locations.clear
11
+ loc = Location.new :id => 50
12
+ Runner.instance.clear
13
13
  Runner.instance.locations.should == []
14
14
  Runner.instance.run loc
15
15
  Runner.instance.locations.should == [loc]
16
- Runner.instance.locations.clear
16
+ Runner.instance.clear
17
17
  end
18
18
 
19
19
  it "should run managed locations" do
20
- loc1 = Location.new :movement_strategy => TestMovementStrategy.new
21
- loc2 = Location.new :movement_strategy => TestMovementStrategy.new
22
- Runner.instance.locations.clear
20
+ loc1 = Location.new :id => 100, :movement_strategy => TestMovementStrategy.new
21
+ loc2 = Location.new :id => 200, :movement_strategy => TestMovementStrategy.new
22
+ Runner.instance.clear
23
23
  Runner.instance.run loc1
24
24
  Runner.instance.run loc2
25
25
  Runner.instance.locations.size.should == 2
26
26
 
27
27
  Runner.instance.start :async => true, :num_threads => 10
28
- Runner.instance.thread_pool.should_not == nil
29
- Runner.instance.thread_pool.max_size.should == 10
28
+ #Runner.instance.thread_pool.should_not == nil
29
+ #Runner.instance.thread_pool.max_size.should == 10
30
30
  Runner.instance.terminate.should == false
31
31
 
32
- # TODO should we sleep here for a fixed time, to allow
33
- # move to be called multiple times ?
32
+ # sleep here to allow move to be called
33
+ sleep 2
34
34
 
35
35
  Runner.instance.stop
36
36
  Runner.instance.terminate.should == true
@@ -42,4 +42,18 @@ describe Runner do
42
42
  loc2.movement_strategy.times_moved.should be > 0
43
43
  end
44
44
 
45
+ it "should set id on managed location to be run if missing" do
46
+ loc1 = Location.new :id => 1, :movement_strategy => TestMovementStrategy.new
47
+ loc3 = Location.new :id => 3, :movement_strategy => TestMovementStrategy.new
48
+ Runner.instance.clear
49
+ Runner.instance.run loc1
50
+ Runner.instance.run loc3
51
+ Runner.instance.locations.size.should == 2
52
+
53
+ loc2 = Location.new :movement_strategy => TestMovementStrategy.new
54
+ loc2a = Runner.instance.run loc2
55
+ loc2.id.should == 2
56
+ Runner.instance.locations.size.should == 3
57
+ end
58
+
45
59
  end
@@ -3,7 +3,7 @@
3
3
  # Copyright (C) 2010 Mohammed Morsi <movitto@yahoo.com>
4
4
  # Licensed under the AGPLv3+ http://www.gnu.org/licenses/agpl.txt
5
5
 
6
- dir = File.dirname(__FILE__)
6
+ dir = File.dirname(__FILE__)
7
7
  require dir + '/spec_helper'
8
8
 
9
9
  describe "Motel::Simrpc" do
@@ -20,63 +20,184 @@ describe "Motel::Simrpc" do
20
20
 
21
21
  it "should permit location creation and retrieval" do
22
22
  locations = Runner.instance.locations.size
23
- location_id = 10
24
- @client.create_location(location_id).should be(true)
23
+ clocation = Location.new :id => 10, :x => 100, :y => -200, :z => 500
24
+ tloc = @client.create_location(clocation)
25
+ tloc.id.should == clocation.id
26
+ tloc.x.should == 100
27
+ tloc.y.should == -200
28
+ tloc.z.should == 500
25
29
  Runner.instance.locations.size.should == locations + 1
26
30
 
27
- loc = @client.get_location(location_id)
31
+ # FIXME test setting / retrieving movement strategy
32
+
33
+ loc = @client.get_location(clocation.id)
34
+ loc.should_not be_nil
35
+ loc.id.should be(clocation.id)
36
+ loc.x.should == 100
37
+ loc.y.should == -200
38
+ loc.z.should == 500
39
+ end
40
+
41
+ it "should autogenerate location id and coordinates on creation if not specified" do
42
+ Runner.instance.clear
43
+ loc1 = Location.new :id => 1
44
+ loc2 = Location.new :id => 2
45
+ loc4 = Location.new :id => 4
46
+ @client.create_location(loc1)
47
+ @client.create_location(loc2)
48
+ @client.create_location(loc4)
49
+
50
+ loc3 = @client.create_location(Location.new)
51
+ loc3.id.should == 3
52
+ loc3.x.should == 0
53
+ loc3.y.should == 0
54
+ loc3.z.should == 0
55
+
56
+ Runner.instance.locations.size.should == 4
57
+
58
+ loc3a = @client.get_location(3)
59
+ loc3a.should_not be_nil
60
+ end
61
+
62
+ it "should autogenerate location if none is specified on creation" do
63
+ Runner.instance.clear
64
+ loc = @client.create_location
65
+ loc.id.should == 1
66
+ loc.x.should == 0
67
+ loc.y.should == 0
68
+ loc.z.should == 0
69
+
70
+ Runner.instance.locations.size.should == 1
71
+
72
+ loc = @client.get_location(1)
28
73
  loc.should_not be_nil
29
- loc.id.should be(location_id)
30
74
  end
31
75
 
32
76
  it "should permit updating a location" do
33
- location_id = 20
34
- @client.create_location(location_id).should be(true)
35
- @client.update_location(Location.new(:id => location_id, :x => 150, :y => 300, :z => -600)).should be(true)
77
+ clocation = Location.new :id => 20
78
+ @client.create_location(clocation).id.should == clocation.id
79
+ @client.update_location(Location.new(:id => clocation.id, :x => 150, :y => 300, :z => -600)).should be(true)
36
80
 
37
- loc = @client.get_location(location_id)
81
+ loc = @client.get_location(clocation.id)
38
82
  loc.should_not be_nil
39
83
  loc.x.should be(150)
40
84
  loc.y.should be(300)
41
85
  loc.z.should be(-600)
42
86
 
43
- loc = @client.request :get_location, location_id
87
+ loc = @client.request :get_location, clocation.id
44
88
  loc.should_not be_nil
45
89
  loc.x.should be(150)
46
90
  end
47
91
 
48
- it "should permit receiving location updates" do
92
+ #it "should invoke callbacks when updating a location" do
93
+ # Runner.instance.clear
94
+ # clocation = Location.new :id => 250
95
+ # @client.create_location(clocation).id.should == clocation.id
96
+
97
+ # # handle and subscribe to location movement
98
+ # times_moved = 0
99
+ # @client.on_location_moved = lambda { |location, d, dx, dy, dz|
100
+ # times_moved += 1
101
+ # }
102
+ # @client.subscribe_to_location_movement(clocation.id).should be(true)
103
+
104
+ # res = @client.update_location(Location.new(:id => clocation.id, :x => 150, :y => 300, :z => -600))
105
+ # res.should be(true)
106
+
107
+ # loc = @client.get_location(clocation.id)
108
+ # loc.should_not be_nil
109
+ # loc.x.should be(150)
110
+ # loc.y.should be(300)
111
+ # loc.z.should be(-600)
112
+ # times_moved.should be(1)
113
+ #end
114
+
115
+ it "should permit receiving location movement updates" do
49
116
  # start the runner here, to actual move location / process callbacks
117
+ Runner.instance.clear
50
118
  Runner.instance.start :async => true
51
119
 
52
120
  # create the location
53
- location_id = 30
54
- @client.create_location(location_id).should be(true)
121
+ clocation = Location.new :id => 30
122
+ @client.create_location(clocation).id.should == clocation.id
55
123
 
56
124
  ## set a linear movement strategy
57
125
  location = Location.new
58
- location.id = location_id
126
+ location.id = clocation.id
59
127
  location.movement_strategy = Linear.new(:step_delay => 1,
60
- :speed => 15,
128
+ :speed => 15,
61
129
  :direction_vector_x => 1,
62
130
  :direction_vector_y => 0,
63
131
  :direction_vector_z => 0)
64
132
  @client.update_location(location).should be(true)
65
133
 
66
- times_moved = 0
134
+ times_moved = 0
67
135
 
68
136
  # handle location_moved method
69
- @client.on_location_received = lambda { |location|
137
+ @client.on_location_moved = lambda { |location, d, dx, dy, dz|
70
138
  times_moved += 1
71
- }
139
+ }
140
+
141
+ ## subscribe to updates
142
+ @client.subscribe_to_location_movement(clocation.id).should be(true)
143
+ Runner.instance.locations.first.movement_callbacks.size.should == 1
144
+ Runner.instance.locations.first.movement_callbacks[0].class.should == Callbacks::Movement
145
+
146
+ ## delay briefly allowing for updates
147
+ sleep 2
148
+
149
+ times_moved.should be > 0
150
+
151
+ # stop the runner
152
+ Runner.instance.stop
153
+ end
154
+
155
+ it "should permit receiving location proximity events" do
156
+ # start the runner here, to actual move location / process callbacks
157
+ Runner.instance.clear
158
+ Runner.instance.start :async => true
159
+
160
+ # create the locations
161
+ clocation1 = Location.new :id => 300
162
+ clocation2 = Location.new :id => 600
163
+ @client.create_location(clocation1).id.should == clocation1.id
164
+ @client.create_location(clocation2).id.should == clocation2.id
165
+
166
+ # update
167
+ location1 = Location.new :id => clocation1.id, :x => 0, :y => 0, :z => 0
168
+ location2 = Location.new :id => clocation2.id, :x => 0, :y => 0, :z => 100
169
+ @client.update_location(location1).should be(true)
170
+ @client.update_location(location2).should be(true)
171
+
172
+ proximity_triggered = false
173
+
174
+ # handle location_moved method
175
+ @client.on_locations_proximity = lambda { |loc1, loc2|
176
+ location1.id.should == clocation1.id
177
+ location2.id.should == clocation2.id
178
+ proximity_triggered = true
179
+ }
72
180
 
73
181
  ## subscribe to updates
74
- @client.subscribe_to_location(location_id).should be(true)
182
+ @client.subscribe_to_locations_proximity(clocation1.id, clocation2.id, "proximity", 10).should be(true)
183
+ Runner.instance.locations.first.proximity_callbacks.size.should == 1
184
+ Runner.instance.locations.first.proximity_callbacks[0].class.should == Callbacks::Proximity
185
+
186
+ # FIXME test all proximity events: proximity, entered_proximity, left_proximity
187
+
188
+ ## delay briefly allowing for updates
189
+ sleep 2
190
+
191
+ proximity_triggered.should be_false
192
+
193
+ # update location to satisfy proximity criteria
194
+ location2.z = 5
195
+ @client.update_location(location2).should be(true)
75
196
 
76
197
  ## delay briefly allowing for updates
77
- sleep 5
198
+ sleep 2
78
199
 
79
- times_moved.should be > 0
200
+ proximity_triggered.should be_true
80
201
 
81
202
  # stop the runner
82
203
  Runner.instance.stop