diff --git a/.gitlab/ci/integration/es.yml b/.gitlab/ci/integration/es.yml
index 79464bddf..15039a6c7 100644
--- a/.gitlab/ci/integration/es.yml
+++ b/.gitlab/ci/integration/es.yml
@@ -11,7 +11,6 @@
- bundle exec rails test test/integration/elasticsearch_active_test.rb
- bundle exec rails test test/integration/elasticsearch_test.rb
- bundle exec rspec --tag searchindex --tag ~type:system --profile 10
- - bundle exec rails test test/integration/report_test.rb
es:7:
<<: *template_integration_es
diff --git a/app/assets/javascripts/app/controllers/_application_controller/technical_error_modal.coffee b/app/assets/javascripts/app/controllers/_application_controller/technical_error_modal.coffee
new file mode 100644
index 000000000..6df18b7cd
--- /dev/null
+++ b/app/assets/javascripts/app/controllers/_application_controller/technical_error_modal.coffee
@@ -0,0 +1,9 @@
+class App.ControllerTechnicalErrorModal extends App.ControllerModal
+ head: "StatusCode: #{status}"
+ contentCode: ''
+ buttonClose: false
+ buttonSubmit: 'Ok'
+ onSubmit: (e) -> @close(e)
+
+ content: ->
+ "
#{@contentCode}
"
diff --git a/app/assets/javascripts/app/controllers/report.coffee b/app/assets/javascripts/app/controllers/report.coffee
index 3be03d142..de1fe139e 100644
--- a/app/assets/javascripts/app/controllers/report.coffee
+++ b/app/assets/javascripts/app/controllers/report.coffee
@@ -171,6 +171,13 @@ class Graph extends App.Controller
backends: @params.backendSelected
)
processData: true
+ error: (xhr) =>
+ return if !_.include([401, 403, 404, 422, 502], xhr.status)
+
+ @bodyModal = new App.ControllerTechnicalErrorModal(
+ head: __('Cannot generate report')
+ contentCode: xhr.responseJSON.error
+ )
success: (data) =>
@update(data)
@delay(@render, interval, 'report-update', 'page')
diff --git a/app/assets/javascripts/app/lib/app_post/ajax.coffee b/app/assets/javascripts/app/lib/app_post/ajax.coffee
index 8f00f13ea..d79e0d39d 100644
--- a/app/assets/javascripts/app/lib/app_post/ajax.coffee
+++ b/app/assets/javascripts/app/lib/app_post/ajax.coffee
@@ -102,12 +102,18 @@ class _ajaxSingleton
# do not show any error message with code 502
return if status is 502
+ try
+ json = JSON.parse(detail)
+ text = json.error_human || json.error
+
+ text = detail if !text
+
+ escaped = App.Utils.htmlEscape(text)
+
# show error message
- new App.ControllerModal(
- head: "StatusCode: #{status}"
- contentInline: "#{App.Utils.htmlEscape(detail)}
"
- buttonClose: true
- buttonSubmit: false
+ new App.ControllerTechnicalErrorModal(
+ contentCode: escaped
+ head: "StatusCode: #{status}"
)
)
diff --git a/app/assets/stylesheets/zammad.scss b/app/assets/stylesheets/zammad.scss
index ca83b5cff..abd6da804 100644
--- a/app/assets/stylesheets/zammad.scss
+++ b/app/assets/stylesheets/zammad.scss
@@ -381,6 +381,26 @@ ul {
z-index: 1;
}
+code {
+ background: hsla(0, 0%, 0%, 0.2);
+ border-radius: 3px;
+ box-decoration-break: clone;
+}
+
+code,
+.hljs {
+ padding: 2px 4px;
+ font-size: 0.88em;
+}
+
+.hljs {
+ background: none;
+}
+
+pre code.hljs {
+ font-size: 1em;
+}
+
pre {
display: block;
padding: 9.5px;
@@ -395,30 +415,25 @@ pre {
border-radius: 3px;
}
+.modal-content pre {
+ background: hsl(0, 0%, 97%);
+ border: 1px solid hsl(0, 0%, 87%);
+}
+
pre code {
padding: 0;
font-size: inherit;
color: inherit;
white-space: pre-wrap;
- background-color: transparent;
- border-radius: 0;
-}
-
-.hljs,
-code {
background: none;
- padding: 2px 4px;
- font-size: 0.88em;
-}
+ border-radius: 0;
+ border: none;
+ overflow-x: auto;
-code:not(.hljs) {
- border: 1px solid rgba(0, 0, 0, 0.2);
- border-radius: 3px;
- white-space: nowrap;
-}
-
-pre code.hljs {
- font-size: 1em;
+ &.hljs {
+ padding: 0;
+ background: none;
+ }
}
.textarea::placeholder,
diff --git a/app/controllers/reports_controller.rb b/app/controllers/reports_controller.rb
index 20a716278..4f7d44468 100644
--- a/app/controllers/reports_controller.rb
+++ b/app/controllers/reports_controller.rb
@@ -22,26 +22,34 @@ class ReportsController < ApplicationController
get_params = params_all
return if !get_params
- result = {}
- get_params[:metric][:backend].each do |backend|
- condition = get_params[:profile].condition
- if backend[:condition]
- backend[:condition].merge(condition)
- else
- backend[:condition] = condition
- end
- next if !backend[:adapter]
+ begin
+ result = {}
+ get_params[:metric][:backend].each do |backend|
+ condition = get_params[:profile].condition
+ if backend[:condition]
+ backend[:condition].merge(condition)
+ else
+ backend[:condition] = condition
+ end
+ next if !backend[:adapter]
- result[backend[:name]] = backend[:adapter].aggs(
- range_start: get_params[:start],
- range_end: get_params[:stop],
- interval: get_params[:range],
- selector: backend[:condition],
- params: backend[:params],
- timezone: get_params[:timezone],
- timezone_offset: get_params[:timezone_offset],
- current_user: current_user
- )
+ result[backend[:name]] = backend[:adapter].aggs(
+ range_start: get_params[:start],
+ range_end: get_params[:stop],
+ interval: get_params[:range],
+ selector: backend[:condition],
+ params: backend[:params],
+ timezone: get_params[:timezone],
+ timezone_offset: get_params[:timezone_offset],
+ current_user: current_user
+ )
+ end
+ rescue => e
+ if e.message.include? 'Conflicting date range'
+ raise Exceptions::UnprocessableEntity, __('Conflicting date ranges. Please check your selected report profile.')
+ end
+
+ raise e
end
render json: {
diff --git a/i18n/zammad.pot b/i18n/zammad.pot
index 6418b535a..5fdfe48c1 100644
--- a/i18n/zammad.pot
+++ b/i18n/zammad.pot
@@ -1403,6 +1403,10 @@ msgstr ""
msgid "Cannot follow-up on a closed ticket. Please create a new ticket."
msgstr ""
+#: app/assets/javascripts/app/controllers/report.coffee
+msgid "Cannot generate report"
+msgstr ""
+
#: app/assets/javascripts/app/lib/app_post/html5_upload.coffee
msgid "Cannot upload file"
msgstr ""
@@ -1867,6 +1871,14 @@ msgstr ""
msgid "Confirmation failed."
msgstr ""
+#: lib/search_index_backend.rb
+msgid "Conflicting date ranges"
+msgstr ""
+
+#: app/controllers/reports_controller.rb
+msgid "Conflicting date ranges. Please check your selected report profile."
+msgstr ""
+
#: app/assets/javascripts/app/views/channel/email_account_wizard.jst.eco
#: app/assets/javascripts/app/views/getting_started/email.jst.eco
#: app/assets/javascripts/app/views/integration/exchange_wizard.jst.eco
diff --git a/lib/search_index_backend.rb b/lib/search_index_backend.rb
index 9e312cca8..3348ea662 100644
--- a/lib/search_index_backend.rb
+++ b/lib/search_index_backend.rb
@@ -438,6 +438,8 @@ example for aggregations within one year
data = selector2query(selectors, options, aggs_interval)
+ verify_date_range(url, data)
+
response = make_request(url, data: data)
if !response.success?
@@ -1208,4 +1210,87 @@ helper method for making HTTP calls and raising error if response was not succes
)
end
+ # verifies date range ElasticSearch payload
+ #
+ # @param url [String] of ElasticSearch
+ # @param payload [Hash] Elasticsearch query payload
+ #
+ # @return [Boolean] or raises error
+ def self.verify_date_range(url, payload)
+ ranges_payload = payload.dig(:query, :bool, :must)
+
+ return true if ranges_payload.nil?
+
+ ranges = ranges_payload
+ .select { |elem| elem.key? :range }
+ .map { |elem| [elem[:range].keys.first, convert_es_date_range(elem)] }
+ .each_with_object({}) { |elem, sum| (sum[elem.first] ||= []) << elem.last }
+
+ return true if ranges.all? { |_, ranges_by_key| verify_single_key_range(ranges_by_key) }
+
+ error_prefix = "Unable to process request to elasticsearch URL '#{url}'."
+ error_suffix = "Payload:\n#{payload.to_json}"
+ error_message = __('Conflicting date ranges')
+
+ result = "#{error_prefix} #{error_message} #{error_suffix}"
+ Rails.logger.error result.first(40_000)
+
+ raise result
+ end
+
+ # checks if all ranges are overlaping
+ #
+ # @param ranges [Array>] to use in search
+ #
+ # @return [Boolean]
+ def self.verify_single_key_range(ranges)
+ ranges
+ .each_with_index
+ .all? do |range, i|
+ ranges
+ .slice((i + 1)..)
+ .all? { |elem| elem.overlaps? range }
+ end
+ end
+
+ # Converts paylaod component to dates range
+ #
+ # @param elem [Hash] payload component
+ #
+ # @return [Range]
+ def self.convert_es_date_range(elem)
+ range = elem[:range].first.last
+ from = parse_es_range_date range[:from] || range[:gt] || '-9999-01-01'
+ to = parse_es_range_date range[:to] || range[:lt] || '9999-01-01'
+
+ from..to
+ end
+
+ # Parses absolute date or converts relative date
+ #
+ # @param input [String] string representation of date
+ #
+ # @return [Range]
+ def self.parse_es_range_date(input)
+ match = input.match(%r{^now(-|\+)(\d+)(\w{1})$})
+
+ return DateTime.parse input if !match
+
+ map = {
+ d: 'day',
+ y: 'year',
+ M: 'month',
+ h: 'hour',
+ m: 'minute',
+ }
+
+ range = match.captures[1].to_i.send map[match.captures[2].to_sym]
+
+ case match.captures[0]
+ when '-'
+ range.ago
+ when '+'
+ range.from_now
+ end
+ end
end
diff --git a/spec/factories/report/profile.rb b/spec/factories/report/profile.rb
index a416752b6..b9f46e18d 100644
--- a/spec/factories/report/profile.rb
+++ b/spec/factories/report/profile.rb
@@ -6,5 +6,20 @@ FactoryBot.define do
active { true }
created_by_id { 1 }
updated_by_id { 1 }
+
+ trait :condition_created_at do
+ transient do
+ ticket_created_at { nil }
+ end
+
+ condition do
+ {
+ 'ticket.created_at' => {
+ operator: 'before (absolute)',
+ value: ticket_created_at.iso8601
+ }
+ }
+ end
+ end
end
end
diff --git a/spec/lib/report/ticket_first_solution_spec.rb b/spec/lib/report/ticket_first_solution_spec.rb
new file mode 100644
index 000000000..bd742f8da
--- /dev/null
+++ b/spec/lib/report/ticket_first_solution_spec.rb
@@ -0,0 +1,192 @@
+# Copyright (C) 2012-2021 Zammad Foundation, http://zammad-foundation.org/
+
+# rubocop:disable RSpec/ExampleLength
+
+require 'rails_helper'
+require 'lib/report_examples'
+
+RSpec.describe Report::TicketFirstSolution, searchindex: true do
+ include_examples 'with report examples'
+
+ describe '.aggs' do
+ it 'gets monthly aggregated results' do
+ result = described_class.aggs(
+ range_start: Time.zone.parse('2015-01-01T00:00:00Z'),
+ range_end: Time.zone.parse('2015-12-31T23:59:59Z'),
+ interval: 'month',
+ selector: {},
+ )
+
+ expect(result).to eq [0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 1, 0]
+ end
+
+ it 'gets monthly aggregated results with high priority' do
+ result = described_class.aggs(
+ range_start: Time.zone.parse('2015-01-01T00:00:00Z'),
+ range_end: Time.zone.parse('2015-12-31T23:59:59Z'),
+ interval: 'month',
+ selector: {
+ 'ticket.priority_id' => {
+ 'operator' => 'is',
+ 'value' => [Ticket::Priority.lookup(name: '3 high').id],
+ }
+ },
+ )
+
+ expect(result).to eq [0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0]
+ end
+
+ it 'gets monthly aggregated results not in merged state' do
+ result = described_class.aggs(
+ range_start: Time.zone.parse('2015-01-01T00:00:00Z'),
+ range_end: Time.zone.parse('2015-12-31T23:59:59Z'),
+ interval: 'month',
+ selector: {
+ 'ticket_state.name' => {
+ 'operator' => 'is not',
+ 'value' => 'merged',
+ }
+ },
+ )
+
+ expect(result).to eq [0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 1, 0]
+ end
+
+ it 'gets monthly aggregated results with not high priority' do
+ result = described_class.aggs(
+ range_start: Time.zone.parse('2015-01-01T00:00:00Z'),
+ range_end: Time.zone.parse('2015-12-31T23:59:59Z'),
+ interval: 'month',
+ selector: {
+ 'ticket.priority_id' => {
+ 'operator' => 'is not',
+ 'value' => [Ticket::Priority.lookup(name: '3 high').id],
+ }
+ },
+ )
+
+ expect(result).to eq [0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0]
+ end
+
+ it 'gets weekly aggregated results' do
+ result = described_class.aggs(
+ range_start: Time.zone.parse('2015-10-26T00:00:00Z'),
+ range_end: Time.zone.parse('2015-10-31T23:59:59Z'),
+ interval: 'week',
+ selector: {},
+ )
+
+ expect(result).to eq [0, 0, 1, 0, 0, 1, 1]
+ end
+
+ it 'gets daily aggregated results' do
+ result = described_class.aggs(
+ range_start: Time.zone.parse('2015-10-01T00:00:00Z'),
+ range_end: Time.zone.parse('2015-11-01T23:59:59Z'),
+ interval: 'day',
+ selector: {},
+ )
+
+ expect(result).to eq [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1]
+ end
+
+ it 'gets hourly aggregated results' do
+ result = described_class.aggs(
+ range_start: Time.zone.parse('2015-10-28T00:00:00Z'),
+ range_end: Time.zone.parse('2015-10-28T23:59:59Z'),
+ interval: 'hour',
+ selector: {},
+ )
+
+ expect(result).to eq [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
+ end
+ end
+
+ describe '.items' do
+ it 'gets items in year range' do
+ result = described_class.items(
+ range_start: Time.zone.parse('2015-01-01T00:00:00Z'),
+ range_end: Time.zone.parse('2015-12-31T23:59:59Z'),
+ selector: {},
+ )
+ expect(result).to match_tickets ticket_5, ticket_6, ticket_7
+ end
+
+ it 'gets items in year range with high priority' do
+ result = described_class.items(
+ range_start: Time.zone.parse('2015-01-01T00:00:00Z'),
+ range_end: Time.zone.parse('2015-12-31T23:59:59Z'),
+ selector: {
+ 'ticket.priority_id' => {
+ 'operator' => 'is',
+ 'value' => [Ticket::Priority.lookup(name: '3 high').id],
+ }
+ }
+ )
+
+ expect(result).to match_tickets ticket_5
+ end
+
+ it 'gets items in year range not in merged state' do
+ result = described_class.items(
+ range_start: Time.zone.parse('2015-01-01T00:00:00Z'),
+ range_end: Time.zone.parse('2015-12-31T23:59:59Z'),
+ selector: {
+ 'ticket_state.name' => {
+ 'operator' => 'is not',
+ 'value' => 'merged',
+ }
+ }
+ )
+
+ expect(result).to match_tickets ticket_5, ticket_6, ticket_7
+ end
+
+ it 'gets items in year range with not high priority' do
+ result = described_class.items(
+ range_start: Time.zone.parse('2015-01-01T00:00:00Z'),
+ range_end: Time.zone.parse('2015-12-31T23:59:59Z'),
+ selector: {
+ 'ticket.priority_id' => {
+ 'operator' => 'is not',
+ 'value' => [Ticket::Priority.lookup(name: '3 high').id],
+ }
+ }
+ )
+
+ expect(result).to match_tickets ticket_6, ticket_7
+ end
+
+ it 'gets items in week range' do
+ result = described_class.items(
+ range_start: Time.zone.parse('2015-10-26T00:00:00Z'),
+ range_end: Time.zone.parse('2015-11-01T23:59:59Z'),
+ selector: {}
+ )
+
+ expect(result).to match_tickets ticket_5, ticket_6, ticket_7
+ end
+
+ it 'gets items in day range' do
+ result = described_class.items(
+ range_start: Time.zone.parse('2015-10-01T00:00:00Z'),
+ range_end: Time.zone.parse('2015-10-31T23:59:59Z'),
+ selector: {}
+ )
+
+ expect(result).to match_tickets ticket_5, ticket_6
+ end
+
+ it 'gets items in hour range' do
+ result = described_class.items(
+ range_start: Time.zone.parse('2015-10-28T00:00:00Z'),
+ range_end: Time.zone.parse('2015-10-28T23:59:59Z'),
+ interval: 'hour',
+ selector: {},
+ )
+
+ expect(result).to match_tickets ticket_5
+ end
+ end
+end
+# rubocop:enable RSpec/ExampleLength
diff --git a/spec/lib/report/ticket_generic_time_spec.rb b/spec/lib/report/ticket_generic_time_spec.rb
index 20f2fc512..cbf8fa24f 100644
--- a/spec/lib/report/ticket_generic_time_spec.rb
+++ b/spec/lib/report/ticket_generic_time_spec.rb
@@ -1,33 +1,333 @@
# Copyright (C) 2012-2021 Zammad Foundation, http://zammad-foundation.org/
require 'rails_helper'
+require 'lib/report_examples'
-RSpec.describe Report::TicketGenericTime do
+RSpec.describe Report::TicketGenericTime, searchindex: true do
+ include_examples 'with report examples'
-=begin
+ describe '.aggs' do
+ it 'gets monthly aggregated results by created_at' do
+ result = described_class.aggs(
+ range_start: Time.zone.parse('2015-01-01T00:00:00Z'),
+ range_end: Time.zone.parse('2015-12-31T23:59:59Z'),
+ interval: 'month', # year, quarter, month, week, day, hour, minute, second
+ selector: {}, # ticket selector to get only a collection of tickets
+ params: { field: 'created_at' },
+ )
- result = Report::TicketGenericTime.items(
- range_start: '2015-01-01T00:00:00Z',
- range_end: '2015-12-31T23:59:59Z',
- selector: selector, # ticket selector to get only a collection of tickets
- params: { field: 'created_at' },
- )
+ expect(result).to eq [0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 1, 0]
+ end
-returns
+ it 'gets monthly aggregated results by created_at not merged' do
+ result = described_class.aggs(
+ range_start: Time.zone.parse('2015-01-01T00:00:00Z'),
+ range_end: Time.zone.parse('2015-12-31T23:59:59Z'),
+ interval: 'month', # year, quarter, month, week, day, hour, minute, second
+ selector: {
+ 'state' => {
+ 'operator' => 'is not',
+ 'value' => 'merged'
+ }
+ },
+ params: { field: 'created_at' },
+ )
- {
- count: 123,
- ticket_ids: [4,5,1,5,0,51,5,56,7,4],
- assets: assets,
- }
+ expect(result).to eq [0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 1, 0]
+ end
+ end
-=end
+ describe '.items' do
+ it 'gets items in year range by created_at' do
+ result = described_class.items(
+ range_start: Time.zone.parse('2015-01-01T00:00:00Z'),
+ range_end: Time.zone.parse('2015-12-31T23:59:59Z'),
+ selector: {}, # ticket selector to get only a collection of tickets
+ params: { field: 'created_at' },
+ )
- describe 'items' do
+ expect(result).to match_tickets ticket_7, ticket_6, ticket_5, ticket_4, ticket_3, ticket_2, ticket_1
+ end
+
+ it 'gets items in year range by created_at not merged' do
+ result = described_class.items(
+ range_start: Time.zone.parse('2015-01-01T00:00:00Z'),
+ range_end: Time.zone.parse('2015-12-31T23:59:59Z'),
+ selector: {
+ 'state' => {
+ 'operator' => 'is not',
+ 'value' => 'merged'
+ }
+ },
+ params: { field: 'created_at' },
+ )
+
+ expect(result).to match_tickets ticket_7, ticket_6, ticket_5, ticket_4, ticket_3, ticket_2, ticket_1
+ end
+
+ it 'gets items in year range by created_at before oct 31st' do
+ result = described_class.items(
+ range_start: Time.zone.parse('2015-01-01T00:00:00Z'),
+ range_end: Time.zone.parse('2015-12-31T23:59:59Z'),
+ selector: {
+ 'created_at' => {
+ 'operator' => 'before (absolute)',
+ 'value' => '2015-10-31T00:00:00Z'
+ }
+ },
+ params: { field: 'created_at' },
+ )
+
+ expect(result).to match_tickets ticket_5, ticket_4, ticket_3, ticket_2, ticket_1
+ end
+
+ it 'gets items in year range by created_at after oct 31st' do
+ result = described_class.items(
+ range_start: Time.zone.parse('2015-01-01T00:00:00Z'),
+ range_end: Time.zone.parse('2015-12-31T23:59:59Z'),
+ selector: {
+ 'created_at' => {
+ 'operator' => 'after (absolute)',
+ 'value' => '2015-10-31T00:00:00Z'
+ }
+ },
+ params: { field: 'created_at' },
+ )
+
+ expect(result).to match_tickets ticket_7, ticket_6
+ end
+
+ it 'gets items in 1 day from now' do
+ result = described_class.items(
+ range_start: 1.year.ago.beginning_of_year,
+ range_end: 1.year.from_now.at_end_of_year,
+ selector: {
+ 'created_at' => {
+ 'operator' => 'after (relative)',
+ 'range' => 'day',
+ 'value' => '1'
+ }
+ }, # ticket selector to get only a collection of tickets
+ params: { field: 'created_at' },
+ )
+
+ expect(result).to match_tickets ticket_after_72h
+ end
+
+ it 'gets items in 1 month from now' do
+ result = described_class.items(
+ range_start: 1.year.ago.beginning_of_year,
+ range_end: 1.year.from_now.at_end_of_year,
+ selector: {
+ 'created_at' => {
+ 'operator' => 'after (relative)',
+ 'range' => 'month',
+ 'value' => '1'
+ }
+ }, # ticket selector to get only a collection of tickets
+ params: { field: 'created_at' },
+ )
+
+ expect(result).to match_tickets []
+ end
+
+ it 'gets items in 1 month ago' do
+ result = described_class.items(
+ range_start: 1.year.ago.beginning_of_year,
+ range_end: 1.year.from_now.at_end_of_year,
+ selector: {
+ 'created_at' => {
+ 'operator' => 'before (relative)',
+ 'range' => 'month',
+ 'value' => '1'
+ }
+ }, # ticket selector to get only a collection of tickets
+ params: { field: 'created_at' },
+ )
+
+ expect(result).to match_tickets ticket_before_40d
+ end
+
+ it 'gets items in 5 months ago' do
+ result = described_class.items(
+ range_start: 1.year.ago.beginning_of_year,
+ range_end: 1.year.from_now.at_end_of_year,
+ selector: {
+ 'created_at' => {
+ 'operator' => 'before (relative)',
+ 'range' => 'month',
+ 'value' => '5'
+ }
+ }, # ticket selector to get only a collection of tickets
+ params: { field: 'created_at' },
+ )
+
+ expect(result).to match_tickets []
+ end
+
+ it 'gets items with aaa+bbb' do
+ result = described_class.items(
+ range_start: Time.zone.parse('2015-01-01T00:00:00Z'),
+ range_end: Time.zone.parse('2015-12-31T23:59:59Z'),
+ selector: {
+ 'tags' => {
+ 'operator' => 'contains all',
+ 'value' => 'aaa, bbb'
+ }
+ },
+ params: { field: 'created_at' },
+ )
+
+ expect(result).to match_tickets ticket_1
+ end
+
+ it 'gets items with not aaa+bbb' do
+ result = described_class.items(
+ range_start: Time.zone.parse('2015-01-01T00:00:00Z'),
+ range_end: Time.zone.parse('2015-12-31T23:59:59Z'),
+ selector: {
+ 'tags' => {
+ 'operator' => 'contains all not',
+ 'value' => 'aaa, bbb'
+ }
+ },
+ params: { field: 'created_at' },
+ )
+
+ expect(result).to match_tickets ticket_7, ticket_6, ticket_5, ticket_4, ticket_3, ticket_2
+ end
+
+ it 'gets items with aaa' do
+ result = described_class.items(
+ range_start: Time.zone.parse('2015-01-01T00:00:00Z'),
+ range_end: Time.zone.parse('2015-12-31T23:59:59Z'),
+ selector: {
+ 'tags' => {
+ 'operator' => 'contains all',
+ 'value' => 'aaa'
+ }
+ },
+ params: { field: 'created_at' },
+ )
+
+ expect(result).to match_tickets ticket_2, ticket_1
+ end
+
+ it 'gets items with not aaa' do
+ result = described_class.items(
+ range_start: Time.zone.parse('2015-01-01T00:00:00Z'),
+ range_end: Time.zone.parse('2015-12-31T23:59:59Z'),
+ selector: {
+ 'tags' => {
+ 'operator' => 'contains all not',
+ 'value' => 'aaa'
+ }
+ },
+ params: { field: 'created_at' },
+ )
+
+ expect(result).to match_tickets ticket_7, ticket_6, ticket_5, ticket_4, ticket_3
+ end
+
+ it 'gets items with one not aaa' do
+ result = described_class.items(
+ range_start: Time.zone.parse('2015-01-01T00:00:00Z'),
+ range_end: Time.zone.parse('2015-12-31T23:59:59Z'),
+ selector: {
+ 'tags' => {
+ 'operator' => 'contains one not',
+ 'value' => 'aaa'
+ }
+ },
+ params: { field: 'created_at' },
+ )
+
+ expect(result).to match_tickets ticket_7, ticket_6, ticket_5, ticket_4, ticket_3
+ end
+
+ it 'gets items with one not aaa+bbb' do
+ result = described_class.items(
+ range_start: Time.zone.parse('2015-01-01T00:00:00Z'),
+ range_end: Time.zone.parse('2015-12-31T23:59:59Z'),
+ selector: {
+ 'tags' => {
+ 'operator' => 'contains one not',
+ 'value' => 'aaa, bbb'
+ }
+ },
+ params: { field: 'created_at' },
+ )
+
+ expect(result).to match_tickets ticket_7, ticket_6, ticket_4, ticket_3
+ end
+
+ it 'gets items with one aaa' do
+ result = described_class.items(
+ range_start: Time.zone.parse('2015-01-01T00:00:00Z'),
+ range_end: Time.zone.parse('2015-12-31T23:59:59Z'),
+ selector: {
+ 'tags' => {
+ 'operator' => 'contains one',
+ 'value' => 'aaa'
+ }
+ },
+ params: { field: 'created_at' },
+ )
+
+ expect(result).to match_tickets ticket_2, ticket_1
+ end
+
+ it 'gets items with one aaa+bbb' do
+ result = described_class.items(
+ range_start: Time.zone.parse('2015-01-01T00:00:00Z'),
+ range_end: Time.zone.parse('2015-12-31T23:59:59Z'),
+ selector: {
+ 'tags' => {
+ 'operator' => 'contains one',
+ 'value' => 'aaa, bbb'
+ }
+ },
+ params: { field: 'created_at' },
+ )
+
+ expect(result).to match_tickets ticket_5, ticket_2, ticket_1
+ end
+
+ it 'gets items with test' do
+ result = described_class.items(
+ range_start: Time.zone.parse('2015-01-01T00:00:00Z'),
+ range_end: Time.zone.parse('2015-12-31T23:59:59Z'),
+ selector: {
+ 'title' => {
+ 'operator' => 'contains',
+ 'value' => 'Test'
+ }
+ },
+ params: { field: 'created_at' },
+ )
+
+ expect(result).to match_tickets ticket_7, ticket_6, ticket_5, ticket_4, ticket_3, ticket_2, ticket_1
+ end
+
+ it 'gets items with not test' do
+ result = described_class.items(
+ range_start: Time.zone.parse('2015-01-01T00:00:00Z'),
+ range_end: Time.zone.parse('2015-12-31T23:59:59Z'),
+ selector: {
+ 'title' => {
+ 'operator' => 'contains not',
+ 'value' => 'Test'
+ }
+ },
+ params: { field: 'created_at' },
+ )
+
+ expect(result).to match_tickets []
+ end
# Regression test for issue #2246 - Records in Reporting not updated when single ActiveRecord can not be found
- it 'correctly handles missing tickets' do
- class_double('SearchIndexBackend', selectors: { ticket_ids: [-1] }).as_stubbed_const
+ it 'correctly handles missing tickets', searchindex: false do
+ class_double('SearchIndexBackend', selectors: { ticket_ids: [-1] }, drop_index: nil, drop_pipeline: nil).as_stubbed_const
expect do
described_class.items(
@@ -39,4 +339,78 @@ returns
end.not_to raise_error
end
end
+
+ context 'when additional attribute exists', db_strategy: :reset do
+ before do
+ ObjectManager::Attribute.add(
+ object: 'Ticket',
+ name: 'test_category',
+ display: 'Test 1',
+ data_type: 'tree_select',
+ data_option: {
+ maxlength: 200,
+ null: false,
+ default: '',
+ options: [
+ { 'name' => 'aa', 'value' => 'aa', 'children' => [{ 'name' => 'aa', 'value' => 'aa::aa' }, { 'name' => 'bb', 'value' => 'aa::bb' }, { 'name' => 'cc', 'value' => 'aa::cc' }] },
+ { 'name' => 'bb', 'value' => 'bb', 'children' => [{ 'name' => 'aa', 'value' => 'bb::aa' }, { 'name' => 'bb', 'value' => 'bb::bb' }, { 'name' => 'cc', 'value' => 'bb::cc' }] },
+ { 'name' => 'cc', 'value' => 'cc', 'children' => [{ 'name' => 'aa', 'value' => 'cc::aa' }, { 'name' => 'bb', 'value' => 'cc::bb' }, { 'name' => 'cc', 'value' => 'cc::cc' }] },
+ ]
+ },
+ active: true,
+ screens: {},
+ position: 20,
+ created_by_id: 1,
+ updated_by_id: 1,
+ editable: false,
+ to_migrate: false,
+ )
+ ObjectManager::Attribute.migration_execute
+
+ ticket_with_category
+
+ rebuild_searchindex
+ end
+
+ let(:ticket_with_category) do
+ travel_to DateTime.new 2015, 10, 28, 9, 30
+ ticket = create(:ticket,
+ group: group_2,
+ customer: customer,
+ test_category: 'cc::bb',
+ state_name: 'new',
+ priority_name: '2 normal')
+
+ ticket.tag_add('aaa', 1)
+ ticket.tag_add('bbb', 1)
+ create(:ticket_article,
+ :inbound_email,
+ ticket: ticket)
+
+ travel 5.hours
+
+ ticket.update! group: group_1
+
+ travel_back
+ ticket
+ end
+
+ describe '.items' do
+ it 'gets items with test_category cc:bb' do
+ result = described_class.items(
+ range_start: Time.zone.parse('2015-01-01T00:00:00Z'),
+ range_end: Time.zone.parse('2015-12-31T23:59:59Z'),
+ selector: {
+ 'test_category' => {
+ 'operator' => 'is',
+ 'value' => 'cc::bb'
+ },
+ },
+ params: { field: 'created_at' },
+ )
+
+ expect(result).to match_tickets ticket_with_category
+ end
+ end
+ end
end
diff --git a/spec/lib/report/ticket_moved_spec.rb b/spec/lib/report/ticket_moved_spec.rb
new file mode 100644
index 000000000..9efb30424
--- /dev/null
+++ b/spec/lib/report/ticket_moved_spec.rb
@@ -0,0 +1,148 @@
+# Copyright (C) 2012-2021 Zammad Foundation, http://zammad-foundation.org/
+
+#
+# rubocop:disable RSpec/ExampleLength
+
+require 'rails_helper'
+require 'lib/report_examples'
+
+RSpec.describe Report::TicketMoved, searchindex: true do
+ include_examples 'with report examples'
+
+ describe '.aggs' do
+ it 'gets monthly aggregated results not in merged state' do
+ result = described_class.aggs(
+ range_start: Time.zone.parse('2015-01-01T00:00:00Z'),
+ range_end: Time.zone.parse('2015-12-31T23:59:59Z'),
+ interval: 'month',
+ selector: {
+ 'ticket_state.name' => {
+ 'operator' => 'is not',
+ 'value' => 'merged',
+ }
+ },
+ params: {
+ type: 'in',
+ },
+ )
+
+ expect(result).to eq [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
+ end
+
+ it 'gets monthly aggregated results in users group' do
+ result = described_class.aggs(
+ range_start: Time.zone.parse('2015-01-01T00:00:00Z'),
+ range_end: Time.zone.parse('2015-12-31T23:59:59Z'),
+ interval: 'month',
+ selector: {
+ 'ticket.group_id' => {
+ 'operator' => 'is',
+ 'value' => [Group.lookup(name: 'Users').id],
+ }
+ },
+ params: {
+ type: 'in',
+ },
+ )
+
+ expect(result).to eq [0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0]
+ end
+
+ it 'gets monthly aggregated results not in merged state and outgoing' do
+ result = described_class.aggs(
+ range_start: Time.zone.parse('2015-01-01T00:00:00Z'),
+ range_end: Time.zone.parse('2015-12-31T23:59:59Z'),
+ interval: 'month',
+ selector: {
+ 'ticket_state.name' => {
+ 'operator' => 'is not',
+ 'value' => 'merged',
+ }
+ },
+ params: {
+ type: 'out',
+ },
+ )
+
+ expect(result).to eq [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
+ end
+
+ it 'gets monthly aggregated results in users group and outgoing' do
+ result = described_class.aggs(
+ range_start: Time.zone.parse('2015-01-01T00:00:00Z'),
+ range_end: Time.zone.parse('2015-12-31T23:59:59Z'),
+ interval: 'month',
+ selector: {
+ 'ticket.group_id' => {
+ 'operator' => 'is',
+ 'value' => [Group.lookup(name: 'Users').id],
+ }
+ },
+ params: {
+ type: 'out',
+ },
+ )
+
+ expect(result).to eq [0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0]
+ end
+
+ end
+
+ describe '.items' do
+ it 'gets items in year range in users group' do
+ result = described_class.items(
+ range_start: Time.zone.parse('2015-01-01T00:00:00Z'),
+ range_end: Time.zone.parse('2015-12-31T23:59:59Z'),
+ selector: {
+ 'ticket.group_id' => {
+ 'operator' => 'is',
+ 'value' => [Group.lookup(name: 'Users').id],
+ }
+ },
+ params: {
+ type: 'in',
+ },
+ )
+
+ expect(result).to match_tickets ticket_1
+ end
+
+ it 'gets items in year range not merged and outgoing' do
+ result = described_class.items(
+ range_start: Time.zone.parse('2015-01-01T00:00:00Z'),
+ range_end: Time.zone.parse('2015-12-31T23:59:59Z'),
+ selector: {
+ 'ticket_state.name' => {
+ 'operator' => 'is not',
+ 'value' => 'merged',
+ }
+ }, # ticket selector to get only a collection of tickets
+ params: {
+ type: 'out',
+ },
+ )
+
+ expect(result).to match_tickets []
+ end
+
+ it 'gets items in year range in users group and outgoing' do
+ result = described_class.items(
+ range_start: Time.zone.parse('2015-01-01T00:00:00Z'),
+ range_end: Time.zone.parse('2015-12-31T23:59:59Z'),
+ selector: {
+ 'ticket.group_id' => {
+ 'operator' => 'is',
+ 'value' => [Group.lookup(name: 'Users').id],
+ }
+ },
+ params: {
+ type: 'out',
+ },
+ )
+
+ expect(result).to match_tickets ticket_2
+ end
+
+ end
+end
+# rubocop:enable RSpec/ExampleLength
diff --git a/spec/lib/report/ticket_reopened_spec.rb b/spec/lib/report/ticket_reopened_spec.rb
new file mode 100644
index 000000000..054fc9663
--- /dev/null
+++ b/spec/lib/report/ticket_reopened_spec.rb
@@ -0,0 +1,129 @@
+# Copyright (C) 2012-2021 Zammad Foundation, http://zammad-foundation.org/
+
+# rubocop:disable RSpec/ExampleLength
+
+require 'rails_helper'
+require 'lib/report_examples'
+
+RSpec.describe Report::TicketReopened, searchindex: true do
+ include_examples 'with report examples'
+
+ describe '.aggs' do
+ it 'gets monthly aggregated results' do
+ result = described_class.aggs(
+ range_start: Time.zone.parse('2015-01-01T00:00:00Z'),
+ range_end: Time.zone.parse('2015-12-31T23:59:59Z'),
+ interval: 'month',
+ selector: {},
+ )
+
+ expect(result).to eq [0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0]
+ end
+
+ it 'gets monthly aggregated results with high priority' do
+ result = described_class.aggs(
+ range_start: Time.zone.parse('2015-01-01T00:00:00Z'),
+ range_end: Time.zone.parse('2015-12-31T23:59:59Z'),
+ interval: 'month',
+ selector: {
+ 'ticket.priority_id' => {
+ 'operator' => 'is',
+ 'value' => [Ticket::Priority.lookup(name: '3 high').id],
+ }
+ }
+ )
+
+ expect(result).to eq [0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0]
+ end
+
+ it 'gets monthly aggregated results with not high priority' do
+ result = described_class.aggs(
+ range_start: Time.zone.parse('2015-01-01T00:00:00Z'),
+ range_end: Time.zone.parse('2015-12-31T23:59:59Z'),
+ interval: 'month',
+ selector: {
+ 'ticket.priority_id' => {
+ 'operator' => 'is not',
+ 'value' => [Ticket::Priority.lookup(name: '3 high').id],
+ }
+ },
+ )
+
+ expect(result).to eq [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
+ end
+
+ it 'gets monthly aggregated results with not merged' do
+ result = described_class.aggs(
+ range_start: Time.zone.parse('2015-01-01T00:00:00Z'),
+ range_end: Time.zone.parse('2015-12-31T23:59:59Z'),
+ interval: 'month',
+ selector: {
+ 'ticket_state.name' => {
+ 'operator' => 'is not',
+ 'value' => 'merged',
+ }
+ },
+ )
+
+ expect(result).to eq [0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0]
+ end
+ end
+
+ describe '.items' do
+ it 'gets items in year range' do
+ result = described_class.items(
+ range_start: Time.zone.parse('2015-01-01T00:00:00Z'),
+ range_end: Time.zone.parse('2015-12-31T23:59:59Z'),
+ selector: {},
+ )
+
+ expect(result).to match_tickets ticket_5
+ end
+
+ it 'gets items in year range with high priority' do
+ result = described_class.items(
+ range_start: Time.zone.parse('2015-01-01T00:00:00Z'),
+ range_end: Time.zone.parse('2015-12-31T23:59:59Z'),
+ selector: {
+ 'ticket.priority_id' => {
+ 'operator' => 'is',
+ 'value' => [Ticket::Priority.lookup(name: '3 high').id],
+ }
+ },
+ )
+
+ expect(result).to match_tickets ticket_5
+ end
+
+ it 'gets items in year range with not high priority' do
+ result = described_class.items(
+ range_start: Time.zone.parse('2015-01-01T00:00:00Z'),
+ range_end: Time.zone.parse('2015-12-31T23:59:59Z'),
+ selector: {
+ 'ticket.priority_id' => {
+ 'operator' => 'is not',
+ 'value' => [Ticket::Priority.lookup(name: '3 high').id],
+ }
+ },
+ )
+
+ expect(result).to match_tickets []
+ end
+
+ it 'gets items in year range with not merged' do
+ result = described_class.items(
+ range_start: Time.zone.parse('2015-01-01T00:00:00Z'),
+ range_end: Time.zone.parse('2015-12-31T23:59:59Z'),
+ selector: {
+ 'ticket_state.name' => {
+ 'operator' => 'is not',
+ 'value' => 'merged',
+ }
+ },
+ )
+
+ expect(result).to match_tickets ticket_5
+ end
+ end
+end
+# rubocop:enable RSpec/ExampleLength
diff --git a/spec/lib/report_examples.rb b/spec/lib/report_examples.rb
new file mode 100644
index 000000000..e770617b4
--- /dev/null
+++ b/spec/lib/report_examples.rb
@@ -0,0 +1,245 @@
+# Copyright (C) 2012-2021 Zammad Foundation, http://zammad-foundation.org/
+
+RSpec.shared_context 'with report examples' do
+ before do |example|
+ next if !example.metadata[:searchindex]
+
+ configure_elasticsearch(required: true, rebuild: true) do
+ ticket_1
+
+ ticket_2
+
+ ticket_3
+
+ ticket_4
+
+ ticket_5
+
+ ticket_6
+
+ ticket_7
+
+ ticket_8
+
+ ticket_9
+
+ ticket_after_72h
+
+ ticket_before_40d
+ end
+ end
+
+ let(:group_1) { Group.lookup(name: 'Users') }
+ let(:group_2) { create(:group) }
+ let(:customer) { User.lookup(email: 'nicole.braun@zammad.org') }
+
+ let(:ticket_1) do
+ travel_to DateTime.new 2015, 10, 28, 9, 30
+ ticket = create(:ticket,
+ group: group_2,
+ customer: customer,
+ state_name: 'new',
+ priority_name: '2 normal')
+
+ ticket.tag_add('aaa', 1)
+ ticket.tag_add('bbb', 1)
+ create(:ticket_article,
+ :inbound_email,
+ ticket: ticket)
+
+ travel 5.hours
+
+ ticket.update! group: group_1
+
+ travel_back
+ ticket
+ end
+
+ let(:ticket_2) do
+ travel_to DateTime.new 2015, 10, 28, 9, 30, 1
+ ticket = create(:ticket,
+ group: group_1,
+ customer: customer,
+ state_name: 'new',
+ priority_name: '2 normal')
+
+ ticket.tag_add('aaa', 1)
+ create(:ticket_article,
+ :inbound_email,
+ ticket: ticket)
+ travel 5.hours - 1.second
+
+ ticket.update! group: group_2
+
+ travel_back
+ ticket
+ end
+
+ let(:ticket_3) do
+ travel_to DateTime.new 2015, 10, 28, 10, 30
+ ticket = create(:ticket,
+ group: group_1,
+ customer: customer,
+ state_name: 'open',
+ priority_name: '3 high')
+ create(:ticket_article,
+ :inbound_email,
+ ticket: ticket)
+
+ travel_back
+ ticket
+ end
+
+ let(:ticket_4) do
+ travel_to DateTime.new 2015, 10, 28, 10, 30, 1
+ ticket = create(:ticket,
+ group: group_1,
+ customer: customer,
+ state_name: 'closed',
+ priority_name: '2 normal',
+ close_at: (1.hour - 1.second).from_now)
+ create(:ticket_article,
+ :inbound_email,
+ ticket: ticket)
+ travel_back
+ ticket
+ end
+
+ let(:ticket_5) do
+ travel_to DateTime.new 2015, 10, 28, 11, 30
+ ticket = create(:ticket,
+ group: group_1,
+ customer: customer,
+ state_name: 'closed',
+ priority_name: '3 high',
+ close_at: 10.minutes.from_now)
+
+ ticket.tag_add('bbb', 1)
+ create(:ticket_article,
+ :outbound_email,
+ ticket: ticket)
+
+ ticket.update! state: Ticket::State.lookup(name: 'open')
+
+ travel 3.hours
+
+ travel_back
+ ticket
+ end
+
+ let(:ticket_6) do
+ travel_to DateTime.new 2015, 10, 31, 12, 30
+ ticket = create(:ticket,
+ group: group_1,
+ customer: customer,
+ state_name: 'closed',
+ priority_name: '2 normal',
+ close_at: 5.minutes.from_now)
+ create(:ticket_article,
+ :outbound_email,
+ ticket: ticket)
+
+ travel_back
+ ticket
+ end
+
+ let(:ticket_7) do
+ travel_to DateTime.new 2015, 11, 1, 12, 30
+ ticket = create(:ticket,
+ group: group_1,
+ customer: customer,
+ state_name: 'closed',
+ priority_name: '2 normal',
+ close_at: Time.zone.now)
+ create(:ticket_article,
+ :inbound_email,
+ ticket: ticket)
+ travel_back
+ ticket
+ end
+
+ let(:ticket_8) do
+ travel_to DateTime.new 2015, 11, 2, 12, 30
+ ticket = create(:ticket,
+ group: group_1,
+ customer: customer,
+ state_name: 'merged',
+ priority_name: '2 normal',
+ close_at: Time.zone.now)
+
+ create(:ticket_article,
+ :inbound_email,
+ ticket: ticket)
+
+ travel_back
+ ticket
+ end
+
+ let(:ticket_9) do
+ travel_to DateTime.new 2037, 11, 2, 12, 30
+ ticket = create(:ticket,
+ group: group_1,
+ customer: customer,
+ state_name: 'merged',
+ priority_name: '2 normal',
+ close_at: Time.zone.now)
+ create(:ticket_article,
+ :inbound_email,
+ ticket: ticket)
+
+ travel_back
+
+ ticket
+ end
+
+ let(:ticket_after_72h) do
+ travel 72.hours do
+ ticket = create(:ticket,
+ group: group_1,
+ customer: customer,
+ state_name: 'closed',
+ priority_name: '2 normal',
+ close_at: 5.minutes.from_now)
+ create(:ticket_article,
+ :outbound_email,
+ ticket: ticket)
+
+ ticket
+ end
+ end
+
+ let(:ticket_before_40d) do
+ travel(-40.days) do
+ ticket = create(:ticket,
+ group: group_1,
+ customer: customer,
+ state_name: 'closed',
+ priority_name: '2 normal',
+ close_at: 5.minutes.from_now)
+ create(:ticket_article,
+ :outbound_email,
+ ticket: ticket)
+
+ ticket
+ end
+ end
+
+ matcher :match_tickets do
+ match do
+ if expected_tickets.blank?
+ actual_ticket_ids.blank?
+ else
+ # GenericTime returns string ids :o
+ actual_ticket_ids.map(&:to_i) == expected_tickets.map(&:id)
+ end
+ end
+
+ def expected_tickets
+ Array(expected)
+ end
+
+ def actual_ticket_ids
+ actual[:ticket_ids]
+ end
+ end
+end
diff --git a/spec/lib/search_index_backend_spec.rb b/spec/lib/search_index_backend_spec.rb
index 5f3f46c03..c7f488c5b 100644
--- a/spec/lib/search_index_backend_spec.rb
+++ b/spec/lib/search_index_backend_spec.rb
@@ -2,11 +2,12 @@
require 'rails_helper'
-RSpec.describe SearchIndexBackend, searchindex: true do
+RSpec.describe SearchIndexBackend do
- before do
- configure_elasticsearch
- rebuild_searchindex
+ before do |example|
+ next if !example.metadata[:searchindex]
+
+ configure_elasticsearch(required: true, rebuild: true)
end
describe '.build_query' do
@@ -19,7 +20,7 @@ RSpec.describe SearchIndexBackend, searchindex: true do
end
end
- describe '.search' do
+ describe '.search', searchindex: true do
context 'query finds results' do
@@ -200,7 +201,8 @@ RSpec.describe SearchIndexBackend, searchindex: true do
end
end
- describe '.remove' do
+ describe '.remove', searchindex: true do
+
context 'record gets deleted' do
let(:record_type) { 'Ticket'.freeze }
@@ -239,7 +241,7 @@ RSpec.describe SearchIndexBackend, searchindex: true do
end
end
- describe '.selectors' do
+ describe '.selectors', searchindex: true do
let(:group1) { create :group }
let(:organization1) { create :organization, note: 'hihi' }
@@ -845,4 +847,145 @@ RSpec.describe SearchIndexBackend, searchindex: true do
end
end
end
+
+ describe '.verify_date_range' do
+ let(:range_1) { { range: { created_at: { from: '2020-01-01T00:00:00.000Z', to: '2021-12-31T23:59:59Z' } } } }
+ let(:range_2) { { range: { created_at: { from: '2020-03-01T00:00:00.000Z', to: '2020-03-31T23:59:59Z' } } } }
+ let(:range_3) { { range: { created_at: { from: '2018-03-01T00:00:00.000Z', to: '2018-03-31T23:59:59Z' } } } }
+ let(:range_4) { { range: { updated_at: { from: '2018-03-01T00:00:00.000Z', to: '2018-03-31T23:59:59Z' } } } }
+
+ def build_payload(*ranges)
+ {
+ query: {
+ bool: {
+ must: ranges
+ }
+ }
+ }
+ end
+
+ it 'verifies single range' do
+ result = described_class.verify_date_range 'url', build_payload(range_1)
+
+ expect(result).to be_truthy
+ end
+
+ it 'verifies multiple intersecting ranges' do
+ result = described_class.verify_date_range 'url', build_payload(range_1, range_2)
+
+ expect(result).to be_truthy
+ end
+
+ it 'verifies non-intersecting ranges on different keys' do
+ result = described_class.verify_date_range 'url', build_payload(range_1, range_4)
+
+ expect(result).to be_truthy
+ end
+
+ it 'verifies payload without any ranges' do
+ result = described_class.verify_date_range 'url', build_payload
+
+ expect(result).to be_truthy
+ end
+
+ it 'verifies payload without payload' do
+ result = described_class.verify_date_range 'url', {}
+
+ expect(result).to be_truthy
+ end
+
+ it 'raises an error with multiple non-intersecting range' do
+ expect { described_class.verify_date_range 'url', build_payload(range_1, range_3) }
+ .to raise_error(%r{Conflicting date ranges})
+ end
+
+ context 'with a stubbed range' do
+ before do
+ allow(described_class).to receive(:convert_es_date_range).and_return(mock_range)
+ end
+
+ let(:mock_range) { instance_double('Range', overlaps?: true) }
+
+ it 'checks overlap once for 2 ranges' do
+ described_class.verify_date_range 'url', build_payload(range_1, range_2)
+ expect(mock_range).to have_received(:overlaps?).exactly(1).times
+ end
+
+ it 'checks overlap 3 times for 3 ranges' do
+ described_class.verify_date_range 'url', build_payload(range_1, range_2, range_3)
+ expect(mock_range).to have_received(:overlaps?).exactly(3).times
+ end
+ end
+ end
+
+ describe '.verify_single_key_range' do
+ let(:range_1) { DateTime.new(2020, 1, 1)..DateTime.new(2021, 12, 31) }
+ let(:range_2) { DateTime.new(2020, 3, 1)..DateTime.new(2020, 3, 31) }
+ let(:range_3) { DateTime.new(2018, 3, 1)..DateTime.new(2018, 3, 31) }
+
+ it 'returns true with a single range' do
+ result = described_class.verify_single_key_range [range_1]
+ expect(result).to be_truthy
+ end
+
+ it 'returns true with overlapping ranges' do
+ result = described_class.verify_single_key_range [range_1, range_2]
+ expect(result).to be_truthy
+ end
+
+ it 'returns false with non-overlapping ranges' do
+ result = described_class.verify_single_key_range [range_1, range_3]
+ expect(result).to be_falsey
+ end
+ end
+
+ describe '.convert_es_date_range' do
+ let(:from) { DateTime.new 2018, 1, 1, 17 }
+ let(:from_placeholder) { DateTime.new(-9999, 1, 1) }
+ let(:to) { DateTime.new 2020, 10, 1, 23 }
+ let(:to_placeholder) { DateTime.new 9999, 1, 1 }
+
+ it 'converts range' do
+ result = described_class.convert_es_date_range(
+ {
+ range: {
+ created_at: {
+ from: '2018-01-01T17:00:00.000Z',
+ to: '2020-10-01T23:00:00Z'
+ }
+ }
+ }
+ )
+
+ expect(result).to eq from..to
+ end
+
+ it 'converts less than' do
+ result = described_class.convert_es_date_range(
+ {
+ range: {
+ created_at: {
+ lt: '2020-10-01T23:00:00Z'
+ }
+ }
+ }
+ )
+
+ expect(result).to eq from_placeholder..to
+ end
+
+ it 'converts greater than' do
+ result = described_class.convert_es_date_range(
+ {
+ range: {
+ created_at: {
+ gt: '2018-01-01T17:00:00.000Z',
+ }
+ }
+ }
+ )
+
+ expect(result).to eq from..to_placeholder
+ end
+ end
end
diff --git a/spec/system/report_spec.rb b/spec/system/report_spec.rb
index 447701b1d..234179ceb 100644
--- a/spec/system/report_spec.rb
+++ b/spec/system/report_spec.rb
@@ -33,4 +33,42 @@ RSpec.describe 'Report', type: :system, searchindex: true do
end
end
end
+
+ context 'report profiles are displayed' do
+ let!(:report_profile_active) { create(:report_profile) }
+ let!(:report_profile_inactive) { create(:report_profile, active: false) }
+
+ it 'shows report profiles' do
+ visit 'report'
+
+ expect(page)
+ .to have_css('ul.checkbox-list .label-text', text: report_profile_active.name)
+ .and have_no_css('ul.checkbox-list .label-text', text: report_profile_inactive.name)
+ end
+ end
+
+ context 'with report profiles with date-based conditions' do
+ let(:report_profile) { create(:report_profile, :condition_created_at, ticket_created_at: 1.year.ago) }
+
+ before do
+ freeze_time
+ report_profile
+ visit 'report'
+ end
+
+ it 'shows previous year for a profile with matching conditions' do
+ click '.js-timePickerYear', text: Time.zone.now.year - 1
+ click '.label-text', text: report_profile.name
+
+ expect(page).to have_no_css('.modal')
+ end
+
+ it 'throws error for a profile when showing a different year than described in the profile' do
+ click '.label-text', text: report_profile.name
+
+ in_modal disappears: false do
+ expect(page).to have_text 'Conflicting date ranges'
+ end
+ end
+ end
end
diff --git a/test/integration/report_test.rb b/test/integration/report_test.rb
deleted file mode 100644
index 48db03649..000000000
--- a/test/integration/report_test.rb
+++ /dev/null
@@ -1,1404 +0,0 @@
-# Copyright (C) 2012-2021 Zammad Foundation, http://zammad-foundation.org/
-
-require 'integration_test_helper'
-
-class ReportTest < ActiveSupport::TestCase
- include SearchindexHelper
-
- setup do
-
- # create attribute
- ObjectManager::Attribute.add(
- object: 'Ticket',
- name: 'test_category',
- display: 'Test 1',
- data_type: 'tree_select',
- data_option: {
- maxlength: 200,
- null: false,
- default: '',
- options: [
- { 'name' => 'aa', 'value' => 'aa', 'children' => [{ 'name' => 'aa', 'value' => 'aa::aa' }, { 'name' => 'bb', 'value' => 'aa::bb' }, { 'name' => 'cc', 'value' => 'aa::cc' }] },
- { 'name' => 'bb', 'value' => 'bb', 'children' => [{ 'name' => 'aa', 'value' => 'bb::aa' }, { 'name' => 'bb', 'value' => 'bb::bb' }, { 'name' => 'cc', 'value' => 'bb::cc' }] },
- { 'name' => 'cc', 'value' => 'cc', 'children' => [{ 'name' => 'aa', 'value' => 'cc::aa' }, { 'name' => 'bb', 'value' => 'cc::bb' }, { 'name' => 'cc', 'value' => 'cc::cc' }] },
- ]
- },
- active: true,
- screens: {},
- position: 20,
- created_by_id: 1,
- updated_by_id: 1,
- editable: false,
- to_migrate: false,
- )
- ObjectManager::Attribute.migration_execute
-
- configure_elasticsearch(required: true)
-
- Ticket.destroy_all
-
- rebuild_searchindex
-
- group1 = Group.lookup(name: 'Users')
- group2 = Group.create!(
- name: 'Report Test',
- updated_by_id: 1,
- created_by_id: 1
- )
-
- @ticket1 = Ticket.create!(
- title: 'test 1',
- group: group2,
- customer_id: 2,
- state: Ticket::State.lookup(name: 'new'),
- priority: Ticket::Priority.lookup(name: '2 normal'),
- created_at: '2015-10-28 09:30:00 UTC',
- updated_at: '2015-10-28 09:30:00 UTC',
- test_category: 'cc::bb',
- updated_by_id: 1,
- created_by_id: 1,
- )
- Ticket::Article.create!(
- ticket_id: @ticket1.id,
- from: 'some_sender@example.com',
- to: 'some_recipient@example.com',
- subject: 'some subject',
- message_id: 'some@id',
- body: 'some message article_inbound',
- internal: false,
- sender: Ticket::Article::Sender.where(name: 'Customer').first,
- type: Ticket::Article::Type.where(name: 'email').first,
- created_at: '2015-10-28 09:30:00 UTC',
- updated_at: '2015-10-28 09:30:00 UTC',
- updated_by_id: 1,
- created_by_id: 1,
- )
- @ticket1.tag_add('aaa', 1)
- @ticket1.tag_add('bbb', 1)
- @ticket1.update!(
- group: Group.lookup(name: 'Users'),
- updated_at: '2015-10-28 14:30:00 UTC',
- )
-
- @ticket2 = Ticket.create!(
- title: 'test 2',
- group: group1,
- customer_id: 2,
- state: Ticket::State.lookup(name: 'new'),
- priority: Ticket::Priority.lookup(name: '2 normal'),
- created_at: '2015-10-28 09:30:01 UTC',
- updated_at: '2015-10-28 09:30:01 UTC',
- updated_by_id: 1,
- created_by_id: 1,
- )
- Ticket::Article.create!(
- ticket_id: @ticket2.id,
- from: 'some_sender@example.com',
- to: 'some_recipient@example.com',
- subject: 'some subject',
- message_id: 'some@id',
- body: 'some message article_inbound',
- internal: false,
- sender: Ticket::Article::Sender.where(name: 'Customer').first,
- type: Ticket::Article::Type.where(name: 'email').first,
- created_at: '2015-10-28 09:30:01 UTC',
- updated_at: '2015-10-28 09:30:01 UTC',
- updated_by_id: 1,
- created_by_id: 1,
- )
- @ticket2.tag_add('aaa', 1)
- @ticket2.update!(
- group_id: group2.id,
- updated_at: '2015-10-28 14:30:00 UTC',
- )
-
- @ticket3 = Ticket.create!(
- title: 'test 3',
- group: group1,
- customer_id: 2,
- state: Ticket::State.lookup(name: 'open'),
- priority: Ticket::Priority.lookup(name: '3 high'),
- created_at: '2015-10-28 10:30:00 UTC',
- updated_at: '2015-10-28 10:30:00 UTC',
- updated_by_id: 1,
- created_by_id: 1,
- )
- Ticket::Article.create!(
- ticket_id: @ticket3.id,
- from: 'some_sender@example.com',
- to: 'some_recipient@example.com',
- subject: 'some subject',
- message_id: 'some@id',
- body: 'some message article_inbound',
- internal: false,
- sender: Ticket::Article::Sender.where(name: 'Customer').first,
- type: Ticket::Article::Type.where(name: 'email').first,
- created_at: '2015-10-28 10:30:00 UTC',
- updated_at: '2015-10-28 10:30:00 UTC',
- updated_by_id: 1,
- created_by_id: 1,
- )
-
- @ticket4 = Ticket.create!(
- title: 'test 4',
- group: group1,
- customer_id: 2,
- state: Ticket::State.lookup(name: 'closed'),
- priority: Ticket::Priority.lookup(name: '2 normal'),
- close_at: '2015-10-28 11:30:00 UTC',
- created_at: '2015-10-28 10:30:01 UTC',
- updated_at: '2015-10-28 10:30:01 UTC',
- updated_by_id: 1,
- created_by_id: 1,
- )
- Ticket::Article.create!(
- ticket_id: @ticket4.id,
- from: 'some_sender@example.com',
- to: 'some_recipient@example.com',
- subject: 'some subject',
- message_id: 'some@id',
- body: 'some message article_inbound',
- internal: false,
- sender: Ticket::Article::Sender.where(name: 'Customer').first,
- type: Ticket::Article::Type.where(name: 'email').first,
- created_at: '2015-10-28 10:30:01 UTC',
- updated_at: '2015-10-28 10:30:01 UTC',
- updated_by_id: 1,
- created_by_id: 1,
- )
-
- @ticket5 = Ticket.create!(
- title: 'test 5',
- group: group1,
- customer_id: 2,
- state: Ticket::State.lookup(name: 'closed'),
- priority: Ticket::Priority.lookup(name: '3 high'),
- close_at: '2015-10-28 11:40:00 UTC',
- created_at: '2015-10-28 11:30:00 UTC',
- updated_at: '2015-10-28 11:30:00 UTC',
- updated_by_id: 1,
- created_by_id: 1,
- )
- Ticket::Article.create!(
- ticket_id: @ticket5.id,
- from: 'some_sender@example.com',
- to: 'some_recipient@example.com',
- subject: 'some subject',
- message_id: 'some@id',
- body: 'some message article_outbound',
- internal: false,
- sender: Ticket::Article::Sender.where(name: 'Agent').first,
- type: Ticket::Article::Type.where(name: 'email').first,
- created_at: '2015-10-28 11:30:00 UTC',
- updated_at: '2015-10-28 11:30:00 UTC',
- updated_by_id: 1,
- created_by_id: 1,
- )
- @ticket5.tag_add('bbb', 1)
- @ticket5.update!(
- state: Ticket::State.lookup(name: 'open'),
- updated_at: '2015-10-28 14:30:00 UTC',
- )
-
- @ticket6 = Ticket.create!(
- title: 'test 6',
- group: group1,
- customer_id: 2,
- state: Ticket::State.lookup(name: 'closed'),
- priority: Ticket::Priority.lookup(name: '2 normal'),
- close_at: '2015-10-31 12:35:00 UTC',
- created_at: '2015-10-31 12:30:00 UTC',
- updated_at: '2015-10-31 12:30:00 UTC',
- updated_by_id: 1,
- created_by_id: 1,
- )
- Ticket::Article.create!(
- ticket_id: @ticket6.id,
- from: 'some_sender@example.com',
- to: 'some_recipient@example.com',
- subject: 'some subject',
- message_id: 'some@id',
- body: 'some message article_outbound',
- internal: false,
- sender: Ticket::Article::Sender.where(name: 'Agent').first,
- type: Ticket::Article::Type.where(name: 'email').first,
- created_at: '2015-10-31 12:30:00 UTC',
- updated_at: '2015-10-31 12:30:00 UTC',
- updated_by_id: 1,
- created_by_id: 1,
- )
-
- @ticket7 = Ticket.create!(
- title: 'test 7',
- group: group1,
- customer_id: 2,
- state: Ticket::State.lookup(name: 'closed'),
- priority: Ticket::Priority.lookup(name: '2 normal'),
- close_at: '2015-11-01 12:30:00 UTC',
- created_at: '2015-11-01 12:30:00 UTC',
- updated_at: '2015-11-01 12:30:00 UTC',
- updated_by_id: 1,
- created_by_id: 1,
- )
- Ticket::Article.create!(
- ticket_id: @ticket7.id,
- from: 'some_sender@example.com',
- to: 'some_recipient@example.com',
- subject: 'some subject',
- message_id: 'some@id',
- body: 'some message article_outbound',
- internal: false,
- sender: Ticket::Article::Sender.where(name: 'Agent').first,
- type: Ticket::Article::Type.where(name: 'email').first,
- created_at: '2015-11-01 12:30:00 UTC',
- updated_at: '2015-11-01 12:30:00 UTC',
- updated_by_id: 1,
- created_by_id: 1,
- )
-
- @ticket8 = Ticket.create!(
- title: 'test 8',
- group: group1,
- customer_id: 2,
- state: Ticket::State.lookup(name: 'merged'),
- priority: Ticket::Priority.lookup(name: '2 normal'),
- close_at: '2015-11-02 12:30:00 UTC',
- created_at: '2015-11-02 12:30:00 UTC',
- updated_at: '2015-11-02 12:30:00 UTC',
- updated_by_id: 1,
- created_by_id: 1,
- )
- Ticket::Article.create!(
- ticket_id: @ticket8.id,
- from: 'some_sender@example.com',
- to: 'some_recipient@example.com',
- subject: 'some subject',
- message_id: 'some@id',
- body: 'some message article_outbound',
- internal: false,
- sender: Ticket::Article::Sender.where(name: 'Agent').first,
- type: Ticket::Article::Type.where(name: 'email').first,
- created_at: '2015-11-02 12:30:00 UTC',
- updated_at: '2015-11-02 12:30:00 UTC',
- updated_by_id: 1,
- created_by_id: 1,
- )
-
- @ticket9 = Ticket.create!(
- title: 'test 9',
- group: group1,
- customer_id: 2,
- state: Ticket::State.lookup(name: 'open'),
- priority: Ticket::Priority.lookup(name: '2 normal'),
- close_at: '2037-11-02 12:30:00 UTC',
- created_at: '2037-11-02 12:30:00 UTC',
- updated_at: '2037-11-02 12:30:00 UTC',
- updated_by_id: 1,
- created_by_id: 1,
- )
- Ticket::Article.create!(
- ticket_id: @ticket9.id,
- from: 'some_sender@example.com',
- to: 'some_recipient@example.com',
- subject: 'some subject',
- message_id: 'some@id',
- body: 'some message article_outbound',
- internal: false,
- sender: Ticket::Article::Sender.where(name: 'Agent').first,
- type: Ticket::Article::Type.where(name: 'email').first,
- created_at: '2037-11-02 12:30:00 UTC',
- updated_at: '2037-11-02 12:30:00 UTC',
- updated_by_id: 1,
- created_by_id: 1,
- )
-
- # execute background jobs
- Scheduler.worker(true)
- SearchIndexBackend.refresh
- end
-
- test 'compare' do
-
- # first solution
- result = Report::TicketFirstSolution.aggs(
- range_start: Time.zone.parse('2015-01-01T00:00:00Z'),
- range_end: Time.zone.parse('2015-12-31T23:59:59Z'),
- interval: 'month', # year, quarter, month, week, day, hour, minute, second
- selector: {}, # ticket selector to get only a collection of tickets
- )
- assert(result)
- assert_equal(0, result[0])
- assert_equal(0, result[1])
- assert_equal(0, result[2])
- assert_equal(0, result[3])
- assert_equal(0, result[4])
- assert_equal(0, result[5])
- assert_equal(0, result[6])
- assert_equal(0, result[7])
- assert_equal(0, result[8])
- assert_equal(2, result[9])
- assert_equal(1, result[10])
- assert_equal(0, result[11])
- assert_nil(result[12])
-
- result = Report::TicketFirstSolution.items(
- range_start: Time.zone.parse('2015-01-01T00:00:00Z'),
- range_end: Time.zone.parse('2015-12-31T23:59:59Z'),
- selector: {}, # ticket selector to get only a collection of tickets
- )
- assert(result)
- assert_equal(@ticket5.id, result[:ticket_ids][0])
- assert_equal(@ticket6.id, result[:ticket_ids][1])
- assert_equal(@ticket7.id, result[:ticket_ids][2])
- assert_nil(result[:ticket_ids][3])
-
- # month - with selector #1
- result = Report::TicketFirstSolution.aggs(
- range_start: Time.zone.parse('2015-01-01T00:00:00Z'),
- range_end: Time.zone.parse('2015-12-31T23:59:59Z'),
- interval: 'month', # year, quarter, month, week, day, hour, minute, second
- selector: {
- 'ticket.priority_id' => {
- 'operator' => 'is',
- 'value' => [Ticket::Priority.lookup(name: '3 high').id],
- }
- }, # ticket selector to get only a collection of tickets
- )
- assert(result)
- assert_equal(0, result[0])
- assert_equal(0, result[1])
- assert_equal(0, result[2])
- assert_equal(0, result[3])
- assert_equal(0, result[4])
- assert_equal(0, result[5])
- assert_equal(0, result[6])
- assert_equal(0, result[7])
- assert_equal(0, result[8])
- assert_equal(1, result[9])
- assert_equal(0, result[10])
- assert_equal(0, result[11])
- assert_nil(result[12])
-
- result = Report::TicketFirstSolution.items(
- range_start: Time.zone.parse('2015-01-01T00:00:00Z'),
- range_end: Time.zone.parse('2015-12-31T23:59:59Z'),
- selector: {
- 'ticket.priority_id' => {
- 'operator' => 'is',
- 'value' => [Ticket::Priority.lookup(name: '3 high').id],
- }
- }, # ticket selector to get only a collection of tickets
- )
- assert(result)
- assert_equal(@ticket5.id, result[:ticket_ids][0])
- assert_nil(result[:ticket_ids][1])
-
- # month - with merged tickets selector
- result = Report::TicketFirstSolution.aggs(
- range_start: Time.zone.parse('2015-01-01T00:00:00Z'),
- range_end: Time.zone.parse('2015-12-31T23:59:59Z'),
- interval: 'month', # year, quarter, month, week, day, hour, minute, second
- selector: {
- 'ticket_state.name' => {
- 'operator' => 'is not',
- 'value' => 'merged',
- }
- }, # ticket selector to get only a collection of tickets
- )
- assert(result)
- assert_equal(0, result[0])
- assert_equal(0, result[1])
- assert_equal(0, result[2])
- assert_equal(0, result[3])
- assert_equal(0, result[4])
- assert_equal(0, result[5])
- assert_equal(0, result[6])
- assert_equal(0, result[7])
- assert_equal(0, result[8])
- assert_equal(2, result[9])
- assert_equal(1, result[10])
- assert_equal(0, result[11])
- assert_nil(result[12])
-
- result = Report::TicketFirstSolution.items(
- range_start: Time.zone.parse('2015-01-01T00:00:00Z'),
- range_end: Time.zone.parse('2015-12-31T23:59:59Z'),
- selector: {
- 'ticket_state.name' => {
- 'operator' => 'is not',
- 'value' => 'merged',
- }
- }, # ticket selector to get only a collection of tickets
- )
- assert(result)
- assert_equal(@ticket5.id, result[:ticket_ids][0])
- assert_nil(result[:ticket_ids][3])
-
- # month - with selector #2
- result = Report::TicketFirstSolution.aggs(
- range_start: Time.zone.parse('2015-01-01T00:00:00Z'),
- range_end: Time.zone.parse('2015-12-31T23:59:59Z'),
- interval: 'month', # year, quarter, month, week, day, hour, minute, second
- selector: {
- 'ticket.priority_id' => {
- 'operator' => 'is not',
- 'value' => [Ticket::Priority.lookup(name: '3 high').id],
- }
- }, # ticket selector to get only a collection of tickets
- )
- assert(result)
- assert_equal(0, result[0])
- assert_equal(0, result[1])
- assert_equal(0, result[2])
- assert_equal(0, result[3])
- assert_equal(0, result[4])
- assert_equal(0, result[5])
- assert_equal(0, result[6])
- assert_equal(0, result[7])
- assert_equal(0, result[8])
- assert_equal(1, result[9])
- assert_equal(1, result[10])
- assert_equal(0, result[11])
- assert_nil(result[12])
-
- result = Report::TicketFirstSolution.items(
- range_start: Time.zone.parse('2015-01-01T00:00:00Z'),
- range_end: Time.zone.parse('2015-12-31T23:59:59Z'),
- selector: {
- 'ticket.priority_id' => {
- 'operator' => 'is not',
- 'value' => [Ticket::Priority.lookup(name: '3 high').id],
- }
- }, # ticket selector to get only a collection of tickets
- )
- assert(result)
- assert_equal(@ticket6.id, result[:ticket_ids][0])
- assert_equal(@ticket7.id, result[:ticket_ids][1])
- assert_nil(result[:ticket_ids][2])
-
- # week
- result = Report::TicketFirstSolution.aggs(
- range_start: Time.zone.parse('2015-10-26T00:00:00Z'),
- range_end: Time.zone.parse('2015-10-31T23:59:59Z'),
- interval: 'week', # year, quarter, month, week, day, hour, minute, second
- selector: {}, # ticket selector to get only a collection of tickets
- )
- assert(result)
- assert_equal(0, result[0])
- assert_equal(0, result[1])
- assert_equal(1, result[2])
- assert_equal(0, result[3])
- assert_equal(0, result[4])
- assert_equal(1, result[5])
- assert_equal(1, result[6])
- assert_nil(result[7])
-
- result = Report::TicketFirstSolution.items(
- range_start: Time.zone.parse('2015-10-26T00:00:00Z'),
- range_end: Time.zone.parse('2015-11-01T23:59:59Z'),
- interval: 'week', # year, quarter, month, week, day, hour, minute, second
- selector: {}, # ticket selector to get only a collection of tickets
- )
- assert(result)
- assert_equal(@ticket5.id, result[:ticket_ids][0])
- assert_equal(@ticket6.id, result[:ticket_ids][1])
- assert_equal(@ticket7.id, result[:ticket_ids][2])
- assert_nil(result[:ticket_ids][3])
-
- # day
- result = Report::TicketFirstSolution.aggs(
- range_start: Time.zone.parse('2015-10-01T00:00:00Z'),
- range_end: Time.zone.parse('2015-11-01T23:59:59Z'),
- interval: 'day', # year, quarter, month, week, day, hour, minute, second
- selector: {}, # ticket selector to get only a collection of tickets
- )
- assert(result)
- assert_equal(0, result[0])
- assert_equal(0, result[1])
- assert_equal(0, result[2])
- assert_equal(0, result[3])
- assert_equal(0, result[4])
- assert_equal(0, result[5])
- assert_equal(0, result[6])
- assert_equal(0, result[7])
- assert_equal(0, result[8])
- assert_equal(0, result[9])
- assert_equal(0, result[10])
- assert_equal(0, result[11])
- assert_equal(0, result[12])
- assert_equal(0, result[13])
- assert_equal(0, result[14])
- assert_equal(0, result[15])
- assert_equal(0, result[16])
- assert_equal(0, result[17])
- assert_equal(0, result[18])
- assert_equal(0, result[19])
- assert_equal(0, result[20])
- assert_equal(0, result[21])
- assert_equal(0, result[22])
- assert_equal(0, result[23])
- assert_equal(0, result[24])
- assert_equal(0, result[25])
- assert_equal(0, result[26])
- assert_equal(1, result[27])
- assert_equal(0, result[28])
- assert_equal(0, result[29])
- assert_equal(1, result[30])
- assert_nil(result[31])
-
- result = Report::TicketFirstSolution.items(
- range_start: Time.zone.parse('2015-10-01T00:00:00Z'),
- range_end: Time.zone.parse('2015-10-31T23:59:59Z'),
- interval: 'day', # year, quarter, month, week, day, hour, minute, second
- selector: {}, # ticket selector to get only a collection of tickets
- )
- assert(result)
- assert_equal(@ticket5.id, result[:ticket_ids][0])
- assert_equal(@ticket6.id, result[:ticket_ids][1])
- assert_nil(result[:ticket_ids][2])
-
- # hour
- result = Report::TicketFirstSolution.aggs(
- range_start: Time.zone.parse('2015-10-28T00:00:00Z'),
- range_end: Time.zone.parse('2015-10-28T23:59:59Z'),
- interval: 'hour', # year, quarter, month, week, day, hour, minute, second
- selector: {}, # ticket selector to get only a collection of tickets
- )
- assert(result)
- assert_equal(0, result[0])
- assert_equal(0, result[1])
- assert_equal(0, result[2])
- assert_equal(0, result[3])
- assert_equal(0, result[4])
- assert_equal(0, result[5])
- assert_equal(0, result[6])
- assert_equal(0, result[7])
- assert_equal(0, result[8])
- assert_equal(0, result[9])
- assert_equal(0, result[10])
- assert_equal(1, result[11])
- assert_equal(0, result[12])
- assert_equal(0, result[13])
- assert_equal(0, result[14])
- assert_equal(0, result[15])
- assert_equal(0, result[16])
- assert_equal(0, result[17])
- assert_equal(0, result[18])
- assert_equal(0, result[19])
- assert_equal(0, result[20])
- assert_equal(0, result[21])
- assert_equal(0, result[22])
- assert_equal(0, result[23])
- assert_nil(result[24])
-
- result = Report::TicketFirstSolution.items(
- range_start: Time.zone.parse('2015-10-28T00:00:00Z'),
- range_end: Time.zone.parse('2015-10-28T23:59:59Z'),
- interval: 'hour', # year, quarter, month, week, day, hour, minute, second
- selector: {}, # ticket selector to get only a collection of tickets
- )
- assert(result)
- assert_equal(@ticket5.id, result[:ticket_ids][0])
- assert_nil(result[:ticket_ids][1])
-
- # reopen
- result = Report::TicketReopened.aggs(
- range_start: Time.zone.parse('2015-01-01T00:00:00Z'),
- range_end: Time.zone.parse('2015-12-31T23:59:59Z'),
- interval: 'month', # year, quarter, month, week, day, hour, minute, second
- selector: {}, # ticket selector to get only a collection of tickets
- )
- assert(result)
- assert_equal(0, result[0])
- assert_equal(0, result[1])
- assert_equal(0, result[2])
- assert_equal(0, result[3])
- assert_equal(0, result[4])
- assert_equal(0, result[5])
- assert_equal(0, result[6])
- assert_equal(0, result[7])
- assert_equal(0, result[8])
- assert_equal(1, result[9])
- assert_equal(0, result[10])
- assert_equal(0, result[11])
- assert_nil(result[12])
-
- result = Report::TicketReopened.items(
- range_start: Time.zone.parse('2015-01-01T00:00:00Z'),
- range_end: Time.zone.parse('2015-12-31T23:59:59Z'),
- selector: {}, # ticket selector to get only a collection of tickets
- )
- assert(result)
- assert_equal(@ticket5.id, result[:ticket_ids][0])
- assert_nil(result[:ticket_ids][1])
-
- # month - with selector #1
- result = Report::TicketReopened.aggs(
- range_start: Time.zone.parse('2015-01-01T00:00:00Z'),
- range_end: Time.zone.parse('2015-12-31T23:59:59Z'),
- interval: 'month', # year, quarter, month, week, day, hour, minute, second
- selector: {
- 'ticket.priority_id' => {
- 'operator' => 'is',
- 'value' => [Ticket::Priority.lookup(name: '3 high').id],
- }
- }, # ticket selector to get only a collection of tickets
- )
- assert(result)
- assert_equal(0, result[0])
- assert_equal(0, result[1])
- assert_equal(0, result[2])
- assert_equal(0, result[3])
- assert_equal(0, result[4])
- assert_equal(0, result[5])
- assert_equal(0, result[6])
- assert_equal(0, result[7])
- assert_equal(0, result[8])
- assert_equal(1, result[9])
- assert_equal(0, result[10])
- assert_equal(0, result[11])
- assert_nil(result[12])
-
- result = Report::TicketReopened.items(
- range_start: Time.zone.parse('2015-01-01T00:00:00Z'),
- range_end: Time.zone.parse('2015-12-31T23:59:59Z'),
- selector: {
- 'ticket.priority_id' => {
- 'operator' => 'is',
- 'value' => [Ticket::Priority.lookup(name: '3 high').id],
- }
- }, # ticket selector to get only a collection of tickets
- )
- assert(result)
- assert_equal(@ticket5.id, result[:ticket_ids][0])
- assert_nil(result[:ticket_ids][1])
-
- # month - with selector #2
- result = Report::TicketReopened.aggs(
- range_start: Time.zone.parse('2015-01-01T00:00:00Z'),
- range_end: Time.zone.parse('2015-12-31T23:59:59Z'),
- interval: 'month', # year, quarter, month, week, day, hour, minute, second
- selector: {
- 'ticket.priority_id' => {
- 'operator' => 'is not',
- 'value' => [Ticket::Priority.lookup(name: '3 high').id],
- }
- }, # ticket selector to get only a collection of tickets
- )
- assert(result)
- assert_equal(0, result[0])
- assert_equal(0, result[1])
- assert_equal(0, result[2])
- assert_equal(0, result[3])
- assert_equal(0, result[4])
- assert_equal(0, result[5])
- assert_equal(0, result[6])
- assert_equal(0, result[7])
- assert_equal(0, result[8])
- assert_equal(0, result[9])
- assert_equal(0, result[10])
- assert_equal(0, result[11])
- assert_nil(result[12])
-
- result = Report::TicketReopened.items(
- range_start: Time.zone.parse('2015-01-01T00:00:00Z'),
- range_end: Time.zone.parse('2015-12-31T23:59:59Z'),
- selector: {
- 'ticket.priority_id' => {
- 'operator' => 'is not',
- 'value' => [Ticket::Priority.lookup(name: '3 high').id],
- }
- }, # ticket selector to get only a collection of tickets
- )
- assert(result)
- assert_nil(result[:ticket_ids][0])
-
- # month - reopened with merge selector
- result = Report::TicketReopened.aggs(
- range_start: Time.zone.parse('2015-01-01T00:00:00Z'),
- range_end: Time.zone.parse('2015-12-31T23:59:59Z'),
- interval: 'month', # year, quarter, month, week, day, hour, minute, second
- selector: {
- 'ticket_state.name' => {
- 'operator' => 'is not',
- 'value' => 'merged',
- }
- }, # ticket selector to get only a collection of tickets
- )
- assert(result)
- assert_equal(0, result[0])
- assert_equal(0, result[1])
- assert_equal(0, result[2])
- assert_equal(0, result[3])
- assert_equal(0, result[4])
- assert_equal(0, result[5])
- assert_equal(0, result[6])
- assert_equal(0, result[7])
- assert_equal(0, result[8])
- assert_equal(1, result[9])
- assert_equal(0, result[10])
- assert_equal(0, result[11])
- assert_nil(result[12])
-
- result = Report::TicketReopened.items(
- range_start: Time.zone.parse('2015-01-01T00:00:00Z'),
- range_end: Time.zone.parse('2015-12-31T23:59:59Z'),
- selector: {
- 'ticket_state.name' => {
- 'operator' => 'is not',
- 'value' => 'merged',
- }
- }, # ticket selector to get only a collection of tickets
- )
- assert(result)
- assert_equal(@ticket5.id, result[:ticket_ids][0])
- assert_nil(result[:ticket_ids][1])
-
- # move in/out without merged status
- result = Report::TicketMoved.aggs(
- range_start: Time.zone.parse('2015-01-01T00:00:00Z'),
- range_end: Time.zone.parse('2015-12-31T23:59:59Z'),
- interval: 'month', # year, quarter, month, week, day, hour, minute, second
- selector: {
- 'ticket_state.name' => {
- 'operator' => 'is not',
- 'value' => 'merged',
- }
- }, # ticket selector to get only a collection of tickets
- params: {
- type: 'in',
- },
- )
- assert(result)
- assert_equal(0, result[0])
- assert_equal(0, result[1])
- assert_equal(0, result[2])
- assert_equal(0, result[3])
- assert_equal(0, result[4])
- assert_equal(0, result[5])
- assert_equal(0, result[6])
- assert_equal(0, result[7])
- assert_equal(0, result[8])
- assert_equal(0, result[9])
- assert_equal(0, result[10])
- assert_equal(0, result[11])
- assert_nil(result[12])
-
- result = Report::TicketMoved.items(
- range_start: Time.zone.parse('2015-01-01T00:00:00Z'),
- range_end: Time.zone.parse('2015-12-31T23:59:59Z'),
- selector: {
- 'ticket.group_id' => {
- 'operator' => 'is',
- 'value' => [Group.lookup(name: 'Users').id],
- }
- }, # ticket selector to get only a collection of tickets
- params: {
- type: 'in',
- },
- )
- assert(result)
- assert_equal(@ticket1.id, result[:ticket_ids][0])
- assert_nil(result[:ticket_ids][1])
-
- # move in/out
- result = Report::TicketMoved.aggs(
- range_start: Time.zone.parse('2015-01-01T00:00:00Z'),
- range_end: Time.zone.parse('2015-12-31T23:59:59Z'),
- interval: 'month', # year, quarter, month, week, day, hour, minute, second
- selector: {
- 'ticket.group_id' => {
- 'operator' => 'is',
- 'value' => [Group.lookup(name: 'Users').id],
- }
- }, # ticket selector to get only a collection of tickets
- params: {
- type: 'in',
- },
- )
- assert(result)
- assert_equal(0, result[0])
- assert_equal(0, result[1])
- assert_equal(0, result[2])
- assert_equal(0, result[3])
- assert_equal(0, result[4])
- assert_equal(0, result[5])
- assert_equal(0, result[6])
- assert_equal(0, result[7])
- assert_equal(0, result[8])
- assert_equal(1, result[9])
- assert_equal(0, result[10])
- assert_equal(0, result[11])
- assert_nil(result[12])
-
- result = Report::TicketMoved.items(
- range_start: Time.zone.parse('2015-01-01T00:00:00Z'),
- range_end: Time.zone.parse('2015-12-31T23:59:59Z'),
- selector: {
- 'ticket.group_id' => {
- 'operator' => 'is',
- 'value' => [Group.lookup(name: 'Users').id],
- }
- }, # ticket selector to get only a collection of tickets
- params: {
- type: 'in',
- },
- )
- assert(result)
- assert_equal(@ticket1.id, result[:ticket_ids][0])
- assert_nil(result[:ticket_ids][1])
-
- # out without merged tickets
- result = Report::TicketMoved.aggs(
- range_start: Time.zone.parse('2015-01-01T00:00:00Z'),
- range_end: Time.zone.parse('2015-12-31T23:59:59Z'),
- interval: 'month', # year, quarter, month, week, day, hour, minute, second
- selector: {
- 'ticket_state.name' => {
- 'operator' => 'is not',
- 'value' => 'merged',
- }
- }, # ticket selector to get only a collection of tickets
- params: {
- type: 'out',
- },
- )
- assert(result)
- assert_equal(0, result[0])
- assert_equal(0, result[1])
- assert_equal(0, result[2])
- assert_equal(0, result[3])
- assert_equal(0, result[4])
- assert_equal(0, result[5])
- assert_equal(0, result[6])
- assert_equal(0, result[7])
- assert_equal(0, result[8])
- assert_equal(0, result[9])
- assert_equal(0, result[10])
- assert_equal(0, result[11])
- assert_nil(result[12])
-
- result = Report::TicketMoved.items(
- range_start: Time.zone.parse('2015-01-01T00:00:00Z'),
- range_end: Time.zone.parse('2015-12-31T23:59:59Z'),
- selector: {
- 'ticket_state.name' => {
- 'operator' => 'is not',
- 'value' => 'merged',
- }
- }, # ticket selector to get only a collection of tickets
- params: {
- type: 'out',
- },
- )
- assert(result)
- assert_nil(result[:ticket_ids][0])
-
- # out
- result = Report::TicketMoved.aggs(
- range_start: Time.zone.parse('2015-01-01T00:00:00Z'),
- range_end: Time.zone.parse('2015-12-31T23:59:59Z'),
- interval: 'month', # year, quarter, month, week, day, hour, minute, second
- selector: {
- 'ticket.group_id' => {
- 'operator' => 'is',
- 'value' => [Group.lookup(name: 'Users').id],
- }
- }, # ticket selector to get only a collection of tickets
- params: {
- type: 'out',
- },
- )
- assert(result)
- assert_equal(0, result[0])
- assert_equal(0, result[1])
- assert_equal(0, result[2])
- assert_equal(0, result[3])
- assert_equal(0, result[4])
- assert_equal(0, result[5])
- assert_equal(0, result[6])
- assert_equal(0, result[7])
- assert_equal(0, result[8])
- assert_equal(1, result[9])
- assert_equal(0, result[10])
- assert_equal(0, result[11])
- assert_nil(result[12])
-
- result = Report::TicketMoved.items(
- range_start: Time.zone.parse('2015-01-01T00:00:00Z'),
- range_end: Time.zone.parse('2015-12-31T23:59:59Z'),
- selector: {
- 'ticket.group_id' => {
- 'operator' => 'is',
- 'value' => [Group.lookup(name: 'Users').id],
- }
- }, # ticket selector to get only a collection of tickets
- params: {
- type: 'out',
- },
- )
- assert(result)
- assert_equal(@ticket2.id, result[:ticket_ids][0])
- assert_nil(result[:ticket_ids][1])
-
- # create at
- result = Report::TicketGenericTime.aggs(
- range_start: Time.zone.parse('2015-01-01T00:00:00Z'),
- range_end: Time.zone.parse('2015-12-31T23:59:59Z'),
- interval: 'month', # year, quarter, month, week, day, hour, minute, second
- selector: {}, # ticket selector to get only a collection of tickets
- params: { field: 'created_at' },
- )
- assert(result)
- assert_equal(0, result[0])
- assert_equal(0, result[1])
- assert_equal(0, result[2])
- assert_equal(0, result[3])
- assert_equal(0, result[4])
- assert_equal(0, result[5])
- assert_equal(0, result[6])
- assert_equal(0, result[7])
- assert_equal(0, result[8])
- assert_equal(6, result[9])
- assert_equal(1, result[10])
- assert_equal(0, result[11])
- assert_nil(result[12])
-
- result = Report::TicketGenericTime.items(
- range_start: Time.zone.parse('2015-01-01T00:00:00Z'),
- range_end: Time.zone.parse('2015-12-31T23:59:59Z'),
- selector: {}, # ticket selector to get only a collection of tickets
- params: { field: 'created_at' },
- )
- assert(result)
- assert_equal(@ticket7.id, result[:ticket_ids][0].to_i)
- assert_equal(@ticket6.id, result[:ticket_ids][1].to_i)
- assert_equal(@ticket5.id, result[:ticket_ids][2].to_i)
- assert_equal(@ticket4.id, result[:ticket_ids][3].to_i)
- assert_equal(@ticket3.id, result[:ticket_ids][4].to_i)
- assert_equal(@ticket2.id, result[:ticket_ids][5].to_i)
- assert_equal(@ticket1.id, result[:ticket_ids][6].to_i)
- assert_nil(result[:ticket_ids][7])
-
- # create at - selector with merge
- result = Report::TicketGenericTime.aggs(
- range_start: Time.zone.parse('2015-01-01T00:00:00Z'),
- range_end: Time.zone.parse('2015-12-31T23:59:59Z'),
- interval: 'month', # year, quarter, month, week, day, hour, minute, second
- selector: {
- 'state' => {
- 'operator' => 'is not',
- 'value' => 'merged'
- }
- }, # ticket selector to get only a collection of tickets
- params: { field: 'created_at' },
- )
- assert(result)
- assert_equal(0, result[0])
- assert_equal(0, result[1])
- assert_equal(0, result[2])
- assert_equal(0, result[3])
- assert_equal(0, result[4])
- assert_equal(0, result[5])
- assert_equal(0, result[6])
- assert_equal(0, result[7])
- assert_equal(0, result[8])
- assert_equal(6, result[9])
- assert_equal(1, result[10])
- assert_equal(0, result[11])
- assert_nil(result[12])
-
- result = Report::TicketGenericTime.items(
- range_start: Time.zone.parse('2015-01-01T00:00:00Z'),
- range_end: Time.zone.parse('2015-12-31T23:59:59Z'),
- selector: {
- 'state' => {
- 'operator' => 'is not',
- 'value' => 'merged'
- }
- }, # ticket selector to get only a collection of tickets
- params: { field: 'created_at' },
- )
-
- assert(result)
- assert_equal(@ticket7.id, result[:ticket_ids][0].to_i)
- assert_equal(@ticket6.id, result[:ticket_ids][1].to_i)
- assert_equal(@ticket5.id, result[:ticket_ids][2].to_i)
- assert_equal(@ticket4.id, result[:ticket_ids][3].to_i)
- assert_equal(@ticket3.id, result[:ticket_ids][4].to_i)
- assert_equal(@ticket2.id, result[:ticket_ids][5].to_i)
- assert_equal(@ticket1.id, result[:ticket_ids][6].to_i)
- assert_nil(result[:ticket_ids][7])
-
- result = Report::TicketGenericTime.items(
- range_start: Time.zone.parse('2015-01-01T00:00:00Z'),
- range_end: Time.zone.parse('2015-12-31T23:59:59Z'),
- selector: {
- 'created_at' => {
- 'operator' => 'before (absolute)',
- 'value' => '2015-10-31T00:00:00Z'
- }
- }, # ticket selector to get only a collection of tickets
- params: { field: 'created_at' },
- )
-
- assert(result)
- assert_equal(@ticket5.id, result[:ticket_ids][0].to_i)
- assert_equal(@ticket4.id, result[:ticket_ids][1].to_i)
- assert_equal(@ticket3.id, result[:ticket_ids][2].to_i)
- assert_equal(@ticket2.id, result[:ticket_ids][3].to_i)
- assert_equal(@ticket1.id, result[:ticket_ids][4].to_i)
- assert_nil(result[:ticket_ids][5])
-
- result = Report::TicketGenericTime.items(
- range_start: Time.zone.parse('2015-01-01T00:00:00Z'),
- range_end: Time.zone.parse('2015-12-31T23:59:59Z'),
- selector: {
- 'created_at' => {
- 'operator' => 'after (absolute)',
- 'value' => '2015-10-31T00:00:00Z'
- }
- }, # ticket selector to get only a collection of tickets
- params: { field: 'created_at' },
- )
-
- assert(result)
- assert_equal(@ticket7.id, result[:ticket_ids][0].to_i)
- assert_equal(@ticket6.id, result[:ticket_ids][1].to_i)
- assert_nil(result[:ticket_ids][2])
-
- Report::TicketGenericTime.items(
- range_start: Time.zone.parse('2015-01-01T00:00:00Z'),
- range_end: Time.zone.parse('2015-12-31T23:59:59Z'),
- selector: {
- 'created_at' => {
- 'operator' => 'before (relative)',
- 'range' => 'day',
- 'value' => '1'
- }
- }, # ticket selector to get only a collection of tickets
- params: { field: 'created_at' },
- )
-
- result = Report::TicketGenericTime.items(
- range_start: Time.zone.parse('2015-01-01T00:00:00Z'),
- range_end: Time.zone.parse('2015-12-31T23:59:59Z'),
- selector: {
- 'created_at' => {
- 'operator' => 'after (relative)',
- 'range' => 'day',
- 'value' => '1'
- }
- }, # ticket selector to get only a collection of tickets
- params: { field: 'created_at' },
- )
-
- assert(result)
- assert_nil(result[:ticket_ids][0])
-
- result = Report::TicketGenericTime.items(
- range_start: Time.zone.parse('2037-01-01T00:00:00Z'),
- range_end: Time.zone.parse('2037-12-31T23:59:59Z'),
- selector: {
- 'created_at' => {
- 'operator' => 'before (relative)',
- 'range' => 'day',
- 'value' => '1'
- }
- }, # ticket selector to get only a collection of tickets
- params: { field: 'created_at' },
- )
-
- assert(result)
- assert_nil(result[:ticket_ids][0])
-
- result = Report::TicketGenericTime.items(
- range_start: Time.zone.parse('2037-01-01T00:00:00Z'),
- range_end: Time.zone.parse('2037-12-31T23:59:59Z'),
- selector: {
- 'created_at' => {
- 'operator' => 'after (relative)',
- 'range' => 'day',
- 'value' => '5'
- }
- }, # ticket selector to get only a collection of tickets
- params: { field: 'created_at' },
- )
-
- assert(result)
- assert_equal(@ticket9.id, result[:ticket_ids][0].to_i)
- assert_nil(result[:ticket_ids][1])
-
- result = Report::TicketGenericTime.items(
- range_start: Time.zone.parse('2037-01-01T00:00:00Z'),
- range_end: Time.zone.parse('2037-12-31T23:59:59Z'),
- selector: {
- 'created_at' => {
- 'operator' => 'before (relative)',
- 'range' => 'month',
- 'value' => '1'
- }
- }, # ticket selector to get only a collection of tickets
- params: { field: 'created_at' },
- )
-
- assert(result)
- assert_nil(result[:ticket_ids][0])
-
- result = Report::TicketGenericTime.items(
- range_start: Time.zone.parse('2037-01-01T00:00:00Z'),
- range_end: Time.zone.parse('2037-12-31T23:59:59Z'),
- selector: {
- 'created_at' => {
- 'operator' => 'after (relative)',
- 'range' => 'month',
- 'value' => '5'
- }
- }, # ticket selector to get only a collection of tickets
- params: { field: 'created_at' },
- )
-
- assert(result)
- assert_equal(@ticket9.id, result[:ticket_ids][0].to_i)
- assert_nil(result[:ticket_ids][1])
-
- result = Report::TicketGenericTime.items(
- range_start: Time.zone.parse('2037-01-01T00:00:00Z'),
- range_end: Time.zone.parse('2037-12-31T23:59:59Z'),
- selector: {
- 'created_at' => {
- 'operator' => 'before (relative)',
- 'range' => 'year',
- 'value' => '1'
- }
- }, # ticket selector to get only a collection of tickets
- params: { field: 'created_at' },
- )
-
- assert(result)
- assert_nil(result[:ticket_ids][0])
-
- result = Report::TicketGenericTime.items(
- range_start: Time.zone.parse('2037-01-01T00:00:00Z'),
- range_end: Time.zone.parse('2037-12-31T23:59:59Z'),
- selector: {
- 'created_at' => {
- 'operator' => 'after (relative)',
- 'range' => 'year',
- 'value' => '5'
- }
- }, # ticket selector to get only a collection of tickets
- params: { field: 'created_at' },
- )
-
- assert(result)
- assert_equal(@ticket9.id, result[:ticket_ids][0].to_i)
- assert_nil(result[:ticket_ids][1])
-
- result = Report::TicketGenericTime.items(
- range_start: Time.zone.parse('2015-01-01T00:00:00Z'),
- range_end: Time.zone.parse('2015-12-31T23:59:59Z'),
- selector: {
- 'tags' => {
- 'operator' => 'contains all',
- 'value' => 'aaa, bbb'
- }
- }, # ticket selector to get only a collection of tickets
- params: { field: 'created_at' },
- )
-
- assert(result)
- assert_equal(@ticket1.id, result[:ticket_ids][0].to_i)
- assert_nil(result[:ticket_ids][1])
-
- result = Report::TicketGenericTime.items(
- range_start: Time.zone.parse('2015-01-01T00:00:00Z'),
- range_end: Time.zone.parse('2015-12-31T23:59:59Z'),
- selector: {
- 'tags' => {
- 'operator' => 'contains all not',
- 'value' => 'aaa, bbb'
- }
- }, # ticket selector to get only a collection of tickets
- params: { field: 'created_at' },
- )
-
- assert(result)
- assert_equal(@ticket7.id, result[:ticket_ids][0].to_i)
- assert_equal(@ticket6.id, result[:ticket_ids][1].to_i)
- assert_equal(@ticket5.id, result[:ticket_ids][2].to_i)
- assert_equal(@ticket4.id, result[:ticket_ids][3].to_i)
- assert_equal(@ticket3.id, result[:ticket_ids][4].to_i)
- assert_equal(@ticket2.id, result[:ticket_ids][5].to_i)
- assert_nil(result[:ticket_ids][6])
-
- result = Report::TicketGenericTime.items(
- range_start: Time.zone.parse('2015-01-01T00:00:00Z'),
- range_end: Time.zone.parse('2015-12-31T23:59:59Z'),
- selector: {
- 'tags' => {
- 'operator' => 'contains all',
- 'value' => 'aaa'
- }
- }, # ticket selector to get only a collection of tickets
- params: { field: 'created_at' },
- )
-
- assert(result)
-
- assert_equal(@ticket2.id, result[:ticket_ids][0].to_i)
- assert_equal(@ticket1.id, result[:ticket_ids][1].to_i)
- assert_nil(result[:ticket_ids][2])
-
- result = Report::TicketGenericTime.items(
- range_start: Time.zone.parse('2015-01-01T00:00:00Z'),
- range_end: Time.zone.parse('2015-12-31T23:59:59Z'),
- selector: {
- 'tags' => {
- 'operator' => 'contains all not',
- 'value' => 'aaa'
- }
- }, # ticket selector to get only a collection of tickets
- params: { field: 'created_at' },
- )
-
- assert(result)
- assert_equal(@ticket7.id, result[:ticket_ids][0].to_i)
- assert_equal(@ticket6.id, result[:ticket_ids][1].to_i)
- assert_equal(@ticket5.id, result[:ticket_ids][2].to_i)
- assert_equal(@ticket4.id, result[:ticket_ids][3].to_i)
- assert_equal(@ticket3.id, result[:ticket_ids][4].to_i)
- assert_nil(result[:ticket_ids][5])
-
- result = Report::TicketGenericTime.items(
- range_start: Time.zone.parse('2015-01-01T00:00:00Z'),
- range_end: Time.zone.parse('2015-12-31T23:59:59Z'),
- selector: {
- 'tags' => {
- 'operator' => 'contains one not',
- 'value' => 'aaa'
- }
- }, # ticket selector to get only a collection of tickets
- params: { field: 'created_at' },
- )
-
- assert(result)
-
- assert_equal(@ticket7.id, result[:ticket_ids][0].to_i)
- assert_equal(@ticket6.id, result[:ticket_ids][1].to_i)
- assert_equal(@ticket5.id, result[:ticket_ids][2].to_i)
- assert_equal(@ticket4.id, result[:ticket_ids][3].to_i)
- assert_equal(@ticket3.id, result[:ticket_ids][4].to_i)
- assert_nil(result[:ticket_ids][5])
-
- result = Report::TicketGenericTime.items(
- range_start: Time.zone.parse('2015-01-01T00:00:00Z'),
- range_end: Time.zone.parse('2015-12-31T23:59:59Z'),
- selector: {
- 'tags' => {
- 'operator' => 'contains one not',
- 'value' => 'aaa, bbb'
- }
- }, # ticket selector to get only a collection of tickets
- params: { field: 'created_at' },
- )
-
- assert(result)
- assert_equal(@ticket7.id, result[:ticket_ids][0].to_i)
- assert_equal(@ticket6.id, result[:ticket_ids][1].to_i)
- assert_equal(@ticket4.id, result[:ticket_ids][2].to_i)
- assert_equal(@ticket3.id, result[:ticket_ids][3].to_i)
- assert_nil(result[:ticket_ids][4])
-
- result = Report::TicketGenericTime.items(
- range_start: Time.zone.parse('2015-01-01T00:00:00Z'),
- range_end: Time.zone.parse('2015-12-31T23:59:59Z'),
- selector: {
- 'tags' => {
- 'operator' => 'contains one',
- 'value' => 'aaa'
- }
- }, # ticket selector to get only a collection of tickets
- params: { field: 'created_at' },
- )
-
- assert(result)
-
- assert_equal(@ticket2.id, result[:ticket_ids][0].to_i)
- assert_equal(@ticket1.id, result[:ticket_ids][1].to_i)
- assert_nil(result[:ticket_ids][2])
-
- result = Report::TicketGenericTime.items(
- range_start: Time.zone.parse('2015-01-01T00:00:00Z'),
- range_end: Time.zone.parse('2015-12-31T23:59:59Z'),
- selector: {
- 'tags' => {
- 'operator' => 'contains one',
- 'value' => 'aaa, bbb'
- }
- }, # ticket selector to get only a collection of tickets
- params: { field: 'created_at' },
- )
-
- assert(result)
- assert_equal(@ticket5.id, result[:ticket_ids][0].to_i)
- assert_equal(@ticket2.id, result[:ticket_ids][1].to_i)
- assert_equal(@ticket1.id, result[:ticket_ids][2].to_i)
- assert_nil(result[:ticket_ids][3])
-
- result = Report::TicketGenericTime.items(
- range_start: Time.zone.parse('2015-01-01T00:00:00Z'),
- range_end: Time.zone.parse('2015-12-31T23:59:59Z'),
- selector: {
- 'title' => {
- 'operator' => 'contains',
- 'value' => 'test'
- }
- }, # ticket selector to get only a collection of tickets
- params: { field: 'created_at' },
- )
-
- assert(result)
- assert_equal(@ticket7.id, result[:ticket_ids][0].to_i)
- assert_equal(@ticket6.id, result[:ticket_ids][1].to_i)
- assert_equal(@ticket5.id, result[:ticket_ids][2].to_i)
- assert_equal(@ticket4.id, result[:ticket_ids][3].to_i)
- assert_equal(@ticket3.id, result[:ticket_ids][4].to_i)
- assert_equal(@ticket2.id, result[:ticket_ids][5].to_i)
- assert_equal(@ticket1.id, result[:ticket_ids][6].to_i)
- assert_nil(result[:ticket_ids][7])
-
- result = Report::TicketGenericTime.items(
- range_start: Time.zone.parse('2015-01-01T00:00:00Z'),
- range_end: Time.zone.parse('2015-12-31T23:59:59Z'),
- selector: {
- 'title' => {
- 'operator' => 'contains not',
- 'value' => 'test'
- }
- }, # ticket selector to get only a collection of tickets
- params: { field: 'created_at' },
- )
-
- assert(result)
- assert_nil(result[:ticket_ids][0])
-
- # search for test_category.keyword to find values with :: in query
- result = Report::TicketGenericTime.items(
- range_start: Time.zone.parse('2015-01-01T00:00:00Z'),
- range_end: Time.zone.parse('2015-12-31T23:59:59Z'),
- selector: {
- 'test_category' => {
- 'operator' => 'is',
- 'value' => 'cc::bb'
- },
- }, # ticket selector to get only a collection of tickets
- params: { field: 'created_at' },
- )
-
- assert(result)
- assert_equal(@ticket1.id, result[:ticket_ids][0].to_i)
- assert_nil(result[:ticket_ids][1])
- end
-
-end