esp_sdk 2.7.0 → 2.8.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (55) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +36 -35
  3. data/.travis.yml +2 -1
  4. data/CHANGELOG.md +9 -0
  5. data/Gemfile.lock +63 -85
  6. data/Rakefile +2 -1
  7. data/esp_sdk.gemspec +3 -4
  8. data/lib/esp/aws_clients.rb +2 -2
  9. data/lib/esp/commands/add_external_account.rb +1 -1
  10. data/lib/esp/commands/commands_tasks.rb +2 -2
  11. data/lib/esp/extensions/active_resource/formats/json_api_format.rb +24 -16
  12. data/lib/esp/extensions/active_resource/validations.rb +1 -1
  13. data/lib/esp/resources/alert.rb +3 -2
  14. data/lib/esp/resources/custom_signature/definition.rb +2 -2
  15. data/lib/esp/resources/dashboard.rb +2 -5
  16. data/lib/esp/resources/resource.rb +14 -15
  17. data/lib/esp/resources/stat.rb +2 -5
  18. data/lib/esp/resources/suppression.rb +1 -1
  19. data/lib/esp/version.rb +1 -1
  20. data/test/esp/integration/custom_signature_definition_integration_test.rb +15 -1
  21. data/test/esp/integration/custom_signature_integration_test.rb +3 -1
  22. data/test/esp/integration/custom_signature_result_alert_integration_test.rb +4 -4
  23. data/test/esp/integration/custom_signature_result_integration_test.rb +2 -1
  24. data/test/esp/integration/json_api_format_integration_test.rb +1 -1
  25. data/test/esp/integration/suppression_integration_test.rb +1 -1
  26. data/test/esp/integration/suppression_unique_identifier_integration_test.rb +1 -1
  27. data/test/esp/resources/custom_signature/definition_test.rb +1 -1
  28. data/test/esp/resources/custom_signature_test.rb +1 -1
  29. data/test/esp/resources/external_account_test.rb +1 -1
  30. data/test/esp/resources/organization_test.rb +6 -6
  31. data/test/esp/resources/service_test.rb +1 -1
  32. data/test/esp/resources/sub_organization_test.rb +3 -3
  33. data/test/esp/resources/team_test.rb +2 -2
  34. data/test/factories/contact_requests.rb +1 -2
  35. data/test/factories/custom_signature/definitions.rb +1 -2
  36. data/test/factories/dashboards.rb +1 -2
  37. data/test/factories/external_accounts.rb +1 -2
  38. data/test/factories/organizations.rb +1 -2
  39. data/test/factories/reports.rb +1 -2
  40. data/test/factories/scan_intervals.rb +1 -2
  41. data/test/factories/stat_custom_signatures.rb +1 -2
  42. data/test/factories/stat_regions.rb +1 -2
  43. data/test/factories/stat_services.rb +1 -2
  44. data/test/factories/stat_signautures.rb +1 -2
  45. data/test/factories/stats.rb +1 -2
  46. data/test/factories/sub_organizations.rb +1 -2
  47. data/test/factories/suppression/regions.rb +2 -4
  48. data/test/factories/suppression/signatures.rb +2 -4
  49. data/test/factories/suppression/unique_identifiers.rb +2 -4
  50. data/test/factories/suppressions.rb +1 -2
  51. data/test/factories/users.rb +1 -2
  52. data/test/test_helper.rb +3 -10
  53. metadata +11 -28
  54. data/lib/tasks/testing.rake +0 -3
  55. data/test/parallel_reporter.rb +0 -93
data/Rakefile CHANGED
@@ -1,12 +1,13 @@
1
1
  require 'bundler/gem_tasks'
2
2
  require 'rake/testtask'
3
3
  load 'lib/tasks/rubocop.rake'
4
- load 'lib/tasks/testing.rake'
5
4
  require 'rdoc/task'
6
5
 
7
6
  Rake::TestTask.new do |task|
8
7
  task.libs << 'test'
9
8
  task.test_files = FileList['test/*_test.rb', 'test/**/*_test.rb'] - FileList["test/esp/integration/**/*_test.rb"]
9
+ task.verbose = false
10
+ task.warning = false
10
11
  end
11
12
 
12
13
  namespace "test" do
@@ -3,7 +3,7 @@ lib = File.expand_path('../lib', __FILE__)
3
3
  $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
