summaryrefslogtreecommitdiff
path: root/qa/qa/support/api.rb
blob: 579227b4f7ae8b3cc9eaae494cb233478e2dfa86 (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
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
# frozen_string_literal: true

require 'rest-client'

module QA
  module Support
    module Api
      HTTP_STATUS_OK = 200
      HTTP_STATUS_CREATED = 201
      HTTP_STATUS_NO_CONTENT = 204
      HTTP_STATUS_ACCEPTED = 202
      HTTP_STATUS_NOT_FOUND = 404
      HTTP_STATUS_SERVER_ERROR = 500

      def post(url, payload, args = {})
        default_args = {
          method: :post,
          url: url,
          payload: payload,
          verify_ssl: false
        }

        RestClient::Request.execute(
          default_args.merge(args)
        )
      rescue RestClient::ExceptionWithResponse => e
        return_response_or_raise(e)
      end

      def get(url, args = {})
        default_args = {
          method: :get,
          url: url,
          verify_ssl: false
        }

        RestClient::Request.execute(
          default_args.merge(args)
        )
      rescue RestClient::ExceptionWithResponse => e
        return_response_or_raise(e)
      end

      def put(url, payload = nil)
        RestClient::Request.execute(
          method: :put,
          url: url,
          payload: payload,
          verify_ssl: false)
      rescue RestClient::ExceptionWithResponse => e
        return_response_or_raise(e)
      end

      def delete(url)
        RestClient::Request.execute(
          method: :delete,
          url: url,
          verify_ssl: false)
      rescue RestClient::ExceptionWithResponse => e
        return_response_or_raise(e)
      end

      def head(url)
        RestClient::Request.execute(
          method: :head,
          url: url,
          verify_ssl: false)
      rescue RestClient::ExceptionWithResponse => e
        return_response_or_raise(e)
      end

      def parse_body(response)
        JSON.parse(response.body, symbolize_names: true)
      end

      def return_response_or_raise(error)
        raise error unless error.respond_to?(:response) && error.response

        error.response
      end

      def auto_paginated_response(url, attempts: 0)
        pages = []
        with_paginated_response_body(url, attempts: attempts) { |response| pages << response }

        pages.flatten
      end

      def with_paginated_response_body(url, attempts: 0)
        not_ok_error = lambda do |resp|
          raise "Failed to GET #{QA::Runtime::API::Request.masked_url(url)} - (#{resp.code}): `#{resp}`."
        end

        loop do
          response = if attempts > 0
                       Retrier.retry_on_exception(max_attempts: attempts, log: false) do
                         get(url).tap { |resp| not_ok_error.call(resp) if resp.code != HTTP_STATUS_OK }
                       end
                     else
                       get(url).tap { |resp| not_ok_error.call(resp) if resp.code != HTTP_STATUS_OK }
                     end

          page, pages = response.headers.values_at(:x_page, :x_total_pages)
          api_endpoint = url.match(%r{v4/(\S+)\?})[1]

          QA::Runtime::Logger.debug("Fetching page (#{page}/#{pages}) for '#{api_endpoint}' ...") unless pages.to_i <= 1

          yield parse_body(response)

          next_link = pagination_links(response).find { |link| link[:rel] == 'next' }
          break unless next_link

          url = next_link[:url]
        end
      end

      def pagination_links(response)
        link = response.headers[:link]
        return unless link

        link.split(',').map do |link|
          match = link.match(/<(?<url>.*)>; rel="(?<rel>\w+)"/)
          break nil unless match

          { url: match[:url], rel: match[:rel] }
        end.compact
      end
    end
  end
end