tengine_core 0.5.28

Sign up to get free protection for your applications and to get access to all the features.
Files changed (156) hide show
  1. data/.document +5 -0
  2. data/.rspec +1 -0
  3. data/Gemfile +40 -0
  4. data/Gemfile.lock +95 -0
  5. data/README.md +54 -0
  6. data/Rakefile +44 -0
  7. data/VERSION +1 -0
  8. data/bin/tengine_atd +8 -0
  9. data/bin/tengine_heartbeat_watchd +8 -0
  10. data/bin/tengined +182 -0
  11. data/examples/VERSION +1 -0
  12. data/examples/uc01_execute_processing_for_event.rb +11 -0
  13. data/examples/uc02_fire_another_event.rb +16 -0
  14. data/examples/uc03_2handlers_for_1event.rb +16 -0
  15. data/examples/uc08_if_both_a_and_b_occurs.rb +11 -0
  16. data/examples/uc10_if_the_event_occurs_at_the_server.rb +15 -0
  17. data/examples/uc50_commit_event_at_first.rb +17 -0
  18. data/examples/uc51_commit_event_at_first_submit.rb +29 -0
  19. data/examples/uc52_commit_event_after_all_handler_submit.rb +31 -0
  20. data/examples/uc52_never_commit_event_unless_all_handler_submit.rb +31 -0
  21. data/examples/uc60_event_in_handler.rb +18 -0
  22. data/examples/uc62_session_in_driver.rb +16 -0
  23. data/examples/uc64_safety_countup.rb +14 -0
  24. data/examples/uc70_driver_enabled_on_activation.rb +13 -0
  25. data/examples/uc71_driver_disabled_on_activation.rb +14 -0
  26. data/examples/uc72_setup_eventmachine.rb +17 -0
  27. data/examples/uc80_raise_io_error.rb +10 -0
  28. data/examples/uc81_raise_runtime_error.rb +10 -0
  29. data/examples2/driver01.rb +18 -0
  30. data/examples2/driver02.rb +19 -0
  31. data/examples2/uc08_if_both_a_and_b_occurs.rb +13 -0
  32. data/examples2/uc10_if_the_event_occurs_at_the_server.rb +18 -0
  33. data/examples2/uc51_commit_event_at_first_submit_1.rb +16 -0
  34. data/examples2/uc51_commit_event_at_first_submit_2.rb +17 -0
  35. data/examples2/uc51_commit_event_at_first_submit_3.rb +17 -0
  36. data/examples2/uc62_session_in_driver.rb +16 -0
  37. data/examples2/uc71_driver_disabled_on_activation.rb +16 -0
  38. data/failure_examples/VERSION +1 -0
  39. data/failure_examples/uc53_submit_outside_of_handler.rb +15 -0
  40. data/failure_examples/uc61_event_outside_of_handler.rb +12 -0
  41. data/failure_examples/uc63_session_outside_of_driver.rb +13 -0
  42. data/lib/tengine/core.rb +74 -0
  43. data/lib/tengine/core/bootstrap.rb +123 -0
  44. data/lib/tengine/core/collection_accessible.rb +34 -0
  45. data/lib/tengine/core/config.rb +10 -0
  46. data/lib/tengine/core/config/atd.rb +225 -0
  47. data/lib/tengine/core/config/core.rb +319 -0
  48. data/lib/tengine/core/config/heartbeat_watcher.rb +229 -0
  49. data/lib/tengine/core/connection_test/.gitignore +1 -0
  50. data/lib/tengine/core/connection_test/fire_bar_on_foo.rb +16 -0
  51. data/lib/tengine/core/driveable.rb +213 -0
  52. data/lib/tengine/core/driver.rb +69 -0
  53. data/lib/tengine/core/driver/finder.rb +42 -0
  54. data/lib/tengine/core/dsl_evaluator.rb +110 -0
  55. data/lib/tengine/core/dsl_filter_def.rb +11 -0
  56. data/lib/tengine/core/dsl_loader.rb +108 -0
  57. data/lib/tengine/core/event.rb +145 -0
  58. data/lib/tengine/core/event/finder.rb +82 -0
  59. data/lib/tengine/core/event_exception_reportable.rb +88 -0
  60. data/lib/tengine/core/event_wrapper.rb +21 -0
  61. data/lib/tengine/core/find_by_name.rb +31 -0
  62. data/lib/tengine/core/handler.rb +152 -0
  63. data/lib/tengine/core/handler_path.rb +33 -0
  64. data/lib/tengine/core/heartbeat_watcher.rb +161 -0
  65. data/lib/tengine/core/io_to_logger.rb +22 -0
  66. data/lib/tengine/core/kernel.rb +510 -0
  67. data/lib/tengine/core/kernel_runtime.rb +91 -0
  68. data/lib/tengine/core/method_traceable.rb +38 -0
  69. data/lib/tengine/core/mongoid_fix.rb +19 -0
  70. data/lib/tengine/core/mutex.rb +177 -0
  71. data/lib/tengine/core/optimistic_lock.rb +69 -0
  72. data/lib/tengine/core/plugins.rb +54 -0
  73. data/lib/tengine/core/schedule.rb +21 -0
  74. data/lib/tengine/core/scheduler.rb +156 -0
  75. data/lib/tengine/core/selectable_attr.rb +29 -0
  76. data/lib/tengine/core/session.rb +21 -0
  77. data/lib/tengine/core/session_wrapper.rb +68 -0
  78. data/lib/tengine/core/setting.rb +21 -0
  79. data/lib/tengine/core/validation.rb +36 -0
  80. data/lib/tengine/errors.rb +18 -0
  81. data/lib/tengine/rspec.rb +8 -0
  82. data/lib/tengine/rspec/context_wrapper.rb +51 -0
  83. data/lib/tengine/rspec/extension.rb +53 -0
  84. data/lib/tengine_core.rb +23 -0
  85. data/spec/factories/tengine_core_drivers.rb +10 -0
  86. data/spec/factories/tengine_core_events.rb +14 -0
  87. data/spec/factories/tengine_core_handler_paths.rb +9 -0
  88. data/spec/factories/tengine_core_handlers.rb +9 -0
  89. data/spec/factories/tengine_core_sessions.rb +9 -0
  90. data/spec/mongoid.yml +35 -0
  91. data/spec/spec_helper.rb +48 -0
  92. data/spec/support/mongo_index_key_log.rb +91 -0
  93. data/spec/tengine/core/bootstrap_spec.rb +278 -0
  94. data/spec/tengine/core/bugfix/bind_dsl_file_in_multi_byte_dir_spec.rb +21 -0
  95. data/spec/tengine/core/bugfix/enabled_on_activation_spec.rb +112 -0
  96. data/spec/tengine/core/bugfix/receive_event_spec.rb +133 -0
  97. data/spec/tengine/core/bugfix/use_dsl_version_method.rb +12 -0
  98. data/spec/tengine/core/bugfix/use_dsl_version_method_spec.rb +28 -0
  99. data/spec/tengine/core/bugfix/use_event_in_handler_dsl.rb +11 -0
  100. data/spec/tengine/core/bugfix//351/235/236ACSII/343/201/256/343/203/206/343/202/231/343/202/243/343/203/254/343/202/257/343/203/210/343/203/252/345/220/215/source_location_encoding.rb +35 -0
  101. data/spec/tengine/core/bugfix//351/235/236ACSII/343/201/256/343/203/206/343/202/231/343/202/243/343/203/254/343/202/257/343/203/210/343/203/252/345/220/215//351/235/236ASCII/343/201/256/343/203/225/343/202/241/343/202/244/343/203/253/345/220/215_dsl.rb +38 -0
  102. data/spec/tengine/core/bugfix//351/235/236ACSII/343/201/256/343/203/207/343/202/243/343/203/254/343/202/257/343/203/210/343/203/252/345/220/215/source_location_encoding.rb +35 -0
  103. data/spec/tengine/core/bugfix//351/235/236ACSII/343/201/256/343/203/207/343/202/243/343/203/254/343/202/257/343/203/210/343/203/252/345/220/215//351/235/236ASCII/343/201/256/343/203/225/343/202/241/343/202/244/343/203/253/345/220/215_dsl.rb +38 -0
  104. data/spec/tengine/core/config/atd_spec.rb +62 -0
  105. data/spec/tengine/core/config/core_spec.rb +479 -0
  106. data/spec/tengine/core/config/heartbeat_watcher_spec.rb +62 -0
  107. data/spec/tengine/core/config/syntax_error_in_erb.yml.erb +13 -0
  108. data/spec/tengine/core/config/wrong_category_name.yml.erb +13 -0
  109. data/spec/tengine/core/config/wrong_field_name.yml.erb +12 -0
  110. data/spec/tengine/core/config/wrong_yaml.yml.erb +13 -0
  111. data/spec/tengine/core/config_spec/another_port.yml +54 -0
  112. data/spec/tengine/core/config_spec/config_with_dir_absolute_load_path.yml +16 -0
  113. data/spec/tengine/core/config_spec/config_with_dir_relative_load_path.yml +16 -0
  114. data/spec/tengine/core/config_spec/config_with_file_absolute_load_path.yml +16 -0
  115. data/spec/tengine/core/config_spec/config_with_file_relative_load_path.yml +16 -0
  116. data/spec/tengine/core/config_spec/log_config_spec.rb +235 -0
  117. data/spec/tengine/core/driveable_spec.rb +240 -0
  118. data/spec/tengine/core/driver_spec.rb +159 -0
  119. data/spec/tengine/core/dsl_loader_spec.rb +172 -0
  120. data/spec/tengine/core/dsls/uc08_if_both_a_and_b_occurs_spec.rb +35 -0
  121. data/spec/tengine/core/dsls/uc10_if_the_event_occurs_at_the_server_spec.rb +58 -0
  122. data/spec/tengine/core/dsls/uc50_commit_event_at_first_spec.rb +29 -0
  123. data/spec/tengine/core/dsls/uc52_commit_event_after_all_handler_submit_spec.rb +33 -0
  124. data/spec/tengine/core/dsls/uc52_never_commit_event_unless_all_handler_submit_spec.rb +37 -0
  125. data/spec/tengine/core/dsls/uc53_submit_outside_of_handler_spec.rb +37 -0
  126. data/spec/tengine/core/dsls/uc60_event_in_handler_spec.rb +31 -0
  127. data/spec/tengine/core/dsls/uc61_event_outside_of_handler_spec.rb +37 -0
  128. data/spec/tengine/core/dsls/uc62_session_in_driver_spec.rb +36 -0
  129. data/spec/tengine/core/dsls/uc63_session_outside_of_driver_spec.rb +35 -0
  130. data/spec/tengine/core/dsls/uc64_safety_countup_spec.rb +134 -0
  131. data/spec/tengine/core/dsls/uc70_driver_enabled_on_activation_spec.rb +39 -0
  132. data/spec/tengine/core/dsls/uc71_driver_disabled_on_activation_spec.rb +36 -0
  133. data/spec/tengine/core/dsls/uc72_setup_eventmachine_spec.rb +39 -0
  134. data/spec/tengine/core/dsls/uc80_raise_io_error_spec.rb +53 -0
  135. data/spec/tengine/core/dsls/uc81_raise_runtime_error_spec.rb +49 -0
  136. data/spec/tengine/core/event/finder_spec.rb +136 -0
  137. data/spec/tengine/core/event_exception_reportable_spec.rb +33 -0
  138. data/spec/tengine/core/event_spec.rb +161 -0
  139. data/spec/tengine/core/event_wrapper_spec.rb +35 -0
  140. data/spec/tengine/core/handler_path_spec.rb +87 -0
  141. data/spec/tengine/core/handler_spec.rb +190 -0
  142. data/spec/tengine/core/heartbeat_watcher_spec.rb +131 -0
  143. data/spec/tengine/core/io_to_logger_spec.rb +30 -0
  144. data/spec/tengine/core/kernel_spec.rb +885 -0
  145. data/spec/tengine/core/mutex_spec.rb +184 -0
  146. data/spec/tengine/core/optimistic_lock_spec.rb +55 -0
  147. data/spec/tengine/core/scheculer_spec.rb +121 -0
  148. data/spec/tengine/core/selectable_attr_spec.rb +30 -0
  149. data/spec/tengine/core/session_spec.rb +104 -0
  150. data/spec/tengine/core/setting_spec.rb +79 -0
  151. data/spec/tengine/core_spec.rb +13 -0
  152. data/spec/tengine_spec.rb +14 -0
  153. data/tengine_core.gemspec +248 -0
  154. data/tmp/log/.gitignore +1 -0
  155. data/tmp/tengined_status/.gitignore +1 -0
  156. metadata +421 -0
