hootenanny 0.0.1 → 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.
Files changed (112) hide show
  1. data/.gitignore +1 -0
  2. data/.travis.yml +5 -0
  3. data/Gemfile +5 -7
  4. data/Gemfile.lock +46 -28
  5. data/app/controllers/hootenanny/notifications_controller.rb +31 -0
  6. data/app/controllers/hootenanny/parameters.rb +16 -0
  7. data/app/controllers/hootenanny/subscriptions_controller.rb +24 -3
  8. data/app/models/hootenanny/publish_notification.rb +90 -0
  9. data/app/models/hootenanny/subscription.rb +72 -23
  10. data/config/routes.rb +2 -1
  11. data/db/migrate/20130607182642_add_started_at_and_lease_duration_to_subscriptions.rb +15 -0
  12. data/db/migrate/20130608225621_add_hmac_secret_to_subscription.rb +5 -0
  13. data/db/migrate/20130611235218_add_publish_notifications.rb +9 -0
  14. data/db/migrate/20130612153138_add_timestamps_to_publish_notification.rb +5 -0
  15. data/db/migrate/20130705200729_add_processed_flag_to_publish_notifications.rb +6 -0
  16. data/db/migrate/20130711061329_switch_publish_notification_process_state_from_boolean_to_string.rb +11 -0
  17. data/db/migrate/20130711061558_add_index_to_notifications_state.rb +5 -0
  18. data/hootenanny.gemspec +6 -2
  19. data/lib/hootenanny/configuration.rb +43 -0
  20. data/lib/hootenanny/correspondent.rb +44 -0
  21. data/lib/hootenanny/errors.rb +42 -1
  22. data/lib/hootenanny/feed.rb +75 -0
  23. data/lib/hootenanny/feed/atom_feed.rb +18 -0
  24. data/lib/hootenanny/feed/atom_feed_item.rb +8 -0
  25. data/lib/hootenanny/feed/digest_feed.rb +14 -0
  26. data/lib/hootenanny/feed/digest_feed_item.rb +11 -0
  27. data/lib/hootenanny/feed/feed_item.rb +30 -0
  28. data/lib/hootenanny/feed/file.rb +66 -0
  29. data/lib/hootenanny/feed/json_feed.rb +48 -0
  30. data/lib/hootenanny/feed/json_feed_item.rb +8 -0
  31. data/lib/hootenanny/feed/null_feed.rb +27 -0
  32. data/lib/hootenanny/feed/rss_feed.rb +52 -0
  33. data/lib/hootenanny/feed/rss_feed_item.rb +8 -0
  34. data/lib/hootenanny/feed_store.rb +30 -0
  35. data/lib/hootenanny/feed_store/file_feed_store.rb +55 -0
  36. data/lib/hootenanny/feed_store/web_feed_store.rb +42 -0
  37. data/lib/hootenanny/hub.rb +116 -22
  38. data/lib/hootenanny/publish_notification_expiration_policy.rb +17 -0
  39. data/lib/hootenanny/request.rb +40 -0
  40. data/lib/hootenanny/request/publish_notification.rb +94 -0
  41. data/lib/hootenanny/request/subscription.rb +153 -0
  42. data/lib/hootenanny/subscription_delivery.rb +47 -0
  43. data/lib/hootenanny/topic.rb +38 -0
  44. data/lib/hootenanny/topic_synchronizer.rb +71 -0
  45. data/lib/hootenanny/uri.rb +53 -0
  46. data/lib/hootenanny/verification.rb +108 -0
  47. data/lib/hootenanny/version.rb +1 -1
  48. data/spec/dummy/config/database.yml +12 -6
  49. data/spec/dummy/db/migrate/20130607183149_add_started_at_and_lease_duration_to_subscriptions.hootenanny.rb +16 -0
  50. data/spec/dummy/db/migrate/20130608231253_add_hmac_secret_to_subscription.hootenanny.rb +6 -0
  51. data/spec/dummy/db/migrate/20130611235546_add_publish_notifications.hootenanny.rb +10 -0
  52. data/spec/dummy/db/migrate/20130612153353_add_timestamps_to_publish_notification.hootenanny.rb +6 -0
  53. data/spec/dummy/db/migrate/20130705200832_add_processed_flag_to_publish_notifications.hootenanny.rb +7 -0
  54. data/spec/dummy/db/migrate/20130711061518_switch_publish_notification_process_state_from_boolean_to_string.hootenanny.rb +12 -0
  55. data/spec/dummy/db/migrate/20130711061629_add_index_to_notifications_state.hootenanny.rb +6 -0
  56. data/spec/factories/publish_notification.rb +13 -0
  57. data/spec/factories/requests/publish_notification.rb +11 -0
  58. data/spec/factories/requests/subscription.rb +46 -0
  59. data/spec/factories/subscription.rb +14 -2
  60. data/spec/factories/verification.rb +15 -0
  61. data/spec/features/publishers/can_notify_the_hub_of_content_updates_spec.rb +58 -0
  62. data/spec/features/subscribers/are_protected_from_unwarranted_subscriptions_spec.rb +59 -0
  63. data/spec/features/subscribers/can_receive_distributions_of_topic_content_spec.rb +175 -0
  64. data/spec/features/subscribers/can_subscribe_to_a_topic_spec.rb +76 -7
  65. data/spec/fixtures/feeds/atom/97d79220f68b4bf27.atom +0 -0
  66. data/spec/fixtures/feeds/atom/sample_feed.atom +51 -0
  67. data/spec/fixtures/feeds/digest/97d79220f68b4bf27.digest +1 -0
  68. data/spec/fixtures/feeds/digest/complete_broadcasted_items/5b187098da59f077f/97d79220f68b4bf27.digest +6 -0
  69. data/spec/fixtures/feeds/digest/incomplete_broadcasted_items/5b187098da59f077f/97d79220f68b4bf27.digest +5 -0
  70. data/spec/fixtures/feeds/digest/sample_feed.digest +6 -0
  71. data/spec/fixtures/feeds/json/97d79220f68b4bf27.json +1 -0
  72. data/spec/fixtures/feeds/json/feed_with_one_item.json +21 -0
  73. data/spec/fixtures/feeds/json/sample_feed.json +30 -0
  74. data/spec/fixtures/feeds/rss/5b187098da59f077f/97d79220f68b4bf27.rss +21 -0
  75. data/spec/fixtures/feeds/rss/97d79220f68b4bf27.rss +0 -0
  76. data/spec/fixtures/feeds/rss/feed_with_one_item.rss +15 -0
  77. data/spec/fixtures/feeds/rss/minimal_feed.rss +12 -0
  78. data/spec/fixtures/feeds/rss/sample_feed.rss +22 -0
  79. data/spec/fixtures/feeds/rss/sample_feed_2.rss +22 -0
  80. data/spec/lib/hootenanny/configuration_spec.rb +7 -0
  81. data/spec/lib/hootenanny/correspondent_spec.rb +94 -0
  82. data/spec/lib/hootenanny/errors_spec.rb +21 -0
  83. data/spec/lib/hootenanny/feed/atom_feed_item_spec.rb +9 -0
  84. data/spec/lib/hootenanny/feed/atom_feed_spec.rb +40 -0
  85. data/spec/lib/hootenanny/feed/digest_feed_item_spec.rb +9 -0
  86. data/spec/lib/hootenanny/feed/digest_feed_spec.rb +40 -0
  87. data/spec/lib/hootenanny/feed/feed_item_spec.rb +49 -0
  88. data/spec/lib/hootenanny/feed/file_spec.rb +66 -0
  89. data/spec/lib/hootenanny/feed/json_feed_item_spec.rb +9 -0
  90. data/spec/lib/hootenanny/feed/json_feed_spec.rb +128 -0
  91. data/spec/lib/hootenanny/feed/null_feed_spec.rb +9 -0
  92. data/spec/lib/hootenanny/feed/rss_feed_item_spec.rb +9 -0
  93. data/spec/lib/hootenanny/feed/rss_feed_spec.rb +143 -0
  94. data/spec/lib/hootenanny/feed_spec.rb +159 -0
  95. data/spec/lib/hootenanny/feed_store/file_feed_store_spec.rb +58 -0
  96. data/spec/lib/hootenanny/feed_store/web_feed_store_spec.rb +47 -0
  97. data/spec/lib/hootenanny/feed_store_spec.rb +27 -0
  98. data/spec/lib/hootenanny/hub_spec.rb +73 -0
  99. data/spec/lib/hootenanny/publish_notification_expiration_policy_spec.rb +35 -0
  100. data/spec/lib/hootenanny/request/publish_notification_spec.rb +43 -0
  101. data/spec/lib/hootenanny/request/subscription_spec.rb +89 -0
  102. data/spec/lib/hootenanny/request_spec.rb +21 -0
  103. data/spec/lib/hootenanny/subscription_delivery_spec.rb +54 -0
  104. data/spec/lib/hootenanny/topic_spec.rb +15 -0
  105. data/spec/lib/hootenanny/topic_synchronizer_spec.rb +98 -0
  106. data/spec/lib/hootenanny/uri_spec.rb +32 -0
  107. data/spec/lib/hootenanny/verification_spec.rb +92 -0
  108. data/spec/models/hootenanny/publish_notification_spec.rb +55 -0
  109. data/spec/models/hootenanny/subscription_spec.rb +58 -19
  110. data/spec/support/verification.rb +63 -0
  111. metadata +231 -14
  112. data/spec/controllers/hootenanny/hub_spec.rb +0 -15
