motel 0.3 → 0.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -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