2023-09-08 10:51:59 -05:00
import { e2e } from '../utils' ;
2022-06-29 04:04:27 -05:00
2022-08-11 10:57:10 -05:00
const MISSING_LABEL_FILTER_ERROR_MESSAGE = 'Select at least 1 label filter (label and value)' ;
2022-06-29 04:04:27 -05:00
const dataSourceName = 'LokiBuilder' ;
const addDataSource = ( ) = > {
e2e . flows . addDataSource ( {
type : 'Loki' ,
2023-09-05 01:59:13 -05:00
expectedAlertMessage : 'Unable to connect with Loki. Please check the server logs for more details.' ,
2022-06-29 04:04:27 -05:00
name : dataSourceName ,
form : ( ) = > {
2023-09-11 05:20:54 -05:00
cy . get ( '#connection-url' ) . type ( 'http://loki-url:3100' ) ;
2022-06-29 04:04:27 -05:00
} ,
} ) ;
} ;
2023-08-03 09:27:23 -05:00
const finalQuery = 'rate({instance=~"instance1|instance2"} | logfmt | __error__=`` [$__auto]' ;
2022-09-30 08:27:48 -05:00
2022-06-29 04:04:27 -05:00
describe ( 'Loki query builder' , ( ) = > {
beforeEach ( ( ) = > {
2023-09-27 05:33:00 -05:00
e2e . flows . login ( Cypress . env ( 'USERNAME' ) , Cypress . env ( 'PASSWORD' ) ) ;
cy . request ( {
url : ` ${ Cypress . env ( 'BASE_URL' ) } /api/datasources/name/ ${ dataSourceName } ` ,
failOnStatusCode : false ,
} ) . then ( ( response ) = > {
if ( response . isOkStatusCode ) {
return ;
2023-09-11 05:20:54 -05:00
}
2023-09-27 05:33:00 -05:00
addDataSource ( ) ;
} ) ;
2022-06-29 04:04:27 -05:00
} ) ;
it ( 'should be able to use all modes' , ( ) = > {
2023-09-11 05:20:54 -05:00
cy . intercept ( /labels\?/ , ( req ) = > {
req . reply ( { status : 'success' , data : [ 'instance' , 'job' , 'source' ] } ) ;
} ) . as ( 'labelsRequest' ) ;
2022-06-29 04:04:27 -05:00
2023-09-11 05:20:54 -05:00
cy . intercept ( /series?/ , ( req ) = > {
2022-06-29 04:04:27 -05:00
req . reply ( { status : 'success' , data : [ { instance : 'instance1' } ] } ) ;
} ) ;
2023-09-11 05:20:54 -05:00
cy . intercept ( /values/ , ( req ) = > {
req . reply ( { status : 'success' , data : [ 'instance1' , 'instance2' ] } ) ;
} ) . as ( 'valuesRequest' ) ;
2023-06-02 05:35:11 -05:00
2024-02-09 12:48:10 -06:00
cy . intercept ( /index\/stats/ , ( req ) = > {
req . reply ( { streams : 2 , chunks : 2660 , bytes : 2721792 , entries : 14408 } ) ;
} ) ;
2022-06-29 04:04:27 -05:00
// Go to Explore and choose Loki data source
e2e . pages . Explore . visit ( ) ;
e2e . components . DataSourcePicker . container ( ) . should ( 'be.visible' ) . click ( ) ;
2023-09-11 05:20:54 -05:00
cy . contains ( dataSourceName ) . scrollIntoView ( ) . should ( 'be.visible' ) . click ( ) ;
2022-06-29 04:04:27 -05:00
// Start in builder mode, click and choose query pattern
2022-09-26 07:03:13 -05:00
e2e . components . QueryBuilder . queryPatterns ( ) . click ( ) ;
2023-09-11 05:20:54 -05:00
cy . contains ( 'Log query starters' ) . click ( ) ;
cy . contains ( 'Use this query' ) . click ( ) ;
cy . contains ( 'No pipeline errors' ) . should ( 'be.visible' ) ;
cy . contains ( 'Logfmt' ) . should ( 'be.visible' ) ;
cy . contains ( '{} | logfmt | __error__=``' ) . should ( 'be.visible' ) ;
2022-06-29 04:04:27 -05:00
// Add operation
2023-09-11 05:20:54 -05:00
cy . contains ( 'Operations' ) . should ( 'be.visible' ) . click ( ) ;
cy . contains ( 'Range functions' ) . should ( 'be.visible' ) . click ( ) ;
cy . contains ( 'Rate' ) . should ( 'be.visible' ) . click ( ) ;
cy . contains ( 'rate({} | logfmt | __error__=`` [$__auto]' ) . should ( 'be.visible' ) ;
2022-06-29 04:04:27 -05:00
// Check for expected error
2023-09-11 05:20:54 -05:00
cy . contains ( MISSING_LABEL_FILTER_ERROR_MESSAGE ) . should ( 'be.visible' ) ;
2022-06-29 04:04:27 -05:00
// Add labels to remove error
2023-06-02 05:35:11 -05:00
e2e . components . QueryBuilder . labelSelect ( ) . should ( 'be.visible' ) . click ( ) ;
// wait until labels are loaded and set on the component before starting to type
2024-02-09 12:48:10 -06:00
e2e . components . QueryBuilder . labelSelect ( ) . children ( 'div' ) . children ( 'input' ) . type ( 'i' ) ;
2023-09-11 05:20:54 -05:00
cy . wait ( '@labelsRequest' ) ;
2024-02-09 12:48:10 -06:00
e2e . components . QueryBuilder . labelSelect ( ) . children ( 'div' ) . children ( 'input' ) . type ( 'nstance{enter}' ) ;
2023-12-26 13:43:06 -06:00
e2e . components . QueryBuilder . matchOperatorSelect ( )
. should ( 'be.visible' )
2024-02-09 12:48:10 -06:00
. click ( { force : true } )
2023-12-26 13:43:06 -06:00
. children ( 'div' )
. children ( 'input' )
. type ( '=~{enter}' , { force : true } ) ;
2023-06-02 05:35:11 -05:00
e2e . components . QueryBuilder . valueSelect ( ) . should ( 'be.visible' ) . click ( ) ;
2024-02-09 12:48:10 -06:00
e2e . components . QueryBuilder . valueSelect ( ) . children ( 'div' ) . children ( 'input' ) . type ( 'instance1{enter}' ) ;
2023-09-11 05:20:54 -05:00
cy . wait ( '@valuesRequest' ) ;
2024-02-09 12:48:10 -06:00
e2e . components . QueryBuilder . valueSelect ( ) . children ( 'div' ) . children ( 'input' ) . type ( 'instance2{enter}' ) ;
2023-09-11 05:20:54 -05:00
cy . contains ( MISSING_LABEL_FILTER_ERROR_MESSAGE ) . should ( 'not.exist' ) ;
cy . contains ( finalQuery ) . should ( 'be.visible' ) ;
2022-06-29 04:04:27 -05:00
2022-09-30 08:27:48 -05:00
// Change to code editor
2023-11-27 06:54:07 -06:00
e2e . components . RadioButton . container ( ) . filter ( ':contains("Code")' ) . click ( ) ;
2023-09-11 05:20:54 -05:00
// We need to test this manually because the final query is split into separate DOM elements using cy.contains(finalQuery).should('be.visible'); does not detect the query.
cy . contains ( 'rate' ) . should ( 'be.visible' ) ;
cy . contains ( 'instance1|instance2' ) . should ( 'be.visible' ) ;
cy . contains ( 'logfmt' ) . should ( 'be.visible' ) ;
cy . contains ( '__error__' ) . should ( 'be.visible' ) ;
cy . contains ( '$__auto' ) . should ( 'be.visible' ) ;
2022-09-30 08:27:48 -05:00
// Checks the explain mode toggle
2023-09-11 05:20:54 -05:00
cy . contains ( 'label' , 'Explain' ) . click ( ) ;
cy . contains ( 'Fetch all log lines matching label filters.' ) . should ( 'be.visible' ) ;
2022-06-29 04:04:27 -05:00
} ) ;
} ) ;