summaryrefslogtreecommitdiff
path: root/spec/support/shared_examples/services/jira/requests/base_shared_examples.rb
blob: 56a6d24d557a33bf8e4fefbb77f6746ca7abe8f2 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
# frozen_string_literal: true

RSpec.shared_examples 'a service that handles Jira API errors' do
  include AfterNextHelpers
  using RSpec::Parameterized::TableSyntax

  where(:exception_class, :exception_message, :expected_message) do
    Errno::ECONNRESET | ''    | 'A connection error occurred'
    Errno::ECONNREFUSED | ''  | 'A connection error occurred'
    Errno::ETIMEDOUT | ''     | 'A timeout error occurred'
    Timeout::Error | ''       | 'A timeout error occurred'
    URI::InvalidURIError | '' | 'The Jira API URL'
    SocketError | ''          | 'The Jira API URL'
    OpenSSL::SSL::SSLError | 'foo'   | 'An SSL error occurred while connecting to Jira: foo'
    JIRA::HTTPError | 'Unauthorized' | 'The credentials for accessing Jira are not valid'
    JIRA::HTTPError | 'Forbidden'    | 'The credentials for accessing Jira are not allowed'
    JIRA::HTTPError | 'Bad Request'  | 'An error occurred while requesting data from Jira'
    JIRA::HTTPError | 'Foo'          | 'An error occurred while requesting data from Jira.'
    JIRA::HTTPError | '{"errorMessages":["foo","bar"]}' | 'An error occurred while requesting data from Jira: foo and bar'
    JIRA::HTTPError | '{"errorMessages":[""]}'          | 'An error occurred while requesting data from Jira.'
  end

  with_them do
    it 'handles the error' do
      stub_client_and_raise(exception_class, exception_message)

      expect(subject).to be_a(ServiceResponse)
      expect(subject).to be_error
      expect(subject.message).to include(expected_message)
    end
  end

  context 'when the JSON in JIRA::HTTPError is unsafe' do
    before do
      stub_client_and_raise(JIRA::HTTPError, error)
    end

    context 'when JSON is malformed' do
      let(:error) { '{"errorMessages":' }

      it 'returns the default error message' do
        expect(subject.message).to eq('An error occurred while requesting data from Jira. Check your Jira integration configuration and try again.')
      end
    end

    context 'when JSON contains tags' do
      let(:error) { '{"errorMessages":["<script>alert(true)</script>foo"]}' }

      it 'sanitizes it' do
        expect(subject.message).to eq('An error occurred while requesting data from Jira: foo. Check your Jira integration configuration and try again.')
      end
    end
  end

  it 'allows unknown exception classes to bubble' do
    stub_client_and_raise(StandardError)

    expect { subject }.to raise_exception(StandardError)
  end

  it 'logs the error' do
    stub_client_and_raise(Timeout::Error, 'foo')

    expect(Gitlab::ProjectServiceLogger).to receive(:error).with(
      hash_including(
        client_url: be_present,
        message: 'Error sending message',
        service_class: described_class.name,
        error: hash_including(
          exception_class: Timeout::Error.name,
          exception_message: 'foo',
          exception_backtrace: be_present
        )
      )
    )
    expect(subject).to be_error
  end

  def stub_client_and_raise(exception_class, message = '')
    # `JIRA::HTTPError` classes take a response from the JIRA API, rather than a `String`.
    message = double(body: message) if exception_class == JIRA::HTTPError

    allow_next(JIRA::Client).to receive(:get).and_raise(exception_class, message)
  end
end