conduit 0.2.6
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.
- checksums.yaml +7 -0
- data/Rakefile +22 -0
- data/app/controllers/conduit/responses_controller.rb +14 -0
- data/app/models/conduit/concerns/storage.rb +41 -0
- data/app/models/conduit/request.rb +109 -0
- data/app/models/conduit/response.rb +50 -0
- data/app/models/conduit/subscription.rb +6 -0
- data/config/routes.rb +3 -0
- data/db/migrate/20131209223122_create_conduit_requests.rb +13 -0
- data/db/migrate/20131209223734_create_conduit_responses.rb +10 -0
- data/db/migrate/20140305202729_create_conduit_subscriptions.rb +12 -0
- data/lib/conduit.rb +60 -0
- data/lib/conduit/acts_as_conduit_subscriber.rb +41 -0
- data/lib/conduit/configuration.rb +43 -0
- data/lib/conduit/core/action.rb +136 -0
- data/lib/conduit/core/connection.rb +85 -0
- data/lib/conduit/core/driver.rb +83 -0
- data/lib/conduit/core/parser.rb +55 -0
- data/lib/conduit/core/render.rb +69 -0
- data/lib/conduit/drivers/keep +0 -0
- data/lib/conduit/engine.rb +20 -0
- data/lib/conduit/storage.rb +37 -0
- data/lib/conduit/storage/aws.rb +94 -0
- data/lib/conduit/storage/file.rb +74 -0
- data/lib/conduit/util.rb +17 -0
- data/lib/conduit/version.rb +3 -0
- data/lib/tasks/conduit_tasks.rake +4 -0
- data/spec/classes/acts_as_conduit_subscriber_spec.rb +61 -0
- data/spec/classes/core/action_spec.rb +53 -0
- data/spec/classes/core/driver_spec.rb +24 -0
- data/spec/controllers/responses_controller_spec.rb +29 -0
- data/spec/dummy/README.rdoc +28 -0
- data/spec/dummy/Rakefile +6 -0
- data/spec/dummy/app/assets/javascripts/application.js +13 -0
- data/spec/dummy/app/assets/stylesheets/application.css +13 -0
- data/spec/dummy/app/controllers/application_controller.rb +5 -0
- data/spec/dummy/app/helpers/application_helper.rb +2 -0
- data/spec/dummy/app/views/layouts/application.html.erb +14 -0
- data/spec/dummy/bin/bundle +3 -0
- data/spec/dummy/bin/rails +4 -0
- data/spec/dummy/bin/rake +4 -0
- data/spec/dummy/config.ru +4 -0
- data/spec/dummy/config/application.rb +29 -0
- data/spec/dummy/config/boot.rb +5 -0
- data/spec/dummy/config/database.yml +20 -0
- data/spec/dummy/config/environment.rb +5 -0
- data/spec/dummy/config/environments/development.rb +29 -0
- data/spec/dummy/config/environments/production.rb +80 -0
- data/spec/dummy/config/environments/test.rb +36 -0
- data/spec/dummy/config/initializers/backtrace_silencers.rb +7 -0
- data/spec/dummy/config/initializers/conduit.rb +5 -0
- data/spec/dummy/config/initializers/filter_parameter_logging.rb +4 -0
- data/spec/dummy/config/initializers/inflections.rb +16 -0
- data/spec/dummy/config/initializers/mime_types.rb +5 -0
- data/spec/dummy/config/initializers/secret_token.rb +12 -0
- data/spec/dummy/config/initializers/session_store.rb +3 -0
- data/spec/dummy/config/initializers/wrap_parameters.rb +14 -0
- data/spec/dummy/config/locales/en.yml +23 -0
- data/spec/dummy/config/routes.rb +3 -0
- data/spec/dummy/db/schema.rb +46 -0
- data/spec/dummy/lib/conduit/drivers/my_driver/actions/foo.rb +10 -0
- data/spec/dummy/lib/conduit/drivers/my_driver/driver.rb +7 -0
- data/spec/dummy/lib/conduit/drivers/my_driver/parsers/foo.rb +13 -0
- data/spec/dummy/lib/conduit/drivers/my_driver/views/foo.erb +5 -0
- data/spec/dummy/lib/conduit/drivers/my_driver/views/layout.erb +3 -0
- data/spec/dummy/log/development.log +0 -0
- data/spec/dummy/log/test.log +9707 -0
- data/spec/dummy/public/404.html +58 -0
- data/spec/dummy/public/422.html +58 -0
- data/spec/dummy/public/500.html +57 -0
- data/spec/dummy/tmp/conduit/1/my_driver/foo/1-response.xml +3 -0
- data/spec/dummy/tmp/conduit/1/my_driver/foo/request.xml +7 -0
- data/spec/models/conduit/request_spec.rb +50 -0
- data/spec/models/conduit/response_spec.rb +52 -0
- data/spec/spec_helper.rb +36 -0
- data/spec/support/helper.rb +15 -0
- data/spec/support/xml/xml_request.xml +7 -0
- data/spec/support/xml/xml_response.xml +3 -0
- metadata +311 -0
@@ -0,0 +1,37 @@
|
|
1
|
+
#
|
2
|
+
# The job of this class is to provide storage
|
3
|
+
# functionality for conduit.
|
4
|
+
#
|
5
|
+
# TODO: Support multiple storage providers
|
6
|
+
#
|
7
|
+
|
8
|
+
require 'conduit/storage/aws'
|
9
|
+
require 'conduit/storage/file'
|
10
|
+
|
11
|
+
module Conduit
|
12
|
+
module Storage
|
13
|
+
|
14
|
+
# Wrapper around the configuration object
|
15
|
+
#
|
16
|
+
# Configurable in:
|
17
|
+
# config/initializers/conduit.rb
|
18
|
+
#
|
19
|
+
def self.config
|
20
|
+
Configuration.storage_config
|
21
|
+
end
|
22
|
+
|
23
|
+
# Get the name of the chosen provider
|
24
|
+
# from the configuration
|
25
|
+
#
|
26
|
+
def self.provider
|
27
|
+
Configuration.storage_config[:provider]
|
28
|
+
end
|
29
|
+
|
30
|
+
# Load in the functionality for the storage provider
|
31
|
+
# that was selected via the configuration
|
32
|
+
#
|
33
|
+
storage_provider_module = const_get(provider.to_s.humanize)
|
34
|
+
extend storage_provider_module
|
35
|
+
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,94 @@
|
|
1
|
+
#
|
2
|
+
# The job of this class is to provide storage
|
3
|
+
# functionality for conduit.
|
4
|
+
#
|
5
|
+
# TODO: Support multiple storage providers
|
6
|
+
#
|
7
|
+
|
8
|
+
require 'aws-sdk'
|
9
|
+
|
10
|
+
module Conduit
|
11
|
+
module Storage
|
12
|
+
module Aws
|
13
|
+
extend ActiveSupport::Rescuable
|
14
|
+
|
15
|
+
def self.extended(base)
|
16
|
+
base.extend(ClassMethods)
|
17
|
+
base.send(:configure)
|
18
|
+
end
|
19
|
+
|
20
|
+
module ClassMethods
|
21
|
+
|
22
|
+
# Configure AWS::S3 if we have explicit config
|
23
|
+
#
|
24
|
+
# TODO: This needs to be tested against AWS IAM.
|
25
|
+
# I'm thinking this being a "module"
|
26
|
+
# might cause issues.
|
27
|
+
#
|
28
|
+
def configure
|
29
|
+
if [:aws_access_key_id, :aws_access_secret].all? { |key| config.has_key?(key) }
|
30
|
+
AWS.config(:access_key_id => config[:aws_access_key_id],
|
31
|
+
:secret_access_key => config[:aws_access_secret])
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
# Primary connection object to AWS::S3
|
36
|
+
#
|
37
|
+
# Configurable in:
|
38
|
+
# config/initializers/conduit.rb
|
39
|
+
# TODO: Update how conduit gets
|
40
|
+
# the credentials for s3
|
41
|
+
#
|
42
|
+
def connection
|
43
|
+
@connection ||= AWS::S3.new
|
44
|
+
end
|
45
|
+
|
46
|
+
# Bucket we want to work with
|
47
|
+
#
|
48
|
+
# Configurable in:
|
49
|
+
# config/initializers/conduit.rb
|
50
|
+
#
|
51
|
+
def bucket
|
52
|
+
@bucket ||= begin
|
53
|
+
bucket = config[:bucket]
|
54
|
+
connection.buckets.create(bucket) unless connection.buckets[bucket].exists?
|
55
|
+
connection.buckets[bucket]
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
# Write a file to AWS::S3
|
60
|
+
#
|
61
|
+
# e.g.
|
62
|
+
# => Conduit::Storage.write('/path/to/file', 'foo')
|
63
|
+
#
|
64
|
+
def write(key, content)
|
65
|
+
bucket.objects[key].write(content)
|
66
|
+
end
|
67
|
+
|
68
|
+
# Read a file from AWS::S3
|
69
|
+
#
|
70
|
+
# e.g.
|
71
|
+
# => Conduit::Storage.read('/path/to/file')
|
72
|
+
#
|
73
|
+
def read(key)
|
74
|
+
bucket.objects[key].read
|
75
|
+
rescue AWS::S3::Errors::NoSuchKey
|
76
|
+
nil
|
77
|
+
end
|
78
|
+
|
79
|
+
# Delete a file from AWS::S3
|
80
|
+
#
|
81
|
+
# e.g.
|
82
|
+
# => Conduit::Storage.delete('/path/to/file')
|
83
|
+
#
|
84
|
+
def delete(key)
|
85
|
+
bucket.objects[key].delete
|
86
|
+
rescue AWS::S3::Errors::NoSuchKey
|
87
|
+
nil
|
88
|
+
end
|
89
|
+
|
90
|
+
end
|
91
|
+
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
@@ -0,0 +1,74 @@
|
|
1
|
+
#
|
2
|
+
# The job of this class is to provide storage
|
3
|
+
# functionality for conduit.
|
4
|
+
#
|
5
|
+
# TODO: Support multiple storage providers
|
6
|
+
#
|
7
|
+
|
8
|
+
require 'fileutils'
|
9
|
+
require 'pathname'
|
10
|
+
|
11
|
+
module Conduit
|
12
|
+
module Storage
|
13
|
+
module File
|
14
|
+
|
15
|
+
#
|
16
|
+
# TODO: Rename this, I originally used file,
|
17
|
+
# not considering the fact that it's
|
18
|
+
# already used in ruby.
|
19
|
+
#
|
20
|
+
|
21
|
+
def self.extended(base)
|
22
|
+
base.extend(ClassMethods)
|
23
|
+
end
|
24
|
+
|
25
|
+
module ClassMethods
|
26
|
+
|
27
|
+
# Return a Pathname object for the
|
28
|
+
# configured file path
|
29
|
+
#
|
30
|
+
def storage_path
|
31
|
+
@storage_path ||= Pathname.new(config[:file_path])
|
32
|
+
end
|
33
|
+
|
34
|
+
# Write a file to AWS::S3
|
35
|
+
#
|
36
|
+
# e.g.
|
37
|
+
# => Conduit::Storage.write('/path/to/file', 'foo')
|
38
|
+
#
|
39
|
+
def write(key, content)
|
40
|
+
full_path = storage_path.join(key)
|
41
|
+
FileUtils.mkdir_p(::File.dirname(full_path))
|
42
|
+
|
43
|
+
::File.open(full_path, 'w') do |f|
|
44
|
+
f.write(content)
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
# Read a file
|
49
|
+
#
|
50
|
+
# e.g.
|
51
|
+
# => Conduit::Storage.read('/path/to/file')
|
52
|
+
#
|
53
|
+
def read(key)
|
54
|
+
::File.read(storage_path.join(key))
|
55
|
+
rescue Errno::ENOENT
|
56
|
+
nil
|
57
|
+
end
|
58
|
+
|
59
|
+
# Delete a file
|
60
|
+
#
|
61
|
+
# e.g.
|
62
|
+
# => Conduit::Storage.delete('/path/to/file')
|
63
|
+
#
|
64
|
+
def delete(key)
|
65
|
+
::File.delete(storage_path.join(key))
|
66
|
+
rescue Errno::ENOENT, Errno::EPERM
|
67
|
+
nil
|
68
|
+
end
|
69
|
+
|
70
|
+
end
|
71
|
+
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
data/lib/conduit/util.rb
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
module Conduit
|
2
|
+
module Util
|
3
|
+
|
4
|
+
# Instantiate the action class with options
|
5
|
+
#
|
6
|
+
# returns:
|
7
|
+
# => Conduit::Driver::Fusion::Purchase
|
8
|
+
#
|
9
|
+
def self.find_driver(*args)
|
10
|
+
driver = args.map(&:to_s).map(&:classify).join('::')
|
11
|
+
Conduit::Driver.const_get(driver)
|
12
|
+
rescue NameError
|
13
|
+
# TODO: Determine the best course of action for failure
|
14
|
+
end
|
15
|
+
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,61 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
# Create a temporary ActiveRecord object to test with
|
4
|
+
#
|
5
|
+
class MySubscriber < ActiveRecord::Base
|
6
|
+
acts_as_conduit_subscriber
|
7
|
+
|
8
|
+
# Update the `updated_at` timestamp
|
9
|
+
# so we know this has been called
|
10
|
+
#
|
11
|
+
def after_conduit_update(action, parsed_response)
|
12
|
+
self.update_column(:updated_at, 1.day.from_now)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
describe MySubscriber do
|
17
|
+
|
18
|
+
# Silly magic to create an empty table for MySubscriber
|
19
|
+
#
|
20
|
+
before(:all) do
|
21
|
+
ActiveRecord::Migration.tap do |a|
|
22
|
+
a.verbose = false
|
23
|
+
a.create_table(:my_subscribers) do |t|
|
24
|
+
t.timestamps
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
# Silly magic to remove an empty table for MySubscriber
|
30
|
+
#
|
31
|
+
after(:all) do
|
32
|
+
ActiveRecord::Migration.tap do |a|
|
33
|
+
a.verbose = false
|
34
|
+
a.drop_table(:my_subscribers)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
context 'without an instance' do
|
39
|
+
its(:class) { should respond_to(:acts_as_conduit_subscriber) }
|
40
|
+
it { should have_many :conduit_requests }
|
41
|
+
end
|
42
|
+
|
43
|
+
context 'with an instance' do
|
44
|
+
before(:each) do
|
45
|
+
Excon.stub({}, body: read_support_file("xml/xml_response.xml"), status: 200)
|
46
|
+
|
47
|
+
@obj = MySubscriber.create
|
48
|
+
@obj.conduit_requests.create(driver: :my_driver, action: :foo,
|
49
|
+
options: request_attributes).perform_request
|
50
|
+
end
|
51
|
+
|
52
|
+
describe '#after_conduit_update' do
|
53
|
+
it 'gets called after a request is updated' do
|
54
|
+
@obj.reload # Bust the cache
|
55
|
+
@obj.updated_at.should_not == @obj.created_at
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
end
|
60
|
+
|
61
|
+
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
shared_examples_for Conduit::Core::Action do
|
4
|
+
|
5
|
+
subject do
|
6
|
+
described_class.new(request_attributes)
|
7
|
+
end
|
8
|
+
|
9
|
+
context 'without an instance' do
|
10
|
+
its(:class) { should respond_to(:remote_url) }
|
11
|
+
its(:class) { should respond_to(:required_attributes) }
|
12
|
+
its(:class) { should respond_to(:optional_attributes) }
|
13
|
+
|
14
|
+
describe '.requirements' do
|
15
|
+
it 'returns an array of required attributes' do
|
16
|
+
subject.class.requirements.should == %i(foo bar baz).to_set
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
describe '.attributes' do
|
21
|
+
it 'returns an array of known attributes' do
|
22
|
+
subject.class.requirements.should == %i(foo bar baz).to_set
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
context 'with an instance' do
|
28
|
+
describe '#view' do
|
29
|
+
it 'returns a rendered view for an action' do
|
30
|
+
a = subject.view.gsub(/\s+/, '')
|
31
|
+
b = read_support_file('xml/xml_request.xml').gsub(/\s+/, '')
|
32
|
+
a.should == b
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
describe '#perform' do
|
37
|
+
it 'returns a 200 status' do
|
38
|
+
subject.perform.status.should == 200
|
39
|
+
end
|
40
|
+
|
41
|
+
it 'returns a response body' do
|
42
|
+
a = subject.perform.body.gsub(/\s+/, '')
|
43
|
+
b = read_support_file('xml/xml_response.xml').gsub(/\s+/, '')
|
44
|
+
a.should == b
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
end
|
50
|
+
|
51
|
+
describe Conduit::Driver::MyDriver::Foo do
|
52
|
+
it_behaves_like Conduit::Core::Action
|
53
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
shared_examples_for Conduit::Core::Driver do
|
4
|
+
|
5
|
+
context 'without an instance' do
|
6
|
+
describe '.credentials' do
|
7
|
+
it 'returns an array of required credentials' do
|
8
|
+
subject.credentials.should == %i(username password).to_set
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
describe '.actions' do
|
13
|
+
it 'returns an array of known action' do
|
14
|
+
subject.actions.should == %i(foo).to_set
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
end
|
19
|
+
|
20
|
+
end
|
21
|
+
|
22
|
+
describe Conduit::Driver::MyDriver do
|
23
|
+
it_behaves_like Conduit::Core::Driver
|
24
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Conduit::ResponsesController do
|
4
|
+
|
5
|
+
let(:request) do
|
6
|
+
Conduit::Request.create(driver: :my_driver,
|
7
|
+
action: :foo, options: request_attributes)
|
8
|
+
end
|
9
|
+
|
10
|
+
let(:xml_content) do
|
11
|
+
read_support_file('xml/xml_response.xml')
|
12
|
+
end
|
13
|
+
|
14
|
+
describe 'create' do
|
15
|
+
before do
|
16
|
+
post :create, { request_id: request.id,
|
17
|
+
content: xml_content, use_route: :conduit }
|
18
|
+
end
|
19
|
+
|
20
|
+
it 'returns a 200 status' do
|
21
|
+
response.status.should == 200
|
22
|
+
end
|
23
|
+
|
24
|
+
it 'creates a response object' do
|
25
|
+
request.responses.length.should == 1
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
== README
|
2
|
+
|
3
|
+
This README would normally document whatever steps are necessary to get the
|
4
|
+
application up and running.
|
5
|
+
|
6
|
+
Things you may want to cover:
|
7
|
+
|
8
|
+
* Ruby version
|
9
|
+
|
10
|
+
* System dependencies
|
11
|
+
|
12
|
+
* Configuration
|
13
|
+
|
14
|
+
* Database creation
|
15
|
+
|
16
|
+
* Database initialization
|
17
|
+
|
18
|
+
* How to run the test suite
|
19
|
+
|
20
|
+
* Services (job queues, cache servers, search engines, etc.)
|
21
|
+
|
22
|
+
* Deployment instructions
|
23
|
+
|
24
|
+
* ...
|
25
|
+
|
26
|
+
|
27
|
+
Please feel free to use a different markup language if you do not plan to run
|
28
|
+
<tt>rake doc:app</tt>.
|
data/spec/dummy/Rakefile
ADDED