Specs for pubsub subscribe service (#2951)
* Add spec for pubsubhubbub/subscribe * Refactor pubsubhubbub/subscribe service
This commit is contained in:
		
							parent
							
								
									441d6dc734
								
							
						
					
					
						commit
						682507bc3c
					
				
					 2 changed files with 123 additions and 5 deletions
				
			
		|  | @ -1,14 +1,61 @@ | ||||||
| # frozen_string_literal: true | # frozen_string_literal: true | ||||||
| 
 | 
 | ||||||
| class Pubsubhubbub::SubscribeService < BaseService | class Pubsubhubbub::SubscribeService < BaseService | ||||||
|  |   URL_PATTERN = /\A#{URI.regexp(%w(http https))}\z/ | ||||||
|  | 
 | ||||||
|  |   attr_reader :account, :callback, :secret, :lease_seconds | ||||||
|  | 
 | ||||||
|   def call(account, callback, secret, lease_seconds) |   def call(account, callback, secret, lease_seconds) | ||||||
|     return ['Invalid topic URL',        422] if account.nil? |     @account = account | ||||||
|     return ['Invalid callback URL',     422] unless !callback.blank? && callback =~ /\A#{URI.regexp(%w(http https))}\z/ |     @callback = callback | ||||||
|     return ['Callback URL not allowed', 403] if DomainBlock.blocked?(Addressable::URI.parse(callback).normalize.host) |     @secret = secret | ||||||
|  |     @lease_seconds = lease_seconds | ||||||
| 
 | 
 | ||||||
|     subscription = Subscription.where(account: account, callback_url: callback).first_or_create!(account: account, callback_url: callback) |     process_subscribe | ||||||
|  |   end | ||||||
|  | 
 | ||||||
|  |   private | ||||||
|  | 
 | ||||||
|  |   def process_subscribe | ||||||
|  |     case subscribe_status | ||||||
|  |     when :invalid_topic | ||||||
|  |       ['Invalid topic URL', 422] | ||||||
|  |     when :invalid_callback | ||||||
|  |       ['Invalid callback URL', 422] | ||||||
|  |     when :callback_not_allowed | ||||||
|  |       ['Callback URL not allowed', 403] | ||||||
|  |     when :valid | ||||||
|  |       confirm_subscription | ||||||
|  |       ['', 202] | ||||||
|  |     end | ||||||
|  |   end | ||||||
|  | 
 | ||||||
|  |   def subscribe_status | ||||||
|  |     if account.nil? | ||||||
|  |       :invalid_topic | ||||||
|  |     elsif !valid_callback? | ||||||
|  |       :invalid_callback | ||||||
|  |     elsif blocked_domain? | ||||||
|  |       :callback_not_allowed | ||||||
|  |     else | ||||||
|  |       :valid | ||||||
|  |     end | ||||||
|  |   end | ||||||
|  | 
 | ||||||
|  |   def confirm_subscription | ||||||
|  |     subscription = locate_subscription | ||||||
|     Pubsubhubbub::ConfirmationWorker.perform_async(subscription.id, 'subscribe', secret, lease_seconds) |     Pubsubhubbub::ConfirmationWorker.perform_async(subscription.id, 'subscribe', secret, lease_seconds) | ||||||
|  |   end | ||||||
| 
 | 
 | ||||||
|     ['', 202] |   def valid_callback? | ||||||
|  |     callback.present? && callback =~ URL_PATTERN | ||||||
|  |   end | ||||||
|  | 
 | ||||||
|  |   def blocked_domain? | ||||||
|  |     DomainBlock.blocked? Addressable::URI.parse(callback).normalize.host | ||||||
|  |   end | ||||||
|  | 
 | ||||||
|  |   def locate_subscription | ||||||
|  |     Subscription.where(account: account, callback_url: callback).first_or_create!(account: account, callback_url: callback) | ||||||
|   end |   end | ||||||
| end | end | ||||||
|  |  | ||||||
							
								
								
									
										71
									
								
								spec/services/pubsubhubbub/subscribe_service_spec.rb
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										71
									
								
								spec/services/pubsubhubbub/subscribe_service_spec.rb
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,71 @@ | ||||||
|  | # frozen_string_literal: true | ||||||
|  | 
 | ||||||
|  | require 'rails_helper' | ||||||
|  | 
 | ||||||
|  | describe Pubsubhubbub::SubscribeService do | ||||||
|  |   describe '#call' do | ||||||
|  |     subject { described_class.new } | ||||||
|  |     let(:user_account) { Fabricate(:account) } | ||||||
|  | 
 | ||||||
|  |     context 'with a nil account' do | ||||||
|  |       it 'returns the invalid topic status results' do | ||||||
|  |         result = service_call(account: nil) | ||||||
|  | 
 | ||||||
|  |         expect(result).to eq invalid_topic_status | ||||||
|  |       end | ||||||
|  |     end | ||||||
|  | 
 | ||||||
|  |     context 'with an invalid callback url' do | ||||||
|  |       it 'returns invalid callback status when callback is blank' do | ||||||
|  |         result = service_call(callback: '') | ||||||
|  | 
 | ||||||
|  |         expect(result).to eq invalid_callback_status | ||||||
|  |       end | ||||||
|  |       it 'returns invalid callback status when callback is not a URI' do | ||||||
|  |         result = service_call(callback: 'invalid-hostname') | ||||||
|  | 
 | ||||||
|  |         expect(result).to eq invalid_callback_status | ||||||
|  |       end | ||||||
|  |     end | ||||||
|  | 
 | ||||||
|  |     context 'with a blocked domain in the callback' do | ||||||
|  |       it 'returns callback not allowed' do | ||||||
|  |         Fabricate(:domain_block, domain: 'test.host', severity: :suspend) | ||||||
|  |         result = service_call(callback: 'https://test.host/api') | ||||||
|  | 
 | ||||||
|  |         expect(result).to eq not_allowed_callback_status | ||||||
|  |       end | ||||||
|  |     end | ||||||
|  | 
 | ||||||
|  |     context 'with a valid account and callback' do | ||||||
|  |       it 'returns success status and confirms subscription' do | ||||||
|  |         allow(Pubsubhubbub::ConfirmationWorker).to receive(:perform_async).and_return(nil) | ||||||
|  |         subscription = Fabricate(:subscription, account: user_account) | ||||||
|  | 
 | ||||||
|  |         result = service_call(callback: subscription.callback_url) | ||||||
|  |         expect(result).to eq success_status | ||||||
|  |         expect(Pubsubhubbub::ConfirmationWorker).to have_received(:perform_async).with(subscription.id, 'subscribe', 'asdf', 3600) | ||||||
|  |       end | ||||||
|  |     end | ||||||
|  |   end | ||||||
|  | 
 | ||||||
|  |   def service_call(account: user_account, callback: 'https://callback.host', secret: 'asdf', lease_seconds: 3600) | ||||||
|  |     subject.call(account, callback, secret, lease_seconds) | ||||||
|  |   end | ||||||
|  | 
 | ||||||
|  |   def invalid_topic_status | ||||||
|  |     ['Invalid topic URL', 422] | ||||||
|  |   end | ||||||
|  | 
 | ||||||
|  |   def invalid_callback_status | ||||||
|  |     ['Invalid callback URL', 422] | ||||||
|  |   end | ||||||
|  | 
 | ||||||
|  |   def not_allowed_callback_status | ||||||
|  |     ['Callback URL not allowed', 403] | ||||||
|  |   end | ||||||
|  | 
 | ||||||
|  |   def success_status | ||||||
|  |     ['', 202] | ||||||
|  |   end | ||||||
|  | end | ||||||
		Loading…
	
	Add table
		
		Reference in a new issue