@@ -0,0 +1,73 @@
1
+ require 'rspectacular/spec_helpers/active_record_basic'
2
+ require 'hootenanny/hub'
3
+
4
+ module Hootenanny
5
+ describe Hub do
6
+ it 'can apply the request' do
7
+ my_request = double
8
+
9
+ allow(my_request).to receive(:apply)
10
+
11
+ Hub.subscribe(my_request)
12
+
13
+ expect(my_request).to(have_received(:apply))
14
+ end
15
+
16
+ it 'can generate a request' do
17
+ allow(Request).to receive(:build)
18
+
19
+ Hub.request(:my_attrs => :my_value)
20
+
21
+ expect(Request).to have_received(:build)
22
+ .with(:my_attrs => :my_value)
23
+ end
24
+
25
+ it 'can broadcast all notifications' do
26
+ create(:publish_notification, :unprocessed,
27
+ :topic => 'http://topic1.com')
28
+ create(:publish_notification, :unprocessed,
29
+ :topic => 'http://topic2.com')
30
+
31
+ allow(Hootenanny::Correspondent).to receive(:broadcast).
32
+ and_return true
33
+
34
+ Hub.broadcast
35
+
36
+ expect(Hootenanny::Correspondent).to have_received(:broadcast).
37
+ with('http://topic1.com')
38
+
39
+ expect(Hootenanny::Correspondent).to have_received(:broadcast).
40
+ with('http://topic2.com')
41
+ end
42
+
43
+ it 'removes the notification if it has been broadcast successfully' do
44
+ notification_the_first = create(:publish_notification, :unprocessed,
45
+ :topic => 'http://topic1.com')
46
+ notification_the_second = create(:publish_notification, :unprocessed,
47
+ :topic => 'http://topic2.com')
48
+
49
+ allow(Hootenanny::Correspondent).to receive(:broadcast).
50
+ and_return true
51
+
52
+ Hub.broadcast
53
+
54
+ expect(notification_the_first.reload).to be_processed
55
+ expect(notification_the_second.reload).to be_processed
56
+ end
57
+
58
+ it 'does not remove the notification if it has not been broadcast successfully' do
59
+ notification_the_first = create(:publish_notification, :unprocessed,
60
+ :topic => 'http://topic1.com')
61
+ notification_the_second = create(:publish_notification, :unprocessed,
62
+ :topic => 'http://topic2.com')
63
+
64
+ allow(Hootenanny::Correspondent).to receive(:broadcast).
65
+ and_return true
66
+
67
+ Hub.broadcast
68
+
69
+ expect { notification_the_first.reload }.to be_true
70
+ expect { notification_the_second.reload }.to be_true
71
+ end
72
+ end
73
+ end
@@ -0,0 +1,35 @@
1
+ require 'rspectacular'
2
+ require 'hootenanny/publish_notification_expiration_policy'
3
+
4
+ module Hootenanny
5
+ describe PublishNotificationExpirationPolicy, :time_mock do
6
+ let(:one_day_ago) { Time.now - 86_400 }
7
+
8
+ it 'will expire the item if it has been at least a day since it has been updated' do
9
+ notification = double(:updated_at => (one_day_ago - 1),
10
+ :expire => true)
11
+
12
+ PublishNotificationExpirationPolicy.apply(notification)
13
+
14
+ expect(notification).to have_received(:expire)
15
+ end
16
+
17
+ it 'will not expire the item if it has been exactly a day since it has been updated' do
18
+ notification = double(:updated_at => one_day_ago,
19
+ :expire => true)
20
+
21
+ PublishNotificationExpirationPolicy.apply(notification)
22
+
23
+ expect(notification).not_to have_received(:expire)
24
+ end
25
+
26
+ it 'will not expire the item if it has been less than a day since it has been updated' do
27
+ notification = double(:updated_at => (one_day_ago + 1),
28
+ :expire => true)
29
+
30
+ PublishNotificationExpirationPolicy.apply(notification)
31
+
32
+ expect(notification).not_to have_received(:expire)
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,43 @@
1
+ require 'rspectacular/spec_helpers/active_record_basic'
2
+ require 'hootenanny/request/publish_notification'
3
+
4
+ module Hootenanny
5
+ describe Request::PublishNotification do
6
+ it 'can properly build itself given valid attributes' do
7
+ my_request = Request::PublishNotification.build(topics: %w{mytopic myothertopic})
8
+
9
+ expect(my_request.topics).to eql %w{mytopic myothertopic}
10
+ end
11
+
12
+ it 'requires at least one topic to be buillt' do
13
+ expect { Request::PublishNotification.build }
14
+ .to raise_error ::Hootenanny::Request::BuildError
15
+ end
16
+
17
+ it 'generates a Publish Notification for a topic' do
18
+ allow(PublishNotification).to receive(:notify)
19
+ .and_return(:publish_notification)
20
+
21
+ my_request = build( :publish_notification_request,
22
+ :topics => 'mytopic')
23
+
24
+ expect(my_request.apply).to have(1).items
25
+ expect(PublishNotification).to have_received(:notify)
26
+ .with('mytopic')
27
+ end
28
+
29
+ it 'generates a Publish Notification for each of the topics' do
30
+ allow(PublishNotification).to receive(:notify)
31
+ .and_return(:publish_notification)
32
+
33
+ my_request = build( :publish_notification_request,
34
+ :topics => %w{mytopic myothertopic})
35
+
36
+ expect(my_request.apply).to have(2).items
37
+ expect(PublishNotification).to have_received(:notify)
38
+ .with('mytopic')
39
+ expect(PublishNotification).to have_received(:notify)
40
+ .with('myothertopic')
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,89 @@
1
+ require 'rspectacular/spec_helpers/active_record_basic'
2
+ require 'hootenanny/request/subscription'
3
+
4
+ module Hootenanny
5
+ describe Request::Subscription do
6
+ let(:verification_class) { double }
7
+
8
+ it 'can properly build itself given valid attributes' do
9
+ my_request = Request::Subscription.build(callback: 'http://mycallback',
10
+ topic: 'http://mytopic',)
11
+
12
+ expect(my_request.subscriber).to eql 'http://mycallback'
13
+ expect(my_request.topic).to eql 'http://mytopic'
14
+ end
15
+
16
+ it 'requires a callback to be buillt' do
17
+ expect { Request::Subscription.build(topic: 'http://mytopic') }
18
+ .to raise_error ::Hootenanny::Request::BuildError
19
+ end
20
+
21
+ it 'requires a topic to be buillt' do
22
+ expect { Request::Subscription.build(callback: 'http://mycallback') }
23
+ .to raise_error ::Hootenanny::Request::BuildError
24
+ end
25
+
26
+ it 'generates a Subscription when the request is verified' do
27
+ allow(Subscription).to receive(:subscribe)
28
+ .and_return(:subscription)
29
+
30
+ my_request = build( :subscription_request,
31
+ :verified,
32
+ :subscriber => 'http://mycallback',
33
+ :topic => 'http://mytopic',
34
+ :digest_secret => 'secret',
35
+ :lease_duration => 600)
36
+
37
+ expect(my_request.apply).to eql :subscription
38
+ expect(Subscription).to( have_received(:subscribe)
39
+ .with( :subscriber => 'http://mycallback',
40
+ :to => 'http://mytopic',
41
+ :lease_duration => 600,
42
+ :digest_secret => 'secret'))
43
+ end
44
+
45
+ it 'defaults the lease duration to 1 hour if none is specified' do
46
+ allow(Subscription).to receive(:subscribe)
47
+ .and_return(:subscription)
48
+
49
+ my_request = build( :subscription_request,
50
+ :verified,
51
+ :subscriber => 'http://mycallback',
52
+ :topic => 'http://mytopic',
53
+ :digest_secret => 'my big secret')
54
+
55
+ expect(my_request.apply).to eql :subscription
56
+ expect(Subscription).to( have_received(:subscribe)
57
+ .with( :subscriber => 'http://mycallback',
58
+ :to => 'http://mytopic',
59
+ :digest_secret => 'my big secret',
60
+ :lease_duration => 1_577_880_000))
61
+ end
62
+
63
+ it 'can create a verification with the proper information' do
64
+ allow(verification_class).to receive(:new)
65
+ .and_return(double :verified? => true)
66
+
67
+ my_request = build( :subscription_request,
68
+ subscriber: 'http://mycallback',
69
+ topic: 'http://mytopic',
70
+ requester_token: '12345',
71
+ verification_class: verification_class)
72
+
73
+ my_request.apply
74
+
75
+ expect(verification_class).to have_received(:new)
76
+ .with(
77
+ url: 'http://mycallback',
78
+ mode: :subscribe,
79
+ topic: 'http://mytopic',
80
+ requester_token: '12345')
81
+ end
82
+
83
+ it 'does not generate a Subscription when the request is unverified' do
84
+ my_request = build(:subscription_request, :unverified)
85
+
86
+ expect { my_request.apply }.to raise_error(Hootenanny::SubscriptionError, 'Request could not be verified.')
87
+ end
88
+ end
89
+ end
@@ -0,0 +1,21 @@
1
+ require 'rspectacular'
2
+ require 'hootenanny/request'
3
+
4
+ module Hootenanny
5
+ describe Request do
6
+ it 'can build the proper request based on the options passed in' do
7
+ allow(Request::Subscription).to(receive(:build))
8
+
9
+ Request.build(type: :subscription,
10
+ other_attr: true)
11
+
12
+ expect(Request::Subscription).to(have_received(:build)
13
+ .with( type: :subscription,
14
+ other_attr: true))
15
+ end
16
+
17
+ it 'raises a wrapped exception whenever no type is passed in' do
18
+ expect { Request.build({}) }.to raise_error(Request::BuildError, 'key not found: :type')
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,54 @@
1
+ require 'rspectacular'
2
+ require 'hootenanny/subscription_delivery'
3
+
4
+ module Hootenanny
5
+ describe SubscriptionDelivery do
6
+ it 'can deliver a feed to a subscriber' do
7
+ feed = double(to_s: 'my_feed_content',
8
+ content_type: 'application/whatever')
9
+
10
+ subscription_stub = stub_request(:post, 'http://example.com').
11
+ with(:headers => {'Content-Type' => 'application/whatever'}).
12
+ to_return(:status => 200)
13
+
14
+ SubscriptionDelivery.deliver(subscriber: 'http://example.com',
15
+ feed: feed)
16
+
17
+ expect(subscription_stub).to have_been_requested
18
+ end
19
+
20
+ it 'will add a verification digest along with the content if a secret was specified' do
21
+ feed = double(to_s: 'my_feed_content',
22
+ content_type: 'application/whatever')
23
+
24
+ subscription_stub = stub_request(:post, 'http://example.com').
25
+ with(:headers => {'Content-Type' => 'application/whatever',
26
+ 'X-Hub-Signature' => 'sha1=dde90de8a0b89aff446c53ff63ec68b4087b0d3b'}).
27
+ to_return(:status => 200)
28
+
29
+ SubscriptionDelivery.deliver(subscriber: 'http://example.com',
30
+ digest_secret: 'secret',
31
+ feed: feed)
32
+
33
+ expect(subscription_stub).to have_been_requested
34
+ end
35
+
36
+ it 'is true if successful' do
37
+ stub_request(:post, 'http://example.com').
38
+ to_return(:status => 200)
39
+
40
+ expect(SubscriptionDelivery.deliver(subscriber: 'http://example.com',
41
+ feed: double.as_null_object)).to \
42
+ be_true
43
+ end
44
+
45
+ it 'is false if unsuccessful' do
46
+ stub_request(:post, 'http://example.com').
47
+ to_return(:status => 300)
48
+
49
+ expect(SubscriptionDelivery.deliver(subscriber: 'http://example.com',
50
+ feed: double.as_null_object)).to \
51
+ be_false
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,15 @@
1
+ require 'rspectacular'
2
+ require 'hootenanny/topic'
3
+
4
+ module Hootenanny
5
+ describe Topic do
6
+ it 'can create itself from a topic' do
7
+ expect(Topic.from_url('http://example.com')).to be_a Topic
8
+ end
9
+
10
+ it 'cannot create itself if the URI is invalid' do
11
+ expect {Topic.from_url('http://#^&@*.com')}.
12
+ to raise_error Hootenanny::URI::InvalidError
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,98 @@
1
+ require 'rspectacular'
2
+ require 'hootenanny/topic_synchronizer'
3
+ require 'hootenanny/errors'
4
+ require 'hootenanny/feed_store/file_feed_store'
5
+
6
+ module Hootenanny
7
+ describe TopicSynchronizer do
8
+ let(:subscription_delivery) { double }
9
+ let(:subscriber_url) { 'http://subscriber.com' }
10
+ let(:topic_url) { 'http://topic.com' }
11
+ let(:local_feed_store) { FeedStore::FileFeedStore.new(
12
+ location: local_feed_file_path) }
13
+ let(:remote_feed_store) { FeedStore::FileFeedStore.new(
14
+ location: remote_feed_file_path) }
15
+
16
+ let(:topic_synchronizer) { TopicSynchronizer.new(
17
+ subscriber: subscriber_url,
18
+ topic: topic_url,
19
+ local_feed_store: local_feed_store,
20
+ remote_feed_store: remote_feed_store,
21
+ subscription_delivery: subscription_delivery) }
22
+
23
+ before { allow(subscription_delivery).to receive(:deliver) }
24
+
25
+ context 'if there are no new items to deliver' do
26
+ let(:local_feed_file_path) { './spec/fixtures/feeds/digest/complete_broadcasted_items' }
27
+ let(:remote_feed_file_path) { './spec/fixtures/feeds/rss' }
28
+
29
+ it 'does not try to deliver anything' do
30
+ expect(topic_synchronizer.sync).to be_true
31
+ expect(subscription_delivery).not_to have_received(:deliver)
32
+ end
33
+ end
34
+
35
+ context 'if there are items to deliver' do
36
+ let(:local_feed_file_path) { './spec/fixtures/feeds/digest/incomplete_broadcasted_items' }
37
+ let(:remote_feed_file_path) { './spec/fixtures/feeds/rss' }
38
+
39
+ context 'and the unsynchronized items were delivered successfully' do
40
+ before { allow(subscription_delivery).to receive(:deliver).
41
+ and_return true }
42
+
43
+ it 'stores the freshly synchronized feed items' do
44
+ allow(local_feed_store).to receive(:store)
45
+
46
+ topic_synchronizer.sync
47
+
48
+ expect(local_feed_store).to have_received(:store)
49
+ end
50
+ end
51
+
52
+ context 'and the unsynchronized items were not delivered successfully' do
53
+ before { allow(subscription_delivery).to receive(:deliver).
54
+ and_return false }
55
+
56
+ it 'returns false' do
57
+ expect(topic_synchronizer.sync).to be_a FalseClass
58
+ end
59
+ end
60
+ end
61
+
62
+ it 'retrieves the local feed store from the global configuration if none is passed in' do
63
+ allow(Hootenanny::Configuration.instance).to receive(:default_local_feed_store)
64
+
65
+ TopicSynchronizer.new(subscriber: 'http://subscriber.com',
66
+ topic: 'http://topic.com')
67
+
68
+ expect(Hootenanny::Configuration.instance).to have_received(:default_local_feed_store)
69
+ end
70
+
71
+ it 'retrieves the remote feed store from the global configuration if none is passed in' do
72
+ allow(Hootenanny::Configuration.instance).to receive(:default_remote_feed_store)
73
+
74
+ TopicSynchronizer.new(subscriber: 'http://subscriber.com',
75
+ topic: 'http://topic.com')
76
+
77
+ expect(Hootenanny::Configuration.instance).to have_received(:default_remote_feed_store)
78
+ end
79
+
80
+ it 'retrieves the remote feed store from the global configuration if none is passed in' do
81
+ allow(Hootenanny::Configuration.instance).to receive(:default_remote_feed_store)
82
+
83
+ TopicSynchronizer.new(subscriber: 'http://subscriber.com',
84
+ topic: 'http://topic.com')
85
+
86
+ expect(Hootenanny::Configuration.instance).to have_received(:default_remote_feed_store)
87
+ end
88
+
89
+ it 'retrieves the subscription delivery from the global configuration if none is passed in' do
90
+ allow(Hootenanny::Configuration.instance).to receive(:default_subscription_delivery)
91
+
92
+ TopicSynchronizer.new(subscriber: 'http://subscriber.com',
93
+ topic: 'http://topic.com')
94
+
95
+ expect(Hootenanny::Configuration.instance).to have_received(:default_subscription_delivery)
96
+ end
97
+ end
98
+ end
@@ -0,0 +1,32 @@
1
+ require 'rspectacular'
2
+ require 'hootenanny/uri'
3
+
4
+ module Hootenanny
5
+ describe URI do
6
+ it 'removes the anchor portion when parsing a URI' do
7
+ uri = URI.parse('http://example.com#anchor')
8
+
9
+ expect(uri.to_s).to eql 'http://example.com'
10
+ end
11
+
12
+ it 'properly handles the error when the URI is invalid' do
13
+ expect { URI.parse('http://example.com!!!!!!!!') }.to raise_error Hootenanny::URI::InvalidError
14
+ end
15
+
16
+ it 'allows HTTP URIs' do
17
+ uri = URI.parse('http://example.com')
18
+
19
+ expect(uri.to_s).to eql 'http://example.com'
20
+ end
21
+
22
+ it 'allows HTTPS URIs' do
23
+ uri = URI.parse('https://example.com')
24
+
25
+ expect(uri.to_s).to eql 'https://example.com'
26
+ end
27
+
28
+ it 'does not allow URIs other than HTTP or HTTPS' do
29
+ expect { URI.parse('ftp://example.com') }.to raise_error Hootenanny::URI::InvalidSchemeError
30
+ end
31
+ end
32
+ end