* trace example parameters

* WIP: simple check

* WIP: check replace_value

* format checks

* check list length

* check create/delete status

* check complex array

* dynamic header

* check 200/201/204 body

* nonstrict

* handle name in response

* split json

* replace check path

* remove format in checks

* remove commented code and reformat

* swicher for gen-checks

* option for disable-check

* reorg
This commit is contained in:
changlong-liu 2020-08-27 13:19:31 +08:00 коммит произвёл GitHub
Родитель e8d9125172
Коммит 872ccd42e6
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
6 изменённых файлов: 375 добавлений и 75 удалений

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

@ -29,7 +29,10 @@ export class ExampleParam {
keys: string[];
defaultName: string;
methodParam: MethodParam;
public constructor(name: string, value: any, isJson: boolean, isKeyValues: boolean, keys: string[], defaultName: string, methodParam: MethodParam) {
ancestors: string[];
replacedValue: any;
rawValue: any;
public constructor(name: string, value: any, isJson: boolean, isKeyValues: boolean, keys: string[], defaultName: string, methodParam: MethodParam, ancestors: string[], rawValue: any) {
this.name = name;
this.value = value;
this.isJson = isJson;
@ -37,6 +40,8 @@ export class ExampleParam {
this.keys = keys;
this.defaultName = defaultName;
this.methodParam = methodParam;
this.ancestors = ancestors;
this.rawValue = rawValue;
}
}
export class CommandExample {
@ -52,6 +57,7 @@ export class CommandExample {
public MethodResponses: any[];
public Method_IsLongRun: boolean;
public MethodParams: MethodParam[];
public ExampleObj: any;
}
export interface CodeModelAz {
@ -176,7 +182,7 @@ export interface CodeModelAz {
GenerateTestInit(): void;
SelectFirstExample(): boolean;
SelectNextExample(): boolean;
FindExampleById(id: string, commandParams: any): string[][];
FindExampleById(id: string, commandParams: any, examples: any[]): string[][];
Example_Body: string[];
Example_Title: string;
Example_Params: any;
@ -186,6 +192,7 @@ export interface CodeModelAz {
GatherInternalResource();
FindExampleWaitById(id: string): string[][];
GetExampleItems(example: CommandExample, isTest: boolean, commandParams: any): string[];
GetExampleChecks(example: CommandExample): string[];
RandomizeNames: boolean;
// readme config

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

@ -11,7 +11,7 @@ import { isArray, isNullOrUndefined } from "util";
import { Capitalize, deepCopy, parseResourceId, ToCamelCase, ToJsonString, ToSnakeCase } from '../../utils/helper';
import { GenerationMode } from "../models";
import { CodeModelAz, CommandExample, ExampleParam, MethodParam } from "./CodeModelAz";
import { azOptions, GenerateDefaultTestScenario, GenerateDefaultTestScenarioByDependency, PrintTestScenario, ResourcePool } from './ScenarioTool';
import { azOptions, GenerateDefaultTestScenario, GenerateDefaultTestScenarioByDependency, PrintTestScenario, ResourcePool, ObjectStatus } from './ScenarioTool';
class ActionParam {
@ -125,15 +125,23 @@ export class CodeModelCliImpl implements CodeModelAz {
}
public get RandomizeNames(): boolean {
if (this.options?.['randomize-names']) return true;
let randomizeNames = this.options?.['randomize-names'];
if (randomizeNames) return true;
return false;
}
public get FormalizeNames(): boolean {
if (this.options?.['formalize-names']) return true;
let formalizeNames = this.options?.['formalize-names'];
if (formalizeNames) return true;
return false;
}
public get GenChecks(): boolean {
let disableChecks = this.options?.['disable-checks'];
if (disableChecks) return false;
return true;
}
private calcOptionRequiredByMethod() {
if (this.SelectFirstCommandGroup()) {
do {
@ -1625,7 +1633,7 @@ export class CodeModelCliImpl implements CodeModelAz {
return (this.Command_GetOriginalOperation && param?.targetProperty?.['isDiscriminator']) ? true : false;
}
private AddExampleParameter(methodParam: MethodParam, example_param: ExampleParam[], value: any, polySubParam: MethodParam): boolean {
private AddExampleParameter(methodParam: MethodParam, example_param: ExampleParam[], value: any, polySubParam: MethodParam, ancestors: string[]): boolean {
let isList: boolean = methodParam.isList;
let isSimpleListOrArray: boolean = methodParam.isSimpleListOrArray;
let defaultName: string = methodParam.value.language['cli'].cliKey;
@ -1648,7 +1656,7 @@ export class CodeModelCliImpl implements CodeModelAz {
if (isSimpleListOrArray) {
if (value instanceof Array) { // spread list
for (let e of value) {
this.AddExampleParameter(methodParam, example_param, e, polySubParam);
this.AddExampleParameter(methodParam, example_param, e, polySubParam, ancestors);
}
handled = true;
}
@ -1692,23 +1700,23 @@ export class CodeModelCliImpl implements CodeModelAz {
keys.push(cliName)
}
if (ret.length > 0) {
example_param.push(new ExampleParam(name, ret, false, true, keys, defaultName, methodParam));
example_param.push(new ExampleParam(name, ret, false, true, keys, defaultName, methodParam, ancestors, value));
}
handled = true;
}
}
if (!handled) {
if (typeof value == 'string') {
example_param.push(new ExampleParam(name, value, false, false, [], defaultName, methodParam));
example_param.push(new ExampleParam(name, value, false, false, [], defaultName, methodParam, ancestors, value));
}
else {
// JSON form
example_param.push(new ExampleParam(name, JSON.stringify(value).split(/[\r\n]+/).join(""), true, false, [], defaultName, methodParam));
example_param.push(new ExampleParam(name, JSON.stringify(value).split(/[\r\n]+/).join(""), true, false, [], defaultName, methodParam, ancestors, value));
}
}
}
else if (typeof value != 'object') {
example_param.push(new ExampleParam(name, value, false, false, [], defaultName, methodParam));
example_param.push(new ExampleParam(name, value, false, false, [], defaultName, methodParam, ancestors, value));
}
else {
// ignore object values if not isList.
@ -1807,7 +1815,7 @@ export class CodeModelCliImpl implements CodeModelAz {
}
if (match) {
// example_param.set(name, value);
this.AddExampleParameter(methodParam, example_param, netValue, polySubParam);
this.AddExampleParameter(methodParam, example_param, netValue, polySubParam, ancestors);
return;
}
}
@ -1830,13 +1838,13 @@ export class CodeModelCliImpl implements CodeModelAz {
}
if (match) {
// example_param.set(name, value);
this.AddExampleParameter(methodParam, example_param, netValue, polySubParam);
this.AddExampleParameter(methodParam, example_param, netValue, polySubParam, ancestors);
return;
}
}
else if (ancestors.length == 0) {
// example_param.set(name, value);
if (this.AddExampleParameter(methodParam, example_param, netValue, polySubParam)) return;
if (this.AddExampleParameter(methodParam, example_param, netValue, polySubParam, ancestors)) return;
}
}
@ -1861,7 +1869,7 @@ export class CodeModelCliImpl implements CodeModelAz {
// }
}
param_name = param_name.split("_").join("-");
ret.push(new ExampleParam("--" + param_name, param.value, param.isJson, param.isKeyValues, param.keys, param.defaultName, param.methodParam));
ret.push(new ExampleParam("--" + param_name, param.value, param.isJson, param.isKeyValues, param.keys, param.defaultName, param.methodParam, param.ancestors, param.rawValue));
};
return ret;
}
@ -1922,6 +1930,7 @@ export class CodeModelCliImpl implements CodeModelAz {
example.Parameters = this.ConvertToCliParameters(params);
example.MethodResponses = this.Method.responses || [];
example.Method_IsLongRun = this.Method.extensions?.['x-ms-long-running-operation'] ? true : false;
example.ExampleObj = example_obj;
if (this.Method_GetSplitOriginalOperation) {
//filter example by name for generic createorupdate
if (this.Command_MethodName.toLowerCase() == "update" && !id.toLowerCase().endsWith("_update"))
@ -1943,11 +1952,30 @@ export class CodeModelCliImpl implements CodeModelAz {
return examples;
}
public GetExampleChecks(example: CommandExample): string[] {
let ret: string[] = [];
if (!this.GenChecks) return ret;
let resourceObjectName = undefined;
for (let param of example.Parameters) {
if (example.ResourceClassName && this.resource_pool.isResource(param.defaultName) == example.ResourceClassName) {
resourceObjectName = param.value;
}
}
let resourceObject = this.resource_pool.findResource(example.ResourceClassName, resourceObjectName, ObjectStatus.Created);
if (resourceObject) {
ret.push(...resourceObject.getCheckers(this.resource_pool, example));
}
ret.push(...this.resource_pool.getListCheckers(example));
return ret;
}
public GetExampleItems(example: CommandExample, isTest: boolean, commandParams: any): string[] {
let parameters: string[] = [];
parameters.push("az " + this.Command_Name);
let hasRG = false;
let resourceObjectName = undefined;
for (let param of example.Parameters) {
let param_value = param.value;
if (isTest || this.FormalizeNames) {
@ -1956,6 +1984,7 @@ export class CodeModelCliImpl implements CodeModelAz {
replaced_value = this.resource_pool.addParamResource(param.defaultName, param_value, param.isJson, param.isKeyValues, isTest);
}
param_value = replaced_value;
param.replacedValue = replaced_value;
}
let slp = param_value;
if (!param.isKeyValues) {
@ -1966,12 +1995,35 @@ export class CodeModelCliImpl implements CodeModelAz {
if (["--resource-group", "-g"].indexOf(param.name) >= 0) {
hasRG = true;
}
if (example.ResourceClassName && this.resource_pool.isResource(param.defaultName) == example.ResourceClassName) {
resourceObjectName = param.value;
}
}
if (isTest && !hasRG && commandParams && commandParams[this.Command_Name] && commandParams[this.Command_Name].has("resourceGroupName")) {
parameters.push('-g ""');
}
if (isTest) {
let resourceObject = this.resource_pool.findResource(example.ResourceClassName, resourceObjectName, undefined);
if (resourceObject) {
let httpMethod = example.HttpMethod.toLowerCase();
if (['put', 'post', 'patch'].indexOf(httpMethod)>=0) {
if (httpMethod == 'post') {
resourceObject.example_params = [];
}
for (let param of example.Parameters) {
resourceObject.addOrUpdateParam(param);
}
resourceObject.testStatus = ObjectStatus.Created;
}
if (httpMethod == 'delete') {
resourceObject.testStatus = ObjectStatus.Deleted;
}
}
}
return parameters;
}
@ -2019,9 +2071,10 @@ export class CodeModelCliImpl implements CodeModelAz {
}
}
public FindExampleById(id: string, commandParams?: any): string[][] {
public FindExampleById(id: string, commandParams: any, examples: CommandExample[]): string[][] {
let ret: string[][] = [];
this.GetAllExamples(id, (example) => {
examples.push(example);
ret.push(this.GetExampleItems(example, true, commandParams));
});
return ret;

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

@ -1,8 +1,7 @@
import * as path from "path"
import { CommandExample, ExampleParam } from "./CodeModelAz";
import { deepCopy, isDict, ToCamelCase, changeCamelToDash } from "../../utils/helper"
import { Example } from "@azure-tools/codemodel";
import { deepCopy, isDict, ToCamelCase, ToPythonString, changeCamelToDash } from "../../utils/helper"
import { EnglishPluralizationService } from "@azure-tools/codegen";
import { isNullOrUndefined } from "util";
@ -201,16 +200,26 @@ class ResourceClass {
}
}
export enum ObjectStatus {
None,
Created,
Deleted,
}
class ResourceObject {
object_name: string;
class_name: string;
// key: string;
sub_resources: Map<string, ResourceClass>; //class_name --> resource_class
example_params: ExampleParam[];
testStatus: ObjectStatus;
public constructor(object_name: string, class_name: string) {
this.object_name = object_name;
this.class_name = class_name;
this.sub_resources = new Map<string, ResourceClass>();
this.example_params = [];
this.testStatus = ObjectStatus.None;
}
public get key(): string {
@ -218,24 +227,142 @@ class ResourceObject {
}
public placeholder(isTest: boolean): string {
if (isTest) return '{' + this.key + '}';
if (isTest) return '{' + this.key + '}';
return getResourceKey(this.class_name, this.object_name, true);
}
public addOrUpdateParam(example_param: ExampleParam) {
// remove all children
for (let i = 0; i < this.example_params.length; i++) {
let param = this.example_params[i];
if (param.ancestors == example_param.ancestors.concat([example_param.name])) {
this.example_params.splice(i);
i--;
}
}
// replace if already there
for (let i = 0; i < this.example_params.length; i++) {
let param = this.example_params[i];
if (JSON.stringify(param.ancestors) == JSON.stringify(example_param.ancestors) && param.name == example_param.name) {
this.example_params[i] = example_param;
return;
}
}
// append to the tail
this.example_params.push(example_param);
}
public getCheckers(resource_pool: ResourcePool, example: CommandExample): string[] {
function hasComplexArray(obj: any): boolean {
if (obj instanceof Array) {
if (obj.length > 1) return true;
for (let s of obj) {
if (hasComplexArray(s)) return true;
}
}
if (isDict(obj)) {
for (let key in obj) {
if (hasComplexArray(obj[key])) return true;
}
}
return false;
}
function addParam(obj: any, param: ExampleParam, checkPath: string, ret: string[]) {
if (isDict(obj)) {
if (checkPath.length > 0) checkPath += ".";
if (param.defaultName in obj && typeof obj[param.defaultName] == typeof param.rawValue && JSON.stringify(obj[param.defaultName]).toLowerCase() == JSON.stringify(param.rawValue).toLowerCase()) {
if (hasComplexArray(param.rawValue)) return;
formatChecker(checkPath + resource_pool.replaceResourceString(param.defaultName, [], [], true), param.rawValue, ret);
return;
}
else if ('name' in obj && typeof obj['name'] == typeof param.rawValue && JSON.stringify(obj['name']).toLowerCase() == JSON.stringify(param.rawValue).toLowerCase()) {
if (hasComplexArray(param.rawValue)) return;
formatChecker(checkPath + 'name', param.rawValue, ret);
return;
}
}
if (obj instanceof Array) {
if (obj.length > 1) return;
addParam(obj[0], param, checkPath + "[0]", ret);
}
if (isDict(obj)) {
if (checkPath.length > 0) checkPath += ".";
for (let key in obj) {
if (checkPath.length==0 && key.toLowerCase()=='properties') {
addParam(obj[key], param, checkPath, ret);
}
else {
addParam(obj[key], param, checkPath + resource_pool.replaceResourceString(key, [], [], true), ret);
}
}
}
}
function formatChecker(checkPath: string, rawValue: any, ret: string[]) {
if (typeof rawValue == 'object') {
if (rawValue instanceof Array) {
if (rawValue.length > 1) return;
if (rawValue.length == 0) {
ret.push(`test.check("${checkPath}", []),`);
}
else {
formatChecker(checkPath + "[0]", rawValue[0], ret);
}
}
else if (isDict(rawValue)) {
if (checkPath.length > 0) checkPath += ".";
if (Object.keys(rawValue).length == 0) {
ret.push(`test.check("${checkPath}", {}),`);
}
for (let key in rawValue) {
formatChecker(checkPath + resource_pool.replaceResourceString(key, [], [], true), rawValue[key], ret);
}
}
}
else {
if (typeof rawValue == 'string') {
let replacedValue = resource_pool.replaceResourceString(rawValue, [], [], true);
ret.push(`test.check("${checkPath}", ${ToPythonString(replacedValue, typeof replacedValue)}, case_sensitive=False),`);
}
else {
ret.push(`test.check("${checkPath}", ${ToPythonString(rawValue, typeof rawValue)}),`);
}
}
}
let ret: string[] = [];
if (['create', 'delete', 'show', 'list', 'update'].indexOf(example.Method) < 0) return ret;
let example_resp_body = null;
for (let statusCode of [200, 201, 204]) {
example_resp_body = example.ExampleObj.responses?.[200]?.body;
if (!isNullOrUndefined(example_resp_body)) break;
}
if (isNullOrUndefined(example_resp_body)) return ret;
for (let param of this.example_params) {
addParam(example_resp_body, param, "", ret);
}
return ret;
}
}
function singlizeLast(word:string) {
function singlizeLast(word: string) {
let eps = new EnglishPluralizationService();
let ws = changeCamelToDash(word).split('-');
let l = ws.length;
ws[l-1] = eps.singularize(ws[l-1]);
ws[l - 1] = eps.singularize(ws[l - 1]);
return ws.join('-');
}
let keyCache = {} //class_name+objectname->key
let formalCache = {}
let keySeq = {} // class_name ->seq
export function getResourceKey(class_name: string, object_name: string, formalName=false): string {
export function getResourceKey(class_name: string, object_name: string, formalName = false): string {
let longKey = (resourceClassKeys[class_name] || class_name) + '_' + object_name;
if (formalName && longKey in formalCache) {
return formalCache[longKey];
@ -247,12 +374,12 @@ export function getResourceKey(class_name: string, object_name: string, formalNa
if (keySeq.hasOwnProperty(class_name)) {
let key = (resourceClassKeys[class_name] || class_name) + '_' + keySeq[class_name];
keySeq[class_name] += 1;
formalCache[longKey] = ToCamelCase(`my-${singlizeLast(class_name)}${keySeq[class_name]-1}`);
formalCache[longKey] = ToCamelCase(`my-${singlizeLast(class_name)}${keySeq[class_name] - 1}`);
if (preparerInfos[class_name]?.name) { // is external resource
keyCache[longKey] = key;
}
else {
keyCache[longKey] = ToCamelCase(`my-${singlizeLast(class_name)}${keySeq[class_name]-1}`);
keyCache[longKey] = ToCamelCase(`my-${singlizeLast(class_name)}${keySeq[class_name] - 1}`);
}
}
else {
@ -268,7 +395,7 @@ export function getResourceKey(class_name: string, object_name: string, formalNa
}
}
return formalName? formalCache[longKey]: keyCache[longKey];
return formalName ? formalCache[longKey] : keyCache[longKey];
}
export class ResourcePool {
@ -277,11 +404,13 @@ export class ResourcePool {
map: Map<string, ResourceClass>;
use_subscription: boolean;
static KEY_SUBSCRIPTIONID = "subscription_id";
replacements: Map<string, string>;
public constructor() {
this.root = new Map<string, ResourceClass>();
this.map = new Map<string, ResourceClass>();
this.use_subscription = false;
this.replacements = new Map<string, string>();
}
private prepareResource(class_name: string, object_name: string, depends: string[][], entitys: PreparerEntity[], preparings: string[][]) {
@ -393,20 +522,81 @@ export class ResourcePool {
return resources[class_name].objects[object_name];
}
public findTreeResource(class_name: string, object_name: string, root: Map<string, ResourceClass>): ResourceObject {
public findResource(class_name: string, object_name: string, testStatus: ObjectStatus): ResourceObject | undefined {
if (isNullOrUndefined(class_name) || isNullOrUndefined(object_name)) return null;
let resource_object = this.findTreeResource(class_name, object_name, this.root, testStatus);
if (resource_object) {
return resource_object;
}
if (class_name in this.map && object_name in this.map[class_name].objects) {
if (isNullOrUndefined(testStatus) || testStatus == this.map[class_name].objects[object_name].testStatus) {
return this.map[class_name].objects[object_name];
}
}
return undefined;
}
public findAllResource(class_name: string, exampleParams: ExampleParam[] = null, testStatus: ObjectStatus = null): ResourceObject[] {
let ret: ResourceObject[] = [];
if (isNullOrUndefined(class_name)) return ret;
this.findAllTreeResource(class_name, this.root, ret);
if (class_name in this.map) {
for (let key in this.map[class_name].objects) {
ret.push(this.map[class_name].objects[key]);
}
}
return ret.filter((resourceObject) => {
for (let critParam of exampleParams) {
let found = false;
for (let resourceParam of resourceObject.example_params) {
if (critParam.name == resourceParam.name && critParam.rawValue == resourceParam.rawValue) {
found = true;
break;
}
}
if (!found) return false;
};
return isNullOrUndefined(testStatus) || testStatus == resourceObject.testStatus;
});
}
public findAllTreeResource(class_name: string, root: Map<string, ResourceClass>, ret: ResourceObject[]) {
if (class_name in root) {
for (let key in root[class_name].objects) {
ret.push(root[class_name].objects[key]);
}
}
for (let c in root) {
for (let o in root[c].objects) {
this.findAllTreeResource(class_name, root[c].objects[o].sub_resources, ret);
}
}
}
public findTreeResource(class_name: string, object_name: string, root: Map<string, ResourceClass>, testStatus: ObjectStatus = null): ResourceObject {
if (class_name in root && object_name in root[class_name].objects) {
return root[class_name].objects[object_name];
if (isNullOrUndefined(testStatus) || testStatus == root[class_name].objects[object_name].testStatus) {
return root[class_name].objects[object_name];
}
}
if (!class_name) {
for (let c in root) {
if (object_name in root[c].objects) {
return root[c].objects[object_name];
if (isNullOrUndefined(testStatus) || testStatus == root[c].objects[object_name].testStatus) {
return root[c].objects[object_name];
}
}
}
}
for (let c in root) {
for (let o in root[c].objects) {
let ret = this.findTreeResource(class_name, object_name, root[c].objects[o].sub_resources);
let ret = this.findTreeResource(class_name, object_name, root[c].objects[o].sub_resources, testStatus);
if (ret) return ret;
}
}
@ -431,7 +621,8 @@ export class ResourcePool {
return this.map[class_name].objects[object_name];
}
public isResource(language): string | null {
public isResource(language: string): string | null {
if (language.startsWith("--")) language = language.substr(2);
for (let resource in resourceLanguages) {
for (let resource_language of resourceLanguages[resource]) {
if (resource_language.toLowerCase() == language.toLowerCase()) return resource;
@ -458,7 +649,7 @@ export class ResourcePool {
return false;
}
public addEndpointResource(endpoint: any, isJson: boolean, isKeyValues: boolean, placeholders: string[], resources: string[], exampleParam: ExampleParam, isTest=true) {
public addEndpointResource(endpoint: any, isJson: boolean, isKeyValues: boolean, placeholders: string[], resources: string[], exampleParam: ExampleParam, isTest = true): any {
if (placeholders == undefined) placeholders = new Array();
if (isJson) {
let body = typeof endpoint == 'string' ? JSON.parse(endpoint) : endpoint;
@ -480,7 +671,7 @@ export class ResourcePool {
if (typeof endpoint == 'string') {
let ret = JSON.stringify(body).split(/[\r\n]+/).join("");
return isTest ? this.formatable(ret, placeholders): ret;
return isTest ? this.formatable(ret, placeholders) : ret;
}
else {
return body;
@ -524,7 +715,9 @@ export class ResourcePool {
}
return ret;
}
return this.replaceResourceString(endpoint, placeholders, resources, isTest);
}
public replaceResourceString(endpoint: string, placeholders: string[], resources: string[], isTest = true): any {
let nodes = endpoint.split('/');
if (nodes.length < 3 || nodes[0].length > 0 || nodes[1].toLowerCase() != SUBSCRIPTIONS) {
return this.getPlaceholder(endpoint, isTest, placeholders);
@ -557,14 +750,14 @@ export class ResourcePool {
}
}
else {
nodes[i + 1] = this.getPlaceholder(nodes[i+1], isTest);
nodes[i + 1] = this.getPlaceholder(nodes[i + 1], isTest);
}
i += 2;
}
return nodes.join('/');
}
public addParamResource(param_name: string, param_value: string, isJson: boolean, isKeyValues: boolean, isTest=true): string {
public addParamResource(param_name: string, param_value: string, isJson: boolean, isKeyValues: boolean, isTest = true): string {
if (typeof param_value !== 'string' || isJson || isKeyValues) return param_value;
if (param_name.startsWith('--')) {
@ -587,7 +780,8 @@ export class ResourcePool {
}
}
public getPlaceholder(object_name: string, isTest: boolean, placeholders: string[]=null): string {
public getPlaceholder(object_name: string, isTest: boolean, placeholders: string[] = null): string {
// find in MapResource
for (let class_name in this.map) {
if (object_name in this.map[class_name].objects) {
@ -615,9 +809,12 @@ export class ResourcePool {
let regex = /^\d\d\d\d\-\d\d\-\d\dT\d\d:\d\d:\d\d.\d+Z$/g
if (azOptions?.['replace-datetime'] && regex.test(object_name)) {
let date = new Date();
date.setDate(date.getDate() + 10);
return date.toISOString();
if (!this.replacements.has(object_name)) {
let date = new Date();
date.setDate(date.getDate() + 10);
this.replacements.set(object_name, date.toISOString());
}
return this.replacements.get(object_name)
}
return object_name;
}
@ -657,5 +854,15 @@ export class ResourcePool {
let depends = resourceClassDepends[child];
return depends && depends.indexOf(parent) >= 0;
}
public getListCheckers(example: CommandExample): string[] {
let ret = [];
if (example.Method != "list") return ret;
let len = this.findAllResource(example.ResourceClassName, example.Parameters, ObjectStatus.Created).length;
if (len > 0) {
ret.push(`test.check('length(@)', ${len}),`);
}
return ret;
}
}

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

@ -3,11 +3,10 @@
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { CodeModelAz } from "./CodeModelAz"
import { CodeModelAz, CommandExample } from "./CodeModelAz"
import { PreparerEntity, getResourceKey } from "./ScenarioTool"
import { ToSnakeCase, ToMultiLine, deepCopy } from '../../utils/helper';
import { ToMultiLine, deepCopy } from '../../utils/helper';
import { HeaderGenerator } from "./Header";
import { HttpWithBodyRequest } from "@azure-tools/codemodel";
let usePreparers = false;
@ -30,11 +29,9 @@ export function GenerateAzureCliTestScenario(model: CodeModelAz): string[] {
let header: HeaderGenerator = new HeaderGenerator();
head.push("");
head.push("import os");
header.addImport("os");
head.push("from azure.cli.testsdk import ScenarioTest");
head.push("from .. import try_manual, raise_if, calc_coverage");
//head.push("from .preparers import (VirtualNetworkPreparer, VnetSubnetPreparer)");
steps.push("");
steps.push("");
steps.push("TEST_DIR = os.path.abspath(os.path.join(os.path.abspath(__file__), '..'))");
@ -44,18 +41,8 @@ export function GenerateAzureCliTestScenario(model: CodeModelAz): string[] {
class_info.push("@try_manual");
class_info.push("class " + model.Extension_NameClass + "ScenarioTest(ScenarioTest):");
class_info.push("");
//initiates.push(" @ResourceGroupPreparer(name_prefix='cli_test_" + model.Extension_NameUnderscored + "')");
// initiates.push(" def test_" + model.Extension_NameUnderscored + "(self, resource_group):");
initiates.push("");
// go through the examples to recognize resources
for (var ci = 0; ci < config.length; ci++) {
let exampleId: string = config[ci].name;
if (exampleId) {
model.FindExampleById(exampleId, commandParams);
}
}
let subscription_id = model.GetSubscriptionKey();
if (subscription_id) {
initiates.push(" self.kwargs.update({");
@ -67,6 +54,7 @@ export function GenerateAzureCliTestScenario(model: CodeModelAz): string[] {
let imports: string[] = [];
let decorators: string[] = [];
let parameterNames = InitiateDependencies(model, imports, decorators, initiates);
let jsonAdded = false;
function parameterLine() {
let ret = "";
@ -90,18 +78,34 @@ export function GenerateAzureCliTestScenario(model: CodeModelAz): string[] {
steps.push(...ToMultiLine(`def ${functionName}(test${parameterLine()}):`));
// find example by name
let found = false;
for (let exampleCmd of model.FindExampleById(exampleId, commandParams)) {
let examples: CommandExample[] = [];
let exampleIdx = 0;
for (let exampleCmd of model.FindExampleById(exampleId, commandParams, examples)) {
if (exampleCmd && exampleCmd.length > 0) {
found = true;
if(exampleCmd[0].indexOf(' delete') > -1) {
if (exampleCmd[0].indexOf(' delete') > -1) {
exampleCmd[0] += " -y";
}
}
for (let idx = 0; idx < exampleCmd.length; idx++) {
let prefix: string = " " + disabled + ((idx == 0) ? "test.cmd('" : " '");
let postfix: string = (idx < exampleCmd.length - 1) ? " '" : "',";
ToMultiLine(prefix + exampleCmd[idx] + postfix, steps);
}
steps.push(" " + disabled + " checks=[])");
let checks = model.GetExampleChecks(examples[exampleIdx++]);
if (checks.length > 0) {
steps.push(" " + disabled + " checks=[");
for (let check of checks) {
ToMultiLine(" " + disabled + " " + check, steps);
if (!jsonAdded && !disabled && check.indexOf("json.loads") >= 0) {
header.addImport("json");
jsonAdded = true;
}
}
steps.push(" " + disabled + " ])");
}
else {
steps.push(" " + disabled + " checks=[])");
}
}
}
if (!found) {
@ -197,11 +201,10 @@ function InitiateDependencies(model: CodeModelAz, imports: string[], decorators:
if (internalObjects.length > 0) {
initiates.push(" self.kwargs.update({");
for (let [class_name, kargs_key, hasCreateExample, object_name] of internalObjects) {
if (hasCreateExample && model.RandomizeNames)
{
if (hasCreateExample && model.RandomizeNames) {
const RANDOMIZE_MIN_LEN = 4;
let prefixLen = Math.floor(object_name.length/2);
if(object_name.length-prefixLen<RANDOMIZE_MIN_LEN) prefixLen = Math.max(object_name.length-RANDOMIZE_MIN_LEN, 0);
let prefixLen = Math.floor(object_name.length / 2);
if (object_name.length - prefixLen < RANDOMIZE_MIN_LEN) prefixLen = Math.max(object_name.length - RANDOMIZE_MIN_LEN, 0);
ToMultiLine(` '${kargs_key}': self.create_random_name(prefix='${object_name}'[:${prefixLen}], length=${Math.max(object_name.length, RANDOMIZE_MIN_LEN)}),`, initiates);
}
else

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

@ -8,6 +8,7 @@ az:
package-name: azure-mgmt-datafactory
namespace: azure.mgmt.datafactory
formalize-names: true
disable-checks: true
az-output-folder: $(azure-cli-extension-folder)/src/datafactory
python-sdk-output-folder: "$(az-output-folder)/azext_datafactory/vendored_sdks/datafactory"

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

@ -39,7 +39,10 @@ def step_managednetworksput(test, rg):
'icrosoft.Network/virtualNetworks/{vn_3}/subnets/default\\"}}]}}" '
'--name "{myManagedNetwork}" '
'--resource-group "{rg}"',
checks=[])
checks=[
test.check("location", "eastus", case_sensitive=False),
test.check("name", "{myManagedNetwork}", case_sensitive=False),
])
# EXAMPLE: ManagementNetworkGroupsPut
@ -56,7 +59,10 @@ def step_managementnetworkgroupsput(test, rg):
'--group-name "{myManagedNetworkGroup}" '
'--managed-network-name "{myManagedNetwork}" '
'--resource-group "{rg}"',
checks=[])
checks=[
test.check("managementGroups", []),
test.check("name", "{myManagedNetworkGroup}", case_sensitive=False),
])
test.cmd('az managed-network mn group wait --created '
'--group-name "{myManagedNetworkGroup}" '
'--resource-group "{rg}"',
@ -71,7 +77,11 @@ def step_scopeassignmentsput(test, rg):
'gedNetwork/managedNetworks/{myManagedNetwork}" '
'--scope "subscriptions/subscriptionC" '
'--name "{myScopeAssignment}"',
checks=[])
checks=[
test.check("assignedManagedNetwork", "/subscriptions/{subscription_id}/resourceGroups/{rg}/providers/M"
"icrosoft.ManagedNetwork/managedNetworks/{myManagedNetwork}", case_sensitive=False),
test.check("name", "{myScopeAssignment}", case_sensitive=False),
])
# EXAMPLE: ManagedNetworkPeeringPoliciesPut
@ -102,7 +112,9 @@ def step_managednetworksget(test, rg):
def step_managednetworkslistbyresourcegroup(test, rg):
test.cmd('az managed-network mn list '
'--resource-group "{rg}"',
checks=[])
checks=[
test.check('length(@)', 1),
])
# EXAMPLE: ManagedNetworksListBySubscription
@ -110,7 +122,9 @@ def step_managednetworkslistbyresourcegroup(test, rg):
def step_managednetworkslistbysubscription(test, rg):
test.cmd('az managed-network mn list '
'-g ""',
checks=[])
checks=[
test.check('length(@)', 1),
])
# EXAMPLE: ScopeAssignmentsGet
@ -119,7 +133,11 @@ def step_scopeassignmentsget(test, rg):
test.cmd('az managed-network mn scope-assignment show '
'--scope "subscriptions/subscriptionC" '
'--name "{myScopeAssignment}"',
checks=[])
checks=[
test.check("assignedManagedNetwork", "/subscriptions/{subscription_id}/resourceGroups/{rg}/providers/M"
"icrosoft.ManagedNetwork/managedNetworks/{myManagedNetwork}", case_sensitive=False),
test.check("name", "{myScopeAssignment}", case_sensitive=False),
])
# EXAMPLE: ScopeAssignmentsList
@ -127,7 +145,9 @@ def step_scopeassignmentsget(test, rg):
def step_scopeassignmentslist(test, rg):
test.cmd('az managed-network mn scope-assignment list '
'--scope "subscriptions/subscriptionC"',
checks=[])
checks=[
test.check('length(@)', 1),
])
# EXAMPLE: ManagementNetworkGroupsGet
@ -137,7 +157,10 @@ def step_managementnetworkgroupsget(test, rg):
'--group-name "{myManagedNetworkGroup}" '
'--managed-network-name "{myManagedNetwork}" '
'--resource-group "{rg}"',
checks=[])
checks=[
test.check("managementGroups", []),
test.check("name", "{myManagedNetworkGroup}", case_sensitive=False),
])
# EXAMPLE: ManagedNetworksGroupsListByManagedNetwork
@ -146,7 +169,9 @@ def step_managednetworksgroupslistbymanagednetwork(test, rg):
test.cmd('az managed-network mn group list '
'--managed-network-name "{myManagedNetwork}" '
'--resource-group "{rg}"',
checks=[])
checks=[
test.check('length(@)', 1),
])
# EXAMPLE: ManagedNetworkPeeringPoliciesGet
@ -156,7 +181,9 @@ def step_managednetworkpeeringpoliciesget(test, rg):
'--managed-network-name "{myManagedNetwork}" '
'--policy-name "{myManagedNetworkPeeringPolicy}" '
'--resource-group "{rg}"',
checks=[])
checks=[
test.check("name", "{myManagedNetworkPeeringPolicy}", case_sensitive=False),
])
# EXAMPLE: ManagedNetworkPeeringPoliciesListByManagedNetwork
@ -165,7 +192,9 @@ def step_managednetworkpeeringpolicieslistbymanagednetwork(test, rg):
test.cmd('az managed-network managed-network-peering-policy list '
'--managed-network-name "{myManagedNetwork}" '
'--resource-group "{rg}"',
checks=[])
checks=[
test.check('length(@)', 1),
])
# EXAMPLE: ManagedNetworkPeeringPoliciesDelete