eye 0.1.11

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 (190) hide show
  1. data/.gitignore +31 -0
  2. data/.rspec +2 -0
  3. data/Gemfile +4 -0
  4. data/LICENSE +22 -0
  5. data/README.md +132 -0
  6. data/Rakefile +18 -0
  7. data/bin/eye +282 -0
  8. data/bin/loader_eye +56 -0
  9. data/examples/processes/em.rb +56 -0
  10. data/examples/processes/forking.rb +20 -0
  11. data/examples/processes/sample.rb +144 -0
  12. data/examples/rbenv.eye +11 -0
  13. data/examples/test.eye +65 -0
  14. data/examples/unicorn.eye +29 -0
  15. data/eye.gemspec +37 -0
  16. data/lib/eye.rb +25 -0
  17. data/lib/eye/application.rb +65 -0
  18. data/lib/eye/checker.rb +118 -0
  19. data/lib/eye/checker/cpu.rb +27 -0
  20. data/lib/eye/checker/file_ctime.rb +29 -0
  21. data/lib/eye/checker/file_size.rb +38 -0
  22. data/lib/eye/checker/http.rb +94 -0
  23. data/lib/eye/checker/memory.rb +27 -0
  24. data/lib/eye/checker/socket.rb +148 -0
  25. data/lib/eye/checker/validation.rb +49 -0
  26. data/lib/eye/child_process.rb +75 -0
  27. data/lib/eye/client.rb +32 -0
  28. data/lib/eye/control.rb +2 -0
  29. data/lib/eye/controller.rb +43 -0
  30. data/lib/eye/controller/commands.rb +64 -0
  31. data/lib/eye/controller/helpers.rb +61 -0
  32. data/lib/eye/controller/load.rb +224 -0
  33. data/lib/eye/controller/send_command.rb +88 -0
  34. data/lib/eye/controller/status.rb +136 -0
  35. data/lib/eye/dsl.rb +52 -0
  36. data/lib/eye/dsl/application_opts.rb +33 -0
  37. data/lib/eye/dsl/chain.rb +12 -0
  38. data/lib/eye/dsl/child_process_opts.rb +7 -0
  39. data/lib/eye/dsl/config_opts.rb +11 -0
  40. data/lib/eye/dsl/group_opts.rb +27 -0
  41. data/lib/eye/dsl/helpers.rb +12 -0
  42. data/lib/eye/dsl/main.rb +58 -0
  43. data/lib/eye/dsl/opts.rb +88 -0
  44. data/lib/eye/dsl/process_opts.rb +21 -0
  45. data/lib/eye/dsl/pure_opts.rb +132 -0
  46. data/lib/eye/dsl/validate.rb +41 -0
  47. data/lib/eye/group.rb +125 -0
  48. data/lib/eye/group/chain.rb +68 -0
  49. data/lib/eye/io/unix_server.rb +44 -0
  50. data/lib/eye/io/unix_socket.rb +39 -0
  51. data/lib/eye/loader.rb +13 -0
  52. data/lib/eye/logger.rb +80 -0
  53. data/lib/eye/process.rb +83 -0
  54. data/lib/eye/process/child.rb +61 -0
  55. data/lib/eye/process/commands.rb +256 -0
  56. data/lib/eye/process/config.rb +70 -0
  57. data/lib/eye/process/controller.rb +72 -0
  58. data/lib/eye/process/data.rb +46 -0
  59. data/lib/eye/process/monitor.rb +97 -0
  60. data/lib/eye/process/notify.rb +17 -0
  61. data/lib/eye/process/scheduler.rb +50 -0
  62. data/lib/eye/process/states.rb +92 -0
  63. data/lib/eye/process/states_history.rb +62 -0
  64. data/lib/eye/process/system.rb +60 -0
  65. data/lib/eye/process/trigger.rb +32 -0
  66. data/lib/eye/process/watchers.rb +67 -0
  67. data/lib/eye/server.rb +51 -0
  68. data/lib/eye/settings.rb +35 -0
  69. data/lib/eye/system.rb +145 -0
  70. data/lib/eye/system_resources.rb +83 -0
  71. data/lib/eye/trigger.rb +53 -0
  72. data/lib/eye/trigger/flapping.rb +24 -0
  73. data/lib/eye/utils.rb +5 -0
  74. data/lib/eye/utils/alive_array.rb +31 -0
  75. data/lib/eye/utils/celluloid_chain.rb +51 -0
  76. data/lib/eye/utils/leak_19.rb +7 -0
  77. data/lib/eye/utils/tail.rb +20 -0
  78. data/spec/checker/cpu_spec.rb +58 -0
  79. data/spec/checker/file_ctime_spec.rb +34 -0
  80. data/spec/checker/file_size_spec.rb +107 -0
  81. data/spec/checker/http_spec.rb +109 -0
  82. data/spec/checker/memory_spec.rb +64 -0
  83. data/spec/checker/socket_spec.rb +116 -0
  84. data/spec/checker_spec.rb +188 -0
  85. data/spec/child_process/child_process_spec.rb +46 -0
  86. data/spec/client_server_spec.rb +34 -0
  87. data/spec/controller/commands_spec.rb +92 -0
  88. data/spec/controller/controller_spec.rb +133 -0
  89. data/spec/controller/find_objects_spec.rb +150 -0
  90. data/spec/controller/group_spec.rb +110 -0
  91. data/spec/controller/intergration_spec.rb +327 -0
  92. data/spec/controller/load_spec.rb +326 -0
  93. data/spec/controller/races_spec.rb +70 -0
  94. data/spec/controller/stop_on_delete_spec.rb +157 -0
  95. data/spec/dsl/chain_spec.rb +140 -0
  96. data/spec/dsl/checks_spec.rb +202 -0
  97. data/spec/dsl/config_spec.rb +44 -0
  98. data/spec/dsl/dsl_spec.rb +73 -0
  99. data/spec/dsl/getter_spec.rb +223 -0
  100. data/spec/dsl/integration_spec.rb +311 -0
  101. data/spec/dsl/load_spec.rb +52 -0
  102. data/spec/dsl/process_spec.rb +330 -0
  103. data/spec/dsl/sub_procs_spec.rb +93 -0
  104. data/spec/dsl/with_server_spec.rb +104 -0
  105. data/spec/example/em.rb +57 -0
  106. data/spec/example/forking.rb +20 -0
  107. data/spec/example/sample.rb +154 -0
  108. data/spec/fixtures/dsl/0.rb +8 -0
  109. data/spec/fixtures/dsl/0a.rb +8 -0
  110. data/spec/fixtures/dsl/0c.rb +8 -0
  111. data/spec/fixtures/dsl/1.rb +5 -0
  112. data/spec/fixtures/dsl/bad.eye +6 -0
  113. data/spec/fixtures/dsl/configs/1.eye +3 -0
  114. data/spec/fixtures/dsl/configs/2.eye +1 -0
  115. data/spec/fixtures/dsl/configs/3.eye +1 -0
  116. data/spec/fixtures/dsl/configs/4.eye +3 -0
  117. data/spec/fixtures/dsl/empty.eye +20 -0
  118. data/spec/fixtures/dsl/include_test.eye +5 -0
  119. data/spec/fixtures/dsl/include_test/1.rb +6 -0
  120. data/spec/fixtures/dsl/include_test/ha.rb +4 -0
  121. data/spec/fixtures/dsl/include_test2.eye +5 -0
  122. data/spec/fixtures/dsl/integration.eye +30 -0
  123. data/spec/fixtures/dsl/integration2.eye +32 -0
  124. data/spec/fixtures/dsl/integration_locks.eye +30 -0
  125. data/spec/fixtures/dsl/integration_sor.eye +32 -0
  126. data/spec/fixtures/dsl/integration_sor2.eye +27 -0
  127. data/spec/fixtures/dsl/integration_sor3.eye +32 -0
  128. data/spec/fixtures/dsl/load.eye +25 -0
  129. data/spec/fixtures/dsl/load2.eye +7 -0
  130. data/spec/fixtures/dsl/load2_dup2.eye +13 -0
  131. data/spec/fixtures/dsl/load2_dup_pid.eye +7 -0
  132. data/spec/fixtures/dsl/load3.eye +10 -0
  133. data/spec/fixtures/dsl/load4.eye +7 -0
  134. data/spec/fixtures/dsl/load5.eye +8 -0
  135. data/spec/fixtures/dsl/load6.eye +17 -0
  136. data/spec/fixtures/dsl/load_dubls.eye +36 -0
  137. data/spec/fixtures/dsl/load_dup_ex_names.eye +15 -0
  138. data/spec/fixtures/dsl/load_error.eye +5 -0
  139. data/spec/fixtures/dsl/load_error_folder/load3.eye +10 -0
  140. data/spec/fixtures/dsl/load_error_folder/load4.eye +7 -0
  141. data/spec/fixtures/dsl/load_folder/load3.eye +10 -0
  142. data/spec/fixtures/dsl/load_folder/load4.eye +7 -0
  143. data/spec/fixtures/dsl/load_int.eye +8 -0
  144. data/spec/fixtures/dsl/load_int2.eye +13 -0
  145. data/spec/fixtures/dsl/load_logger.eye +26 -0
  146. data/spec/fixtures/dsl/load_logger2.eye +3 -0
  147. data/spec/fixtures/dsl/long_load.eye +5 -0
  148. data/spec/fixtures/dsl/subfolder1/proc1.rb +3 -0
  149. data/spec/fixtures/dsl/subfolder2.eye +9 -0
  150. data/spec/fixtures/dsl/subfolder2/common.rb +1 -0
  151. data/spec/fixtures/dsl/subfolder2/proc2.rb +3 -0
  152. data/spec/fixtures/dsl/subfolder2/sub/proc3.rb +6 -0
  153. data/spec/fixtures/dsl/subfolder3.eye +8 -0
  154. data/spec/fixtures/dsl/subfolder3/common.rb +1 -0
  155. data/spec/fixtures/dsl/subfolder3/proc4.rb +3 -0
  156. data/spec/fixtures/dsl/subfolder3/sub/proc5.rb +6 -0
  157. data/spec/fixtures/dsl/subfolder4.eye +6 -0
  158. data/spec/fixtures/dsl/subfolder4/a.rb +2 -0
  159. data/spec/fixtures/dsl/subfolder4/b.rb +1 -0
  160. data/spec/fixtures/dsl/subfolder4/c.rb +1 -0
  161. data/spec/mock_spec.rb +32 -0
  162. data/spec/process/checks/child_checks_spec.rb +79 -0
  163. data/spec/process/checks/cpu_spec.rb +114 -0
  164. data/spec/process/checks/ctime_spec.rb +43 -0
  165. data/spec/process/checks/fsize_spec.rb +22 -0
  166. data/spec/process/checks/http_spec.rb +52 -0
  167. data/spec/process/checks/intergration_spec.rb +32 -0
  168. data/spec/process/checks/memory_spec.rb +113 -0
  169. data/spec/process/child_process_spec.rb +125 -0
  170. data/spec/process/config_spec.rb +75 -0
  171. data/spec/process/controller_spec.rb +173 -0
  172. data/spec/process/monitoring_spec.rb +180 -0
  173. data/spec/process/restart_spec.rb +174 -0
  174. data/spec/process/scheduler_spec.rb +150 -0
  175. data/spec/process/start_spec.rb +261 -0
  176. data/spec/process/states_history_spec.rb +118 -0
  177. data/spec/process/stop_spec.rb +150 -0
  178. data/spec/process/system_spec.rb +100 -0
  179. data/spec/process/triggers/flapping_spec.rb +81 -0
  180. data/spec/process/update_config_spec.rb +63 -0
  181. data/spec/spec_helper.rb +120 -0
  182. data/spec/support/rr_celluloid.rb +36 -0
  183. data/spec/support/scheduler_hack.rb +16 -0
  184. data/spec/support/spec_support.rb +164 -0
  185. data/spec/system_resources_spec.rb +59 -0
  186. data/spec/system_spec.rb +170 -0
  187. data/spec/utils/alive_array_spec.rb +50 -0
  188. data/spec/utils/celluloid_chain_spec.rb +82 -0
  189. data/spec/utils/tail_spec.rb +21 -0
  190. metadata +558 -0
