2022-01-01 13:38:12 +00:00
# Copyright (C) 2012-2022 Zammad Foundation, https://zammad-foundation.org/
2021-06-01 12:20:20 +00:00
2019-02-13 07:31:36 +00:00
require 'rails_helper'
2021-11-29 14:21:47 +00:00
RSpec . describe SearchIndexBackend do
2019-07-04 13:23:58 +00:00
2021-11-29 14:21:47 +00:00
before do | example |
next if ! example . metadata [ :searchindex ]
configure_elasticsearch ( required : true , rebuild : true )
2019-07-04 13:23:58 +00:00
end
2019-02-13 07:31:36 +00:00
describe '.build_query' do
2019-04-15 01:41:17 +00:00
subject ( :query ) { described_class . build_query ( '' , query_extension : params ) }
2019-02-13 07:31:36 +00:00
let ( :params ) { { 'bool' = > { 'filter' = > { 'term' = > { 'a' = > 'b' } } } } }
it 'coerces :query_extension hash keys to symbols' do
expect ( query . dig ( :query , :bool , :filter , :term , :a ) ) . to eq ( 'b' )
end
end
2021-11-29 14:21:47 +00:00
describe '.search' , searchindex : true do
2019-09-26 11:41:20 +00:00
context 'query finds results' do
let ( :record_type ) { 'Ticket' . freeze }
let ( :record ) { create :ticket }
before do
2021-07-06 17:36:27 +00:00
record . search_index_update_backend
2019-09-26 11:41:20 +00:00
described_class . refresh
end
it 'finds added records' do
result = described_class . search ( record . number , record_type , sort_by : [ 'updated_at' ] , order_by : [ 'desc' ] )
expect ( result ) . to eq ( [ { id : record . id . to_s , type : record_type } ] )
end
end
2019-02-13 07:31:36 +00:00
2021-07-06 17:36:27 +00:00
context 'when search for user firstname + double lastname' do
let ( :record_type ) { 'User' . freeze }
let ( :record ) { create :user , login : 'a' , email : 'a@a.de' , firstname : 'AnFirst' , lastname : 'ASplit Lastname' }
before do
record . search_index_update_backend
described_class . refresh
end
it 'finds user record' do
result = described_class . search ( 'AnFirst ASplit Lastname' , record_type , sort_by : [ 'updated_at' ] , order_by : [ 'desc' ] )
expect ( result ) . to eq ( [ { id : record . id . to_s , type : record_type } ] )
end
end
2019-02-13 07:31:36 +00:00
context 'for query with no results' do
2019-09-26 11:41:20 +00:00
subject ( :search ) { described_class . search ( query , index , limit : 3000 ) }
2019-02-13 07:31:36 +00:00
let ( :query ) { 'preferences.notification_sound.enabled:*' }
context 'on a single index' do
let ( :index ) { 'User' }
2019-07-04 13:23:58 +00:00
it { is_expected . to be_an ( Array ) . and be_empty }
2019-02-13 07:31:36 +00:00
end
context 'on multiple indices' do
let ( :index ) { %w[ User Organization ] }
it { is_expected . to be_an ( Array ) . and not_include ( nil ) . and be_empty }
end
end
2021-07-06 18:40:09 +00:00
context 'search with date that requires time zone conversion' , time_zone : 'Europe/Vilnius' do
let ( :record_type ) { 'Ticket' . freeze }
let ( :record ) { create :ticket }
before do
2021-07-14 14:07:07 +00:00
travel_to ( Time . zone . parse ( '2019-01-02 00:33' ) )
2021-07-06 18:40:09 +00:00
described_class . add ( record_type , record )
described_class . refresh
end
2021-07-14 14:07:07 +00:00
it 'finds record in a given timezone with a range' do
Setting . set ( 'timezone_default' , 'UTC' )
2021-07-06 18:40:09 +00:00
result = described_class . search ( 'created_at: [2019-01-01 TO 2019-01-01]' , record_type )
expect ( result ) . to eq ( [ { id : record . id . to_s , type : record_type } ] )
end
2021-07-14 14:07:07 +00:00
it 'finds record in a far away timezone with a date' do
Setting . set ( 'timezone_default' , 'Europe/Vilnius' )
result = described_class . search ( 'created_at: 2019-01-02' , record_type )
expect ( result ) . to eq ( [ { id : record . id . to_s , type : record_type } ] )
end
it 'finds record in UTC with date' do
Setting . set ( 'timezone_default' , 'UTC' )
result = described_class . search ( 'created_at: 2019-01-01' , record_type )
expect ( result ) . to eq ( [ { id : record . id . to_s , type : record_type } ] )
end
2021-07-06 18:40:09 +00:00
end
2021-07-12 08:18:46 +00:00
context 'does find integer values for ticket data' , db_strategy : :reset do
let ( :record_type ) { 'Ticket' . freeze }
let ( :record ) { create :ticket , inttest : '1021052349' }
before do
create ( :object_manager_attribute_integer , name : 'inttest' , data_option : {
'default' = > 0 ,
'min' = > 0 ,
'max' = > 99_999_999 ,
} )
ObjectManager :: Attribute . migration_execute
record . search_index_update_backend
described_class . refresh
end
it 'finds added records by integer part' do
result = described_class . search ( '102105' , record_type , sort_by : [ 'updated_at' ] , order_by : [ 'desc' ] )
expect ( result ) . to eq ( [ { id : record . id . to_s , type : record_type } ] )
end
it 'finds added records by integer' do
result = described_class . search ( '1021052349' , record_type , sort_by : [ 'updated_at' ] , order_by : [ 'desc' ] )
expect ( result ) . to eq ( [ { id : record . id . to_s , type : record_type } ] )
end
it 'finds added records by quoted integer' do
result = described_class . search ( '"1021052349"' , record_type , sort_by : [ 'updated_at' ] , order_by : [ 'desc' ] )
expect ( result ) . to eq ( [ { id : record . id . to_s , type : record_type } ] )
end
end
2019-02-13 07:31:36 +00:00
end
describe '.append_wildcard_to_simple_query' do
context 'with "simple" queries' do
let ( :queries ) { << ~ QUERIES . lines . map { | x | x . split ( '#' ) [ 0 ] } . map ( & :strip ) }
M
Max
Max . # dot and underscore are acceptable characters in simple queries
A_
A_B
ä ö ü
123
* ax # wildcards are allowed in simple queries
Max *
M * x
M? x
test @example . com
test @example .
test @example
test @
QUERIES
it 'appends a * to the original query' do
2020-11-24 16:20:57 +00:00
expect ( queries . map { | query | described_class . append_wildcard_to_simple_query ( query ) } )
2019-02-13 07:31:36 +00:00
. to eq ( queries . map { | q | " #{ q } * " } )
end
end
context 'with "complex" queries (using search operators)' do
let ( :queries ) { << ~ QUERIES . lines . map { | x | x . split ( '#' ) [ 0 ] } . map ( & :strip ) }
title : " some words with spaces " # exact phrase / without quotation marks " an AND search for the words will be performed (in Zammad 1.5 and lower an OR search will be performed)
title : " some wor* " # exact phrase beginning with "some wor*" will be searched
created_at : [ 2017 - 01 - 01 TO 2017 - 12 - 31 ] # a time range
created_at : > now - 1 h # created within last hour
state : new OR state : open
( state : new OR state : open ) OR priority : " 3 normal "
( state : new OR state : open ) AND customer . lastname :smith
state : ( new OR open ) AND title : ( full text search ) # state: new OR open & title: full OR text OR search
tags : " some tag "
owner . email : " bod@example.com " AND state : ( new OR open OR pending * ) # show all open tickets of a certain agent
state : closed AND _missing_ : tag # all closed objects without tags
article_count : [ 1 TO 5 ] # tickets with 1 to 5 articles
article_count : [ 10 TO * ] # tickets with 10 or more articles
article . from : bob # also article.from can be used
article . body : heat ~ # using the fuzzy operator will also find terms that are similar, in this case also "head"
article . body : / joh?n(ath[oa]n) / # using regular expressions
user : M
user : Max
user : Max .
user : Max *
organization : A_B
organization : A_B *
user : M
user : Max
user : Max .
user : Max *
organization : A_B
organization : A_B *
id : 123
number : 123
id :" 123 "
number : " 123 "
QUERIES
it 'returns the original query verbatim' do
2020-11-24 16:20:57 +00:00
expect ( queries . map { | query | described_class . append_wildcard_to_simple_query ( query ) } )
2019-02-13 07:31:36 +00:00
. to eq ( queries )
end
end
end
2019-07-04 13:23:58 +00:00
2021-11-29 14:21:47 +00:00
describe '.remove' , searchindex : true do
2019-09-26 11:41:20 +00:00
context 'record gets deleted' do
2019-07-04 13:23:58 +00:00
2019-09-26 11:41:20 +00:00
let ( :record_type ) { 'Ticket' . freeze }
let ( :deleted_record ) { create :ticket }
2019-07-04 13:23:58 +00:00
2019-09-26 11:41:20 +00:00
before do
described_class . add ( record_type , deleted_record )
described_class . refresh
end
2019-07-04 13:23:58 +00:00
2019-09-26 11:41:20 +00:00
it 'removes record from search index' do
described_class . remove ( record_type , deleted_record . id )
described_class . refresh
2019-07-04 13:23:58 +00:00
2019-09-26 11:41:20 +00:00
result = described_class . search ( deleted_record . number , record_type , sort_by : [ 'updated_at' ] , order_by : [ 'desc' ] )
2019-07-04 13:23:58 +00:00
expect ( result ) . to eq ( [ ] )
end
2019-09-26 11:41:20 +00:00
context 'other records present' do
let ( :other_record ) { create :ticket }
before do
described_class . add ( record_type , other_record )
described_class . refresh
end
it " doesn't remove other records " do
described_class . remove ( record_type , deleted_record . id )
described_class . refresh
result = described_class . search ( other_record . number , record_type , sort_by : [ 'updated_at' ] , order_by : [ 'desc' ] )
expect ( result ) . to eq ( [ { id : other_record . id . to_s , type : record_type } ] )
end
end
2019-07-04 13:23:58 +00:00
end
end
2019-10-30 07:45:31 +00:00
2021-11-29 14:21:47 +00:00
describe '.selectors' , searchindex : true do
2019-10-30 07:45:31 +00:00
2021-01-27 09:58:35 +00:00
let ( :group1 ) { create :group }
let ( :organization1 ) { create :organization , note : 'hihi' }
let ( :agent1 ) { create :agent , organization : organization1 , groups : [ group1 ] }
let ( :customer1 ) { create :customer , organization : organization1 , firstname : 'special-first-name' }
let ( :ticket1 ) do
ticket = create :ticket , title : 'some-title1' , state_id : 1 , created_by : agent1
ticket . tag_add ( 't1' , 1 )
ticket
end
let ( :ticket2 ) do
ticket = create :ticket , title : 'some_title2' , state_id : 4
ticket . tag_add ( 't2' , 1 )
ticket
end
let ( :ticket3 ) do
ticket = create :ticket , title : 'some::title3' , state_id : 1
ticket . tag_add ( 't1' , 1 )
ticket . tag_add ( 't2' , 1 )
ticket
end
2019-10-30 07:45:31 +00:00
let ( :ticket4 ) { create :ticket , title : 'phrase some-title4' , state_id : 1 }
let ( :ticket5 ) { create :ticket , title : 'phrase some_title5' , state_id : 1 }
let ( :ticket6 ) { create :ticket , title : 'phrase some::title6' , state_id : 1 }
let ( :ticket7 ) { create :ticket , title : 'some title7' , state_id : 1 }
2021-01-27 09:58:35 +00:00
let ( :ticket8 ) { create :ticket , title : 'sometitle' , group : group1 , state_id : 1 , owner : agent1 , customer : customer1 , organization : organization1 }
let ( :article8 ) { create :ticket_article , ticket : ticket8 , subject : 'lorem ipsum' }
2019-10-30 07:45:31 +00:00
before do
Ticket . destroy_all # needed to remove not created tickets
2021-04-29 15:34:27 +00:00
travel ( - 1 . hour )
2021-03-16 08:59:32 +00:00
create ( :mention , mentionable : ticket1 , user : agent1 )
2020-12-10 15:14:14 +00:00
ticket1 . search_index_update_backend
2021-04-29 15:34:27 +00:00
travel 1 . hour
2020-12-10 15:14:14 +00:00
ticket2 . search_index_update_backend
2019-10-30 07:45:31 +00:00
travel 1 . second
2020-12-10 15:14:14 +00:00
ticket3 . search_index_update_backend
2019-10-30 07:45:31 +00:00
travel 1 . second
2020-12-10 15:14:14 +00:00
ticket4 . search_index_update_backend
2019-10-30 07:45:31 +00:00
travel 1 . second
2020-12-10 15:14:14 +00:00
ticket5 . search_index_update_backend
2019-10-30 07:45:31 +00:00
travel 1 . second
2020-12-10 15:14:14 +00:00
ticket6 . search_index_update_backend
2019-10-30 07:45:31 +00:00
travel 1 . second
2020-12-10 15:14:14 +00:00
ticket7 . search_index_update_backend
2021-04-29 15:34:27 +00:00
travel 1 . hour
2021-01-27 09:58:35 +00:00
article8 . ticket . search_index_update_backend
2019-10-30 07:45:31 +00:00
described_class . refresh
end
context 'query with contains' do
2021-04-29 15:34:27 +00:00
it 'finds records with till (relative)' do
result = described_class . selectors ( 'Ticket' ,
{ 'ticket.created_at' = > { 'operator' = > 'till (relative)' , 'value' = > '30' , 'range' = > 'minute' } } ,
{ } ,
{
field : 'created_at' , # sort to verify result
} )
expect ( result ) . to eq ( { count : 7 , ticket_ids : [ ticket7 . id . to_s , ticket6 . id . to_s , ticket5 . id . to_s , ticket4 . id . to_s , ticket3 . id . to_s , ticket2 . id . to_s , ticket1 . id . to_s ] } )
end
it 'finds records with from (relative)' do
result = described_class . selectors ( 'Ticket' ,
{ 'ticket.created_at' = > { 'operator' = > 'from (relative)' , 'value' = > '30' , 'range' = > 'minute' } } ,
{ } ,
{
field : 'created_at' , # sort to verify result
} )
expect ( result ) . to eq ( { count : 7 , ticket_ids : [ ticket8 . id . to_s , ticket7 . id . to_s , ticket6 . id . to_s , ticket5 . id . to_s , ticket4 . id . to_s , ticket3 . id . to_s , ticket2 . id . to_s ] } )
end
it 'finds records with till (relative) including +1 hour ticket' do
result = described_class . selectors ( 'Ticket' ,
{ 'ticket.created_at' = > { 'operator' = > 'till (relative)' , 'value' = > '120' , 'range' = > 'minute' } } ,
{ } ,
{
field : 'created_at' , # sort to verify result
} )
expect ( result ) . to eq ( { count : 8 , ticket_ids : [ ticket8 . id . to_s , ticket7 . id . to_s , ticket6 . id . to_s , ticket5 . id . to_s , ticket4 . id . to_s , ticket3 . id . to_s , ticket2 . id . to_s , ticket1 . id . to_s ] } )
end
it 'finds records with from (relative) including -1 hour ticket' do
result = described_class . selectors ( 'Ticket' ,
{ 'ticket.created_at' = > { 'operator' = > 'from (relative)' , 'value' = > '120' , 'range' = > 'minute' } } ,
{ } ,
{
field : 'created_at' , # sort to verify result
} )
expect ( result ) . to eq ( { count : 8 , ticket_ids : [ ticket8 . id . to_s , ticket7 . id . to_s , ticket6 . id . to_s , ticket5 . id . to_s , ticket4 . id . to_s , ticket3 . id . to_s , ticket2 . id . to_s , ticket1 . id . to_s ] } )
end
2021-01-27 09:58:35 +00:00
it 'finds records with tags which contains all' do
result = described_class . selectors ( 'Ticket' ,
{ 'ticket.tags' = > { 'operator' = > 'contains all' , 'value' = > 't1, t2' } } ,
{ } ,
{
field : 'created_at' , # sort to verify result
} )
expect ( result ) . to eq ( { count : 1 , ticket_ids : [ ticket3 . id . to_s ] } )
end
it 'finds records with tags which contains one' do
result = described_class . selectors ( 'Ticket' ,
{ 'ticket.tags' = > { 'operator' = > 'contains one' , 'value' = > 't1, t2' } } ,
{ } ,
{
field : 'created_at' , # sort to verify result
} )
expect ( result ) . to eq ( { count : 3 , ticket_ids : [ ticket3 . id . to_s , ticket2 . id . to_s , ticket1 . id . to_s ] } )
end
it 'finds records with tags which contains all not' do
result = described_class . selectors ( 'Ticket' ,
{ 'ticket.tags' = > { 'operator' = > 'contains all not' , 'value' = > 't2' } } ,
{ } ,
{
field : 'created_at' , # sort to verify result
} )
expect ( result ) . to eq ( { count : 6 , ticket_ids : [ ticket8 . id . to_s , ticket7 . id . to_s , ticket6 . id . to_s , ticket5 . id . to_s , ticket4 . id . to_s , ticket1 . id . to_s ] } )
end
it 'finds records with tags which contains one not' do
result = described_class . selectors ( 'Ticket' ,
{ 'ticket.tags' = > { 'operator' = > 'contains one not' , 'value' = > 't1' } } ,
{ } ,
{
field : 'created_at' , # sort to verify result
} )
expect ( result ) . to eq ( { count : 6 , ticket_ids : [ ticket8 . id . to_s , ticket7 . id . to_s , ticket6 . id . to_s , ticket5 . id . to_s , ticket4 . id . to_s , ticket2 . id . to_s ] } )
end
it 'finds records with organization note' do
result = described_class . selectors ( 'Ticket' ,
{
'organization.note' = > {
'operator' = > 'contains' ,
'value' = > 'hihi' ,
} ,
} ,
{ } ,
{
field : 'created_at' , # sort to verify result
} )
expect ( result ) . to eq ( { count : 1 , ticket_ids : [ ticket8 . id . to_s ] } )
end
it 'finds records with customer firstname' do
result = described_class . selectors ( 'Ticket' ,
{
'customer.firstname' = > {
'operator' = > 'contains' ,
'value' = > 'special' ,
} ,
} ,
{ } ,
{
field : 'created_at' , # sort to verify result
} )
expect ( result ) . to eq ( { count : 1 , ticket_ids : [ ticket8 . id . to_s ] } )
end
it 'finds records with article subject' do
result = described_class . selectors ( 'Ticket' ,
{
'article.subject' = > {
'operator' = > 'contains' ,
'value' = > 'ipsum' ,
} ,
} ,
{ } ,
{
field : 'created_at' , # sort to verify result
} )
expect ( result ) . to eq ( { count : 1 , ticket_ids : [ ticket8 . id . to_s ] } )
end
2020-10-07 14:53:52 +00:00
it 'finds records with pre_condition not_set' do
result = described_class . selectors ( 'Ticket' ,
{
'created_by_id' = > {
'pre_condition' = > 'not_set' ,
'operator' = > 'is' ,
} ,
} ,
{ } ,
{
field : 'created_at' , # sort to verify result
} )
expect ( result ) . to eq ( { count : 7 , ticket_ids : [ ticket8 . id . to_s , ticket7 . id . to_s , ticket6 . id . to_s , ticket5 . id . to_s , ticket4 . id . to_s , ticket3 . id . to_s , ticket2 . id . to_s ] } )
end
it 'finds records with pre_condition current_user.id' do
result = described_class . selectors ( 'Ticket' ,
{
'owner_id' = > {
'pre_condition' = > 'current_user.id' ,
'operator' = > 'is' ,
} ,
} ,
{ current_user : agent1 } ,
{
field : 'created_at' , # sort to verify result
} )
expect ( result ) . to eq ( { count : 1 , ticket_ids : [ ticket8 . id . to_s ] } )
end
it 'finds records with pre_condition current_user.organization_id' do
result = described_class . selectors ( 'Ticket' ,
{
'organization_id' = > {
'pre_condition' = > 'current_user.organization_id' ,
'operator' = > 'is' ,
} ,
} ,
{ current_user : agent1 } ,
{
field : 'created_at' , # sort to verify result
} )
expect ( result ) . to eq ( { count : 1 , ticket_ids : [ ticket8 . id . to_s ] } )
end
2019-10-30 07:45:31 +00:00
it 'finds records with containing phrase' do
result = described_class . selectors ( 'Ticket' ,
{
'title' = > {
'operator' = > 'contains' ,
'value' = > 'phrase' ,
} ,
} ,
{ } ,
{
field : 'created_at' , # sort to verify result
} )
expect ( result ) . to eq ( { count : 3 , ticket_ids : [ ticket6 . id . to_s , ticket5 . id . to_s , ticket4 . id . to_s ] } )
end
it 'finds records with containing some title7' do
result = described_class . selectors ( 'Ticket' ,
'title' = > {
'operator' = > 'contains' ,
'value' = > 'some title7' ,
} )
expect ( result ) . to eq ( { count : 1 , ticket_ids : [ ticket7 . id . to_s ] } )
end
it 'finds records with containing -' do
result = described_class . selectors ( 'Ticket' ,
'title' = > {
'operator' = > 'contains' ,
'value' = > 'some-title1' ,
} )
expect ( result ) . to eq ( { count : 1 , ticket_ids : [ ticket1 . id . to_s ] } )
end
it 'finds records with containing _' do
result = described_class . selectors ( 'Ticket' ,
'title' = > {
'operator' = > 'contains' ,
'value' = > 'some_title2' ,
} )
expect ( result ) . to eq ( { count : 1 , ticket_ids : [ ticket2 . id . to_s ] } )
end
it 'finds records with containing ::' do
result = described_class . selectors ( 'Ticket' ,
'title' = > {
'operator' = > 'contains' ,
'value' = > 'some::title3' ,
} )
expect ( result ) . to eq ( { count : 1 , ticket_ids : [ ticket3 . id . to_s ] } )
end
it 'finds records with containing 4' do
result = described_class . selectors ( 'Ticket' ,
'state_id' = > {
'operator' = > 'contains' ,
'value' = > 4 ,
} )
expect ( result ) . to eq ( { count : 1 , ticket_ids : [ ticket2 . id . to_s ] } )
end
it 'finds records with containing "4"' do
result = described_class . selectors ( 'Ticket' ,
'state_id' = > {
'operator' = > 'contains' ,
'value' = > '4' ,
} )
expect ( result ) . to eq ( { count : 1 , ticket_ids : [ ticket2 . id . to_s ] } )
end
end
context 'query with contains not' do
it 'finds records with containing not phrase' do
result = described_class . selectors ( 'Ticket' ,
{
'title' = > {
'operator' = > 'contains not' ,
'value' = > 'phrase' ,
} ,
} ,
{ } ,
{
field : 'created_at' , # sort to verify result
} )
2019-11-19 08:03:46 +00:00
expect ( result ) . to eq ( { count : 5 , ticket_ids : [ ticket8 . id . to_s , ticket7 . id . to_s , ticket3 . id . to_s , ticket2 . id . to_s , ticket1 . id . to_s ] } )
2019-10-30 07:45:31 +00:00
end
it 'finds records with containing not some title7' do
result = described_class . selectors ( 'Ticket' ,
'title' = > {
'operator' = > 'contains not' ,
'value' = > 'some title7' ,
} )
2019-11-19 08:03:46 +00:00
expect ( result ) . to eq ( { count : 7 , ticket_ids : [ ticket8 . id . to_s , ticket6 . id . to_s , ticket5 . id . to_s , ticket4 . id . to_s , ticket3 . id . to_s , ticket2 . id . to_s , ticket1 . id . to_s ] } )
2019-10-30 07:45:31 +00:00
end
it 'finds records with containing not -' do
result = described_class . selectors ( 'Ticket' ,
'title' = > {
'operator' = > 'contains not' ,
'value' = > 'some-title1' ,
} )
2019-11-19 08:03:46 +00:00
expect ( result ) . to eq ( { count : 7 , ticket_ids : [ ticket8 . id . to_s , ticket7 . id . to_s , ticket6 . id . to_s , ticket5 . id . to_s , ticket4 . id . to_s , ticket3 . id . to_s , ticket2 . id . to_s ] } )
2019-10-30 07:45:31 +00:00
end
it 'finds records with containing not _' do
result = described_class . selectors ( 'Ticket' ,
'title' = > {
'operator' = > 'contains not' ,
'value' = > 'some_title2' ,
} )
2019-11-19 08:03:46 +00:00
expect ( result ) . to eq ( { count : 7 , ticket_ids : [ ticket8 . id . to_s , ticket7 . id . to_s , ticket6 . id . to_s , ticket5 . id . to_s , ticket4 . id . to_s , ticket3 . id . to_s , ticket1 . id . to_s ] } )
2019-10-30 07:45:31 +00:00
end
it 'finds records with containing not ::' do
result = described_class . selectors ( 'Ticket' ,
'title' = > {
'operator' = > 'contains not' ,
'value' = > 'some::title3' ,
} )
2019-11-19 08:03:46 +00:00
expect ( result ) . to eq ( { count : 7 , ticket_ids : [ ticket8 . id . to_s , ticket7 . id . to_s , ticket6 . id . to_s , ticket5 . id . to_s , ticket4 . id . to_s , ticket2 . id . to_s , ticket1 . id . to_s ] } )
2019-10-30 07:45:31 +00:00
end
it 'finds records with containing not 4' do
result = described_class . selectors ( 'Ticket' ,
'state_id' = > {
'operator' = > 'contains not' ,
'value' = > 4 ,
} )
2019-11-19 08:03:46 +00:00
expect ( result ) . to eq ( { count : 7 , ticket_ids : [ ticket8 . id . to_s , ticket7 . id . to_s , ticket6 . id . to_s , ticket5 . id . to_s , ticket4 . id . to_s , ticket3 . id . to_s , ticket1 . id . to_s ] } )
2019-10-30 07:45:31 +00:00
end
it 'finds records with containing not "4"' do
result = described_class . selectors ( 'Ticket' ,
'state_id' = > {
'operator' = > 'contains not' ,
'value' = > '4' ,
} )
2019-11-19 08:03:46 +00:00
expect ( result ) . to eq ( { count : 7 , ticket_ids : [ ticket8 . id . to_s , ticket7 . id . to_s , ticket6 . id . to_s , ticket5 . id . to_s , ticket4 . id . to_s , ticket3 . id . to_s , ticket1 . id . to_s ] } )
2019-10-30 07:45:31 +00:00
end
end
context 'query with is' do
it 'finds records with is phrase' do
result = described_class . selectors ( 'Ticket' ,
'title' = > {
'operator' = > 'is' ,
'value' = > 'phrase' ,
} )
expect ( result ) . to eq ( { count : 0 , ticket_ids : [ ] } )
end
it 'finds records with is some title7' do
result = described_class . selectors ( 'Ticket' ,
'title' = > {
'operator' = > 'is' ,
'value' = > 'some title7' ,
} )
expect ( result ) . to eq ( { count : 1 , ticket_ids : [ ticket7 . id . to_s ] } )
end
it 'finds records with is -' do
result = described_class . selectors ( 'Ticket' ,
'title' = > {
'operator' = > 'is' ,
'value' = > 'some-title1' ,
} )
expect ( result ) . to eq ( { count : 1 , ticket_ids : [ ticket1 . id . to_s ] } )
end
it 'finds records with is _' do
result = described_class . selectors ( 'Ticket' ,
'title' = > {
'operator' = > 'is' ,
'value' = > 'some_title2' ,
} )
expect ( result ) . to eq ( { count : 1 , ticket_ids : [ ticket2 . id . to_s ] } )
end
it 'finds records with is ::' do
result = described_class . selectors ( 'Ticket' ,
'title' = > {
'operator' = > 'is' ,
'value' = > 'some::title3' ,
} )
expect ( result ) . to eq ( { count : 1 , ticket_ids : [ ticket3 . id . to_s ] } )
end
it 'finds records with is 4' do
result = described_class . selectors ( 'Ticket' ,
'state_id' = > {
'operator' = > 'is' ,
'value' = > 4 ,
} )
expect ( result ) . to eq ( { count : 1 , ticket_ids : [ ticket2 . id . to_s ] } )
end
it 'finds records with is "4"' do
result = described_class . selectors ( 'Ticket' ,
'state_id' = > {
'operator' = > 'is' ,
'value' = > '4' ,
} )
expect ( result ) . to eq ( { count : 1 , ticket_ids : [ ticket2 . id . to_s ] } )
end
end
context 'query with is not' do
it 'finds records with is not phrase' do
result = described_class . selectors ( 'Ticket' ,
'title' = > {
'operator' = > 'is not' ,
'value' = > 'phrase' ,
} )
2019-11-19 08:03:46 +00:00
expect ( result ) . to eq ( { count : 8 , ticket_ids : [ ticket8 . id . to_s , ticket7 . id . to_s , ticket6 . id . to_s , ticket5 . id . to_s , ticket4 . id . to_s , ticket3 . id . to_s , ticket2 . id . to_s , ticket1 . id . to_s ] } )
2019-10-30 07:45:31 +00:00
end
it 'finds records with is not some title7' do
result = described_class . selectors ( 'Ticket' ,
'title' = > {
'operator' = > 'is not' ,
'value' = > 'some title7' ,
} )
2019-11-19 08:03:46 +00:00
expect ( result ) . to eq ( { count : 7 , ticket_ids : [ ticket8 . id . to_s , ticket6 . id . to_s , ticket5 . id . to_s , ticket4 . id . to_s , ticket3 . id . to_s , ticket2 . id . to_s , ticket1 . id . to_s ] } )
2019-10-30 07:45:31 +00:00
end
it 'finds records with is not -' do
result = described_class . selectors ( 'Ticket' ,
'title' = > {
'operator' = > 'is not' ,
'value' = > 'some-title1' ,
} )
2019-11-19 08:03:46 +00:00
expect ( result ) . to eq ( { count : 7 , ticket_ids : [ ticket8 . id . to_s , ticket7 . id . to_s , ticket6 . id . to_s , ticket5 . id . to_s , ticket4 . id . to_s , ticket3 . id . to_s , ticket2 . id . to_s ] } )
2019-10-30 07:45:31 +00:00
end
it 'finds records with is not _' do
result = described_class . selectors ( 'Ticket' ,
'title' = > {
'operator' = > 'is not' ,
'value' = > 'some_title2' ,
} )
2019-11-19 08:03:46 +00:00
expect ( result ) . to eq ( { count : 7 , ticket_ids : [ ticket8 . id . to_s , ticket7 . id . to_s , ticket6 . id . to_s , ticket5 . id . to_s , ticket4 . id . to_s , ticket3 . id . to_s , ticket1 . id . to_s ] } )
2019-10-30 07:45:31 +00:00
end
it 'finds records with is not ::' do
result = described_class . selectors ( 'Ticket' ,
'title' = > {
'operator' = > 'is not' ,
'value' = > 'some::title3' ,
} )
2019-11-19 08:03:46 +00:00
expect ( result ) . to eq ( { count : 7 , ticket_ids : [ ticket8 . id . to_s , ticket7 . id . to_s , ticket6 . id . to_s , ticket5 . id . to_s , ticket4 . id . to_s , ticket2 . id . to_s , ticket1 . id . to_s ] } )
2019-10-30 07:45:31 +00:00
end
it 'finds records with is not 4' do
result = described_class . selectors ( 'Ticket' ,
'state_id' = > {
'operator' = > 'is not' ,
'value' = > 4 ,
} )
2019-11-19 08:03:46 +00:00
expect ( result ) . to eq ( { count : 7 , ticket_ids : [ ticket8 . id . to_s , ticket7 . id . to_s , ticket6 . id . to_s , ticket5 . id . to_s , ticket4 . id . to_s , ticket3 . id . to_s , ticket1 . id . to_s ] } )
2019-10-30 07:45:31 +00:00
end
it 'finds records with is not "4"' do
result = described_class . selectors ( 'Ticket' ,
'state_id' = > {
'operator' = > 'is not' ,
'value' = > '4' ,
} )
2019-11-19 08:03:46 +00:00
expect ( result ) . to eq ( { count : 7 , ticket_ids : [ ticket8 . id . to_s , ticket7 . id . to_s , ticket6 . id . to_s , ticket5 . id . to_s , ticket4 . id . to_s , ticket3 . id . to_s , ticket1 . id . to_s ] } )
2019-10-30 07:45:31 +00:00
end
2019-11-19 08:03:46 +00:00
it 'finds records with is not state_id ["4"] and title ["sometitle"]' do
result = described_class . selectors ( 'Ticket' ,
'state_id' = > {
'operator' = > 'is not' ,
'value' = > [ '4' ] ,
} ,
'title' = > {
'operator' = > 'is' ,
'value' = > [ 'sometitle' ] ,
} )
expect ( result ) . to eq ( { count : 1 , ticket_ids : [ ticket8 . id . to_s ] } )
end
2019-10-30 07:45:31 +00:00
end
2021-03-16 08:59:32 +00:00
context 'mentions' do
it 'finds records with pre_condition is not_set' do
result = described_class . selectors ( 'Ticket' ,
{
'ticket.mention_user_ids' = > {
'pre_condition' = > 'not_set' ,
'operator' = > 'is' ,
} ,
} ,
{ current_user : agent1 } ,
{
field : 'created_at' , # sort to verify result
} )
expect ( result ) . to eq ( { count : 7 , ticket_ids : [ ticket8 . id . to_s , ticket7 . id . to_s , ticket6 . id . to_s , ticket5 . id . to_s , ticket4 . id . to_s , ticket3 . id . to_s , ticket2 . id . to_s ] } )
end
it 'finds records with pre_condition is not not_set' do
result = described_class . selectors ( 'Ticket' ,
{
'ticket.mention_user_ids' = > {
'pre_condition' = > 'not_set' ,
'operator' = > 'is not' ,
} ,
} ,
{ current_user : agent1 } ,
{
field : 'created_at' , # sort to verify result
} )
expect ( result ) . to eq ( { count : 1 , ticket_ids : [ ticket1 . id . to_s ] } )
end
it 'finds records with pre_condition is current_user.id' do
result = described_class . selectors ( 'Ticket' ,
{
'ticket.mention_user_ids' = > {
'pre_condition' = > 'current_user.id' ,
'operator' = > 'is' ,
} ,
} ,
{ current_user : agent1 } ,
{
field : 'created_at' , # sort to verify result
} )
expect ( result ) . to eq ( { count : 1 , ticket_ids : [ ticket1 . id . to_s ] } )
end
it 'finds records with pre_condition is not current_user.id' do
result = described_class . selectors ( 'Ticket' ,
{
'ticket.mention_user_ids' = > {
'pre_condition' = > 'current_user.id' ,
'operator' = > 'is not' ,
} ,
} ,
{ current_user : agent1 } ,
{
field : 'created_at' , # sort to verify result
} )
expect ( result ) . to eq ( { count : 7 , ticket_ids : [ ticket8 . id . to_s , ticket7 . id . to_s , ticket6 . id . to_s , ticket5 . id . to_s , ticket4 . id . to_s , ticket3 . id . to_s , ticket2 . id . to_s ] } )
end
it 'finds records with pre_condition is specific' do
result = described_class . selectors ( 'Ticket' ,
{
'ticket.mention_user_ids' = > {
'pre_condition' = > 'specific' ,
'operator' = > 'is' ,
'value' = > agent1 . id ,
} ,
} ,
{ } ,
{
field : 'created_at' , # sort to verify result
} )
expect ( result ) . to eq ( { count : 1 , ticket_ids : [ ticket1 . id . to_s ] } )
end
it 'finds records with pre_condition is not specific' do
result = described_class . selectors ( 'Ticket' ,
{
'ticket.mention_user_ids' = > {
'pre_condition' = > 'specific' ,
'operator' = > 'is not' ,
'value' = > agent1 . id ,
} ,
} ,
{ } ,
{
field : 'created_at' , # sort to verify result
} )
expect ( result ) . to eq ( { count : 7 , ticket_ids : [ ticket8 . id . to_s , ticket7 . id . to_s , ticket6 . id . to_s , ticket5 . id . to_s , ticket4 . id . to_s , ticket3 . id . to_s , ticket2 . id . to_s ] } )
end
end
2019-10-30 07:45:31 +00:00
end
2021-11-29 14:21:47 +00:00
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
2019-02-13 07:31:36 +00:00
end