authorjapps / zerocode

A community-developed, free, opensource, automated testing framework for microservices APIs, Kafka(Data Streams) and Load testing. Zerocode Open Source enables you to create, change and maintain your automated test scenarios via simple JSON or YAML files. Visit documentation below:
https://zerocode-tdd.tddfy.com
Apache License 2.0
909 stars 397 forks source link

Tokens in csvSource parameter sources computed at usage #659

Closed Tobolov closed 5 months ago

Tobolov commented 7 months ago

Solution to Implement:

YAML View of Scenario:

---
scenarioName: Demonstrate bug
parameterized:
  csvSource:
  - "|firstRandom|, |secondRandom|, |myName|"
  - "${RANDOM.NUMBER}, ${RANDOM.NUMBER}, Foo"

Usage:

steps:
- name: create_app
  url: kafka-topic:APP
  operation: produce
  request:
    recordType: JSON
    records:
    - key: "${PARAM.firstRandom}"
      value:
        appId: "${PARAM.firstRandom}", <------- instead of ${0}, 
        // and retain`${0}` working as usual for not to break existing tests (keep backward compatible)
        userId: "${PARAM.secondRandom}", <------- instead of ${1}
        userName: "${PARAM.myName}" <------- instead of ${2}

When it runs, it should replace the random values like below:

---
scenarioName: Demonstrate bug
parameterized:
  csvSource:
  - "|firstRandom|, |secondRandom|"
  - 20240506, 20230507, Foo
steps:
- name: create_app
  url: kafka-topic:APP
  operation: produce
  request:
    recordType: JSON
    records:
    - key: '20240506' <------ from the csvSource
      value:
        appId: '20240506' <------ from the csvSource
        userId: '20230507' <------ from the csvSource
        userName: 'Foo' <------ from csvSource
  verify:
    status: Ok

JSON View of Scenario:

