sbsm 1.0.0

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.
Files changed (50) hide show
  1. data/COPYING +515 -0
  2. data/History.txt +5 -0
  3. data/Manifest.txt +49 -0
  4. data/README.txt +41 -0
  5. data/Rakefile +28 -0
  6. data/data/_flavored_uri.grammar +24 -0
  7. data/data/_uri.grammar +22 -0
  8. data/data/_zone_uri.grammar +24 -0
  9. data/data/flavored_uri.grammar +24 -0
  10. data/data/uri.grammar +22 -0
  11. data/data/zone_uri.grammar +24 -0
  12. data/install.rb +1098 -0
  13. data/lib/cgi/drbsession.rb +37 -0
  14. data/lib/sbsm/cgi.rb +79 -0
  15. data/lib/sbsm/drb.rb +19 -0
  16. data/lib/sbsm/drbserver.rb +162 -0
  17. data/lib/sbsm/exception.rb +28 -0
  18. data/lib/sbsm/flavored_uri_parser.rb +47 -0
  19. data/lib/sbsm/index.rb +66 -0
  20. data/lib/sbsm/lookandfeel.rb +176 -0
  21. data/lib/sbsm/lookandfeelfactory.rb +50 -0
  22. data/lib/sbsm/lookandfeelwrapper.rb +109 -0
  23. data/lib/sbsm/redefine_19_cookie.rb +4 -0
  24. data/lib/sbsm/redirector.rb +37 -0
  25. data/lib/sbsm/request.rb +162 -0
  26. data/lib/sbsm/session.rb +542 -0
  27. data/lib/sbsm/state.rb +301 -0
  28. data/lib/sbsm/time.rb +29 -0
  29. data/lib/sbsm/trans_handler.rb +119 -0
  30. data/lib/sbsm/turing.rb +25 -0
  31. data/lib/sbsm/uri_parser.rb +45 -0
  32. data/lib/sbsm/user.rb +47 -0
  33. data/lib/sbsm/validator.rb +256 -0
  34. data/lib/sbsm/viralstate.rb +47 -0
  35. data/lib/sbsm/zone_uri_parser.rb +48 -0
  36. data/test/data/dos_file.txt +2 -0
  37. data/test/data/lnf_file.txt +2 -0
  38. data/test/data/mac_file.txt +1 -0
  39. data/test/stub/cgi.rb +35 -0
  40. data/test/suite.rb +29 -0
  41. data/test/test_drbserver.rb +83 -0
  42. data/test/test_index.rb +90 -0
  43. data/test/test_lookandfeel.rb +230 -0
  44. data/test/test_session.rb +372 -0
  45. data/test/test_state.rb +176 -0
  46. data/test/test_trans_handler.rb +447 -0
  47. data/test/test_user.rb +44 -0
  48. data/test/test_validator.rb +126 -0
  49. data/usage-en.txt +112 -0
  50. metadata +142 -0