@@ -0,0 +1,110 @@
1
+ require File.dirname(__FILE__) + '/../spec_helper'
2
+
3
+ describe "Eye::Group" do
4
+
5
+ describe "Chain calls" do
6
+
7
+ it "should call chain_schedule for start" do
8
+ @g = Eye::Group.new('gr', {:chain => {:start => {:type => :async, :command => :start, :grace => 7}}})
9
+ mock(@g).chain_schedule(:async, 7, :start)
10
+ @g.start
11
+ end
12
+
13
+ it "should call chain_schedule for start, with type sync" do
14
+ @g = Eye::Group.new('gr', {:chain => {:start => {:type => :sync, :command => :start, :grace => 7}}})
15
+ mock(@g).chain_schedule(:sync, 7, :start)
16
+ @g.start
17
+ end
18
+
19
+ it "config for start and restart, use both" do
20
+ @g = Eye::Group.new('gr', {:chain => {:start => {:type => :async, :command => :start, :grace => 7}, :restart => {:type => :sync, :command => :restart, :grace => 8}}})
21
+ mock(@g).chain_schedule(:async, 7, :start)
22
+ @g.start
23
+
24
+ mock(@g).chain_schedule(:sync, 8, :restart)
25
+ @g.restart
26
+ end
27
+
28
+ it "should use options type" do
29
+ @g = Eye::Group.new('gr', {:chain => {:start => {:type => :sync, :command => :start}}})
30
+ mock(@g).chain_schedule(:sync, Eye::Group::DEFAULT_CHAIN, :start)
31
+ @g.start
32
+ end
33
+
34
+ it "with empty grace, should call default grace 0" do
35
+ @g = Eye::Group.new('gr', {:chain => {:start => {:command => :start}}})
36
+ mock(@g).chain_schedule(:async, Eye::Group::DEFAULT_CHAIN, :start)
37
+ @g.start
38
+ end
39
+
40
+ it "chain options for restart, but called start, should call chain but with default options" do
41
+ @g = Eye::Group.new('gr', {:chain => {:start => {:command => :restart}}})
42
+ mock(@g).chain_schedule(:async, Eye::Group::DEFAULT_CHAIN, :restart)
43
+ @g.restart
44
+ end
45
+
46
+ it "restart without grace, should call default grace 0" do
47
+ @g = Eye::Group.new('gr', {:chain => {:restart => {:command => :restart}}})
48
+ mock(@g).chain_schedule(:async, Eye::Group::DEFAULT_CHAIN, :restart)
49
+ @g.restart
50
+ end
51
+
52
+ it "restart with invalid type, should call with async" do
53
+ @g = Eye::Group.new('gr', {:chain => {:restart => {:command => :restart, :type => [12324]}}})
54
+ mock(@g).chain_schedule(:async, Eye::Group::DEFAULT_CHAIN, :restart)
55
+ @g.restart
56
+ end
57
+
58
+ it "restart with invalid grace, should call default grace 0" do
59
+ @g = Eye::Group.new('gr', {:chain => {:restart => {:command => :restart, :grace => []}}})
60
+ mock(@g).chain_schedule(:async, Eye::Group::DEFAULT_CHAIN, :restart)
61
+ @g.restart
62
+ end
63
+
64
+ it "restart with invalid grace, should call default grace 0" do
65
+ @g = Eye::Group.new('gr', {:chain => {:restart => {:command => :restart, :grace => :some_error}}})
66
+ mock(@g).chain_schedule(:async, Eye::Group::DEFAULT_CHAIN, :restart)
67
+ @g.restart
68
+ end
69
+
70
+ it "restart with empty config, should call chain_schedule" do
71
+ @g = Eye::Group.new('gr', {})
72
+ mock(@g).chain_schedule(:async, Eye::Group::DEFAULT_CHAIN, :restart)
73
+ @g.restart
74
+ end
75
+
76
+ it "when chain clearing by force" do
77
+ @g = Eye::Group.new('gr', {:chain => {:start => {:command => :start, :grace => 0}, :restart => {:command => :restart, :grace => 0}}})
78
+ mock(@g).chain_schedule(:async, 0, :monitor)
79
+ @g.monitor
80
+
81
+ mock(@g).chain_schedule(:async, 0, :restart)
82
+ @g.restart
83
+
84
+ mock(@g).chain_schedule(:async, 0, :start)
85
+ @g.start
86
+ end
87
+
88
+ it "with params" do
89
+ @g = Eye::Group.new('gr', {})
90
+ mock(@g).async_schedule(:signal, 15)
91
+ @g.signal(15)
92
+ end
93
+
94
+ describe "monitor using chain as start" do
95
+ it "monitor call chain" do
96
+ @g = Eye::Group.new('gr', {:chain => {:start => {:command => :start, :grace => 3}}})
97
+ mock(@g).chain_schedule(:async, 3, :monitor)
98
+ @g.monitor
99
+ end
100
+
101
+ it "monitor not call chain" do
102
+ @g = Eye::Group.new('gr', {:chain => {:restart => {:command => :restart, :grace => 3}}})
103
+ mock(@g).chain_schedule(:async, Eye::Group::DEFAULT_CHAIN, :monitor)
104
+ @g.monitor
105
+ end
106
+ end
107
+
108
+ end
109
+
110
+ end
@@ -0,0 +1,327 @@
1
+ require File.dirname(__FILE__) + '/../spec_helper'
2
+
3
+ describe "Intergration" do
4
+ before :each do
5
+ @c = Eye::Controller.new
6
+ @c.load(fixture("dsl/integration.eye"))
7
+ @processes = @c.all_processes
8
+ @p1 = @processes.detect{|c| c.name == 'sample1'}
9
+ @p2 = @processes.detect{|c| c.name == 'sample2'}
10
+ @p3 = @processes.detect{|c| c.name == 'forking'}
11
+ @samples = @c.all_groups.detect{|c| c.name == 'samples'}
12
+ sleep 10 # to ensure that all processes started
13
+
14
+ @processes.size.should == 3
15
+ @processes.map{|c| c.state_name}.uniq.should == [:up]
16
+ @childs = @p3.childs.keys rescue []
17
+
18
+ @c.info_string.split("\n").size.should == 8
19
+ @c.info_string.strip.size.should > 100
20
+ end
21
+
22
+ after :each do
23
+ @processes.each do |p|
24
+ p.schedule(:stop) if p.alive?
25
+ end
26
+ sleep 5
27
+ @processes.each do |process|
28
+ force_kill_process(process) if process.alive?
29
+ end
30
+
31
+ force_kill_pid(@old_pid1)
32
+ force_kill_pid(@old_pid2)
33
+ force_kill_pid(@old_pid3)
34
+ (@childs || []).each do |pid|
35
+ force_kill_pid(pid)
36
+ end
37
+ end
38
+
39
+ it "restart process group samples" do
40
+ @old_pid1 = @p1.pid
41
+ @old_pid2 = @p2.pid
42
+ @old_pid3 = @p3.pid
43
+ @c.send_command(:restart, "samples")
44
+ sleep 11 # while they restarting
45
+
46
+ @processes.map{|c| c.state_name}.uniq.should == [:up]
47
+ @p1.pid.should_not == @old_pid1
48
+ @p2.pid.should_not == @old_pid2
49
+ @p3.pid.should == @old_pid3
50
+ end
51
+
52
+ it "restart process" do
53
+ @old_pid1 = @p1.pid
54
+ @old_pid2 = @p2.pid
55
+ @old_pid3 = @p3.pid
56
+ @c.send_command(:restart, "sample1")
57
+ sleep 10 # while they restarting
58
+
59
+ @processes.map{|c| c.state_name}.uniq.should == [:up]
60
+ @p1.pid.should_not == @old_pid1
61
+ @p2.pid.should == @old_pid2
62
+ @p3.pid.should == @old_pid3
63
+ end
64
+
65
+ it "restart process forking" do
66
+ @old_pid1 = @p1.pid
67
+ @old_pid2 = @p2.pid
68
+ @old_pid3 = @p3.pid
69
+ @c.send_command(:restart, "forking")
70
+ sleep 11 # while they restarting
71
+
72
+ @processes.map{|c| c.state_name}.uniq.should == [:up]
73
+ @p1.pid.should == @old_pid1
74
+ @p2.pid.should == @old_pid2
75
+ @p3.pid.should_not == @old_pid3
76
+
77
+ @p1.last_scheduled_reason.should == 'monitor by user'
78
+ @p3.last_scheduled_reason.should == 'restart by user'
79
+ end
80
+
81
+ it "restart missing" do
82
+ @old_pid1 = @p1.pid
83
+ @old_pid2 = @p2.pid
84
+ @old_pid3 = @p3.pid
85
+ @c.send_command(:restart, "blabla").should == []
86
+ sleep 1
87
+ @processes.map{|c| c.state_name}.uniq.should == [:up]
88
+ @p1.pid.should == @old_pid1
89
+ @p2.pid.should == @old_pid2
90
+ @p3.pid.should == @old_pid3
91
+ end
92
+
93
+ describe "chain" do
94
+ it "restart group with chain sync" do
95
+ @samples.config.merge!(:chain => C.restart_sync)
96
+
97
+ @old_pid1 = @p1.pid
98
+ @old_pid2 = @p2.pid
99
+ @old_pid3 = @p3.pid
100
+ @c.send_command(:restart, "samples")
101
+ sleep 15 # while they restarting
102
+
103
+ @processes.map{|c| c.state_name}.uniq.should == [:up]
104
+ @p1.pid.should_not == @old_pid1
105
+ @p2.pid.should_not == @old_pid2
106
+ @p3.pid.should == @old_pid3
107
+
108
+ r1 = @p1.states_history.detect{|c| c[:state] == :restarting}[:at]
109
+ r2 = @p2.states_history.detect{|c| c[:state] == :restarting}[:at]
110
+
111
+ # >8 because, grace start, and grace stop added
112
+ (r2 - r1).should > 8
113
+ end
114
+
115
+ it "restart group with chain async" do
116
+ @samples.config.merge!(:chain => C.restart_async)
117
+
118
+ @old_pid1 = @p1.pid
119
+ @old_pid2 = @p2.pid
120
+ @old_pid3 = @p3.pid
121
+ @c.send_command(:restart, "samples")
122
+ sleep 15 # while they restarting
123
+
124
+ @processes.map{|c| c.state_name}.uniq.should == [:up]
125
+ @p1.pid.should_not == @old_pid1
126
+ @p2.pid.should_not == @old_pid2
127
+ @p3.pid.should == @old_pid3
128
+
129
+ r1 = @p1.states_history.detect{|c| c[:state] == :restarting}[:at]
130
+ r2 = @p2.states_history.detect{|c| c[:state] == :restarting}[:at]
131
+
132
+ # restart sended, in 5 seconds to each
133
+ (r2 - r1).should be_within(0.2).of(5)
134
+ end
135
+
136
+ it "if processes dead in chain restart, nothing raised" do
137
+ @samples.config.merge!(:chain => C.restart_async)
138
+
139
+ @old_pid1 = @p1.pid
140
+ @old_pid2 = @p2.pid
141
+ @old_pid3 = @p3.pid
142
+ @c.send_command(:restart, "samples")
143
+ sleep 3
144
+
145
+ # in the middle of the process, we kill all processes
146
+ @p1.terminate
147
+ @p2.terminate
148
+
149
+ sleep 3
150
+
151
+ # nothing happens
152
+ @samples.alive?.should == true
153
+ end
154
+ end
155
+
156
+ it "stop group" do
157
+ @old_pid1 = @p1.pid
158
+ @old_pid2 = @p2.pid
159
+ @old_pid3 = @p3.pid
160
+ @c.send_command(:stop, "samples")
161
+ sleep 7 # while they stopping
162
+
163
+ @p1.state_name.should == :unmonitored
164
+ @p2.state_name.should == :unmonitored
165
+ @p3.state_name.should == :up
166
+
167
+ Eye::System.pid_alive?(@old_pid1).should == false
168
+ Eye::System.pid_alive?(@old_pid2).should == false
169
+ Eye::System.pid_alive?(@old_pid3).should == true
170
+
171
+ sth = @p1.states_history.last
172
+ sth[:reason].should == 'stop by user'
173
+ sth[:state].should == :unmonitored
174
+ end
175
+
176
+ it "stop process" do
177
+ @old_pid1 = @p1.pid
178
+ @old_pid2 = @p2.pid
179
+ @old_pid3 = @p3.pid
180
+
181
+ @c.send_command(:stop, "sample1")
182
+ sleep 7 # while they stopping
183
+
184
+ @p1.state_name.should == :unmonitored
185
+ @p2.state_name.should == :up
186
+ @p3.state_name.should == :up
187
+
188
+ Eye::System.pid_alive?(@old_pid1).should == false
189
+ Eye::System.pid_alive?(@old_pid2).should == true
190
+ Eye::System.pid_alive?(@old_pid3).should == true
191
+ end
192
+
193
+ it "unmonitor process" do
194
+ @old_pid1 = @p1.pid
195
+ @old_pid2 = @p2.pid
196
+ @old_pid3 = @p3.pid
197
+
198
+ @c.send_command(:unmonitor, "sample1").should == ["int:samples:sample1"]
199
+ sleep 7 # while they stopping
200
+
201
+ @p1.state_name.should == :unmonitored
202
+ @p2.state_name.should == :up
203
+ @p3.state_name.should == :up
204
+
205
+ Eye::System.pid_alive?(@old_pid1).should == true
206
+ Eye::System.pid_alive?(@old_pid2).should == true
207
+ Eye::System.pid_alive?(@old_pid3).should == true
208
+ end
209
+
210
+ it "send signal to process throught all schedules" do
211
+ mock(@p1).signal('usr2')
212
+ mock(@p2).signal('usr2')
213
+ mock(@p3).signal('usr2')
214
+
215
+ @c.signal('usr2', "int").should == ["int"]
216
+ sleep 3 # while they gettings
217
+
218
+ @p1.last_scheduled_command.should == :signal
219
+ @p1.last_scheduled_reason.should == 'signal by user'
220
+
221
+ mock(@p1).signal('usr1')
222
+ @c.signal('usr1', 'sample1')
223
+ sleep 0.5
224
+ end
225
+
226
+ describe "delete" do
227
+ it "delete group not monitoring anymore" do
228
+ @old_pid1 = @p1.pid
229
+ @old_pid2 = @p2.pid
230
+ @old_pid3 = @p3.pid
231
+
232
+ @c.send_command(:delete, "samples").should == ["int:samples"]
233
+ sleep 7 # while
234
+
235
+ @c.all_processes.should == [@p3]
236
+ @c.all_groups.map(&:name).should == ['__default__']
237
+
238
+ Eye::System.pid_alive?(@old_pid1).should == true
239
+ Eye::System.pid_alive?(@old_pid2).should == true
240
+ Eye::System.pid_alive?(@old_pid3).should == true
241
+
242
+ Eye::System.send_signal(@old_pid1)
243
+ sleep 0.5
244
+ Eye::System.pid_alive?(@old_pid1).should == false
245
+
246
+ # noone up this
247
+ sleep 2
248
+ Eye::System.pid_alive?(@old_pid1).should == false
249
+ end
250
+
251
+ it "delete process not monitoring anymore" do
252
+ @old_pid1 = @p1.pid
253
+ @old_pid2 = @p2.pid
254
+ @old_pid3 = @p3.pid
255
+
256
+ @c.send_command(:delete, "sample1")
257
+ sleep 7 # while
258
+
259
+ @c.all_processes.map(&:name).sort.should == %w{forking sample2}
260
+ @c.all_groups.map(&:name).sort.should == %w{__default__ samples}
261
+ @c.group_by_name('samples').processes.full_size.should == 1
262
+ @c.group_by_name('samples').processes.map(&:name).should == %w{sample2}
263
+
264
+ Eye::System.pid_alive?(@old_pid1).should == true
265
+ Eye::System.pid_alive?(@old_pid2).should == true
266
+ Eye::System.pid_alive?(@old_pid3).should == true
267
+
268
+ Eye::System.send_signal(@old_pid1)
269
+ sleep 0.5
270
+ Eye::System.pid_alive?(@old_pid1).should == false
271
+ end
272
+
273
+ it "delete application" do
274
+ @old_pid1 = @p1.pid
275
+ @old_pid2 = @p2.pid
276
+ @old_pid3 = @p3.pid
277
+
278
+ @c.send_command(:delete, "int")
279
+ sleep 7 # while
280
+
281
+ @c.all_processes.should == []
282
+ @c.all_groups.should == []
283
+ @c.applications.should == []
284
+
285
+ Eye::System.pid_alive?(@old_pid1).should == true
286
+ Eye::System.pid_alive?(@old_pid2).should == true
287
+ Eye::System.pid_alive?(@old_pid3).should == true
288
+
289
+ Eye::System.send_signal(@old_pid1)
290
+ sleep 0.5
291
+ Eye::System.pid_alive?(@old_pid1).should == false
292
+
293
+ actors = Celluloid::Actor.all.map(&:class)
294
+ actors.should_not include(Eye::Utils::CelluloidChain)
295
+ actors.should_not include(Eye::Process)
296
+ actors.should_not include(Eye::Group)
297
+ actors.should_not include(Eye::Application)
298
+ actors.should_not include(Eye::Checker::Memory)
299
+ end
300
+
301
+ it "delete by mask" do
302
+ @old_pid1 = @p1.pid
303
+ @old_pid2 = @p2.pid
304
+ @old_pid3 = @p3.pid
305
+
306
+ @c.send_command(:delete, "sam*").should == ["int:samples"]
307
+ sleep 7 # while
308
+
309
+ @c.all_processes.should == [@p3]
310
+ @c.all_groups.map(&:name).should == ['__default__']
311
+
312
+ Eye::System.pid_alive?(@old_pid1).should == true
313
+ Eye::System.pid_alive?(@old_pid2).should == true
314
+ Eye::System.pid_alive?(@old_pid3).should == true
315
+
316
+ Eye::System.send_signal(@old_pid1)
317
+ sleep 0.5
318
+ Eye::System.pid_alive?(@old_pid1).should == false
319
+
320
+ # noone up this
321
+ sleep 2
322
+ Eye::System.pid_alive?(@old_pid1).should == false
323
+ end
324
+ end
325
+
326
+
327
+ end
@@ -0,0 +1,326 @@
1
+ require File.dirname(__FILE__) + '/../spec_helper'
2
+
3
+ describe "Eye::Controller::Load" do
4
+ subject{ Eye::Controller.new }
5
+
6
+ it "blank" do
7
+ subject.load.should == {:error => true, :message => "config file '' not found!"}
8
+ end
9
+
10
+ it "not exists file" do
11
+ subject.load("/asdf/asd/fasd/fas/df/sfd").should == {:error => true, :message => "config file '/asdf/asd/fasd/fas/df/sfd' not found!"}
12
+ end
13
+
14
+ it "load 1 app" do
15
+ subject.load(fixture("dsl/load.eye")).should include(error: false)
16
+ subject.short_tree.should == {
17
+ "app1"=>{
18
+ "gr1"=>{"p1"=>"/tmp/app1-gr1-p1.pid", "p2"=>"/tmp/app1-gr1-p2.pid"},
19
+ "gr2"=>{"q3"=>"/tmp/app1-gr2-q3.pid"},
20
+ "__default__"=>{"g4"=>"/tmp/app1-g4.pid", "g5"=>"/tmp/app1-g5.pid"}},
21
+ "app2"=>{"__default__"=>{"z1"=>"/tmp/app2-z1.pid"}}}
22
+ end
23
+
24
+ it "load correctly application, groups for full_names processes" do
25
+ subject.load(fixture("dsl/load.eye")).should include(error: false)
26
+
27
+ p1 = subject.process_by_name('p1')
28
+ p1[:application].should == 'app1'
29
+ p1[:group].should == 'gr1'
30
+ p1.name.should == 'p1'
31
+ p1.full_name.should == 'app1:gr1:p1'
32
+
33
+ gr1 = subject.group_by_name 'gr1'
34
+ gr1.full_name.should == 'app1:gr1'
35
+
36
+ g4 = subject.process_by_name('g4')
37
+ g4[:application].should == 'app1'
38
+ g4[:group].should == '__default__'
39
+ g4.name.should == 'g4'
40
+ g4.full_name.should == 'app1:g4'
41
+ end
42
+
43
+ it "load + 1new app" do
44
+ subject.load(fixture("dsl/load.eye")).should include(error: false)
45
+ subject.short_tree.should == {
46
+ "app1"=>{
47
+ "gr1"=>{"p1"=>"/tmp/app1-gr1-p1.pid", "p2"=>"/tmp/app1-gr1-p2.pid"},
48
+ "gr2"=>{"q3"=>"/tmp/app1-gr2-q3.pid"},
49
+ "__default__"=>{"g4"=>"/tmp/app1-g4.pid", "g5"=>"/tmp/app1-g5.pid"}},
50
+ "app2"=>{"__default__"=>{"z1"=>"/tmp/app2-z1.pid"}}}
51
+
52
+ subject.load(fixture("dsl/load2.eye")).should include(error: false)
53
+
54
+ subject.short_tree.should == {
55
+ "app1"=>{
56
+ "gr1"=>{"p1"=>"/tmp/app1-gr1-p1.pid", "p2"=>"/tmp/app1-gr1-p2.pid"},
57
+ "gr2"=>{"q3"=>"/tmp/app1-gr2-q3.pid"},
58
+ "__default__"=>{"g4"=>"/tmp/app1-g4.pid", "g5"=>"/tmp/app1-g5.pid"}},
59
+ "app2"=>{"__default__"=>{"z1"=>"/tmp/app2-z1.pid"}},
60
+ "app3"=>{"__default__"=>{"e1"=>"/tmp/app3-e1.pid"}}}
61
+ end
62
+
63
+ it "load 1 changed app" do
64
+ subject.load(fixture("dsl/load.eye")).should include(error: false)
65
+ subject.load(fixture("dsl/load2.eye")).should include(error: false)
66
+
67
+ p = subject.process_by_name('e1')
68
+ p[:daemonize].should == false
69
+
70
+ proxy(p).schedule :update_config, is_a(Hash), is_a(String)
71
+ dont_allow(p).schedule :monitor
72
+
73
+ subject.load(fixture("dsl/load3.eye")).should include(error: false)
74
+
75
+ subject.short_tree.should == {
76
+ "app1"=>{
77
+ "gr1"=>{"p1"=>"/tmp/app1-gr1-p1.pid", "p2"=>"/tmp/app1-gr1-p2.pid"},
78
+ "gr2"=>{"q3"=>"/tmp/app1-gr2-q3.pid"},
79
+ "__default__"=>{"g4"=>"/tmp/app1-g4.pid", "g5"=>"/tmp/app1-g5.pid"}},
80
+ "app2"=>{"__default__"=>{"z1"=>"/tmp/app2-z1.pid"}},
81
+ "app3"=>{"wow"=>{"e1"=>"/tmp/app3-e1.pid"}}}
82
+
83
+ sleep 0.1
84
+ p2 = subject.process_by_name('e1')
85
+ p2[:daemonize].should == true
86
+
87
+ p.object_id.should == p2.object_id
88
+ end
89
+
90
+ it "load -> delete -> load" do
91
+ subject.load(fixture("dsl/load.eye")).should include(error: false)
92
+ subject.load(fixture("dsl/load2.eye")).should include(error: false)
93
+ subject.command(:delete, 'app3')
94
+ subject.load(fixture("dsl/load3.eye")).should include(error: false)
95
+
96
+ subject.short_tree.should == {
97
+ "app1"=>{
98
+ "gr1"=>{"p1"=>"/tmp/app1-gr1-p1.pid", "p2"=>"/tmp/app1-gr1-p2.pid"},
99
+ "gr2"=>{"q3"=>"/tmp/app1-gr2-q3.pid"},
100
+ "__default__"=>{"g4"=>"/tmp/app1-g4.pid", "g5"=>"/tmp/app1-g5.pid"}},
101
+ "app2"=>{"__default__"=>{"z1"=>"/tmp/app2-z1.pid"}},
102
+ "app3"=>{"wow"=>{"e1"=>"/tmp/app3-e1.pid"}}}
103
+ end
104
+
105
+ it "load + 1 app, and pid_file crossed" do
106
+ subject.load(fixture("dsl/load2.eye")).should include(error: false)
107
+ subject.load(fixture("dsl/load4.eye")).should include(:error => true, :message => "dublicate pid_files: {\"/tmp/app3-e1.pid\"=>2}")
108
+
109
+ subject.short_tree.should == {
110
+ "app3"=>{"__default__"=>{"e1"=>"/tmp/app3-e1.pid"}}}
111
+ end
112
+
113
+ it "check syntax" do
114
+ subject.load(fixture("dsl/load2.eye")).should include(error: false)
115
+ subject.check(fixture("dsl/load4.eye")).should include(:error => true, :message => "dublicate pid_files: {\"/tmp/app3-e1.pid\"=>2}")
116
+ end
117
+
118
+ it "check explain" do
119
+ res = subject.explain(fixture("dsl/load2.eye"))
120
+ res[:error].should == false
121
+ res[:config].is_a?(Hash).should == true
122
+ end
123
+
124
+ it "process and groups disappears" do
125
+ subject.load(fixture("dsl/load.eye")).should include(error: false)
126
+ subject.group_by_name('gr1').processes.full_size.should == 2
127
+
128
+ subject.load(fixture("dsl/load5.eye")).should include(error: false)
129
+ sleep 0.5
130
+
131
+ group_actors = Celluloid::Actor.all.select{|c| c.class == Eye::Group }
132
+ process_actors = Celluloid::Actor.all.select{|c| c.class == Eye::Process }
133
+
134
+ subject.short_tree.should == {
135
+ "app1"=>{"gr1"=>{"p1"=>"/tmp/app1-gr1-p1.pid"}},
136
+ "app2"=>{"__default__"=>{"z1"=>"/tmp/app2-z1.pid"}}}
137
+
138
+ group_actors.map{|a| a.name}.sort.should == %w{__default__ gr1}
139
+ process_actors.map{|a| a.name}.sort.should == %w{p1 z1}
140
+
141
+ subject.group_by_name('gr1').processes.full_size.should == 1
142
+
143
+ # terminate 1 action
144
+ subject.process_by_name('p1').terminate
145
+ subject.info_string.should be_a(String)
146
+ end
147
+
148
+ it "swap groups" do
149
+ subject.load(fixture("dsl/load.eye")).should include(error: false)
150
+ subject.load(fixture("dsl/load6.eye")).should include(error: false)
151
+
152
+ subject.short_tree.should == {
153
+ "app1" => {
154
+ "gr2"=>{"p1"=>"/tmp/app1-gr1-p1.pid", "p2"=>"/tmp/app1-gr1-p2.pid"},
155
+ "gr1"=>{"q3"=>"/tmp/app1-gr2-q3.pid"},
156
+ "__default__"=>{"g4"=>"/tmp/app1-g4.pid", "g5"=>"/tmp/app1-g5.pid"}},
157
+ "app2"=>{"__default__"=>{"z1"=>"/tmp/app2-z1.pid"}}}
158
+ end
159
+
160
+ it "two configs with same pids (should validate final config)" do
161
+ subject.load(fixture("dsl/load.eye")).should include(error: false)
162
+ subject.load(fixture("dsl/load2*.eye")).should == {:error => true, :message=>"dublicate pid_files: {\"/tmp/app3-e1.pid\"=>2}"}
163
+ end
164
+
165
+ it "two configs with same pids (should validate final config)" do
166
+ subject.load(fixture("dsl/load.eye")).should include(error: false)
167
+ subject.load(fixture("dsl/load2.eye")).should include(error: false)
168
+ subject.load(fixture("dsl/load2_*.eye")).should == {:error => true, :message=>"dublicate pid_files: {\"/tmp/app3-e1.pid\"=>2}"}
169
+ end
170
+
171
+ it "dups of pid_files, but they different with expand" do
172
+ subject.load(fixture("dsl/load2_dup2.eye")).should include(error: false)
173
+ end
174
+
175
+ it "dups of names but in different scopes" do
176
+ subject.load(fixture("dsl/load_dup_ex_names.eye")).should include(error: false)
177
+ end
178
+
179
+ describe "configs" do
180
+ after(:each){ set_glogger }
181
+
182
+ it "load logger" do
183
+ subject.load(fixture("dsl/load_logger.eye")).should include(error: false)
184
+ Eye::Logger.dev.should == "/tmp/1.log"
185
+ end
186
+
187
+ it "set logger when load multiple configs" do
188
+ subject.load(fixture("dsl/load_logger{,2}.eye")).should include(error: false)
189
+ Eye::Logger.dev.should == "/tmp/1.log"
190
+ end
191
+
192
+ it "should corrent load config section" do
193
+ subject.load(fixture("dsl/configs/{1,2}.eye")).should include(error: false)
194
+ Eye::Logger.dev.should == "/tmp/a.log"
195
+ subject.current_config[:config].should == {:logger=>"/tmp/a.log", :http=>{:enable=>true}}
196
+
197
+ subject.load(fixture("dsl/configs/3.eye")).should include(error: false)
198
+ Eye::Logger.dev.should == "/tmp/a.log"
199
+ subject.current_config[:config].should == {:logger=>"/tmp/a.log", :http=>{:enable=>false}}
200
+
201
+ subject.load(fixture("dsl/configs/4.eye")).should include(error: false)
202
+ Eye::Logger.dev.should == nil
203
+ subject.current_config[:config].should == {:logger=>'', :http=>{:enable=>false}}
204
+
205
+ subject.load(fixture("dsl/configs/2.eye")).should include(error: false)
206
+ Eye::Logger.dev.should == nil
207
+ subject.current_config[:config].should == {:logger=>'', :http=>{:enable=>true}}
208
+ end
209
+ end
210
+
211
+
212
+ it "load folder" do
213
+ subject.load(fixture("dsl/load_folder/")).should include(error: false)
214
+ subject.short_tree.should == {
215
+ "app3" => {"wow"=>{"e1"=>"/tmp/app3-e1.pid"}},
216
+ "app4" => {"__default__"=>{"e2"=>"/tmp/app4-e2.pid"}}
217
+ }
218
+ end
219
+
220
+ it "load folder with error" do
221
+ subject.load(fixture("dsl/load_error_folder/")).should include(error: true)
222
+ end
223
+
224
+ it "load files by mask" do
225
+ subject.load(fixture("dsl/load_folder/*.eye")).should include(error: false)
226
+ subject.short_tree.should == {
227
+ "app3" => {"wow"=>{"e1"=>"/tmp/app3-e1.pid"}},
228
+ "app4" => {"__default__"=>{"e2"=>"/tmp/app4-e2.pid"}}
229
+ }
230
+ end
231
+
232
+ it "load files by mask with error" do
233
+ subject.load(fixture("dsl/load_error_folder/*.eye")).should include(error: true)
234
+ end
235
+
236
+ it "load not files with mask" do
237
+ subject.load(fixture("dsl/load_folder/*.bla")).should include(error: true)
238
+ end
239
+
240
+ it "bad mask" do
241
+ subject.load(" asdf asdf afd d").should == {:error => true, :message => "config file ' asdf asdf afd d' not found!"}
242
+ end
243
+
244
+ it "group update it settings" do
245
+ subject.load(fixture("dsl/load.eye")).should include(error: false)
246
+ app = subject.application_by_name('app1')
247
+ gr = subject.group_by_name('gr2')
248
+ gr.config[:chain].should == {:restart => {:grace=>0.5, :action=>:restart}, :start => {:grace=>0.5, :action=>:start}}
249
+
250
+ subject.load(fixture("dsl/load6.eye")).should include(error: false)
251
+ sleep 1
252
+
253
+ gr.config[:chain].should == {:restart => {:grace=>1.0, :action=>:restart}, :start => {:grace=>1.0, :action=>:start}}
254
+ end
255
+
256
+ it "load multiple apps with cross constants" do
257
+ subject.load(fixture('dsl/subfolder{2,3}.eye'))
258
+ subject.process_by_name('e1')[:working_dir].should == '/tmp'
259
+ subject.process_by_name('e2')[:working_dir].should == 'sub3'
260
+
261
+ subject.process_by_name('e3')[:working_dir].should == '/tmp'
262
+ subject.process_by_name('e4')[:working_dir].should == 'sub2'
263
+ end
264
+
265
+ it "raised load" do
266
+ subject.load(fixture("dsl/load_error.eye")).should == {error: true, message: "No such file or directory - /asd/fasd/fas/df/asd/fas/df/d"}
267
+ Eye.logger = $logger_path
268
+ end
269
+
270
+ describe "synchronize groups" do
271
+ it "correctly schedule monitor for groups and processes" do
272
+ subject.load(fixture("dsl/load_int.eye")).should include(error: false)
273
+ sleep 0.5
274
+
275
+ p0 = subject.process_by_name 'p0'
276
+ p1 = subject.process_by_name 'p1'
277
+ p2 = subject.process_by_name 'p2'
278
+ gr1 = subject.group_by_name 'gr1'
279
+ gr_ = subject.group_by_name '__default__'
280
+
281
+ p0.schedule_history.states.should == [:monitor]
282
+ p1.schedule_history.states.should == [:monitor]
283
+ p2.schedule_history.states.should == [:monitor]
284
+ gr1.schedule_history.states.should == [:monitor]
285
+ gr_.schedule_history.states.should == [:monitor]
286
+
287
+ subject.load(fixture("dsl/load_int2.eye")).should include(error: false)
288
+ sleep 0.5
289
+
290
+ p1.alive?.should == false
291
+ p0.alive?.should == false
292
+
293
+ p01 = subject.process_by_name 'p0-1'
294
+ p4 = subject.process_by_name 'p4'
295
+ p5 = subject.process_by_name 'p5'
296
+ gr2 = subject.group_by_name 'gr2'
297
+
298
+ p2.schedule_history.states.should == [:monitor, :update_config]
299
+ gr1.schedule_history.states.should == [:monitor, :update_config]
300
+ gr_.schedule_history.states.should == [:monitor, :update_config]
301
+
302
+ p01.schedule_history.states.should == [:monitor]
303
+ p4.schedule_history.states.should == [:monitor]
304
+ p5.schedule_history.states.should == [:monitor]
305
+ gr2.schedule_history.states.should == [:monitor]
306
+ end
307
+ end
308
+
309
+ describe "load is exclusive" do
310
+ it "run double in time" do
311
+ t = Time.now
312
+ Eye::Control.async.command(:load, fixture("dsl/long_load.eye"))
313
+ Eye::Control.async.command(:load, fixture("dsl/long_load.eye"))
314
+ sleep 2.5
315
+ Eye::Control.command(:info).should be_a(String) # actor should free here
316
+ end
317
+
318
+ it "load with subloads" do
319
+ silence_warnings{
320
+ Eye::Control.command(:load, fixture("dsl/subfolder2.eye"))
321
+ }
322
+ Eye::Control.command(:info).should be_a(String) # actor should free here
323
+ end
324
+ end
325
+
326
+ end