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 CHANGED
@@ -2,4 +2,5 @@
2
2
  .bundle
3
3
  Gemfile.lock
4
4
  pkg/*
5
- .torquespec/*
5
+ .torquespec/*
6
+ /README.html
@@ -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
- if ENV['TORQUEBOX_APP_NAME']
16
+ TorqueSpec.remote {
17
17
  module TorqueSpec
18
18
  def deploy(*descriptors)
19
19
  end
20
20
  end
21
- else
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
- end
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
- ENV['TORQUEBOX_APP_NAME'] ? group : group.extend( TorqueSpec::Daemon::Client )
57
+ TorqueSpec.remote? ? group : group.extend( TorqueSpec::Daemon::Client )
55
58
  end
56
59
  end
57
60
  end
@@ -6,7 +6,7 @@ module TorqueSpec
6
6
  class Daemon
7
7
 
8
8
  def initialize(opts={})
9
- puts "JC: create daemon opts=#{opts.inspect}"
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 "JC: start daemon"
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 "JC: stop daemon"
33
+ puts "daemon: stop"
41
34
  DRb.stop_service
42
35
  end
43
36
 
44
37
  def run(name, reporter)
45
- puts "JC: run #{name}"
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 << block.call if block
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
 
@@ -1,3 +1,3 @@
1
1
  module TorqueSpec
2
- VERSION = "0.3.2"
2
+ VERSION = "0.3.3"
3
3
  end
@@ -15,10 +15,10 @@ end
15
15
 
16
16
  describe "simple directory deployment" do
17
17
 
18
- deploy <<-END.gsub(/^ {4}/,'')
18
+ deploy <<-DD_END.gsub(/^ {4}/,'')
19
19
  application:
20
20
  root: #{File.dirname(__FILE__)}/../apps/simple
21
- END
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
- hash: 23
5
- prerelease: false
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-11 00:00:00 -04:00
14
+ date: 2011-06-14 00:00:00 -04:00
20
15
  default_executable:
21
16
  dependencies:
22
- - !ruby/object:Gem::Dependency
23
- name: rspec
24
- prerelease: false
25
- requirement: &id001 !ruby/object:Gem::Requirement
26
- none: false
27
- requirements:
28
- - - ">="
29
- - !ruby/object:Gem::Version
30
- hash: 3
31
- segments:
32
- - 0
33
- version: "0"
34
- type: :runtime
35
- version_requirements: *id001
36
- - !ruby/object:Gem::Dependency
37
- name: json
38
- prerelease: false
39
- requirement: &id002 !ruby/object:Gem::Requirement
40
- none: false
41
- requirements:
42
- - - ">="
43
- - !ruby/object:Gem::Version
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.md
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
- - !ruby/object:Gem::Version
96
- hash: 3
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
- - !ruby/object:Gem::Version
105
- hash: 3
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.3.7
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.