Forum Discussion

AAB55's avatar
AAB55
New Contributor
3 months ago

Reuse adapted xml file and send in REST

Hi SmartBear,

Long time ago that I was here (under a different name :-)  ). Glad to be back though ;-)

So, my question:

We want to send a file as Query, cached, multipart/form-data.

After sending we need to adapt, e.g. the vinnumber, save the file and send again with REST request.

For the moment I have this:

 

import groovy.xml.XmlParser
import groovy.xml.XmlUtil

// 1 Generate VIN
def chars = "ABCDEFGHJKLMNPRSTUVWXYZ0123456789"
def random = new Random()
def generatedVin = (1..17).collect { chars[random.nextInt(chars.length())] }.join()

log.info "Generated VIN: " + generatedVin

// 2 Get file path from test case level -->wll fetch it from folder project
def filePath = context.expand('${#TestCase#file}')
def file2 = new File(filePath)

log.info "File path: " + filePath


// 3 Parse XML
def xml = new XmlParser().parse(file)

// 4 Update VIN
xml.Body.VehicleTransportOrder.Line.Vehicle.VehicleID[0].value.generatedVin

// 5 Write updated XML
def writer = new FileWriter(file2)
XmlUtil.serialize(xml, writer)
writer.close()

log.info "VIN replaced successfully"

The original file came with the composite testproject as everybody needs to be able to reach that file. We don't know if this would be better put in a folder because we will have different files from different clients. But this is what we came up to.

The file is read correctly, the vinnumber = generated, but the new number can't be put in that attached file anymore.

Anybody an idea on what should be the best steps now?

 

Thanks in advance, AAB

 

