Home > database >  How can I Identify a line in a csv file based on a variable value and start iterating over the file
How can I Identify a line in a csv file based on a variable value and start iterating over the file

Time:10-25

I am using Jmeter to send multiple HTTPS requests to some API. I need to compose the XML body of these requests with different data each time.

I have a csv file which looks like this:

iDocType,iDocId,iName,iDate
P,555551555,Braiden,2022-12-31
I,100000001,Dominique,2024-12-10
P,100000002,Joyce,2025-11-15
.........

And I have this piece of code in a JSR223 PreProcessor (under the HTTPS Sampler) which creates multiple XML objects and populates them one by one with csv values and finally gives this object to Jmeter to use in the sampler as request body data:

def writer = new StringWriter()
def xml = new groovy.xml.MarkupBuilder(writer)
def pReqID = 'ID0000'

def numberOfNodes = 3

//input from csv file
travelDocNbr = vars.get('iDocId').toInteger();

def lines = new File("TestData\\test.csv").readLines()

xml.nodes() {
    1.upto(numberOfNodes, { lineNo ->
        xml.object(a: 'false', b: 'false', pReqID: pReqID   (lineNo).toString()) {
            xml.al(ad: '2021-09-20', alc: 'bla', bla: '2021-09-20T11:00:00.000Z', sn: 'AB8912')
            xml.doc(docType: lines.get(lineNo).split(',')[0],
                    docId: lines.get(lineNo).split(',')[1],
                    name: lines.get(lineNo).split(',')[2],
                    date: lines.get(lineNo).split(',')[3])
            }
        }
    )
}

def nodeAsText = writer.toString()
//log.info(nodeAsText)

vars.put('passengers3XmlObj', nodeAsText)   

This always gives this result:

<nodes>
  <object a='false' b='false' pReqID='ID00001'>
    <al ad='2021-09-20' alc='bla' bla='2021-09-20T11:00:00.000Z' sn='AB8912' />
    <doc docType='P' docId='555551555' name='Braiden' date='12/31/2022' />
  </object>
  <object a='false' b='false' pReqID='ID00002'>
    <al ad='2021-09-20' alc='bla' bla='2021-09-20T11:00:00.000Z' sn='AB8912' />
    <doc docType='P' docId='100000001' name='Dominique' date='12/10/2024' />
  </object>
  <object a='false' b='false' pReqID='ID00003'>
    <al ad='2021-09-20' alc='bla' bla='2021-09-20T11:00:00.000Z' sn='AB8912' />
    <doc docType='P' docId='100000002' name='Joyce' date='11/15/2025' />
  </object>
</nodes>

The problem is that this script starts composing objects from the first value in the CSV file and always creates the same XML object in each sampler request's body. I need it to change values from the CSV each time. For this, I was thinking if I could have a variable which always changes in each sampler iteration, like the iName value (I get a different one on each sampler iteration thanks to the CSV Data Set config test element) and use that to find the line in the CSV file and start composing objects from that line onwards.

So, for example, given that the csv file has just the 3 lines mentioned at the beginning and I have the value "Dominique" stored in a variable I want to pass it to a function and get the following result:

<nodes>
  <object a='false' b='false' pReqID='ID00001'>
    <al ad='2021-09-20' alc='bla' bla='2021-09-20T11:00:00.000Z' sn='AB8912' />
    <doc docType='P' docId='100000001' name='Dominique' date='12/10/2024' />
  </object>
  <object a='false' b='false' pReqID='ID00002'>
    <al ad='2021-09-20' alc='bla' bla='2021-09-20T11:00:00.000Z' sn='AB8912' />
    <doc docType='P' docId='100000002' name='Joyce' date='11/15/2025' />
  </object>
  <object a='false' b='false' pReqID='ID00003'>
    <al ad='2021-09-20' alc='bla' bla='2021-09-20T11:00:00.000Z' sn='AB8912' />
    <doc docType='P' docId='555551555' name='Braiden' date='12/31/2022' />
  </object>
</nodes>

Can someone please tell me how this can be done?

CodePudding user response:

If you want to get the number of line where Dominique text is present it can be done using findIndexOf() function like:

def dominiquePosition = lines.findIndexOf { line -> line.contains('Dominique') }

then you can start building your XML from the position retrieved in the above line:

dominiquePosition.upto(numberOfNodes, { lineNo ->

The iteration can be obtained using vars.getIteration() function where vars stands for JMeterVariables class instance. See Top 8 JMeter Java Classes You Should Be Using with Groovy article for more details on this and other JMeter API shorthands available for the JSR223 Test Elements

CodePudding user response:

I'd put the code in a natural groovy way.

UPDATE: I added some more CSV lines to demonstrate how numberOfNodes affects the output.

def pReqID = 'ID0000'

def numberOfNodes = 2
String startFrom = 'Dominique'

int pos = -1

def csv = """\
iDocType,iDocId,iName,iDate
P,555551555,Braiden,2022-12-31 
I,100000001,Dominique,2024-12-10 
P,100000002,Joyce,2025-11-15
P,555551555,Braiden,2022-12-31 
I,100000001,Dominique,2024-12-10 
P,100000002,Joyce,2025-11-15
""".readLines().drop( 1 ).withIndex().collect{
  def ( docType, docId, name, date ) = it[ 0 ].trim().split( ',' )
  if( -1 == pos && startFrom == name ) pos = it[ 1 ]
  [ docType:docType, docId:docId, name:name, date:date ]
}

//here the skipped lines are reodered to the bottom, if needed
def reoderedCsv = -1 < pos ? csv[ pos..-1 ]   csv[ 0..<pos ] : csv

def writer = new StringWriter()
new groovy.xml.MarkupBuilder(writer).nodes() {

    reoderedCsv.take numberOfNodes eachWithIndex{ data, ix ->
         object(a: 'false', b: 'false', pReqID:"$pReqID${ix   1}" ) {
            al ad:'2021-09-20', alc:'bla', bla:'2021-09-20T11:00:00.000Z', sn:'AB8912'
            doc data
         }
    }
}

println writer

prints:

<nodes>
  <object a='false' b='false' pReqID='ID00001'>
    <al ad='2021-09-20' alc='bla' bla='2021-09-20T11:00:00.000Z' sn='AB8912' />
    <doc docType='P' docId='555551555' name='Braiden' date='2022-12-31' />
  </object>
  <object a='false' b='false' pReqID='ID00002'>
    <al ad='2021-09-20' alc='bla' bla='2021-09-20T11:00:00.000Z' sn='AB8912' />
    <doc docType='I' docId='100000001' name='Dominique' date='2024-12-10' />
  </object>
  <object a='false' b='false' pReqID='ID00003'>
    <al ad='2021-09-20' alc='bla' bla='2021-09-20T11:00:00.000Z' sn='AB8912' />
    <doc docType='P' docId='100000002' name='Joyce' date='2025-11-15' />
  </object>
</nodes>
  • Related