265 lines
		
	
	
		
			8.6 KiB
		
	
	
	
		
			Ruby
		
	
	
	
	
	
			
		
		
	
	
			265 lines
		
	
	
		
			8.6 KiB
		
	
	
	
		
			Ruby
		
	
	
	
	
	
| # frozen_string_literal: true
 | |
| 
 | |
| # rubocop:disable Metrics/BlockLength
 | |
| require 'spec_helper'
 | |
| 
 | |
| describe(Jekyll::Algolia::ErrorHandler) do
 | |
|   let(:current) { Jekyll::Algolia::ErrorHandler }
 | |
|   let(:configurator) { Jekyll::Algolia::Configurator }
 | |
|   let(:logger) { Jekyll::Algolia::Logger }
 | |
| 
 | |
|   describe '.stop' do
 | |
|     subject { -> { current.stop(error) } }
 | |
| 
 | |
|     let(:error) { double('Error') }
 | |
|     let(:identified_error) { nil }
 | |
|     before do
 | |
|       allow(current).to receive(:identify).and_return(identified_error)
 | |
|       allow(logger).to receive(:log)
 | |
|     end
 | |
| 
 | |
|     context 'with unknown error' do
 | |
|       let(:identified_error) { false }
 | |
|       before do
 | |
|         expect(logger).to receive(:log).with("E:#{error}")
 | |
|       end
 | |
| 
 | |
|       it { is_expected.to raise_error SystemExit }
 | |
|     end
 | |
| 
 | |
|     context 'with known error' do
 | |
|       let(:identified_error) { { name: 'foo', details: 'bar' } }
 | |
|       before do
 | |
|         expect(logger).to receive(:known_message).with('foo', 'bar')
 | |
|       end
 | |
| 
 | |
|       it { is_expected.to raise_error SystemExit }
 | |
|     end
 | |
|   end
 | |
| 
 | |
|   describe '.error_hash' do
 | |
|     subject { current.error_hash(message) }
 | |
| 
 | |
|     context 'with a regular error message' do
 | |
|       let(:message) do
 | |
|         'Cannot POST to '\
 | |
|         'https://MY_APP_ID.algolia.net/1/section/index_name/action: '\
 | |
|         '{"message":"Custom message","status":403}'\
 | |
|         "\n (403)"
 | |
|       end
 | |
| 
 | |
|       it do
 | |
|         should include('verb' => 'POST')
 | |
|         should include('scheme' => 'https')
 | |
|         should include('application_id' => 'MY_APP_ID')
 | |
|         should include('api_version' => 1)
 | |
|         should include('api_section' => 'section')
 | |
|         should include('index_name' => 'index_name')
 | |
|         should include('api_action' => 'action')
 | |
|         should include('message' => 'Custom message')
 | |
|         should include('status' => 403)
 | |
|       end
 | |
|     end
 | |
| 
 | |
|     context 'with a message with query parameters' do
 | |
|       let(:message) do
 | |
|         'Cannot POST to '\
 | |
|         'https://MY_APP_ID.algolia.net/1/section/index_name/action?foo=bar: '\
 | |
|         '{"message":"Custom message","status":403}'\
 | |
|         "\n (403)"
 | |
|       end
 | |
| 
 | |
|       it do
 | |
|         should include('foo' => 'bar')
 | |
|       end
 | |
|     end
 | |
| 
 | |
|     context 'with an error message with weird characaters' do
 | |
|       let(:message) do
 | |
|         'Cannot POST to '\
 | |
|         'https://MY_APP_ID.algolia.net/1/section/index_name$`!</action: '\
 | |
|         '{"message":"Custom message","status":403}'\
 | |
|         "\n (403)"
 | |
|       end
 | |
| 
 | |
|       it do
 | |
|         should include('index_name' => 'index_name$`!<')
 | |
|       end
 | |
|     end
 | |
| 
 | |
|     context 'with a malformed error message' do
 | |
|       let(:message) { 'Unable to even parse this' }
 | |
| 
 | |
|       it { should eq false }
 | |
|     end
 | |
|   end
 | |
| 
 | |
