* fix variable patches

* add test case

* update changelog

* update snapshot
This commit is contained in:
Lei Ni 2022-08-02 10:25:32 +08:00 коммит произвёл GitHub
Родитель f37550d3cb
Коммит c1996477d6
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
6 изменённых файлов: 1354 добавлений и 192 удалений

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

@ -1,6 +1,7 @@
# Change Log - oav # Change Log - oav
## 07/20/2022 3.0.4 ## 07/20/2022 3.0.4
- GenerateExamples - Support data generation in byte format - GenerateExamples - Support data generation in byte format
- ModelValidator - Support data validation in byte format - ModelValidator - Support data validation in byte format
- API Scenario - API Scenario
@ -8,8 +9,10 @@
- Fix step variable unresolved in newman collection - Fix step variable unresolved in newman collection
- Fix bugs about html report - Fix bugs about html report
- Aggregate reports into one per scenario file - Aggregate reports into one per scenario file
- Fix bug of object variables and patches
## 07/06/2022 3.0.3 ## 07/06/2022 3.0.3
- Generate high quality examples from API Scenario tests - Generate high quality examples from API Scenario tests
## 06/30/2022 3.0.2 ## 06/30/2022 3.0.2

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

@ -336,7 +336,7 @@ export class ApiScenarioLoader implements Loader<ScenarioDefinition> {
throw new Error("Invalid step"); throw new Error("Invalid step");
} }
} catch (error) { } catch (error) {
throw new Error(`Failed to load step ${rawStep.step}: ${(error as any).message}`); throw new Error(`Failed to load step ${JSON.stringify(rawStep)}: ${(error as any).message}`);
} }
if (step.outputVariables) { if (step.outputVariables) {
@ -381,28 +381,40 @@ export class ApiScenarioLoader implements Loader<ScenarioDefinition> {
ctx.stepTracking.set(step.step, step); ctx.stepTracking.set(step.step, step);
const getVariable = (name: string): Variable => { const getVariable = (
const variable = name: string,
step.variables[name] ?? ctx.scenario?.variables[name] ?? ctx.scenarioDef.variables[name]; ...scopes: Array<VariableScope | undefined>
if (variable === undefined) { ): Variable | undefined => {
const requiredVariables = if (!scopes || scopes.length === 0) {
ctx.scenario?.requiredVariables ?? ctx.scenarioDef.requiredVariables; scopes = [step, ctx.scenario, ctx.scenarioDef];
if ( }
requiredVariables.includes(name) || for (const scope of scopes) {
(ctx.scenarioDef.scope === "ResourceGroup" && if (scope && scope.variables[name]) {
["subscriptionId", "resourceGroupName", "location"].indexOf(name) >= 0) return scope.variables[name];
) { }
}
for (const scope of scopes) {
if (scope && scope.requiredVariables.includes(name)) {
return { return {
type: "string", type: "string",
value: `$(${name})`, value: `$(${name})`,
}; };
} }
} }
return variable; if (
ctx.scenarioDef.scope === "ResourceGroup" &&
["subscriptionId", "resourceGroupName", "location"].includes(name)
) {
return {
type: "string",
value: `$(${name})`,
};
}
return undefined;
}; };
const requireVariable = (name: string) => { const requireVariable = (name: string) => {
if (["resourceGroupName"].includes(name)) { if (ctx.scenarioDef.scope === "ResourceGroup" && ["resourceGroupName"].includes(name)) {
return; return;
} }
const requiredVariables = const requiredVariables =
@ -441,7 +453,13 @@ export class ApiScenarioLoader implements Loader<ScenarioDefinition> {
if (value.type === "object" || value.type === "secureObject" || value.type === "array") { if (value.type === "object" || value.type === "secureObject" || value.type === "array") {
if (value.patches) { if (value.patches) {
const obj = cloneDeep(getVariable(name)); const variable = ctx.scenario
? getVariable(name, ctx.scenario, ctx.scenarioDef)
: getVariable(name, ctx.scenarioDef);
if (!variable) {
throw new Error(`Variable ${name} not found in step ${step.step}`);
}
const obj = cloneDeep(variable);
if (typeof obj !== "object") { if (typeof obj !== "object") {
// TODO dynamic json patch // TODO dynamic json patch
throw new Error(`Can not Json Patch on ${name}, type of ${typeof obj}`); throw new Error(`Can not Json Patch on ${name}, type of ${typeof obj}`);
@ -737,6 +755,11 @@ const convertVariables = (rawVariables: RawVariableScope["variables"]) => {
if (val.value === undefined && val.prefix === undefined) { if (val.value === undefined && val.prefix === undefined) {
result.requiredVariables.push(key); result.requiredVariables.push(key);
} }
} else if (
(val.type === "object" || val.type === "secureObject" || val.type === "array") &&
val.patches !== undefined
) {
// ok
} else { } else {
throw new Error( throw new Error(
`Only string and secureString type is supported in environment variables, please specify value for: ${key}` `Only string and secureString type is supported in environment variables, please specify value for: ${key}`

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

@ -37,7 +37,7 @@ export class TemplateGenerator {
public exampleParameterConvention( public exampleParameterConvention(
step: Pick<StepRestCall, "parameters" | "responses" | "operation">, step: Pick<StepRestCall, "parameters" | "responses" | "operation">,
variables: (name: string) => any, getVariable: (name: string) => any,
operation: Operation operation: Operation
) { ) {
const toMatch: string[] = []; const toMatch: string[] = [];
@ -45,7 +45,7 @@ export class TemplateGenerator {
const parameters = cloneDeep(step.parameters); const parameters = cloneDeep(step.parameters);
for (const paramName of Object.keys(parameters)) { for (const paramName of Object.keys(parameters)) {
if (variables(paramName) === undefined) { if (getVariable(paramName) === undefined) {
continue; continue;
} }

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

@ -771,6 +771,111 @@ Object {
}, },
}, },
}, },
Object {
"_scenarioDef": [Circular],
"description": "",
"requiredVariables": Array [
"subscriptionId",
"location",
],
"scenario": "patchVariables",
"secretVariables": Array [],
"shareScope": true,
"steps": Array [
Object {
"description": undefined,
"operation": Object {},
"operationId": "StorageAccounts_Create",
"outputVariables": Object {},
"parameters": Object {
"accountName": "$(accountName)",
"api-version": "2021-08-01",
"parameters": Object {
"properties": Object {
"kind": "StorageV2",
"location": "$(location)",
"patches": Array [
Object {
"add": "/properties/kind",
"value": "StorageV2",
},
],
"properties": Object {
"encryption": Object {
"keySource": "Microsoft.Storage",
"services": Object {
"blob": Object {},
},
},
},
"sku": "Standard",
},
},
"resourceGroupName": "$(resourceGroupName)",
"subscriptionId": "$(subscriptionId)",
},
"requiredVariables": Array [],
"responses": Object {},
"secretVariables": Array [],
"step": "createStorageAccount",
"type": "restCall",
"variables": Object {
"parameters": Object {
"type": "object",
"value": Object {
"properties": Object {
"kind": "StorageV2",
"location": "$(location)",
"patches": Array [
Object {
"add": "/properties/kind",
"value": "StorageV2",
},
],
"properties": Object {
"encryption": Object {
"keySource": "Microsoft.Storage",
"services": Object {
"blob": Object {},
},
},
},
"sku": "Standard",
},
},
},
},
},
],
"variables": Object {
"parameters": Object {
"type": "object",
"value": Object {
"properties": Object {
"kind": "StorageV2",
"location": "$(location)",
"patches": Array [
Object {
"add": "/properties/kind",
"value": "StorageV2",
},
],
"properties": Object {
"encryption": Object {
"keySource": "Microsoft.Storage",
"services": Object {
"blob": Object {},
},
},
},
"sku": Object {
"name": "Standard_LRS",
},
},
},
},
},
},
], ],
"scope": "ResourceGroup", "scope": "ResourceGroup",
"secretVariables": Array [], "secretVariables": Array [],

Разница между файлами не показана из-за своего большого размера Загрузить разницу

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

@ -28,7 +28,7 @@ scenarios:
kind: StorageV2 kind: StorageV2
location: $(location) location: $(location)
properties: properties:
encryption: {"services": {"blob": {}}, "keySource": "Microsoft.Storage"} encryption: { "services": { "blob": {} }, "keySource": "Microsoft.Storage" }
- scenario: overrideVariable - scenario: overrideVariable
variables: variables:
accountName: $(accountName)2 accountName: $(accountName)2
@ -52,7 +52,7 @@ scenarios:
kind: StorageV2 kind: StorageV2
location: $(location) location: $(location)
properties: properties:
encryption: {"services": {"blob": {}}, "keySource": "Microsoft.Storage"} encryption: { "services": { "blob": {} }, "keySource": "Microsoft.Storage" }
- scenario: primitiveParameter - scenario: primitiveParameter
variables: variables:
accountName: accountName:
@ -78,7 +78,7 @@ scenarios:
kind: StorageV2 kind: StorageV2
location: $(location) location: $(location)
properties: properties:
encryption: {"services": {"blob": {}}, "keySource": "Microsoft.Storage"} encryption: { "services": { "blob": {} }, "keySource": "Microsoft.Storage" }
- step: DeletedAccounts_Get - step: DeletedAccounts_Get
operationId: DeletedAccounts_Get operationId: DeletedAccounts_Get
parameters: parameters:
@ -87,3 +87,27 @@ scenarios:
deletedAccountName: deletedAccountName:
type: string type: string
prefix: foobar prefix: foobar
- scenario: patchVariables
variables:
parameters:
type: object
value:
properties:
sku:
name: Standard_LRS
kind: StorageV2
location: $(location)
properties:
encryption: { "services": { "blob": {} }, "keySource": "Microsoft.Storage" }
patches:
- add: /properties/kind
value: StorageV2
steps:
- step: createStorageAccount
operationId: StorageAccounts_Create
variables:
parameters:
type: object
patches:
- replace: /properties/sku
value: Standard