lackie 0.1.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/Gemfile +7 -0
- data/Gemfile.lock +57 -0
- data/README.rdoc +65 -0
- data/Rakefile +13 -0
- data/features/remote_control.feature +19 -0
- data/features/step_definitions/lackie_steps.rb +23 -0
- data/features/support/config.ru +7 -0
- data/features/support/env.rb +54 -0
- data/features/support/example_app/app.html +13 -0
- data/features/support/example_app.rb +9 -0
- data/lackie.gemspec +27 -0
- data/lib/lackie/javascript/json2.js +483 -0
- data/lib/lackie/javascript/surrender.js +58 -0
- data/lib/lackie/javascript/surrender.rb +15 -0
- data/lib/lackie/javascript.rb +1 -0
- data/lib/lackie/poller.rb +22 -0
- data/lib/lackie/rack/middleware.rb +85 -0
- data/lib/lackie/rack.rb +2 -0
- data/lib/lackie/remote_control.rb +51 -0
- data/lib/lackie.rb +8 -0
- data/spec/lackie/javascript/surrender_spec.rb +16 -0
- data/spec/lackie/poller_spec.rb +34 -0
- data/spec/lackie/rack/middleware_spec.rb +77 -0
- data/spec/lackie/remote_control_spec.rb +46 -0
- data/spec/spec_helper.rb +6 -0
- metadata +197 -0
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
@@ -0,0 +1,57 @@
|
|
1
|
+
PATH
|
2
|
+
remote: .
|
3
|
+
specs:
|
4
|
+
lackie (0.1.0)
|
5
|
+
rack (~> 1.2.1)
|
6
|
+
rest-client (~> 1.4.2)
|
7
|
+
|
8
|
+
GEM
|
9
|
+
remote: http://rubygems.org/
|
10
|
+
specs:
|
11
|
+
builder (2.1.2)
|
12
|
+
cgi_multipart_eof_fix (2.5.0)
|
13
|
+
cucumber (0.10.0)
|
14
|
+
builder (>= 2.1.2)
|
15
|
+
diff-lcs (~> 1.1.2)
|
16
|
+
gherkin (~> 2.3.2)
|
17
|
+
json (~> 1.4.6)
|
18
|
+
term-ansicolor (~> 1.0.5)
|
19
|
+
daemons (1.0.10)
|
20
|
+
diff-lcs (1.1.2)
|
21
|
+
fastthread (1.0.1)
|
22
|
+
gem_plugin (0.2.3)
|
23
|
+
gherkin (2.3.3)
|
24
|
+
json (~> 1.4.6)
|
25
|
+
json (1.4.6)
|
26
|
+
mime-types (1.16)
|
27
|
+
mongrel (1.1.5)
|
28
|
+
cgi_multipart_eof_fix (>= 2.4)
|
29
|
+
daemons (>= 1.0.3)
|
30
|
+
fastthread (>= 1.0.1)
|
31
|
+
gem_plugin (>= 0.2.3)
|
32
|
+
rack (1.2.1)
|
33
|
+
relevance-rcov (0.9.2.1)
|
34
|
+
rest-client (1.4.2)
|
35
|
+
mime-types (>= 1.16)
|
36
|
+
rspec (2.2.0)
|
37
|
+
rspec-core (~> 2.2)
|
38
|
+
rspec-expectations (~> 2.2)
|
39
|
+
rspec-mocks (~> 2.2)
|
40
|
+
rspec-core (2.3.1)
|
41
|
+
rspec-expectations (2.3.0)
|
42
|
+
diff-lcs (~> 1.1.2)
|
43
|
+
rspec-mocks (2.3.0)
|
44
|
+
term-ansicolor (1.0.5)
|
45
|
+
|
46
|
+
PLATFORMS
|
47
|
+
ruby
|
48
|
+
|
49
|
+
DEPENDENCIES
|
50
|
+
bundler (~> 1.0.7)
|
51
|
+
cucumber (~> 0.10.0)
|
52
|
+
lackie!
|
53
|
+
mongrel (~> 1.1.5)
|
54
|
+
rack (~> 1.2.1)
|
55
|
+
relevance-rcov (~> 0.9.2.1)
|
56
|
+
rest-client (~> 1.4.2)
|
57
|
+
rspec (~> 2.2.0)
|
data/README.rdoc
ADDED
@@ -0,0 +1,65 @@
|
|
1
|
+
= Lackie
|
2
|
+
|
3
|
+
== Warning
|
4
|
+
|
5
|
+
I haven't used Lackie to develop an application yet. But I have used it in
|
6
|
+
various browsers including firefox, chrome and the samsung maple emulator.
|
7
|
+
|
8
|
+
== About
|
9
|
+
|
10
|
+
Lackie enables automation of remote applications using an HTTP middleman:
|
11
|
+
|
12
|
+
Ruby Client -> Lackie Service <- Remote App
|
13
|
+
|
14
|
+
Lackie automates applications running in environments that are difficult to
|
15
|
+
control remotely. Lackie requires minimal support in target environments:
|
16
|
+
scheduling (e.g. window.setInterval) and HTTP client capabilities (e.g. ajax).
|
17
|
+
|
18
|
+
Where it's difficult to programmatically launch the remote application, it can
|
19
|
+
be started manually before the automation begins. Lackie effectively "attaches"
|
20
|
+
itself to the running "zombie" application.
|
21
|
+
|
22
|
+
Lackie uses an HTTP service as a proxy for application automation commands:
|
23
|
+
|
24
|
+
1. application surrenders control to automation
|
25
|
+
2. the surrendered application polls Lackie for commands
|
26
|
+
3. the automator sends a command to Lackie
|
27
|
+
4. the application executes the command and sends the result to Lackie
|
28
|
+
5. the automator polls Lackie and receives the result (or error)
|
29
|
+
|
30
|
+
== Usage
|
31
|
+
|
32
|
+
Lackie is implemented as rack middleware, so:
|
33
|
+
|
34
|
+
require 'rack'
|
35
|
+
require 'lackie'
|
36
|
+
require 'lackie/rack'
|
37
|
+
|
38
|
+
Rack::Builder.app do
|
39
|
+
use Lackie::Rack::Middleware
|
40
|
+
run MyApp
|
41
|
+
end
|
42
|
+
|
43
|
+
It will intercept all requests where the path starts with /lackie/
|
44
|
+
|
45
|
+
Lackie expects remote applications to:
|
46
|
+
|
47
|
+
1. poll the middleware for commands expressed as strings
|
48
|
+
2. execute those commands when they appear
|
49
|
+
3. send string results back to the middleware
|
50
|
+
|
51
|
+
== Example
|
52
|
+
|
53
|
+
The source code includes an example rack app:
|
54
|
+
|
55
|
+
rackup features/support/config.ru
|
56
|
+
|
57
|
+
Open this URL in your browser of choice:
|
58
|
+
|
59
|
+
http://localhost:9292/example_app/app.html
|
60
|
+
|
61
|
+
Now you can execute commands in the remote application:
|
62
|
+
|
63
|
+
require 'rubygems'
|
64
|
+
require 'lackie'
|
65
|
+
Lackie::RemoteControl.new("localhost", 9292).exec("1 + 2") # => "3"
|
data/Rakefile
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
require 'rake'
|
2
|
+
require 'rspec/core/rake_task'
|
3
|
+
|
4
|
+
desc "Run all specs with rcov"
|
5
|
+
RSpec::Core::RakeTask.new(:rcov) do |t|
|
6
|
+
t.rcov = true
|
7
|
+
t.rcov_opts = %w{--exclude gems\/,spec\/,features\/}
|
8
|
+
end
|
9
|
+
|
10
|
+
desc "Run all specs, then all features"
|
11
|
+
task :default do
|
12
|
+
system("rspec spec && cucumber features")
|
13
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
Feature: Remote Control
|
2
|
+
In order to automate remote applications with HTTP client capabilities
|
3
|
+
As a client
|
4
|
+
I want to surrender applications as javascript lackies
|
5
|
+
|
6
|
+
Scenario: Remote Execution
|
7
|
+
Given I have surrendered my web page as a lackie
|
8
|
+
When I tell the lackie to execute "1 + 1"
|
9
|
+
Then I should see a result with the value "2"
|
10
|
+
|
11
|
+
Scenario: Remote Execution Error
|
12
|
+
Given I have surrendered my web page as a lackie
|
13
|
+
When I tell the lackie to execute "(function() { throw 'whoopsie'; })()"
|
14
|
+
Then I should see an error with the message "whoopsie"
|
15
|
+
|
16
|
+
Scenario: Remote Log
|
17
|
+
Given I have surrendered my web page as a lackie
|
18
|
+
When I tell the lackie to log "yipee"
|
19
|
+
Then I should see a result with the value "yipee"
|
@@ -0,0 +1,23 @@
|
|
1
|
+
Given /^I have surrendered my web page as a lackie$/ do
|
2
|
+
browse_example_app
|
3
|
+
end
|
4
|
+
|
5
|
+
When /^I tell the lackie to log "([^\"]*)"$/ do |message|
|
6
|
+
@response = remote_control.log(message)
|
7
|
+
end
|
8
|
+
|
9
|
+
When /^I tell the lackie to execute "([^\"]*)"$/ do |script|
|
10
|
+
begin
|
11
|
+
@response = remote_control.exec(script)
|
12
|
+
rescue => e
|
13
|
+
@error = e
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
Then /^I should see a result with the value "([^\"]*)"$/ do |value|
|
18
|
+
@response.to_s.should == value
|
19
|
+
end
|
20
|
+
|
21
|
+
Then /^I should see an error with the message "([^\"]*)"$/ do |message|
|
22
|
+
@error.message.should == message
|
23
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
$:.unshift(File.dirname(__FILE__) + '/../../lib')
|
2
|
+
$:.unshift(File.dirname(__FILE__))
|
3
|
+
|
4
|
+
require 'rack'
|
5
|
+
require 'mongrel'
|
6
|
+
require 'selenium-webdriver'
|
7
|
+
require 'lackie'
|
8
|
+
require 'lackie/rack'
|
9
|
+
require 'example_app'
|
10
|
+
|
11
|
+
module LackieWorld
|
12
|
+
def remote_control
|
13
|
+
Lackie::RemoteControl.new(host, port)
|
14
|
+
end
|
15
|
+
|
16
|
+
def browse_example_app
|
17
|
+
web_driver.get "http://#{host}:#{port}/example_app/app.html"
|
18
|
+
end
|
19
|
+
|
20
|
+
private
|
21
|
+
|
22
|
+
def host
|
23
|
+
"localhost"
|
24
|
+
end
|
25
|
+
|
26
|
+
def port
|
27
|
+
6663
|
28
|
+
end
|
29
|
+
|
30
|
+
def web_driver
|
31
|
+
@@web_driver ||= begin
|
32
|
+
start_server
|
33
|
+
driver = Selenium::WebDriver.for :firefox
|
34
|
+
at_exit { driver.close }
|
35
|
+
driver
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def start_server
|
40
|
+
rack_server = nil
|
41
|
+
rack_thread = Thread.new do
|
42
|
+
::Rack::Handler::Mongrel.run(ExampleApp.build, :Host => host, :Port => port) do |server|
|
43
|
+
rack_server = server
|
44
|
+
end
|
45
|
+
end
|
46
|
+
at_exit do
|
47
|
+
rack_server.stop
|
48
|
+
rack_thread.kill
|
49
|
+
end
|
50
|
+
sleep 0.05 while rack_server.nil?
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
World(LackieWorld)
|
@@ -0,0 +1,13 @@
|
|
1
|
+
<html>
|
2
|
+
<head>
|
3
|
+
<title>Lackie: Surrendered Web Page Example</title>
|
4
|
+
</head>
|
5
|
+
<body>
|
6
|
+
|
7
|
+
<!-- Lackie::RemoteControl#log creates elements under #LackieLog, if it exists -->
|
8
|
+
<div id="LackieLog" style="background-color:#ffffff"></div>
|
9
|
+
|
10
|
+
<script type="text/javascript" src="/lackie/surrender"></script>
|
11
|
+
|
12
|
+
</body>
|
13
|
+
</html>
|
data/lackie.gemspec
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
$LOAD_PATH.unshift File.expand_path("../lib", __FILE__)
|
3
|
+
require "lackie"
|
4
|
+
|
5
|
+
Gem::Specification.new do |s|
|
6
|
+
s.name = 'lackie'
|
7
|
+
s.version = Lackie::VERSION
|
8
|
+
s.authors = ['Josh Chisholm']
|
9
|
+
s.description = 'Automates remote applications using an HTTP middleman'
|
10
|
+
s.summary = "lackie-#{s.version}"
|
11
|
+
s.email = 'joshuachisholm@gmail.com'
|
12
|
+
s.homepage = 'http://github.com/joshski/lackie'
|
13
|
+
|
14
|
+
s.add_dependency 'rack', '~> 1.2.1'
|
15
|
+
s.add_dependency 'rest-client', '~> 1.4.2'
|
16
|
+
|
17
|
+
s.add_development_dependency 'rspec', '~> 2.2.0'
|
18
|
+
s.add_development_dependency 'cucumber', '~> 0.10.0'
|
19
|
+
s.add_development_dependency 'mongrel', '~> 1.1.5'
|
20
|
+
s.add_development_dependency 'relevance-rcov', '~> 0.9.2.1'
|
21
|
+
|
22
|
+
s.rubygems_version = "1.3.7"
|
23
|
+
s.files = `git ls-files`.split("\n")
|
24
|
+
s.test_files = `git ls-files -- {spec,features}/*`.split("\n")
|
25
|
+
s.extra_rdoc_files = ["README.rdoc"]
|
26
|
+
s.require_path = "lib"
|
27
|
+
end
|