|   describe '.readable_largest_record_keys' do
 | |
|     let(:record) { { foo: foo, bar: bar, baz: baz, small: 'xxx' } }
 | |
|     let(:foo) { 'x' * 1000 }
 | |
|     let(:bar) { 'x' * 10_000 }
 | |
|     let(:baz) { 'x' * 100_000 }
 | |
| 
 | |
|     subject { current.readable_largest_record_keys(record) }
 | |
| 
 | |
|     it { should eq 'baz (100.00 Kb), bar (10.00 Kb), foo (1.00 Kb)' }
 | |
|   end
 | |
| 
 | |
|   describe '.identify' do
 | |
|     subject { current.identify(error, context) }
 | |
| 
 | |
|     let(:error) { double('Error', message: message) }
 | |
|     let(:context) { {} }
 | |
| 
 | |
|     context 'with unknown application_id' do
 | |
|       let(:message) do
 | |
|         # rubocop:disable Metrics/LineLength
 | |
|         'Cannot reach any host: '\
 | |
|         'getaddrinfo: Name or service not known (MY_APP_ID-dsn.algolia.net:443), '\
 | |
|         'getaddrinfo: No address associated with hostname (MY_APP_ID-3.algolianet.com:443), '\
 | |
|         'getaddrinfo: No address associated with hostname (MY_APP_ID-1.algolianet.com:443), '\
 | |
|         'getaddrinfo: No address associated with hostname (MY_APP_ID-2.algolianet.com:443)'
 | |
|         # rubocop:enable Metrics/LineLength
 | |
|       end
 | |
| 
 | |
|       it { should include(name: 'unknown_application_id') }
 | |
|       it { should include(details: { 'application_id' => 'MY_APP_ID' }) }
 | |
|     end
 | |
| 
 | |
|     context 'with unknown application_id and no DSN' do
 | |
|       let(:message) do
 | |
|         # rubocop:disable Metrics/LineLength
 | |
|         'Cannot reach any host: '\
 | |
|         'getaddrinfo: Name or service not known (MY_APP_ID.algolia.net:443), '\
 | |
|         'getaddrinfo: No address associated with hostname (MY_APP_ID-3.algolianet.com:443), '\
 | |
|         'getaddrinfo: No address associated with hostname (MY_APP_ID-1.algolianet.com:443), '\
 | |
|         'getaddrinfo: No address associated with hostname (MY_APP_ID-2.algolianet.com:443)'
 | |
|         # rubocop:enable Metrics/LineLength
 | |
|       end
 | |
| 
 | |
|       it { should include(name: 'unknown_application_id') }
 | |
|       it { should include(details: { 'application_id' => 'MY_APP_ID' }) }
 | |
|     end
 | |
| 
 | |
|     context 'with wrong API key' do
 | |
|       before do
 | |
|         allow(configurator)
 | |
|           .to receive(:index_name)
 | |
|           .and_return('my_index')
 | |
|       end
 | |
|       let(:message) do
 | |
|         'Cannot POST to '\
 | |
|         'https://MY_APP_ID.algolia.net/1/indexes/my_index/batch: '\
 | |
|         '{"message":"Invalid Application-ID or API key","status":403}'\
 | |
|         "\n (403)"
 | |
|       end
 | |
| 
 | |
|       it { should include(name: 'invalid_credentials') }
 | |
|       it do
 | |
|         should include(details: {
 | |
|                          'application_id' => 'MY_APP_ID'
 | |
|                        })
 | |
|       end
 | |
|     end
 | |
| 
 | |
|     context 'with a record too big' do
 | |
|       let(:message) do
 | |
|         '400: Cannot POST to '\
 | |
|         'https://MY_APP_ID.algolia.net/1/indexes/my_index/batch: '\
 | |
|         '{"message":"Record at the position 3 '\
 | |
|         'objectID=deadbeef is too big size=109196 bytes. '\
 | |
|         'Contact us if you need an extended quota","position":3,'\
 | |
|         '"objectID":"deadbeef","status":400} (400)'
 | |
|       end
 | |
|       let(:context) do
 | |
