@@ -11,7 +11,7 @@ import com.dtolabs.rundeck.core.execution.workflow.DataOutput
1111class DataKeyFilterMultiLinesSpec extends Specification {
1212
1313 @Unroll
14- def " multiline-filter-ok" () {
14+ def " multiline-filter-ok: #testName " () {
1515 given :
1616 def plugin = new DataKeyFilterMultiLines ()
1717 plugin. regex = regex
@@ -48,7 +48,7 @@ class DataKeyFilterMultiLinesSpec extends Specification {
4848
4949
5050 where :
51- dolog | name | regex | lines | expect
51+ dolog | name | regex | lines | expect | testName
5252 true | null | DataKeyFilterMultiLines . PATTERN | [' some_list = first_element' ,
5353 ' second_element' ,
5454 ' third_element' ,
@@ -58,7 +58,7 @@ class DataKeyFilterMultiLinesSpec extends Specification {
5858 ' second_element\n ' +
5959 ' third_element\n ' +
6060 ' fourth_element\n '
61- ]
61+ ] | " default key=value pattern "
6262 true | " log" | " ^\\ s*User Comments:\\ s*(.*)" | [' User Comments: This is a' ,
6363 ' test' ,
6464 ' message' ,
@@ -67,15 +67,15 @@ class DataKeyFilterMultiLinesSpec extends Specification {
6767 [log : ' This is a\n ' +
6868 ' test\n ' +
6969 ' message\n ' +
70- ' done\n ' ]
70+ ' done\n ' ] | " user comments with named capture "
7171
7272
7373
7474
7575 }
7676
7777 @Unroll
78- def " multiline-filter-nok" () {
78+ def " multiline-filter-nok: #testName " () {
7979 given :
8080 def plugin = new DataKeyFilterMultiLines ()
8181 plugin. regex = regex
@@ -113,16 +113,16 @@ class DataKeyFilterMultiLinesSpec extends Specification {
113113
114114 // case when the name is not set and the pattern doesn't capture a key
115115 where :
116- dolog | name | regex | lines | expect
116+ dolog | name | regex | lines | expect | testName
117117 true | null | " ^\\ s*User Comments:\\ s*(.*)" | [' User Comments: This is a' ,
118118 ' test' ,
119119 ' message' ,
120120 ' ' ,
121- ' done' ] | null
121+ ' done' ] | null | " single capture group without name parameter "
122122 }
123123
124124 @Unroll
125- def " multiline-filter-multiple-key-value-pairs" () {
125+ def " multiline-filter-multiple-key-value-pairs: #testName " () {
126126 given :
127127 def plugin = new DataKeyFilterMultiLines ()
128128 plugin. regex = regex
@@ -160,30 +160,119 @@ class DataKeyFilterMultiLinesSpec extends Specification {
160160
161161
162162 where :
163- dolog | name | regex | lines | expect
163+ dolog | name | regex | lines | expect | testName
164164 true | null | " (\\ w+)\\ s(\\ d+)" | [' hello 1' ,
165165 ' world 2' ,
166166 ' test 456' ,
167167 ' ' ,
168- ' done' ] | [test : " 456" , hello : " 1" , world : " 2" ]
168+ ' done' ] | [test : " 456" , hello : " 1" , world : " 2" ] | " basic two-group capture "
169169
170170
171171 true | " any_name" | " (\\ w+\\ s\\ d+)" | [' hello 1' ,
172172 ' world 2' ,
173173 ' test 456' ,
174174 ' ' ,
175- ' done' ] | [" any_name" : " hello 1\n world 2\n test 456" ]
175+ ' done' ] | [" any_name" : " hello 1\n world 2\n test 456" ] | " single group with name parameter "
176176
177177 true | null | " (\\ w+\\ s\\ d+)" | [' hello 1' ,
178178 ' world 2' ,
179179 ' test 456' ,
180180 ' ' ,
181- ' done' ] | null
181+ ' done' ] | null | " single group without name parameter "
182182
183183 // Test AWS SSM behavior: multiple lines arriving together in a single event
184- true | null | " (\\ w+)\\ s(\\ d+)" | [' hello 1\n world 2\n test 456\n\n done' ] | [test : " 456" , hello : " 1" , world : " 2" ]
184+ true | null | " (\\ w+)\\ s(\\ d+)" | [' hello 1\n world 2\n test 456\n\n done' ] | [test : " 456" , hello : " 1" , world : " 2" ] | " SSM multiline in single event "
185185
186186 // Test mixed behavior: some lines together, some separate
187- true | null | " (\\ w+)\\ s(\\ d+)" | [' hello 1\n world 2' , ' test 456' , ' done' ] | [test : " 456" , hello : " 1" , world : " 2" ]
187+ true | null | " (\\ w+)\\ s(\\ d+)" | [' hello 1\n world 2' , ' test 456' , ' done' ] | [test : " 456" , hello : " 1" , world : " 2" ] | " mixed multiline and separate events"
188+ }
189+
190+ @Unroll
191+ def " multiline-filter-complex-regex-patterns: #testName" () {
192+ given :
193+ def plugin = new DataKeyFilterMultiLines ()
194+ plugin. regex = regex
195+ plugin. logData = dolog
196+ plugin. name = name
197+ plugin. captureMultipleKeysValues = captureMultiple
198+ def sharedoutput = new DataOutput (ContextView . global())
199+ def context = Mock (PluginLoggingContext ) {
200+ getOutputContext() >> sharedoutput
201+ }
202+ def events = []
203+ lines. each { line ->
204+ events << Mock (LogEventControl ) {
205+ getMessage() >> line
206+ getEventType() >> ' log'
207+ getLoglevel() >> LogLevel . NORMAL
208+ }
209+ }
210+ when :
211+ plugin. init(context)
212+ events. each {
213+ plugin. handleEvent(context, it)
214+ }
215+ plugin. complete(context)
216+ then :
217+
218+ sharedoutput. getSharedContext(). getData(ContextView . global())?. getData() == (expect ? [' data' : expect] : null )
219+
220+ where :
221+ dolog | name | captureMultiple | regex | lines | expect | testName
222+
223+ // Test timestamp parsing with multiple groups (only first 2 groups used as key-value)
224+ true | null | true | " (\\ d{4}-\\ d{2}-\\ d{2})\\ s(\\ d{2}:\\ d{2}:\\ d{2})\\ s([A-Z]+)\\ s(.+)" | [' 2023-11-06 14:30:15 INFO Application started' ,
225+ ' 2023-11-06 14:30:16 ERROR Database connection failed' ] |
226+ [' 2023-11-06' : ' 14:30:15\n 14:30:16' ] | " timestamp parsing with log levels"
227+
228+ // Test file path parsing with escaped characters
229+ true | null | true | " File:\\ s+(.+\\ .log)\\ s+Size:\\ s+(\\ d+)" | [' File: /var/log/app.log Size: 1024' ,
230+ ' File: /tmp/debug.log Size: 512' ] |
231+ [' /var/log/app.log' : ' 1024' , ' /tmp/debug.log' : ' 512' ] | " file path and size parsing"
232+
233+ // Test JSON-like parsing
234+ true | null | true | ' "([^"]+)":\\ s*"([^"]+)"' | [' "name": "John Doe"' ,
235+ 236+ ' "status": "active"' ] |
237+ [
name :
' John Doe' ,
email :
' [email protected] ' ,
status :
' active' ] |
" JSON key-value parsing" 238+
239+ // Test IP address and port parsing
240+ true | null | true | " (\\ d{1,3}\\ .\\ d{1,3}\\ .\\ d{1,3}\\ .\\ d{1,3}):(\\ d+)" | [' 192.168.1.100:8080' ,
241+ ' 10.0.0.1:3306' ,
242+ ' 127.0.0.1:5432' ] |
243+ [' 192.168.1.100' : ' 8080' , ' 10.0.0.1' : ' 3306' , ' 127.0.0.1' : ' 5432' ] | " IP address and port extraction"
244+
245+ // Test case-insensitive matching (using (?i) flag)
246+ true | null | true | " (?i)(ERROR|WARN|INFO)\\ s+(.+)" | [' ERROR Database connection failed' ,
247+ ' warn Memory usage high' ,
248+ ' Info Application started' ] |
249+ [ERROR : ' Database connection failed' , warn : ' Memory usage high' , Info : ' Application started' ] | " case-insensitive log level matching"
250+
251+ // Test complex log format parsing
252+ true | null | true | " \\ [([^\\ ]]+)\\ ]\\ s+(\\ w+):\\ s+(.+)" | [' [2023-11-06 14:30:15] INFO: System startup completed' ,
253+ ' [2023-11-06 14:30:16] ERROR: Database timeout' ] |
254+ [' 2023-11-06 14:30:15' : ' INFO' , ' 2023-11-06 14:30:16' : ' ERROR' ] | " structured log format with brackets"
255+
256+ // Test URL parameter parsing
257+ true | null | true | " ([^=]+)=([^&\\ s]+)" | [' user=admin' ,
258+ ' session=abc123' ,
259+ ' timeout=300' ] |
260+ [user : ' admin' , session : ' abc123' , timeout : ' 300' ] | " URL parameter parsing"
261+
262+ // Test multiline with newlines in single event (like SSM) with complex regex
263+ true | null | true | " STATUS\\ s+(\\ w+)\\ s+MSG\\ s+(.+)" | [' STATUS SUCCESS MSG Operation completed\n STATUS FAILED MSG Connection timeout\n STATUS PENDING MSG Waiting for response' ] |
264+ [SUCCESS : ' Operation completed' , FAILED : ' Connection timeout' , PENDING : ' Waiting for response' ] | " status message parsing in single event"
265+
266+ // Test with single group and name parameter for simple metric extraction
267+ true | " cpu_usage" | true | " CPU:\\ s+(\\ d+)%" | [' CPU: 85%' ,
268+ ' Some other line' ,
269+ ' CPU: 92%' ] |
270+ [' cpu_usage' : ' 85\n 92' ] | " CPU metric extraction with name"
271+
272+ // Test email parsing with complex domains
273+ true |
null |
true |
" ([a-zA-Z0-9._%+-]+)@([a-zA-Z0-9.-]+\\ .[a-zA-Z]{2,})" | [
' [email protected] ' ,
274+ 275+ 276+ [' user' : ' example.com' , ' admin' : ' sub.domain.org' , ' test.user+tag' : ' company.co.uk' ] | " email address domain extraction"
188277 }
189278}
0 commit comments