4
  require 'esp/version'
5
5
 
6
- Gem::Specification.new do |spec|
6
+ Gem::Specification.new do |spec| # rubocop:disable Metrics/BlockLength
7
7
  spec.name = 'esp_sdk'
8
8
  spec.version = ESP::VERSION
9
9
  spec.authors = ['Evident.io']
@@ -26,19 +26,18 @@ Gem::Specification.new do |spec|
26
26
  spec.add_development_dependency 'guard-minitest'
27
27
  spec.add_development_dependency 'guard-rubocop'
28
28
  spec.add_development_dependency 'minitest'
29
- spec.add_development_dependency 'minitest-reporters'
30
29
  spec.add_development_dependency 'shoulda'
31
30
  spec.add_development_dependency 'mocha'
32
31
  spec.add_development_dependency 'bourne'
33
32
  spec.add_development_dependency 'webmock'
34
- spec.add_development_dependency 'coveralls'
35
33
  spec.add_development_dependency 'factory_girl'
36
34
  spec.add_development_dependency 'yard'
37
35
  spec.add_development_dependency 'awesome_print'
38
36
  spec.add_development_dependency 'aws-sdk'
39
37
  spec.add_development_dependency 'rdiscount'
38
+ spec.add_development_dependency 'bundler-audit'
40
39
 
41
40
  spec.add_dependency 'activeresource', '~> 4.0.0'
42
- spec.add_dependency 'api-auth', '~> 2.0.0'
41
+ spec.add_dependency 'api-auth', '~> 2.0'
43
42
  spec.add_dependency 'rack'
44
43
  end
@@ -35,8 +35,8 @@ module ESP
35
35
  ESP_OWNER_ID.fetch(ESP.env, "762160981991")
36
36
  end
37
37
 