|         { records: [
 | |
|           {
 | |
|             objectID: 'deadbeef',
 | |
|             title: 'Page title',
 | |
|             url: '/path/to/file.ext',
 | |
|             # rubocop:disable Metrics/LineLength
 | |
|             content: 'A very long text that is obviously too long to fit in one record, but that would be too long to actually display in the error message as well so we will cut it at 100 characters.'
 | |
|             # rubocop:enable Metrics/LineLength
 | |
|           },
 | |
|           { objectID: 'foo' }
 | |
|         ] }
 | |
|       end
 | |
|       let(:record_log_path) { '/source/output.log' }
 | |
|       let(:probable_wrong_keys) { 'foo, bar, baz' }
 | |
|       before do
 | |
|         allow(configurator)
 | |
|           .to receive(:algolia)
 | |
|           .with('nodes_to_index')
 | |
|           .and_return('p,li,foo')
 | |
|         expect(logger)
 | |
|           .to receive(:write_to_file)
 | |
|           .and_return(record_log_path)
 | |
|         expect(current)
 | |
|           .to receive(:readable_largest_record_keys)
 | |
|           .and_return(probable_wrong_keys)
 | |
|       end
 | |
| 
 | |
|       it { should include(name: 'record_too_big') }
 | |
| 
 | |
|       it do
 | |
|         details = subject[:details]
 | |
|         expect(details).to include('object_id' => 'deadbeef')
 | |
|         expect(details).to include('object_title' => 'Page title')
 | |
|         expect(details).to include('object_url' => '/path/to/file.ext')
 | |
|         expect(details).to include('record_log_path' => record_log_path)
 | |
|         expect(details).to include('probable_wrong_keys' => probable_wrong_keys)
 | |
|         expect(details).to include('size' => '109.20 Kb')
 | |
|         expect(details).to include('size_limit' => '10 Kb')
 | |
|         expect(details).to include('nodes_to_index' => 'p,li,foo')
 | |
|       end
 | |
|     end
 | |
| 
 | |
|     context 'with an unknown setting' do
 | |
|       let(:message) do
 | |
|         # rubocop:disable Metrics/LineLength
 | |
|         '400: Cannot PUT to '\
 | |
|         'https://MY_APP_ID.algolia.net/1/indexes/my_index/settings: '\
 | |
|         '{"message":"Invalid object attributes: deadbeef near line:1 column:456",'\
 | |
|         '"status":400} (400)'
 | |
|         # rubocop:enable Metrics/LineLength
 | |
|       end
 | |
|       let(:context) do
 | |
|         { settings:
 | |
|           {
 | |
|             'searchableAttributes' => %w[foo bar],
 | |
|             'deadbeef' => 'foofoo'
 | |
|           } }
 | |
|       end
 | |
| 
 | |
|       it { should include(name: 'unknown_settings') }
 | |
|       it do
 | |
|         details = subject[:details]
 | |
|         expect(details).to include('setting_name' => 'deadbeef')
 | |
|         expect(details).to include('setting_value' => 'foofoo')
 | |
|       end
 | |
|     end
 | |
| 
 | |
|     context 'with an invalid index name' do
 | |
|       before do
 | |
|         allow(configurator)
 | |
|           .to receive(:index_name)
 | |
|           .and_return('invalid_index_name')
 | |
|       end
 | |
|       let(:message) do
 | |
|         # rubocop:disable Metrics/LineLength
 | |
|         '400: Cannot GET to '\
 | |
|         'https://MY_APP_ID-dsn.algolia.net/1/indexes/invalid_index_name/settings?getVersion=2: '\
 | |
|         '{"message":"indexName is not valid","status":400} (400)'
 | |
|         # rubocop:enable Metrics/LineLength
 | |
|       end
 | |
| 
 | |
|       it { should include(name: 'invalid_index_name') }
 | |
|       it do
 | |
|         details = subject[:details]
 | |
|         expect(details).to include('index_name' => 'invalid_index_name')
 | |
|       end
 | |
|     end
 | |
|   end
 | |
| end
 | |
| # rubocop:enable Metrics/BlockLength
 |