Skip to content

Commit 3db4381

Browse files
authored
Fix exactCopy example with __body__ (#524)
The body was being put in quotes - it needs to be treated like an object instead of a string constant.
1 parent 9c91709 commit 3db4381

File tree

7 files changed

+187
-8
lines changed

7 files changed

+187
-8
lines changed

src/compiler/Restler.Compiler.Test/ExampleTests.fs

+69-1
Original file line numberDiff line numberDiff line change
@@ -524,12 +524,80 @@ module Examples =
524524
exactCopy = false
525525
}
526526

527-
let testConfig = { config with ExampleConfigFiles = Some [ {exampleConfigFile with exactCopy = false }] }
527+
let testConfig = { config with ExampleConfigFiles = Some [ exampleConfigFile ] }
528528
Restler.Workflow.generateRestlerGrammar None testConfig
529529

530530
let grammarFilePath = Path.Combine(grammarOutputDirectoryPath, Restler.Workflow.Constants.DefaultRestlerGrammarFileName)
531531
let grammar = File.ReadAllText(grammarFilePath)
532532
Assert.True(grammar.Contains("required-param"))
533533
Assert.True(grammar.Contains("optional-param"))
534534

535+
536+
/// Test that the grammar is correct when the entire body is replaced by an example payload.
537+
/// Both 'exactCopy' settings should be tested.
538+
[<Fact>]
539+
let ``replace entire body with example`` () =
540+
let grammarOutputDirectoryPath = ctx.testRootDirPath
541+
let config = { Restler.Config.SampleConfig with
542+
IncludeOptionalParameters = false
543+
GrammarOutputDirectoryPath = Some grammarOutputDirectoryPath
544+
ResolveBodyDependencies = false
545+
UseBodyExamples = Some true
546+
UseQueryExamples = Some true
547+
DataFuzzing = true
548+
SwaggerSpecFilePath = Some [(Path.Combine(Environment.CurrentDirectory, @"swagger\exampleTests\body_param.json"))]
549+
}
550+
551+
let exampleConfigFile = {
552+
filePath = Path.Combine(Environment.CurrentDirectory, @"swagger\exampleTests\body_param_example.json")
553+
exactCopy = true
554+
}
555+
556+
let testConfig = { config with ExampleConfigFiles = Some [ exampleConfigFile ] }
557+
Restler.Workflow.generateRestlerGrammar None testConfig
558+
559+
let expectedGrammarFilePath = Path.Combine(Environment.CurrentDirectory,
560+
@"baselines\exampleTests\body_param_exactCopy_grammar.py")
561+
let actualGrammarFilePath = Path.Combine(grammarOutputDirectoryPath,
562+
Restler.Workflow.Constants.DefaultRestlerGrammarFileName)
563+
let grammarDiff = getLineDifferences expectedGrammarFilePath actualGrammarFilePath
564+
let message = sprintf "Grammar Does not match baseline. First difference: %A" grammarDiff
565+
Assert.True(grammarDiff.IsNone, message)
566+
567+
///// Test that the grammar is correct when the entire body is replaced by an example payload.
568+
///// Both 'exactCopy' settings should be tested.
569+
//[<Fact>]
570+
//let ``replace entire body with example`` () =
571+
// let grammarOutputDirectoryPath = ctx.testRootDirPath
572+
573+
// let customDictionaryText = "{ \"restler_custom_payload\":\
574+
// { \"/subnets/{subnetName}/get/__body__\": [\"abc\"] } }\
575+
// "
576+
// // TODO: passing in the dictionary directly via 'SwaggerSpecConfig' is not working.
577+
// // Write out the dictionary until the but is fixed
578+
// //
579+
// let dictionaryFilePath =
580+
// Path.Combine(grammarOutputDirectoryPath,
581+
// "input_dict.json")
582+
// File.WriteAllText(dictionaryFilePath, customDictionaryText)
583+
584+
// let config = { Restler.Config.SampleConfig with
585+
// IncludeOptionalParameters = true
586+
// GrammarOutputDirectoryPath = Some grammarOutputDirectoryPath
587+
// ResolveBodyDependencies = true
588+
// UseBodyExamples = Some true
589+
// SwaggerSpecFilePath = Some [Path.Combine(Environment.CurrentDirectory, @"swagger\dependencyTests\subnet_id.json")]
590+
// AllowGetProducers = true
591+
// CustomDictionaryFilePath = Some dictionaryFilePath
592+
// }
593+
594+
// Restler.Workflow.generateRestlerGrammar None config
595+
596+
// let grammarFilePath = Path.Combine(grammarOutputDirectoryPath,
597+
// Restler.Workflow.Constants.DefaultRestlerGrammarFileName)
598+
// let grammar = File.ReadAllText(grammarFilePath)
599+
600+
// Assert.True(grammar.Contains("""restler_custom_payload("/subnets/{subnetName}/get/__body__", quoted=False)"""))
601+
602+
535603
interface IClassFixture<Fixtures.TestSetupAndCleanup>

src/compiler/Restler.Compiler.Test/Restler.Compiler.Test.fsproj

