Support input dependencies based on annotations for any variable type. (#450)

Before this change, only 'restler_custom_payload_uuid4_suffix' could have
an associated input-only producer.

Now, any parameter that can be annotated may be associated with an
input-only producer.

Testing:
- Manual testing: modified demo_server to have a writer.
- Added unit test
This commit is contained in:
marina-p 2022-01-27 15:56:57 -08:00 коммит произвёл GitHub
Родитель 662a9e86d8
Коммит 14d4c7ad50
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
16 изменённых файлов: 570 добавлений и 287 удалений

Просмотреть файл

@ -181,8 +181,8 @@ def des_param_payload(param_payload_json, tag='', body_param=True):
is_dynamic_object = False
if 'Fuzzable' in payload:
content_type = payload['Fuzzable'][0]
content_value = payload['Fuzzable'][1]
content_type = payload['Fuzzable']['primitiveType']
content_value = payload['Fuzzable']['defaultValue']
fuzzable = True
elif 'Constant' in payload:
content_type = payload['Constant'][0]

Просмотреть файл

@ -136,12 +136,11 @@
"LeafNode": {
"name": "population",
"payload": {
"Fuzzable": [
"Int",
"1000",
null,
"population"
]
"Fuzzable": {
"primitiveType": "Int",
"defaultValue": "1000",
"parameterName": "population"
}
},
"isRequired": false,
"isReadOnly": false
@ -164,10 +163,11 @@
"LeafNode": {
"name": "strtest",
"payload": {
"Fuzzable": [
"String",
"true"
]
"Fuzzable": {
"primitiveType": "String",
"defaultValue": "true",
"parameterName": "population"
}
},
"isRequired": true,
"isReadOnly": false
@ -247,8 +247,8 @@
"LeafNode": {
"name": "",
"payload": {
"Fuzzable": [
{
"Fuzzable": {
"primitiveType": {
"Enum": [
"group",
"String",
@ -260,8 +260,8 @@
null
]
},
"A"
]
"defaultValue": "A"
}
}
}
}
@ -482,8 +482,8 @@
"LeafNode": {
"name": "group",
"payload": {
"Fuzzable": [
{
"Fuzzable": {
"primitiveType": {
"Enum": [
"group",
"String",
@ -495,8 +495,8 @@
null
]
},
"A"
]
"defaultValue": "A"
}
}
}
}
@ -1524,11 +1524,11 @@
"LeafNode": {
"name": "testbool",
"payload": {
"Fuzzable": [
"Bool",
"testval",
false
]
"Fuzzable": {
"primitiveType": "Bool",
"defaultValue": "testval",
"exampleValue": "false"
}
},
"isRequired": true,
"isReadOnly": false
@ -2150,10 +2150,10 @@
"LeafNode": {
"name": "",
"payload": {
"Fuzzable": [
"DateTime",
"2020-1-1"
]
"Fuzzable": {
"primitiveType": "DateTime",
"defaultValue": "2020-1-1"
}
},
"isRequired": true,
"isReadOnly": false
@ -2185,10 +2185,10 @@
"LeafNode": {
"name": "datetest",
"payload": {
"Fuzzable": [
"DateTime",
"2020-1-1"
]
"Fuzzable": {
"primitiveType": "DateTime",
"defaultValue": "2020-1-1"
}
},
"isRequired": false,
"isReadOnly": false

Просмотреть файл

@ -114,10 +114,10 @@
"LeafNode": {
"name": "population",
"payload": {
"Fuzzable": [
"Int",
"1000"
]
"Fuzzable": {
"primitiveType": "Int",
"defaultValue": "1000"
}
},
"isRequired": false,
"isReadOnly": false
@ -140,10 +140,10 @@
"LeafNode": {
"name": "strtest",
"payload": {
"Fuzzable": [
"String",
"true"
]
"Fuzzable": {
"primitiveType": "String",
"defaultValue": "true"
}
},
"isRequired": true,
"isReadOnly": false
@ -171,10 +171,10 @@
"LeafNode": {
"name": "subtest",
"payload": {
"Fuzzable": [
"Bool",
"true"
]
"Fuzzable": {
"primitiveType": "Bool",
"defaultValue": "true"
}
},
"isRequired": false,
"isReadOnly": false
@ -265,8 +265,10 @@
"LeafNode": {
"name": "",
"payload": {
"Fuzzable": [
{
"Fuzzable": {
"primitiveType":
{
"Enum": [
"group",
"String",
@ -278,8 +280,8 @@
null
]
},
"A"
]
"defaultValue": "A"
}
}
}
}
@ -508,7 +510,8 @@
"LeafNode": {
"name": "group",
"payload": {
"Fuzzable": [
"Fuzzable": {
"primitiveType":
{
"Enum": [
"group",
@ -521,8 +524,8 @@
null
]
},
"A"
]
"defaultValue": "A"
}
}
}
}

Просмотреть файл

@ -324,7 +324,7 @@ module Dependencies =
ResolveBodyDependencies = true
UseBodyExamples = Some true
SwaggerSpecFilePath = Some [(Path.Combine(Environment.CurrentDirectory, @"swagger\dependencyTests\input_producer_spec.json"))]
CustomDictionaryFilePath = None
CustomDictionaryFilePath = Some (Path.Combine(Environment.CurrentDirectory, @"swagger\dependencyTests\input_producer_dict.json"))
AnnotationFilePath = Some (Path.Combine(Environment.CurrentDirectory, @"swagger\dependencyTests\input_producer_annotations.json"))
AllowGetProducers = true
}
@ -337,6 +337,20 @@ module Dependencies =
Assert.True(grammar.Contains("""restler_custom_payload_uuid4_suffix("fileId", writer=_file__fileId__post_fileId_path.writer())"""))
Assert.True(grammar.Contains("""restler_static_string(_file__fileId__post_fileId_path.reader(), quoted=False)"""))
// Validate (tag, label) annotation. tag - body producer (jsonpath), label: path parameter.
Assert.True(grammar.Contains("""primitives.restler_custom_payload("tag", quoted=True, writer=_archive_post_tag.writer())"""))
Assert.True(grammar.Contains("""restler_static_string(_archive_post_tag.reader(), quoted=True)"""))
// Validate (name, name) annotation. name - body producer (POST) and consumer (PUT).
Assert.True(grammar.Contains("""primitives.restler_fuzzable_object("{ \"fuzz\": false }", writer=_archive_post_name.writer())"""))
Assert.True(grammar.Contains("""primitives.restler_static_string(_archive_post_name.reader(), quoted=False)"""))
// Validate (hash, sig) annotation. hash - header producer (POST), sig - header consumer (PUT)
Assert.True(grammar.Contains("""primitives.restler_custom_payload_query("hash", writer=_archive_post_hash_query.writer())"""))
Assert.True(grammar.Contains("""primitives.restler_static_string(_archive_post_hash_query.reader(), quoted=False)"""))
/// Test that the entire body should be able to be replaced with a custom payload
/// from the dictionary

Просмотреть файл

@ -76,6 +76,9 @@
<Content Include="swagger\dependencyTests\input_producer_spec.json">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="swagger\dependencyTests\input_producer_dict.json">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="swagger\dependencyTests\input_producer_annotations.json">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>

Просмотреть файл

@ -43,12 +43,10 @@
"LeafNode": {
"name": "name",
"payload": {
"Fuzzable": [
"String",
"fuzzstring",
null,
null
]
"Fuzzable": {
"primitiveType": "String",
"defaultValue": "fuzzstring"
}
},
"isRequired": false,
"isReadOnly": false
@ -58,12 +56,10 @@
"LeafNode": {
"name": "tags",
"payload": {
"Fuzzable": [
"Object",
"{ \"fuzz\": false }",
null,
null
]
"Fuzzable": {
"primitiveType": "Object",
"defaultValue": "{ \"fuzz\": false }"
}
},
"isRequired": false,
"isReadOnly": false
@ -159,12 +155,10 @@
"LeafNode": {
"name": "",
"payload": {
"Fuzzable": [
"String",
"fuzzstring",
null,
null
]
"Fuzzable": {
"primitiveType": "String",
"defaultValue": "fuzzstring"
}
},
"isRequired": false,
"isReadOnly": false
@ -198,12 +192,10 @@
"LeafNode": {
"name": "name",
"payload": {
"Fuzzable": [
"String",
"fuzzstring",
null,
null
]
"Fuzzable": {
"primitiveType": "String",
"defaultValue": "fuzzstring"
}
},
"isRequired": true,
"isReadOnly": false
@ -213,12 +205,10 @@
"LeafNode": {
"name": "tags",
"payload": {
"Fuzzable": [
"Object",
"{ \"fuzz\": false }",
null,
null
]
"Fuzzable": {
"primitiveType": "Object",
"defaultValue": "{ \"fuzz\": false }"
}
},
"isRequired": false,
"isReadOnly": false
@ -246,12 +236,10 @@
"LeafNode": {
"name": "name",
"payload": {
"Fuzzable": [
"String",
"fuzzstring",
null,
null
]
"Fuzzable": {
"primitiveType": "String",
"defaultValue": "fuzzstring"
}
},
"isRequired": false,
"isReadOnly": false
@ -261,12 +249,10 @@
"LeafNode": {
"name": "id",
"payload": {
"Fuzzable": [
"Number",
"1.23",
null,
null
]
"Fuzzable": {
"primitiveType": "Number",
"defaultValue": "1.23"
}
},
"isRequired": true,
"isReadOnly": false
@ -306,12 +292,10 @@
"LeafNode": {
"name": "",
"payload": {
"Fuzzable": [
"String",
"fuzzstring",
null,
null
]
"Fuzzable": {
"primitiveType": "String",
"defaultValue": "fuzzstring"
}
},
"isRequired": false,
"isReadOnly": false

Просмотреть файл

@ -70,8 +70,8 @@
"LeafNode": {
"name": "",
"payload": {
"Fuzzable": [
{
"Fuzzable": {
"primitiveType": {
"Enum": [
"api-version",
"String",
@ -81,10 +81,8 @@
null
]
},
"2020-03-01",
null,
null
]
"defaultValue": "2020-03-01"
}
},
"isRequired": true,
"isReadOnly": false
@ -215,8 +213,8 @@
"LeafNode": {
"name": "",
"payload": {
"Fuzzable": [
{
"Fuzzable": {
"primitiveType": {
"Enum": [
"api-version",
"String",
@ -226,10 +224,8 @@
null
]
},
"2020-03-01",
null,
null
]
"defaultValue": "2020-03-01"
}
},
"isRequired": true,
"isReadOnly": false
@ -381,8 +377,8 @@
"LeafNode": {
"name": "",
"payload": {
"Fuzzable": [
{
"Fuzzable": {
"primitiveType": {
"Enum": [
"api-version",
"String",
@ -392,10 +388,8 @@
null
]
},
"2020-03-01",
null,
null
]
"defaultValue": "2020-03-01"
}
},
"isRequired": true,
"isReadOnly": false
@ -443,12 +437,10 @@
}
},
{
"Fuzzable": [
"String",
"fuzzstring",
null,
null
]
"Fuzzable": {
"primitiveType": "String",
"defaultValue": "fuzzstring"
}
}
],
"queryParameters": [
@ -478,8 +470,8 @@
"LeafNode": {
"name": "",
"payload": {
"Fuzzable": [
{
"Fuzzable": {
"primitiveType": {
"Enum": [
"api-version",
"String",
@ -489,10 +481,8 @@
null
]
},
"2020-03-01",
null,
null
]
"defaultValue": "2020-03-01"
}
},
"isRequired": true,
"isReadOnly": false
@ -540,12 +530,10 @@
}
},
{
"Fuzzable": [
"String",
"fuzzstring",
null,
null
]
"Fuzzable": {
"primitiveType": "String",
"defaultValue": "fuzzstring"
}
}
],
"queryParameters": [
@ -575,8 +563,8 @@
"LeafNode": {
"name": "",
"payload": {
"Fuzzable": [
{
"Fuzzable": {
"primitiveType": {
"Enum": [
"api-version",
"String",
@ -586,10 +574,8 @@
null
]
},
"2020-03-01",
null,
null
]
"defaultValue": "2020-03-01"
}
},
"isRequired": true,
"isReadOnly": false

Просмотреть файл

@ -5,6 +5,30 @@
"producer_method": "POST",
"producer_resource_name": "fileId",
"consumer_param": "fileId"
},
{
"producer_endpoint": "/archive",
"producer_method": "POST",
"producer_resource_name": "hash",
"consumer_param": "sig"
},
{
"producer_endpoint": "/archive",
"producer_method": "POST",
"producer_resource_name": "/tag",
"consumer_param": "label"
},
{
"producer_endpoint": "/archive",
"producer_method": "POST",
"producer_resource_name": "/tag",
"consumer_param": "/tag"
},
{
"producer_endpoint": "/archive",
"producer_method": "POST",
"producer_resource_name": "/name",
"consumer_param": "/name"
}
]
}

Просмотреть файл

@ -0,0 +1,9 @@
{
"restler_custom_payload": {
"sig": [ "12345" ],
"tag": ["important"]
},
"restler_custom_payload_query": {
"hash": [ "56789" ]
}
}

Просмотреть файл

@ -13,10 +13,98 @@
"fileId":{
"type": "String",
"description": "the file id"
},
"Archive": {
"properties": {
"name": {
"type": "object"
},
"tag": {
"type": "string"
}
}
}
},
"paths": {
"/archive/{archiveId}/{label}": {
"get": {
"parameters": [
{
"in": "path",
"name": "archiveId",
"required": true,
"type": "string"
},
{
"in": "path",
"name": "label",
"required": true,
"type": "string"
}
],
"responses": {
"200": {
"description": "Success"
}
}
}
},
"/archive": {
"post": {
"parameters": [
{
"in": "query",
"name": "hash",
"required": true,
"type": "number"
},
{
"in": "body",
"name": "bodyParam",
"required": true,
"schema": {
"$ref": "#/definitions/Archive"
}
}
],
"responses": {
"201": {
"description": "Success"
}
}
}
},
"/archive/{archiveId}": {
"put": {
"parameters": [
{
"in": "path",
"name": "archiveId",
"required": true,
"type": "String"
},
{
"in": "query",
"name": "sig",
"required": true,
"type": "number"
},
{
"in": "body",
"name": "bodyParam",
"required": true,
"schema": {
"$ref": "#/definitions/Archive"
}
}
],
"responses": {
"201": {
"description": "Success"
}
}
}
},
"/file/{fileId}": {
"post": {
"parameters": [

Просмотреть файл

@ -372,7 +372,10 @@ type Producer =
/// Currently, only assigning such values from the dictionary is supported.
/// The dictionary payload is an option type because it is only present when
/// the initial payload is being generated.
| InputParameter of InputOnlyProducer * DictionaryPayload option
/// (producer, dictionary payload, isWriter)
/// When 'isWriter' is true, this is a writer variable that should be generated
/// with the original payload.
| InputParameter of InputOnlyProducer * DictionaryPayload option * bool
| OrderingConstraintParameter of OrderingConstraintProducer

Просмотреть файл

@ -24,28 +24,31 @@ module Types =
trackedParameterName: string option
}
type DynamicObjectWriter =
| DynamicObjectWriter of string
/// RESTler grammar built-in types
/// IMPORTANT ! All primitives must be supported in restler/engine/primitives.py
type RequestPrimitiveType =
| Restler_static_string_constant of string
| Restler_static_string_variable of string * bool
| Restler_static_string_jtoken_delim of string
| Restler_fuzzable_string of RequestPrimitiveTypeData
| Restler_fuzzable_datetime of RequestPrimitiveTypeData
| Restler_fuzzable_date of RequestPrimitiveTypeData
| Restler_fuzzable_object of RequestPrimitiveTypeData
| Restler_fuzzable_string of RequestPrimitiveTypeData * DynamicObjectWriter option
| Restler_fuzzable_datetime of RequestPrimitiveTypeData * DynamicObjectWriter option
| Restler_fuzzable_date of RequestPrimitiveTypeData * DynamicObjectWriter option
| Restler_fuzzable_object of RequestPrimitiveTypeData * DynamicObjectWriter option
| Restler_fuzzable_delim of RequestPrimitiveTypeData
| Restler_fuzzable_uuid4 of RequestPrimitiveTypeData
| Restler_fuzzable_group of RequestPrimitiveTypeData
| Restler_fuzzable_bool of RequestPrimitiveTypeData
| Restler_fuzzable_int of RequestPrimitiveTypeData
| Restler_fuzzable_number of RequestPrimitiveTypeData
| Restler_fuzzable_uuid4 of RequestPrimitiveTypeData * DynamicObjectWriter option
| Restler_fuzzable_group of RequestPrimitiveTypeData * DynamicObjectWriter option
| Restler_fuzzable_bool of RequestPrimitiveTypeData * DynamicObjectWriter option
| Restler_fuzzable_int of RequestPrimitiveTypeData * DynamicObjectWriter option
| Restler_fuzzable_number of RequestPrimitiveTypeData * DynamicObjectWriter option
| Restler_multipart_formdata of string
| Restler_custom_payload of RequestPrimitiveTypeData
| Restler_custom_payload_header of string
| Restler_custom_payload_query of string
| Restler_custom_payload of RequestPrimitiveTypeData * DynamicObjectWriter option
| Restler_custom_payload_header of string * DynamicObjectWriter option
| Restler_custom_payload_query of string * DynamicObjectWriter option
/// (Payload name, dynamic object writer name)
| Restler_custom_payload_uuid4_suffix of string * string option
| Restler_custom_payload_uuid4_suffix of string * DynamicObjectWriter option
| Restler_refreshable_authentication_token of string
| Restler_basepath of string
| Shadow_values of string
@ -72,20 +75,27 @@ let rec getRestlerPythonPayload (payload:FuzzingPayload) (isQuoted:bool) : Reque
match p with
| Constant (t,v) ->
Restler_static_string_constant v
| Fuzzable (t,v,exv,parameterName) ->
match t with
| Bool -> Restler_fuzzable_bool { defaultValue = v ; isQuoted = false ; exampleValue = exv ; trackedParameterName = parameterName }
| Fuzzable fp ->
let v = fp.defaultValue
let exv = fp.exampleValue
let parameterName = fp.parameterName
let dynamicObject = if fp.dynamicObject.IsSome then Some (DynamicObjectWriter fp.dynamicObject.Value.variableName) else None
match fp.primitiveType with
| Bool ->
Restler_fuzzable_bool ({ defaultValue = v ; isQuoted = false ; exampleValue = exv ; trackedParameterName = parameterName }, dynamicObject)
| PrimitiveType.DateTime ->
Restler_fuzzable_datetime { defaultValue = v ; isQuoted = isQuoted ; exampleValue = exv ; trackedParameterName = parameterName }
Restler_fuzzable_datetime ({ defaultValue = v ; isQuoted = isQuoted ; exampleValue = exv ; trackedParameterName = parameterName }, dynamicObject)
| PrimitiveType.Date ->
Restler_fuzzable_date { defaultValue = v ; isQuoted = isQuoted ; exampleValue = exv ; trackedParameterName = parameterName }
Restler_fuzzable_date ({ defaultValue = v ; isQuoted = isQuoted ; exampleValue = exv ; trackedParameterName = parameterName }, dynamicObject)
| PrimitiveType.String ->
Restler_fuzzable_string { defaultValue = v ; isQuoted = isQuoted ; exampleValue = exv ; trackedParameterName = parameterName }
| PrimitiveType.Object -> Restler_fuzzable_object { defaultValue = v ; isQuoted = false ; exampleValue = exv ; trackedParameterName = parameterName }
| Int -> Restler_fuzzable_int { defaultValue = v ; isQuoted = false; exampleValue = exv ; trackedParameterName = parameterName }
| Number -> Restler_fuzzable_number { defaultValue = v ; isQuoted = false ; exampleValue = exv ; trackedParameterName = parameterName }
Restler_fuzzable_string ({ defaultValue = v ; isQuoted = isQuoted ; exampleValue = exv ; trackedParameterName = parameterName }, dynamicObject)
| PrimitiveType.Object -> Restler_fuzzable_object ({ defaultValue = v ; isQuoted = false ; exampleValue = exv ; trackedParameterName = parameterName }, dynamicObject)
| Int -> Restler_fuzzable_int ({ defaultValue = v ; isQuoted = false; exampleValue = exv ; trackedParameterName = parameterName }, dynamicObject)
| Number -> Restler_fuzzable_number ({ defaultValue = v ; isQuoted = false ; exampleValue = exv ; trackedParameterName = parameterName }, dynamicObject)
| Uuid ->
Restler_fuzzable_uuid4 { defaultValue = v ; isQuoted = isQuoted ; exampleValue = exv ; trackedParameterName = parameterName }
Restler_fuzzable_uuid4 ({ defaultValue = v ; isQuoted = isQuoted ; exampleValue = exv ; trackedParameterName = parameterName }, dynamicObject)
| PrimitiveType.Enum (enumPropertyName, _, enumeration, defaultValue) ->
let defaultStr =
match defaultValue with
@ -97,18 +107,19 @@ let rec getRestlerPythonPayload (payload:FuzzingPayload) (isQuoted:bool) : Reque
(enumeration |> List.map (fun s -> sprintf "'%s'" s) |> String.concat ",")
defaultStr
)
Restler_fuzzable_group
{ defaultValue = groupValue ; isQuoted = isQuoted ; exampleValue = exv ; trackedParameterName = parameterName }
Restler_fuzzable_group (
{ defaultValue = groupValue ; isQuoted = isQuoted ; exampleValue = exv ; trackedParameterName = parameterName }, dynamicObject)
| Custom c ->
let dynamicObject = if c.dynamicObject.IsSome then Some (DynamicObjectWriter c.dynamicObject.Value.variableName) else None
match c.payloadType with
| CustomPayloadType.String ->
Restler_custom_payload { defaultValue = c.payloadValue ; isQuoted = isQuoted ; exampleValue = None ; trackedParameterName = None }
Restler_custom_payload ({ defaultValue = c.payloadValue ; isQuoted = isQuoted ; exampleValue = None ; trackedParameterName = None }, dynamicObject)
| CustomPayloadType.UuidSuffix ->
Restler_custom_payload_uuid4_suffix (c.payloadValue, if c.dynamicObject.IsSome then Some c.dynamicObject.Value.variableName else None)
Restler_custom_payload_uuid4_suffix (c.payloadValue, dynamicObject)
| CustomPayloadType.Header ->
Restler_custom_payload_header c.payloadValue // TODO: need test
Restler_custom_payload_header (c.payloadValue, dynamicObject)
| CustomPayloadType.Query ->
Restler_custom_payload_query c.payloadValue // TODO: need test
Restler_custom_payload_query (c.payloadValue, dynamicObject)
| DynamicObject dv ->
Restler_static_string_variable (sprintf "%s.reader()" dv.variableName, isQuoted)
| PayloadParts p ->
@ -350,10 +361,10 @@ let generatePythonParameter includeOptionalParameters parameterKind (requestPara
| FuzzingPayload.Constant (primitiveType, v) ->
isPrimitiveTypeQuoted primitiveType (isNull v),
false, false
| FuzzingPayload.Fuzzable (primitiveType, _, _,_) ->
| FuzzingPayload.Fuzzable fp ->
// Note: this is a current RESTler limitation -
// fuzzable values may not be set to null without changing the grammar.
isPrimitiveTypeQuoted primitiveType false,
isPrimitiveTypeQuoted fp.primitiveType false,
true, false
| FuzzingPayload.DynamicObject dv ->
isPrimitiveTypeQuoted dv.primitiveType false,
@ -1065,6 +1076,12 @@ let getRequests(requests:Request list) includeOptionalParameters =
let quotedStr = sprintf "%s%s%s" exDelim exStr exDelim
sprintf ", param_name=%s" quotedStr
let formatDynamicObjectVariable (dynamicObject:DynamicObjectWriter option) =
match dynamicObject with
| None -> ""
| Some (DynamicObjectWriter v) ->
sprintf ", writer=%s.writer()" v
let str =
match p with
| Restler_static_string_jtoken_delim s ->
@ -1088,7 +1105,7 @@ let getRequests(requests:Request list) includeOptionalParameters =
sprintf "primitives.restler_static_string(%s, quoted=%s)"
s
(if isQuoted then "True" else "False")
| Restler_fuzzable_string s ->
| Restler_fuzzable_string (s, dynamicObject) ->
if String.IsNullOrEmpty s.defaultValue then
printfn "ERROR: fuzzable strings should not be empty. Skipping."
""
@ -1103,39 +1120,44 @@ let getRequests(requests:Request list) includeOptionalParameters =
(if s.isQuoted then "True" else "False")
exampleParameter
trackedParamName
| Restler_fuzzable_group s ->
| Restler_fuzzable_group (s, dynamicObject) ->
sprintf "primitives.restler_fuzzable_group(%s,quoted=%s%s)"
s.defaultValue
(if s.isQuoted then "True" else "False")
(getExamplePrimitiveParameter s.exampleValue)
| Restler_fuzzable_int s ->
sprintf "primitives.restler_fuzzable_int(\"%s\"%s%s)"
| Restler_fuzzable_int (s, dynamicObject) ->
sprintf "primitives.restler_fuzzable_int(\"%s\"%s%s%s)"
s.defaultValue
(getExamplePrimitiveParameter s.exampleValue)
(getTrackedParamPrimitiveParameter s.trackedParameterName)
| Restler_fuzzable_number s ->
sprintf "primitives.restler_fuzzable_number(\"%s\"%s%s)"
(formatDynamicObjectVariable dynamicObject)
| Restler_fuzzable_number (s, dynamicObject) ->
sprintf "primitives.restler_fuzzable_number(\"%s\"%s%s%s)"
s.defaultValue
(getExamplePrimitiveParameter s.exampleValue)
(getTrackedParamPrimitiveParameter s.trackedParameterName)
| Restler_fuzzable_bool s ->
sprintf "primitives.restler_fuzzable_bool(\"%s\"%s%s)"
(formatDynamicObjectVariable dynamicObject)
| Restler_fuzzable_bool (s, dynamicObject) ->
sprintf "primitives.restler_fuzzable_bool(\"%s\"%s%s%s)"
s.defaultValue
(getExamplePrimitiveParameter s.exampleValue)
(getTrackedParamPrimitiveParameter s.trackedParameterName)
| Restler_fuzzable_datetime s ->
sprintf "primitives.restler_fuzzable_datetime(\"%s\", quoted=%s%s%s)"
(formatDynamicObjectVariable dynamicObject)
| Restler_fuzzable_datetime (s, dynamicObject) ->
sprintf "primitives.restler_fuzzable_datetime(\"%s\", quoted=%s%s%s%s)"
s.defaultValue
(if s.isQuoted then "True" else "False")
(getExamplePrimitiveParameter s.exampleValue)
(getTrackedParamPrimitiveParameter s.trackedParameterName)
| Restler_fuzzable_date s ->
sprintf "primitives.restler_fuzzable_date(\"%s\", quoted=%s%s%s)"
(formatDynamicObjectVariable dynamicObject)
| Restler_fuzzable_date (s, dynamicObject) ->
sprintf "primitives.restler_fuzzable_date(\"%s\", quoted=%s%s%s%s)"
s.defaultValue
(if s.isQuoted then "True" else "False")
(getExamplePrimitiveParameter s.exampleValue)
(getTrackedParamPrimitiveParameter s.trackedParameterName)
| Restler_fuzzable_object s ->
(formatDynamicObjectVariable dynamicObject)
| Restler_fuzzable_object (s, dynamicObject) ->
if String.IsNullOrEmpty s.defaultValue then
printfn "ERROR: fuzzable objects should not be empty. Skipping."
""
@ -1144,31 +1166,35 @@ let getRequests(requests:Request list) includeOptionalParameters =
let quotedDefaultString =
sprintf "%s%s%s" delim str delim
let exampleParameter = getExamplePrimitiveParameter s.exampleValue
sprintf "primitives.restler_fuzzable_object(%s%s%s)"
sprintf "primitives.restler_fuzzable_object(%s%s%s%s)"
quotedDefaultString
exampleParameter
(getTrackedParamPrimitiveParameter s.trackedParameterName)
| Restler_fuzzable_uuid4 s ->
sprintf "primitives.restler_fuzzable_uuid4(\"%s\", quoted=%s%s%s)"
(formatDynamicObjectVariable dynamicObject)
| Restler_fuzzable_uuid4 (s, dynamicObject) ->
sprintf "primitives.restler_fuzzable_uuid4(\"%s\", quoted=%s%s%s%s)"
s.defaultValue
(if s.isQuoted then "True" else "False")
(getExamplePrimitiveParameter s.exampleValue)
(getTrackedParamPrimitiveParameter s.trackedParameterName)
| Restler_custom_payload p ->
sprintf "primitives.restler_custom_payload(\"%s\", quoted=%s)"
(formatDynamicObjectVariable dynamicObject)
| Restler_custom_payload (p, dynamicObject) ->
sprintf "primitives.restler_custom_payload(\"%s\", quoted=%s%s)"
p.defaultValue
(if p.isQuoted then "True" else "False")
| Restler_custom_payload_uuid4_suffix (p, variableName) ->
let variableNamePart =
match variableName with
| None -> ""
| Some vn ->
sprintf ", writer=%s.writer()" vn
sprintf "primitives.restler_custom_payload_uuid4_suffix(\"%s\"%s)" p variableNamePart
| Restler_custom_payload_header p ->
sprintf "primitives.restler_custom_payload_header(\"%s\")" p
| Restler_custom_payload_query q ->
sprintf "primitives.restler_custom_payload_query(\"%s\")" q
(formatDynamicObjectVariable dynamicObject)
| Restler_custom_payload_uuid4_suffix (p, dynamicObject) ->
sprintf "primitives.restler_custom_payload_uuid4_suffix(\"%s\"%s)"
p
(formatDynamicObjectVariable dynamicObject)
| Restler_custom_payload_header (p, dynamicObject) ->
sprintf "primitives.restler_custom_payload_header(\"%s\"%s)"
p
(formatDynamicObjectVariable dynamicObject)
| Restler_custom_payload_query (q, dynamicObject) ->
sprintf "primitives.restler_custom_payload_query(\"%s\"%s)"
q
(formatDynamicObjectVariable dynamicObject)
| Restler_refreshable_authentication_token tok ->
sprintf "primitives.restler_refreshable_authentication_token(\"%s\")" tok
| Restler_basepath bp ->

Просмотреть файл

@ -52,7 +52,7 @@ type UserSpecifiedRequestConfig =
let getWriterVariable (producer:Producer) (kind:DynamicObjectVariableKind) =
match producer with
| InputParameter (iop, _) ->
| InputParameter (iop, _, _) ->
{
requestId = iop.id.RequestId
accessPathParts = iop.getInputParameterAccessPath()
@ -133,7 +133,7 @@ let getResponseParsers (dependencies:seq<ProducerConsumerDependency>) (orderingC
match ro.id.ResourceReference with
| HeaderResource _ -> Some DynamicObjectVariableKind.Header
| _ -> Some DynamicObjectVariableKind.BodyResponseProperty
| InputParameter (_, _) ->
| InputParameter (_, _,_) ->
Some DynamicObjectVariableKind.InputParameter
| _ -> None
match writerVariableKind with
@ -496,11 +496,16 @@ module private Parameters =
match parameterPayload with
| LeafNode leafProperty ->
let leafNodePayload =
match leafProperty.payload with
| Fuzzable (Enum(propertyName, propertyType, values, defaultValue), x, y, z) ->
Fuzzable (Enum(p.Name, propertyType, values, defaultValue), x, y, z)
| Fuzzable (a, b, c, _) ->
Fuzzable (a, b, c, if trackParameters then Some p.Name else None)
| Fuzzable fp ->
match fp.primitiveType with
| Enum(propertyName, propertyType, values, defaultValue) ->
let primitiveType = PrimitiveType.Enum(p.Name, propertyType, values, defaultValue)
Fuzzable { fp with primitiveType = primitiveType }
| _ ->
Fuzzable {fp with
parameterName = if trackParameters then Some p.Name else None }
| _ -> leafProperty.payload
LeafNode { leafProperty with payload = leafNodePayload }
| InternalNode (internalNode, children) ->

Просмотреть файл

@ -463,27 +463,16 @@ let findProducerWithResourceName
else
Seq.empty
// If the consumer is exactly the same as the producer, then check if
// a custom payload is defined in the dictionary. If so, return the empty seq
// (the custom payload will be picked up later), and if not create a custom UUID suffix
let dictionary, inputOnlyProducer =
match inputOnlyProducers |> Seq.tryHead with
| None -> dictionary, None
| Some iop ->
if annotationProducerRequestId = consumer.id.RequestId then
// This is when the value is written
if dictionary.restler_custom_payload.Value.ContainsKey(consumerResourceName) then
dictionary, None // TODO: support custom payloads
else
let dictionary, suffixProducer = addUuidSuffixEntryForConsumer consumerResourceName dictionary consumer.id
match suffixProducer with
| Some (DictionaryPayload dp) ->
dictionary, Some (InputParameter(iop, Some dp))
| _ ->
raise (invalidOp("a suffix entry must be a dictionary payload"))
// This is the writer. This will be handled later.
dictionary, None
else
// Read the value - no associated dictionary payload
dictionary, Some (InputParameter(iop, None))
dictionary, Some (InputParameter(iop, None, false))
let annotationProducer =
[ responseProducers
@ -523,6 +512,56 @@ let findProducerWithResourceName
]
|> Seq.concat
// Check if this consumer is a writer for an input-only producer.
// If yes, this information must be added to the dictionary matches (if any).
let dictionary, inputProducerMatches =
match annotationProducer with
| Some _ -> dictionary, Seq.empty
| None ->
// Find the input-only producer corresponding to this consumer
let matchingInputOnlyProducers =
producers.getInputOnlyProducers(consumer.id.ResourceName)
let inputOnlyProducers =
matchingInputOnlyProducers
|> Seq.filter (fun p ->
p.id.RequestId = consumer.id.RequestId &&
p.id.ResourceReference = consumer.id.ResourceReference)
match inputOnlyProducers |> Seq.tryHead with
| Some iop ->
match [ dictionaryMatches ; uuidSuffixDictionaryMatches ] |> Seq.concat |> Seq.tryHead with
| Some p ->
// Add the dictionary payload
let dictionaryPayload =
match p with
| DictionaryPayload dp -> dp
| _ -> raise (invalidArg "dictionaryMatches" "A dictionary payload was expected.")
dictionary, InputParameter(iop, Some dictionaryPayload, true) |> stn
| None ->
// By default, create a custom_payload_uuid_suffix, so a different ID will be
// generated each time the value is written.
// TODO: This logic will only work for string types (e.g. names). It does not currently work for other types that
// need a unique value assigned (e.g. GUIDs and integers).
// Once a type is introduced for unique GUIDs and integers, this logic should be modified to create an
// appropriate dictionary entry that will direct RESTler to automatically generate unique values.
//
// If a dictionary payload is not returned below, a fuzzable payload will be generated as usual, and the
// fuzzed value will be asssigned to the producer (writer variable).
match consumer.id.PrimitiveType with
| PrimitiveType.String ->
let dictionary, suffixProducer =
addUuidSuffixEntryForConsumer consumerResourceName dictionary consumer.id
match suffixProducer with
| Some (DictionaryPayload dp) ->
dictionary, InputParameter(iop, Some dp, true) |> stn
| _ ->
raise (invalidOp("a suffix entry must be a dictionary payload"))
| _ ->
dictionary, InputParameter(iop, None, true) |> stn
| None ->
dictionary, Seq.empty
// Here the producers just match on the resource name. If the container also matches,
// it will match fully.
let inferredExactMatches = matchingResourceProducersByEndpoint
@ -618,6 +657,7 @@ let findProducerWithResourceName
else
dictionary,
[ if annotationProducer.IsSome then stn annotationProducer.Value else Seq.empty
inputProducerMatches
dictionaryMatches
uuidSuffixDictionaryMatches
inferredExactMatches
@ -783,7 +823,7 @@ let findAnnotation globalAnnotations
let getPayloadPrimitiveType (payload:FuzzingPayload) =
match payload with
| Constant (t,_) -> t
| Fuzzable (t,_,_,_) -> t
| Fuzzable fp -> fp.primitiveType
| Custom cp -> cp.primitiveType
| DynamicObject d -> d.primitiveType
| PayloadParts _ ->
@ -884,7 +924,7 @@ let getParameterDependencies parameterKind globalAnnotations
let resourceAccessPath = PropertyAccessPaths.getLeafAccessPath parentAccessPath p
let primitiveType =
match p.payload with
| FuzzingPayload.Fuzzable (pt, _, _,_) -> Some pt
| FuzzingPayload.Fuzzable fp -> Some fp.primitiveType
| FuzzingPayload.Constant (pt, _) -> Some pt
| FuzzingPayload.Custom c -> Some c.primitiveType
| _ -> None
@ -958,47 +998,52 @@ let createHeaderResponseProducer (requestId:RequestId) (headerParameterName:stri
let createInputOnlyProducerFromAnnotation (a:ProducerConsumerAnnotation)
(pathConsumers:(RequestId * seq<Consumer>) [])
(queryConsumers:(RequestId * seq<Consumer>) [])
(bodyConsumers:(RequestId * seq<Consumer>) []) =
(bodyConsumers:(RequestId * seq<Consumer>) [])
(headerConsumers:(RequestId * seq<Consumer>) [])=
let findConsumer (candidateConsumers:(RequestId * seq<Consumer>) []) resourceName =
let c = candidateConsumers
|> Array.tryFind (fun (reqId, _) -> reqId = a.producerId)
match c with
| None ->
// The consumer for the parameter was not found.
None
| Some (req, consumers) ->
consumers
|> Seq.tryFind (fun c -> c.id.ResourceName = resourceName)
// Find the producer in the list of consumers
match a.producerParameter.Value with
| ResourceName rn ->
if a.producerId.endpoint.Contains(sprintf "{%s}" rn) then
// Look for the corresponding path producer.
// This is needed to determine its type.
let pc = pathConsumers
|> Array.tryFind (fun (reqId, s) -> reqId = a.producerId)
let parameterKind, consumer =
if a.producerId.endpoint.Contains(sprintf "{%s}" rn) then
let pathConsumer = findConsumer pathConsumers rn
ParameterKind.Path, pathConsumer
else
// Check if this parameter name exists in the query or header.
let queryConsumer = findConsumer queryConsumers rn
if queryConsumer.IsSome then
ParameterKind.Query, queryConsumer
else
ParameterKind.Header, findConsumer headerConsumers rn
let pathConsumer =
match pc with
| None ->
// The consumer for the path parameter was not found.
None
| Some (req, consumers) ->
consumers
|> Seq.tryFind (fun c -> c.id.ResourceName = rn)
match consumer with
| None -> None
| Some c ->
// 'c' is the consumer that is the input producer.
// Its value will be written to a writer variable.
let resource = ApiResource(c.id.RequestId,
c.id.ResourceReference,
c.id.NamingConvention,
c.id.PrimitiveType)
let inputOnlyProducer =
{
InputOnlyProducer.id = resource
parameterKind = parameterKind
}
Some (rn, inputOnlyProducer)
match pathConsumer with
| None ->
// The consumer for the path parameter was not found.
None
| Some c ->
let resource = ApiResource(c.id.RequestId,
c.id.ResourceReference,
c.id.NamingConvention,
c.id.PrimitiveType)
let inputOnlyProducer =
{
InputOnlyProducer.id = resource
parameterKind = ParameterKind.Path
}
Some (rn, inputOnlyProducer)
else
// TODO: add query and header support
// Note: here, it is ambiguous whether this resource refers to a
// query or body resource without specifying the path. For a producer
// id, it should be required to specify a path to a body parameter.
printfn "Warning: Query parameter input producers are not currently supported (parameter %s not found in path)." rn
None
| ResourcePath accessPath ->
let bc = bodyConsumers
|> Array.tryFind (fun (reqId, s) -> reqId = a.producerId)
@ -1026,6 +1071,9 @@ let createInputOnlyProducerFromAnnotation (a:ProducerConsumerAnnotation)
InputOnlyProducer.id = resource
parameterKind = ParameterKind.Body
}
// The producer needs to be found both for the consumer parameter (reader)
// and for the producer parameter itself (writer)
Some (c.id.ResourceName, inputOnlyProducer)
@ -1216,10 +1264,11 @@ let extractDependencies (requestData:(RequestId*RequestData)[])
rd.localAnnotations
|> Seq.iter (fun a ->
if a.producerParameter.IsSome then
let ip = createInputOnlyProducerFromAnnotation a pathConsumers queryConsumers bodyConsumers
let ip = createInputOnlyProducerFromAnnotation a pathConsumers queryConsumers bodyConsumers headerConsumers
if ip.IsSome then
let resourceName, producer = ip.Value
producers.addInputOnlyProducer(resourceName, producer)
)
)
@ -1229,7 +1278,7 @@ let extractDependencies (requestData:(RequestId*RequestData)[])
globalAnnotations
|> Seq.iter (fun a ->
if a.producerParameter.IsSome then
let ip = createInputOnlyProducerFromAnnotation a pathConsumers queryConsumers bodyConsumers
let ip = createInputOnlyProducerFromAnnotation a pathConsumers queryConsumers bodyConsumers headerConsumers
if ip.IsSome then
let resourceName, producer = ip.Value
producers.addInputOnlyProducer(resourceName, producer)
@ -1485,12 +1534,12 @@ module DependencyLookup =
// Mark the type of the dynamic object to be the type of the input parameter if available
let primitiveType =
match defaultPayload with
| FuzzingPayload.Fuzzable (primitiveType, _, _, _) -> primitiveType
| FuzzingPayload.Fuzzable fp -> fp.primitiveType
| _ ->
printfn "Warning: primitive type not available for %A [resource: %s]" requestId consumerResourceName
responseProducer.id.PrimitiveType
DynamicObject { primitiveType = primitiveType; variableName = variableName; isWriter = false }
| Some (InputParameter (inputParameterProducer, dictionaryPayload)) ->
| Some (InputParameter (inputParameterProducer, dictionaryPayload, isWriter)) ->
let accessPath = inputParameterProducer.getInputParameterAccessPath()
let variableName = DynamicObjectNaming.generateDynamicObjectVariableName
@ -1499,14 +1548,24 @@ module DependencyLookup =
// Mark the type of the dynamic object to be the type of the input parameter if available
let primitiveType =
match defaultPayload with
| FuzzingPayload.Fuzzable (primitiveType, _, _, _) -> primitiveType
| FuzzingPayload.Fuzzable fp -> fp.primitiveType
| _ ->
printfn "Warning: primitive type not available for %A [resource: %s]" requestId consumerResourceName
inputParameterProducer.id.PrimitiveType
let dynamicObject =
{ primitiveType = primitiveType; variableName = variableName; isWriter = false }
match dictionaryPayload with
| None -> DynamicObject dynamicObject
| None ->
if isWriter then
match defaultPayload with
| Fuzzable fp ->
Fuzzable { fp with dynamicObject = Some dynamicObject }
| Custom cp ->
Custom { cp with dynamicObject = Some dynamicObject }
| _ ->
failwith "Input producers are not supported for this payload type."
else
DynamicObject dynamicObject
| Some dp ->
Custom { payloadType = dp.payloadType
primitiveType = dp.primitiveType
@ -1596,7 +1655,11 @@ module DependencyLookup =
else
let defaultPayload =
match p.payload with
| None -> Fuzzable (PrimitiveType.String, "", None, None)
| None -> Fuzzable { primitiveType = PrimitiveType.String
defaultValue = ""
exampleValue = None
parameterName = None
dynamicObject = None }
| Some p -> p
let propertyAccessPath =
{ path = PropertyAccessPaths.getInnerAccessPath resourceAccessPath p
@ -1620,14 +1683,24 @@ module DependencyLookup =
| Tree.LeafNode leafProperty ->
leafProperty.payload, leafProperty.isRequired, leafProperty.isReadOnly
| Tree.InternalNode (i, _) ->
let defaultFuzzablePayload =
{ primitiveType = PrimitiveType.String
defaultValue = ""
exampleValue = None
parameterName = None
dynamicObject = None }
let payload =
match i.propertyType with
| NestedType.Object ->
(Fuzzable (PrimitiveType.Object, "{}", None, None))
Fuzzable {defaultFuzzablePayload with
primitiveType = PrimitiveType.Object
defaultValue = "{}" }
| NestedType.Array ->
(Fuzzable (PrimitiveType.Object, "[]", None, None))
Fuzzable {defaultFuzzablePayload with
primitiveType = PrimitiveType.Object
defaultValue = "[]" }
| NestedType.Property ->
(Fuzzable (PrimitiveType.String, "", None, None))
Fuzzable defaultFuzzablePayload
payload, i.isRequired, i.isReadOnly
let dependencyPayload = getConsumerPayload dependencies pathPayload requestId parameterName EmptyAccessPath defaultPayload
@ -1728,7 +1801,7 @@ let writeDependencies dependenciesFilePath dependencies (unresolvedOnly:bool) =
rp.id.RequestId.endpoint,
getMethod rp.id,
getParameter rp.id
| Some (InputParameter (ip, dp)) -> // TODO: what to serialize?
| Some (InputParameter (ip, dp, _)) -> // TODO: what to serialize?
ip.id.RequestId.endpoint,
getMethod ip.id,
getParameter ip.id

Просмотреть файл

@ -166,6 +166,26 @@ type CustomPayload =
dynamicObject: DynamicObject option
}
type FuzzablePayload =
{
/// The primitive type of the payload, as declared in the specification
primitiveType : PrimitiveType
/// The default value of the payload
defaultValue : string
/// The example value specified in the spec, if any
exampleValue : string option
/// The parameter name, if available.
parameterName : string option
/// The associated dynamic object, whose value should be
/// assigned to the value generated from this payload.
/// For example, an input value from a request body property.
dynamicObject: DynamicObject option
}
/// The payload for a property specified in as a request parameter
type FuzzingPayload =
/// Example: (Int "1")
@ -173,7 +193,7 @@ type FuzzingPayload =
/// (data type, default value, example value, parameter name)
/// Example: (Int "1", "2")
| Fuzzable of PrimitiveType * string * string option * string option
| Fuzzable of FuzzablePayload
/// The custom payload, as specified in the fuzzing dictionary
| Custom of CustomPayload

Просмотреть файл

@ -119,7 +119,16 @@ module SchemaUtilities =
let getFuzzableValueForObjectType (objectType:NJsonSchema.JsonObjectType) (format:string) (exampleValue: string option) (propertyName: string option)
(trackParameters:bool) =
Fuzzable (getGrammarPrimitiveTypeWithDefaultValue objectType format exampleValue propertyName trackParameters)
let primitiveType, defaultValue, exampleValue, propertyName =
getGrammarPrimitiveTypeWithDefaultValue objectType format exampleValue propertyName trackParameters
Fuzzable
{
primitiveType = primitiveType
defaultValue = defaultValue
exampleValue = exampleValue
parameterName = propertyName
dynamicObject = None
}
/// Get a boolean property from 'ExtensionData', if it exists.
let getExtensionDataBooleanPropertyValue (extensionData:System.Collections.Generic.IDictionary<string, obj>) (extensionDataKeyName:string) =
@ -224,7 +233,14 @@ module SwaggerVisitors =
match enumValues with
| [] -> "null"
| h::rest -> h
Fuzzable (PrimitiveType.Enum (propertyName, grammarPrimitiveType, enumValues, defaultValue), defaultFuzzableEnumValue, exv, None)
Fuzzable
{
primitiveType = PrimitiveType.Enum (propertyName, grammarPrimitiveType, enumValues, defaultValue)
defaultValue = defaultFuzzableEnumValue
exampleValue = exv
parameterName = None
dynamicObject = None
}
| NJsonSchema.JsonObjectType.Object
| NJsonSchema.JsonObjectType.None ->
// Example of JsonObjectType.None: "content": {} without a type specified in Swagger.
@ -232,7 +248,14 @@ module SwaggerVisitors =
getFuzzableValueForObjectType NJsonSchema.JsonObjectType.Object propertySchema.Format exampleValue (Some propertyName) trackParameters
| NJsonSchema.JsonObjectType.File ->
// Fuzz it as a string.
Fuzzable (PrimitiveType.String, "file object", None, if trackParameters then Some propertyName else None)
Fuzzable
{
primitiveType = PrimitiveType.String
defaultValue = "file object"
exampleValue = None
parameterName = if trackParameters then Some propertyName else None
dynamicObject = None
}
| nst ->
raise (UnsupportedType (sprintf "Unsupported type formatting: %A" nst))
{ LeafProperty.name = propertyName; payload = payload ;isRequired = isRequired ; isReadOnly = isReadOnly }
@ -255,8 +278,8 @@ module SwaggerVisitors =
| LeafNode leafProperty ->
let payload = leafProperty.payload
match payload with
| Fuzzable(a, b, c, _) ->
let payload = Fuzzable (a, b, c, Some paramName)
| Fuzzable fp ->
let payload = Fuzzable { fp with parameterName = Some paramName }
LeafNode { leafProperty with LeafProperty.payload = payload }
| x -> tree
| InternalNode (_,_) -> tree
@ -383,15 +406,15 @@ module SwaggerVisitors =
| Some v ->
let examplePropertyPayload =
match fuzzablePropertyPayload.payload with
| Fuzzable (primitiveType, defaultValue, _, propertyName) ->
let payloadValue = GenerateGrammarElements.formatJTokenProperty primitiveType v
| Fuzzable fp ->
let payloadValue = GenerateGrammarElements.formatJTokenProperty fp.primitiveType v
// Replace the default payload with the example payload, preserving type information.
// 'generateFuzzablePayload' is specified a schema example is found for the parent
// object (e.g. an array).
if generateFuzzablePayload then
Fuzzable (primitiveType, defaultValue, Some payloadValue, propertyName)
Fuzzable { fp with exampleValue = Some payloadValue }
else
Constant (primitiveType, payloadValue)
Constant (fp.primitiveType, payloadValue)
| _ -> raise (invalidOp(sprintf "invalid payload %A, expected fuzzable" fuzzablePropertyPayload))
{ fuzzablePropertyPayload with payload = examplePropertyPayload }
@ -507,7 +530,14 @@ module SwaggerVisitors =
match s.Type with
| JsonObjectType.Object ->
// Do not insert a default fuzzable property for objects
Fuzzable (PrimitiveType.Object, "{ }", None, None)
Fuzzable
{
primitiveType = PrimitiveType.Object
defaultValue = "{ }"
exampleValue = None
parameterName = None
dynamicObject = None
}
| _ ->
getFuzzableValueForObjectType s.Item.Type s.Format None None trackParameters
@ -523,7 +553,15 @@ module SwaggerVisitors =
else
Some (getValueForObjectType schema.Item)
| JsonObjectType.None ->
Some (Fuzzable (PrimitiveType.Object, "{ }", None, None))
let fp =
{
primitiveType = PrimitiveType.Object
defaultValue = "{ }"
exampleValue = None
parameterName = None
dynamicObject = None
}
Some (Fuzzable fp)
| _ ->
Some (getValueForObjectType schema)
@ -733,7 +771,14 @@ module SwaggerVisitors =
let leafPayload =
let exampleValue = GenerateGrammarElements.formatJTokenProperty primitiveType v
if generateFuzzablePayloadsForExamples then
FuzzingPayload.Fuzzable (primitiveType, defaultValue, Some exampleValue, None)
FuzzingPayload.Fuzzable
{
primitiveType = primitiveType
defaultValue = defaultValue
exampleValue = Some exampleValue
parameterName = None
dynamicObject = None
}
else
FuzzingPayload.Constant (primitiveType, exampleValue)