@@ -0,0 +1,184 @@
1
+ # -*- coding: utf-8 -*-
2
+ require 'spec_helper'
3
+ require 'tengine/core'
4
+
5
+ describe Tengine::Core::Mutex do
6
+ before do
7
+ Tengine::Core::Mutex::Mutex.delete_all
8
+ end
9
+
10
+ context "#new" do
11
+ subject { Tengine::Core::Mutex.new "test mutex 01" }
12
+
13
+ it { should be_kind_of(Tengine::Core::Mutex) }
14
+ its(:mutex) { should be_kind_of(Tengine::Core::Mutex::Mutex) }
15
+ its(:recursive) { should be_zero }
16
+
17
+ context "negative ttl" do
18
+ it { expect { Tengine::Core::Mutex.new "test negative ttl", -1 }.to raise_exception(ArgumentError) }
19
+ end
20
+
21
+ context "infinite ttl" do
22
+ it { expect { Tengine::Core::Mutex.new "test negative ttl", (1.0 / 0.0) }.to raise_exception(TypeError) }
23
+ end
24
+ end
25
+
26
+ context "#synchronize" do
27
+ subject { Tengine::Core::Mutex.new "test mutex 01", Math::PI / 10 }
28
+
29
+ it "requires block" do
30
+ expect {
31
+ subject.synchronize
32
+ }.to raise_exception(ArgumentError)
33
+ end
34
+
35
+ it "synchronizes #0: no other lockers" do
36
+ block_called = false
37
+ EM.run_block do
38
+ subject.synchronize do
39
+ block_called = true
40
+ end
41
+ end
42
+ block_called.should be_true
43
+ end
44
+
45
+ it "synchronizes #1: with another locker, which is expired" do
46
+ # "stub" waiters
47
+ m = subject.mutex
48
+ m.waiters ||= []
49
+ m.waiters << { :_id => 1, :timeout => Time.at(0) }
50
+ m.save
51
+
52
+ block_called = false
53
+ t0 = Time.now
54
+ EM.run_block do
55
+ subject.synchronize do
56
+ block_called = true
57
+ end
58
+ end
59
+ t1 = Time.now
60
+ block_called.should be_true
61
+ m.reload.waiters.should be_empty
62
+ (t1 - t0).should be_within(0.5).of(0) #immediate
63
+ end
64
+
65
+ it "synchronizes #2: with another locker, which is expiring" do
66
+ # "stub" waiters
67
+ m = subject.mutex
68
+ m.waiters ||= []
69
+ m.waiters << { :_id => 1, :timeout => Time.now + m.ttl / 2 }
70
+ m.save
71
+
72
+ block_called = false
73
+ t0 = Time.now
74
+ EM.run do
75
+ subject.synchronize do
76
+ block_called = true
77
+ EM.stop
78
+ end
79
+ end
80
+ t1 = Time.now
81
+ block_called.should be_true
82
+ m.reload.waiters.should be_empty
83
+ (t1 - t0).should be_within(0.5).of(0.3 + m.ttl)
84
+ end
85
+
86
+ it "synchronizes #3: with another locker, which is not expiring" do
87
+ # "stub" waiters
88
+ m = subject.mutex
89
+ s = mock("mutex")
90
+ s.stub("_id").and_return(1)
91
+ m.waiters ||= []
92
+ m.waiters << { :_id => s._id, :timeout => Time.now + 10 }
93
+ m.save
94
+
95
+ block_called = false
96
+ t0 = Time.now
97
+ EM.run do
98
+ EM.add_timer 5 do
99
+ m.unlock s
100
+ end
101
+ subject.synchronize do
102
+ block_called = true
103
+ EM.stop
104
+ end
105
+ end
106
+ t1 = Time.now
107
+ block_called.should be_true
108
+ m.reload.waiters.should be_empty
109
+ (t1 - t0).should be_within(0.5).of(5 + m.ttl)
110
+ end
111
+
112
+ it "synchronizes #4: multi-threaded situation" do
113
+ x = y = z = nil
114
+
115
+ EM.run do
116
+ EM.defer do
117
+ m = Tengine::Core::Mutex.new "test mutex 02"
118
+ m.synchronize do
119
+ x = Time.now.to_f
120
+ end
121
+ y = Time.now.to_f
122
+ end
123
+
124
+ EM.defer do
125
+ sleep 0.5
126
+ m = Tengine::Core::Mutex.new "test mutex 02"
127
+ m.synchronize do
128
+ z = Time.now.to_f
129
+ end
130
+ end
131
+
132
+ EM.add_timer(2.5) do
133
+ EM.stop
134
+ end
135
+ end
136
+
137
+ x.should_not be_nil
138
+ y.should_not be_nil
139
+ z.should_not be_nil
140
+ x.should < z
141
+ y.should <= z
142
+ end
143
+ end
144
+
145
+ context "#heartbeat" do
146
+ subject { Tengine::Core::Mutex.new "test mutex 01", Math::PI / 10 }
147
+
148
+ it "prevents automatic unlocking" do
149
+ m = subject.mutex
150
+ t1 = nil
151
+ t0 = Time.now.to_f
152
+ EM.run do
153
+ EM.defer do
154
+ subject.synchronize do
155
+ 20.times do
156
+ subject.heartbeat
157
+ sleep(m.ttl / 2)
158
+ end
159
+ end
160
+ end
161
+ EM.defer do
162
+ sleep m.ttl
163
+ loop do
164
+ # hacky...
165
+ if h = m.reload.waiters.first
166
+ if h["timeout"] < Time.now
167
+ t1 = Time.now.to_f
168
+ EM.stop
169
+ break
170
+ end
171
+ else
172
+ t1 = Time.now.to_f
173
+ EM.stop
174
+ break
175
+ end
176
+ end
177
+ end
178
+ end
179
+
180
+ t1.should_not be_nil
181
+ (t1 - t0).should be_within(0.5).of(10 * subject.mutex.ttl)
182
+ end
183
+ end
184
+ end
@@ -0,0 +1,55 @@
1
+ # -*- coding: utf-8 -*-
2
+ require 'spec_helper'
3
+
4
+ describe Tengine::Core::OptimisticLock do
5
+
6
+ class Tengine::Core::OptimisticLockTestBox1
7
+ include Mongoid::Document
8
+ include Tengine::Core::OptimisticLock
9
+
10
+ set_locking_field :version
11
+
12
+ field :version, :type => Integer
13
+ field :value, :type => String
14
+ end
15
+
16
+ context "update_with_lock" do
17
+ before do
18
+ @test_box1 = Tengine::Core::OptimisticLockTestBox1.create!(:version => 2, :value => "foo")
19
+ end
20
+
21
+ it "競合がなければ素直に更新する" do
22
+ test_box = Tengine::Core::OptimisticLockTestBox1.find(@test_box1.id)
23
+ test_box.update_with_lock do
24
+ test_box.value += "o"
25
+ end
26
+ test_box.reload
27
+ test_box.value.should == "fooo"
28
+ test_box.version.should == 3
29
+ end
30
+
31
+ it "競合しても単純に上書きしたりせず、最新を取得し直して更新する" do
32
+ test_box1 = Tengine::Core::OptimisticLockTestBox1.find(@test_box1.id)
33
+ test_box2 = Tengine::Core::OptimisticLockTestBox1.find(@test_box1.id)
34
+ # test_box1を更新
35
+ test_box1_count = 0
36
+ test_box1.update_with_lock do
37
+ test_box1_count += 1
38
+ test_box1.value += "o"
39
+ end
40
+ test_box1_count.should == 1
41
+ test_box1.value.should == "fooo"
42
+ test_box1.version.should == 3
43
+ # test_box2を更新
44
+ test_box2_count = 0
45
+ test_box2.update_with_lock do
46
+ test_box2_count += 1
47
+ test_box2.value += "w"
48
+ end
49
+ test_box2_count.should == 2
50
+ test_box2.value.should == "fooow"
51
+ test_box2.version.should == 4
52
+ end
53
+ end
54
+
55
+ end
@@ -0,0 +1,121 @@
1
+ # -*- coding: utf-8 -*-
2
+ require 'spec_helper'
3
+ require 'amqp'
4
+
5
+ require_relative '../../../lib/tengine/core/scheduler'
6
+ require 'tengine/mq/suite'
7
+
8
+ describe Tengine::Core::Scheduler do
9
+ before do
10
+ Tengine::Core::Schedule.delete_all
11
+ @uuid = UUID.new
12
+ end
13
+
14
+ subject do
15
+ Tengine::Core::Scheduler.new(%w[--heartbeat-atd-interval=30])
16
+ end
17
+
18
+ describe "#search_for_schedule" do
19
+
20
+ before do
21
+ @fixtures = Array.new
22
+ @fixtures << Tengine::Core::Schedule.new(event_type_name: "stop.execution.job.tengine", scheduled_at: 1.day.ago)
23
+ @fixtures << Tengine::Core::Schedule.new(event_type_name: "stop.execution.job.tengine", scheduled_at: Time.now + 10)
24
+ @fixtures << Tengine::Core::Schedule.new(event_type_name: "stop.execution.job.tengine", scheduled_at: 1.day.ago, status: Tengine::Core::Schedule::FIRED)
25
+ @fixtures.each {|i| i.save! }
26
+ end
27
+
28
+ it "古いものを検索してくる" do
29
+ EM.stub(:next_tick).and_yield
30
+ set = []
31
+ subject.search_for_schedule do |i|
32
+ set << i
33
+ end
34
+
35
+ set.should include(@fixtures[0])
36
+ set.should_not include(@fixtures[1])
37
+ set.should_not include(@fixtures[2])
38
+ end
39
+ end
40
+
41
+ describe "#send_last_event" do
42
+ it "finished.process.atd.tengineの発火" do
43
+ sender = mock(:sender)
44
+ subject.stub(:sender).and_return(sender)
45
+ sender.should_receive(:fire).with("finished.process.atd.tengine", an_instance_of(Hash))
46
+ sender.should_receive(:stop)
47
+ subject.send_last_event
48
+ end
49
+ end
50
+
51
+ describe "#send_periodic_event" do
52
+ it "atd.heartbeat.tengineの発火" do
53
+ sender = mock(:sender)
54
+ subject.stub(:sender).and_return(sender)
55
+ sender.should_receive(:fire).with("atd.heartbeat.tengine", an_instance_of(Hash))
56
+ sender.stub(:fire).with("finished.process.atd.tengine", an_instance_of(Hash)) # 来るかも
57
+ subject.send_periodic_event
58
+ end
59
+ end
60
+
61
+ describe "#send_scheduled_event" do
62
+ it "スケジュールされたイベントの発火" do
63
+ s0 = Tengine::Core::Schedule.new(event_type_name: "test.event.not.tengine", source_name: "test://localhost/dev/null", properties: {foo: 'bar'})
64
+ sender = mock(:sender)
65
+ subject.stub(:sender).and_return(sender)
66
+ sender.should_receive(:fire).with(s0.event_type_name, an_instance_of(Hash)) do |e1, h|
67
+ h[:source_name].should == s0.source_name
68
+ h[:properties].should == {:foo => 'bar'}
69
+ h[:key].should == s0._id
70
+ end
71
+
72
+ subject.send_scheduled_event s0
73
+ end
74
+ end
75
+
76
+ describe "#mark_schedule_done" do
77
+ it "実行したスケジュールは終了とする" do
78
+ s0 = Tengine::Core::Schedule.new(event_type_name: "test.event.not.tengine", source_name: "test://localhost/dev/null")
79
+ s0.save
80
+ subject.mark_schedule_done s0
81
+ s0.reload
82
+ s0.status.should == Tengine::Core::Schedule::FIRED
83
+ end
84
+
85
+ it "すでに終了していたら何もしない" do
86
+ s0 = Tengine::Core::Schedule.new(event_type_name: "test.event.not.tengine", source_name: "test://localhost/dev/null", status: Tengine::Core::Schedule::FIRED)
87
+ s0.save
88
+ s0.reload
89
+ t = s0.updated_at
90
+ subject.mark_schedule_done s0
91
+ s0.reload
92
+ s0.updated_at.should == t
93
+ end
94
+ end
95
+
96
+ describe "#sender" do
97
+ before do
98
+ conn = mock(:connection)
99
+ conn.stub(:on_tcp_connection_loss)
100
+ conn.stub(:after_recovery)
101
+ conn.stub(:on_closed)
102
+ AMQP.stub(:connect).with(an_instance_of(Hash)).and_return(conn)
103
+ end
104
+ subject { Tengine::Core::Scheduler.new([]).sender }
105
+ it { should be_kind_of(Tengine::Event::Sender) }
106
+ end
107
+
108
+ describe "#run" do
109
+ it "各種timerを登録する" do
110
+ EM.stub(:run).and_yield
111
+ Daemons.stub(:run_proc).with(anything, anything).and_yield
112
+ EM.should_receive(:add_periodic_timer).exactly(2).times
113
+ Tengine::Core::MethodTraceable.stub(:disabled=)
114
+ sender = mock(:sender)
115
+ sender.stub(:wait_for_connection).and_yield
116
+ subject.stub(:sender).and_return(sender)
117
+ subject.instance_eval { @config }.stub(:setup_loggers)
118
+ subject.run __FILE__
119
+ end
120
+ end
121
+ end
@@ -0,0 +1,30 @@
1
+ # -*- coding: utf-8 -*-
2
+ require 'spec_helper'
3
+
4
+ require 'stringio'
5
+
6
+ describe Tengine::Core::SelectableAttr do
7
+
8
+ module TestModule1
9
+ class TestClass1
10
+ include Tengine::Core::SelectableAttr
11
+ selectable_attr :foo do
12
+ entry 1, :a, "do"
13
+ entry 2, :b, "re"
14
+ entry 3, :c, "mi"
15
+ end
16
+ multi_selectable_attr :bar do
17
+ entry 1, :x, "red"
18
+ entry 2, :y, "green"
19
+ entry 3, :z, "blue"
20
+ end
21
+ end
22
+ end
23
+
24
+ it "i18n_scopeが設定されている" do
25
+ TestModule1::TestClass1.foo_enum.i18n_scope.should == ['selectable_attrs', 'test_module1/test_class1', 'foo']
26
+ TestModule1::TestClass1.bar_enum.i18n_scope.should == ['selectable_attrs', 'test_module1/test_class1', 'bar']
27
+ end
28
+
29
+
30
+ end
@@ -0,0 +1,104 @@
1
+ # -*- coding: utf-8 -*-
2
+ require 'spec_helper'
3
+
4
+ describe Tengine::Core::Session do
5
+ context "should save Hash as properties" do
6
+ subject do
7
+ Tengine::Core::Session.create!(:properties => {
8
+ "key1" => 100,
9
+ "key2" => "string value",
10
+ "key3" => Time.utc(2011,9,4,20,58),
11
+ :key4 => [:array, "of", "variables", true, false, nil, 99.9999],
12
+ :key5 => {:nested => "hash"},
13
+ :key6 => :symbol_value,
14
+ })
15
+ end
16
+ it do
17
+ subject.properties["key1"].should == 100
18
+ subject.properties["key2"].should == "string value"
19
+ subject.properties["key3"].should == Time.utc(2011,9,4,20,58)
20
+ subject.properties[:key4].should == [:array, "of", "variables", true, false, nil, 99.9999]
21
+ subject.properties[:key5].should == {:nested => "hash"}
22
+ subject.properties[:key6].should == :symbol_value
23
+ end
24
+ it "should allow to read properties by using []" do
25
+ subject["key1"].should == 100
26
+ subject["key2"].should == "string value"
27
+ subject["key3"].should == Time.utc(2011,9,4,20,58)
28
+ subject[:key4].should == [:array, "of", "variables", true, false, nil, 99.9999]
29
+ subject[:key5].should == {:nested => "hash"}
30
+ subject[:key6].should == :symbol_value
31
+ end
32
+ it "should allow to write properties by using []=" do
33
+ subject["key1"] = 99
34
+ subject["key1"].should == 99
35
+ end
36
+ end
37
+
38
+ describe :update_with_lock do
39
+ before do
40
+ @session1 = Tengine::Core::Session.create!(
41
+ :lock_version => 2,
42
+ :properties => {
43
+ "key1" => 100,
44
+ "key2" => "string value",
45
+ "key3" => Time.utc(2011,9,4,20,58),
46
+ :key4 => [:array, "of", "variables", true, false, nil, 99.9999],
47
+ :key5 => {:nested => "hash"},
48
+ :key6 => :symbol_value,
49
+ })
50
+ end
51
+
52
+ it "競合がなければ素直に更新する" do
53
+ session = Tengine::Core::Session.find(@session1.id)
54
+ session.update_with_lock do
55
+ session.properties['key1'] += 1
56
+ end
57
+ session.reload
58
+ session.properties['key1'].should == 101
59
+ end
60
+
61
+ it "競合しても単純に上書きしたりせず、最新を取得し直して更新する" do
62
+ session1 = Tengine::Core::Session.find(@session1.id)
63
+ session2 = Tengine::Core::Session.find(@session1.id)
64
+ # session1を更新
65
+ session1.update_with_lock do
66
+ session1.properties['key1'] += 1
67
+ end
68
+ session1.properties['key1'].should == 101
69
+ # session2を更新
70
+ session1.update_with_lock do
71
+ session1.properties['key1'] += 1
72
+ end
73
+ session1.properties['key1'].should == 102
74
+ end
75
+
76
+ it "リトライ回数をオーバーすると例外が発生する" do
77
+ session1 = Tengine::Core::Session.find(@session1.id)
78
+ session2 = Tengine::Core::Session.find(@session1.id)
79
+
80
+ session1.update_with_lock{ session1.properties['key1'] += 1 } # [2] 100 -> [3] 101
81
+
82
+ f = Fiber.new do
83
+ session2.update_with_lock(:retry => 3) do
84
+ Fiber.yield
85
+ session1.properties['key1'] += 1
86
+ end
87
+ end
88
+ f.resume # [2] 100 -> [3] 101 を試みて失敗
89
+
90
+ session1.reload; session1.update_with_lock{ session1.properties['key1'] += 1 } # [3] 101 -> [4] 102
91
+ f.resume # [3] 101 -> [4] 102 を試みて失敗。リトライ1回
92
+
93
+ session1.reload; session1.update_with_lock{ session1.properties['key1'] += 1 } # [4] 102 -> [5] 103
94
+ f.resume # [4] 102 -> [5] 103 を試みて失敗。リトライ2回
95
+
96
+ session1.reload; session1.update_with_lock{ session1.properties['key1'] += 1 } # [5] 103 -> [6] 104
97
+ expect{
98
+ f.resume # [5] 103 -> [6] 104 を試みて失敗。リトライ3回失敗したので、例外がraiseされる
99
+ }.to raise_error(Tengine::Core::OptimisticLock::RetryOverError)
100
+ end
101
+
102
+ end
103
+
104
+ end