+10-1
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,10 @@
5858
<Content Include="baselines\exampleTests\array_example_grammar.py">
5959
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
6060
</Content>
61-
<Content Include="baselines\dependencyTests\path_in_dictionary_payload_grammar.py">
61+
<Content Include="baselines\exampleTests\body_param_exactCopy_grammar.py">
62+
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
63+
</Content>
64+
<Content Include="baselines\dependencyTests\path_in_dictionary_payload_grammar.py">
6265
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
6366
</Content>
6467
<Content Include="baselines\dependencyTests\header_response_writer_grammar.py">
@@ -236,6 +239,12 @@
236239
<Content Include="swagger\ExampleTests\optional_params_example.json">
237240
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
238241
</Content>
242+
<Content Include="swagger\ExampleTests\body_param.json">
243+
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
244+
</Content>
245+
<Content Include="swagger\ExampleTests\body_param_example.json">
246+
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
247+
</Content>
239248
<Content Include="swagger\get_path_dependencies.json">
240249
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
241250
</Content>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
""" THIS IS AN AUTOMATICALLY GENERATED FILE!"""
2+
from __future__ import print_function
3+
import json
4+
from engine import primitives
5+
from engine.core import requests
6+
from engine.errors import ResponseParsingException
7+
from engine import dependencies
8+
req_collection = requests.RequestCollection([])
9+
# Endpoint: /products, method: Post
10+
request = requests.Request([
11+
primitives.restler_static_string("POST "),
12+
primitives.restler_basepath("/api"),
13+
primitives.restler_static_string("/"),
14+
primitives.restler_static_string("products"),
15+
primitives.restler_static_string(" HTTP/1.1\r\n"),
16+
primitives.restler_static_string("Accept: application/json\r\n"),
17+
primitives.restler_static_string("Host: localhost:8888\r\n"),
18+
primitives.restler_static_string("Content-Type: "),
19+
primitives.restler_static_string("application/json"),
20+
primitives.restler_static_string("\r\n"),
21+
primitives.restler_refreshable_authentication_token("authentication_token_tag"),
22+
primitives.restler_static_string("\r\n"),
23+
primitives.restler_static_string("<xml><label>banana</label></xml>"),
24+
primitives.restler_static_string("\r\n"),
25+
26+
],
27+
requestId="/products"
28+
)
29+
req_collection.add_request(request)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
{
2+
"basePath": "/api",
3+
"consumes": [
4+
"application/json"
5+
],
6+
"host": "localhost:8888",
7+
"info": {
8+
"description": "Simple API with required and optional parameters.",
9+
"title": "The title.",
10+
"version": "1.0.0"
11+
},
12+
"definitions": {
13+
"Product": {
14+
"xml": {
15+
"name": "Product"
16+
},
17+
"properties": {
18+
"label": {
19+
"type": "string"
20+
},
21+
"expiration": {
22+
"type": "string",
23+
"format": "date"
24+
}
25+
}
26+
}
27+
},
28+
"paths": {
29+
"/products": {
30+
"post": {
31+
"parameters": [
32+
{
33+
"name": "orderDetails",
34+
"in": "body",
35+
"required": true,
36+
"schema": {
37+
"$ref": "#/definitions/Product"
38+
}
39+
}
40+
41+
],
42+
"responses": {
43+
"200": {
44+
"description": "Success"
45+
}
46+
}
47+
}
48+
}
49+
},
50+
"swagger": "2.0"
51+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
{
2+
"paths": {
3+
"/products": {
4+
"post": {
5+
"1": {
6+
"parameters": {
7+
"__body__": "<xml><label>banana</label></xml>"
8+
}
9+
}
10+
}
11+
}
12+
}
13+
}

src/compiler/Restler.Compiler/Compiler.fs

+12-5
Original file line numberDiff line numberDiff line change
@@ -296,12 +296,19 @@ module private Parameters =
296296
if examplePayload.exactCopy then
297297
let payload =
298298
let primitiveType =
299-
match payloadValue.Type with
300-
| JTokenType.Array
301-
| JTokenType.Object ->
299+
// If the example is for the body, it should
300+
// be treated as an object. This covers cases when
301+
// the example is for a content type other than json, so it
302+
// needs to be provided as a string in the example file.
303+
if declaredParameter.Kind = OpenApiParameterKind.Body then
302304
PrimitiveType.Object
303-
| _ ->
304-
PrimitiveType.String
305+
else
306+
match payloadValue.Type with
307+
| JTokenType.Array
308+
| JTokenType.Object ->
309+
PrimitiveType.Object
310+
| _ ->
311+
PrimitiveType.String
305312
let formattedPayloadValue = GenerateGrammarElements.formatJTokenProperty primitiveType payloadValue
306313
Constant (primitiveType, formattedPayloadValue)
307314

src/compiler/Restler.Compiler/SwaggerVisitors.fs

+3-1
Original file line numberDiff line numberDiff line change
@@ -355,7 +355,9 @@ module SwaggerVisitors =
355355
| PrimitiveType.String
356356
| PrimitiveType.DateTime
357357
| PrimitiveType.Enum (_, PrimitiveType.String, _, _)
358-
| PrimitiveType.Uuid ->
358+
| PrimitiveType.Uuid
359+
// Special case: non-Json bodies (e.g. text, xml) should not be quoted
360+
| PrimitiveType.Object when (rawValue.[0] = ''' || rawValue.[0] = '"') ->
359361
// Remove the start and end quotes, which are preserved with 'Formatting.None'.
360362
if rawValue.Length > 1 then
361363
match rawValue.[0], rawValue.[rawValue.Length-1] with

0 commit comments

Comments
 (0)