ernie 2.4.0 → 2.5.0

Sign up to get free protection for your applications and to get access to all the features.
data/History.txt CHANGED
@@ -1,3 +1,10 @@
1
+ = 2.5.0 / 2010-11-19
2
+ * Major Enhancements
3
+ * Enable multi-node mode (#11)
4
+ * Bug Fixes
5
+ * Properly determine whether function or module is missing.
6
+ * Spawn a process for receive_term to keep acceptor non-blocking.
7
+
1
8
  = 2.4.0 / 2010-05-21
2
9
  * Minor Additions
3
10
  * Add -E cli option for setting extra Erlang VM options
data/README.md CHANGED
@@ -59,6 +59,8 @@ Running
59
59
  -a, --access-log LOGFILE Access log file.
60
60
  -d, --detached Run as a daemon.
61
61
  -P, --pidfile PIDFILE Location to write pid file.
62
+ --name NAME Erlang process name.
63
+ --sname SNAME Erlang short process name.
62
64
  -E, --erlang ERLANG_OPTIONS Options passed to Erlang VM.
63
65
 
64
66
  Commands:
data/Rakefile CHANGED
@@ -1,67 +1,155 @@
1
1
  require 'rubygems'
2
2
  require 'rake'
3
+ require 'date'
3
4
 
4
- begin
5
- require 'jeweler'
6
- Jeweler::Tasks.new do |gem|
7
- gem.name = "ernie"
8
- gem.rubyforge_project = "ernie"
9
- gem.summary = %Q{Ernie is a BERT-RPC server implementation.}
10
- gem.description = %Q{Ernie is an Erlang/Ruby hybrid BERT-RPC server implementation packaged as a gem.}
11
- gem.email = "tom@mojombo.com"
12
- gem.homepage = "http://github.com/mojombo/ernie"
13
- gem.authors = ["Tom Preston-Werner"]
14
- gem.files.include(["ext"])
15
- gem.extensions << 'ext/extconf.rb'
16
- gem.add_dependency('bert', '>= 1.1.0')
17
- gem.add_dependency('bertrpc', '>= 1.0.0')
18
-
19
- # gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
20
- end
21
- rescue LoadError
22
- puts "Jeweler not available. Install it with: sudo gem install technicalpickles-jeweler -s http://gems.github.com"
5
+ #############################################################################
6
+ #
7
+ # Helper functions
8
+ #
9
+ #############################################################################
10
+
11
+ def name
12
+ @name ||= Dir['*.gemspec'].first.split('.').first
13
+ end
14
+
15
+ def version
16
+ line = File.read("lib/#{name}.rb")[/^\s*VERSION\s*=\s*.*/]
17
+ line.match(/.*VERSION\s*=\s*['"](.*)['"]/)[1]
18
+ end
19
+
20
+ def date
21
+ Date.today.to_s
22
+ end
23
+
24
+ def rubyforge_project
25
+ name
26
+ end
27
+
28
+ def gemspec_file
29
+ "#{name}.gemspec"
23
30
  end
24
31
 
32
+ def gem_file
33
+ "#{name}-#{version}.gem"
34
+ end
35
+
36
+ def replace_header(head, header_name)
37
+ head.sub!(/(\.#{header_name}\s*= ').*'/) { "#{$1}#{send(header_name)}'"}
38
+ end
39
+
40
+ #############################################################################
41
+ #
42
+ # Standard tasks
43
+ #
44
+ #############################################################################
45
+
46
+ task :default => :test
47
+
25
48
  require 'rake/testtask'
26
49
  Rake::TestTask.new(:test) do |test|
27
50
  test.libs << 'lib' << 'test'
28
- test.pattern = 'test/**/*_test.rb'
51
+ test.pattern = 'test/**/test_*.rb'
29
52
  test.verbose = true
30
53
  end
31
54
 
32
- begin
33
- require 'rcov/rcovtask'
34
- Rcov::RcovTask.new do |test|
35
- test.libs << 'test'
36
- test.pattern = 'test/**/*_test.rb'
37
- test.verbose = true
38
- end
39
- rescue LoadError
40
- task :rcov do
41
- abort "RCov is not available. In order to run rcov, you must: sudo gem install spicycode-rcov"
42
- end
55
+ desc "Generate RCov test coverage and open in your browser"
56
+ task :coverage do
57
+ require 'rcov'
58
+ sh "rm -fr coverage"
59
+ sh "rcov test/test_*.rb"
60
+ sh "open coverage/index.html"
43
61
  end
44
62
 
45
- task :default => :test
63
+ require 'rake/rdoctask'
64
+ Rake::RDocTask.new do |rdoc|
65
+ rdoc.rdoc_dir = 'rdoc'
66
+ rdoc.title = "#{name} #{version}"
67
+ rdoc.rdoc_files.include('README*')
68
+ rdoc.rdoc_files.include('lib/**/*.rb')
69
+ end
70
+
71
+ desc "Open an irb session preloaded with this library"
72
+ task :console do
73
+ sh "irb -rubygems -r ./lib/#{name}.rb"
74
+ end
46
75
 
47
- # require 'rake/rdoctask'
48
- # Rake::RDocTask.new do |rdoc|
49
- # if File.exist?('VERSION.yml')
50
- # config = YAML.load(File.read('VERSION.yml'))
51
- # version = "#{config[:major]}.#{config[:minor]}.#{config[:patch]}"
52
- # else
53
- # version = ""
54
- # end
55
- #
56
- # rdoc.rdoc_dir = 'rdoc'
57
- # rdoc.title = "ernie #{version}"
58
- # rdoc.rdoc_files.include('README*')
59
- # rdoc.rdoc_files.include('lib/**/*.rb')
60
- # end
76
+ #############################################################################
77
+ #
78
+ # Custom tasks (add your own tasks here)
79
+ #
80
+ #############################################################################
61
81
 
62
82
  task :ebuild do
63
83
  ERLC_TEST_FLAGS = ""
64
84
  ERLC_FLAGS = "-o ../ebin"
65
85
  cd "elib"
66
86
  sh "erlc #{ERLC_FLAGS} #{ERLC_TEST_FLAGS} #{Dir["**/*.erl"].join(" ")}"
67
- end
87
+ end
88
+
89
+ #############################################################################
90
+ #
91
+ # Packaging tasks
92
+ #
93
+ #############################################################################
94
+
95
+ desc "Create tag v#{version} and build and push #{gem_file} to Rubygems"
96
+ task :release => :build do
97
+ unless `git branch` =~ /^\* master$/
98
+ puts "You must be on the master branch to release!"
99
+ exit!
100
+ end
101
+ sh "git commit --allow-empty -a -m 'Release #{version}'"
102
+ sh "git tag v#{version}"
103
+ sh "git push origin master"
104
+ sh "git push origin v#{version}"
105
+ sh "gem push pkg/#{name}-#{version}.gem"
106
+ end
107
+
108
+ desc "Build #{gem_file} into the pkg directory"
109
+ task :build => :gemspec do
110
+ sh "mkdir -p pkg"
111
+ sh "gem build #{gemspec_file}"
112
+ sh "mv #{gem_file} pkg"
113
+ end
114
+
115
+ desc "Generate #{gemspec_file}"
116
+ task :gemspec => :validate do
117
+ # read spec file and split out manifest section
118
+ spec = File.read(gemspec_file)
119
+ head, manifest, tail = spec.split(" # = MANIFEST =\n")
120
+
121
+ # replace name version and date
122
+ replace_header(head, :name)
123
+ replace_header(head, :version)
124
+ replace_header(head, :date)
125
+ #comment this out if your rubyforge_project has a different name
126
+ replace_header(head, :rubyforge_project)
127
+
128
+ # determine file list from git ls-files
129
+ files = `git ls-files`.
130
+ split("\n").
131
+ sort.
132
+ reject { |file| file =~ /^\./ }.
133
+ reject { |file| file =~ /^(rdoc|pkg)/ }.
134
+ map { |file| " #{file}" }.
135
+ join("\n")
136
+
137
+ # piece file back together and write
138
+ manifest = " s.files = %w[\n#{files}\n ]\n"
139
+ spec = [head, manifest, tail].join(" # = MANIFEST =\n")
140
+ File.open(gemspec_file, 'w') { |io| io.write(spec) }
141
+ puts "Updated #{gemspec_file}"
142
+ end
143
+
144
+ desc "Validate #{gemspec_file}"
145
+ task :validate do
146
+ libfiles = Dir['lib/*'] - ["lib/#{name}.rb", "lib/#{name}"]
147
+ unless libfiles.empty?
148
+ puts "Directory `lib` should only contain a `#{name}.rb` file and `#{name}` dir."
149
+ exit!
150
+ end
151
+ unless Dir['VERSION*'].empty?
152
+ puts "A `VERSION` file at root level violates Gem best practices."
153
+ exit!
154
+ end
155
+ end
data/bin/ernie CHANGED
@@ -14,14 +14,10 @@ def code_paths
14
14
  DEFAULT_ERLANG_CODEPATHS.map {|n| "-pz #{rel(n)}" }.join(" ") + " \\"
15
15
  end
16
16
 
17
- def version
18
- yml = YAML.load(File.read(File.join(File.dirname(__FILE__), *%w[.. VERSION.yml])))
19
- "#{yml[:major]}.#{yml[:minor]}.#{yml[:patch]}"
20
- end
21
-
22
17
  require 'optparse'
23
18
  require 'pp'
24
19
  require 'yaml'
20
+ require 'ernie'
25
21
 
26
22
  help = <<HELP
27
23
  Ernie is an Erlang/Ruby BERT-RPC Server.
@@ -42,7 +38,7 @@ HELP
42
38
  options = {}
43
39
  OptionParser.new do |opts|
44
40
  opts.banner = help
45
- opts.version = version
41
+ opts.version = Ernie::VERSION
46
42
 
47
43
  opts.on("-c CONFIG", "--config CONFIG", "Config file") do |x|
48
44
  options[:config] = x
@@ -64,6 +60,14 @@ OptionParser.new do |opts|
64
60
  options[:detached] = true
65
61
  end
66
62
 
63
+ opts.on("--name NAME", "Erlang proccess name") do |x|
64
+ options[:name] = x
65
+ end
66
+
67
+ opts.on("--sname NAME", "Erlang short proccess name") do |x|
68
+ options[:sname] = x
69
+ end
70
+
67
71
  opts.on("-P", "--pidfile PIDFILE", "Location to write pid file.") do |x|
68
72
  options[:pidfile] = x
69
73
  end
@@ -99,9 +103,13 @@ else
99
103
  pidfile = options[:pidfile] ? "-ernie_server_app pidfile \"'#{options[:pidfile]}'\"" : ''
100
104
  detached = options[:detached] ? '-detached' : ''
101
105
  access_log = options[:access_log] ? "-ernie_server_app access_log '\"#{options[:access_log]}\"'" : ''
106
+ name = options[:name] ? "-name #{options[:name]}" : ''
107
+ sname = options[:sname] ? "-sname #{options[:sname]}" : ''
102
108
  erl_options = options[:erl_options]
103
109
 
104
110
  cmd = %Q{erl -boot start_sasl \
111
+ #{name} \
112
+ #{sname} \
105
113
  #{detached} \
106
114
  +Bc \
107
115
  +K true \
@@ -115,5 +123,6 @@ else
115
123
  -run ernie_server_app boot \
116
124
  #{erl_options}}.squeeze(' ')
117
125
  puts cmd
126
+ STDOUT.flush
118
127
  exec(cmd)
119
128
  end
@@ -18,19 +18,19 @@
18
18
  %%====================================================================
19
19
 
20
20
  start_link(Args) ->
21
- gen_server:start_link({global, ?MODULE}, ?MODULE, Args, []).
21
+ gen_server:start_link({local, ?MODULE}, ?MODULE, Args, []).
22
22
 
23
23
  start(Args) ->
24
24
  gen_server:start({global, ?MODULE}, ?MODULE, Args, []).
25
25
 
26
26
  acc(Request) ->
27
- gen_server:cast({global, ?MODULE}, {acc, Request}).
27
+ gen_server:cast(?MODULE, {acc, Request}).
28
28
 
29
29
  err(Request, Msg, Args) ->
30
- gen_server:cast({global, ?MODULE}, {err, Request, Msg, Args}).
30
+ gen_server:cast(?MODULE, {err, Request, Msg, Args}).
31
31
 
32
32
  reopen() ->
33
- gen_server:cast({global, ?MODULE}, reopen).
33
+ gen_server:cast(?MODULE, reopen).
34
34
 
35
35
  %%====================================================================
36
36
  %% gen_server callbacks
@@ -3,7 +3,7 @@
3
3
  -include_lib("ernie.hrl").
4
4
 
5
5
  %% api
6
- -export([start_link/1, start/1, process/1, kick/0, fin/0]).
6
+ -export([start_link/1, start/1, process/1, enqueue_request/1, kick/0, fin/0]).
7
7
 
8
8
  %% gen_server callbacks
9
9
  -export([init/1, handle_call/3, handle_cast/2, handle_info/2,
@@ -14,19 +14,22 @@
14
14
  %%====================================================================
15
15
 
16
16
  start_link(Args) ->
17
- gen_server:start_link({global, ?MODULE}, ?MODULE, Args, []).
17
+ gen_server:start_link({local, ?MODULE}, ?MODULE, Args, []).
18
18
 
19
19
  start(Args) ->
20
- gen_server:start({global, ?MODULE}, ?MODULE, Args, []).
20
+ gen_server:start({local, ?MODULE}, ?MODULE, Args, []).
21
21
 
22
22
  process(Sock) ->
23
- gen_server:cast({global, ?MODULE}, {process, Sock}).
23
+ gen_server:cast(?MODULE, {process, Sock}).
24
+
25
+ enqueue_request(Request) ->
26
+ gen_server:call(?MODULE, {enqueue_request, Request}).
24
27
 
25
28
  kick() ->
26
- gen_server:cast({global, ?MODULE}, kick).
29
+ gen_server:cast(?MODULE, kick).
27
30
 
28
31
  fin() ->
29
- gen_server:cast({global, ?MODULE}, fin).
32
+ gen_server:cast(?MODULE, fin).
30
33
 
31
34
  %%====================================================================
32
35
  %% gen_server callbacks
@@ -57,6 +60,16 @@ init([Port, Configs]) ->
57
60
  %% {stop, Reason, State}
58
61
  %% Description: Handling call messages
59
62
  %%--------------------------------------------------------------------
63
+ handle_call({enqueue_request, Request}, _From, State) ->
64
+ case Request#request.priority of
65
+ high ->
66
+ Hq2 = queue:in(Request, State#state.hq),
67
+ Lq2 = State#state.lq;
68
+ low ->
69
+ Hq2 = State#state.hq,
70
+ Lq2 = queue:in(Request, State#state.lq)
71
+ end,
72
+ {reply, ok, State#state{hq = Hq2, lq = Lq2}};
60
73
  handle_call(_Request, _From, State) ->
61
74
  {reply, ok, State}.
62
75
 
@@ -71,8 +84,9 @@ handle_cast({process, Sock}, State) ->
71
84
  lq = queue:len(State#state.lq),
72
85
  taccept = erlang:now()},
73
86
  Request = #request{sock = Sock, log = Log},
74
- State2 = receive_term(Request, State),
75
- {noreply, State2};
87
+ spawn(fun() -> receive_term(Request, State) end),
88
+ logger:debug("Spawned receiver~n", []),
89
+ {noreply, State};
76
90
  handle_cast(kick, State) ->
77
91
  case queue:out(State#state.hq) of
78
92
  {{value, Request}, Hq2} ->
@@ -175,20 +189,11 @@ receive_term(Request, State) ->
175
189
  _Any ->
176
190
  Request2 = Request#request{action = BinaryTerm},
177
191
  close_if_cast(Term, Request2),
178
- case Request2#request.priority of
179
- high ->
180
- Hq2 = queue:in(Request2, State#state.hq),
181
- Lq2 = State#state.lq;
182
- low ->
183
- Hq2 = State#state.hq,
184
- Lq2 = queue:in(Request2, State#state.lq)
185
- end,
186
- ernie_server:kick(),
187
- State#state{hq = Hq2, lq = Lq2}
192
+ ernie_server:enqueue_request(Request2),
193
+ ernie_server:kick()
188
194
  end;
189
195
  {error, closed} ->
190
- ok = gen_tcp:close(Sock),
191
- State
196
+ ok = gen_tcp:close(Sock)
192
197
  end.
193
198
 
194
199
  process_info(Request, priority, [Priority]) ->
@@ -200,16 +205,28 @@ process_request(Request, Priority, Q2, State) ->
200
205
  ActionTerm = bert:decode(Request#request.action),
201
206
  {_Type, Mod, _Fun, _Args} = ActionTerm,
202
207
  Specs = lists:filter(fun({X, _Id}) -> Mod =:= X end, State#state.map),
203
- process_module(ActionTerm, Specs, Request, Priority, Q2, State).
208
+ case Specs of
209
+ [] -> no_module(Mod, Request, Priority, Q2, State);
210
+ _Else -> process_module(ActionTerm, Specs, Request, Priority, Q2, State)
211
+ end.
204
212
 
205
- process_module(ActionTerm, [], Request, Priority, Q2, State) ->
206
- {_Type, Mod, _Fun, _Args} = ActionTerm,
213
+ no_module(Mod, Request, Priority, Q2, State) ->
207
214
  logger:debug("No such module ~p~n", [Mod]),
208
215
  Sock = Request#request.sock,
209
216
  Class = <<"ServerError">>,
210
217
  Message = list_to_binary(io_lib:format("No such module '~p'", [Mod])),
211
218
  gen_tcp:send(Sock, term_to_binary({error, [server, 0, Class, Message, []]})),
212
219
  ok = gen_tcp:close(Sock),
220
+ finish(Priority, Q2, State).
221
+
222
+ process_module(ActionTerm, [], Request, Priority, Q2, State) ->
223
+ {_Type, Mod, Fun, _Args} = ActionTerm,
224
+ logger:debug("No such function ~p:~p~n", [Mod, Fun]),
225
+ Sock = Request#request.sock,
226
+ Class = <<"ServerError">>,
227
+ Message = list_to_binary(io_lib:format("No such function '~p:~p'", [Mod, Fun])),
228
+ gen_tcp:send(Sock, term_to_binary({error, [server, 0, Class, Message, []]})),
229
+ ok = gen_tcp:close(Sock),
213
230
  finish(Priority, Q2, State);
214
231
  process_module(ActionTerm, Specs, Request, Priority, Q2, State) ->
215
232
  [{_Mod, Id} | OtherSpecs] = Specs,
data/elib/logger.erl CHANGED
@@ -15,28 +15,28 @@
15
15
  %%====================================================================
16
16
 
17
17
  start_link(Args) ->
18
- gen_server:start_link({global, ?MODULE}, ?MODULE, Args, []).
18
+ gen_server:start_link({local, ?MODULE}, ?MODULE, Args, []).
19
19
 
20
20
  start(Args) ->
21
- gen_server:start({global, ?MODULE}, ?MODULE, Args, []).
21
+ gen_server:start({local, ?MODULE}, ?MODULE, Args, []).
22
22
 
23
23
  set_log_level(Level) ->
24
- gen_server:call({global, ?MODULE}, {set_log_level, Level}).
24
+ gen_server:call(?MODULE, {set_log_level, Level}).
25
25
 
26
26
  debug(Msg, Args) ->
27
- gen_server:cast({global, ?MODULE}, {debug, Msg, Args}).
27
+ gen_server:cast(?MODULE, {debug, Msg, Args}).
28
28
 
29
29
  info(Msg, Args) ->
30
- gen_server:cast({global, ?MODULE}, {info, Msg, Args}).
30
+ gen_server:cast(?MODULE, {info, Msg, Args}).
31
31
 
32
32
  warn(Msg, Args) ->
33
- gen_server:cast({global, ?MODULE}, {warn, Msg, Args}).
33
+ gen_server:cast(?MODULE, {warn, Msg, Args}).
34
34
 
35
35
  error(Msg, Args) ->
36
- gen_server:cast({global, ?MODULE}, {error, Msg, Args}).
36
+ gen_server:cast(?MODULE, {error, Msg, Args}).
37
37
 
38
38
  fatal(Msg, Args) ->
39
- gen_server:cast({global, ?MODULE}, {fatal, Msg, Args}).
39
+ gen_server:cast(?MODULE, {fatal, Msg, Args}).
40
40
 
41
41
  %%====================================================================
42
42
  %% gen_server callbacks
data/ernie.gemspec CHANGED
@@ -1,95 +1,77 @@
1
- # Generated by jeweler
2
- # DO NOT EDIT THIS FILE DIRECTLY
3
- # Instead, edit Jeweler::Tasks in rakefile, and run the gemspec command
4
- # -*- encoding: utf-8 -*-
5
-
6
1
  Gem::Specification.new do |s|
7
- s.name = %q{ernie}
8
- s.version = "2.4.0"
9
-
2
+ s.specification_version = 2 if s.respond_to? :specification_version=
10
3
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
- s.authors = ["Tom Preston-Werner"]
12
- s.date = %q{2010-05-21}
13
- s.default_executable = %q{ernie}
14
- s.description = %q{Ernie is an Erlang/Ruby hybrid BERT-RPC server implementation packaged as a gem.}
15
- s.email = %q{tom@mojombo.com}
16
- s.executables = ["ernie"]
4
+ s.rubygems_version = '1.3.6'
5
+
6
+ s.name = 'ernie'
7
+ s.version = '2.5.0'
8
+ s.date = '2010-11-19'
9
+ s.rubyforge_project = 'ernie'
10
+
11
+ s.summary = "Ernie is a BERT-RPC server implementation."
12
+ s.description = "Ernie is an Erlang/Ruby hybrid BERT-RPC server implementation packaged as a gem."
13
+
14
+ s.authors = ["Tom Preston-Werner"]
15
+ s.email = 'tom@mojombo.com'
16
+ s.homepage = 'http://github.com/mojombo/ernie'
17
+
18
+ s.require_paths = %w[lib]
19
+
17
20
  s.extensions = ["ext/extconf.rb", "ext/extconf.rb"]
18
- s.extra_rdoc_files = [
19
- "LICENSE",
20
- "README.md"
21
- ]
22
- s.files = [
23
- ".document",
24
- ".gitignore",
25
- "History.txt",
26
- "LICENSE",
27
- "README.md",
28
- "Rakefile",
29
- "VERSION.yml",
30
- "bin/ernie",
31
- "contrib/ebench.erl",
32
- "ebin/ernie_server_app.app",
33
- "elib/asset_pool.erl",
34
- "elib/asset_pool_sup.erl",
35
- "elib/bert.erl",
36
- "elib/ernie.hrl",
37
- "elib/ernie_access_logger.erl",
38
- "elib/ernie_access_logger_sup.erl",
39
- "elib/ernie_admin.erl",
40
- "elib/ernie_config.erl",
41
- "elib/ernie_native.erl",
42
- "elib/ernie_server.erl",
43
- "elib/ernie_server_app.erl",
44
- "elib/ernie_server_sup.erl",
45
- "elib/logger.erl",
46
- "elib/logger_sup.erl",
47
- "elib/port_wrapper.erl",
48
- "ernie.gemspec",
49
- "examples/example.cfg",
50
- "examples/example.config",
51
- "examples/ext.erl",
52
- "examples/ext.rb",
53
- "examples/nat.erl",
54
- "ext/Makefile",
55
- "ext/extconf.rb",
56
- "lib/ernie.rb",
57
- "test/ernie_server_test.rb",
58
- "test/ernie_test.rb",
59
- "test/helper.rb",
60
- "test/load.rb",
61
- "test/sample/ext.rb",
62
- "test/sample/sample.cfg"
63
- ]
64
- s.homepage = %q{http://github.com/mojombo/ernie}
21
+
22
+ s.executables = ["ernie"]
23
+ s.default_executable = 'ernie'
24
+
65
25
  s.rdoc_options = ["--charset=UTF-8"]
66
- s.require_paths = ["lib"]
67
- s.rubyforge_project = %q{ernie}
68
- s.rubygems_version = %q{1.3.6}
69
- s.summary = %q{Ernie is a BERT-RPC server implementation.}
70
- s.test_files = [
71
- "test/ernie_server_test.rb",
72
- "test/ernie_test.rb",
73
- "test/helper.rb",
74
- "test/load.rb",
75
- "test/sample/ext.rb",
76
- "examples/ext.rb"
77
- ]
26
+ s.extra_rdoc_files = %w[LICENSE README.md]
78
27
 
79
- if s.respond_to? :specification_version then
80
- current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
81
- s.specification_version = 3
28
+ s.add_dependency('bert', [">= 1.1.0"])
29
+ s.add_dependency('bertrpc', [">= 1.0.0"])
82
30
 
83
- if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
84
- s.add_runtime_dependency(%q<bert>, [">= 1.1.0"])
85
- s.add_runtime_dependency(%q<bertrpc>, [">= 1.0.0"])
86
- else
87
- s.add_dependency(%q<bert>, [">= 1.1.0"])
88
- s.add_dependency(%q<bertrpc>, [">= 1.0.0"])
89
- end
90
- else
91
- s.add_dependency(%q<bert>, [">= 1.1.0"])
92
- s.add_dependency(%q<bertrpc>, [">= 1.0.0"])
93
- end
94
- end
31
+ s.add_development_dependency('shoulda', [">= 2.11.3", "< 3.0.0"])
32
+
33
+ # = MANIFEST =
34
+ s.files = %w[
35
+ History.txt
36
+ LICENSE
37
+ README.md
38
+ Rakefile
39
+ bin/ernie
40
+ contrib/ebench.erl
41
+ ebin/ernie_server_app.app
42
+ elib/asset_pool.erl
43
+ elib/asset_pool_sup.erl
44
+ elib/bert.erl
45
+ elib/ernie.hrl
46
+ elib/ernie_access_logger.erl
47
+ elib/ernie_access_logger_sup.erl
48
+ elib/ernie_admin.erl
49
+ elib/ernie_config.erl
50
+ elib/ernie_native.erl
51
+ elib/ernie_server.erl
52
+ elib/ernie_server_app.erl
53
+ elib/ernie_server_sup.erl
54
+ elib/logger.erl
55
+ elib/logger_sup.erl
56
+ elib/port_wrapper.erl
57
+ ernie.gemspec
58
+ examples/example.cfg
59
+ examples/example.config
60
+ examples/ext.erl
61
+ examples/ext.rb
62
+ examples/nat.erl
63
+ ext/Makefile
64
+ ext/extconf.rb
65
+ lib/ernie.rb
66
+ test/helper.rb
67
+ test/load.rb
68
+ test/sample/ext.rb
69
+ test/sample/intTest.erl
70
+ test/sample/sample.cfg
71
+ test/test_ernie.rb
72
+ test/test_ernie_server.rb
73
+ ]
74
+ # = MANIFEST =
95
75
 
76
+ s.test_files = s.files.select { |path| path =~ /^test\/test_.*\.rb/ }
77
+ end
data/lib/ernie.rb CHANGED
@@ -3,6 +3,8 @@ require 'bert'
3
3
  require 'logger'
4
4
 
5
5
  class Ernie
6
+ VERSION = '2.5.0'
7
+
6
8
  class << self
7
9
  attr_accessor :mods, :current_mod, :log
8
10
  attr_accessor :auto_start
@@ -185,13 +187,8 @@ class Ernie
185
187
  end
186
188
 
187
189
  def self.version
188
- yml = YAML.load(File.read(File.join(File.dirname(__FILE__), *%w[.. VERSION.yml])))
189
- "#{yml[:major]}.#{yml[:minor]}.#{yml[:patch]}"
190
- rescue
191
- 'unknown'
190
+ VERSION
192
191
  end
193
-
194
- VERSION = self.version
195
192
  end
196
193
 
197
194
  class Ernie::ServerError < StandardError; end
data/test/helper.rb CHANGED
@@ -2,7 +2,7 @@ require 'rubygems'
2
2
  require 'test/unit'
3
3
  require 'shoulda'
4
4
 
5
- ERNIE_ROOT = File.join(File.dirname(__FILE__), *%w[..])
5
+ ERNIE_ROOT = File.expand_path(File.join(File.dirname(__FILE__), *%w[..]))
6
6
 
7
7
  $:.unshift(File.join(ERNIE_ROOT, 'lib'))
8
8
 
@@ -0,0 +1,60 @@
1
+ -module(intTest).
2
+
3
+ -export([zeronary/0, unary/1, binary/2, ternary/3, big/1, set_state/1, get_state/0, connect_nodes/0, sleep/1]).
4
+
5
+ connect_nodes() ->
6
+ net_adm:ping('ernie0@127.0.0.1').
7
+
8
+ zeronary() ->
9
+ foo.
10
+
11
+ unary(A) ->
12
+ A.
13
+
14
+ binary(A,B) ->
15
+ A + B.
16
+
17
+ ternary(A,B,C) ->
18
+ A + B + C.
19
+
20
+ big(A) ->
21
+ string:copies("a", A).
22
+
23
+ sleep(Time) ->
24
+ receive after Time ->
25
+ ok
26
+ end.
27
+
28
+ get_state() ->
29
+ case catch global:send(test_saved_state, {get_state, self()}) of
30
+ {'EXIT',{badarg, _}} ->
31
+ {error, no_record};
32
+ _ ->
33
+ receive
34
+ {ok, State} ->
35
+ State
36
+ after 1000 ->
37
+ {error, timeout}
38
+ end
39
+ end.
40
+
41
+ set_state(State) ->
42
+ spawn(fun() -> wrapper(State) end),
43
+ ok.
44
+
45
+ wrapper(State) ->
46
+ case global:register_name(test_saved_state, self()) of
47
+ no ->
48
+ global:send(test_saved_state, {set_state, State});
49
+ yes ->
50
+ recv(State)
51
+ end.
52
+
53
+ recv(State) ->
54
+ receive
55
+ {set_state, NewState} ->
56
+ recv(NewState);
57
+ {get_state, Pid} ->
58
+ Pid ! {ok, State},
59
+ recv(State)
60
+ end.
@@ -1,4 +1,8 @@
1
1
  [{module, ext},
2
2
  {type, external},
3
- {command, "ruby /Users/tom/dev/mojombo/ernie/test/sample/ext.rb"},
4
- {count, 1}].
3
+ {command, "ruby test/sample/ext.rb"},
4
+ {count, 1}].
5
+ [{module, intTest},
6
+ {type, native},
7
+ {codepaths, ["test/sample"]}
8
+ ].
File without changes
@@ -0,0 +1,221 @@
1
+ require File.dirname(__FILE__) + '/helper'
2
+
3
+ PORT = 27118
4
+
5
+ class ErnieServerTest < Test::Unit::TestCase
6
+
7
+ # global setup
8
+ def setup
9
+ @servers ||= []
10
+ Dir.chdir(ERNIE_ROOT)
11
+ `erlc -o test/sample #{ERNIE_ROOT}/test/sample/intTest.erl`
12
+ Signal.trap("INT") do
13
+ puts "Shutting Down"
14
+ shutdown_servers
15
+ teardown
16
+ exit
17
+ end
18
+ end
19
+
20
+ def teardown
21
+ `rm test/sample/intTest.beam`
22
+ end
23
+
24
+ context "An Ernie Server" do
25
+ setup do
26
+ start_server
27
+ end
28
+
29
+ context "call" do
30
+ should "handle zeronary" do
31
+ assert_equal :foo, svc.call.ext.zeronary
32
+ assert_equal :foo, svc.call.intTest.zeronary
33
+ end
34
+
35
+ should "handle unary" do
36
+ assert_equal 5, svc.call.ext.unary(5)
37
+ assert_equal 5, svc.call.intTest.unary(5)
38
+ end
39
+
40
+ should "handle binary" do
41
+ assert_equal 7, svc.call.ext.binary(5, 2)
42
+ assert_equal 7, svc.call.intTest.binary(5, 2)
43
+ end
44
+
45
+ should "handle ternary" do
46
+ assert_equal 10, svc.call.ext.ternary(5, 2, 3)
47
+ assert_equal 10, svc.call.intTest.ternary(5, 2, 3)
48
+ end
49
+
50
+ should "handle massive binaries" do
51
+ assert_equal 8 * 1024 * 1024, svc.call.ext.big(8 * 1024 * 1024).size
52
+ assert_equal 8 * 1024 * 1024, svc.call.intTest.big(8 * 1024 * 1024).size
53
+ end
54
+
55
+ should "not block on internal modules" do
56
+ time = Time.now
57
+ svc.call.intTest.sleep(1000)
58
+ assert(Time.now >= time + 1)
59
+
60
+ time = Time.now
61
+ svc.cast.intTest.sleep(1000)
62
+ svc.cast.intTest.sleep(1000)
63
+ svc.cast.intTest.sleep(1000)
64
+ svc.call.intTest.zeronary
65
+ assert(Time.now < time + 1)
66
+ end
67
+
68
+ should "get an error on missing module" do
69
+ begin
70
+ svc.call.failboat.mcfail(:fail)
71
+ fail "Expected a BERTRPC::ServerError"
72
+ rescue BERTRPC::ServerError => e
73
+ assert_equal "No such module 'failboat'", e.message
74
+ else
75
+ assert false, 'failed to raise on missing module'
76
+ end
77
+ end
78
+
79
+ should "get an error on missing function" do
80
+ begin
81
+ svc.call.ext.mcfail(:fail)
82
+ fail "Expected a BERTRPC::ServerError"
83
+ rescue BERTRPC::ServerError => e
84
+ assert_equal "No such function 'ext:mcfail'", e.message
85
+ else
86
+ assert false, 'failed to raise on missing function'
87
+ end
88
+
89
+ begin
90
+ svc.call.intTest.mcfail(:fail)
91
+ fail "Expected a BERTRPC::ServerError"
92
+ rescue BERTRPC::ServerError => e
93
+ assert_equal "No such function 'intTest:mcfail'", e.message
94
+ else
95
+ assert false, 'failed to raise on missing function'
96
+ end
97
+ end
98
+ end
99
+
100
+ context "cast" do
101
+ should "be received and return immediately" do
102
+ t0 = Time.now
103
+ assert_equal nil, svc.cast.ext.set_state(7)
104
+ assert Time.now - t0 < 1
105
+ assert_equal 7, svc.call.ext.get_state
106
+
107
+ t0 = Time.now
108
+ assert_equal nil, svc.cast.intTest.set_state(7)
109
+ assert Time.now - t0 < 1
110
+ sleep 0.25
111
+ assert_equal 7, svc.call.intTest.get_state
112
+ end
113
+ end
114
+
115
+ teardown do
116
+ shutdown_server
117
+ end
118
+ end
119
+
120
+ context "Two Ernie Servers" do
121
+ setup do
122
+ start_servers(2)
123
+ @servers.each do |svc|
124
+ svc.cast.intTest.connect_nodes
125
+ end
126
+ end
127
+
128
+ context "call" do
129
+
130
+ should "handle zeronary" do
131
+ @servers.each do |svc|
132
+ assert_equal :foo, svc.call.ext.zeronary
133
+ assert_equal :foo, svc.call.intTest.zeronary
134
+ end
135
+ end
136
+
137
+ should "handle unary" do
138
+ @servers.each do |svc|
139
+ assert_equal 5, svc.call.ext.unary(5)
140
+ assert_equal 5, svc.call.intTest.unary(5)
141
+ end
142
+ end
143
+
144
+ should "handle binary" do
145
+ @servers.each do |svc|
146
+ assert_equal 7, svc.call.ext.binary(5, 2)
147
+ assert_equal 7, svc.call.intTest.binary(5, 2)
148
+ end
149
+ end
150
+
151
+ should "handle ternary" do
152
+ @servers.each do |svc|
153
+ assert_equal 10, svc.call.ext.ternary(5, 2, 3)
154
+ assert_equal 10, svc.call.intTest.ternary(5, 2, 3)
155
+ end
156
+ end
157
+
158
+ should "handle massive binaries" do
159
+ @servers.each do |svc|
160
+ assert_equal 8 * 1024 * 1024, svc.call.ext.big(8 * 1024 * 1024).size
161
+ assert_equal 8 * 1024 * 1024, svc.call.intTest.big(8 * 1024 * 1024).size
162
+ end
163
+ end
164
+
165
+ should "make joined erlang nodes possible" do
166
+ assert_equal nil, @servers.first.cast.intTest.set_state(7)
167
+ sleep 0.25
168
+ assert_equal 7, @servers.last.call.intTest.get_state
169
+ end
170
+
171
+ end
172
+
173
+ teardown do
174
+ shutdown_servers(2)
175
+ end
176
+ end
177
+
178
+ protected
179
+
180
+ def svc
181
+ @servers[rand(@servers.size-1)]
182
+ end
183
+
184
+ def start_server
185
+ start_servers(1)
186
+ end
187
+
188
+ def shutdown_server
189
+ shutdown_servers(1)
190
+ end
191
+
192
+ def start_servers(n = 1)
193
+ n.times do
194
+ `#{ERNIE_ROOT}/bin/ernie -c #{ERNIE_ROOT}/test/sample/sample.cfg \
195
+ -P /tmp/ernie#{@servers.size}.pid \
196
+ -p #{PORT + @servers.size} \
197
+ --name ernie#{@servers.size}@127.0.0.1 \
198
+ -d`
199
+
200
+ @servers << BERTRPC::Service.new('localhost', PORT + @servers.size)
201
+ loop do
202
+ begin
203
+ @servers.last.call.ext.zeronary
204
+ break
205
+ rescue Object => e
206
+ sleep 0.1
207
+ end
208
+ end
209
+ end
210
+ end
211
+
212
+ def shutdown_servers(n = nil)
213
+ start = @servers.size - 1
214
+ last = start - (n || start)
215
+ (start).downto(last >= 0 ? last : 0) do |i|
216
+ pid = File.read("/tmp/ernie#{i}.pid")
217
+ `kill -9 #{pid}`
218
+ end
219
+ end
220
+
221
+ end
metadata CHANGED
@@ -1,12 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ernie
3
3
  version: !ruby/object:Gem::Version
4
+ hash: 27
4
5
  prerelease: false
5
6
  segments:
6
7
  - 2
7
- - 4
8
+ - 5
8
9
  - 0
9
- version: 2.4.0
10
+ version: 2.5.0
10
11
  platform: ruby
11
12
  authors:
12
13
  - Tom Preston-Werner
@@ -14,16 +15,18 @@ autorequire:
14
15
  bindir: bin
15
16
  cert_chain: []
16
17
 
17
- date: 2010-05-21 00:00:00 -07:00
18
+ date: 2010-11-19 00:00:00 -06:00
18
19
  default_executable: ernie
19
20
  dependencies:
20
21
  - !ruby/object:Gem::Dependency
21
22
  name: bert
22
23
  prerelease: false
23
24
  requirement: &id001 !ruby/object:Gem::Requirement
25
+ none: false
24
26
  requirements:
25
27
  - - ">="
26
28
  - !ruby/object:Gem::Version
29
+ hash: 19
27
30
  segments:
28
31
  - 1
29
32
  - 1
@@ -35,9 +38,11 @@ dependencies:
35
38
  name: bertrpc
36
39
  prerelease: false
37
40
  requirement: &id002 !ruby/object:Gem::Requirement
41
+ none: false
38
42
  requirements:
39
43
  - - ">="
40
44
  - !ruby/object:Gem::Version
45
+ hash: 23
41
46
  segments:
42
47
  - 1
43
48
  - 0
@@ -45,6 +50,30 @@ dependencies:
45
50
  version: 1.0.0
46
51
  type: :runtime
47
52
  version_requirements: *id002
53
+ - !ruby/object:Gem::Dependency
54
+ name: shoulda
55
+ prerelease: false
56
+ requirement: &id003 !ruby/object:Gem::Requirement
57
+ none: false
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ hash: 37
62
+ segments:
63
+ - 2
64
+ - 11
65
+ - 3
66
+ version: 2.11.3
67
+ - - <
68
+ - !ruby/object:Gem::Version
69
+ hash: 7
70
+ segments:
71
+ - 3
72
+ - 0
73
+ - 0
74
+ version: 3.0.0
75
+ type: :development
76
+ version_requirements: *id003
48
77
  description: Ernie is an Erlang/Ruby hybrid BERT-RPC server implementation packaged as a gem.
49
78
  email: tom@mojombo.com
50
79
  executables:
@@ -56,13 +85,10 @@ extra_rdoc_files:
56
85
  - LICENSE
57
86
  - README.md
58
87
  files:
59
- - .document
60
- - .gitignore
61
88
  - History.txt
62
89
  - LICENSE
63
90
  - README.md
64
91
  - Rakefile
65
- - VERSION.yml
66
92
  - bin/ernie
67
93
  - contrib/ebench.erl
68
94
  - ebin/ernie_server_app.app
@@ -90,12 +116,13 @@ files:
90
116
  - ext/Makefile
91
117
  - ext/extconf.rb
92
118
  - lib/ernie.rb
93
- - test/ernie_server_test.rb
94
- - test/ernie_test.rb
95
119
  - test/helper.rb
96
120
  - test/load.rb
97
121
  - test/sample/ext.rb
122
+ - test/sample/intTest.erl
98
123
  - test/sample/sample.cfg
124
+ - test/test_ernie.rb
125
+ - test/test_ernie_server.rb
99
126
  has_rdoc: true
100
127
  homepage: http://github.com/mojombo/ernie
101
128
  licenses: []
@@ -106,30 +133,30 @@ rdoc_options:
106
133
  require_paths:
107
134
  - lib
108
135
  required_ruby_version: !ruby/object:Gem::Requirement
136
+ none: false
109
137
  requirements:
110
138
  - - ">="
111
139
  - !ruby/object:Gem::Version
140
+ hash: 3
112
141
  segments:
113
142
  - 0
114
143
  version: "0"
115
144
  required_rubygems_version: !ruby/object:Gem::Requirement
145
+ none: false
116
146
  requirements:
117
147
  - - ">="
118
148
  - !ruby/object:Gem::Version
149
+ hash: 3
119
150
  segments:
120
151
  - 0
121
152
  version: "0"
122
153
  requirements: []
123
154
 
124
155
  rubyforge_project: ernie
125
- rubygems_version: 1.3.6
156
+ rubygems_version: 1.3.7
126
157
  signing_key:
127
- specification_version: 3
158
+ specification_version: 2
128
159
  summary: Ernie is a BERT-RPC server implementation.
129
160
  test_files:
130
- - test/ernie_server_test.rb
131
- - test/ernie_test.rb
132
- - test/helper.rb
133
- - test/load.rb
134
- - test/sample/ext.rb
135
- - examples/ext.rb
161
+ - test/test_ernie.rb
162
+ - test/test_ernie_server.rb
data/.document DELETED
@@ -1,5 +0,0 @@
1
- README.md
2
- lib/**/*.rb
3
- bin/*
4
- features/**/*.feature
5
- LICENSE
data/.gitignore DELETED
@@ -1,2 +0,0 @@
1
- *.beam
2
- pkg
data/VERSION.yml DELETED
@@ -1,5 +0,0 @@
1
- ---
2
- :minor: 4
3
- :build:
4
- :patch: 0
5
- :major: 2
@@ -1,77 +0,0 @@
1
- require File.dirname(__FILE__) + '/helper'
2
-
3
- PORT = 27118
4
-
5
- class ErnieServerTest < Test::Unit::TestCase
6
- context "An Ernie Server" do
7
- setup do
8
- `#{ERNIE_ROOT}/bin/ernie -c #{ERNIE_ROOT}/test/sample/sample.cfg \
9
- -P /tmp/ernie.pid \
10
- -p #{PORT} \
11
- -d`
12
- @svc = BERTRPC::Service.new('localhost', PORT)
13
- loop do
14
- begin
15
- @svc.call.ext.zeronary
16
- break
17
- rescue Object => e
18
- sleep 0.1
19
- end
20
- end
21
- end
22
-
23
- context "call" do
24
- should "handle zeronary" do
25
- assert_equal :foo, @svc.call.ext.zeronary
26
- end
27
-
28
- should "handle unary" do
29
- assert_equal 5, @svc.call.ext.unary(5)
30
- end
31
-
32
- should "handle binary" do
33
- assert_equal 7, @svc.call.ext.binary(5, 2)
34
- end
35
-
36
- should "handle ternary" do
37
- assert_equal 10, @svc.call.ext.ternary(5, 2, 3)
38
- end
39
-
40
- should "handle massive binaries" do
41
- assert_equal 8 * 1024 * 1024, @svc.call.ext.big(8 * 1024 * 1024).size
42
- end
43
-
44
- should "get an error on missing module" do
45
- begin
46
- @svc.call.failboat.mcfail(:fail)
47
- fail "Expected a BERTRPC::ServerError"
48
- rescue BERTRPC::ServerError => e
49
- assert_equal "No such module 'failboat'", e.message
50
- end
51
- end
52
-
53
- should "get an error on missing function" do
54
- begin
55
- @svc.call.ext.mcfail(:fail)
56
- fail "Expected a BERTRPC::ServerError"
57
- rescue BERTRPC::ServerError => e
58
- assert_equal "No such function 'ext:mcfail'", e.message
59
- end
60
- end
61
- end
62
-
63
- context "cast" do
64
- should "be received and return immediately" do
65
- t0 = Time.now
66
- assert_equal nil, @svc.cast.ext.set_state(7)
67
- assert Time.now - t0 < 1
68
- assert_equal 7, @svc.call.ext.get_state
69
- end
70
- end
71
-
72
- teardown do
73
- pid = File.read('/tmp/ernie.pid')
74
- `kill -9 #{pid}`
75
- end
76
- end
77
- end