2 Replies

  • Humashankar's avatar
    Humashankar
    Icon for Champion Level 3 rankChampion Level 3

    Hi AAB55​ 

    If the VIN is the only value that changes, you could avoid parsing and serializing the entire XML and simply perform a string replacement on a placeholder, replacing VIN with the generated value before sending the request. This is often simpler and more maintainable.

    Hope this helps!!

  • AAB55's avatar
    AAB55
    New Contributor

    Hi Humashankar​ 

    Thank you for your response. As this could be an option, I've decided to do this differently. I wanted to be able to use the objects from ReadyAPI together with groovyscript. How I did it:

    A first groovyscript: to lookup the files in a local 'resource' folder. A lot of those files have different extensions.

    def basePath = context.expand('${#Global#filePath}')
    
    def sourceDir = new File(basePath + "/resources")
    
    def files = sourceDir.listFiles()
            .findAll { it.isFile() }
    
    def filePaths = files.collect { it.absolutePath }
    
    testRunner.testCase.setPropertyValue(
            "fileList",
            filePaths.join("|")
    )
    
    testRunner.testCase.setPropertyValue( "fileIndex", "0")
    
    log.info "FOUND ${filePaths.size()} FILES"

    2nd step is use of Data Source. I gave a name to the property 'currentFile' and use this groovy:

    def fileList =
        testRunner.testCase.getPropertyValue(
            "fileList"
        )
    
    def index =
        testRunner.testCase.getPropertyValue(
            "fileIndex"
        ) as Integer
    
    def files =
        fileList.split("\\|")
    
    if(index >= files.size()) {
    
        log.info "NO MORE FILES"
    
        return false
    }
    
    result["currentFile"] =
        files[index]
    
    log.info(
        "CURRENT FILE = " +
        files[index]
    )

    The 3rd step is the REST request where I've attached the original file, saved on project level , as multipart/form-data

    Followed by another groovyscript that will check which type of file we need to tackle, change the random vinnumber and saved it in a local folder to be fetched again in a next step

    import groovy.xml.*
    import java.util.Random
    
    // PATHS
    // =====================================================
    def basePath = context.expand('${#Global#filePath}')
    def currentFile = context.expand('${Data Source#currentFile}')
    log.info("CURRENT FILE = " + currentFile)
    
    def inputFile = new File(currentFile)
    if (!inputFile.exists()) {
        throw new Exception(
                "FILE NOT FOUND : " + currentFile)
    }
    def originalFileName = inputFile.name
    log.info("FILE NAME = " + originalFileName)
    
    // NEW VIN
    // =====================================================
    def newVin = {
    
        def chars = "ABCDEFGHJKLMNPRSTUVWXYZ0123456789"
    
        (1..17).collect {chars[new Random().nextInt(chars.length())] }.join()
    }
    
    // DISPATCHER
    // =====================================================
    def generatedContent
    if(originalFileName.toLowerCase().endsWith(".xml")) {
        generatedContent = processXml(inputFile, newVin)
    }
    else if(originalFileName.toLowerCase().endsWith(".conv")) {
        generatedContent = processConv(inputFile, newVin)
    }
    else {
        generatedContent = processFlatFile(inputFile, newVin)
    }
    
    // XML
    // =====================================================
    def processXml(file,newVin) {
        def xml = new XmlParser(false,false).parse(file)
        boolean replaced = false
        xml.depthFirst().each { node ->
            if(replaced) return
            def nodeName = node.name().toString().toLowerCase()
            if(nodeName.contains("vin") ||
               nodeName.contains("vehicleid")) {
                log.info("FOUND XML NODE = ${nodeName}")
                node.value = newVin
                replaced = true
            }
        }
        return XmlUtil.serialize(xml)
    }
    
    // FORD CONV
    // =====================================================
    def processConv(file,newVin) {
        boolean replaced = false
        def lines = file.readLines()
        def updated = lines.collect { line ->
            if(!replaced) {
                def matcher = line =~ /(WF0[A-Z0-9]{14})/
                if(matcher.find()) {
                    def oldVin = matcher.group(1)
                    //log.info("FOUND FORD VIN = ${oldVin}" )
                    line = line.replaceFirst( oldVin, newVin)
                    replaced = true
                }
            }
            return line
        }
        updated.join("\n")
    }
    
    // DCUK
    // =====================================================
    def processFlatFile(file,newVin) {
        boolean replaced = false
        def lines = file.readLines()
        def updated = lines.collect { line ->
            if(!replaced) {
                def matcher =line =~ /(W1K[A-Z0-9]{10,20})/
                if(matcher.find()) {
                    def oldVin = matcher.group(1)
                   // log.info("FOUND DCUK VIN = ${oldVin}" )
                    line = line.replaceFirst(oldVin, newVin )
                    replaced = true
                }
            }
            return line
        }
        updated.join("\n")
    }
    
    // SAVE FILE
    // =====================================================
    def generatedDir = new File(basePath + "/generated")
    if(!generatedDir.exists()) {
        generatedDir.mkdirs()
    }
    def generatedFileName = inputFile.name.replace( ".", "_" + System.currentTimeMillis() + "_generated.")
    def fullPath =generatedDir.absolutePath + "/" +generatedFileName
    new File(fullPath).write(
            generatedContent,
            "UTF-8"
    )
    //log.info "GENERATED FILE = ${fullPath}"
    // generated file properties
    testRunner.testCase.setPropertyValue( "generatedFile", fullPath)
    testRunner.testCase.setPropertyValue("generatedFileName", inputFile.name)
    //log.info("GENERATED FILE NAME = " +new File(fullPath).getName()
    
    def currentIndex =
        context.expand('${#TestCase#fileIndex}') as Integer
    log.info "INDEX BEFORE = ${currentIndex}"
    testRunner.testCase.setPropertyValue(
        "fileIndex",
        (currentIndex + 1).toString()
    )
    log.info "INDEX AFTER = ${currentIndex + 1}"
    
    // SET PARTNERNAME
    // =====================================================
    def detectPartner(fileName) {
        def knownPartners = [
            "FORD",
            "DCUK",
            "JLR-RAIL",
            "PDL",
            "PRI",
            "CarArrival",
            "STELLANT"
        ]
        for(p in knownPartners) {
            if(fileName.toUpperCase().contains(p.toUpperCase())) {
                return p
            }
        }
        return "UNKNOWN"
    }
    def partner =detectPartner(originalFileName)
    testRunner.testCase.setPropertyValue( "partner", partner)
    //log.info("PARTNER = " + partner)

    5th step is the next REST request that fetches the newly create file.

    and the last step is a cleanup from the previous step. You need to unattache the previous file so the newly created file can be added.

    And it works as a charm!

    Regards!