torquespec 0.3.2 → 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.
- 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.
|