Endava / cats

CATS is a REST API Fuzzer and negative testing tool for OpenAPI endpoints. CATS automatically generates, runs and reports tests with minimum configuration and no coding effort. Tests are self-healing and do not require maintenance.
Apache License 2.0
1.11k stars 75 forks source link

NullPointerException when using discriminator, oneOf, allOf #69

Closed donquichotte closed 1 year ago

donquichotte commented 1 year ago

Hi,

I am trying to test an API that uses an openapi definition with a discriminator, allOf and oneOf.

This results in a java.lang.NullPointerException when trying to fuzz the path where the object is used.

Version: 8.6.2 (also happened on 8.5.0).

The definition appears to be valid according to https://editor.swagger.io/, no errors are reported when entering it into the editor.

Full error trace:

java.lang.NullPointerException
        at com.endava.cats.model.generator.OpenAPIModelGenerator.normalizeDiscriminatorMappingsToOneOf(OpenAPIModelGenerator.java:329)
        at com.endava.cats.model.generator.OpenAPIModelGenerator.resolveModelToExample(OpenAPIModelGenerator.java:270)
        at com.endava.cats.model.generator.OpenAPIModelGenerator.addXXXOfExamples(OpenAPIModelGenerator.java:454)
        at com.endava.cats.model.generator.OpenAPIModelGenerator.populateWithComposedSchema(OpenAPIModelGenerator.java:374)
        at com.endava.cats.model.generator.OpenAPIModelGenerator.resolveModelToExample(OpenAPIModelGenerator.java:281)
        at com.endava.cats.model.generator.OpenAPIModelGenerator.addXXXOfExamples(OpenAPIModelGenerator.java:454)
        at com.endava.cats.model.generator.OpenAPIModelGenerator.populateWithComposedSchema(OpenAPIModelGenerator.java:404)
        at com.endava.cats.model.generator.OpenAPIModelGenerator.resolveModelToExample(OpenAPIModelGenerator.java:281)
        at com.endava.cats.model.generator.OpenAPIModelGenerator.generate(OpenAPIModelGenerator.java:95)
        at com.endava.cats.factory.FuzzingDataFactory.generateSample(FuzzingDataFactory.java:353)
        at com.endava.cats.factory.FuzzingDataFactory.getResponsePayloads(FuzzingDataFactory.java:578)
        at com.endava.cats.factory.FuzzingDataFactory.getFuzzDataForNonBodyMethods(FuzzingDataFactory.java:248)
        at com.endava.cats.factory.FuzzingDataFactory.getFuzzingDataForGet(FuzzingDataFactory.java:171)
        at com.endava.cats.factory.FuzzingDataFactory.fromPathItem(FuzzingDataFactory.java:100)
        at com.endava.cats.factory.FuzzingDataFactory_ClientProxy.fromPathItem(Unknown Source)
        at com.endava.cats.command.CatsCommand.fuzzPath(CatsCommand.java:262)
        at com.endava.cats.command.CatsCommand.startFuzzing(CatsCommand.java:180)
        at com.endava.cats.command.CatsCommand.doLogic(CatsCommand.java:141)
        at com.endava.cats.command.CatsCommand.run(CatsCommand.java:126)
        at picocli.CommandLine.executeUserObject(CommandLine.java:2026)
        at picocli.CommandLine.access$1500(CommandLine.java:148)
        at picocli.CommandLine$RunLast.executeUserObjectOfLastSubcommandWithSameParent(CommandLine.java:2461)
        at picocli.CommandLine$RunLast.handle(CommandLine.java:2453)
        at picocli.CommandLine$RunLast.handle(CommandLine.java:2415)
        at picocli.CommandLine$AbstractParseResultHandler.execute(CommandLine.java:2273)
        at picocli.CommandLine$RunLast.execute(CommandLine.java:2417)
        at picocli.CommandLine.execute(CommandLine.java:2170)
        at com.endava.cats.CatsMain.run(CatsMain.java:36)
        at com.endava.cats.CatsMain_ClientProxy.run(Unknown Source)
        at io.quarkus.runtime.ApplicationLifecycleManager.run(ApplicationLifecycleManager.java:132)
        at io.quarkus.runtime.Quarkus.run(Quarkus.java:71)
        at io.quarkus.runtime.Quarkus.run(Quarkus.java:44)
        at io.quarkus.runner.GeneratedMain.main(Unknown Source)

Offending openapi definition:

openapi: 3.0.2
info:
  title: Minimum Crashing Example
  version: '0.0'
servers:
  - url: http://api.server.test/
components:
  schemas:

    VariantDiscriminator:
      type: object
      required:
        ["discr"]
      properties:
        discr:
          type: string
          enum: [
            "option_1",
            "option_2"
          ]
      discriminator:
        propertyName: discr
        mapping:
          "option_1": '#/components/schemas/VariantOption1'
          "option_2": '#/components/schemas/VariantOption2'

    VariantOption1:
      type: object
      allOf: [
        $ref: '#/components/schemas/VariantDiscriminator',
        $ref: '#/components/schemas/VariantOption1AdditionalStuff']

    VariantOption2:
      type: object
      allOf: [
        $ref: '#/components/schemas/VariantDiscriminator',
        $ref: '#/components/schemas/VariantOption2AdditionalStuff']

    Variant:
      type: object
      oneOf: [
        $ref: '#/components/schemas/VariantOption1',
        $ref: '#/components/schemas/VariantOption2']

    VariantOption1AdditionalStuff:
      type: object
      properties:
        i:
          type: integer
    VariantOption2AdditionalStuff:
      type: object
      properties:
        j: 
          type: string
paths:
  /variant:
    get:
      summary: Get variant
      description: Get variant
      tags:
        - Variant
      responses:
        '200':
          description: Get variant
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Variant'

Any ideas on why this breaks?

en-milie commented 1 year ago

Hi @donquichotte. Thank you for reporting this. I'll check to see what happens.

en-milie commented 1 year ago

The fix will be available in the next release.

en-milie commented 1 year ago

The fix is available in: https://github.com/Endava/cats/releases/tag/cats-8.7.0

donquichotte commented 1 year ago

Thank you, I am unable to reproduce the issue after the fix, using various OpenAPI definitions using the offending pattern.