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.
Files changed (79) hide show
  1. checksums.yaml +7 -0
  2. data/Rakefile +22 -0
  3. data/app/controllers/conduit/responses_controller.rb +14 -0
  4. data/app/models/conduit/concerns/storage.rb +41 -0
  5. data/app/models/conduit/request.rb +109 -0
  6. data/app/models/conduit/response.rb +50 -0
  7. data/app/models/conduit/subscription.rb +6 -0
  8. data/config/routes.rb +3 -0
  9. data/db/migrate/20131209223122_create_conduit_requests.rb +13 -0
  10. data/db/migrate/20131209223734_create_conduit_responses.rb +10 -0
  11. data/db/migrate/20140305202729_create_conduit_subscriptions.rb +12 -0
  12. data/lib/conduit.rb +60 -0
  13. data/lib/conduit/acts_as_conduit_subscriber.rb +41 -0
  14. data/lib/conduit/configuration.rb +43 -0
  15. data/lib/conduit/core/action.rb +136 -0
  16. data/lib/conduit/core/connection.rb +85 -0
  17. data/lib/conduit/core/driver.rb +83 -0
  18. data/lib/conduit/core/parser.rb +55 -0
  19. data/lib/conduit/core/render.rb +69 -0
  20. data/lib/conduit/drivers/keep +0 -0
  21. data/lib/conduit/engine.rb +20 -0
  22. data/lib/conduit/storage.rb +37 -0
  23. data/lib/conduit/storage/aws.rb +94 -0
  24. data/lib/conduit/storage/file.rb +74 -0
  25. data/lib/conduit/util.rb +17 -0
  26. data/lib/conduit/version.rb +3 -0
  27. data/lib/tasks/conduit_tasks.rake +4 -0
  28. data/spec/classes/acts_as_conduit_subscriber_spec.rb +61 -0
  29. data/spec/classes/core/action_spec.rb +53 -0
  30. data/spec/classes/core/driver_spec.rb +24 -0
  31. data/spec/controllers/responses_controller_spec.rb +29 -0
  32. data/spec/dummy/README.rdoc +28 -0
  33. data/spec/dummy/Rakefile +6 -0
  34. data/spec/dummy/app/assets/javascripts/application.js +13 -0
  35. data/spec/dummy/app/assets/stylesheets/application.css +13 -0
  36. data/spec/dummy/app/controllers/application_controller.rb +5 -0
  37. data/spec/dummy/app/helpers/application_helper.rb +2 -0
  38. data/spec/dummy/app/views/layouts/application.html.erb +14 -0
  39. data/spec/dummy/bin/bundle +3 -0
  40. data/spec/dummy/bin/rails +4 -0
  41. data/spec/dummy/bin/rake +4 -0
  42. data/spec/dummy/config.ru +4 -0
  43. data/spec/dummy/config/application.rb +29 -0
  44. data/spec/dummy/config/boot.rb +5 -0
  45. data/spec/dummy/config/database.yml +20 -0
  46. data/spec/dummy/config/environment.rb +5 -0
  47. data/spec/dummy/config/environments/development.rb +29 -0
  48. data/spec/dummy/config/environments/production.rb +80 -0
  49. data/spec/dummy/config/environments/test.rb +36 -0
  50. data/spec/dummy/config/initializers/backtrace_silencers.rb +7 -0
  51. data/spec/dummy/config/initializers/conduit.rb +5 -0
  52. data/spec/dummy/config/initializers/filter_parameter_logging.rb +4 -0
  53. data/spec/dummy/config/initializers/inflections.rb +16 -0
  54. data/spec/dummy/config/initializers/mime_types.rb +5 -0
  55. data/spec/dummy/config/initializers/secret_token.rb +12 -0
  56. data/spec/dummy/config/initializers/session_store.rb +3 -0
  57. data/spec/dummy/config/initializers/wrap_parameters.rb +14 -0
  58. data/spec/dummy/config/locales/en.yml +23 -0
  59. data/spec/dummy/config/routes.rb +3 -0
  60. data/spec/dummy/db/schema.rb +46 -0
  61. data/spec/dummy/lib/conduit/drivers/my_driver/actions/foo.rb +10 -0
  62. data/spec/dummy/lib/conduit/drivers/my_driver/driver.rb +7 -0
  63. data/spec/dummy/lib/conduit/drivers/my_driver/parsers/foo.rb +13 -0
  64. data/spec/dummy/lib/conduit/drivers/my_driver/views/foo.erb +5 -0
  65. data/spec/dummy/lib/conduit/drivers/my_driver/views/layout.erb +3 -0
  66. data/spec/dummy/log/development.log +0 -0
  67. data/spec/dummy/log/test.log +9707 -0
  68. data/spec/dummy/public/404.html +58 -0
  69. data/spec/dummy/public/422.html +58 -0
  70. data/spec/dummy/public/500.html +57 -0
  71. data/spec/dummy/tmp/conduit/1/my_driver/foo/1-response.xml +3 -0
  72. data/spec/dummy/tmp/conduit/1/my_driver/foo/request.xml +7 -0
  73. data/spec/models/conduit/request_spec.rb +50 -0
  74. data/spec/models/conduit/response_spec.rb +52 -0
  75. data/spec/spec_helper.rb +36 -0
  76. data/spec/support/helper.rb +15 -0
  77. data/spec/support/xml/xml_request.xml +7 -0
  78. data/spec/support/xml/xml_response.xml +3 -0
  79. 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
@@ -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,3 @@
1
+ module Conduit
2
+ VERSION = "0.2.6"
3
+ end
@@ -0,0 +1,4 @@
1
+ # desc "Explaining what the task does"
2
+ # task :conduit do
3
+ # # Task goes here
4
+ # 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>.
@@ -0,0 +1,6 @@
1
+ # Add your own tasks in files placed in lib/tasks ending in .rake,
2
+ # for example lib/tasks/capistrano.rake, and they will automatically be available to Rake.
3
+
4
+ require File.expand_path('../config/application', __FILE__)
5
+
6
+ Dummy::Application.load_tasks