Improve failure output to make debugging /failure fixing in tests simpler
Origin situation
I accidently defined a wrong type in my test (I used String.class instead of JsonFieldType.STRING) which led to a resources.json containing:
, {
"attributes" : { },
"description" : "my text...",
"ignored" : false,
"path" : "content[].metaData.xyz",
"type" : "java.lang.String",
"optional" : true
}, {
which leads to gradle failure with:
Task openapi3 FAILED
FAILURE: Build failed with an exception.
* What went wrong:
Execution failed for task 'openapi3'.
> unknown field type java.lang.string
That was all output.
Of course this is my fault, but to find the problem wasn't easy - at the beginning I did not recognize that the resource.json output inside build/generated-snippets/myTargetFolder is full used to generate openapi parts and there you can find the location of the problem etc. etc.
Wanted
It would be nice to have
- the location of the problematic
resource.jsonor - the problematic test case, or
- the path/attributes or
- anything else that makes it simpler to locate the problematic part inside the gradle output in failure case.
Hey @de-jcup ,
thanks for the report and sorry that this caused you trouble!
Yeah, it's an unfortunate "user" (developer) error. By design (using restdocs field descriptors to generate the raw format and using different gradle plugins to generate the respective target formats) there are some constraints for a solution:
- Apparently, the restdocs FieldDescriptor doesn't have a problem with an arbitrary Java type. We value restdocs interface, so a test failure there wouldn't be appropriate.
- Thus validation would need to happen in the respective gradle plugins. It already correctly fails, but the error message wasn't helpful enough
- To include test/source line info in the gradle plugin error, we'd need to use reflection/debug symbols to store this information in the
resource.jsonsnippet
Imo, the last point would be overkill. I'd leave this open for further discussion/suggestions, but will eventually close it as "won't do" if no one steps up.
Hello @ozscheyge ,
To include test/source line info in the gradle plugin error, we'd need to use reflection/debug symbols to store this information in the resource.json snippet Imo, the last point would be overkill.
I absolutely agree... this would be too much effort - at least for the error handling
Suggestions
Simple show file path
Scope: after resources.json has been generated and users do generate output from it (e.g. openapi3.yaml) - so inside processing existing 'resource.json' files
I haven't looked at the sources exactly and I have no real experience with Kotlin at the moment - but normally the currently fetched resources.json file path should be available while doing generation of output.
So when just remembering last read resources.json file and showing the full path in case of error should be possible without much effort?
Show related JSON object as output / hint
Scope: after resources.json has been generated and users do generate output from it (e.g. openapi3.yaml) - so inside processing existing 'resource.json' files
In error case show complete JSON elements from current JSON object. (in my example before this would be
{
"attributes" : { },
"description" : "my text...",
"ignored" : false,
"path" : "content[].metaData.xyz",
"type" : "java.lang.String",
"optional" : true
}
So its more clear for users what resource part is the problem.
Together with the existing error message (+ maybe path information) it should be very easy to locate problematic part. This should be possible without additional debug meta data or reflection usage.
I'm running into a similar problem right now, but I can't seem to figure out where the issue is orignating from:
Caused by: java.lang.IllegalArgumentException: unknown field type false
at com.epages.restdocs.apispec.jsonschema.JsonSchemaFromFieldDescriptorsGenerator$FieldDescriptorWithSchemaType.typeToSchema(JsonSchemaFromFieldDescriptorsGenerator.kt:251)
at com.epages.restdocs.apispec.jsonschema.JsonSchemaFromFieldDescriptorsGenerator$FieldDescriptorWithSchemaType.jsonSchemaType(JsonSchemaFromFieldDescriptorsGenerator.kt:206)
at com.epages.restdocs.apispec.jsonschema.JsonSchemaFromFieldDescriptorsGenerator.handleEndOfPath(JsonSchemaFromFieldDescriptorsGenerator.kt:170)
at com.epages.restdocs.apispec.jsonschema.JsonSchemaFromFieldDescriptorsGenerator.access$handleEndOfPath(JsonSchemaFromFieldDescriptorsGenerator.kt:26)
at com.epages.restdocs.apispec.jsonschema.JsonSchemaFromFieldDescriptorsGenerator$traverse$1$1.apply(JsonSchemaFromFieldDescriptorsGenerator.kt:91)
at com.epages.restdocs.apispec.jsonschema.JsonSchemaFromFieldDescriptorsGenerator$traverse$1$1.apply(JsonSchemaFromFieldDescriptorsGenerator.kt:26)
at com.epages.restdocs.apispec.jsonschema.JsonSchemaFromFieldDescriptorsGenerator$traverse$1.accept(JsonSchemaFromFieldDescriptorsGenerator.kt:89)
at com.epages.restdocs.apispec.jsonschema.JsonSchemaFromFieldDescriptorsGenerator$traverse$1.accept(JsonSchemaFromFieldDescriptorsGenerator.kt:26)
at com.epages.restdocs.apispec.jsonschema.JsonSchemaFromFieldDescriptorsGenerator.traverse(JsonSchemaFromFieldDescriptorsGenerator.kt:83)
at com.epages.restdocs.apispec.jsonschema.JsonSchemaFromFieldDescriptorsGenerator.generateSchema(JsonSchemaFromFieldDescriptorsGenerator.kt:32)
at com.epages.restdocs.apispec.jsonschema.JsonSchemaFromFieldDescriptorsGenerator.generateSchema$default(JsonSchemaFromFieldDescriptorsGenerator.kt:28)
at com.epages.restdocs.apispec.openapi2.OpenApi20Generator.responseModel2Response(OpenApi20Generator.kt:480)
at com.epages.restdocs.apispec.openapi2.OpenApi20Generator.resourceModels2Operation(OpenApi20Generator.kt:312)
at com.epages.restdocs.apispec.openapi2.OpenApi20Generator.resourceModels2Path(OpenApi20Generator.kt:225)
at com.epages.restdocs.apispec.openapi2.OpenApi20Generator.generatePaths(OpenApi20Generator.kt:182)
at com.epages.restdocs.apispec.openapi2.OpenApi20Generator.generate$restdocs_api_spec_openapi_generator(OpenApi20Generator.kt:69)
at com.epages.restdocs.apispec.openapi2.OpenApi20Generator.generateAndSerialize(OpenApi20Generator.kt:95)
at com.epages.restdocs.apispec.gradle.OpenApiTask.generateSpecification(OpenApiTask.kt:28)
at com.epages.restdocs.apispec.gradle.ApiSpecTask.aggregateResourceModels(ApiSpecTask.kt:49)
at org.gradle.internal.reflect.JavaMethod.invoke(JavaMethod.java:73)
at org.gradle.api.internal.project.taskfactory.StandardTaskAction.doExecute(StandardTaskAction.java:48)
at org.gradle.api.internal.project.taskfactory.StandardTaskAction.execute(StandardTaskAction.java:41)
at org.gradle.api.internal.project.taskfactory.StandardTaskAction.execute(StandardTaskAction.java:28)
at org.gradle.api.internal.AbstractTask$TaskActionWrapper.execute(AbstractTask.java:704)
at org.gradle.api.internal.AbstractTask$TaskActionWrapper.execute(AbstractTask.java:671)
at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter$2.run(ExecuteActionsTaskExecuter.java:284)
at org.gradle.internal.operations.DefaultBuildOperationExecutor$RunnableBuildOperationWorker.execute(DefaultBuildOperationExecutor.java:301)
at org.gradle.internal.operations.DefaultBuildOperationExecutor$RunnableBuildOperationWorker.execute(DefaultBuildOperationExecutor.java:293)
at org.gradle.internal.operations.DefaultBuildOperationExecutor.execute(DefaultBuildOperationExecutor.java:175)
at org.gradle.internal.operations.DefaultBuildOperationExecutor.run(DefaultBuildOperationExecutor.java:91)
at org.gradle.internal.operations.DelegatingBuildOperationExecutor.run(DelegatingBuildOperationExecutor.java:31)
at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter.executeAction(ExecuteActionsTaskExecuter.java:273)
at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter.executeActions(ExecuteActionsTaskExecuter.java:258)
at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter.access$200(ExecuteActionsTaskExecuter.java:67)
at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter$TaskExecution.execute(ExecuteActionsTaskExecuter.java:145)
at org.gradle.internal.execution.impl.steps.ExecuteStep.execute(ExecuteStep.java:49)
at org.gradle.internal.execution.impl.steps.CancelExecutionStep.execute(CancelExecutionStep.java:34)
at org.gradle.internal.execution.impl.steps.TimeoutStep.executeWithoutTimeout(TimeoutStep.java:69)
at org.gradle.internal.execution.impl.steps.TimeoutStep.execute(TimeoutStep.java:49)
at org.gradle.internal.execution.impl.steps.CatchExceptionStep.execute(CatchExceptionStep.java:33)
at org.gradle.internal.execution.impl.steps.CreateOutputsStep.execute(CreateOutputsStep.java:50)
at org.gradle.internal.execution.impl.steps.SnapshotOutputStep.execute(SnapshotOutputStep.java:43)
at org.gradle.internal.execution.impl.steps.SnapshotOutputStep.execute(SnapshotOutputStep.java:29)
at org.gradle.internal.execution.impl.steps.CacheStep.executeWithoutCache(CacheStep.java:134)
at org.gradle.internal.execution.impl.steps.CacheStep.lambda$execute$3(CacheStep.java:83)
at org.gradle.internal.execution.impl.steps.CacheStep.execute(CacheStep.java:82)
at org.gradle.internal.execution.impl.steps.CacheStep.execute(CacheStep.java:36)
at org.gradle.internal.execution.impl.steps.PrepareCachingStep.execute(PrepareCachingStep.java:33)
at org.gradle.internal.execution.impl.steps.StoreSnapshotsStep.execute(StoreSnapshotsStep.java:38)
at org.gradle.internal.execution.impl.steps.StoreSnapshotsStep.execute(StoreSnapshotsStep.java:23)
at org.gradle.internal.execution.impl.steps.SkipUpToDateStep.executeBecause(SkipUpToDateStep.java:96)
at org.gradle.internal.execution.impl.steps.SkipUpToDateStep.lambda$execute$0(SkipUpToDateStep.java:89)
at org.gradle.internal.execution.impl.steps.SkipUpToDateStep.execute(SkipUpToDateStep.java:52)
at org.gradle.internal.execution.impl.steps.SkipUpToDateStep.execute(SkipUpToDateStep.java:36)
at org.gradle.internal.execution.impl.DefaultWorkExecutor.execute(DefaultWorkExecutor.java:34)
at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter.execute(ExecuteActionsTaskExecuter.java:91)
... 32 more
Any ideas on how I can track this down.
Hey @virtualdogbert ,
would you mind posting your resource.json of the snippet which might be affected? You'll find those in your project directory under
build/generated-snippets/{snippetName}/resource.json
If you have plenty of snippets, this grep might help:
grep --include resource.json -rn "type.*:.*false" build/
I have a lot of snippets, been working hard, but your grep, made me realize why my find wasn't working and now I can track things down. It was a JsonFieldType.array instead of JsonFieldType.ARRAY
After fighting some merge conflicts on the branch this was an easy fix. Thanks.