@@ -0,0 +1,372 @@
1
+ #!/usr/bin/env ruby
2
+ #
3
+ # State Based Session Management
4
+ # Copyright (C) 2004 Hannes Wyss
5
+ #
6
+ # This library is free software; you can redistribute it and/or
7
+ # modify it under the terms of the GNU Lesser General Public
8
+ # License as published by the Free Software Foundation; either
9
+ # version 2.1 of the License, or (at your option) any later version.
10
+ #
11
+ # This library is distributed in the hope that it will be useful,
12
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
13
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14
+ # Lesser General Public License for more details.
15
+ #
16
+ # You should have received a copy of the GNU Lesser General Public
17
+ # License along with this library; if not, write to the Free Software
18
+ # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19
+ #
20
+ # ywesee - intellectual capital connected, Winterthurerstrasse 52, CH-8006 Z�rich, Switzerland
21
+ # hwyss@ywesee.com
22
+ #
23
+ # TestSession -- sbsm -- 22.10.2002 -- hwyss@ywesee.com
24
+
25
+ require 'test/unit'
26
+ require 'sbsm/session'
27
+ #require 'htmlgrid/component'
28
+
29
+ class StubSessionUnknownUser
30
+ end
31
+ class StubSessionApp
32
+ def unknown_user
33
+ StubSessionUnknownUser.new
34
+ end
35
+ def login(session)
36
+ false
37
+ end
38
+ def async(&block)
39
+ block.call
40
+ end
41
+ end
42
+ class StubSessionValidator
43
+ def reset_errors; end
44
+ def validate(key, value, mandatory=false)
45
+ value
46
+ end
47
+ def valid_values(key)
48
+ if(key=='foo')
49
+ ['foo', 'bar']
50
+ end
51
+ end
52
+ def error?
53
+ false
54
+ end
55
+ end
56
+ class StubSessionRequest < Hash
57
+ attr_accessor :unparsed_uri
58
+ def params
59
+ self
60
+ end
61
+ def cookies
62
+ {}
63
+ end
64
+ def request_method
65
+ 'GET'
66
+ end
67
+ end
68
+ class StubSessionView
69
+ def http_headers
70
+ {
71
+ "foo" => "bar"
72
+ }
73
+ end
74
+ def initialize(foo, bar)
75
+ end
76
+ def to_html(context)
77
+ '0123456789' * 3
78
+ end
79
+ end
80
+ class StubSessionBarState < SBSM::State
81
+ EVENT_MAP = {
82
+ :foobar => StubSessionBarState,
83
+ }
84
+ end
85
+ class StubSessionBarfoosState < SBSM::State
86
+ DIRECT_EVENT = :barfoos
87
+ end
88
+ class StubSessionFooState < SBSM::State
89
+ EVENT_MAP = {
90
+ :bar => StubSessionBarState
91
+ }
92
+ end
93
+ class StubSessionState < SBSM::State
94
+ VIEW = StubSessionView
95
+ attr_accessor :volatile
96
+ def foo
97
+ @foo ||= StubSessionFooState.new(@session,@model)
98
+ end
99
+ end
100
+ class StubVolatileState < SBSM::State
101
+ VOLATILE = true
102
+ end
103
+ class Session < SBSM::Session
104
+ DEFAULT_STATE = StubSessionState
105
+ DRB_LOAD_LIMIT = 10
106
+ CAP_MAX_THRESHOLD = 3
107
+ MAX_STATES = 3
108
+ DEFAULT_FLAVOR = 'gcc'
109
+ attr_accessor :user, :state
110
+ attr_accessor :attended_states, :cached_states
111
+ attr_writer :lookandfeel, :persistent_user_input
112
+ attr_writer :active_state
113
+ public :active_state
114
+ end
115
+ class StubSessionSession < SBSM::Session
116
+ attr_accessor :lookandfeel
117
+ attr_accessor :persistent_user_input
118
+ DEFAULT_FLAVOR = 'gcc'
119
+ LF_FACTORY = {
120
+ 'gcc' => 'ccg',
121
+ 'sbb' => 'bbs',
122
+ }
123
+ def initialize(*args)
124
+ super
125
+ persistent_user_input = {}
126
+ end
127
+ def persistent_user_input(key)
128
+ super
129
+ end
130
+ end
131
+
132
+ class TestSession < Test::Unit::TestCase
133
+ def setup
134
+ @session = Session.new("test", StubSessionApp.new, StubSessionValidator.new)
135
+ @request = StubSessionRequest.new
136
+ @state = StubSessionState.new(@session, nil)
137
+ end
138
+ def test_attended_states_store
139
+ @session.process(@request)
140
+ state = @session.state
141
+ expected = {
142
+ state.object_id => state
143
+ }
144
+ #puts 'test'
145
+ #puts @state
146
+ assert_equal(expected, @session.attended_states)
147
+ end
148
+ def test_attended_states_cap_max
149
+ req1 = StubSessionRequest.new
150
+ @session.process(req1)
151
+ state1 = @session.state
152
+ req2 = StubSessionRequest.new
153
+ req2["event"] = "foo"
154
+ @session.process(req2)
155
+ state2 = @session.state
156
+ assert_not_equal(state1, state2)
157
+ req3 = StubSessionRequest.new
158
+ req3["event"] = :bar
159
+ @session.process(req3)
160
+ state3 = @session.state
161
+ assert_not_equal(state1, state3)
162
+ assert_not_equal(state2, state3)
163
+ attended = {
164
+ state1.object_id => state1,
165
+ state2.object_id => state2,
166
+ state3.object_id => state3,
167
+ }
168
+ assert_equal(attended, @session.attended_states)
169
+ req4 = StubSessionRequest.new
170
+ req4["event"] = :foobar
171
+ @session.process(req4)
172
+ @session.cap_max_states
173
+ state4 = @session.state
174
+ assert_not_equal(state1, state4)
175
+ assert_not_equal(state2, state4)
176
+ assert_not_equal(state3, state4)
177
+ attended = {
178
+ state2.object_id => state2,
179
+ state3.object_id => state3,
180
+ state4.object_id => state4,
181
+ }
182
+ assert_equal(attended, @session.attended_states)
183
+ end
184
+ def test_active_state1
185
+ # Szenarien
186
+ # - Keine State-Information in User-Input
187
+ # - Unbekannter State in User-Input
188
+ # - Bekannter State in User-Input
189
+
190
+ state = StubSessionState.new(@session, nil)
191
+ @session.attended_states = {
192
+ state.object_id => state,
193
+ }
194
+ @session.active_state = @state
195
+ assert_equal(@state, @session.active_state)
196
+ end
197
+ def test_active_state2
198
+ # Szenarien
199
+ # - Keine State-Information in User-Input
200
+ # - Unbekannter State in User-Input
201
+ # - Bekannter State in User-Input
202
+
203
+ state = StubSessionState.new(@session, nil)
204
+ @session.attended_states = {
205
+ state.object_id => state,
206
+ }
207
+ @session.active_state = @state
208
+ @request.store('state_id', state.object_id.next)
209
+ @session.process(@request)
210
+ assert_equal(@state, @session.active_state)
211
+ end
212
+ def test_active_state3
213
+ # Szenarien
214
+ # - Keine State-Information in User-Input
215
+ # - Unbekannter State in User-Input
216
+ # - Bekannter State in User-Input
217
+
218
+ state = StubSessionState.new(@session, nil)
219
+ @session.attended_states = {
220
+ state.object_id => state,
221
+ }
222
+ @session.state = @state
223
+ @request.store('state_id', state.object_id)
224
+ @session.process(@request)
225
+ assert_equal(state, @session.active_state)
226
+ end
227
+ def test_volatile_state
228
+ state = StubSessionState.new(@session, nil)
229
+ volatile = StubVolatileState.new(@session, nil)
230
+ state.volatile = volatile
231
+ @session.active_state = state
232
+ @session.state = state
233
+ @request.store('event', :volatile)
234
+ newstate = @session.process(@request)
235
+ assert_equal(:volatile, @session.event)
236
+ assert_equal(volatile, @session.state)
237
+ assert_equal(state, @session.active_state)
238
+ @request.store('event', :foo)
239
+ newstate = @session.process(@request)
240
+ assert_equal(state.foo, @session.state)
241
+ assert_equal(state.foo, @session.active_state)
242
+ end
243
+ def test_cgi_compatible
244
+ assert_respond_to(@session, :restore)
245
+ assert_respond_to(@session, :update)
246
+ assert_respond_to(@session, :close)
247
+ assert_respond_to(@session, :delete)
248
+ end
249
+ def test_restore
250
+ assert_instance_of(Session, @session.restore[:proxy])
251
+ end
252
+ def test_user_input_no_request
253
+ assert_nil(@session.user_input(:no_input))
254
+ end
255
+ def test_user_input_nil
256
+ @session.process(@request)
257
+ assert_nil(@session.user_input(:no_input))
258
+ end
259
+ def test_user_input
260
+ @request["foo"] = "bar"
261
+ @request["baz"] = "zuv"
262
+ @session.process(@request)
263
+ assert_equal("bar", @session.user_input(:foo))
264
+ assert_equal("zuv", @session.user_input(:baz))
265
+ assert_equal("zuv", @session.user_input(:baz))
266
+ result = @session.user_input(:foo, :baz)
267
+ expected = {
268
+ :foo => 'bar',
269
+ :baz => 'zuv',
270
+ }
271
+ assert_equal(expected, result)
272
+ end
273
+ def test_user_input_hash
274
+ @request["hash[1]"] = "4"
275
+ @request["hash[2]"] = "5"
276
+ @request["hash[3]"] = "6"
277
+ @session.process(@request)
278
+ hash = @session.user_input(:hash)
279
+ assert_equal(Hash, hash.class)
280
+ assert_equal(3, hash.size)
281
+ assert_equal("4", hash["1"])
282
+ assert_equal("5", hash["2"])
283
+ assert_equal("6", hash["3"])
284
+ end
285
+ def test_http_headers
286
+ expected = {
287
+ "foo" => "bar"
288
+ }
289
+ assert_equal(expected, @session.http_headers)
290
+ end
291
+ def test_http_protocol
292
+ assert_equal("http", @session.http_protocol)
293
+ end
294
+ def test_login_fail_keep_user
295
+ @session.login
296
+ assert_equal(StubSessionUnknownUser, @session.user.class)
297
+ end
298
+ def test_logged_in
299
+ assert_equal(StubSessionUnknownUser, @session.user.class)
300
+ assert_equal(false, @session.logged_in?)
301
+ end
302
+ def test_valid_values
303
+ assert_equal(['foo', 'bar'], @session.valid_values('foo'))
304
+ assert_equal([], @session.valid_values('oof'))
305
+ end
306
+ def test_persistent_user_input
307
+ @request["baz"] = "zuv"
308
+ @session.process(@request)
309
+ assert_equal("zuv", @session.persistent_user_input(:baz))
310
+ @session.process(StubSessionRequest.new)
311
+ assert_equal("zuv", @session.persistent_user_input(:baz))
312
+ @request["baz"] = "bla"
313
+ @session.process(@request)
314
+ assert_equal("bla", @session.persistent_user_input(:baz))
315
+ end
316
+ def test_process
317
+ state = StubSessionState.new(@session, nil)
318
+ @session.attended_states = {
319
+ state.object_id => state,
320
+ }
321
+ @session.state = @state
322
+ expected = state.foo
323
+ @request.store('state_id', state.object_id)
324
+ @request.store('event', :foo)
325
+ @session.process(@request)
326
+ assert_equal(expected, @session.state)
327
+ assert_equal(expected, @session.attended_states[expected.object_id])
328
+ end
329
+ def test_logout
330
+ state = StubSessionBarState.new(@session, nil)
331
+ @session.attended_states.store(state.object_id, state)
332
+ assert_equal(state, @session.attended_states[state.object_id])
333
+ @session.logout
334
+ assert_equal(1, @session.attended_states.size)
335
+ end
336
+ def test_lookandfeel
337
+ @session.lookandfeel=nil
338
+ @session.persistent_user_input = {
339
+ :flavor => 'some',
340
+ }
341
+ lnf = @session.lookandfeel
342
+ assert_equal('gcc', @session.flavor)
343
+ assert_equal('gcc', lnf.flavor)
344
+ assert_instance_of(SBSM::Lookandfeel, lnf)
345
+ lnf2 = @session.lookandfeel
346
+ assert_equal(lnf, lnf2)
347
+ @session.persistent_user_input = {
348
+ :flavor => 'other',
349
+ }
350
+ lnf3 = @session.lookandfeel
351
+ assert_instance_of(SBSM::Lookandfeel, lnf)
352
+ assert_equal(lnf, lnf3) ## flavor does not change!
353
+ end
354
+ def test_lookandfeel2
355
+ session = StubSessionSession.new("test", StubSessionApp.new, StubSessionValidator.new)
356
+ session.lookandfeel=nil
357
+ session.persistent_user_input = {
358
+ :flavor => 'gcc',
359
+ }
360
+ lnf = session.lookandfeel
361
+ assert_equal('gcc', session.flavor)
362
+ end
363
+ def test_lookandfeel3
364
+ session = StubSessionSession.new("test", StubSessionApp.new, StubSessionValidator.new)
365
+ session.lookandfeel=nil
366
+ lnf2 = session.lookandfeel
367
+ session.persistent_user_input = {
368
+ :flavor => 'other',
369
+ }
370
+ assert_equal('gcc', session.flavor)
371
+ end
372
+ end
@@ -0,0 +1,176 @@
1
+ #!/usr/bin/env ruby
2
+ #
3
+ # State Based Session Management
4
+ # Copyright (C) 2004 Hannes Wyss
5
+ #
6
+ # This library is free software; you can redistribute it and/or
7
+ # modify it under the terms of the GNU Lesser General Public
8
+ # License as published by the Free Software Foundation; either
9
+ # version 2.1 of the License, or (at your option) any later version.
10
+ #
11
+ # This library is distributed in the hope that it will be useful,
12
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
13
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14
+ # Lesser General Public License for more details.
15
+ #
16
+ # You should have received a copy of the GNU Lesser General Public
17
+ # License along with this library; if not, write to the Free Software
18
+ # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19
+ #
20
+ # ywesee - intellectual capital connected, Winterthurerstrasse 52, CH-8006 Z�rich, Switzerland
21
+ # hwyss@ywesee.com
22
+ #
23
+ # TestState -- oddb -- 20.11.2002 -- hwyss@ywesee.com
24
+
25
+ $: << File.dirname(__FILE__)
26
+ $: << File.expand_path("../lib", File.dirname(__FILE__))
27
+
28
+ require 'test/unit'
29
+ require 'sbsm/state'
30
+
31
+ class StubStateState1
32
+ attr_accessor :previous
33
+ def initialize(*args)
34
+ end
35
+ def reset_view
36
+ end
37
+ end
38
+ class StubStateState2
39
+ attr_accessor :previous
40
+ def initialize(*args)
41
+ end
42
+ def reset_view
43
+ end
44
+ end
45
+ class StubStateState3
46
+ attr_accessor :previous
47
+ def initialize(*args)
48
+ end
49
+ def reset_view
50
+ end
51
+ end
52
+ class StubStateView
53
+ attr_reader :model, :session
54
+ def initialize(model, session)
55
+ @model, @session = model, session
56
+ end
57
+ end
58
+ class StubStateUserView < StubStateView
59
+ end
60
+ class StubStateUser
61
+ end
62
+ class StubStateSession
63
+ def user
64
+ :test_default
65
+ end
66
+ end
67
+ class StubStateUserSession
68
+ def user
69
+ StubStateUser.new
70
+ end
71
+ end
72
+ class State < SBSM::State
73
+ attr_reader :init_called
74
+ attr_writer :errors, :session, :filter, :warnings
75
+ DIRECT_EVENT = :foo
76
+ EVENT_MAP = {
77
+ :bar => StubStateState1
78
+ }
79
+ GLOBAL_MAP = {
80
+ :baz => StubStateState2
81
+ }
82
+ VIEW = StubStateView
83
+ def himself
84
+ self
85
+ end
86
+ def buc
87
+ StubStateState3.new
88
+ end
89
+ def init
90
+ @init_called = true
91
+ end
92
+ end
93
+ class UserState < State
94
+ VIEW = {
95
+ :default => StubStateView,
96
+ StubStateUser => StubStateUserView,
97
+ }
98
+ end
99
+
100
+ class TestState < Test::Unit::TestCase
101
+ def setup
102
+ @state = State.new(nil, nil)
103
+ end
104
+ def test_direct_event
105
+ assert_equal(:foo, State.direct_event)
106
+ end
107
+ def test_trigger_default
108
+ assert_equal(@state, @state.trigger(:foo))
109
+ end
110
+ def test_trigger_event
111
+ assert_equal(StubStateState1, @state.trigger(:bar).class)
112
+ end
113
+ def test_trigger_global
114
+ assert_equal(StubStateState2, @state.trigger(:baz).class)
115
+ end
116
+ def test_trigger_method
117
+ assert_equal(StubStateState3, @state.trigger(:buc).class)
118
+ end
119
+ def test_errors
120
+ assert_equal(false, @state.error?)
121
+ @state.errors = {:de => 'ein Error'}
122
+ assert_equal(true, @state.error?)
123
+ assert_equal('ein Error', @state.error(:de))
124
+ new_state = @state.trigger(:himself)
125
+ assert_equal(@state, new_state)
126
+ assert_equal(false, @state.error?)
127
+
128
+ end
129
+ def test_default
130
+ assert_respond_to(@state, :default)
131
+ end
132
+ def test_warnings
133
+ assert_equal(false, @state.warning?)
134
+ warning = SBSM::Warning.new('eine Warnung', :foo, '')
135
+ @state.warnings = [warning]
136
+ assert_equal(true, @state.warning?)
137
+ assert_equal(warning, @state.warning(:foo))
138
+ new_state = @state.trigger(:himself)
139
+ assert_equal(@state, new_state)
140
+ assert_equal(false, @state.warning?)
141
+ @state.add_warning('A Message', 'key', 'A Value')
142
+ assert_equal(true, @state.warning?)
143
+ assert_equal(1, @state.warnings.size)
144
+ warning = @state.warnings.first
145
+ assert_equal(warning, @state.warning(:key))
146
+ assert_instance_of(SBSM::Warning, warning)
147
+ assert_equal('A Message', warning.message)
148
+ assert_equal(:key, warning.key)
149
+ assert_equal('A Value', warning.value)
150
+ @state.add_warning('Another Message', :key2, 'Another Value')
151
+ assert_equal(2, @state.warnings.size)
152
+ end
153
+ end
154
+ class TestUserState < Test::Unit::TestCase
155
+ def test_no_user_view_defined
156
+ state = State.new(StubStateSession.new, nil)
157
+ assert_equal(StubStateView, state.view.class)
158
+ end
159
+ def test_default_user_view
160
+ state = UserState.new(StubStateSession.new, nil)
161
+ assert_equal(StubStateView, state.view.class)
162
+ end
163
+ def test_user_view
164
+ state = UserState.new(StubStateUserSession.new, nil)
165
+ assert_equal(StubStateUserView, state.view.class)
166
+ end
167
+ def test_filtered_view
168
+ model = [1,2,3,4,5]
169
+ state = UserState.new(StubStateSession.new, model)
170
+ state.filter = Proc.new { |model|
171
+ model.select { |entry| entry > 2 }
172
+ }
173
+ view = state.view
174
+ assert_equal(3, view.model.size)
175
+ end
176
+ end