{
  "scenarioName": "Demonstrate bug",
  "parameterized": {
    "csvSource": [
      "|firstRandom|, |secondRandom|, |myName|",
      "${RANDOM.NUMBER}, ${RANDOM.NUMBER}, Foo"
    ]
  }

Usage:

  "steps": [
    {
      "name": "create_app",
      "url": "kafka-topic:APP",
      "operation": "produce",
      "request": {
        "recordType": "JSON",
        "records": [
          {
            "key": "${PARAM.firstRandom}",
            "value": {
              "appId": "${PARAM.firstRandom}", <------- instead of ${0}
              "userId": "${PARAM.secondRandom}" <------- instead of ${1}
              "userName": "${PARAM.myName}" <------- instead of ${2}
            }
          }
        ]
      },
      "verify": {
        "status": "Ok"
      }
    }

When it runs, it should replace with the random values like below:

{
  "scenarioName": "Demonstrate bug",
  "parameterized": {
    "csvSource": [
      "|firstRandom|, |secondRandom|",
      "20240506, 20230507, Foo"
    ]
  },
  "steps": [
    {
      "name": "create_app",
      "url": "kafka-topic:APP",
      "operation": "produce",
      "request": {
        "recordType": "JSON",
        "records": [
          {
            "key": "20240506",
            "value": {
              "appId": "20240506",
              "userId": "20230507",
              "userName": "Foo",
            }
          }
        ]
      },
      "verify": {
        "status": "Ok"
      }
    },

---------------- End of Solution -----------------


**** ISSUE DESCRIPTION **** Goal: I want to generate a random ID and use it throughout a test scenario, without bloating the scenario file (lookups such as $.create_app.request.records[0].key too bloaty).

How I want to achieve this: Generate random id's in a csvSource and reference them throughout the scenario. Bonus points if the values in the csvSource can be named and referenced in a manner like ${PARAM:APP_ID} or even #.APP_ID.

Issue: Tokens such as ${RANDOM.NUMBER} are only computed at usage in parameter sources, as opposed to when the scenario starts.

Scenario to replicate:

---
scenarioName: Demonstrate bug
parameterized:
  csvSource:
    #  {0}: App ID                    {1}: User ID
    - "${RANDOM.NUMBER}, ${RANDOM.NUMBER}"
steps:
  - name: create_app
    url: "kafka-topic:APP"
    operation: produce
    request:
      recordType: JSON
      records:
        - key: ${0}
          value:
            appId: ${0}
            userId: ${1}
    verify:
      status: Ok
  - name: verify_app
    url: "kafka-topic:APP"
    operation: consume
    retry:
      max: 3
      delay: 1000 #ms
    request:
      consumerLocalConfigs:
        recordType: JSON
        commitSync: true
        showRecordsConsumed: true
        maxNoOfRetryPollsOrTimeouts: 3
    verify:
      size: 1
      records:
        - key: ${0}
          value:
            appId: ${0}
            userId: ${1}

Exception:

java.lang.RuntimeException: Assertion failed for :- 

[Demonstrate bug] 
    |
    |
    +---Step --> [verify_app] 

Failures:
--------- 
Assertion jsonPath '$.records[0].value.userId' with actual value '2425071383995341726' did not match the expected value '5053246237145541956'
----------------------------------------------------------------------------------------------------------------------------------
Assertion jsonPath '$.records[0].value.appId' with actual value '3469817706342973769' did not match the expected value '2758064321223210465'
----------------------------------------------------------------------------------------------------------------------------------
Assertion jsonPath '$.records[0].key' with actual value '4194790416790024356' did not match the expected value '3658409644815306301'

    at org.jsmart.zerocode.core.runner.StepNotificationHandler.handleAssertionFailed(StepNotificationHandler.java:37)
    at org.jsmart.zerocode.core.runner.StepNotificationHandler.handleAssertion(StepNotificationHandler.java:71)
    at org.jsmart.zerocode.core.runner.ZeroCodeMultiStepsScenarioRunnerImpl.executeRetry(ZeroCodeMultiStepsScenarioRunnerImpl.java:316)
    at org.jsmart.zerocode.core.runner.ZeroCodeMultiStepsScenarioRunnerImpl.executeRetryWithSteps(ZeroCodeMultiStepsScenarioRunnerImpl.java:191)
    at org.jsmart.zerocode.core.runner.ZeroCodeMultiStepsScenarioRunnerImpl.executeSteps(ZeroCodeMultiStepsScenarioRunnerImpl.java:173)
    at org.jsmart.zerocode.core.runner.ZeroCodeMultiStepsScenarioRunnerImpl.runScenario(ZeroCodeMultiStepsScenarioRunnerImpl.java:136)
    at org.jsmart.zerocode.core.runner.ZeroCodeUnitRunner.runLeafJsonTest(ZeroCodeUnitRunner.java:223)
    at org.jsmart.zerocode.core.runner.ZeroCodeUnitRunner.runChild(ZeroCodeUnitRunner.java:127)
    at org.jsmart.zerocode.core.runner.ZeroCodeUnitRunner.runChild(ZeroCodeUnitRunner.java:51)
    at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
    at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
    at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
    at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
    at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
    at org.jsmart.zerocode.core.runner.ZeroCodeUnitRunner.run(ZeroCodeUnitRunner.java:107)
    at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
    at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:69)
    at com.intellij.rt.junit.IdeaTestRunner$Repeater$1.execute(IdeaTestRunner.java:38)
    at com.intellij.rt.execution.junit.TestsRepeater.repeat(TestsRepeater.java:11)
    at com.intellij.rt.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:35)
    at com.intellij.rt.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:232)
    at com.intellij.rt.junit.JUnitStarter.main(JUnitStarter.java:55)
luke-zhou commented 5 months ago

Hi, just wondering if this issue is still open. If so, can I work on this issue?

authorjapps commented 5 months ago

Hi, just wondering if this issue is still open. If so, can I work on this issue?

@luke-zhou , It's open. You can start working please. Thanks

luke-zhou commented 5 months ago

cool, that is good. just want to confirm my idea here. I am thinking to add something like "#name-tag" to the end of the following 5 type of tokens:

    RANDOM.UUID
    RANDOM.UUID.FIXED
    RANDOM.NUMBER
    RANDOM.NUMBER.FIXED
    RANDOM.STRING

so when the user need to use the same value as the previous random value, he can just quote the name-tag. For example:

---
scenarioName: Demonstrate bug
parameterized:
  csvSource:
    #  {0}: App ID                    {1}: User ID
    - "${RANDOM.NUMBER#0}, ${RANDOM.NUMBER#first}"
steps:
  - name: create_app
    url: "kafka-topic:APP"
    operation: produce
    request:
      recordType: JSON
      records:
        - key: ${RANDOM.NUMBER#0}
          value:
            appId: ${RANDOM.NUMBER#0}
            userId: ${RANDOM.NUMBER#first}
    verify:
      status: Ok
  - name: verify_app
    url: "kafka-topic:APP"
    operation: consume
    retry:
      max: 3
      delay: 1000 #ms
    request:
      consumerLocalConfigs:
        recordType: JSON
        commitSync: true
        showRecordsConsumed: true
        maxNoOfRetryPollsOrTimeouts: 3
    verify:
      size: 1
      records:
        - key: ${RANDOM.NUMBER#0}
          value:
            appId: ${RANDOM.NUMBER#0}
            userId: ${RANDOM.NUMBER#first}
authorjapps commented 5 months ago

cool, that is good. just want to confirm my idea here. I am thinking to add something like "#name-tag" to the end of the following 5 type of tokens:

Hello @luke-zhou , really appreciate you have been trying to solutionize it. Good to see your ideas, prefix "#first" etc might create confusion imo.

Can you have a look at the Issue description section "Solution to Implement:", which could be simpler ? https://github.com/authorjapps/zerocode/issues/659#issue-2234390371

Basically the 1st line has got words (without spaces) wrapped by "|", will be treated as a headers.

  • "|firstRandom|, |secondRandom|, |myName|"

Everytime a scenario runs it should pick the value under each header (e.g "${PARAM.firstRandom}" <------- instead of ${0} which is the current behavior).

Also it will keep the scenario clean and readable.

Can you give it a try to implement it?

nirmalchandra commented 5 months ago

appId: "${PARAM.firstRandom}", <------- instead of ${0}

Also, keep ${0} working as usual for not to break existing tests (keep backward compatible I mean)

luke-zhou commented 5 months ago

ok, no problem, will give a shot

nirmalchandra commented 5 months ago

PR is ready to be merged.

Test result is here:

authorjapps commented 5 months ago

PR is ready to be merged.

Test result is here:

@Tobolov , can you have a look at the test result and check you got everything you needed for this issue?

authorjapps commented 5 months ago

TODO - Add documentation for this feature. Take help from here.