tengine_support 0.3.0 → 0.3.3

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,66 @@
1
+ # -*- coding: utf-8 -*-
2
+ require 'tengine/support/config/definition'
3
+
4
+ require 'optparse' # ここ以外でrequireしないし、関係するクラスを記述しません。
5
+
6
+ class Tengine::Support::Config::Definition::OptparseVisitor
7
+
8
+ attr_reader :option_parser
9
+ def initialize(suite)
10
+ @option_parser = OptionParser.new
11
+ @suite = suite
12
+ end
13
+
14
+ alias_method :o, :option_parser
15
+
16
+ def visit(d)
17
+ case d
18
+ when Tengine::Support::Config::Definition::Suite then
19
+ option_parser.banner = d.banner
20
+ d.children.each{|child| child.accept_visitor(self)}
21
+ when Tengine::Support::Config::Definition::Group then
22
+ if d.children.any?{|c| c.is_a?(Tengine::Support::Config::Definition::Field)}
23
+ o.separator ""
24
+ o.separator "#{d.__name__}:"
25
+ end
26
+ d.children.each{|child| child.accept_visitor(self)}
27
+ when Tengine::Support::Config::Definition then
28
+ o.separator ""
29
+ o.separator "#{d.__name__}:"
30
+ d.children.each{|child| child.accept_visitor(self)}
31
+ when Tengine::Support::Config::Definition::Field then
32
+ desc = d.description_value
33
+ desc_str = desc.respond_to?(:call) ? desc.call : desc
34
+ long_opt = d.long_opt
35
+ args = [d.short_opt, long_opt, desc_str].compact
36
+ case d.__type__
37
+ when :action then
38
+ obj = eval("self", d.__block__.binding)
39
+ (class << obj; self; end).module_eval do
40
+ attr_accessor :option_parser
41
+ end
42
+ obj.option_parser = option_parser
43
+ o.on(*args, &d.__block__)
44
+ when :separator then
45
+ o.separator(d.description)
46
+ else
47
+ case d.type
48
+ when :boolean then
49
+ o.on(*args){d.__parent__.send("#{d.__name__}=", true)}
50
+ when :load_config then
51
+ long_opt << "=VAL"
52
+ o.on(*args){|f| d.__parent__.send("#{d.__name__}=", f) }
53
+ else
54
+ long_opt << "=VAL"
55
+ if default_value = d.default_value
56
+ desc_str << " default: #{default_value.inspect}"
57
+ end
58
+ o.on(*args){|val| d.__parent__.send("#{d.__name__}=", val)}
59
+ end
60
+ end
61
+ else
62
+ raise "Unsupported definition class #{d.class.name}"
63
+ end
64
+
65
+ end
66
+ end
@@ -0,0 +1,42 @@
1
+ # -*- coding: utf-8 -*-
2
+ require 'tengine/support/config/definition'
3
+
4
+ require 'tengine/support/yaml_with_erb'
5
+
6
+ class Tengine::Support::Config::Definition::Suite
7
+ include Tengine::Support::Config::Definition::HasManyChildren
8
+
9
+ def mapping(mapping = nil)
10
+ @mapping = mapping if mapping
11
+ @mapping
12
+ end
13
+
14
+ def parent; nil; end
15
+ def root; self; end
16
+
17
+ def load_file(filepath)
18
+ load(YAML.load_file(filepath))
19
+ end
20
+
21
+ def banner(banner = nil)
22
+ @banner = banner if banner
23
+ @banner
24
+ end
25
+
26
+ def parse!(argv)
27
+ v = Tengine::Support::Config::Definition::OptparseVisitor.new(self)
28
+ self.accept_visitor(v)
29
+ if load_config = children.detect{|child| child.type == :load_config}
30
+ opts = v.option_parser.getopts(argv.dup) # このdup重要。もう一度parseに使用する場合に中身が空にならないように。
31
+ if filepath = opts[load_config.__name__.to_s]
32
+ load_file(filepath)
33
+ end
34
+ end
35
+ v.option_parser.parse(argv.dup)
36
+ end
37
+
38
+ def name_array
39
+ []
40
+ end
41
+
42
+ end
@@ -0,0 +1,23 @@
1
+ require 'tengine/support/config'
2
+
3
+ class Tengine::Support::Config::Logger
4
+ include Tengine::Support::Config::Definition
5
+
6
+ field :output, 'file path or "STDOUT" / "STDERR".', :type => :string
7
+ field :rotation, 'rotation file count or daily,weekly,monthly.', :type => :string
8
+ field :rotation_size, 'number of max log file size.', :type => :integer
9
+ field :level, 'debug/info/warn/error/fatal.', :type => :string
10
+
11
+ def new_logger
12
+ case output
13
+ when "STDOUT" then dev = STDOUT
14
+ when "STDERR" then dev = STDERR
15
+ else dev = output
16
+ end
17
+ shift_age = (rotation =~ /\A\d+\Z/) ? rotation.to_i : rotation
18
+ result = Logger.new(dev, shift_age, rotation_size)
19
+ result.level = Logger.const_get(level.upcase)
20
+ result
21
+ end
22
+
23
+ end
@@ -0,0 +1,14 @@
1
+ require 'tengine/support/config'
2
+
3
+ module Tengine::Support::Config::Mongoid
4
+
5
+ class Connection
6
+ include Tengine::Support::Config::Definition
7
+ field :host , 'hostname to connect db.', :default => 'localhost', :type => :string
8
+ field :port , "port to connect db.", :default => 27017, :type => :integer
9
+ field :username, 'username to connect db.', :type => :string
10
+ field :password, 'password to connect db.', :type => :string
11
+ field :database, 'database name to connect db.', :type => :string
12
+ end
13
+
14
+ end
@@ -0,0 +1,27 @@
1
+ module App1
2
+ class ProcessConfig
3
+ include Tengine::Support::Config::Definition
4
+ field :daemon, "process works on background.", :type => :boolean
5
+ field :pid_dir, "path/to/dir for PID created.", :type => :directory
6
+ end
7
+
8
+ class LoggerConfig < Tengine::Support::Config::Logger
9
+ parameter :logger_name
10
+ depends :process_config
11
+ depends :log_common
12
+ field :output,
13
+ :default => proc{
14
+ process_config.daemon ?
15
+ "./log/#{logger_name}.log" : "STDOUT" },
16
+ :default_description => proc{"if daemon process then \"./log/#{logger_name}.log\" else \"STDOUT\""}
17
+ field :rotation,
18
+ :default => proc{ log_common.rotation },
19
+ :default_description => proc{"value of #{log_common.long_opt}-rotation"}
20
+ field :rotation_size,
21
+ :default => proc{ log_common.rotation_size },
22
+ :default_description => proc{"value of #{log_common.long_opt}-rotation-size"}
23
+ field :level,
24
+ :default => proc{ log_common.level },
25
+ :default_description => proc{"value of #{log_common.long_opt}-level"}
26
+ end
27
+ end
@@ -0,0 +1,49 @@
1
+ def build_suite1
2
+ Tengine::Support::Config.suite do
3
+ banner <<EOS
4
+ Usage: config_test [-k action] [-f path_to_config]
5
+ [-H db_host] [-P db_port] [-U db_user] [-S db_pass] [-B db_database]
6
+
7
+ EOS
8
+
9
+ field(:action, "test|load|start|enable|stop|force-stop|status|activate", :type => :string, :default => "start")
10
+ load_config(:config, "path/to/config_file", :type => :string)
11
+ add(:process, App1::ProcessConfig)
12
+ add(:db, Tengine::Support::Config::Mongoid::Connection, :defaults => {:database => "tengine_production"})
13
+ group(:event_queue) do
14
+ add(:connection, Tengine::Support::Config::Amqp::Connection)
15
+ add(:exchange , Tengine::Support::Config::Amqp::Exchange, :defaults => {:name => 'tengine_event_exchange'})
16
+ add(:queue , Tengine::Support::Config::Amqp::Queue , :defaults => {:name => 'tengine_event_queue'})
17
+ end
18
+ add(:log_common, Tengine::Support::Config::Logger,
19
+ :defaults => {
20
+ :rotation => 3 ,
21
+ :rotation_size => 1024 * 1024,
22
+ :level => 'info' ,
23
+ })
24
+ add(:application_log, App1::LoggerConfig,
25
+ :logger_name => "application",
26
+ :dependencies => { :process_config => :process, :log_common => :log_common,})
27
+ add(:process_stdout_log, App1::LoggerConfig,
28
+ :logger_name => "#{File.basename($PROGRAM_NAME)}_stdout",
29
+ :dependencies => { :process_config => :process, :log_common => :log_common,})
30
+ add(:process_stderr_log, App1::LoggerConfig,
31
+ :logger_name => "#{File.basename($PROGRAM_NAME)}_stderr",
32
+ :dependencies => { :process_config => :process, :log_common => :log_common,})
33
+ separator("\nGeneral:")
34
+ __action__(:version, "show version"){ STDOUT.puts "1.1.1"; exit }
35
+ __action__(:help , "show this help message"){ STDOUT.puts option_parser.help; exit }
36
+
37
+ mapping({
38
+ [:action] => :k,
39
+ [:config] => :f,
40
+ [:process, :daemon] => :D,
41
+ [:db, :host] => :O,
42
+ [:db, :port] => :P,
43
+ [:db, :username] => :U,
44
+ [:db, :password] => :S,
45
+ })
46
+ end
47
+
48
+ end
49
+
@@ -0,0 +1,24 @@
1
+ # -*- coding: utf-8 -*-
2
+ require File.expand_path(File.dirname(__FILE__) + '/../../spec_helper')
3
+
4
+ describe 'Tengine::Support::Config::Amqp' do
5
+
6
+ context "static" do
7
+ describe Tengine::Support::Config::Amqp::Connection.host do
8
+ it { subject.should be_a(Tengine::Support::Config::Definition::Field)}
9
+ its(:type){ should == :string }
10
+ its(:__name__){ should == :host }
11
+ its(:description){ should == 'hostname to connect queue.'}
12
+ its(:default){ should == 'localhost'}
13
+ end
14
+
15
+ describe Tengine::Support::Config::Amqp::Connection.port do
16
+ it { subject.should be_a(Tengine::Support::Config::Definition::Field)}
17
+ its(:type){ should == :integer }
18
+ its(:__name__){ should == :port }
19
+ its(:description){ should == 'port to connect queue.'}
20
+ its(:default){ should == 5672}
21
+ end
22
+ end
23
+
24
+ end
@@ -0,0 +1,86 @@
1
+ # -*- coding: utf-8 -*-
2
+ require File.expand_path(File.dirname(__FILE__) + '/../../spec_helper')
3
+
4
+ require 'logger'
5
+ require 'tempfile'
6
+
7
+ describe 'Tengine::Support::Config::Logger' do
8
+
9
+ context "static" do
10
+
11
+ describe Tengine::Support::Config::Logger.output do
12
+ it { subject.should be_a(Tengine::Support::Config::Definition::Field)}
13
+ its(:type){ should == :string }
14
+ its(:__name__){ should == :output }
15
+ its(:description){ should == 'file path or "STDOUT" / "STDERR".'}
16
+ its(:default){ should == nil}
17
+ end
18
+ end
19
+
20
+ describe :new_logger do
21
+ it "STDOUTの場合" do
22
+ config = Tengine::Support::Config::Logger.new
23
+ config.output = "STDOUT"
24
+ config.level = "warn"
25
+ config.rotation = nil
26
+ config.rotation_size = nil
27
+ config.output.should == "STDOUT"
28
+ config.level.should == "warn"
29
+ config.rotation.should == nil
30
+ config.rotation_size.should == nil
31
+
32
+ logger = Logger.new(STDOUT, nil, nil)
33
+ Logger.should_receive(:new).with(STDOUT, nil, nil).and_return(logger)
34
+ logger.should_receive(:level=).with(Logger::WARN)
35
+ config.new_logger.should == logger
36
+ end
37
+
38
+ it "STDERRの場合" do
39
+ config = Tengine::Support::Config::Logger.new
40
+ config.output = "STDERR"
41
+ config.level = "warn"
42
+ config.rotation = nil
43
+ config.rotation_size = nil
44
+ logger = Logger.new(STDERR, nil, nil)
45
+ Logger.should_receive(:new).with(STDERR, nil, nil).and_return(logger)
46
+ logger.should_receive(:level=).with(Logger::WARN)
47
+ config.new_logger.should == logger
48
+ end
49
+
50
+ context "ファイル名の場合" do
51
+ before do
52
+ @filepath = Tempfile.new("test.log")
53
+ end
54
+ after do
55
+ @filepath.close
56
+ end
57
+
58
+ %w[daily weekly monthly].each do |shift_age|
59
+ it "shift_age が #{shift_age}" do
60
+ config = Tengine::Support::Config::Logger.new
61
+ config.output = @filepath
62
+ config.level = "info"
63
+ config.rotation = shift_age
64
+ config.rotation_size = nil
65
+ logger = Logger.new(@filepath, shift_age, nil)
66
+ Logger.should_receive(:new).with(@filepath, shift_age, nil).and_return(logger)
67
+ logger.should_receive(:level=).with(Logger::INFO)
68
+ config.new_logger.should == logger
69
+ end
70
+ end
71
+
72
+ it "shift_ageが整数値" do
73
+ config = Tengine::Support::Config::Logger.new
74
+ config.output = @filepath
75
+ config.level = "info"
76
+ config.rotation = "3"
77
+ config.rotation_size = 10 * 1024 * 1024 # 10MB
78
+ logger = Logger.new(@filepath, 3, 10 * 1024 * 1024)
79
+ Logger.should_receive(:new).with(@filepath, 3, 10 * 1024 * 1024).and_return(logger)
80
+ logger.should_receive(:level=).with(Logger::INFO)
81
+ config.new_logger.should == logger
82
+ end
83
+ end
84
+ end
85
+
86
+ end
@@ -0,0 +1,24 @@
1
+ # -*- coding: utf-8 -*-
2
+ require File.expand_path(File.dirname(__FILE__) + '/../../spec_helper')
3
+
4
+ describe 'Tengine::Support::Config::Mongoid' do
5
+
6
+ context "static" do
7
+ describe Tengine::Support::Config::Mongoid::Connection.host do
8
+ it { subject.should be_a(Tengine::Support::Config::Definition::Field)}
9
+ its(:type){ should == :string }
10
+ its(:__name__){ should == :host }
11
+ its(:description){ should == 'hostname to connect db.'}
12
+ its(:default){ should == 'localhost'}
13
+ end
14
+
15
+ describe Tengine::Support::Config::Mongoid::Connection.port do
16
+ it { subject.should be_a(Tengine::Support::Config::Definition::Field)}
17
+ its(:type){ should == :integer }
18
+ its(:__name__){ should == :port }
19
+ its(:description){ should == 'port to connect db.'}
20
+ its(:default){ should == 27017}
21
+ end
22
+ end
23
+
24
+ end
@@ -0,0 +1,190 @@
1
+ # -*- coding: utf-8 -*-
2
+ require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
3
+
4
+ describe "config" do
5
+
6
+ context "app1 setting" do
7
+ context "static" do
8
+
9
+ describe App1::ProcessConfig.daemon do
10
+ it { subject.should be_a(Tengine::Support::Config::Definition::Field)}
11
+ its(:type){ should == :boolean }
12
+ its(:__name__){ should == :daemon }
13
+ its(:description){ should == 'process works on background.'}
14
+ its(:default){ should == nil}
15
+ end
16
+
17
+ describe App1::ProcessConfig.pid_dir do
18
+ it { subject.should be_a(Tengine::Support::Config::Definition::Field)}
19
+ its(:type){ should == :directory }
20
+ its(:__name__){ should == :pid_dir }
21
+ its(:description){ should == 'path/to/dir for PID created.'}
22
+ its(:default){ should == nil}
23
+ end
24
+ end
25
+
26
+ context "dynamic" do
27
+ before(:all) do
28
+ @suite = build_suite1
29
+ end
30
+
31
+ subject do
32
+ @suite
33
+ end
34
+
35
+ describe "accessors" do
36
+ it { subject.action.should == nil}
37
+ it { subject.config.should == nil}
38
+ it { subject.process.should be_a(App1::ProcessConfig) }
39
+ it { subject.process.daemon.should == nil}
40
+ it { subject.process.pid_dir.should == nil}
41
+ it { subject.db.should be_a(Tengine::Support::Config::Mongoid::Connection) }
42
+ it { subject.db.host.should == "localhost"}
43
+ it { subject.db.port.should == 27017}
44
+ it { subject.db.username.should == nil}
45
+ it { subject.db.password.should == nil}
46
+ it { subject.db.database.should == "tengine_production"}
47
+ it { subject.event_queue.connection.host.should == "localhost"}
48
+ it { subject.event_queue.connection.port.should == 5672}
49
+ it { subject.event_queue.exchange.name.should == "tengine_event_exchange"}
50
+ it { subject.event_queue.exchange.type.should == 'direct'}
51
+ it { subject.event_queue.exchange.durable.should == true}
52
+ it { subject.event_queue.queue.name.should == "tengine_event_queue"}
53
+ it { subject.event_queue.queue.durable.should == true}
54
+ it { subject.log_common.output.should == nil}
55
+ it { subject.log_common.rotation.should == 3}
56
+ it { subject.log_common.rotation_size.should == 1024 * 1024}
57
+ it { subject.log_common.level.should == "info"}
58
+ it { subject.application_log.output.should == "STDOUT"}
59
+ it { subject.application_log.rotation.should == 3}
60
+ it { subject.application_log.rotation_size.should == 1024 * 1024}
61
+ it { subject.application_log.level.should == "info"}
62
+ end
63
+
64
+ it :to_hash do
65
+ subject.to_hash.should == {
66
+ :action => 'start',
67
+ :config => nil,
68
+ :process => {
69
+ :daemon => nil,
70
+ :pid_dir => nil,
71
+ },
72
+ :db => {
73
+ :host => 'localhost',
74
+ :port => 27017,
75
+ :username => nil,
76
+ :password => nil,
77
+ :database => 'tengine_production'
78
+ },
79
+ :event_queue => {
80
+ :connection => {
81
+ :host => 'localhost',
82
+ :port => 5672,
83
+ :vhost => nil,
84
+ :user => nil,
85
+ :pass => nil,
86
+ },
87
+ :exchange => {
88
+ :name => 'tengine_event_exchange',
89
+ :type => 'direct',
90
+ :durable => true,
91
+ },
92
+ :queue => {
93
+ :name => 'tengine_event_queue',
94
+ :durable => true,
95
+ },
96
+ },
97
+
98
+ :log_common => {
99
+ :output => nil ,
100
+ :rotation => 3 ,
101
+ :rotation_size => 1024 * 1024,
102
+ :level => 'info' ,
103
+ }.freeze,
104
+
105
+ :application_log => {
106
+ :output => "STDOUT",
107
+ :rotation=>3, :rotation_size=>1048576, :level=>"info"
108
+ }.freeze,
109
+
110
+ :process_stdout_log => {
111
+ :output => "STDOUT",
112
+ :rotation=>3, :rotation_size=>1048576, :level=>"info"
113
+ }.freeze,
114
+
115
+ :process_stderr_log => {
116
+ :output => "STDOUT",
117
+ :rotation=>3, :rotation_size=>1048576, :level=>"info"
118
+ }.freeze,
119
+ }
120
+ end
121
+
122
+ it "suite has children" do
123
+ subject.children.map(&:__name__).should == [
124
+ :action, :config,
125
+ :process, :db, :event_queue, :log_common,
126
+ :application_log, :process_stdout_log, :process_stderr_log, :separator10, :version, :help]
127
+ end
128
+
129
+ context "suite returns child by name" do
130
+ {
131
+ :process => App1::ProcessConfig,
132
+ :db => Tengine::Support::Config::Mongoid::Connection,
133
+ :event_queue => Tengine::Support::Config::Definition::Group,
134
+ [:event_queue, :connection] => NilClass,
135
+ [:event_queue, :exchange ] => NilClass,
136
+ [:event_queue, :queue ] => NilClass,
137
+ :log_common => Tengine::Support::Config::Logger,
138
+ :application_log => App1::LoggerConfig,
139
+ :process_stdout_log => App1::LoggerConfig,
140
+ :process_stderr_log => App1::LoggerConfig,
141
+ }.each do |name, klass|
142
+ it{ subject.child_by_name(name).should be_a(klass) }
143
+ end
144
+
145
+ {
146
+ :process => App1::ProcessConfig,
147
+ :db => Tengine::Support::Config::Mongoid::Connection,
148
+ :event_queue => Tengine::Support::Config::Definition::Group,
149
+ [:event_queue, :connection] => Tengine::Support::Config::Amqp::Connection,
150
+ [:event_queue, :exchange ] => Tengine::Support::Config::Amqp::Exchange,
151
+ [:event_queue, :queue ] => Tengine::Support::Config::Amqp::Queue,
152
+ :log_common => Tengine::Support::Config::Logger,
153
+ :application_log => App1::LoggerConfig,
154
+ :process_stdout_log => App1::LoggerConfig,
155
+ :process_stderr_log => App1::LoggerConfig,
156
+ }.each do |name_array, klass|
157
+ it{ subject.find(name_array).should be_a(klass) }
158
+ end
159
+ end
160
+
161
+ context "parent and children" do
162
+ it do
163
+ log_common = subject.find(:log_common)
164
+ application_log = subject.find(:application_log)
165
+ log_common.should_not == application_log
166
+ log_common.children.each do |log_common_child|
167
+ application_log_child = application_log.child_by_name(log_common_child.__name__)
168
+ application_log_child.should_not be_nil
169
+ application_log_child.__name__.should == log_common_child.__name__
170
+ application_log_child.object_id.should_not == log_common_child.object_id
171
+ application_log_child.__parent__.should == application_log
172
+ log_common_child.__parent__.should == log_common
173
+ end
174
+ end
175
+ end
176
+
177
+ context "dependencies" do
178
+ it do
179
+ application_log = subject.find(:application_log)
180
+ application_log.process_config.should_not be_nil
181
+ application_log.process_config.should be_a(App1::ProcessConfig)
182
+ application_log.log_common.should_not be_nil
183
+ application_log.log_common.should be_a(Tengine::Support::Config::Logger)
184
+ end
185
+ end
186
+
187
+ end
188
+ end
189
+
190
+ end