38
- def trust_policy(external_account_id) # rubocop:disable Metrics/MethodLength
39
- <<TRUST_POLICY
38
+ def trust_policy(external_account_id)
39
+ <<-TRUST_POLICY.gsub(/^\s*/, '')
40
40
  {
41
41
  "Version": "2012-10-17",
42
42
  "Statement": [
@@ -1,6 +1,6 @@
1
1
  require 'optparse'
2
2
 
3
- ARGV.clone.options do |opts|
3
+ ARGV.clone.options do |opts| # rubocop:disable Metrics/BlockLength
4
4
  opts.banner = "Usage: esp add_external_account"
5
5
 
6
6
  opts.separator ""
@@ -8,7 +8,7 @@ module ESP
8
8
  class CommandsTasks
9
9
  attr_reader :argv
10
10
 
11
- HELP_MESSAGE = <<-EOT
11
+ HELP_MESSAGE = <<-EOT.freeze
12
12
  Usage: esp COMMAND [environment] [ARGS]
13
13
 
14
14
  The ESP commands are:
@@ -18,7 +18,7 @@ The ESP commands are:
18
18
  All commands can be run with -h (or --help) for more information.
19
19
  EOT
20
20
 
21
- COMMAND_WHITELIST = %w(console add_external_account version help)
21
+ COMMAND_WHITELIST = %w(console add_external_account version help).freeze
22
22
 
23
23
  def initialize(argv)
24
24
  @argv = argv
@@ -4,9 +4,9 @@ module ActiveResource
4
4
  # @private
5
5
  class ConnectionError
6
6
  def initialize(response)
7
- @response = if response.respond_to?(:response)
8
- message = decoded_errors(response.response.body)
9
- Struct.new(:body, :code, :message).new(response.response.body, response.code, message)
7
+ @response = if response.respond_to?(:body)
8
+ message = decoded_errors(response.body)
9
+ Struct.new(:body, :code, :message).new(response.body, response.code, message)
10
10
  else
11
11
  response
12
12
  end
@@ -15,7 +15,7 @@ module ActiveResource
15
15
  private
16
16
 
17
17
  def decoded_errors(json)
18
- Array((Hash(ActiveSupport::JSON.decode(json)))['errors'].map { |e| e['title'] }).join(" ")
18
+ Array(Hash(ActiveSupport::JSON.decode(json))['errors'].map { |e| e['title'] }).join(" ")
19
19
  rescue
20
20
  []
21
21
  end
@@ -43,9 +43,7 @@ module ActiveResource
43
43
  Formats.remove_root(parse_json_api(ActiveSupport::JSON.decode(json)))
44
44
  end
45
45
 
46
- private
47
-
48
- def self.parse_json_api(elements)
46
+ def parse_json_api(elements)
49
47
  included = elements.delete('included')
50
48
  elements.tap do |e|
51
49
  Array.wrap(e.fetch('data', {})).each do |object|
@@ -53,16 +51,18 @@ module ActiveResource
53
51
  end
54
52
  end
55
53
  end
54
+ private_class_method :parse_json_api
56
55
 
57
- def self.parse_object!(object, included = nil)
56
+ def parse_object!(object, included = nil)
58
57
  return object unless object.respond_to?(:each)
59
58
  merge_attributes!(object)
60
59
  parse_elements(object)
61
60
  parse_relationships!(object, included)
62
61
  object
63
62
  end
63
+ private_class_method :parse_object!
64
64
 
65
- def self.parse_elements(object)
65
+ def parse_elements(object)
66
66
  object.each_value do |value|
67
67
  if value.is_a? Hash
68
68
  parse_object!(value)
@@ -71,20 +71,23 @@ module ActiveResource
71
71
  end
72
72
  end
73
73
  end
74
+ private_class_method :parse_elements
74
75
 
75
- def self.parse_relationships!(object, included)
76
+ def parse_relationships!(object, included)
76
77
  object.fetch('relationships', {}).each do |assoc, details|
77
78
  extract_foreign_keys!(object, assoc, details)
78
79
  merge_included_objects!(object, assoc, details['data'], included)
79
80
  end
80
81
  end
82
+ private_class_method :parse_relationships!
81
83
 
82
- def self.merge_attributes!(object)
84
+ def merge_attributes!(object)
83
85
  return unless object.is_a? Hash
84
86
  object.merge! object.delete('attributes') unless object['attributes'].blank?
85
87
  end
88
+ private_class_method :merge_attributes!
86
89
 
87
- def self.extract_foreign_keys!(object, assoc, assoc_details)
90
+ def extract_foreign_keys!(object, assoc, assoc_details)
88
91
  data = assoc_details['data']
89
92
  related_link = assoc_details.fetch('links', {}).fetch('related', {})
90
93
  if data.present?
@@ -93,16 +96,18 @@ module ActiveResource
93
96
  parse_related_link(object, assoc, related_link)
94
97
  end
95
98
  end
99
+ private_class_method :extract_foreign_keys!
96
100
 
97
- def self.parse_data(object, assoc, data)
101
+ def parse_data(object, assoc, data)
98
102
  if data.is_a? Array
99
103
  object["#{assoc.singularize}_ids"] = data.map { |d| d['id'] }
100
104
  else
101
105
  object["#{assoc}_id"] = data['id']
102
106
  end
103
107
  end
108
+ private_class_method :parse_data
104
109
 
105
- def self.parse_related_link(object, assoc, related_link)
110
+ def parse_related_link(object, assoc, related_link)
106
111
  # parse the url to get the id if the data node is not returned
107
112
  related_link.scan(%r{/(\d+)\.json$}) do |id|
108
113
  object["#{assoc}_id"] = id.first
@@ -111,8 +116,9 @@ module ActiveResource
111
116
  uri = URI.parse(related_link)
112
117
  object["#{assoc.singularize}_ids"] = Rack::Utils.parse_nested_query(CGI.unescape(uri.query)).fetch('filter', {}).fetch('id_in', []) if uri.query.present?
113
118
  end
119
+ private_class_method :parse_related_link
114
120
 
115
- def self.merge_included_objects!(object, assoc, data, included)
121
+ def merge_included_objects!(object, assoc, data, included)
116
122
  return if included.blank?
117
123
  object[assoc] = case data
118
124
  when Array
@@ -121,14 +127,16 @@ module ActiveResource
121
127
  merge_nested_included_objects(object, [data], included).first
122
128
  end
123
129
  end
130
+ private_class_method :merge_included_objects!
124
131
 
125
- def self.merge_nested_included_objects(object, data, included)
132
+ def merge_nested_included_objects(object, data, included)
126
133
  assocs = included.compact.select { |i| data.include?(i.slice('type', 'id')) }
127
134
  # Remove the object from the included array to prevent an infinite loop if one of it's associations relates back to itself.
128
135
  assoc_included = included.dup
129
136
  assoc_included.delete(object)
130
137
  assocs.map { |i| parse_object!(i, assoc_included) }
131
138
  end
139
+ private_class_method :merge_nested_included_objects
132
140
  end
133
141
  end
134
142
  end
@@ -27,7 +27,7 @@ module ActiveResource
27
27
  private
28
28
 
29
29
  def decoded_errors(json)
30
- Array((Hash(ActiveSupport::JSON.decode(json)))['errors'])
30
+ Array(Hash(ActiveSupport::JSON.decode(json))['errors'])
31
31
  rescue
32
32
  []
33
33
  end
@@ -133,12 +133,13 @@ module ESP
133
133
  suppress(Suppression::UniqueIdentifier, reason)
134
134
  end
135
135
 
136
- private
137
-
138
136
  # Overridden because alerts does not use ransack for searching
139
137
  def self.filters(params)
140
138
  { filter: params }
141
139
  end
140
+ private_class_method :filters
141
+
142
+ private
142
143
 
143
144
  def suppress(klass, reason)
144
145
  fail ArgumentError, "You must specify the reason.".freeze unless reason.present?
@@ -11,7 +11,7 @@ module ESP
11
11
  patch(:activate).tap do |response|
12
12
  load_attributes_from_response(response)
13
13
  end
14
- rescue ActiveResource::BadRequest, ActiveResource::ResourceInvalid, ActiveResource::UnauthorizedAccess => error
14
+ rescue ActiveResource::BadRequest, ActiveResource::ResourceInvalid, ActiveResource::UnauthorizedAccess, ActiveResource::ForbiddenAccess => error
15
15
  load_remote_errors(error, true)
16
16
  self.code = error.response.code
17
17
  false
@@ -22,7 +22,7 @@ module ESP
22
22
  patch(:archive).tap do |response|
23
23
  load_attributes_from_response(response)
24
24
  end
25
- rescue ActiveResource::BadRequest, ActiveResource::ResourceInvalid, ActiveResource::UnauthorizedAccess => error
25
+ rescue ActiveResource::BadRequest, ActiveResource::ResourceInvalid, ActiveResource::UnauthorizedAccess, ActiveResource::ForbiddenAccess => error
26
26
  load_remote_errors(error, true)
27
27
  self.code = error.response.code
28
28
  false
@@ -16,11 +16,8 @@ module ESP
16
16
  # @return [void]
17
17
  def self.where(attrs)
18
18
  # when calling `recent.next_page` it will come into here
19
- if attrs[:from].to_s.include?('recent')
20
- super
21
- else
22
- fail ESP::NotImplementedError, 'Regular ARELlike methods are disabled. Use the .recent method.'
23
- end
19
+ return super if attrs[:from].to_s.include?('recent')
20
+ fail ESP::NotImplementedError, 'Regular ARELlike methods are disabled. Use the .recent method.'
24
21
  end
25
22
 
26
23
  # Not Implemented. You cannot create or update a Dashboard.
@@ -1,30 +1,30 @@
1
1
  module ESP
2
2
  # @private
3
3
  class Resource < ActiveResource::Base
4
- self.site = ESP.site
5
- self.proxy = ESP.http_proxy
4
+ self.site = ESP.site
5
+ self.proxy = ESP.http_proxy
6
6
  self.format = ActiveResource::Formats::JsonAPIFormat
7
7
  with_api_auth(ESP.access_key_id, ESP.secret_access_key)
8
8
  headers["Content-Type"] = format.mime_type
9
- headers["User-Agent"] = "Ruby SDK #{ESP::VERSION}"
9
+ headers["User-Agent"] = "Ruby SDK #{ESP::VERSION}"
10
10
 
11
11
  self.collection_parser = ActiveResource::PaginatedCollection
12
12
 
13
13
  # List of predicates that can be used for searching
14
- PREDICATES = %w(sorts m eq eq_any eq_all not_eq not_eq_any not_eq_all matches matches_any matches_all does_not_match does_not_match_any does_not_match_all lt lt_any lt_all lteq lteq_any lteq_all gt gt_any gt_all gteq gteq_any gteq_all in in_any in_all not_in not_in_any not_in_all cont cont_any cont_all not_cont not_cont_any not_cont_all start start_any start_all not_start not_start_any not_start_all end end_any end_all not_end not_end_any not_end_all true false present blank null not_null).join('|').freeze
14
+ PREDICATES = %w(sorts m eq eq_any eq_all not_eq not_eq_any not_eq_all matches matches_any matches_all does_not_match does_not_match_any does_not_match_all lt lt_any lt_all lteq lteq_any lteq_all gt gt_any gt_all gteq gteq_any gteq_all in in_any in_all not_in not_in_any not_in_all cont cont_any cont_all not_cont not_cont_any not_cont_all start start_any start_all not_start not_start_any not_start_all end end_any end_all not_end not_end_any not_end_all true false present blank null not_null).join('|').freeze
15
15
 
16
16
  # Pass a json api compliant hash to the api.
17
17
  def serializable_hash(*)
18
- h = attributes.extract!('included')
19
- h['data'] = { 'type' => self.class.to_s.underscore.sub('esp/', '').pluralize,
20
- 'attributes' => changed_attributes.except('id', 'type', 'created_at', 'updated_at', 'relationships') }
18
+ h = attributes.extract!('included')
19
+ h['data'] = { 'type' => self.class.to_s.underscore.sub('esp/', '').pluralize,
20
+ 'attributes' => changed_attributes.except('id', 'type', 'created_at', 'updated_at', 'relationships') }
21
21
  h['data']['id'] = id if id.present?
22
22
  h
23
23
  end
24
24
 
25
25
  def self.where(clauses = {})
26
26
  fail ArgumentError, "expected a clauses Hash, got #{clauses.inspect}" unless clauses.is_a? Hash
27
- from = clauses.delete(:from) || "#{prefix}#{name.demodulize.pluralize.underscore}"
27
+ from = clauses.delete(:from) || "#{prefix}#{name.demodulize.pluralize.underscore}"
28
28
  clauses = { params: clauses }.with_indifferent_access
29
29
  arrange_options(clauses)
30
30
  prefix_options, query_options = split_options(clauses)
@@ -34,7 +34,7 @@ module ESP
34
34
  end
35
35
 
36
36
  def self.find(*arguments)
37
- scope = arguments.slice!(0)
37
+ scope = arguments.slice!(0)
38
38
  options = (arguments.slice!(0) || {}).with_indifferent_access
39
39
  arrange_options(options)
40
40
  super(scope, options).tap do |object|
@@ -63,22 +63,21 @@ module ESP
63
63
  return object unless object.is_a? ActiveResource::PaginatedCollection
64
64
  # Need to set from so paginated collection can use it for page calls.
65
65
  object.tap do |collection|
66
- collection.from = options['from']
66
+ collection.from = options['from']
67
67
  collection.original_params = options.fetch('params', {})
68
68
  end
69
69
  end
70
70
 
71
71
  def self.arrange_options(options)
72
72
  if options[:params].present?
73
- page = options[:params][:page] ? { page: options[:params].delete(:page) } : {}
73
+ page = options[:params][:page] ? { page: options[:params].delete(:page) } : {}
74
74
  include = options[:params][:include] ? { include: options[:params].delete(:include) } : {}
75
75
  options[:params].merge!(options[:params].delete(:filter)) if options[:params][:filter]
76
76
  options[:params] = filters(options[:params]).merge!(page).merge!(include)
77
77
  end
78
- if options[:include].present?
79
- options[:params] ||= {}
80
- options[:params].merge!(options.extract!(:include))
81
- end
78
+ return unless options[:include].present?
79
+ options[:params] ||= {}
80
+ options[:params].merge!(options.extract!(:include))
82
81
  end
83
82
  end
84
83
  end
@@ -32,11 +32,8 @@ module ESP
32
32
  # @return [void]
33
33
  def self.where(attrs)
34
34
  # when calling `latest_for_teams.next_page` it will come into here
35
- if attrs[:from].to_s.include?('latest_for_teams')
36
- super
37
- else
38
- fail ESP::NotImplementedError
39
- end
35
+ return super if attrs[:from].to_s.include?('latest_for_teams')
36
+ fail ESP::NotImplementedError
40
37
  end
41
38
 
42
39
  # Not Implemented. You cannot search for a Stat.
@@ -98,7 +98,7 @@ module ESP
98
98
  patch(:deactivate).tap do |response|
99
99
  load_attributes_from_response(response)
100
100
  end
101
- rescue ActiveResource::BadRequest, ActiveResource::ResourceInvalid, ActiveResource::UnauthorizedAccess => error
101
+ rescue ActiveResource::BadRequest, ActiveResource::ResourceInvalid, ActiveResource::UnauthorizedAccess, ActiveResource::ForbiddenAccess => error
102
102
  load_remote_errors(error, true)
103
103
  self.code = error.response.code
104
104
  false
@@ -1,3 +1,3 @@
1
1
  module ESP
2
- VERSION = '2.7.0'.freeze
2
+ VERSION = '2.8.0'.freeze
3
3
  end
@@ -53,7 +53,11 @@ module ESP::Integration
53
53
  should 'activate definition' do
54
54
  custom_signature = ESP::CustomSignature.last
55
55
  fail 'Missing custom signature' if custom_signature.blank?
56
- definition = ESP::CustomSignature::Definition.create(custom_signature_id: custom_signature.id)
56
+ definition = custom_signature.definitions.last
57
+
58
+ if definition.blank? || definition.status != 'editable'
59
+ definition = ESP::CustomSignature::Definition.create(custom_signature_id: custom_signature.id)
60
+ end
57
61
 
58
62
  assert_equal 'editable', definition.status
59
63
 
@@ -67,6 +71,16 @@ module ESP::Integration
67
71
  should 'be able to create, update and destroy' do
68
72
  custom_signature = ESP::CustomSignature.last
69
73
  fail 'Missing custom signature' if custom_signature.blank?
74
+ old_definition = custom_signature.definitions.last
75
+
76
+ if old_definition.present? && old_definition.status == 'editable'
77
+ old_definition.destroy
78
+
79
+ assert_raises ActiveResource::ResourceNotFound do
80
+ ESP::CustomSignature::Definition.find(old_definition.id)
81
+ end
82
+ end
83
+
70
84
  definition = ESP::CustomSignature::Definition.new(custom_signature_id: custom_signature.id)
71
85
 
72
86
  assert_predicate definition, :new?
@@ -36,7 +36,9 @@ module ESP::Integration
36
36
 
37
37
  context '#CRUD' do
38
38
  should 'be able to create, update and destroy' do
39
- custom_signature = ESP::CustomSignature.new(@custom_signature.attributes)
39
+ team = ESP::Team.last
40
+ assert_predicate team, :present?
41
+ custom_signature = ESP::CustomSignature.new(@custom_signature.attributes.merge(team_ids: [team.id]))
40
42
 
41
43
  assert_predicate custom_signature, :new?
42
44
 
@@ -6,7 +6,7 @@ module ESP::Integration
6
6
  context 'live calls' do
7
7
  context '#for_result' do
8
8
  should 'return alerts' do
9
- result = ESP::CustomSignature::Result.first
9
+ result = ESP::CustomSignature::Result.first(params: { sorts: 'id' })
10
10
  fail 'Missing result' if result.blank?
11
11
 
12
12
  alerts = ESP::CustomSignature::Result::Alert.for_result(result.id)
@@ -17,7 +17,7 @@ module ESP::Integration
17
17
 
18
18
  context '#custom_signature' do
19
19
  should 'return a custom_signature' do
20
- result = ESP::CustomSignature::Result.first
20
+ result = ESP::CustomSignature::Result.first(params: { sorts: 'id' })
21
21
  fail 'Missing result' if result.blank?
22
22
  alert = ESP::CustomSignature::Result::Alert.for_result(result.id).first
23
23
 
@@ -30,7 +30,7 @@ module ESP::Integration
30
30
 
31
31
  context '#external_account' do
32
32
  should 'return a external_account' do
33
- result = ESP::CustomSignature::Result.first
33
+ result = ESP::CustomSignature::Result.first(params: { sorts: 'id' })
34
34
  fail 'Missing result' if result.blank?
35
35
  alert = ESP::CustomSignature::Result::Alert.for_result(result.id).first
36
36
 
@@ -43,7 +43,7 @@ module ESP::Integration
43
43
 
44
44
  context '#region' do
45
45
  should 'return a region' do
46
- result = ESP::CustomSignature::Result.first
46
+ result = ESP::CustomSignature::Result.first(params: { sorts: 'id' })
47
47
  fail 'Missing result' if result.blank?
48
48
  alert = ESP::CustomSignature::Result::Alert.for_result(result.id).first
49
49