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:
Родитель
662a9e86d8
Коммит
14d4c7ad50
|
@ -181,8 +181,8 @@ def des_param_payload(param_payload_json, tag='', body_param=True):
|
||||||
is_dynamic_object = False
|
is_dynamic_object = False
|
||||||
|
|
||||||
if 'Fuzzable' in payload:
|
if 'Fuzzable' in payload:
|
||||||
content_type = payload['Fuzzable'][0]
|
content_type = payload['Fuzzable']['primitiveType']
|
||||||
content_value = payload['Fuzzable'][1]
|
content_value = payload['Fuzzable']['defaultValue']
|
||||||
fuzzable = True
|
fuzzable = True
|
||||||
elif 'Constant' in payload:
|
elif 'Constant' in payload:
|
||||||
content_type = payload['Constant'][0]
|
content_type = payload['Constant'][0]
|
||||||
|
|
|
@ -136,12 +136,11 @@
|
||||||
"LeafNode": {
|
"LeafNode": {
|
||||||
"name": "population",
|
"name": "population",
|
||||||
"payload": {
|
"payload": {
|
||||||
"Fuzzable": [
|
"Fuzzable": {
|
||||||
"Int",
|
"primitiveType": "Int",
|
||||||
"1000",
|
"defaultValue": "1000",
|
||||||
null,
|
"parameterName": "population"
|
||||||
"population"
|
}
|
||||||
]
|
|
||||||
},
|
},
|
||||||
"isRequired": false,
|
"isRequired": false,
|
||||||
"isReadOnly": false
|
"isReadOnly": false
|
||||||
|
@ -164,10 +163,11 @@
|
||||||
"LeafNode": {
|
"LeafNode": {
|
||||||
"name": "strtest",
|
"name": "strtest",
|
||||||
"payload": {
|
"payload": {
|
||||||
"Fuzzable": [
|
"Fuzzable": {
|
||||||
"String",
|
"primitiveType": "String",
|
||||||
"true"
|
"defaultValue": "true",
|
||||||
]
|
"parameterName": "population"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"isRequired": true,
|
"isRequired": true,
|
||||||
"isReadOnly": false
|
"isReadOnly": false
|
||||||
|
@ -247,8 +247,8 @@
|
||||||
"LeafNode": {
|
"LeafNode": {
|
||||||
"name": "",
|
"name": "",
|
||||||
"payload": {
|
"payload": {
|
||||||
"Fuzzable": [
|
"Fuzzable": {
|
||||||
{
|
"primitiveType": {
|
||||||
"Enum": [
|
"Enum": [
|
||||||
"group",
|
"group",
|
||||||
"String",
|
"String",
|
||||||
|
@ -260,8 +260,8 @@
|
||||||
null
|
null
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"A"
|
"defaultValue": "A"
|
||||||
]
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -482,8 +482,8 @@
|
||||||
"LeafNode": {
|
"LeafNode": {
|
||||||
"name": "group",
|
"name": "group",
|
||||||
"payload": {
|
"payload": {
|
||||||
"Fuzzable": [
|
"Fuzzable": {
|
||||||
{
|
"primitiveType": {
|
||||||
"Enum": [
|
"Enum": [
|
||||||
"group",
|
"group",
|
||||||
"String",
|
"String",
|
||||||
|
@ -495,8 +495,8 @@
|
||||||
null
|
null
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"A"
|
"defaultValue": "A"
|
||||||
]
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1524,11 +1524,11 @@
|
||||||
"LeafNode": {
|
"LeafNode": {
|
||||||
"name": "testbool",
|
"name": "testbool",
|
||||||
"payload": {
|
"payload": {
|
||||||
"Fuzzable": [
|
"Fuzzable": {
|
||||||
"Bool",
|
"primitiveType": "Bool",
|
||||||
"testval",
|
"defaultValue": "testval",
|
||||||
false
|
"exampleValue": "false"
|
||||||
]
|
}
|
||||||
},
|
},
|
||||||
"isRequired": true,
|
"isRequired": true,
|
||||||
"isReadOnly": false
|
"isReadOnly": false
|
||||||
|
@ -2150,10 +2150,10 @@
|
||||||
"LeafNode": {
|
"LeafNode": {
|
||||||
"name": "",
|
"name": "",
|
||||||
"payload": {
|
"payload": {
|
||||||
"Fuzzable": [
|
"Fuzzable": {
|
||||||
"DateTime",
|
"primitiveType": "DateTime",
|
||||||
"2020-1-1"
|
"defaultValue": "2020-1-1"
|
||||||
]
|
}
|
||||||
},
|
},
|
||||||
"isRequired": true,
|
"isRequired": true,
|
||||||
"isReadOnly": false
|
"isReadOnly": false
|
||||||
|
@ -2185,10 +2185,10 @@
|
||||||
"LeafNode": {
|
"LeafNode": {
|
||||||
"name": "datetest",
|
"name": "datetest",
|
||||||
"payload": {
|
"payload": {
|
||||||
"Fuzzable": [
|
"Fuzzable": {
|
||||||
"DateTime",
|
"primitiveType": "DateTime",
|
||||||
"2020-1-1"
|
"defaultValue": "2020-1-1"
|
||||||
]
|
}
|
||||||
},
|
},
|
||||||
"isRequired": false,
|
"isRequired": false,
|
||||||
"isReadOnly": false
|
"isReadOnly": false
|
||||||
|
|
|
@ -114,10 +114,10 @@
|
||||||
"LeafNode": {
|
"LeafNode": {
|
||||||
"name": "population",
|
"name": "population",
|
||||||
"payload": {
|
"payload": {
|
||||||
"Fuzzable": [
|
"Fuzzable": {
|
||||||
"Int",
|
"primitiveType": "Int",
|
||||||
"1000"
|
"defaultValue": "1000"
|
||||||
]
|
}
|
||||||
},
|
},
|
||||||
"isRequired": false,
|
"isRequired": false,
|
||||||
"isReadOnly": false
|
"isReadOnly": false
|
||||||
|
@ -140,10 +140,10 @@
|
||||||
"LeafNode": {
|
"LeafNode": {
|
||||||
"name": "strtest",
|
"name": "strtest",
|
||||||
"payload": {
|
"payload": {
|
||||||
"Fuzzable": [
|
"Fuzzable": {
|
||||||
"String",
|
"primitiveType": "String",
|
||||||
"true"
|
"defaultValue": "true"
|
||||||
]
|
}
|
||||||
},
|
},
|
||||||
"isRequired": true,
|
"isRequired": true,
|
||||||
"isReadOnly": false
|
"isReadOnly": false
|
||||||
|
@ -171,10 +171,10 @@
|
||||||
"LeafNode": {
|
"LeafNode": {
|
||||||
"name": "subtest",
|
"name": "subtest",
|
||||||
"payload": {
|
"payload": {
|
||||||
"Fuzzable": [
|
"Fuzzable": {
|
||||||
"Bool",
|
"primitiveType": "Bool",
|
||||||
"true"
|
"defaultValue": "true"
|
||||||
]
|
}
|
||||||
},
|
},
|
||||||
"isRequired": false,
|
"isRequired": false,
|
||||||
"isReadOnly": false
|
"isReadOnly": false
|
||||||
|
@ -265,8 +265,10 @@
|
||||||
"LeafNode": {
|
"LeafNode": {
|
||||||
"name": "",
|
"name": "",
|
||||||
"payload": {
|
"payload": {
|
||||||
"Fuzzable": [
|
|
||||||
{
|
"Fuzzable": {
|
||||||
|
"primitiveType":
|
||||||
|
{
|
||||||
"Enum": [
|
"Enum": [
|
||||||
"group",
|
"group",
|
||||||
"String",
|
"String",
|
||||||
|
@ -278,8 +280,8 @@
|
||||||
null
|
null
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"A"
|
"defaultValue": "A"
|
||||||
]
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -508,7 +510,8 @@
|
||||||
"LeafNode": {
|
"LeafNode": {
|
||||||
"name": "group",
|
"name": "group",
|
||||||
"payload": {
|
"payload": {
|
||||||
"Fuzzable": [
|
"Fuzzable": {
|
||||||
|
"primitiveType":
|
||||||
{
|
{
|
||||||
"Enum": [
|
"Enum": [
|
||||||
"group",
|
"group",
|
||||||
|
@ -521,8 +524,8 @@
|
||||||
null
|
null
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"A"
|
"defaultValue": "A"
|
||||||
]
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -324,7 +324,7 @@ module Dependencies =
|
||||||
ResolveBodyDependencies = true
|
ResolveBodyDependencies = true
|
||||||
UseBodyExamples = Some true
|
UseBodyExamples = Some true
|
||||||
SwaggerSpecFilePath = Some [(Path.Combine(Environment.CurrentDirectory, @"swagger\dependencyTests\input_producer_spec.json"))]
|
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"))
|
AnnotationFilePath = Some (Path.Combine(Environment.CurrentDirectory, @"swagger\dependencyTests\input_producer_annotations.json"))
|
||||||
AllowGetProducers = true
|
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_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)"""))
|
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
|
/// Test that the entire body should be able to be replaced with a custom payload
|
||||||
/// from the dictionary
|
/// from the dictionary
|
||||||
|
|
|
@ -76,6 +76,9 @@
|
||||||
<Content Include="swagger\dependencyTests\input_producer_spec.json">
|
<Content Include="swagger\dependencyTests\input_producer_spec.json">
|
||||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
</Content>
|
</Content>
|
||||||
|
<Content Include="swagger\dependencyTests\input_producer_dict.json">
|
||||||
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
|
</Content>
|
||||||
<Content Include="swagger\dependencyTests\input_producer_annotations.json">
|
<Content Include="swagger\dependencyTests\input_producer_annotations.json">
|
||||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
</Content>
|
</Content>
|
||||||
|
|
|
@ -43,12 +43,10 @@
|
||||||
"LeafNode": {
|
"LeafNode": {
|
||||||
"name": "name",
|
"name": "name",
|
||||||
"payload": {
|
"payload": {
|
||||||
"Fuzzable": [
|
"Fuzzable": {
|
||||||
"String",
|
"primitiveType": "String",
|
||||||
"fuzzstring",
|
"defaultValue": "fuzzstring"
|
||||||
null,
|
}
|
||||||
null
|
|
||||||
]
|
|
||||||
},
|
},
|
||||||
"isRequired": false,
|
"isRequired": false,
|
||||||
"isReadOnly": false
|
"isReadOnly": false
|
||||||
|
@ -58,12 +56,10 @@
|
||||||
"LeafNode": {
|
"LeafNode": {
|
||||||
"name": "tags",
|
"name": "tags",
|
||||||
"payload": {
|
"payload": {
|
||||||
"Fuzzable": [
|
"Fuzzable": {
|
||||||
"Object",
|
"primitiveType": "Object",
|
||||||
"{ \"fuzz\": false }",
|
"defaultValue": "{ \"fuzz\": false }"
|
||||||
null,
|
}
|
||||||
null
|
|
||||||
]
|
|
||||||
},
|
},
|
||||||
"isRequired": false,
|
"isRequired": false,
|
||||||
"isReadOnly": false
|
"isReadOnly": false
|
||||||
|
@ -159,12 +155,10 @@
|
||||||
"LeafNode": {
|
"LeafNode": {
|
||||||
"name": "",
|
"name": "",
|
||||||
"payload": {
|
"payload": {
|
||||||
"Fuzzable": [
|
"Fuzzable": {
|
||||||
"String",
|
"primitiveType": "String",
|
||||||
"fuzzstring",
|
"defaultValue": "fuzzstring"
|
||||||
null,
|
}
|
||||||
null
|
|
||||||
]
|
|
||||||
},
|
},
|
||||||
"isRequired": false,
|
"isRequired": false,
|
||||||
"isReadOnly": false
|
"isReadOnly": false
|
||||||
|
@ -198,12 +192,10 @@
|
||||||
"LeafNode": {
|
"LeafNode": {
|
||||||
"name": "name",
|
"name": "name",
|
||||||
"payload": {
|
"payload": {
|
||||||
"Fuzzable": [
|
"Fuzzable": {
|
||||||
"String",
|
"primitiveType": "String",
|
||||||
"fuzzstring",
|
"defaultValue": "fuzzstring"
|
||||||
null,
|
}
|
||||||
null
|
|
||||||
]
|
|
||||||
},
|
},
|
||||||
"isRequired": true,
|
"isRequired": true,
|
||||||
"isReadOnly": false
|
"isReadOnly": false
|
||||||
|
@ -213,12 +205,10 @@
|
||||||
"LeafNode": {
|
"LeafNode": {
|
||||||
"name": "tags",
|
"name": "tags",
|
||||||
"payload": {
|
"payload": {
|
||||||
"Fuzzable": [
|
"Fuzzable": {
|
||||||
"Object",
|
"primitiveType": "Object",
|
||||||
"{ \"fuzz\": false }",
|
"defaultValue": "{ \"fuzz\": false }"
|
||||||
null,
|
}
|
||||||
null
|
|
||||||
]
|
|
||||||
},
|
},
|
||||||
"isRequired": false,
|
"isRequired": false,
|
||||||
"isReadOnly": false
|
"isReadOnly": false
|
||||||
|
@ -246,12 +236,10 @@
|
||||||
"LeafNode": {
|
"LeafNode": {
|
||||||
"name": "name",
|
"name": "name",
|
||||||
"payload": {
|
"payload": {
|
||||||
"Fuzzable": [
|
"Fuzzable": {
|
||||||
"String",
|
"primitiveType": "String",
|
||||||
"fuzzstring",
|
"defaultValue": "fuzzstring"
|
||||||
null,
|
}
|
||||||
null
|
|
||||||
]
|
|
||||||
},
|
},
|
||||||
"isRequired": false,
|
"isRequired": false,
|
||||||
"isReadOnly": false
|
"isReadOnly": false
|
||||||
|
@ -261,12 +249,10 @@
|
||||||
"LeafNode": {
|
"LeafNode": {
|
||||||
"name": "id",
|
"name": "id",
|
||||||
"payload": {
|
"payload": {
|
||||||
"Fuzzable": [
|
"Fuzzable": {
|
||||||
"Number",
|
"primitiveType": "Number",
|
||||||
"1.23",
|
"defaultValue": "1.23"
|
||||||
null,
|
}
|
||||||
null
|
|
||||||
]
|
|
||||||
},
|
},
|
||||||
"isRequired": true,
|
"isRequired": true,
|
||||||
"isReadOnly": false
|
"isReadOnly": false
|
||||||
|
@ -306,12 +292,10 @@
|
||||||
"LeafNode": {
|
"LeafNode": {
|
||||||
"name": "",
|
"name": "",
|
||||||
"payload": {
|
"payload": {
|
||||||
"Fuzzable": [
|
"Fuzzable": {
|
||||||
"String",
|
"primitiveType": "String",
|
||||||
"fuzzstring",
|
"defaultValue": "fuzzstring"
|
||||||
null,
|
}
|
||||||
null
|
|
||||||
]
|
|
||||||
},
|
},
|
||||||
"isRequired": false,
|
"isRequired": false,
|
||||||
"isReadOnly": false
|
"isReadOnly": false
|
||||||
|
|
|
@ -70,8 +70,8 @@
|
||||||
"LeafNode": {
|
"LeafNode": {
|
||||||
"name": "",
|
"name": "",
|
||||||
"payload": {
|
"payload": {
|
||||||
"Fuzzable": [
|
"Fuzzable": {
|
||||||
{
|
"primitiveType": {
|
||||||
"Enum": [
|
"Enum": [
|
||||||
"api-version",
|
"api-version",
|
||||||
"String",
|
"String",
|
||||||
|
@ -81,10 +81,8 @@
|
||||||
null
|
null
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"2020-03-01",
|
"defaultValue": "2020-03-01"
|
||||||
null,
|
}
|
||||||
null
|
|
||||||
]
|
|
||||||
},
|
},
|
||||||
"isRequired": true,
|
"isRequired": true,
|
||||||
"isReadOnly": false
|
"isReadOnly": false
|
||||||
|
@ -215,8 +213,8 @@
|
||||||
"LeafNode": {
|
"LeafNode": {
|
||||||
"name": "",
|
"name": "",
|
||||||
"payload": {
|
"payload": {
|
||||||
"Fuzzable": [
|
"Fuzzable": {
|
||||||
{
|
"primitiveType": {
|
||||||
"Enum": [
|
"Enum": [
|
||||||
"api-version",
|
"api-version",
|
||||||
"String",
|
"String",
|
||||||
|
@ -226,10 +224,8 @@
|
||||||
null
|
null
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"2020-03-01",
|
"defaultValue": "2020-03-01"
|
||||||
null,
|
}
|
||||||
null
|
|
||||||
]
|
|
||||||
},
|
},
|
||||||
"isRequired": true,
|
"isRequired": true,
|
||||||
"isReadOnly": false
|
"isReadOnly": false
|
||||||
|
@ -381,8 +377,8 @@
|
||||||
"LeafNode": {
|
"LeafNode": {
|
||||||
"name": "",
|
"name": "",
|
||||||
"payload": {
|
"payload": {
|
||||||
"Fuzzable": [
|
"Fuzzable": {
|
||||||
{
|
"primitiveType": {
|
||||||
"Enum": [
|
"Enum": [
|
||||||
"api-version",
|
"api-version",
|
||||||
"String",
|
"String",
|
||||||
|
@ -392,10 +388,8 @@
|
||||||
null
|
null
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"2020-03-01",
|
"defaultValue": "2020-03-01"
|
||||||
null,
|
}
|
||||||
null
|
|
||||||
]
|
|
||||||
},
|
},
|
||||||
"isRequired": true,
|
"isRequired": true,
|
||||||
"isReadOnly": false
|
"isReadOnly": false
|
||||||
|
@ -443,12 +437,10 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"Fuzzable": [
|
"Fuzzable": {
|
||||||
"String",
|
"primitiveType": "String",
|
||||||
"fuzzstring",
|
"defaultValue": "fuzzstring"
|
||||||
null,
|
}
|
||||||
null
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"queryParameters": [
|
"queryParameters": [
|
||||||
|
@ -478,8 +470,8 @@
|
||||||
"LeafNode": {
|
"LeafNode": {
|
||||||
"name": "",
|
"name": "",
|
||||||
"payload": {
|
"payload": {
|
||||||
"Fuzzable": [
|
"Fuzzable": {
|
||||||
{
|
"primitiveType": {
|
||||||
"Enum": [
|
"Enum": [
|
||||||
"api-version",
|
"api-version",
|
||||||
"String",
|
"String",
|
||||||
|
@ -489,10 +481,8 @@
|
||||||
null
|
null
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"2020-03-01",
|
"defaultValue": "2020-03-01"
|
||||||
null,
|
}
|
||||||
null
|
|
||||||
]
|
|
||||||
},
|
},
|
||||||
"isRequired": true,
|
"isRequired": true,
|
||||||
"isReadOnly": false
|
"isReadOnly": false
|
||||||
|
@ -540,12 +530,10 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"Fuzzable": [
|
"Fuzzable": {
|
||||||
"String",
|
"primitiveType": "String",
|
||||||
"fuzzstring",
|
"defaultValue": "fuzzstring"
|
||||||
null,
|
}
|
||||||
null
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"queryParameters": [
|
"queryParameters": [
|
||||||
|
@ -575,8 +563,8 @@
|
||||||
"LeafNode": {
|
"LeafNode": {
|
||||||
"name": "",
|
"name": "",
|
||||||
"payload": {
|
"payload": {
|
||||||
"Fuzzable": [
|
"Fuzzable": {
|
||||||
{
|
"primitiveType": {
|
||||||
"Enum": [
|
"Enum": [
|
||||||
"api-version",
|
"api-version",
|
||||||
"String",
|
"String",
|
||||||
|
@ -586,10 +574,8 @@
|
||||||
null
|
null
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"2020-03-01",
|
"defaultValue": "2020-03-01"
|
||||||
null,
|
}
|
||||||
null
|
|
||||||
]
|
|
||||||
},
|
},
|
||||||
"isRequired": true,
|
"isRequired": true,
|
||||||
"isReadOnly": false
|
"isReadOnly": false
|
||||||
|
|
|
@ -5,6 +5,30 @@
|
||||||
"producer_method": "POST",
|
"producer_method": "POST",
|
||||||
"producer_resource_name": "fileId",
|
"producer_resource_name": "fileId",
|
||||||
"consumer_param": "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":{
|
"fileId":{
|
||||||
"type": "String",
|
"type": "String",
|
||||||
"description": "the file id"
|
"description": "the file id"
|
||||||
|
},
|
||||||
|
"Archive": {
|
||||||
|
"properties": {
|
||||||
|
"name": {
|
||||||
|
"type": "object"
|
||||||
|
},
|
||||||
|
"tag": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"paths": {
|
"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}": {
|
"/file/{fileId}": {
|
||||||
"post": {
|
"post": {
|
||||||
"parameters": [
|
"parameters": [
|
||||||
|
|
|
@ -372,7 +372,10 @@ type Producer =
|
||||||
/// Currently, only assigning such values from the dictionary is supported.
|
/// Currently, only assigning such values from the dictionary is supported.
|
||||||
/// The dictionary payload is an option type because it is only present when
|
/// The dictionary payload is an option type because it is only present when
|
||||||
/// the initial payload is being generated.
|
/// 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
|
| OrderingConstraintParameter of OrderingConstraintProducer
|
||||||
|
|
||||||
|
|
|
@ -24,28 +24,31 @@ module Types =
|
||||||
trackedParameterName: string option
|
trackedParameterName: string option
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type DynamicObjectWriter =
|
||||||
|
| DynamicObjectWriter of string
|
||||||
|
|
||||||
/// RESTler grammar built-in types
|
/// RESTler grammar built-in types
|
||||||
/// IMPORTANT ! All primitives must be supported in restler/engine/primitives.py
|
/// IMPORTANT ! All primitives must be supported in restler/engine/primitives.py
|
||||||
type RequestPrimitiveType =
|
type RequestPrimitiveType =
|
||||||
| Restler_static_string_constant of string
|
| Restler_static_string_constant of string
|
||||||
| Restler_static_string_variable of string * bool
|
| Restler_static_string_variable of string * bool
|
||||||
| Restler_static_string_jtoken_delim of string
|
| Restler_static_string_jtoken_delim of string
|
||||||
| Restler_fuzzable_string of RequestPrimitiveTypeData
|
| Restler_fuzzable_string of RequestPrimitiveTypeData * DynamicObjectWriter option
|
||||||
| Restler_fuzzable_datetime of RequestPrimitiveTypeData
|
| Restler_fuzzable_datetime of RequestPrimitiveTypeData * DynamicObjectWriter option
|
||||||
| Restler_fuzzable_date of RequestPrimitiveTypeData
|
| Restler_fuzzable_date of RequestPrimitiveTypeData * DynamicObjectWriter option
|
||||||
| Restler_fuzzable_object of RequestPrimitiveTypeData
|
| Restler_fuzzable_object of RequestPrimitiveTypeData * DynamicObjectWriter option
|
||||||
| Restler_fuzzable_delim of RequestPrimitiveTypeData
|
| Restler_fuzzable_delim of RequestPrimitiveTypeData
|
||||||
| Restler_fuzzable_uuid4 of RequestPrimitiveTypeData
|
| Restler_fuzzable_uuid4 of RequestPrimitiveTypeData * DynamicObjectWriter option
|
||||||
| Restler_fuzzable_group of RequestPrimitiveTypeData
|
| Restler_fuzzable_group of RequestPrimitiveTypeData * DynamicObjectWriter option
|
||||||
| Restler_fuzzable_bool of RequestPrimitiveTypeData
|
| Restler_fuzzable_bool of RequestPrimitiveTypeData * DynamicObjectWriter option
|
||||||
| Restler_fuzzable_int of RequestPrimitiveTypeData
|
| Restler_fuzzable_int of RequestPrimitiveTypeData * DynamicObjectWriter option
|
||||||
| Restler_fuzzable_number of RequestPrimitiveTypeData
|
| Restler_fuzzable_number of RequestPrimitiveTypeData * DynamicObjectWriter option
|
||||||
| Restler_multipart_formdata of string
|
| Restler_multipart_formdata of string
|
||||||
| Restler_custom_payload of RequestPrimitiveTypeData
|
| Restler_custom_payload of RequestPrimitiveTypeData * DynamicObjectWriter option
|
||||||
| Restler_custom_payload_header of string
|
| Restler_custom_payload_header of string * DynamicObjectWriter option
|
||||||
| Restler_custom_payload_query of string
|
| Restler_custom_payload_query of string * DynamicObjectWriter option
|
||||||
/// (Payload name, dynamic object writer name)
|
/// (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_refreshable_authentication_token of string
|
||||||
| Restler_basepath of string
|
| Restler_basepath of string
|
||||||
| Shadow_values of string
|
| Shadow_values of string
|
||||||
|
@ -72,20 +75,27 @@ let rec getRestlerPythonPayload (payload:FuzzingPayload) (isQuoted:bool) : Reque
|
||||||
match p with
|
match p with
|
||||||
| Constant (t,v) ->
|
| Constant (t,v) ->
|
||||||
Restler_static_string_constant v
|
Restler_static_string_constant v
|
||||||
| Fuzzable (t,v,exv,parameterName) ->
|
| Fuzzable fp ->
|
||||||
match t with
|
let v = fp.defaultValue
|
||||||
| Bool -> Restler_fuzzable_bool { defaultValue = v ; isQuoted = false ; exampleValue = exv ; trackedParameterName = parameterName }
|
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 ->
|
| 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 ->
|
| 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 ->
|
| PrimitiveType.String ->
|
||||||
Restler_fuzzable_string { defaultValue = v ; isQuoted = isQuoted ; 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 }
|
| 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 }
|
| 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 }
|
|
||||||
|
| Number -> Restler_fuzzable_number ({ defaultValue = v ; isQuoted = false ; exampleValue = exv ; trackedParameterName = parameterName }, dynamicObject)
|
||||||
| Uuid ->
|
| 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) ->
|
| PrimitiveType.Enum (enumPropertyName, _, enumeration, defaultValue) ->
|
||||||
let defaultStr =
|
let defaultStr =
|
||||||
match defaultValue with
|
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 ",")
|
(enumeration |> List.map (fun s -> sprintf "'%s'" s) |> String.concat ",")
|
||||||
defaultStr
|
defaultStr
|
||||||
)
|
)
|
||||||
Restler_fuzzable_group
|
Restler_fuzzable_group (
|
||||||
{ defaultValue = groupValue ; isQuoted = isQuoted ; exampleValue = exv ; trackedParameterName = parameterName }
|
{ defaultValue = groupValue ; isQuoted = isQuoted ; exampleValue = exv ; trackedParameterName = parameterName }, dynamicObject)
|
||||||
| Custom c ->
|
| Custom c ->
|
||||||
|
let dynamicObject = if c.dynamicObject.IsSome then Some (DynamicObjectWriter c.dynamicObject.Value.variableName) else None
|
||||||
match c.payloadType with
|
match c.payloadType with
|
||||||
| CustomPayloadType.String ->
|
| 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 ->
|
| 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 ->
|
| CustomPayloadType.Header ->
|
||||||
Restler_custom_payload_header c.payloadValue // TODO: need test
|
Restler_custom_payload_header (c.payloadValue, dynamicObject)
|
||||||
| CustomPayloadType.Query ->
|
| CustomPayloadType.Query ->
|
||||||
Restler_custom_payload_query c.payloadValue // TODO: need test
|
Restler_custom_payload_query (c.payloadValue, dynamicObject)
|
||||||
| DynamicObject dv ->
|
| DynamicObject dv ->
|
||||||
Restler_static_string_variable (sprintf "%s.reader()" dv.variableName, isQuoted)
|
Restler_static_string_variable (sprintf "%s.reader()" dv.variableName, isQuoted)
|
||||||
| PayloadParts p ->
|
| PayloadParts p ->
|
||||||
|
@ -350,10 +361,10 @@ let generatePythonParameter includeOptionalParameters parameterKind (requestPara
|
||||||
| FuzzingPayload.Constant (primitiveType, v) ->
|
| FuzzingPayload.Constant (primitiveType, v) ->
|
||||||
isPrimitiveTypeQuoted primitiveType (isNull v),
|
isPrimitiveTypeQuoted primitiveType (isNull v),
|
||||||
false, false
|
false, false
|
||||||
| FuzzingPayload.Fuzzable (primitiveType, _, _,_) ->
|
| FuzzingPayload.Fuzzable fp ->
|
||||||
// Note: this is a current RESTler limitation -
|
// Note: this is a current RESTler limitation -
|
||||||
// fuzzable values may not be set to null without changing the grammar.
|
// fuzzable values may not be set to null without changing the grammar.
|
||||||
isPrimitiveTypeQuoted primitiveType false,
|
isPrimitiveTypeQuoted fp.primitiveType false,
|
||||||
true, false
|
true, false
|
||||||
| FuzzingPayload.DynamicObject dv ->
|
| FuzzingPayload.DynamicObject dv ->
|
||||||
isPrimitiveTypeQuoted dv.primitiveType false,
|
isPrimitiveTypeQuoted dv.primitiveType false,
|
||||||
|
@ -1065,6 +1076,12 @@ let getRequests(requests:Request list) includeOptionalParameters =
|
||||||
let quotedStr = sprintf "%s%s%s" exDelim exStr exDelim
|
let quotedStr = sprintf "%s%s%s" exDelim exStr exDelim
|
||||||
sprintf ", param_name=%s" quotedStr
|
sprintf ", param_name=%s" quotedStr
|
||||||
|
|
||||||
|
let formatDynamicObjectVariable (dynamicObject:DynamicObjectWriter option) =
|
||||||
|
match dynamicObject with
|
||||||
|
| None -> ""
|
||||||
|
| Some (DynamicObjectWriter v) ->
|
||||||
|
sprintf ", writer=%s.writer()" v
|
||||||
|
|
||||||
let str =
|
let str =
|
||||||
match p with
|
match p with
|
||||||
| Restler_static_string_jtoken_delim s ->
|
| Restler_static_string_jtoken_delim s ->
|
||||||
|
@ -1088,7 +1105,7 @@ let getRequests(requests:Request list) includeOptionalParameters =
|
||||||
sprintf "primitives.restler_static_string(%s, quoted=%s)"
|
sprintf "primitives.restler_static_string(%s, quoted=%s)"
|
||||||
s
|
s
|
||||||
(if isQuoted then "True" else "False")
|
(if isQuoted then "True" else "False")
|
||||||
| Restler_fuzzable_string s ->
|
| Restler_fuzzable_string (s, dynamicObject) ->
|
||||||
if String.IsNullOrEmpty s.defaultValue then
|
if String.IsNullOrEmpty s.defaultValue then
|
||||||
printfn "ERROR: fuzzable strings should not be empty. Skipping."
|
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")
|
(if s.isQuoted then "True" else "False")
|
||||||
exampleParameter
|
exampleParameter
|
||||||
trackedParamName
|
trackedParamName
|
||||||
| Restler_fuzzable_group s ->
|
| Restler_fuzzable_group (s, dynamicObject) ->
|
||||||
sprintf "primitives.restler_fuzzable_group(%s,quoted=%s%s)"
|
sprintf "primitives.restler_fuzzable_group(%s,quoted=%s%s)"
|
||||||
s.defaultValue
|
s.defaultValue
|
||||||
(if s.isQuoted then "True" else "False")
|
(if s.isQuoted then "True" else "False")
|
||||||
(getExamplePrimitiveParameter s.exampleValue)
|
(getExamplePrimitiveParameter s.exampleValue)
|
||||||
| Restler_fuzzable_int s ->
|
| Restler_fuzzable_int (s, dynamicObject) ->
|
||||||
sprintf "primitives.restler_fuzzable_int(\"%s\"%s%s)"
|
sprintf "primitives.restler_fuzzable_int(\"%s\"%s%s%s)"
|
||||||
s.defaultValue
|
s.defaultValue
|
||||||
(getExamplePrimitiveParameter s.exampleValue)
|
(getExamplePrimitiveParameter s.exampleValue)
|
||||||
(getTrackedParamPrimitiveParameter s.trackedParameterName)
|
(getTrackedParamPrimitiveParameter s.trackedParameterName)
|
||||||
| Restler_fuzzable_number s ->
|
(formatDynamicObjectVariable dynamicObject)
|
||||||
sprintf "primitives.restler_fuzzable_number(\"%s\"%s%s)"
|
| Restler_fuzzable_number (s, dynamicObject) ->
|
||||||
|
sprintf "primitives.restler_fuzzable_number(\"%s\"%s%s%s)"
|
||||||
s.defaultValue
|
s.defaultValue
|
||||||
(getExamplePrimitiveParameter s.exampleValue)
|
(getExamplePrimitiveParameter s.exampleValue)
|
||||||
(getTrackedParamPrimitiveParameter s.trackedParameterName)
|
(getTrackedParamPrimitiveParameter s.trackedParameterName)
|
||||||
| Restler_fuzzable_bool s ->
|
(formatDynamicObjectVariable dynamicObject)
|
||||||
sprintf "primitives.restler_fuzzable_bool(\"%s\"%s%s)"
|
| Restler_fuzzable_bool (s, dynamicObject) ->
|
||||||
|
sprintf "primitives.restler_fuzzable_bool(\"%s\"%s%s%s)"
|
||||||
s.defaultValue
|
s.defaultValue
|
||||||
(getExamplePrimitiveParameter s.exampleValue)
|
(getExamplePrimitiveParameter s.exampleValue)
|
||||||
(getTrackedParamPrimitiveParameter s.trackedParameterName)
|
(getTrackedParamPrimitiveParameter s.trackedParameterName)
|
||||||
| Restler_fuzzable_datetime s ->
|
(formatDynamicObjectVariable dynamicObject)
|
||||||
sprintf "primitives.restler_fuzzable_datetime(\"%s\", quoted=%s%s%s)"
|
| Restler_fuzzable_datetime (s, dynamicObject) ->
|
||||||
|
sprintf "primitives.restler_fuzzable_datetime(\"%s\", quoted=%s%s%s%s)"
|
||||||
s.defaultValue
|
s.defaultValue
|
||||||
(if s.isQuoted then "True" else "False")
|
(if s.isQuoted then "True" else "False")
|
||||||
(getExamplePrimitiveParameter s.exampleValue)
|
(getExamplePrimitiveParameter s.exampleValue)
|
||||||
(getTrackedParamPrimitiveParameter s.trackedParameterName)
|
(getTrackedParamPrimitiveParameter s.trackedParameterName)
|
||||||
| Restler_fuzzable_date s ->
|
(formatDynamicObjectVariable dynamicObject)
|
||||||
sprintf "primitives.restler_fuzzable_date(\"%s\", quoted=%s%s%s)"
|
| Restler_fuzzable_date (s, dynamicObject) ->
|
||||||
|
sprintf "primitives.restler_fuzzable_date(\"%s\", quoted=%s%s%s%s)"
|
||||||
s.defaultValue
|
s.defaultValue
|
||||||
(if s.isQuoted then "True" else "False")
|
(if s.isQuoted then "True" else "False")
|
||||||
(getExamplePrimitiveParameter s.exampleValue)
|
(getExamplePrimitiveParameter s.exampleValue)
|
||||||
(getTrackedParamPrimitiveParameter s.trackedParameterName)
|
(getTrackedParamPrimitiveParameter s.trackedParameterName)
|
||||||
| Restler_fuzzable_object s ->
|
(formatDynamicObjectVariable dynamicObject)
|
||||||
|
| Restler_fuzzable_object (s, dynamicObject) ->
|
||||||
if String.IsNullOrEmpty s.defaultValue then
|
if String.IsNullOrEmpty s.defaultValue then
|
||||||
printfn "ERROR: fuzzable objects should not be empty. Skipping."
|
printfn "ERROR: fuzzable objects should not be empty. Skipping."
|
||||||
""
|
""
|
||||||
|
@ -1144,31 +1166,35 @@ let getRequests(requests:Request list) includeOptionalParameters =
|
||||||
let quotedDefaultString =
|
let quotedDefaultString =
|
||||||
sprintf "%s%s%s" delim str delim
|
sprintf "%s%s%s" delim str delim
|
||||||
let exampleParameter = getExamplePrimitiveParameter s.exampleValue
|
let exampleParameter = getExamplePrimitiveParameter s.exampleValue
|
||||||
sprintf "primitives.restler_fuzzable_object(%s%s%s)"
|
sprintf "primitives.restler_fuzzable_object(%s%s%s%s)"
|
||||||
quotedDefaultString
|
quotedDefaultString
|
||||||
exampleParameter
|
exampleParameter
|
||||||
(getTrackedParamPrimitiveParameter s.trackedParameterName)
|
(getTrackedParamPrimitiveParameter s.trackedParameterName)
|
||||||
| Restler_fuzzable_uuid4 s ->
|
(formatDynamicObjectVariable dynamicObject)
|
||||||
sprintf "primitives.restler_fuzzable_uuid4(\"%s\", quoted=%s%s%s)"
|
| Restler_fuzzable_uuid4 (s, dynamicObject) ->
|
||||||
|
sprintf "primitives.restler_fuzzable_uuid4(\"%s\", quoted=%s%s%s%s)"
|
||||||
s.defaultValue
|
s.defaultValue
|
||||||
(if s.isQuoted then "True" else "False")
|
(if s.isQuoted then "True" else "False")
|
||||||
(getExamplePrimitiveParameter s.exampleValue)
|
(getExamplePrimitiveParameter s.exampleValue)
|
||||||
(getTrackedParamPrimitiveParameter s.trackedParameterName)
|
(getTrackedParamPrimitiveParameter s.trackedParameterName)
|
||||||
| Restler_custom_payload p ->
|
(formatDynamicObjectVariable dynamicObject)
|
||||||
sprintf "primitives.restler_custom_payload(\"%s\", quoted=%s)"
|
| Restler_custom_payload (p, dynamicObject) ->
|
||||||
|
sprintf "primitives.restler_custom_payload(\"%s\", quoted=%s%s)"
|
||||||
p.defaultValue
|
p.defaultValue
|
||||||
(if p.isQuoted then "True" else "False")
|
(if p.isQuoted then "True" else "False")
|
||||||
| Restler_custom_payload_uuid4_suffix (p, variableName) ->
|
(formatDynamicObjectVariable dynamicObject)
|
||||||
let variableNamePart =
|
| Restler_custom_payload_uuid4_suffix (p, dynamicObject) ->
|
||||||
match variableName with
|
sprintf "primitives.restler_custom_payload_uuid4_suffix(\"%s\"%s)"
|
||||||
| None -> ""
|
p
|
||||||
| Some vn ->
|
(formatDynamicObjectVariable dynamicObject)
|
||||||
sprintf ", writer=%s.writer()" vn
|
| Restler_custom_payload_header (p, dynamicObject) ->
|
||||||
sprintf "primitives.restler_custom_payload_uuid4_suffix(\"%s\"%s)" p variableNamePart
|
sprintf "primitives.restler_custom_payload_header(\"%s\"%s)"
|
||||||
| Restler_custom_payload_header p ->
|
p
|
||||||
sprintf "primitives.restler_custom_payload_header(\"%s\")" p
|
(formatDynamicObjectVariable dynamicObject)
|
||||||
| Restler_custom_payload_query q ->
|
| Restler_custom_payload_query (q, dynamicObject) ->
|
||||||
sprintf "primitives.restler_custom_payload_query(\"%s\")" q
|
sprintf "primitives.restler_custom_payload_query(\"%s\"%s)"
|
||||||
|
q
|
||||||
|
(formatDynamicObjectVariable dynamicObject)
|
||||||
| Restler_refreshable_authentication_token tok ->
|
| Restler_refreshable_authentication_token tok ->
|
||||||
sprintf "primitives.restler_refreshable_authentication_token(\"%s\")" tok
|
sprintf "primitives.restler_refreshable_authentication_token(\"%s\")" tok
|
||||||
| Restler_basepath bp ->
|
| Restler_basepath bp ->
|
||||||
|
|
|
@ -52,7 +52,7 @@ type UserSpecifiedRequestConfig =
|
||||||
|
|
||||||
let getWriterVariable (producer:Producer) (kind:DynamicObjectVariableKind) =
|
let getWriterVariable (producer:Producer) (kind:DynamicObjectVariableKind) =
|
||||||
match producer with
|
match producer with
|
||||||
| InputParameter (iop, _) ->
|
| InputParameter (iop, _, _) ->
|
||||||
{
|
{
|
||||||
requestId = iop.id.RequestId
|
requestId = iop.id.RequestId
|
||||||
accessPathParts = iop.getInputParameterAccessPath()
|
accessPathParts = iop.getInputParameterAccessPath()
|
||||||
|
@ -133,7 +133,7 @@ let getResponseParsers (dependencies:seq<ProducerConsumerDependency>) (orderingC
|
||||||
match ro.id.ResourceReference with
|
match ro.id.ResourceReference with
|
||||||
| HeaderResource _ -> Some DynamicObjectVariableKind.Header
|
| HeaderResource _ -> Some DynamicObjectVariableKind.Header
|
||||||
| _ -> Some DynamicObjectVariableKind.BodyResponseProperty
|
| _ -> Some DynamicObjectVariableKind.BodyResponseProperty
|
||||||
| InputParameter (_, _) ->
|
| InputParameter (_, _,_) ->
|
||||||
Some DynamicObjectVariableKind.InputParameter
|
Some DynamicObjectVariableKind.InputParameter
|
||||||
| _ -> None
|
| _ -> None
|
||||||
match writerVariableKind with
|
match writerVariableKind with
|
||||||
|
@ -496,11 +496,16 @@ module private Parameters =
|
||||||
match parameterPayload with
|
match parameterPayload with
|
||||||
| LeafNode leafProperty ->
|
| LeafNode leafProperty ->
|
||||||
let leafNodePayload =
|
let leafNodePayload =
|
||||||
|
|
||||||
match leafProperty.payload with
|
match leafProperty.payload with
|
||||||
| Fuzzable (Enum(propertyName, propertyType, values, defaultValue), x, y, z) ->
|
| Fuzzable fp ->
|
||||||
Fuzzable (Enum(p.Name, propertyType, values, defaultValue), x, y, z)
|
match fp.primitiveType with
|
||||||
| Fuzzable (a, b, c, _) ->
|
| Enum(propertyName, propertyType, values, defaultValue) ->
|
||||||
Fuzzable (a, b, c, if trackParameters then Some p.Name else None)
|
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
|
| _ -> leafProperty.payload
|
||||||
LeafNode { leafProperty with payload = leafNodePayload }
|
LeafNode { leafProperty with payload = leafNodePayload }
|
||||||
| InternalNode (internalNode, children) ->
|
| InternalNode (internalNode, children) ->
|
||||||
|
|
|
@ -463,27 +463,16 @@ let findProducerWithResourceName
|
||||||
else
|
else
|
||||||
Seq.empty
|
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 =
|
let dictionary, inputOnlyProducer =
|
||||||
match inputOnlyProducers |> Seq.tryHead with
|
match inputOnlyProducers |> Seq.tryHead with
|
||||||
| None -> dictionary, None
|
| None -> dictionary, None
|
||||||
| Some iop ->
|
| Some iop ->
|
||||||
if annotationProducerRequestId = consumer.id.RequestId then
|
if annotationProducerRequestId = consumer.id.RequestId then
|
||||||
// This is when the value is written
|
// This is the writer. This will be handled later.
|
||||||
if dictionary.restler_custom_payload.Value.ContainsKey(consumerResourceName) then
|
dictionary, None
|
||||||
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"))
|
|
||||||
else
|
else
|
||||||
// Read the value - no associated dictionary payload
|
// Read the value - no associated dictionary payload
|
||||||
dictionary, Some (InputParameter(iop, None))
|
dictionary, Some (InputParameter(iop, None, false))
|
||||||
|
|
||||||
let annotationProducer =
|
let annotationProducer =
|
||||||
[ responseProducers
|
[ responseProducers
|
||||||
|
@ -523,6 +512,56 @@ let findProducerWithResourceName
|
||||||
]
|
]
|
||||||
|> Seq.concat
|
|> 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,
|
// Here the producers just match on the resource name. If the container also matches,
|
||||||
// it will match fully.
|
// it will match fully.
|
||||||
let inferredExactMatches = matchingResourceProducersByEndpoint
|
let inferredExactMatches = matchingResourceProducersByEndpoint
|
||||||
|
@ -618,6 +657,7 @@ let findProducerWithResourceName
|
||||||
else
|
else
|
||||||
dictionary,
|
dictionary,
|
||||||
[ if annotationProducer.IsSome then stn annotationProducer.Value else Seq.empty
|
[ if annotationProducer.IsSome then stn annotationProducer.Value else Seq.empty
|
||||||
|
inputProducerMatches
|
||||||
dictionaryMatches
|
dictionaryMatches
|
||||||
uuidSuffixDictionaryMatches
|
uuidSuffixDictionaryMatches
|
||||||
inferredExactMatches
|
inferredExactMatches
|
||||||
|
@ -783,7 +823,7 @@ let findAnnotation globalAnnotations
|
||||||
let getPayloadPrimitiveType (payload:FuzzingPayload) =
|
let getPayloadPrimitiveType (payload:FuzzingPayload) =
|
||||||
match payload with
|
match payload with
|
||||||
| Constant (t,_) -> t
|
| Constant (t,_) -> t
|
||||||
| Fuzzable (t,_,_,_) -> t
|
| Fuzzable fp -> fp.primitiveType
|
||||||
| Custom cp -> cp.primitiveType
|
| Custom cp -> cp.primitiveType
|
||||||
| DynamicObject d -> d.primitiveType
|
| DynamicObject d -> d.primitiveType
|
||||||
| PayloadParts _ ->
|
| PayloadParts _ ->
|
||||||
|
@ -884,7 +924,7 @@ let getParameterDependencies parameterKind globalAnnotations
|
||||||
let resourceAccessPath = PropertyAccessPaths.getLeafAccessPath parentAccessPath p
|
let resourceAccessPath = PropertyAccessPaths.getLeafAccessPath parentAccessPath p
|
||||||
let primitiveType =
|
let primitiveType =
|
||||||
match p.payload with
|
match p.payload with
|
||||||
| FuzzingPayload.Fuzzable (pt, _, _,_) -> Some pt
|
| FuzzingPayload.Fuzzable fp -> Some fp.primitiveType
|
||||||
| FuzzingPayload.Constant (pt, _) -> Some pt
|
| FuzzingPayload.Constant (pt, _) -> Some pt
|
||||||
| FuzzingPayload.Custom c -> Some c.primitiveType
|
| FuzzingPayload.Custom c -> Some c.primitiveType
|
||||||
| _ -> None
|
| _ -> None
|
||||||
|
@ -958,47 +998,52 @@ let createHeaderResponseProducer (requestId:RequestId) (headerParameterName:stri
|
||||||
let createInputOnlyProducerFromAnnotation (a:ProducerConsumerAnnotation)
|
let createInputOnlyProducerFromAnnotation (a:ProducerConsumerAnnotation)
|
||||||
(pathConsumers:(RequestId * seq<Consumer>) [])
|
(pathConsumers:(RequestId * seq<Consumer>) [])
|
||||||
(queryConsumers:(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
|
// Find the producer in the list of consumers
|
||||||
match a.producerParameter.Value with
|
match a.producerParameter.Value with
|
||||||
| ResourceName rn ->
|
| ResourceName rn ->
|
||||||
if a.producerId.endpoint.Contains(sprintf "{%s}" rn) then
|
let parameterKind, consumer =
|
||||||
// Look for the corresponding path producer.
|
if a.producerId.endpoint.Contains(sprintf "{%s}" rn) then
|
||||||
// This is needed to determine its type.
|
let pathConsumer = findConsumer pathConsumers rn
|
||||||
let pc = pathConsumers
|
ParameterKind.Path, pathConsumer
|
||||||
|> Array.tryFind (fun (reqId, s) -> reqId = a.producerId)
|
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 consumer with
|
||||||
match pc with
|
| None -> None
|
||||||
| None ->
|
| Some c ->
|
||||||
// The consumer for the path parameter was not found.
|
// 'c' is the consumer that is the input producer.
|
||||||
None
|
// Its value will be written to a writer variable.
|
||||||
| Some (req, consumers) ->
|
let resource = ApiResource(c.id.RequestId,
|
||||||
consumers
|
c.id.ResourceReference,
|
||||||
|> Seq.tryFind (fun c -> c.id.ResourceName = rn)
|
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 ->
|
| ResourcePath accessPath ->
|
||||||
let bc = bodyConsumers
|
let bc = bodyConsumers
|
||||||
|> Array.tryFind (fun (reqId, s) -> reqId = a.producerId)
|
|> Array.tryFind (fun (reqId, s) -> reqId = a.producerId)
|
||||||
|
@ -1026,6 +1071,9 @@ let createInputOnlyProducerFromAnnotation (a:ProducerConsumerAnnotation)
|
||||||
InputOnlyProducer.id = resource
|
InputOnlyProducer.id = resource
|
||||||
parameterKind = ParameterKind.Body
|
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)
|
Some (c.id.ResourceName, inputOnlyProducer)
|
||||||
|
|
||||||
|
|
||||||
|
@ -1216,10 +1264,11 @@ let extractDependencies (requestData:(RequestId*RequestData)[])
|
||||||
rd.localAnnotations
|
rd.localAnnotations
|
||||||
|> Seq.iter (fun a ->
|
|> Seq.iter (fun a ->
|
||||||
if a.producerParameter.IsSome then
|
if a.producerParameter.IsSome then
|
||||||
let ip = createInputOnlyProducerFromAnnotation a pathConsumers queryConsumers bodyConsumers
|
let ip = createInputOnlyProducerFromAnnotation a pathConsumers queryConsumers bodyConsumers headerConsumers
|
||||||
if ip.IsSome then
|
if ip.IsSome then
|
||||||
let resourceName, producer = ip.Value
|
let resourceName, producer = ip.Value
|
||||||
producers.addInputOnlyProducer(resourceName, producer)
|
producers.addInputOnlyProducer(resourceName, producer)
|
||||||
|
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -1229,7 +1278,7 @@ let extractDependencies (requestData:(RequestId*RequestData)[])
|
||||||
globalAnnotations
|
globalAnnotations
|
||||||
|> Seq.iter (fun a ->
|
|> Seq.iter (fun a ->
|
||||||
if a.producerParameter.IsSome then
|
if a.producerParameter.IsSome then
|
||||||
let ip = createInputOnlyProducerFromAnnotation a pathConsumers queryConsumers bodyConsumers
|
let ip = createInputOnlyProducerFromAnnotation a pathConsumers queryConsumers bodyConsumers headerConsumers
|
||||||
if ip.IsSome then
|
if ip.IsSome then
|
||||||
let resourceName, producer = ip.Value
|
let resourceName, producer = ip.Value
|
||||||
producers.addInputOnlyProducer(resourceName, producer)
|
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
|
// Mark the type of the dynamic object to be the type of the input parameter if available
|
||||||
let primitiveType =
|
let primitiveType =
|
||||||
match defaultPayload with
|
match defaultPayload with
|
||||||
| FuzzingPayload.Fuzzable (primitiveType, _, _, _) -> primitiveType
|
| FuzzingPayload.Fuzzable fp -> fp.primitiveType
|
||||||
| _ ->
|
| _ ->
|
||||||
printfn "Warning: primitive type not available for %A [resource: %s]" requestId consumerResourceName
|
printfn "Warning: primitive type not available for %A [resource: %s]" requestId consumerResourceName
|
||||||
responseProducer.id.PrimitiveType
|
responseProducer.id.PrimitiveType
|
||||||
DynamicObject { primitiveType = primitiveType; variableName = variableName; isWriter = false }
|
DynamicObject { primitiveType = primitiveType; variableName = variableName; isWriter = false }
|
||||||
| Some (InputParameter (inputParameterProducer, dictionaryPayload)) ->
|
| Some (InputParameter (inputParameterProducer, dictionaryPayload, isWriter)) ->
|
||||||
|
|
||||||
let accessPath = inputParameterProducer.getInputParameterAccessPath()
|
let accessPath = inputParameterProducer.getInputParameterAccessPath()
|
||||||
let variableName = DynamicObjectNaming.generateDynamicObjectVariableName
|
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
|
// Mark the type of the dynamic object to be the type of the input parameter if available
|
||||||
let primitiveType =
|
let primitiveType =
|
||||||
match defaultPayload with
|
match defaultPayload with
|
||||||
| FuzzingPayload.Fuzzable (primitiveType, _, _, _) -> primitiveType
|
| FuzzingPayload.Fuzzable fp -> fp.primitiveType
|
||||||
| _ ->
|
| _ ->
|
||||||
printfn "Warning: primitive type not available for %A [resource: %s]" requestId consumerResourceName
|
printfn "Warning: primitive type not available for %A [resource: %s]" requestId consumerResourceName
|
||||||
inputParameterProducer.id.PrimitiveType
|
inputParameterProducer.id.PrimitiveType
|
||||||
let dynamicObject =
|
let dynamicObject =
|
||||||
{ primitiveType = primitiveType; variableName = variableName; isWriter = false }
|
{ primitiveType = primitiveType; variableName = variableName; isWriter = false }
|
||||||
match dictionaryPayload with
|
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 ->
|
| Some dp ->
|
||||||
Custom { payloadType = dp.payloadType
|
Custom { payloadType = dp.payloadType
|
||||||
primitiveType = dp.primitiveType
|
primitiveType = dp.primitiveType
|
||||||
|
@ -1596,7 +1655,11 @@ module DependencyLookup =
|
||||||
else
|
else
|
||||||
let defaultPayload =
|
let defaultPayload =
|
||||||
match p.payload with
|
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
|
| Some p -> p
|
||||||
let propertyAccessPath =
|
let propertyAccessPath =
|
||||||
{ path = PropertyAccessPaths.getInnerAccessPath resourceAccessPath p
|
{ path = PropertyAccessPaths.getInnerAccessPath resourceAccessPath p
|
||||||
|
@ -1620,14 +1683,24 @@ module DependencyLookup =
|
||||||
| Tree.LeafNode leafProperty ->
|
| Tree.LeafNode leafProperty ->
|
||||||
leafProperty.payload, leafProperty.isRequired, leafProperty.isReadOnly
|
leafProperty.payload, leafProperty.isRequired, leafProperty.isReadOnly
|
||||||
| Tree.InternalNode (i, _) ->
|
| Tree.InternalNode (i, _) ->
|
||||||
|
let defaultFuzzablePayload =
|
||||||
|
{ primitiveType = PrimitiveType.String
|
||||||
|
defaultValue = ""
|
||||||
|
exampleValue = None
|
||||||
|
parameterName = None
|
||||||
|
dynamicObject = None }
|
||||||
let payload =
|
let payload =
|
||||||
match i.propertyType with
|
match i.propertyType with
|
||||||
| NestedType.Object ->
|
| NestedType.Object ->
|
||||||
(Fuzzable (PrimitiveType.Object, "{}", None, None))
|
Fuzzable {defaultFuzzablePayload with
|
||||||
|
primitiveType = PrimitiveType.Object
|
||||||
|
defaultValue = "{}" }
|
||||||
| NestedType.Array ->
|
| NestedType.Array ->
|
||||||
(Fuzzable (PrimitiveType.Object, "[]", None, None))
|
Fuzzable {defaultFuzzablePayload with
|
||||||
|
primitiveType = PrimitiveType.Object
|
||||||
|
defaultValue = "[]" }
|
||||||
| NestedType.Property ->
|
| NestedType.Property ->
|
||||||
(Fuzzable (PrimitiveType.String, "", None, None))
|
Fuzzable defaultFuzzablePayload
|
||||||
payload, i.isRequired, i.isReadOnly
|
payload, i.isRequired, i.isReadOnly
|
||||||
let dependencyPayload = getConsumerPayload dependencies pathPayload requestId parameterName EmptyAccessPath defaultPayload
|
let dependencyPayload = getConsumerPayload dependencies pathPayload requestId parameterName EmptyAccessPath defaultPayload
|
||||||
|
|
||||||
|
@ -1728,7 +1801,7 @@ let writeDependencies dependenciesFilePath dependencies (unresolvedOnly:bool) =
|
||||||
rp.id.RequestId.endpoint,
|
rp.id.RequestId.endpoint,
|
||||||
getMethod rp.id,
|
getMethod rp.id,
|
||||||
getParameter 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,
|
ip.id.RequestId.endpoint,
|
||||||
getMethod ip.id,
|
getMethod ip.id,
|
||||||
getParameter ip.id
|
getParameter ip.id
|
||||||
|
|
|
@ -166,6 +166,26 @@ type CustomPayload =
|
||||||
dynamicObject: DynamicObject option
|
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
|
/// The payload for a property specified in as a request parameter
|
||||||
type FuzzingPayload =
|
type FuzzingPayload =
|
||||||
/// Example: (Int "1")
|
/// Example: (Int "1")
|
||||||
|
@ -173,7 +193,7 @@ type FuzzingPayload =
|
||||||
|
|
||||||
/// (data type, default value, example value, parameter name)
|
/// (data type, default value, example value, parameter name)
|
||||||
/// Example: (Int "1", "2")
|
/// Example: (Int "1", "2")
|
||||||
| Fuzzable of PrimitiveType * string * string option * string option
|
| Fuzzable of FuzzablePayload
|
||||||
|
|
||||||
/// The custom payload, as specified in the fuzzing dictionary
|
/// The custom payload, as specified in the fuzzing dictionary
|
||||||
| Custom of CustomPayload
|
| Custom of CustomPayload
|
||||||
|
|
|
@ -119,7 +119,16 @@ module SchemaUtilities =
|
||||||
|
|
||||||
let getFuzzableValueForObjectType (objectType:NJsonSchema.JsonObjectType) (format:string) (exampleValue: string option) (propertyName: string option)
|
let getFuzzableValueForObjectType (objectType:NJsonSchema.JsonObjectType) (format:string) (exampleValue: string option) (propertyName: string option)
|
||||||
(trackParameters:bool) =
|
(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.
|
/// Get a boolean property from 'ExtensionData', if it exists.
|
||||||
let getExtensionDataBooleanPropertyValue (extensionData:System.Collections.Generic.IDictionary<string, obj>) (extensionDataKeyName:string) =
|
let getExtensionDataBooleanPropertyValue (extensionData:System.Collections.Generic.IDictionary<string, obj>) (extensionDataKeyName:string) =
|
||||||
|
@ -224,7 +233,14 @@ module SwaggerVisitors =
|
||||||
match enumValues with
|
match enumValues with
|
||||||
| [] -> "null"
|
| [] -> "null"
|
||||||
| h::rest -> h
|
| 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.Object
|
||||||
| NJsonSchema.JsonObjectType.None ->
|
| NJsonSchema.JsonObjectType.None ->
|
||||||
// Example of JsonObjectType.None: "content": {} without a type specified in Swagger.
|
// 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
|
getFuzzableValueForObjectType NJsonSchema.JsonObjectType.Object propertySchema.Format exampleValue (Some propertyName) trackParameters
|
||||||
| NJsonSchema.JsonObjectType.File ->
|
| NJsonSchema.JsonObjectType.File ->
|
||||||
// Fuzz it as a string.
|
// 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 ->
|
| nst ->
|
||||||
raise (UnsupportedType (sprintf "Unsupported type formatting: %A" nst))
|
raise (UnsupportedType (sprintf "Unsupported type formatting: %A" nst))
|
||||||
{ LeafProperty.name = propertyName; payload = payload ;isRequired = isRequired ; isReadOnly = isReadOnly }
|
{ LeafProperty.name = propertyName; payload = payload ;isRequired = isRequired ; isReadOnly = isReadOnly }
|
||||||
|
@ -255,8 +278,8 @@ module SwaggerVisitors =
|
||||||
| LeafNode leafProperty ->
|
| LeafNode leafProperty ->
|
||||||
let payload = leafProperty.payload
|
let payload = leafProperty.payload
|
||||||
match payload with
|
match payload with
|
||||||
| Fuzzable(a, b, c, _) ->
|
| Fuzzable fp ->
|
||||||
let payload = Fuzzable (a, b, c, Some paramName)
|
let payload = Fuzzable { fp with parameterName = Some paramName }
|
||||||
LeafNode { leafProperty with LeafProperty.payload = payload }
|
LeafNode { leafProperty with LeafProperty.payload = payload }
|
||||||
| x -> tree
|
| x -> tree
|
||||||
| InternalNode (_,_) -> tree
|
| InternalNode (_,_) -> tree
|
||||||
|
@ -383,15 +406,15 @@ module SwaggerVisitors =
|
||||||
| Some v ->
|
| Some v ->
|
||||||
let examplePropertyPayload =
|
let examplePropertyPayload =
|
||||||
match fuzzablePropertyPayload.payload with
|
match fuzzablePropertyPayload.payload with
|
||||||
| Fuzzable (primitiveType, defaultValue, _, propertyName) ->
|
| Fuzzable fp ->
|
||||||
let payloadValue = GenerateGrammarElements.formatJTokenProperty primitiveType v
|
let payloadValue = GenerateGrammarElements.formatJTokenProperty fp.primitiveType v
|
||||||
// Replace the default payload with the example payload, preserving type information.
|
// Replace the default payload with the example payload, preserving type information.
|
||||||
// 'generateFuzzablePayload' is specified a schema example is found for the parent
|
// 'generateFuzzablePayload' is specified a schema example is found for the parent
|
||||||
// object (e.g. an array).
|
// object (e.g. an array).
|
||||||
if generateFuzzablePayload then
|
if generateFuzzablePayload then
|
||||||
Fuzzable (primitiveType, defaultValue, Some payloadValue, propertyName)
|
Fuzzable { fp with exampleValue = Some payloadValue }
|
||||||
else
|
else
|
||||||
Constant (primitiveType, payloadValue)
|
Constant (fp.primitiveType, payloadValue)
|
||||||
| _ -> raise (invalidOp(sprintf "invalid payload %A, expected fuzzable" fuzzablePropertyPayload))
|
| _ -> raise (invalidOp(sprintf "invalid payload %A, expected fuzzable" fuzzablePropertyPayload))
|
||||||
|
|
||||||
{ fuzzablePropertyPayload with payload = examplePropertyPayload }
|
{ fuzzablePropertyPayload with payload = examplePropertyPayload }
|
||||||
|
@ -507,7 +530,14 @@ module SwaggerVisitors =
|
||||||
match s.Type with
|
match s.Type with
|
||||||
| JsonObjectType.Object ->
|
| JsonObjectType.Object ->
|
||||||
// Do not insert a default fuzzable property for objects
|
// 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
|
getFuzzableValueForObjectType s.Item.Type s.Format None None trackParameters
|
||||||
|
|
||||||
|
@ -523,7 +553,15 @@ module SwaggerVisitors =
|
||||||
else
|
else
|
||||||
Some (getValueForObjectType schema.Item)
|
Some (getValueForObjectType schema.Item)
|
||||||
| JsonObjectType.None ->
|
| 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)
|
Some (getValueForObjectType schema)
|
||||||
|
|
||||||
|
@ -733,7 +771,14 @@ module SwaggerVisitors =
|
||||||
let leafPayload =
|
let leafPayload =
|
||||||
let exampleValue = GenerateGrammarElements.formatJTokenProperty primitiveType v
|
let exampleValue = GenerateGrammarElements.formatJTokenProperty primitiveType v
|
||||||
if generateFuzzablePayloadsForExamples then
|
if generateFuzzablePayloadsForExamples then
|
||||||
FuzzingPayload.Fuzzable (primitiveType, defaultValue, Some exampleValue, None)
|
FuzzingPayload.Fuzzable
|
||||||
|
{
|
||||||
|
primitiveType = primitiveType
|
||||||
|
defaultValue = defaultValue
|
||||||
|
exampleValue = Some exampleValue
|
||||||
|
parameterName = None
|
||||||
|
dynamicObject = None
|
||||||
|
}
|
||||||
else
|
else
|
||||||
FuzzingPayload.Constant (primitiveType, exampleValue)
|
FuzzingPayload.Constant (primitiveType, exampleValue)
|
||||||
|
|
||||||
|
|
Загрузка…
Ссылка в новой задаче