torquespec 0.3.2 → 0.3.3
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +2 -1
- data/README.org +171 -0
- data/lib/rspec/core/torquespec-extensions.rb +7 -4
- data/lib/torquespec/daemon.rb +11 -12
- data/lib/torquespec/torquespec.rb +10 -2
- data/lib/torquespec/version.rb +1 -1
- data/spec/hello_world_spec.rb +2 -2
- metadata +62 -79
- data/README.md +0 -8
data/.gitignore
CHANGED
data/README.org
ADDED
@@ -0,0 +1,171 @@
|
|
1
|
+
#+TITLE: Integration Testing for TorqueBox
|
2
|
+
#+AUTHOR: Jim Crossley
|
3
|
+
#+EMAIL: jcrossley@redhat.com
|
4
|
+
#+LANGUAGE: en
|
5
|
+
#+OPTIONS: H:3 num:nil toc:nil \n:nil @:t ::t |:t ^:t -:t f:t *:t <:t
|
6
|
+
#+OPTIONS: TeX:t LaTeX:nil skip:nil d:nil todo:t pri:nil tags:not-in-toc
|
7
|
+
#+INFOJS_OPT: view:nil toc:nil ltoc:t mouse:underline buttons:0 path:http://orgmode.org/org-info.js
|
8
|
+
#+EXPORT_SELECT_TAGS: export
|
9
|
+
#+EXPORT_EXCLUDE_TAGS: noexport
|
10
|
+
|
11
|
+
* TorqueSpec
|
12
|
+
|
13
|
+
TorqueSpec extends the [[http://relishapp.com/rspec][RSpec testing framework]] to provide
|
14
|
+
integration testing for applications designed to run on the
|
15
|
+
[[http://torquebox.org/][TorqueBox Ruby application server]]. Before running your RSpec
|
16
|
+
examples, TorqueSpec ensures that a TorqueBox server is running and
|
17
|
+
enables you to verify expectations against real applications
|
18
|
+
deployed on it.
|
19
|
+
|
20
|
+
Easy browser control/simulation is possible via the [[https://github.com/jnicklas/capybara][capybara]] or
|
21
|
+
[[https://github.com/brynary/webrat][webrat]] gems, of course, but TorqueSpec also provides "in-container"
|
22
|
+
testing, where your examples are actually run within the TorqueBox
|
23
|
+
server itself.
|
24
|
+
|
25
|
+
** Installation
|
26
|
+
|
27
|
+
Install the torquespec gem:
|
28
|
+
|
29
|
+
: $ gem install torquespec
|
30
|
+
|
31
|
+
And then in your spec files (or indirectly via =spec_helper.rb=):
|
32
|
+
|
33
|
+
: require 'torquespec'
|
34
|
+
|
35
|
+
Doing this will cause TorqueSpec to add a "before suite" hook that
|
36
|
+
fires up a TorqueBox server, i.e. JBoss, prior to running your
|
37
|
+
specs and an "after suite" hook to shut it down.
|
38
|
+
|
39
|
+
** RSpec extensions
|
40
|
+
|
41
|
+
Aiming to be minimally intrusive, TorqueSpec makes two new methods
|
42
|
+
available to your spec files: =deploy= and =remote_describe=.
|
43
|
+
|
44
|
+
*** deploy()
|
45
|
+
|
46
|
+
Determines which app[s] are deployed prior to running a particular
|
47
|
+
=ExampleGroup=, so typically called from a top-level =describe=
|
48
|
+
block. The deployment and subsequent undeployment occur within
|
49
|
+
"before all" and "after all" RSpec hooks, respectively.
|
50
|
+
|
51
|
+
The method accepts any number of arguments, each of which should
|
52
|
+
represent a [[http://torquebox.org/2x/builds/html-docs/deployment-descriptors.html][TorqueBox deployment descriptor]], typically a YAML
|
53
|
+
"here document", a Hash, or a path to an existing file. It also
|
54
|
+
accepts a block, the result of which should also be one or more
|
55
|
+
deployment descriptors. Here's an example using a single here
|
56
|
+
doc:
|
57
|
+
|
58
|
+
: describe "basic test with heredoc" do
|
59
|
+
:
|
60
|
+
: deploy <<-DD_END.gsub(/^ {4}/,'')
|
61
|
+
: application:
|
62
|
+
: root: #{File.dirname(__FILE__)}/../app
|
63
|
+
: env: development
|
64
|
+
: web:
|
65
|
+
: context: /basic
|
66
|
+
: DD_END
|
67
|
+
:
|
68
|
+
: it "should work" do
|
69
|
+
: visit "/basic"
|
70
|
+
: page.should have_content('it worked')
|
71
|
+
: page.find("#success")[:class].should == 'basic'
|
72
|
+
: end
|
73
|
+
:
|
74
|
+
: end
|
75
|
+
|
76
|
+
Here docs are especially nice because they support string
|
77
|
+
substitution. Note that we're setting the location of the app
|
78
|
+
relative to the location of the spec file itself,
|
79
|
+
e.g. =__FILE__=. And the little =gsub(/^ {4},'')= trick allows
|
80
|
+
you to indent the YAML relative to the Ruby.
|
81
|
+
|
82
|
+
*** remote_describe()
|
83
|
+
|
84
|
+
TorqueSpec supports "in container" testing via the
|
85
|
+
=remote_describe= method. It behaves exactly like the RSpec
|
86
|
+
=describe= method, but the resulting =ExampleGroup= will be run
|
87
|
+
inside the TorqueBox server.
|
88
|
+
|
89
|
+
If your spec calls =remote_describe=, TorqueSpec will deploy a
|
90
|
+
small daemon with your application. This daemon will act as an
|
91
|
+
additional RSpec runner to which the "local" runner will delegate
|
92
|
+
the invocation of those =ExampleGroups= defined by
|
93
|
+
=remote_describe=. This delegation occurs via DRb: the "remote"
|
94
|
+
runner reports its results to the "local" one, allowing you to
|
95
|
+
summarize the results of all your tests, both in-container and
|
96
|
+
out, in a single report.
|
97
|
+
|
98
|
+
Because your specs are consumed by two separate RSpec processes,
|
99
|
+
you must ensure that any gems other than TorqueSpec/RSpec are
|
100
|
+
available to the process that needs them.
|
101
|
+
|
102
|
+
: require 'torquespec'
|
103
|
+
:
|
104
|
+
: TorqueSpec.local {
|
105
|
+
: require 'capybara'
|
106
|
+
: }
|
107
|
+
:
|
108
|
+
: app = <<-END.gsub(/^ {4}/,'')
|
109
|
+
: application:
|
110
|
+
: root: #{File.dirname(__FILE__)}/../app
|
111
|
+
: END
|
112
|
+
:
|
113
|
+
: describe "local test" do
|
114
|
+
: deploy(app)
|
115
|
+
:
|
116
|
+
: it "should work" do
|
117
|
+
: visit "/"
|
118
|
+
: page.should have_content('it worked')
|
119
|
+
: end
|
120
|
+
: end
|
121
|
+
:
|
122
|
+
: remote_describe "remote test" do
|
123
|
+
: deploy(app)
|
124
|
+
:
|
125
|
+
: it "should work" do
|
126
|
+
: some_service = inject(com.foo.SomeService)
|
127
|
+
: some_service.run.should == 'SUCCESS'
|
128
|
+
: end
|
129
|
+
: end
|
130
|
+
|
131
|
+
The above spec shows two example groups, one local and one remote.
|
132
|
+
But this spec will be processed by both the local test runner and
|
133
|
+
the remote daemon. The local one uses =capybara= so its require
|
134
|
+
is guarded in a =TorqueSpec.local= block, which won't be run
|
135
|
+
remotely. There's a complementary =TorqueSpec.remote= method
|
136
|
+
available, too.
|
137
|
+
|
138
|
+
Note also that the remote example is injecting a service that
|
139
|
+
wouldn't be available in the local runtime, only in the remote
|
140
|
+
TorqueBox server. Hence, the convenience, if not potential
|
141
|
+
confusion, of in-container testing. :)
|
142
|
+
|
143
|
+
** Configuration
|
144
|
+
|
145
|
+
Configuration parameters are variables in the TorqueSpec namespace, e.g. =TorqueSpec.max_heap=.
|
146
|
+
|
147
|
+
| Parameter | Description | Default |
|
148
|
+
|--------------+----------------------------------------------------------------+---------------|
|
149
|
+
| ~knob_root~ | Where TorqueSpec creates your deployment descriptors | .torquespec |
|
150
|
+
| ~jboss_home~ | Where JBoss is installed | ~$JBOSS_HOME~ |
|
151
|
+
| ~max_heap~ | The maximum RAM allocated to the JBoss JVM | 1024 MB |
|
152
|
+
| ~jvm_args~ | Arguments to the JVM running JBoss | /see below/ |
|
153
|
+
| ~drb_port~ | The in-container spec runner listens on this port for requests | 7772 |
|
154
|
+
| ~lazy~ | Whether to use a running JBoss and leave it running when done | false |
|
155
|
+
|
156
|
+
By default, TorqueSpec is initialized thusly:
|
157
|
+
|
158
|
+
: TorqueSpec.configure do |config|
|
159
|
+
: config.drb_port = 7772
|
160
|
+
: config.knob_root = ".torquespec"
|
161
|
+
: config.jvm_args = "-Xms64m -Xmx1024m -XX:MaxPermSize=512m -XX:+UseConcMarkSweepGC -XX:+UseParNewGC -XX:+CMSClassUnloadingEnabled -Dgem.path=default"
|
162
|
+
: end
|
163
|
+
|
164
|
+
Include a similar block in your =spec_helper.rb= to customize any of these.
|
165
|
+
|
166
|
+
** Dependencies
|
167
|
+
|
168
|
+
TorqueSpec has been extensively tested with RSpec 2, though RSpec 1
|
169
|
+
should be compatible as well. But really, why are you still using
|
170
|
+
RSpec 1?
|
171
|
+
|
@@ -13,12 +13,15 @@ TorqueSpec::Configurator.configure do |config|
|
|
13
13
|
config.extend(TorqueSpec)
|
14
14
|
end
|
15
15
|
|
16
|
-
|
16
|
+
TorqueSpec.remote {
|
17
17
|
module TorqueSpec
|
18
18
|
def deploy(*descriptors)
|
19
19
|
end
|
20
20
|
end
|
21
|
-
|
21
|
+
}
|
22
|
+
|
23
|
+
TorqueSpec.local {
|
24
|
+
|
22
25
|
require 'torquespec/server'
|
23
26
|
|
24
27
|
TorqueSpec::Configurator.configure do |config|
|
@@ -43,7 +46,7 @@ else
|
|
43
46
|
Thread.current[:app_server].stop
|
44
47
|
end
|
45
48
|
end
|
46
|
-
|
49
|
+
}
|
47
50
|
|
48
51
|
require 'torquespec/daemon'
|
49
52
|
|
@@ -51,7 +54,7 @@ module TorqueSpec
|
|
51
54
|
module ObjectExtensions
|
52
55
|
def remote_describe(*args, &example_group_block)
|
53
56
|
group = describe(*args, &example_group_block)
|
54
|
-
|
57
|
+
TorqueSpec.remote? ? group : group.extend( TorqueSpec::Daemon::Client )
|
55
58
|
end
|
56
59
|
end
|
57
60
|
end
|
data/lib/torquespec/daemon.rb
CHANGED
@@ -6,7 +6,7 @@ module TorqueSpec
|
|
6
6
|
class Daemon
|
7
7
|
|
8
8
|
def initialize(opts={})
|
9
|
-
puts "
|
9
|
+
puts "daemon: create opts=#{opts.inspect}"
|
10
10
|
dir = opts['pwd'].to_s
|
11
11
|
raise "The 'pwd' option must contain a valid directory name" if dir.empty? || !File.exist?(dir)
|
12
12
|
Dir.chdir( dir ) do
|
@@ -25,24 +25,17 @@ module TorqueSpec
|
|
25
25
|
end
|
26
26
|
|
27
27
|
def start
|
28
|
-
puts "
|
28
|
+
puts "daemon: start"
|
29
29
|
DRb.start_service("druby://127.0.0.1:#{TorqueSpec.drb_port}", self)
|
30
|
-
10.times do
|
31
|
-
if DRb.current_server
|
32
|
-
break
|
33
|
-
else
|
34
|
-
sleep(0.1)
|
35
|
-
end
|
36
|
-
end
|
37
30
|
end
|
38
31
|
|
39
32
|
def stop
|
40
|
-
puts "
|
33
|
+
puts "daemon: stop"
|
41
34
|
DRb.stop_service
|
42
35
|
end
|
43
36
|
|
44
37
|
def run(name, reporter)
|
45
|
-
puts "
|
38
|
+
puts "daemon: run #{name}"
|
46
39
|
example_group = @world.example_groups.find { |g| g.name == name }
|
47
40
|
example_group.run( reporter )
|
48
41
|
end
|
@@ -65,15 +58,21 @@ module TorqueSpec
|
|
65
58
|
def run_remotely(reporter)
|
66
59
|
DRb.start_service("druby://127.0.0.1:0")
|
67
60
|
daemon = DRbObject.new_with_uri("druby://127.0.0.1:#{TorqueSpec.drb_port}")
|
61
|
+
attempts = 10
|
68
62
|
begin
|
69
63
|
daemon.run( name, reporter )
|
64
|
+
rescue DRb::DRbConnError
|
65
|
+
# Overcome DRb.start_service() race condition
|
66
|
+
raise unless (attempts-=1) > 0
|
67
|
+
sleep(0.2)
|
68
|
+
retry
|
70
69
|
ensure
|
71
70
|
DRb.stop_service
|
72
71
|
end
|
73
72
|
end
|
74
73
|
|
75
74
|
def deploy_paths
|
76
|
-
[ DeploymentDescriptor.new({}, display_name, true).path ]
|
75
|
+
[ DeploymentDescriptor.new( {}, display_name, true ).path ]
|
77
76
|
end
|
78
77
|
|
79
78
|
end
|
@@ -7,7 +7,7 @@ module TorqueSpec
|
|
7
7
|
metaclass = class << self; self; end
|
8
8
|
metaclass.send(:define_method, :deploy_paths) do
|
9
9
|
return @deploy_paths if @deploy_paths
|
10
|
-
descriptors
|
10
|
+
descriptors += [block.call].flatten if block
|
11
11
|
i = descriptors.size > 1 ? 0 : nil
|
12
12
|
@deploy_paths = descriptors.map do |descriptor|
|
13
13
|
DeploymentDescriptor.new(descriptor,
|
@@ -29,6 +29,15 @@ module TorqueSpec
|
|
29
29
|
def as7?
|
30
30
|
File.exist?( File.join( jboss_home, "bin/standalone.sh" ) )
|
31
31
|
end
|
32
|
+
def jboss_home
|
33
|
+
@jboss_home ||= ENV['JBOSS_HOME'] || jboss_home_from_server_gem
|
34
|
+
end
|
35
|
+
def jboss_home_from_server_gem
|
36
|
+
require 'torquebox-server'
|
37
|
+
TorqueBox::Server.jboss_home
|
38
|
+
rescue Exception
|
39
|
+
$stderr.puts "WARN: Unable to determine JBoss install location; set either TorqueSpec.jboss_home or ENV['JBOSS_HOME']"
|
40
|
+
end
|
32
41
|
end
|
33
42
|
|
34
43
|
# A somewhat hackish way of exposing client-side gems to the server-side daemon
|
@@ -70,7 +79,6 @@ end
|
|
70
79
|
TorqueSpec.configure do |config|
|
71
80
|
config.drb_port = 7772
|
72
81
|
config.knob_root = ".torquespec"
|
73
|
-
config.jboss_home = ENV['JBOSS_HOME']
|
74
82
|
config.jvm_args = "-Xms64m -Xmx1024m -XX:MaxPermSize=512m -XX:+UseConcMarkSweepGC -XX:+UseParNewGC -XX:+CMSClassUnloadingEnabled -Dgem.path=default"
|
75
83
|
end
|
76
84
|
|
data/lib/torquespec/version.rb
CHANGED
data/spec/hello_world_spec.rb
CHANGED
@@ -15,10 +15,10 @@ end
|
|
15
15
|
|
16
16
|
describe "simple directory deployment" do
|
17
17
|
|
18
|
-
deploy <<-
|
18
|
+
deploy <<-DD_END.gsub(/^ {4}/,'')
|
19
19
|
application:
|
20
20
|
root: #{File.dirname(__FILE__)}/../apps/simple
|
21
|
-
|
21
|
+
DD_END
|
22
22
|
|
23
23
|
it "should greet the world" do
|
24
24
|
response = open("http://localhost:8080") {|f| f.read}
|
metadata
CHANGED
@@ -1,52 +1,41 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: torquespec
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
|
5
|
-
|
6
|
-
segments:
|
7
|
-
- 0
|
8
|
-
- 3
|
9
|
-
- 2
|
10
|
-
version: 0.3.2
|
4
|
+
prerelease:
|
5
|
+
version: 0.3.3
|
11
6
|
platform: ruby
|
12
7
|
authors:
|
13
|
-
- Jim Crossley
|
14
|
-
- Bob McWhirter
|
8
|
+
- Jim Crossley
|
9
|
+
- Bob McWhirter
|
15
10
|
autorequire:
|
16
11
|
bindir: bin
|
17
12
|
cert_chain: []
|
18
13
|
|
19
|
-
date: 2011-06-
|
14
|
+
date: 2011-06-14 00:00:00 -04:00
|
20
15
|
default_executable:
|
21
16
|
dependencies:
|
22
|
-
- !ruby/object:Gem::Dependency
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
hash: 3
|
45
|
-
segments:
|
46
|
-
- 0
|
47
|
-
version: "0"
|
48
|
-
type: :runtime
|
49
|
-
version_requirements: *id002
|
17
|
+
- !ruby/object:Gem::Dependency
|
18
|
+
name: rspec
|
19
|
+
prerelease: false
|
20
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
21
|
+
none: false
|
22
|
+
requirements:
|
23
|
+
- - ">="
|
24
|
+
- !ruby/object:Gem::Version
|
25
|
+
version: "0"
|
26
|
+
type: :runtime
|
27
|
+
version_requirements: *id001
|
28
|
+
- !ruby/object:Gem::Dependency
|
29
|
+
name: json
|
30
|
+
prerelease: false
|
31
|
+
requirement: &id002 !ruby/object:Gem::Requirement
|
32
|
+
none: false
|
33
|
+
requirements:
|
34
|
+
- - ">="
|
35
|
+
- !ruby/object:Gem::Version
|
36
|
+
version: "0"
|
37
|
+
type: :runtime
|
38
|
+
version_requirements: *id002
|
50
39
|
description: Write integration tests around the deployment of your app to a real JBoss app server
|
51
40
|
email: team@projectodd.org
|
52
41
|
executables: []
|
@@ -56,29 +45,29 @@ extensions: []
|
|
56
45
|
extra_rdoc_files: []
|
57
46
|
|
58
47
|
files:
|
59
|
-
- .gitignore
|
60
|
-
- Gemfile
|
61
|
-
- README.
|
62
|
-
- Rakefile
|
63
|
-
- apps/empty/torquebox.yml
|
64
|
-
- apps/node-info.war
|
65
|
-
- apps/simple.knob
|
66
|
-
- apps/simple/config.ru
|
67
|
-
- lib/rspec/core/torquespec-extensions.rb
|
68
|
-
- lib/torque_spec/daemon.rb
|
69
|
-
- lib/torquespec.rb
|
70
|
-
- lib/torquespec/as6.rb
|
71
|
-
- lib/torquespec/as7.rb
|
72
|
-
- lib/torquespec/daemon.rb
|
73
|
-
- lib/torquespec/deployment_descriptor.rb
|
74
|
-
- lib/torquespec/server.rb
|
75
|
-
- lib/torquespec/torquespec.rb
|
76
|
-
- lib/torquespec/version.rb
|
77
|
-
- spec/empty_spec.rb
|
78
|
-
- spec/guard_spec.rb
|
79
|
-
- spec/hello_world_spec.rb
|
80
|
-
- spec/remote_spec.rb
|
81
|
-
- torquespec.gemspec
|
48
|
+
- .gitignore
|
49
|
+
- Gemfile
|
50
|
+
- README.org
|
51
|
+
- Rakefile
|
52
|
+
- apps/empty/torquebox.yml
|
53
|
+
- apps/node-info.war
|
54
|
+
- apps/simple.knob
|
55
|
+
- apps/simple/config.ru
|
56
|
+
- lib/rspec/core/torquespec-extensions.rb
|
57
|
+
- lib/torque_spec/daemon.rb
|
58
|
+
- lib/torquespec.rb
|
59
|
+
- lib/torquespec/as6.rb
|
60
|
+
- lib/torquespec/as7.rb
|
61
|
+
- lib/torquespec/daemon.rb
|
62
|
+
- lib/torquespec/deployment_descriptor.rb
|
63
|
+
- lib/torquespec/server.rb
|
64
|
+
- lib/torquespec/torquespec.rb
|
65
|
+
- lib/torquespec/version.rb
|
66
|
+
- spec/empty_spec.rb
|
67
|
+
- spec/guard_spec.rb
|
68
|
+
- spec/hello_world_spec.rb
|
69
|
+
- spec/remote_spec.rb
|
70
|
+
- torquespec.gemspec
|
82
71
|
has_rdoc: true
|
83
72
|
homepage: http://github.com/torquebox/torquespec
|
84
73
|
licenses: []
|
@@ -87,34 +76,28 @@ post_install_message:
|
|
87
76
|
rdoc_options: []
|
88
77
|
|
89
78
|
require_paths:
|
90
|
-
- lib
|
79
|
+
- lib
|
91
80
|
required_ruby_version: !ruby/object:Gem::Requirement
|
92
81
|
none: false
|
93
82
|
requirements:
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
segments:
|
98
|
-
- 0
|
99
|
-
version: "0"
|
83
|
+
- - ">="
|
84
|
+
- !ruby/object:Gem::Version
|
85
|
+
version: "0"
|
100
86
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
101
87
|
none: false
|
102
88
|
requirements:
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
segments:
|
107
|
-
- 0
|
108
|
-
version: "0"
|
89
|
+
- - ">="
|
90
|
+
- !ruby/object:Gem::Version
|
91
|
+
version: "0"
|
109
92
|
requirements: []
|
110
93
|
|
111
94
|
rubyforge_project: torquespec
|
112
|
-
rubygems_version: 1.
|
95
|
+
rubygems_version: 1.5.1
|
113
96
|
signing_key:
|
114
97
|
specification_version: 3
|
115
98
|
summary: Deploy TorqueBox knobs to a running JBoss instance
|
116
99
|
test_files:
|
117
|
-
- spec/empty_spec.rb
|
118
|
-
- spec/guard_spec.rb
|
119
|
-
- spec/hello_world_spec.rb
|
120
|
-
- spec/remote_spec.rb
|
100
|
+
- spec/empty_spec.rb
|
101
|
+
- spec/guard_spec.rb
|
102
|
+
- spec/hello_world_spec.rb
|
103
|
+
- spec/remote_spec.rb
|
data/README.md
DELETED
@@ -1,8 +0,0 @@
|
|
1
|
-
# TorqueSpec #
|
2
|
-
|
3
|
-
TorqueSpec helps you build integration tests for your TorqueBox
|
4
|
-
applications. It encapsulates the control of a JBoss AS instance, and
|
5
|
-
makes it easy to deploy your apps before running your RSpec examples
|
6
|
-
and undeploy them afterwards.
|
7
|
-
|
8
|
-
More docs coming soon.
|