hydra 0.2.0 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/VERSION +1 -1
- data/hydra.gemspec +8 -2
- data/lib/hydra/io.rb +15 -2
- data/lib/hydra/message.rb +32 -6
- data/lib/hydra/message/runner_messages.rb +36 -0
- data/lib/hydra/pipe.rb +8 -4
- data/lib/hydra/runner.rb +25 -1
- data/lib/hydra/ssh.rb +10 -13
- data/test/helper.rb +1 -0
- data/test/sample_tests/assert_true.rb +7 -0
- data/test/sample_tests/write_file.rb +10 -0
- data/test/test_message.rb +31 -0
- data/test/test_runner.rb +23 -5
- metadata +8 -2
- data/lib/hydra/message/runner_requests_file.rb +0 -7
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.
|
1
|
+
0.3.0
|
data/hydra.gemspec
CHANGED
@@ -5,7 +5,7 @@
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = %q{hydra}
|
8
|
-
s.version = "0.
|
8
|
+
s.version = "0.3.0"
|
9
9
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
11
|
s.authors = ["Nick Gauthier"]
|
@@ -29,12 +29,15 @@ Gem::Specification.new do |s|
|
|
29
29
|
"lib/hydra.rb",
|
30
30
|
"lib/hydra/io.rb",
|
31
31
|
"lib/hydra/message.rb",
|
32
|
-
"lib/hydra/message/
|
32
|
+
"lib/hydra/message/runner_messages.rb",
|
33
33
|
"lib/hydra/pipe.rb",
|
34
34
|
"lib/hydra/runner.rb",
|
35
35
|
"lib/hydra/ssh.rb",
|
36
36
|
"test/echo_the_dolphin.rb",
|
37
37
|
"test/helper.rb",
|
38
|
+
"test/sample_tests/assert_true.rb",
|
39
|
+
"test/sample_tests/write_file.rb",
|
40
|
+
"test/test_message.rb",
|
38
41
|
"test/test_pipe.rb",
|
39
42
|
"test/test_runner.rb",
|
40
43
|
"test/test_ssh.rb"
|
@@ -47,8 +50,11 @@ Gem::Specification.new do |s|
|
|
47
50
|
s.test_files = [
|
48
51
|
"test/test_ssh.rb",
|
49
52
|
"test/helper.rb",
|
53
|
+
"test/test_message.rb",
|
50
54
|
"test/test_pipe.rb",
|
51
55
|
"test/test_runner.rb",
|
56
|
+
"test/sample_tests/write_file.rb",
|
57
|
+
"test/sample_tests/assert_true.rb",
|
52
58
|
"test/echo_the_dolphin.rb"
|
53
59
|
]
|
54
60
|
|
data/lib/hydra/io.rb
CHANGED
@@ -1,6 +1,12 @@
|
|
1
1
|
module Hydra #:nodoc:
|
2
|
+
# Module that implemets methods that auto-serialize and deserialize messaging
|
3
|
+
# objects.
|
2
4
|
module MessagingIO
|
3
|
-
# Read a
|
5
|
+
# Read a Message from the input IO object. Automatically build
|
6
|
+
# a message from the response and return it.
|
7
|
+
#
|
8
|
+
# IO.gets
|
9
|
+
# => Hydra::Message # or subclass
|
4
10
|
def gets
|
5
11
|
raise IOError unless @reader
|
6
12
|
message = @reader.gets
|
@@ -8,7 +14,9 @@ module Hydra #:nodoc:
|
|
8
14
|
return Message.build(eval(message.chomp))
|
9
15
|
end
|
10
16
|
|
11
|
-
# Write a
|
17
|
+
# Write a Message to the output IO object. It will automatically
|
18
|
+
# serialize a Message object.
|
19
|
+
# IO.write Hydra::Message.new
|
12
20
|
def write(message)
|
13
21
|
raise IOError unless @writer
|
14
22
|
raise UnprocessableMessage unless message.is_a?(Hydra::Message)
|
@@ -19,13 +27,18 @@ module Hydra #:nodoc:
|
|
19
27
|
end
|
20
28
|
end
|
21
29
|
|
30
|
+
# Closes the IO object.
|
22
31
|
def close
|
23
32
|
@reader.close if @reader
|
24
33
|
@writer.close if @writer
|
25
34
|
end
|
26
35
|
|
36
|
+
# IO will return this error if it cannot process a message.
|
37
|
+
# For example, if you tried to write a string, it would fail,
|
38
|
+
# because the string is not a message.
|
27
39
|
class UnprocessableMessage < RuntimeError
|
28
40
|
attr_accessor :message
|
41
|
+
# Allow a custom message for the exception.
|
29
42
|
def initialize(message = "Message expected")
|
30
43
|
@message = message
|
31
44
|
end
|
data/lib/hydra/message.rb
CHANGED
@@ -1,18 +1,44 @@
|
|
1
1
|
module Hydra #:nodoc:
|
2
|
-
|
2
|
+
# Base message object. Used to pass messages with parameters around
|
3
|
+
# via IO objects.
|
4
|
+
# class MyMessage < Hydra::Message
|
5
|
+
# attr_accessor :my_var
|
6
|
+
# def serialize
|
7
|
+
# super(:my_var => @my_var)
|
8
|
+
# end
|
9
|
+
# end
|
10
|
+
# m = MyMessage.new(:my_var => 'my value')
|
11
|
+
# m.my_var
|
12
|
+
# => "my value"
|
13
|
+
# m.serialize
|
14
|
+
# => "{:class=>TestMessage::MyMessage, :my_var=>\"my value\"}"
|
15
|
+
# Hydra::Message.build(eval(@m.serialize)).my_var
|
16
|
+
# => "my value"
|
17
|
+
class Message
|
18
|
+
# Create a new message. Opts is a hash where the keys
|
19
|
+
# are attributes of the message and the values are
|
20
|
+
# set to the attribute.
|
3
21
|
def initialize(opts = {})
|
4
|
-
opts.each do |
|
5
|
-
self.send(
|
22
|
+
opts.each do |variable,value|
|
23
|
+
self.send("#{variable}=",value)
|
6
24
|
end
|
7
25
|
end
|
26
|
+
|
27
|
+
# Build a message from a hash. The hash must contain
|
28
|
+
# the :class symbol, which is the class of the message
|
29
|
+
# that it will build to.
|
8
30
|
def self.build(hash)
|
9
31
|
hash.delete(:class).new(hash)
|
10
32
|
end
|
11
33
|
|
34
|
+
# Serialize the message for output on an IO channel.
|
35
|
+
# This is really just a string representation of a hash
|
36
|
+
# with no newlines. It adds in the class automatically
|
12
37
|
def serialize(opts = {})
|
13
|
-
opts
|
14
|
-
opts.inspect
|
38
|
+
opts.merge({:class => self.class}).inspect
|
15
39
|
end
|
16
40
|
end
|
17
41
|
end
|
18
|
-
|
42
|
+
|
43
|
+
require 'hydra/message/runner_messages'
|
44
|
+
|
@@ -0,0 +1,36 @@
|
|
1
|
+
module Hydra #:nodoc:
|
2
|
+
module Messages #:nodoc:
|
3
|
+
module Runner #:nodoc:
|
4
|
+
# Message indicating that a Runner needs a file to run
|
5
|
+
class RequestFile < Hydra::Message
|
6
|
+
end
|
7
|
+
|
8
|
+
# Message telling the Runner to run a file
|
9
|
+
class RunFile < Hydra::Message
|
10
|
+
attr_accessor :file
|
11
|
+
def serialize #:nodoc:
|
12
|
+
super(:file => @file)
|
13
|
+
end
|
14
|
+
def handle(runner) #:nodoc:
|
15
|
+
runner.run_file(@file)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
# Message for the Runner to respond with its results
|
20
|
+
class Results < Hydra::Message
|
21
|
+
attr_accessor :output
|
22
|
+
attr_accessor :file
|
23
|
+
def serialize #:nodoc:
|
24
|
+
super(:output => @output, :file => @file)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
# Message to tell the Runner to shut down
|
29
|
+
class Shutdown < Hydra::Message
|
30
|
+
def handle(runner) #:nodoc:
|
31
|
+
runner.stop
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
data/lib/hydra/pipe.rb
CHANGED
@@ -2,15 +2,19 @@ require 'hydra/io'
|
|
2
2
|
module Hydra #:nodoc:
|
3
3
|
# Read and write between two processes via pipes. For example:
|
4
4
|
# @pipe = Hydra::Pipe.new
|
5
|
-
# Process.fork do
|
5
|
+
# @child = Process.fork do
|
6
6
|
# @pipe.identify_as_child
|
7
|
-
#
|
8
|
-
# puts "A message from my parent:\n#{@pipe.gets}"
|
7
|
+
# puts "A message from my parent:\n#{@pipe.gets.text}"
|
9
8
|
# @pipe.close
|
10
9
|
# end
|
11
10
|
# @pipe.identify_as_parent
|
12
|
-
# @pipe.write "Hello
|
11
|
+
# @pipe.write Hydra::Messages::TestMessage.new(:text => "Hello!")
|
13
12
|
# @pipe.close
|
13
|
+
#
|
14
|
+
# Note that the TestMessage class is only available in tests, and
|
15
|
+
# not in Hydra by default.
|
16
|
+
#
|
17
|
+
#
|
14
18
|
# When the process forks, the pipe is copied. When a pipe is
|
15
19
|
# identified as a parent or child, it is choosing which ends
|
16
20
|
# of the pipe to use.
|
data/lib/hydra/runner.rb
CHANGED
@@ -1,8 +1,32 @@
|
|
1
1
|
module Hydra #:nodoc:
|
2
|
+
# Hydra class responsible for running test files
|
2
3
|
class Runner
|
4
|
+
# Boot up a runner. It takes an IO object (generally a pipe from its
|
5
|
+
# parent) to send it messages on which files to execute.
|
3
6
|
def initialize(io)
|
4
7
|
@io = io
|
5
|
-
@io.write Hydra::Messages::
|
8
|
+
@io.write Hydra::Messages::Runner::RequestFile.new
|
9
|
+
process_messages
|
10
|
+
end
|
11
|
+
|
12
|
+
# The runner will continually read messages and handle them.
|
13
|
+
def process_messages
|
14
|
+
@running = true
|
15
|
+
while @running
|
16
|
+
message = @io.gets
|
17
|
+
message.handle(self) if message
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
# Run a test file and report the results
|
22
|
+
def run_file(file)
|
23
|
+
`ruby #{file}`
|
24
|
+
@io.write Hydra::Messages::Runner::Results.new(:output => "Finished", :file => file)
|
25
|
+
end
|
26
|
+
|
27
|
+
# Stop running
|
28
|
+
def stop
|
29
|
+
@running = false
|
6
30
|
end
|
7
31
|
end
|
8
32
|
end
|
data/lib/hydra/ssh.rb
CHANGED
@@ -2,20 +2,17 @@ require 'open3'
|
|
2
2
|
require 'hydra/io'
|
3
3
|
module Hydra #:nodoc:
|
4
4
|
# Read and write with an ssh connection. For example:
|
5
|
-
#
|
6
|
-
#
|
7
|
-
#
|
8
|
-
#
|
5
|
+
# @ssh = Hydra::SSH.new(
|
6
|
+
# 'localhost', # connect to this machine
|
7
|
+
# '/home/user', # move to the home directory
|
8
|
+
# "ruby hydra/test/echo_the_dolphin.rb" # run the echo script
|
9
|
+
# )
|
10
|
+
# @message = Hydra::Messages::TestMessage.new("Hey there!")
|
11
|
+
# @ssh.write @message
|
12
|
+
# puts @ssh.gets.text
|
13
|
+
# => "Hey there!"
|
9
14
|
#
|
10
|
-
#
|
11
|
-
# example:
|
12
|
-
# @ssh = Hydra::SSH.new('nick@nite')
|
13
|
-
# @ssh.write('irb')
|
14
|
-
# @ssh.write("5+3")
|
15
|
-
# @ssh.gets
|
16
|
-
# => "5+3\n" # because irb echoes commands
|
17
|
-
# @ssh.gets
|
18
|
-
# => "8" # the output from irb
|
15
|
+
# Note that what ever process you run should respond with Hydra messages.
|
19
16
|
class SSH
|
20
17
|
include Open3
|
21
18
|
include Hydra::MessagingIO
|
data/test/helper.rb
CHANGED
@@ -0,0 +1,31 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), 'helper')
|
2
|
+
|
3
|
+
class TestMessage < Test::Unit::TestCase
|
4
|
+
class MyMessage < Hydra::Message
|
5
|
+
attr_accessor :my_var
|
6
|
+
def serialize
|
7
|
+
super(:my_var => @my_var)
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
context "with a message" do
|
12
|
+
setup do
|
13
|
+
@m = MyMessage.new(:my_var => 'my value')
|
14
|
+
end
|
15
|
+
should "set values" do
|
16
|
+
assert_equal 'my value', @m.my_var
|
17
|
+
end
|
18
|
+
should "serialize" do
|
19
|
+
assert_equal(
|
20
|
+
{:class=>TestMessage::MyMessage, :my_var=>"my value"},
|
21
|
+
eval(@m.serialize)
|
22
|
+
)
|
23
|
+
end
|
24
|
+
should "build from serialization" do
|
25
|
+
assert_equal(
|
26
|
+
@m.my_var,
|
27
|
+
Hydra::Message.build(eval(@m.serialize)).my_var
|
28
|
+
)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
data/test/test_runner.rb
CHANGED
@@ -11,14 +11,32 @@ class TestRunner < Test::Unit::TestCase
|
|
11
11
|
@pipe.identify_as_parent
|
12
12
|
end
|
13
13
|
teardown do
|
14
|
+
@pipe.close
|
14
15
|
Process.wait(@child)
|
15
16
|
end
|
16
|
-
should "
|
17
|
-
assert @pipe.gets.is_a?(Hydra::Messages::
|
17
|
+
should "boot and run a file and shut down" do
|
18
|
+
assert @pipe.gets.is_a?(Hydra::Messages::Runner::RequestFile)
|
19
|
+
|
20
|
+
file = File.join(File.dirname(__FILE__), 'sample_tests', 'assert_true.rb')
|
21
|
+
@pipe.write(Hydra::Messages::Runner::RunFile.new(:file => file))
|
22
|
+
response = @pipe.gets
|
23
|
+
assert response.is_a?(Hydra::Messages::Runner::Results)
|
24
|
+
assert response.output =~ /Finished/
|
25
|
+
assert_equal file, response.file
|
26
|
+
@pipe.write(Hydra::Messages::Runner::Shutdown.new)
|
18
27
|
end
|
19
|
-
|
20
|
-
|
28
|
+
|
29
|
+
should "run a test" do
|
30
|
+
target = File.join(Dir.tmpdir, 'hydra_test.txt')
|
31
|
+
FileUtils.rm_f(target)
|
32
|
+
assert !File.exists?(target)
|
33
|
+
file = File.join(File.dirname(__FILE__), 'sample_tests', 'write_file.rb')
|
34
|
+
assert @pipe.gets.is_a?(Hydra::Messages::Runner::RequestFile)
|
35
|
+
@pipe.write(Hydra::Messages::Runner::RunFile.new(:file => file))
|
36
|
+
response = @pipe.gets
|
37
|
+
@pipe.write(Hydra::Messages::Runner::Shutdown.new)
|
38
|
+
assert File.exists?(target)
|
39
|
+
assert_equal "HYDRA", File.read(target)
|
21
40
|
end
|
22
|
-
should "terminate when sent a shutdown message"
|
23
41
|
end
|
24
42
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: hydra
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Nick Gauthier
|
@@ -54,12 +54,15 @@ files:
|
|
54
54
|
- lib/hydra.rb
|
55
55
|
- lib/hydra/io.rb
|
56
56
|
- lib/hydra/message.rb
|
57
|
-
- lib/hydra/message/
|
57
|
+
- lib/hydra/message/runner_messages.rb
|
58
58
|
- lib/hydra/pipe.rb
|
59
59
|
- lib/hydra/runner.rb
|
60
60
|
- lib/hydra/ssh.rb
|
61
61
|
- test/echo_the_dolphin.rb
|
62
62
|
- test/helper.rb
|
63
|
+
- test/sample_tests/assert_true.rb
|
64
|
+
- test/sample_tests/write_file.rb
|
65
|
+
- test/test_message.rb
|
63
66
|
- test/test_pipe.rb
|
64
67
|
- test/test_runner.rb
|
65
68
|
- test/test_ssh.rb
|
@@ -94,6 +97,9 @@ summary: Distributed testing toolkit
|
|
94
97
|
test_files:
|
95
98
|
- test/test_ssh.rb
|
96
99
|
- test/helper.rb
|
100
|
+
- test/test_message.rb
|
97
101
|
- test/test_pipe.rb
|
98
102
|
- test/test_runner.rb
|
103
|
+
- test/sample_tests/write_file.rb
|
104
|
+
- test/sample_tests/assert_true.rb
|
99
105
|
- test/echo_the_dolphin.rb
|