From f23b68541ebb6d1c2532e899b40b6555ea02c463 Mon Sep 17 00:00:00 2001 From: Yuchao Yan Date: Thu, 7 May 2026 16:00:48 +0800 Subject: [PATCH 01/36] add sync script --- .../typespec-python/eng/scripts/regenerate.ts | 688 ------------------ packages/typespec-python/eng/scripts/sync.ts | 201 +++++ packages/typespec-python/package.json | 2 + 3 files changed, 203 insertions(+), 688 deletions(-) delete mode 100644 packages/typespec-python/eng/scripts/regenerate.ts create mode 100644 packages/typespec-python/eng/scripts/sync.ts diff --git a/packages/typespec-python/eng/scripts/regenerate.ts b/packages/typespec-python/eng/scripts/regenerate.ts deleted file mode 100644 index 9fd3ab95f7..0000000000 --- a/packages/typespec-python/eng/scripts/regenerate.ts +++ /dev/null @@ -1,688 +0,0 @@ -/* eslint-disable no-console */ -/** - * Regenerates Python SDK code from TypeSpec definitions. - * - * Uses in-process TypeSpec compilation to avoid subprocess spawning overhead. - * This is significantly faster than spawning `tsp compile` for each spec. - */ - -import { compile, NodeHost } from "@typespec/compiler"; -import { promises, rmSync } from "fs"; -import { platform } from "os"; -import { dirname, join, relative, resolve } from "path"; -import pc from "picocolors"; -import { fileURLToPath } from "url"; -import { parseArgs } from "util"; - -// ---- Shared constants ---- - -const SKIP_SPECS: string[] = ["type/file"]; - -const SpecialFlags: Record> = { - azure: { - "generate-test": true, - "generate-sample": true, - }, -}; - -function toPosix(dir: string): string { - return dir.replace(/\\/g, "/"); -} - -interface RegenerateFlags { - flavor: string; - debug: boolean; - name?: string; -} - -async function getSubdirectories(baseDir: string, flags: RegenerateFlags): Promise { - const subdirectories: string[] = []; - - async function searchDir(currentDir: string) { - const items = await promises.readdir(currentDir, { withFileTypes: true }); - - const promisesArray = items.map(async (item) => { - const subDirPath = join(currentDir, item.name); - if (item.isDirectory()) { - const mainTspPath = join(subDirPath, "main.tsp"); - const clientTspPath = join(subDirPath, "client.tsp"); - - const mainTspRelativePath = toPosix(relative(baseDir, mainTspPath)); - - if (SKIP_SPECS.some((skipSpec) => mainTspRelativePath.includes(skipSpec))) return; - - const hasMainTsp = await promises - .access(mainTspPath) - .then(() => true) - .catch(() => false); - const hasClientTsp = await promises - .access(clientTspPath) - .then(() => true) - .catch(() => false); - - if (mainTspRelativePath.toLowerCase().includes(flags.name || "")) { - if (mainTspRelativePath.includes("resiliency/srv-driven")) { - subdirectories.push(resolve(subDirPath, "old.tsp")); - } - if (hasClientTsp) { - subdirectories.push(resolve(subDirPath, "client.tsp")); - } else if (hasMainTsp) { - subdirectories.push(resolve(subDirPath, "main.tsp")); - } - } - - await searchDir(subDirPath); - } - }); - - await Promise.all(promisesArray); - } - - await searchDir(baseDir); - return subdirectories; -} - -// Parse arguments -const argv = parseArgs({ - args: process.argv.slice(2), - options: { - flavor: { type: "string", short: "f" }, - name: { type: "string", short: "n" }, - debug: { type: "boolean", short: "d" }, - jobs: { type: "string", short: "j" }, - help: { type: "boolean", short: "h" }, - }, -}); - -if (argv.values.help) { - console.log(` -${pc.bold("Usage:")} tsx regenerate.ts [options] - -${pc.bold("Description:")} - Regenerates Python SDK code from TypeSpec definitions using in-process compilation. - This avoids spawning a new Node.js process for each spec, making it significantly faster. - -${pc.bold("Options:")} - ${pc.cyan("-f, --flavor ")} - SDK flavor to regenerate. If not specified, regenerates both flavors. - - ${pc.cyan("-n, --name ")} - Filter packages by name pattern (case-insensitive substring match). - - ${pc.cyan("-d, --debug")} - Enable debug output during regeneration. - - ${pc.cyan("-j, --jobs ")} - Number of parallel compilation tasks (default: 30 on Linux/Mac, 10 on Windows). - - ${pc.cyan("-h, --help")} - Show this help message. - -${pc.bold("Examples:")} - ${pc.dim("# Regenerate all packages for both flavors")} - tsx regenerate.ts - - ${pc.dim("# Regenerate only Azure packages")} - tsx regenerate.ts --flavor azure - - ${pc.dim("# Regenerate a specific package by name")} - tsx regenerate.ts --flavor azure --name authentication-api-key -`); - process.exit(0); -} - -// Get paths -const SCRIPT_DIR = dirname(fileURLToPath(import.meta.url)); -const PLUGIN_DIR = resolve(SCRIPT_DIR, "../../"); -const AZURE_HTTP_SPECS = resolve(PLUGIN_DIR, "node_modules/@azure-tools/azure-http-specs/specs"); -const HTTP_SPECS = resolve(PLUGIN_DIR, "node_modules/@typespec/http-specs/specs"); -const EMITTER_NAME = "@azure-tools/typespec-python"; - -function isAzureSpec(specPath: string): boolean { - return specPath.startsWith(AZURE_HTTP_SPECS); -} - -// Emitter options -const AZURE_EMITTER_OPTIONS: Record | Record[]> = { - "azure/client-generator-core/access": { - namespace: "specs.azure.clientgenerator.core.access", - }, - "azure/client-generator-core/alternate-type": { - namespace: "specs.azure.clientgenerator.core.alternatetype", - }, - "azure/client-generator-core/api-version": { - namespace: "specs.azure.clientgenerator.core.apiversion", - }, - "azure/client-generator-core/client-initialization/default": { - namespace: "specs.azure.clientgenerator.core.clientinitialization.default", - }, - "azure/client-generator-core/client-initialization/individually": { - namespace: "specs.azure.clientgenerator.core.clientinitialization.individually", - }, - "azure/client-generator-core/client-initialization/individuallyParent": { - namespace: "specs.azure.clientgenerator.core.clientinitialization.individuallyparent", - }, - "azure/client-generator-core/client-default-value": { - namespace: "specs.azure.clientgenerator.core.clientdefaultvalue", - }, - "azure/client-generator-core/client-doc": { - namespace: "specs.azure.clientgenerator.core.clientdoc", - }, - "azure/client-generator-core/client-location": { - namespace: "specs.azure.clientgenerator.core.clientlocation", - }, - "azure/client-generator-core/deserialize-empty-string-as-null": { - namespace: "specs.azure.clientgenerator.core.emptystring", - }, - "azure/client-generator-core/flatten-property": { - namespace: "specs.azure.clientgenerator.core.flattenproperty", - }, - "azure/client-generator-core/usage": { - namespace: "specs.azure.clientgenerator.core.usage", - }, - "azure/client-generator-core/override": { - namespace: "specs.azure.clientgenerator.core.override", - }, - "azure/client-generator-core/hierarchy-building": { - namespace: "specs.azure.clientgenerator.core.hierarchybuilding", - }, - "azure/client-generator-core/next-link-verb": { - namespace: "specs.azure.clientgenerator.core.nextlinkverb", - }, - "azure/client-generator-core/response-as-bool": { - namespace: "specs.azure.clientgenerator.core.responseasbool", - }, - "azure/core/basic": { - namespace: "specs.azure.core.basic", - }, - "azure/core/lro/rpc": { - namespace: "specs.azure.core.lro.rpc", - }, - "azure/core/lro/standard": { - namespace: "specs.azure.core.lro.standard", - }, - "azure/core/model": { - namespace: "specs.azure.core.model", - }, - "azure/core/page": { - namespace: "specs.azure.core.page", - }, - "azure/core/scalar": { - namespace: "specs.azure.core.scalar", - }, - "azure/core/traits": { - namespace: "specs.azure.core.traits", - }, - "azure/encode/duration": { - namespace: "specs.azure.encode.duration", - }, - "azure/example/basic": { - namespace: "specs.azure.example.basic", - }, - "azure/payload/pageable": { - namespace: "specs.azure.payload.pageable", - }, - "azure/versioning/previewVersion": { - namespace: "specs.azure.versioning.previewversion", - }, - "client/structure/default": { - namespace: "client.structure.service", - }, - "client/structure/multi-client": { - "package-name": "client-structure-multiclient", - namespace: "client.structure.multiclient", - }, - "client/structure/renamed-operation": { - "package-name": "client-structure-renamedoperation", - namespace: "client.structure.renamedoperation", - }, - "client/structure/two-operation-group": { - "package-name": "client-structure-twooperationgroup", - namespace: "client.structure.twooperationgroup", - }, - "client/naming": { - namespace: "client.naming.main", - }, - "client/overload": { - namespace: "client.overload", - }, - "encode/duration": { - namespace: "encode.duration", - }, - "encode/numeric": { - namespace: "encode.numeric", - }, - "parameters/basic": { - namespace: "parameters.basic", - }, - "parameters/spread": { - namespace: "parameters.spread", - }, - "payload/content-negotiation": { - namespace: "payload.contentnegotiation", - }, - "payload/multipart": { - namespace: "payload.multipart", - }, - "serialization/encoded-name/json": { - namespace: "serialization.encodedname.json", - }, - "special-words": { - namespace: "specialwords", - }, - "service/multi-service": { - namespace: "service.multiservice", - }, -}; - -const EMITTER_OPTIONS: Record | Record[]> = { - "resiliency/srv-driven/old.tsp": { - "package-name": "resiliency-srv-driven1", - namespace: "resiliency.srv.driven1", - "package-mode": "azure-dataplane", - "package-pprint-name": "ResiliencySrvDriven1", - }, - "resiliency/srv-driven": { - "package-name": "resiliency-srv-driven2", - namespace: "resiliency.srv.driven2", - "package-mode": "azure-dataplane", - "package-pprint-name": "ResiliencySrvDriven2", - }, - "authentication/api-key": { - "clear-output-folder": "true", - }, - "authentication/http/custom": { - "package-name": "authentication-http-custom", - namespace: "authentication.http.custom", - "package-pprint-name": "Authentication Http Custom", - }, - "authentication/union": [ - { - "package-name": "authentication-union", - namespace: "authentication.union", - }, - { - "package-name": "setuppy-authentication-union", - namespace: "setuppy.authentication.union", - "keep-setup-py": "true", - }, - ], - "type/array": { - "package-name": "typetest-array", - namespace: "typetest.array", - }, - "type/dictionary": { - "package-name": "typetest-dictionary", - namespace: "typetest.dictionary", - }, - "type/enum/extensible": { - "package-name": "typetest-enum-extensible", - namespace: "typetest.enum.extensible", - }, - "type/enum/fixed": { - "package-name": "typetest-enum-fixed", - namespace: "typetest.enum.fixed", - }, - "type/model/empty": { - "package-name": "typetest-model-empty", - namespace: "typetest.model.empty", - }, - "type/model/inheritance/enum-discriminator": { - "package-name": "typetest-model-enumdiscriminator", - namespace: "typetest.model.enumdiscriminator", - }, - "type/model/inheritance/nested-discriminator": { - "package-name": "typetest-model-nesteddiscriminator", - namespace: "typetest.model.nesteddiscriminator", - }, - "type/model/inheritance/not-discriminated": { - "package-name": "typetest-model-notdiscriminated", - namespace: "typetest.model.notdiscriminated", - }, - "type/model/inheritance/single-discriminator": { - "package-name": "typetest-model-singlediscriminator", - namespace: "typetest.model.singlediscriminator", - }, - "type/model/inheritance/recursive": [ - { - "package-name": "typetest-model-recursive", - namespace: "typetest.model.recursive", - }, - { - "package-name": "generation-subdir", - namespace: "generation.subdir", - "generation-subdir": "_generated", - "clear-output-folder": "true", - }, - ], - "type/model/usage": { - "package-name": "typetest-model-usage", - namespace: "typetest.model.usage", - }, - "type/model/visibility": [ - { - "package-name": "typetest-model-visibility", - namespace: "typetest.model.visibility", - }, - { - "package-name": "headasbooleantrue", - namespace: "headasbooleantrue", - "head-as-boolean": "true", - }, - { - "package-name": "headasbooleanfalse", - namespace: "headasbooleanfalse", - "head-as-boolean": "false", - }, - ], - "type/property/nullable": { - "package-name": "typetest-property-nullable", - namespace: "typetest.property.nullable", - }, - "type/property/optionality": { - "package-name": "typetest-property-optional", - namespace: "typetest.property.optional", - }, - "type/property/additional-properties": { - "package-name": "typetest-property-additionalproperties", - namespace: "typetest.property.additionalproperties", - }, - "type/scalar": { - "package-name": "typetest-scalar", - namespace: "typetest.scalar", - }, - "type/property/value-types": { - "package-name": "typetest-property-valuetypes", - namespace: "typetest.property.valuetypes", - }, - "type/union": { - "package-name": "typetest-union", - namespace: "typetest.union", - }, - "type/union/discriminated": { - "package-name": "typetest-discriminatedunion", - namespace: "typetest.discriminatedunion", - }, - "type/file": { - "package-name": "typetest-file", - namespace: "typetest.file", - }, - documentation: { - "package-name": "specs-documentation", - namespace: "specs.documentation", - }, - // Repo-specific overrides - "client/structure/client-operation-group": { - "package-name": "client-structure-clientoperationgroup", - namespace: "client.structure.clientoperationgroup", - }, -}; - -interface CompileTask { - spec: string; - outputDir: string; - options: Record; -} - -// Group of tasks for the same spec that must run sequentially -interface TaskGroup { - spec: string; - tasks: CompileTask[]; -} - -function defaultPackageName(spec: string): string { - const specDir = isAzureSpec(spec) ? AZURE_HTTP_SPECS : HTTP_SPECS; - return toPosix(relative(specDir, dirname(spec))) - .replace(/\//g, "-") - .toLowerCase(); -} - -function getEmitterOptions(spec: string, flavor: string): Record[] { - const specDir = isAzureSpec(spec) ? AZURE_HTTP_SPECS : HTTP_SPECS; - const relativeSpec = toPosix(relative(specDir, spec)); - const key = relativeSpec.includes("resiliency/srv-driven/old.tsp") - ? relativeSpec - : dirname(relativeSpec); - const emitterOpts = EMITTER_OPTIONS[key] || - (flavor === "azure" ? AZURE_EMITTER_OPTIONS[key] : [{}]) || [{}]; - return Array.isArray(emitterOpts) ? emitterOpts : [emitterOpts]; -} - -function buildTaskGroups(specs: string[], flags: RegenerateFlags): TaskGroup[] { - const groups: TaskGroup[] = []; - - for (const spec of specs) { - const tasks: CompileTask[] = []; - - for (const emitterConfig of getEmitterOptions(spec, flags.flavor)) { - const options: Record = { ...emitterConfig }; - - // Add flavor-specific options - options["flavor"] = flags.flavor; - for (const [k, v] of Object.entries(SpecialFlags[flags.flavor] ?? {})) { - options[k] = v; - } - - // Set output directory - use tests/generated// structure - const packageName = (options["package-name"] as string) || defaultPackageName(spec); - const outputDir = - (options["emitter-output-dir"] as string) || - toPosix(`${PLUGIN_DIR}/tests/generated/${flags.flavor}/${packageName}`); - options["emitter-output-dir"] = outputDir; - - // Debug mode - if (flags.debug) { - options["debug"] = true; - } - - // Examples directory - options["examples-dir"] = toPosix(join(dirname(spec), "examples")); - - tasks.push({ spec, outputDir, options }); - } - - groups.push({ spec, tasks }); - } - - return groups; -} - -async function compileSpec(task: CompileTask): Promise<{ success: boolean; error?: string }> { - const { spec, outputDir, options } = task; - - try { - // Build compiler options - const compilerOptions = { - emit: [PLUGIN_DIR], - options: { - [EMITTER_NAME]: options, - }, - }; - - // Compile using TypeSpec compiler directly (no subprocess) - const program = await compile(NodeHost, spec, compilerOptions); - - if (program.hasError()) { - const errors = program.diagnostics - .filter((d) => d.severity === "error") - .map((d) => d.message) - .join("\n"); - return { success: false, error: errors }; - } - - return { success: true }; - } catch (err) { - // Clean up on error - rmSync(outputDir, { recursive: true, force: true }); - return { success: false, error: String(err) }; - } -} - -async function runParallel(groups: TaskGroup[], maxJobs: number): Promise> { - const results = new Map(); - const executing: Set> = new Set(); - - // Count total tasks for progress - const totalTasks = groups.reduce((sum, g) => sum + g.tasks.length, 0); - let completed = 0; - - for (const group of groups) { - // Each group runs as a unit - tasks within a group run sequentially - // But different groups can run in parallel - const runGroup = async () => { - const specDir = isAzureSpec(group.spec) ? AZURE_HTTP_SPECS : HTTP_SPECS; - const shortName = toPosix(relative(specDir, dirname(group.spec))); - - // Run all tasks in this group sequentially to avoid state pollution - let groupSuccess = true; - for (const task of group.tasks) { - const packageName = (task.options["package-name"] as string) || shortName; - console.log(pc.blue(`[${completed + 1}/${totalTasks}] Compiling ${packageName}...`)); - - const result = await compileSpec(task); - completed++; - - if (result.success) { - console.log(pc.green(`[${completed}/${totalTasks}] ${packageName} succeeded`)); - } else { - console.log( - pc.red(`[${completed}/${totalTasks}] ${packageName} failed: ${result.error}`), - ); - groupSuccess = false; - } - } - - results.set(group.spec, groupSuccess); - }; - - const p = runGroup().finally(() => executing.delete(p)); - executing.add(p); - - if (executing.size >= maxJobs) { - await Promise.race(executing); - } - } - - await Promise.all(executing); - return results; -} - -// Preprocess: create files that should be deleted after regeneration (for testing) -async function preprocess(flavor: string): Promise { - if (flavor === "azure") { - const generalParts = [PLUGIN_DIR, "tests", "generated", "azure"]; - const authFile = join( - ...generalParts, - "authentication-api-key", - "authentication", - "apikey", - "_operations", - "to_be_deleted.py", - ); - await promises.mkdir(dirname(authFile), { recursive: true }); - await promises.writeFile(authFile, "# This file is to be deleted after regeneration"); - - const folderParts = [...generalParts, "generation-subdir"]; - const genFile = join(...folderParts, "generation", "subdir", "_generated", "to_be_deleted.py"); - await promises.mkdir(dirname(genFile), { recursive: true }); - await promises.writeFile(genFile, "# This file is to be deleted after regeneration"); - - const testFile = join(...folderParts, "generated_tests", "to_be_deleted.py"); - await promises.mkdir(dirname(testFile), { recursive: true }); - await promises.writeFile(testFile, "# This file is to be kept after regeneration"); - - const keptFile = join(...folderParts, "generation", "subdir", "to_be_kept.py"); - await promises.mkdir(dirname(keptFile), { recursive: true }); - await promises.writeFile(keptFile, "# This file is to be kept after regeneration"); - } -} - -async function regenerateFlavor( - flavor: string, - name: string | undefined, - debug: boolean, - jobs: number, -): Promise { - console.log(pc.cyan(`\n${"=".repeat(60)}`)); - console.log(pc.cyan(`Regenerating ${flavor} flavor`)); - console.log(pc.cyan(`${"=".repeat(60)}\n`)); - - const flags: RegenerateFlags = { flavor, debug, name }; - - // Preprocess - await preprocess(flavor); - - // Collect specs - const azureSpecs = flavor === "azure" ? await getSubdirectories(AZURE_HTTP_SPECS, flags) : []; - const standardSpecs = await getSubdirectories(HTTP_SPECS, flags); - const allSpecs = [...azureSpecs, ...standardSpecs]; - - // Build task groups (tasks for same spec run sequentially to avoid state pollution) - const groups = buildTaskGroups(allSpecs, flags); - const totalTasks = groups.reduce((sum, g) => sum + g.tasks.length, 0); - - console.log(pc.cyan(`Found ${allSpecs.length} specs (${totalTasks} total tasks) to compile`)); - console.log(pc.cyan(`Using ${jobs} parallel jobs\n`)); - - // Run compilation - const startTime = performance.now(); - const results = await runParallel(groups, jobs); - const duration = (performance.now() - startTime) / 1000; - - // Summary - const succeeded = Array.from(results.values()).filter((v) => v).length; - const failed = results.size - succeeded; - - console.log(pc.cyan(`\n${"=".repeat(60)}`)); - console.log(pc.cyan(`Results: ${succeeded} succeeded, ${failed} failed`)); - console.log(pc.cyan(`Time: ${duration.toFixed(1)}s`)); - console.log(pc.cyan(`${"=".repeat(60)}\n`)); - - return failed === 0; -} - -async function main() { - const isWindows = platform() === "win32"; - const flavor = argv.values.flavor; - const name = argv.values.name; - const debug = argv.values.debug ?? false; - // Windows has slower file system operations and process spawning, - // so use fewer parallel jobs to avoid I/O contention and memory pressure - const defaultJobs = isWindows ? 10 : 30; - const jobs = argv.values.jobs ? parseInt(argv.values.jobs, 10) : defaultJobs; - - console.log(pc.cyan(`\nRegeneration config:`)); - console.log(pc.cyan(` Platform: ${isWindows ? "Windows" : "Unix"}`)); - console.log(pc.cyan(` Mode: in-process compilation`)); - console.log(pc.cyan(` Jobs: ${jobs}`)); - if (name) { - console.log(pc.cyan(` Filter: ${name}`)); - } - console.log(); - - const startTime = performance.now(); - let success: boolean; - - if (flavor) { - success = await regenerateFlavor(flavor, name, debug, jobs); - } else { - // Both flavors - const azureSuccess = await regenerateFlavor("azure", name, debug, jobs); - const unbrandedSuccess = await regenerateFlavor("unbranded", name, debug, jobs); - success = azureSuccess && unbrandedSuccess; - } - - const totalDuration = (performance.now() - startTime) / 1000; - console.log( - success - ? pc.green(`\nRegeneration completed successfully in ${totalDuration.toFixed(1)}s`) - : pc.red(`\nRegeneration failed after ${totalDuration.toFixed(1)}s`), - ); - - process.exit(success ? 0 : 1); -} - -main().catch((err) => { - console.error(pc.red(`Fatal error: ${err}`)); - process.exit(1); -}); diff --git a/packages/typespec-python/eng/scripts/sync.ts b/packages/typespec-python/eng/scripts/sync.ts new file mode 100644 index 0000000000..6152c7f589 --- /dev/null +++ b/packages/typespec-python/eng/scripts/sync.ts @@ -0,0 +1,201 @@ +/* eslint-disable no-console */ +/** + * Sync eng/scripts from the upstream http-client-python checkout (sibling + * `core/` repo) into this package's eng/scripts directory. + * + * typespec-python is mostly a wrapper around http-client-python, so the build / + * setup / CI helper scripts under eng/ should be kept identical between the two + * packages. This script copies the files from /core/packages/ + * http-client-python/eng/scripts/ into this repo so we don't have to maintain + * duplicate copies by hand. If the core/ checkout isn't present the script + * exits with an informational message and does nothing. + * + * Usage: + * tsx eng/scripts/sync.ts # write mode: overwrite local files + * tsx eng/scripts/sync.ts --check # check mode: exit non-zero on drift (CI) + */ +import fs from "fs"; +import { dirname, join, sep } from "path"; +import pc from "picocolors"; +import { fileURLToPath } from "url"; +import { parseArgs } from "util"; + +const here = dirname(fileURLToPath(import.meta.url)); +// eng/scripts/sync.ts -> package root is two levels up +const packageRoot = join(here, "..", ".."); +const destEngScripts = join(packageRoot, "eng", "scripts"); + +// Source lives in the sibling `core/` checkout at the repo root: +// /core/packages/http-client-python/eng/scripts +// packageRoot == /packages/typespec-python, so the repo root is two +// levels up from packageRoot. +const repoRoot = join(packageRoot, "..", ".."); +const sourceRoot = join( + repoRoot, + "core", + "packages", + "http-client-python", + "eng", + "scripts", +); + +/** + * Files (relative to eng/scripts, POSIX path) that should be synced from the + * upstream @typespec/http-client-python package. Anything not listed here is + * ignored — keeping this an allow-list makes it explicit which files this + * package is willing to inherit from upstream. + * + * To pull in a new upstream file, add it here and run `pnpm sync`. + */ +const INCLUDES: readonly string[] = [ + // Shared CI config + "ci/config/mypy.ini", + "ci/config/pylintrc", + "ci/config/pyrightconfig.json", + + // Shared CI runners (invoked by run-tests.ts via tox) + "ci/run_apiview.py", + "ci/run_mypy.py", + "ci/run_pylint.py", + "ci/run_pyright.py", + "ci/run_sphinx_build.py", + "ci/util.py", + + // Regeneration scripts (the local regenerate.ts is intentionally synced from + // upstream; regenerate-common.ts is its shared helper module). + "ci/regenerate.ts", + "ci/regenerate-common.ts", + + // Shared setup scripts (invoked by package.json install/prepare hooks) + "setup/install.py", + "setup/package_manager.py", + "setup/prepare.py", + "setup/run_tsp.py", + "setup/run-python3.ts", + "setup/system-requirements.ts", + "setup/venvtools.py", +]; + +const argv = parseArgs({ + args: process.argv.slice(2), + options: { + check: { type: "boolean", short: "c", default: false }, + help: { type: "boolean", short: "h", default: false }, + }, +}); + +if (argv.values.help) { + console.log(` +${pc.bold("Usage:")} tsx eng/scripts/sync.ts [options] + +${pc.bold("Description:")} + Copy the files listed in INCLUDES from + /core/packages/http-client-python/eng/scripts/ into this package's + eng/scripts/. Anything not in INCLUDES is left untouched. If the core/ + checkout is not present, the script exits with an informational message and + does nothing. + +${pc.bold("Options:")} + ${pc.cyan("-c, --check")} Compare only; exit non-zero on any drift (for CI). + ${pc.cyan("-h, --help")} Show this help. +`); + process.exit(0); +} + +const check = argv.values.check ?? false; + +function toPosix(p: string): string { + return p.split(sep).join("/"); +} + +function readBytes(p: string): Buffer | null { + try { + return fs.readFileSync(p); + } catch { + return null; + } +} + +interface SyncStats { + copied: string[]; + unchanged: string[]; + drifted: string[]; // only populated in --check mode + missing: string[]; // listed in INCLUDES but not present in the source package +} + +function syncFile(srcAbs: string, destAbs: string, relPath: string, stats: SyncStats): void { + const srcBuf = fs.readFileSync(srcAbs); + const destBuf = readBytes(destAbs); + + if (destBuf && destBuf.equals(srcBuf)) { + stats.unchanged.push(relPath); + return; + } + + if (check) { + stats.drifted.push(relPath); + return; + } + + fs.mkdirSync(dirname(destAbs), { recursive: true }); + fs.writeFileSync(destAbs, srcBuf); + stats.copied.push(relPath); +} + +function main(): void { + if (!fs.existsSync(sourceRoot)) { + console.log( + pc.yellow( + `core/ checkout not found at:\n ${sourceRoot}\n` + + `Skipping sync. Clone the typespec repo into /core (or run\n` + + `the appropriate submodule init command) and re-run this script.`, + ), + ); + process.exit(0); + } + + console.log(pc.bold("Source:") + " " + sourceRoot); + console.log(pc.bold("Destination:") + " " + destEngScripts); + console.log(pc.bold("Mode:") + " " + (check ? "check (read-only)" : "write")); + console.log(""); + + const stats: SyncStats = { copied: [], unchanged: [], drifted: [], missing: [] }; + + for (const rel of INCLUDES) { + const srcAbs = join(sourceRoot, ...rel.split("/")); + if (!fs.existsSync(srcAbs)) { + stats.missing.push(rel); + continue; + } + const destAbs = join(destEngScripts, ...rel.split("/")); + syncFile(srcAbs, destAbs, toPosix(rel), stats); + } + + if (stats.copied.length) { + console.log(pc.green(pc.bold(`Copied (${stats.copied.length}):`))); + for (const f of stats.copied) console.log(" " + f); + } + if (stats.drifted.length) { + console.log(pc.red(pc.bold(`Drifted (${stats.drifted.length}):`))); + for (const f of stats.drifted) console.log(" " + f); + } + if (stats.missing.length) { + console.log(pc.yellow(pc.bold(`Missing in source (${stats.missing.length}):`))); + for (const f of stats.missing) console.log(" " + f); + } + console.log(pc.dim(`Unchanged: ${stats.unchanged.length}`)); + + if (check && (stats.drifted.length > 0 || stats.missing.length > 0)) { + console.error( + pc.red( + `\neng/scripts has drifted from core/packages/http-client-python.\n` + + `Run 'pnpm sync' (or 'tsx eng/scripts/sync.ts') and commit the result.`, + ), + ); + process.exit(1); + } + + console.log(pc.green(pc.bold(check ? "\nNo drift detected." : "\nSync complete."))); +} + +main(); diff --git a/packages/typespec-python/package.json b/packages/typespec-python/package.json index 896263f674..7c1ae78593 100644 --- a/packages/typespec-python/package.json +++ b/packages/typespec-python/package.json @@ -38,6 +38,8 @@ "format:extra": "tsx ./eng/scripts/ci/format.ts --python", "format:extra:check": "tsx ./eng/scripts/ci/format.ts --python --check", "regenerate": "tsx ./eng/scripts/regenerate.ts", + "sync": "tsx ./eng/scripts/sync.ts", + "sync:check": "tsx ./eng/scripts/sync.ts --check", "test:python:e2e": "tsx ./eng/scripts/ci/run-tests.ts", "regen-docs": "pnpm run build && tspd doc . --enable-experimental --output-dir ./website/src/content/docs/docs/emitters/clients/typespec-python/reference --skip-js" }, From bd5719cae9a4c3c312ee546738ce9cc7adbfac54 Mon Sep 17 00:00:00 2001 From: Yuchao Yan Date: Thu, 7 May 2026 16:45:20 +0800 Subject: [PATCH 02/36] sync eng folder --- .../eng/scripts/ci/config/mypy.ini | 7 +- .../eng/scripts/ci/config/pylintrc | 4 +- .../eng/scripts/ci/config/pyrightconfig.json | 4 +- .../eng/scripts/ci/regenerate.ts | 852 ++++++++++++++++++ .../eng/scripts/ci/run_apiview.py | 38 +- .../eng/scripts/ci/run_mypy.py | 62 +- .../eng/scripts/ci/run_pylint.py | 56 +- .../eng/scripts/ci/run_pyright.py | 74 +- .../eng/scripts/ci/run_sphinx_build.py | 33 +- .../typespec-python/eng/scripts/ci/util.py | 82 +- .../eng/scripts/setup/install.py | 49 +- .../eng/scripts/setup/package_manager.py | 21 +- .../eng/scripts/setup/prepare.py | 13 +- .../eng/scripts/setup/run-python3.ts | 12 +- .../eng/scripts/setup/run_batch.py | 199 ++++ .../eng/scripts/setup/run_tsp.py | 15 +- .../eng/scripts/setup/system-requirements.ts | 22 +- .../eng/scripts/setup/venvtools.py | 7 +- packages/typespec-python/eng/scripts/sync.ts | 4 +- packages/typespec-python/package.json | 2 +- 20 files changed, 1337 insertions(+), 219 deletions(-) create mode 100644 packages/typespec-python/eng/scripts/ci/regenerate.ts create mode 100644 packages/typespec-python/eng/scripts/setup/run_batch.py diff --git a/packages/typespec-python/eng/scripts/ci/config/mypy.ini b/packages/typespec-python/eng/scripts/ci/config/mypy.ini index cfd4a49719..6bd11f1f11 100644 --- a/packages/typespec-python/eng/scripts/ci/config/mypy.ini +++ b/packages/typespec-python/eng/scripts/ci/config/mypy.ini @@ -1,9 +1,8 @@ # global configurations [mypy] -python_version = 3.9 +python_version = 3.10 # Exclude mypy check for sub client tests -exclude = (.*azure/clientgenerator/core/clientinitialization/operations/_operations\.py|.*azure/clientgenerator/core/clientinitialization/aio/operations/_operations\.py) - +exclude = .*/clientinitialization/.*\.py # module level configurations [mypy-jsonrpc.*] @@ -38,3 +37,5 @@ ignore_missing_imports = True [mypy-yaml.*] ignore_missing_imports = True + + diff --git a/packages/typespec-python/eng/scripts/ci/config/pylintrc b/packages/typespec-python/eng/scripts/ci/config/pylintrc index ad23a561c6..387021335f 100644 --- a/packages/typespec-python/eng/scripts/ci/config/pylintrc +++ b/packages/typespec-python/eng/scripts/ci/config/pylintrc @@ -1,5 +1,5 @@ [MASTER] -py-version=3.9 +py-version=3.10 ignore-patterns=test_*,conftest,setup reports=no @@ -17,7 +17,7 @@ enable=useless-suppression # too-many-arguments: Due to the nature of the CLI many commands have large arguments set which reflect in large arguments set in corresponding methods. # too-many-lines: Due to code generation many files end up with too many lines. # Let's black deal with bad-continuation -disable=missing-docstring,locally-disabled,fixme,cyclic-import,too-many-arguments,invalid-name,duplicate-code,too-few-public-methods,consider-using-f-string,super-with-arguments,redefined-builtin,import-outside-toplevel,client-suffix-needed,unnecessary-dunder-call,unnecessary-ellipsis,disallowed-name,consider-using-max-builtin,unknown-option-value,file-needs-copyright-header +disable=missing-docstring,locally-disabled,fixme,cyclic-import,too-many-arguments,invalid-name,duplicate-code,too-few-public-methods,consider-using-f-string,super-with-arguments,redefined-builtin,import-outside-toplevel,client-suffix-needed,unnecessary-dunder-call,unnecessary-ellipsis,disallowed-name,consider-using-max-builtin,unknown-option-value,file-needs-copyright-header,too-many-positional-arguments [FORMAT] max-line-length=120 diff --git a/packages/typespec-python/eng/scripts/ci/config/pyrightconfig.json b/packages/typespec-python/eng/scripts/ci/config/pyrightconfig.json index bebfe77f91..ef8340726d 100644 --- a/packages/typespec-python/eng/scripts/ci/config/pyrightconfig.json +++ b/packages/typespec-python/eng/scripts/ci/config/pyrightconfig.json @@ -2,7 +2,5 @@ "reportUnnecessaryCast": "warning", "reportTypeCommentUsage": true, "reportMissingImports": false, - "reportAttributeAccessIssue": false, - "pythonVersion": "3.9", - "exclude": ["**/build/**"] + "pythonVersion": "3.10" } diff --git a/packages/typespec-python/eng/scripts/ci/regenerate.ts b/packages/typespec-python/eng/scripts/ci/regenerate.ts new file mode 100644 index 0000000000..a65230db57 --- /dev/null +++ b/packages/typespec-python/eng/scripts/ci/regenerate.ts @@ -0,0 +1,852 @@ +/* eslint-disable no-console */ +/** + * Regenerates Python SDK code from TypeSpec definitions. + * + * Uses in-process TypeSpec compilation to avoid subprocess spawning overhead. + * This is significantly faster than spawning `tsp compile` for each spec. + */ + +import { compile, NodeHost } from "@typespec/compiler"; +import { execSync } from "child_process"; +import { existsSync, rmSync } from "fs"; +import { access, mkdir, readdir, writeFile } from "fs/promises"; +import { platform } from "os"; +import { dirname, join, relative, resolve } from "path"; +import pc from "picocolors"; +import { fileURLToPath } from "url"; +import { parseArgs } from "util"; + +// Parse arguments +const argv = parseArgs({ + args: process.argv.slice(2), + options: { + flavor: { type: "string", short: "f" }, + name: { type: "string", short: "n" }, + debug: { type: "boolean", short: "d" }, + pluginDir: { type: "string" }, + emitterName: { type: "string" }, + generatedFolder: { type: "string" }, + jobs: { type: "string", short: "j" }, + help: { type: "boolean", short: "h" }, + }, +}); + +if (argv.values.help) { + console.log(` +${pc.bold("Usage:")} tsx regenerate.ts [options] + +${pc.bold("Description:")} + Regenerates Python SDK code from TypeSpec definitions using in-process compilation. + This avoids spawning a new Node.js process for each spec, making it significantly faster. + +${pc.bold("Options:")} + ${pc.cyan("-f, --flavor ")} + SDK flavor to regenerate. If not specified, regenerates both flavors. + + ${pc.cyan("-n, --name ")} + Filter packages by name pattern (case-insensitive substring match). + Examples: + --name xml Regenerate packages containing "xml" + --name authentication Regenerate authentication packages + --name type/array Regenerate the type/array package + + ${pc.cyan("-d, --debug")} + Enable debug output during regeneration. + + ${pc.cyan("-j, --jobs ")} + Number of parallel compilation tasks (default: 30 on Linux/Mac, 10 on Windows). + + ${pc.cyan("-h, --help")} + Show this help message. + +${pc.bold("Examples:")} + ${pc.dim("# Regenerate all packages for both flavors")} + tsx regenerate.ts + + ${pc.dim("# Regenerate only Azure packages")} + tsx regenerate.ts --flavor azure + + ${pc.dim("# Regenerate a specific package by name")} + tsx regenerate.ts --flavor azure --name authentication-api-key + + ${pc.dim("# Regenerate with more parallelism")} + tsx regenerate.ts --jobs 50 +`); + process.exit(0); +} + +// ---- Shared constants ---- + +const SKIP_SPECS: string[] = ["type/file", "service/multiple-services"]; + +const SpecialFlags: Record> = { + azure: { + "generate-test": true, + "generate-sample": true, + }, +}; + +function toPosix(dir: string): string { + return dir.replace(/\\/g, "/"); +} + +interface RegenerateFlags { + flavor: string; + debug: boolean; + name?: string; + pyodide?: boolean; +} + +// ---- Base emitter options ---- + +const AZURE_EMITTER_OPTIONS: Record | Record[]> = { + "azure/client-generator-core/access": { + namespace: "specs.azure.clientgenerator.core.access", + }, + "azure/client-generator-core/alternate-type": { + namespace: "specs.azure.clientgenerator.core.alternatetype", + }, + "azure/client-generator-core/api-version": { + namespace: "specs.azure.clientgenerator.core.apiversion", + }, + "azure/client-generator-core/client-initialization/default": { + namespace: "specs.azure.clientgenerator.core.clientinitialization.default", + }, + "azure/client-generator-core/client-initialization/individually": { + namespace: "specs.azure.clientgenerator.core.clientinitialization.individually", + }, + "azure/client-generator-core/client-initialization/individuallyParent": { + namespace: "specs.azure.clientgenerator.core.clientinitialization.individuallyparent", + }, + "azure/client-generator-core/client-location": { + namespace: "specs.azure.clientgenerator.core.clientlocation", + }, + "azure/client-generator-core/deserialize-empty-string-as-null": { + namespace: "specs.azure.clientgenerator.core.emptystring", + }, + "azure/client-generator-core/flatten-property": { + namespace: "specs.azure.clientgenerator.core.flattenproperty", + }, + "azure/client-generator-core/usage": { + namespace: "specs.azure.clientgenerator.core.usage", + }, + "azure/client-generator-core/client-doc": { + namespace: "specs.azure.clientgenerator.core.clientdoc", + }, + "azure/client-generator-core/override": { + namespace: "specs.azure.clientgenerator.core.override", + }, + "azure/client-generator-core/hierarchy-building": { + namespace: "specs.azure.clientgenerator.core.hierarchybuilding", + }, + "azure/core/basic": { + namespace: "specs.azure.core.basic", + }, + "azure/core/lro/rpc": { + namespace: "specs.azure.core.lro.rpc", + }, + "azure/core/lro/standard": { + namespace: "specs.azure.core.lro.standard", + }, + "azure/core/model": { + namespace: "specs.azure.core.model", + }, + "azure/core/page": { + namespace: "specs.azure.core.page", + }, + "azure/core/scalar": { + namespace: "specs.azure.core.scalar", + }, + "azure/core/traits": { + namespace: "specs.azure.core.traits", + }, + "azure/encode/duration": { + namespace: "specs.azure.encode.duration", + }, + "azure/example/basic": { + namespace: "specs.azure.example.basic", + }, + "azure/payload/pageable": { + namespace: "specs.azure.payload.pageable", + }, + "azure/versioning/previewVersion": { + namespace: "specs.azure.versioning.previewversion", + }, + "client/structure/default": { + namespace: "client.structure.service", + }, + "client/structure/multi-client": { + "package-name": "client-structure-multiclient", + namespace: "client.structure.multiclient", + }, + "client/structure/renamed-operation": { + "package-name": "client-structure-renamedoperation", + namespace: "client.structure.renamedoperation", + }, + "client/structure/two-operation-group": { + "package-name": "client-structure-twooperationgroup", + namespace: "client.structure.twooperationgroup", + }, + "client/naming": { + namespace: "client.naming.main", + }, + "client/overload": { + namespace: "client.overload", + }, + "encode/duration": { + namespace: "encode.duration", + }, + "encode/numeric": { + namespace: "encode.numeric", + }, + "parameters/basic": { + namespace: "parameters.basic", + }, + "parameters/spread": { + namespace: "parameters.spread", + }, + "payload/content-negotiation": { + namespace: "payload.contentnegotiation", + }, + "payload/multipart": { + namespace: "payload.multipart", + }, + "serialization/encoded-name/json": { + namespace: "serialization.encodedname.json", + }, + "special-words": { + namespace: "specialwords", + }, + "service/multi-service": { + namespace: "service.multiservice", + }, + "client/structure/client-operation-group": { + "package-name": "client-structure-clientoperationgroup", + namespace: "client.structure.clientoperationgroup", + }, +}; + +const EMITTER_OPTIONS: Record | Record[]> = { + "resiliency/srv-driven/old.tsp": { + "package-name": "resiliency-srv-driven1", + namespace: "resiliency.srv.driven1", + "package-mode": "azure-dataplane", + "package-pprint-name": "ResiliencySrvDriven1", + }, + "resiliency/srv-driven": { + "package-name": "resiliency-srv-driven2", + namespace: "resiliency.srv.driven2", + "package-mode": "azure-dataplane", + "package-pprint-name": "ResiliencySrvDriven2", + }, + "authentication/api-key": { + "clear-output-folder": "true", + }, + "authentication/http/custom": { + "package-name": "authentication-http-custom", + namespace: "authentication.http.custom", + "package-pprint-name": "Authentication Http Custom", + }, + "authentication/union": [ + { + "package-name": "authentication-union", + namespace: "authentication.union", + }, + { + "package-name": "setuppy-authentication-union", + namespace: "setuppy.authentication.union", + "keep-setup-py": "true", + }, + ], + "type/array": { + "package-name": "typetest-array", + namespace: "typetest.array", + }, + "type/dictionary": { + "package-name": "typetest-dictionary", + namespace: "typetest.dictionary", + }, + "type/enum/extensible": { + "package-name": "typetest-enum-extensible", + namespace: "typetest.enum.extensible", + }, + "type/enum/fixed": { + "package-name": "typetest-enum-fixed", + namespace: "typetest.enum.fixed", + }, + "type/model/empty": { + "package-name": "typetest-model-empty", + namespace: "typetest.model.empty", + }, + "type/model/inheritance/enum-discriminator": { + "package-name": "typetest-model-enumdiscriminator", + namespace: "typetest.model.enumdiscriminator", + }, + "type/model/inheritance/nested-discriminator": { + "package-name": "typetest-model-nesteddiscriminator", + namespace: "typetest.model.nesteddiscriminator", + }, + "type/model/inheritance/not-discriminated": { + "package-name": "typetest-model-notdiscriminated", + namespace: "typetest.model.notdiscriminated", + }, + "type/model/inheritance/single-discriminator": { + "package-name": "typetest-model-singlediscriminator", + namespace: "typetest.model.singlediscriminator", + }, + "type/model/inheritance/recursive": [ + { + "package-name": "typetest-model-recursive", + namespace: "typetest.model.recursive", + }, + { + "package-name": "generation-subdir", + namespace: "generation.subdir", + "generation-subdir": "_generated", + "generate-test": "false", + "clear-output-folder": "true", + }, + ], + "type/model/usage": { + "package-name": "typetest-model-usage", + namespace: "typetest.model.usage", + }, + "type/model/visibility": [ + { + "package-name": "typetest-model-visibility", + namespace: "typetest.model.visibility", + }, + { + "package-name": "headasbooleantrue", + namespace: "headasbooleantrue", + "head-as-boolean": "true", + }, + { + "package-name": "headasbooleanfalse", + namespace: "headasbooleanfalse", + "head-as-boolean": "false", + }, + ], + "type/property/nullable": { + "package-name": "typetest-property-nullable", + namespace: "typetest.property.nullable", + }, + "type/property/optionality": { + "package-name": "typetest-property-optional", + namespace: "typetest.property.optional", + }, + "type/property/additional-properties": { + "package-name": "typetest-property-additionalproperties", + namespace: "typetest.property.additionalproperties", + }, + "type/scalar": { + "package-name": "typetest-scalar", + namespace: "typetest.scalar", + }, + "type/property/value-types": { + "package-name": "typetest-property-valuetypes", + namespace: "typetest.property.valuetypes", + }, + "type/union": { + "package-name": "typetest-union", + namespace: "typetest.union", + }, + "type/union/discriminated": { + "package-name": "typetest-discriminatedunion", + namespace: "typetest.discriminatedunion", + }, + "type/file": { + "package-name": "typetest-file", + namespace: "typetest.file", + }, + documentation: { + "package-name": "specs-documentation", + namespace: "specs.documentation", + }, + "versioning/added": [ + { + "package-name": "versioning-added", + namespace: "versioning.added", + }, + { + "package-name": "generation-subdir2", + namespace: "generation.subdir2", + "generate-test": "false", + "generation-subdir": "_generated", + }, + ], +}; + +// ---- Shared utility functions ---- + +async function getSubdirectories(baseDir: string, flags: RegenerateFlags): Promise { + const subdirectories: string[] = []; + + async function searchDir(currentDir: string) { + const items = await readdir(currentDir, { withFileTypes: true }); + + const promisesArray = items.map(async (item) => { + const subDirPath = join(currentDir, item.name); + if (item.isDirectory()) { + const mainTspPath = join(subDirPath, "main.tsp"); + const clientTspPath = join(subDirPath, "client.tsp"); + + const mainTspRelativePath = toPosix(relative(baseDir, mainTspPath)); + + if (SKIP_SPECS.some((skipSpec) => mainTspRelativePath.includes(skipSpec))) return; + + const hasMainTsp = await access(mainTspPath) + .then(() => true) + .catch(() => false); + const hasClientTsp = await access(clientTspPath) + .then(() => true) + .catch(() => false); + + if (mainTspRelativePath.toLowerCase().includes(flags.name || "")) { + if (mainTspRelativePath.includes("resiliency/srv-driven")) { + subdirectories.push(resolve(subDirPath, "old.tsp")); + } + if (hasClientTsp) { + subdirectories.push(resolve(subDirPath, "client.tsp")); + } else if (hasMainTsp) { + subdirectories.push(resolve(subDirPath, "main.tsp")); + } + } + + await searchDir(subDirPath); + } + }); + + await Promise.all(promisesArray); + } + + await searchDir(baseDir); + return subdirectories; +} + +async function preprocess(flavor: string, generatedFolder: string): Promise { + if (flavor === "azure") { + const testsGeneratedDir = resolve(generatedFolder, "../tests/generated/azure"); + + const DELETE_CONTENT = "# This file is to be deleted after regeneration"; + const DELETE_FILE = "to_be_deleted.py"; + const entries: { folder: string[]; file: string; content: string }[] = [ + { + folder: ["authentication-api-key", "authentication", "apikey", "_operations"], + file: DELETE_FILE, + content: DELETE_CONTENT, + }, + { + folder: ["generation-subdir", "generation", "subdir", "_generated"], + file: DELETE_FILE, + content: DELETE_CONTENT, + }, + { + folder: ["generation-subdir", "generated_tests"], + file: DELETE_FILE, + content: DELETE_CONTENT, + }, + { + folder: ["generation-subdir", "generation", "subdir"], + file: "to_be_kept.py", + content: "# This file is to be kept after regeneration", + }, + ]; + + await Promise.all( + entries.map(async ({ folder, file, content }) => { + const targetFolder = join(testsGeneratedDir, ...folder); + await mkdir(targetFolder, { recursive: true }); + await writeFile(join(targetFolder, file), content); + }), + ); + } +} + +// Get paths +const SCRIPT_DIR = dirname(fileURLToPath(import.meta.url)); +const PLUGIN_DIR = argv.values.pluginDir + ? resolve(argv.values.pluginDir) + : resolve(SCRIPT_DIR, "../../../"); +const AZURE_HTTP_SPECS = resolve(PLUGIN_DIR, "node_modules/@azure-tools/azure-http-specs/specs"); +const HTTP_SPECS = resolve(PLUGIN_DIR, "node_modules/@typespec/http-specs/specs"); +const GENERATED_FOLDER = argv.values.generatedFolder + ? resolve(argv.values.generatedFolder) + : resolve(PLUGIN_DIR, "generator"); +const EMITTER_NAME = argv.values.emitterName || "@typespec/http-client-python"; + +interface CompileTask { + spec: string; + outputDir: string; + options: Record; +} + +// Group of tasks for the same spec that must run sequentially +interface TaskGroup { + spec: string; + tasks: CompileTask[]; +} + +// Check whether a spec path belongs to azure-http-specs (vs standard http-specs). +// Using "azure-http-specs" instead of "azure" to avoid false positives when the +// working directory path contains "azure" (e.g. azure-sdk-for-python). +function isAzureSpec(spec: string): boolean { + return spec.includes("azure-http-specs"); +} + +function defaultPackageName(spec: string): string { + const specDir = isAzureSpec(spec) ? AZURE_HTTP_SPECS : HTTP_SPECS; + return toPosix(relative(specDir, dirname(spec))) + .replace(/\//g, "-") + .toLowerCase(); +} + +function getEmitterOptions(spec: string, flavor: string): Record[] { + const specDir = isAzureSpec(spec) ? AZURE_HTTP_SPECS : HTTP_SPECS; + const relativeSpec = toPosix(relative(specDir, spec)); + const key = relativeSpec.includes("resiliency/srv-driven/old.tsp") + ? relativeSpec + : dirname(relativeSpec); + const emitterOpts = EMITTER_OPTIONS[key] || + (flavor === "azure" ? AZURE_EMITTER_OPTIONS[key] : [{}]) || [{}]; + return Array.isArray(emitterOpts) ? emitterOpts : [emitterOpts]; +} + +function buildTaskGroups(specs: string[], flags: RegenerateFlags): TaskGroup[] { + const groups: TaskGroup[] = []; + + for (const spec of specs) { + const tasks: CompileTask[] = []; + + for (const emitterConfig of getEmitterOptions(spec, flags.flavor)) { + // Apply flavor defaults first, then per-spec options so they can override (e.g., "generate-test": "false") + const options: Record = {}; + for (const [k, v] of Object.entries(SpecialFlags[flags.flavor] ?? {})) { + options[k] = v; + } + Object.assign(options, emitterConfig); + + // Add flavor + options["flavor"] = flags.flavor; + + // Set output directory - use tests/generated// structure + const packageName = (options["package-name"] as string) || defaultPackageName(spec); + const outputDir = + (options["emitter-output-dir"] as string) || + toPosix(`${GENERATED_FOLDER}/../tests/generated/${flags.flavor}/${packageName}`); + options["emitter-output-dir"] = outputDir; + + // Debug mode + if (flags.debug) { + options["debug"] = true; + } + + // Examples directory + options["examples-dir"] = toPosix(join(dirname(spec), "examples")); + + // Emit YAML only - Python processing is batched after all specs compile + options["emit-yaml-only"] = true; + + tasks.push({ spec, outputDir, options }); + } + + groups.push({ spec, tasks }); + } + + return groups; +} + +async function compileSpec(task: CompileTask): Promise<{ success: boolean; error?: string }> { + const { spec, outputDir, options } = task; + + try { + // Build compiler options + const compilerOptions = { + emit: [PLUGIN_DIR], + options: { + [EMITTER_NAME]: options, + }, + }; + + // Compile using TypeSpec compiler directly (no subprocess) + const program = await compile(NodeHost, spec, compilerOptions); + + if (program.hasError()) { + const errors = program.diagnostics + .filter((d) => d.severity === "error") + .map((d) => d.message) + .join("\n"); + return { success: false, error: errors }; + } + + return { success: true }; + } catch (err) { + // Clean up on error + rmSync(outputDir, { recursive: true, force: true }); + return { success: false, error: String(err) }; + } +} + +function renderProgressBar( + completed: number, + failed: number, + total: number, + width: number = 40, +): string { + const successCount = completed - failed; + const successWidth = Math.round((successCount / total) * width); + const failWidth = Math.round((failed / total) * width); + const emptyWidth = width - successWidth - failWidth; + + const successBar = pc.bgGreen(" ".repeat(successWidth)); + const failBar = failed > 0 ? pc.bgRed(" ".repeat(failWidth)) : ""; + const emptyBar = pc.dim("░".repeat(Math.max(0, emptyWidth))); + + const percent = Math.round((completed / total) * 100); + return `${successBar}${failBar}${emptyBar} ${pc.cyan(`${percent}%`)} (${completed}/${total})`; +} + +async function runParallel(groups: TaskGroup[], maxJobs: number): Promise> { + const results = new Map(); + const executing: Set> = new Set(); + + // Count total tasks for progress + const totalTasks = groups.reduce((sum, g) => sum + g.tasks.length, 0); + let completed = 0; + let failed = 0; + const failedSpecs: string[] = []; + + // Check if we're in a TTY for progress bar updates + const isTTY = process.stdout.isTTY; + + const updateProgress = () => { + if (isTTY) { + process.stdout.write(`\r${renderProgressBar(completed, failed, totalTasks)}`); + } + }; + + // Initial progress bar + updateProgress(); + + for (const group of groups) { + // Each group runs as a unit - tasks within a group run sequentially + // But different groups can run in parallel + const runGroup = async () => { + const specDir = isAzureSpec(group.spec) ? AZURE_HTTP_SPECS : HTTP_SPECS; + const shortName = toPosix(relative(specDir, dirname(group.spec))); + + // Run all tasks in this group sequentially to avoid state pollution + let groupSuccess = true; + for (const task of group.tasks) { + const packageName = (task.options["package-name"] as string) || shortName; + + const result = await compileSpec(task); + completed++; + + if (!result.success) { + failed++; + failedSpecs.push(`${packageName}: ${result.error}`); + groupSuccess = false; + } + + updateProgress(); + } + + results.set(group.spec, groupSuccess); + }; + + const p = runGroup().finally(() => executing.delete(p)); + executing.add(p); + + if (executing.size >= maxJobs) { + await Promise.race(executing); + } + } + + await Promise.all(executing); + + // Clear progress bar line and print final status + if (isTTY) { + process.stdout.write("\r" + " ".repeat(60) + "\r"); + } + + // Print failures at the end + if (failedSpecs.length > 0) { + console.log(pc.red(`\nFailed specs:`)); + for (const spec of failedSpecs) { + console.log(pc.red(` • ${spec}`)); + } + } + + return results; +} + +async function collectConfigFiles(generatedDir: string, flavor: string): Promise { + const flavorDir = join(generatedDir, "..", "tests", "generated", flavor); + try { + await access(flavorDir); + } catch { + return []; + } + + const configFiles: string[] = []; + for (const pkg of await readdir(flavorDir, { withFileTypes: true })) { + if (pkg.isDirectory()) { + const pkgDir = join(flavorDir, pkg.name); + for (const file of await readdir(pkgDir)) { + if (file.startsWith(".tsp-codegen-") && file.endsWith(".json")) { + configFiles.push(join(pkgDir, file)); + } + } + } + } + return configFiles; +} + +function runBatchPythonProcessing(flavor: string, configCount: number, jobs: number): boolean { + if (configCount === 0) return true; + + console.log(pc.cyan(`\nRunning batch Python processing on ${configCount} specs...`)); + + // Find Python venv + let venvPath = join(PLUGIN_DIR, "venv"); + if (existsSync(join(venvPath, "bin"))) { + venvPath = join(venvPath, "bin", "python"); + } else if (existsSync(join(venvPath, "Scripts"))) { + venvPath = join(venvPath, "Scripts", "python.exe"); + } else { + console.error(pc.red("Python venv not found")); + return false; + } + + const batchScript = join(PLUGIN_DIR, "eng", "scripts", "setup", "run_batch.py"); + + try { + // Pass directory and flavor instead of individual config files to avoid command line length limits on Windows + execSync( + `"${venvPath}" "${batchScript}" --generated-dir "${PLUGIN_DIR}" --flavor ${flavor} --jobs ${jobs}`, + { + stdio: "inherit", + cwd: PLUGIN_DIR, + }, + ); + return true; + } catch { + return false; + } +} + +async function regenerateFlavor( + flavor: string, + name: string | undefined, + debug: boolean, + jobs: number, +): Promise { + console.log(pc.cyan(`\n${"=".repeat(60)}`)); + console.log(pc.cyan(`Regenerating ${flavor} flavor`)); + console.log(pc.cyan(`${"=".repeat(60)}\n`)); + + const flags: RegenerateFlags = { flavor, debug, name }; + + // Preprocess + await preprocess(flavor, GENERATED_FOLDER); + + // Collect specs + const azureSpecs = flavor === "azure" ? await getSubdirectories(AZURE_HTTP_SPECS, flags) : []; + const standardSpecs = await getSubdirectories(HTTP_SPECS, flags); + const allSpecs = [...azureSpecs, ...standardSpecs]; + + // Build task groups (tasks for same spec run sequentially to avoid state pollution) + const groups = buildTaskGroups(allSpecs, flags); + const totalTasks = groups.reduce((sum, g) => sum + g.tasks.length, 0); + + console.log(pc.cyan(`Found ${allSpecs.length} specs (${totalTasks} total tasks) to compile`)); + console.log(pc.cyan(`Using ${jobs} parallel jobs\n`)); + + // Run compilation (emits YAML only) + const startTime = performance.now(); + const results = await runParallel(groups, jobs); + const compileTime = (performance.now() - startTime) / 1000; + + // Summary for TypeSpec compilation + const succeeded = Array.from(results.values()).filter((v) => v).length; + const compileFailed = results.size - succeeded; + + console.log( + pc.cyan( + `\nTypeSpec compilation: ${succeeded} succeeded, ${compileFailed} failed (${compileTime.toFixed(1)}s)`, + ), + ); + + if (compileFailed > 0) { + console.log(pc.red(`Skipping Python processing due to compilation failures`)); + return false; + } + + // Batch process all specs with Python + const pyStartTime = performance.now(); + const configCount = (await collectConfigFiles(GENERATED_FOLDER, flavor)).length; + // Use fewer Python jobs since Python processing is heavier + const pyJobs = Math.max(4, jobs); + const pySuccess = runBatchPythonProcessing(flavor, configCount, pyJobs); + const pyTime = (performance.now() - pyStartTime) / 1000; + + const totalTime = (performance.now() - startTime) / 1000; + + console.log(pc.cyan(`\n${"=".repeat(60)}`)); + console.log(pc.cyan(`Results: ${succeeded} specs processed`)); + console.log( + pc.cyan( + ` TypeSpec: ${compileTime.toFixed(1)}s | Python: ${pyTime.toFixed(1)}s | Total: ${totalTime.toFixed(1)}s`, + ), + ); + console.log(pc.cyan(`${"=".repeat(60)}\n`)); + + return pySuccess; +} + +async function main() { + const isWindows = platform() === "win32"; + const flavor = argv.values.flavor; + const name = argv.values.name; + const debug = argv.values.debug ?? false; + // Windows has slower file system operations and process spawning, + // so use fewer parallel jobs to avoid I/O contention and memory pressure + const defaultJobs = isWindows ? 10 : 30; + const jobs = argv.values.jobs ? parseInt(argv.values.jobs, 10) : defaultJobs; + + console.log(pc.cyan(`\nRegeneration config:`)); + console.log(pc.cyan(` Platform: ${isWindows ? "Windows" : "Unix"}`)); + console.log(pc.cyan(` Mode: in-process compilation`)); + console.log(pc.cyan(` Jobs: ${jobs}`)); + if (name) { + console.log(pc.cyan(` Filter: ${name}`)); + } + console.log(); + + const startTime = performance.now(); + let success: boolean; + + if (flavor) { + success = await regenerateFlavor(flavor, name, debug, jobs); + } else { + // Both flavors + const azureSuccess = await regenerateFlavor("azure", name, debug, jobs); + const unbrandedSuccess = await regenerateFlavor("unbranded", name, debug, jobs); + success = azureSuccess && unbrandedSuccess; + } + + const totalDuration = (performance.now() - startTime) / 1000; + console.log( + success + ? pc.green(`\nRegeneration completed successfully in ${totalDuration.toFixed(1)}s`) + : pc.red(`\nRegeneration failed after ${totalDuration.toFixed(1)}s`), + ); + + process.exit(success ? 0 : 1); +} + +main().catch((err) => { + console.error(pc.red(`Fatal error: ${err}`)); + process.exit(1); +}); diff --git a/packages/typespec-python/eng/scripts/ci/run_apiview.py b/packages/typespec-python/eng/scripts/ci/run_apiview.py index 5345f694ef..48d6f890a3 100644 --- a/packages/typespec-python/eng/scripts/ci/run_apiview.py +++ b/packages/typespec-python/eng/scripts/ci/run_apiview.py @@ -10,32 +10,38 @@ import os import sys -from subprocess import check_call, CalledProcessError +from subprocess import run, TimeoutExpired import logging from util import run_check logging.getLogger().setLevel(logging.INFO) +# Timeout for each apiview generation (seconds) +APIVIEW_TIMEOUT = 30 + def _single_dir_apiview(mod): - loop = 0 - while True: + for attempt in range(2): try: - check_call( - [ - "apistubgen", - "--pkg-path", - str(mod.absolute()), - ] + result = run( + ["apistubgen", "--pkg-path", str(mod.absolute())], + capture_output=True, + timeout=APIVIEW_TIMEOUT, ) - except CalledProcessError as e: - if loop >= 2: # retry for maximum 3 times because sometimes the apistubgen has transient failure. - logging.error("{} exited with apiview generation error {}".format(mod.stem, e.returncode)) + if result.returncode == 0: + return True + if attempt == 1: + logging.error(f"{mod.stem} failed: {result.stderr.decode()[:200]}") + return False + except TimeoutExpired: + if attempt == 1: + logging.error(f"{mod.stem} timed out after {APIVIEW_TIMEOUT}s") + return False + except Exception as e: + if attempt == 1: + logging.error(f"{mod.stem} error: {e}") return False - else: - loop += 1 - continue - return True + return False if __name__ == "__main__": diff --git a/packages/typespec-python/eng/scripts/ci/run_mypy.py b/packages/typespec-python/eng/scripts/ci/run_mypy.py index c452ea0e54..ef99a32638 100644 --- a/packages/typespec-python/eng/scripts/ci/run_mypy.py +++ b/packages/typespec-python/eng/scripts/ci/run_mypy.py @@ -12,7 +12,7 @@ import os import logging import sys -from util import run_check +from util import run_check, get_package_namespace_dir logging.getLogger().setLevel(logging.INFO) @@ -26,40 +26,34 @@ def get_config_file_location(): return os.path.join(os.path.dirname(__file__), "config/mypy.ini") -def _has_python_files(directory): - """Check if a directory contains any .py files recursively.""" - return any(directory.rglob("*.py")) - - -def _single_dir_mypy(mod): - try: - inner_class = next( - (d for d in mod.iterdir() if d.is_dir() and d.name not in ("build", "generated_tests", "specs", "generated_samples") and not str(d).endswith("egg-info") and _has_python_files(d)), - None - ) - if inner_class is None: - logging.warning("No valid source directory found in %s, skipping", mod) - return True - check_call( - [ - sys.executable, - "-m", - "mypy", - "--config-file", - get_config_file_location(), - "--ignore-missing", - "--exclude", - "build", - str(inner_class.absolute()), - ] - ) +def _single_dir_mypy(mod, retries=2): + inner_class = get_package_namespace_dir(mod) + if not inner_class: + logging.info(f"No package directory found in {mod}, skipping") return True - except CalledProcessError as e: - logging.error("{} exited with mypy error {}".format(mod.stem, e.returncode)) - return False - except Exception as e: - logging.error("Unexpected error processing %s: %s", mod, e) - return False + for attempt in range(1, retries + 2): + try: + check_call( + [ + sys.executable, + "-m", + "mypy", + "--config-file", + get_config_file_location(), + "--ignore-missing", + str(inner_class.absolute()), + ] + ) + return True + except CalledProcessError as e: + if attempt <= retries: + logging.warning( + "{} mypy attempt {} failed (exit {}), retrying...".format(inner_class.stem, attempt, e.returncode) + ) + else: + logging.error("{} exited with mypy error {}".format(inner_class.stem, e.returncode)) + return False + return False if __name__ == "__main__": diff --git a/packages/typespec-python/eng/scripts/ci/run_pylint.py b/packages/typespec-python/eng/scripts/ci/run_pylint.py index 3e8bbf220e..c184c56a3d 100644 --- a/packages/typespec-python/eng/scripts/ci/run_pylint.py +++ b/packages/typespec-python/eng/scripts/ci/run_pylint.py @@ -12,7 +12,7 @@ import os import logging import sys -from util import run_check +from util import run_check, get_package_namespace_dir logging.getLogger().setLevel(logging.INFO) @@ -26,41 +26,33 @@ def get_rfc_file_location(): return os.path.join(os.path.dirname(__file__), "config/pylintrc") -def _has_python_files(directory): - """Check if a directory contains any .py files recursively.""" - return any(directory.rglob("*.py")) - - def _single_dir_pylint(mod): + inner_class = get_package_namespace_dir(mod) + if not inner_class: + logging.info(f"No package directory found in {mod}, skipping") + return True + # Only load the Azure pylint guidelines checker plugin for azure packages. + # The plugin (azure-pylint-guidelines-checker) is only installed in the + # lint-azure tox environment and is not available for unbranded packages. + is_azure = "azure" in mod.parts + pylint_args = [ + sys.executable, + "-m", + "pylint", + "--rcfile={}".format(get_rfc_file_location()), + "--evaluation=(max(0, 0 if fatal else 10.0 - ((float(5 * error + warning + refactor + convention + info)/ statement) * 10)))", + "--output-format=parseable", + "--recursive=y", + "--py-version=3.10", + ] + if is_azure: + pylint_args.append("--load-plugins=pylint_guidelines_checker") + pylint_args.append(str(inner_class.absolute())) try: - inner_class = next( - (d for d in mod.iterdir() if d.is_dir() and d.name not in ("build", "generated_tests", "specs", "generated_samples") and not str(d).endswith("egg-info") and _has_python_files(d)), - None - ) - if inner_class is None: - logging.warning("No valid source directory found in %s, skipping", mod) - return True - check_call( - [ - sys.executable, - "-m", - "pylint", - "--rcfile={}".format(get_rfc_file_location()), - "--evaluation=(max(0, 0 if fatal else 10.0 - ((float(5 * error + warning + refactor + convention + info)/ statement) * 10)))", - "--load-plugins=pylint_guidelines_checker", - "--output-format=parseable", - "--recursive=y", - "--ignore=build", - "--py-version=3.9", - str(inner_class.absolute()), - ] - ) + check_call(pylint_args) return True except CalledProcessError as e: - logging.error("{} exited with linting error {}".format(mod.stem, e.returncode)) - return False - except Exception as e: - logging.error("Unexpected error processing %s: %s", mod, e) + logging.error("{} exited with linting error {}".format(str(inner_class.absolute()), e.returncode)) return False diff --git a/packages/typespec-python/eng/scripts/ci/run_pyright.py b/packages/typespec-python/eng/scripts/ci/run_pyright.py index fef8c468ea..b998b515d2 100644 --- a/packages/typespec-python/eng/scripts/ci/run_pyright.py +++ b/packages/typespec-python/eng/scripts/ci/run_pyright.py @@ -13,7 +13,7 @@ import logging import sys import time -from util import run_check +from util import run_check, get_package_namespace_dir logging.getLogger().setLevel(logging.INFO) @@ -27,51 +27,39 @@ def get_pyright_config_file_location(): return os.path.join(os.path.dirname(__file__), "config/pyrightconfig.json") -def _has_python_files(directory): - """Check if a directory contains any .py files recursively.""" - return any(directory.rglob("*.py")) - - def _single_dir_pyright(mod): - try: - inner_class = next( - (d for d in mod.iterdir() if d.is_dir() and d.name not in ("build", "generated_tests", "specs", "generated_samples") and not str(d).endswith("egg-info") and _has_python_files(d)), - None - ) - if inner_class is None: - logging.warning("No valid source directory found in %s, skipping", mod) - return True - retries = 3 - while retries: - try: - # After fully support client hierarchy, we can remove this check - if "azure-client-generator-core-client-initialization" in str(inner_class.absolute()): - return True - - check_output( - [ - sys.executable, - "-m", - "pyright", - "-p", - get_pyright_config_file_location(), - str(inner_class.absolute()), - ], - text=True, - ) + inner_class = get_package_namespace_dir(mod) + if not inner_class: + logging.info(f"No package directory found in {mod}, skipping") + return True + retries = 3 + while retries: + try: + # After fully support client hierarchy, we can remove this check + if "azure-client-generator-core-client-initialization" in str(inner_class.absolute()): return True - except CalledProcessError as e: - logging.exception("{} exited with pyright error {}".format(inner_class.stem, e.returncode)) - logging.error(f"PyRight stdout:\n{e.stdout}\n===========") - logging.error(f"PyRight stderr:\n{e.stderr}\n===========") - # PyRight has shown to randomly failed with a 217, retry the same folder 3 times should help - retries -= 1 - time.sleep(5) - return False - except Exception as e: - logging.error("Unexpected error processing %s: %s", mod, e) - return False + check_output( + [ + sys.executable, + "-m", + "pyright", + "-p", + get_pyright_config_file_location(), + str(inner_class.absolute()), + ], + text=True, + ) + return True + except CalledProcessError as e: + logging.exception("{} exited with pyright error {}".format(inner_class.stem, e.returncode)) + logging.error(f"PyRight stdout:\n{e.stdout}\n===========") + logging.error(f"PyRight stderr:\n{e.stderr}\n===========") + # PyRight has shown to randomly failed with a 217, retry the same folder 3 times should help + retries -= 1 + time.sleep(5) + + return False if __name__ == "__main__": diff --git a/packages/typespec-python/eng/scripts/ci/run_sphinx_build.py b/packages/typespec-python/eng/scripts/ci/run_sphinx_build.py index e97476aed9..0dba25b8f6 100644 --- a/packages/typespec-python/eng/scripts/ci/run_sphinx_build.py +++ b/packages/typespec-python/eng/scripts/ci/run_sphinx_build.py @@ -8,18 +8,21 @@ # This script is used to execute sphinx documentation build within a tox environment. # It uses a central sphinx configuration and validates docstrings by running sphinx-build. -from subprocess import check_call, CalledProcessError +from subprocess import run, TimeoutExpired import os import logging import sys from pathlib import Path -from util import run_check +from util import run_check, SKIP_PACKAGE_DIRS logging.getLogger().setLevel(logging.INFO) # Get the central Sphinx config directory SPHINX_CONF_DIR = os.path.abspath(os.path.dirname(__file__)) +# Timeout for each sphinx build (seconds) +SPHINX_TIMEOUT = 120 + def _create_minimal_index_rst(docs_dir, package_name, module_names): """Create a minimal index.rst file for sphinx to process.""" @@ -50,7 +53,12 @@ def _single_dir_sphinx(mod): # Find the actual Python package directories package_dirs = [ - d for d in mod.iterdir() if d.is_dir() and not d.name.startswith("_") and (d / "__init__.py").exists() + d + for d in mod.iterdir() + if d.is_dir() + and not d.name.startswith("_") + and d.name not in SKIP_PACKAGE_DIRS + and (d / "__init__.py").exists() ] if not package_dirs: @@ -85,7 +93,7 @@ def _single_dir_sphinx(mod): sys.path.insert(0, str(mod.absolute())) try: - result = check_call( + result = run( [ sys.executable, "-m", @@ -100,12 +108,19 @@ def _single_dir_sphinx(mod): "-q", # Quiet mode (only show warnings/errors) str(docs_dir.absolute()), # Source directory str(output_dir.absolute()), # Output directory - ] + ], + capture_output=True, + timeout=SPHINX_TIMEOUT, ) - logging.info(f"Sphinx build completed successfully for {mod.stem}") - return True - except CalledProcessError as e: - logging.error(f"{mod.stem} exited with sphinx build error {e.returncode}") + if result.returncode == 0: + return True + logging.error(f"{mod.stem} sphinx error: {result.stderr.decode()[:500]}") + return False + except TimeoutExpired: + logging.error(f"{mod.stem} timed out after {SPHINX_TIMEOUT}s") + return False + except Exception as e: + logging.error(f"{mod.stem} sphinx error: {e}") return False finally: # Remove from sys.path diff --git a/packages/typespec-python/eng/scripts/ci/util.py b/packages/typespec-python/eng/scripts/ci/util.py index 80fa1a3408..07aba0f3f4 100644 --- a/packages/typespec-python/eng/scripts/ci/util.py +++ b/packages/typespec-python/eng/scripts/ci/util.py @@ -8,15 +8,32 @@ import logging from pathlib import Path import argparse -from multiprocessing import Pool +from concurrent.futures import ProcessPoolExecutor, as_completed logging.getLogger().setLevel(logging.INFO) -# Root folder is the typespec-python package root -ROOT_FOLDER = os.path.abspath(os.path.join(os.path.abspath(__file__), "..", "..", "..", "..")) +# Root is the tests directory (4 levels up from this file: ci -> scripts -> eng -> package_root, then into tests) +ROOT_FOLDER = os.path.abspath(os.path.join(os.path.abspath(__file__), "..", "..", "..", "..", "tests")) IGNORE_FOLDER = [] +# Directories inside each generated package that should be skipped by all CI checks. +# These are auto-generated test/sample scaffolding, not the actual SDK code. +SKIP_PACKAGE_DIRS = {"generated_tests", "generated_samples", "build", "__pycache__", ".pytest_cache"} + + +def get_package_namespace_dir(mod): + """Find the actual namespace directory inside a generated package, skipping non-SDK dirs.""" + for d in mod.iterdir(): + if ( + d.is_dir() + and not d.name.startswith("_") + and not d.name.endswith("egg-info") + and d.name not in SKIP_PACKAGE_DIRS + ): + return d + return None + def run_check(name, call_back, log_info): parser = argparse.ArgumentParser( @@ -29,13 +46,6 @@ def run_check(name, call_back, log_info): help="The test folder we're in. Can be 'azure' or 'unbranded'", required=True, ) - parser.add_argument( - "-g", - "--generator", - dest="generator", - help="The generator we're using. Optional.", - required=False, - ) parser.add_argument( "-f", "--file-name", @@ -47,26 +57,52 @@ def run_check(name, call_back, log_info): "-s", "--subfolder", dest="subfolder", - help="The specific sub folder to validate, default to 'generated'. Optional.", + help="The subfolder containing generated code, default to 'generated'.", required=False, default="generated", ) + parser.add_argument( + "-j", + "--jobs", + dest="jobs", + help="Number of parallel jobs (default: CPU count)", + type=int, + required=False, + default=max(1, os.cpu_count()), + ) args = parser.parse_args() - # Build path: tests/generated/{flavor}/ - pkg_dir = Path(ROOT_FOLDER) / Path("tests") / Path(args.subfolder) / Path(args.test_folder) - if args.generator: - pkg_dir /= Path(args.generator) + # Path structure: tests/generated/{test_folder}/ + pkg_dir = Path(ROOT_FOLDER) / Path(args.subfolder) / Path(args.test_folder) dirs = [d for d in pkg_dir.iterdir() if d.is_dir() and not d.stem.startswith("_") and d.stem not in IGNORE_FOLDER] if args.file_name: dirs = [d for d in dirs if args.file_name.lower() in d.stem.lower()] - if len(dirs) > 1: - with Pool() as pool: - result = pool.map(call_back, dirs) - response = all(result) - else: - response = call_back(dirs[0]) - if not response: - logging.error("%s fails", log_info) + + if not dirs: + logging.info("No directories to process") + return + + logging.info(f"Processing {len(dirs)} packages with {args.jobs} parallel jobs...") + + failed = [] + succeeded = 0 + + with ProcessPoolExecutor(max_workers=args.jobs) as executor: + futures = {executor.submit(call_back, d): d for d in dirs} + for future in as_completed(futures): + pkg = futures[future] + try: + if future.result(): + succeeded += 1 + else: + failed.append(pkg.stem) + except Exception as e: + logging.error(f"{pkg.stem} raised exception: {e}") + failed.append(pkg.stem) + + logging.info(f"{log_info}: {succeeded} succeeded, {len(failed)} failed") + + if failed: + logging.error(f"{log_info} failed for: {', '.join(failed)}") exit(1) diff --git a/packages/typespec-python/eng/scripts/setup/install.py b/packages/typespec-python/eng/scripts/setup/install.py index cdeba45e97..487acc67b1 100644 --- a/packages/typespec-python/eng/scripts/setup/install.py +++ b/packages/typespec-python/eng/scripts/setup/install.py @@ -7,22 +7,57 @@ # -------------------------------------------------------------------------- import sys -if not sys.version_info >= (3, 9, 0): - raise Exception("Autorest for Python extension requires Python 3.9 at least") +if not sys.version_info >= (3, 10, 0): + print( + "Warning: Autorest for Python extension requires Python 3.10 at least. We will run your code with Pyodide since your Python version isn't adequate." + ) + sys.exit(2) # Exit code 2 for inadequate environment try: from package_manager import detect_package_manager, PackageManagerNotFoundError detect_package_manager() # Just check if we have a package manager except (ImportError, ModuleNotFoundError, PackageManagerNotFoundError): - raise Exception( - "Your Python installation doesn't have a suitable package manager (pip or uv) available" + print( + "Warning: Your Python installation doesn't have a suitable package manager (pip or uv) available. We will run your code with Pyodide since your Python environment isn't adequate." ) + sys.exit(2) # Exit code 2 for inadequate environment try: import venv -except ImportError: - raise Exception("Your Python installation doesn't have venv available") +except (ImportError, ModuleNotFoundError): + print( + "Warning: Your Python installation doesn't have venv available. We will run your code with Pyodide since your Python version isn't adequate." + ) + sys.exit(2) # Exit code 2 for inadequate environment + + +# Now we have a package manager (uv or pip) and Py >= 3.10, go to work +# At this point, both Python and package manager are confirmed to be available +# Any failures from here should fail the npm install, not fallback to Pyodide + +from pathlib import Path + +# eng/scripts/setup/install.py -> need to go up 4 levels to get to package root +_ROOT_DIR = Path(__file__).parent.parent.parent.parent + + +def main(): + venv_path = _ROOT_DIR / "venv" + + # Create virtual environment using package manager abstraction + from package_manager import create_venv_with_package_manager, install_packages + + try: + venv_context = create_venv_with_package_manager(venv_path) + + # Install required packages - install_packages handles package manager logic + install_packages([f"{_ROOT_DIR}/generator"], venv_context, cwd=_ROOT_DIR) + except Exception as e: + # Since Python and package manager are available, any failure here should fail the npm install + print(f"Error: Installation failed despite Python and package manager being available: {e}") + sys.exit(1) # Exit code 1 for installation failure -# Now we have a package manager (uv or pip) and Py >= 3.9 and check is over +if __name__ == "__main__": + main() diff --git a/packages/typespec-python/eng/scripts/setup/package_manager.py b/packages/typespec-python/eng/scripts/setup/package_manager.py index c6bd178fb5..3b6698279d 100644 --- a/packages/typespec-python/eng/scripts/setup/package_manager.py +++ b/packages/typespec-python/eng/scripts/setup/package_manager.py @@ -25,7 +25,7 @@ def _check_command_available(command: str) -> bool: try: subprocess.run([command, "--version"], capture_output=True, check=True) return True - except (subprocess.CalledProcessError, FileNotFoundError): + except (subprocess.CalledProcessError, FileNotFoundError, PermissionError): return False @@ -48,16 +48,12 @@ def detect_package_manager() -> str: # As a last resort, try using python -m pip try: - subprocess.run( - [sys.executable, "-m", "pip", "--version"], capture_output=True, check=True - ) + subprocess.run([sys.executable, "-m", "pip", "--version"], capture_output=True, check=True) return "python -m pip" - except (subprocess.CalledProcessError, FileNotFoundError): + except (subprocess.CalledProcessError, FileNotFoundError, PermissionError): pass - raise PackageManagerNotFoundError( - "No suitable package manager found. Please install either uv or pip." - ) + raise PackageManagerNotFoundError("No suitable package manager found. Please install either uv or pip.") def get_install_command(package_manager: str, venv_context=None) -> list: @@ -89,9 +85,7 @@ def get_install_command(package_manager: str, venv_context=None) -> list: raise ValueError(f"Unknown package manager: {package_manager}") -def install_packages( - packages: list, venv_context=None, package_manager: str = None -) -> None: +def install_packages(packages: list, venv_context=None, package_manager: str = None, cwd: Path = None) -> None: """Install packages using the available package manager. Args: @@ -105,7 +99,10 @@ def install_packages( install_cmd = get_install_command(package_manager, venv_context) try: - subprocess.check_call(install_cmd + packages) + if cwd: + subprocess.check_call(install_cmd + packages, cwd=cwd) + else: + subprocess.check_call(install_cmd + packages) except subprocess.CalledProcessError as e: raise RuntimeError(f"Failed to install packages with {package_manager}: {e}") diff --git a/packages/typespec-python/eng/scripts/setup/prepare.py b/packages/typespec-python/eng/scripts/setup/prepare.py index 045442ffb6..6e6de3d547 100644 --- a/packages/typespec-python/eng/scripts/setup/prepare.py +++ b/packages/typespec-python/eng/scripts/setup/prepare.py @@ -7,25 +7,28 @@ # -------------------------------------------------------------------------- import sys -if not sys.version_info >= (3, 9, 0): - raise Exception("Autorest for Python extension requires Python 3.9 at least") +if not sys.version_info >= (3, 10, 0): + raise Warning( + "Autorest for Python extension requires Python 3.10 at least. We will run your code with Pyodide since your Python version isn't adequate." + ) from pathlib import Path from package_manager import create_venv_with_package_manager, install_packages +# eng/scripts/setup/prepare.py -> need to go up 4 levels to get to package root _ROOT_DIR = Path(__file__).parent.parent.parent.parent def main(): venv_path = _ROOT_DIR / "venv" + venv_preexists = venv_path.exists() - # Create virtual environment using package manager abstraction - from package_manager import create_venv_with_package_manager, install_packages + assert venv_preexists # Otherwise install was not done venv_context = create_venv_with_package_manager(venv_path) try: - install_packages(["-r", f"{_ROOT_DIR}/dev_requirements.txt"], venv_context) + install_packages(["-r", f"{_ROOT_DIR}/generator/dev_requirements.txt"], venv_context, cwd=_ROOT_DIR) except FileNotFoundError as e: raise ValueError(e.filename) diff --git a/packages/typespec-python/eng/scripts/setup/run-python3.ts b/packages/typespec-python/eng/scripts/setup/run-python3.ts index 9c5d9499ed..422a28be73 100644 --- a/packages/typespec-python/eng/scripts/setup/run-python3.ts +++ b/packages/typespec-python/eng/scripts/setup/run-python3.ts @@ -9,18 +9,12 @@ import cp from "child_process"; import { patchPythonPath } from "./system-requirements.js"; -async function runPython3(...args: string[]) { +export async function runPython3(...args: string[]) { const command = await patchPythonPath(["python", ...args], { - version: ">=3.9", + version: ">=3.10", environmentVariable: "AUTOREST_PYTHON_EXE", }); - const [cmd, ...cmdArgs] = command; - cp.execFileSync(cmd, cmdArgs, { + cp.execSync(command.join(" "), { stdio: [0, 1, 2], }); } - -runPython3(...process.argv.slice(2)).catch((err) => { - console.error(err.toString()); // eslint-disable-line no-console - process.exit(1); -}); diff --git a/packages/typespec-python/eng/scripts/setup/run_batch.py b/packages/typespec-python/eng/scripts/setup/run_batch.py new file mode 100644 index 0000000000..6d6bef5b0d --- /dev/null +++ b/packages/typespec-python/eng/scripts/setup/run_batch.py @@ -0,0 +1,199 @@ +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- +""" +Batch process multiple TypeSpec YAML files in a single Python process. +This avoids the overhead of spawning a new Python process for each spec. +""" + +import argparse +import json +import sys +import os +from pathlib import Path +from concurrent.futures import ProcessPoolExecutor, as_completed +from multiprocessing import freeze_support + +# Add the generator to the path +_ROOT_DIR = Path(__file__).parent.parent.parent.parent +sys.path.insert(0, str(_ROOT_DIR / "generator")) + + +def process_single_spec(config_path_str: str) -> tuple[str, bool, str]: + """Process a single spec from its config file. + + Returns: (output_dir, success, error_message) + """ + # Import inside function for multiprocessing compatibility + from pygen import preprocess, codegen + + config_path = Path(config_path_str) + try: + with open(config_path, "r", encoding="utf-8") as f: + config = json.load(f) + + yaml_path = config["yamlPath"] + command_args = config["commandArgs"] + output_dir = config["outputDir"] + + # Pass command args directly to pygen - pygen expects hyphenated keys + # Remove keys that shouldn't be passed to pygen. + # Also coerce the string values "true"/"false" to real booleans, matching the behavior + # of pygen.utils.parse_args (the CLI path). Without this, the emitter passes string + # "false" for flags like keep-setup-py, which is truthy in Python and causes pygen to + # take the wrong branch (e.g. generating setup.py instead of pyproject.toml). + def _coerce(value): + if value == "true": + return True + if value == "false": + return False + return value + + pygen_args = { + k: _coerce(v) for k, v in command_args.items() if k not in ["emit-yaml-only"] + } + + # Run preprocess and codegen (black is batched at the end for performance) + preprocess.PreProcessPlugin(output_folder=output_dir, tsp_file=yaml_path, **pygen_args).process() + + codegen.CodeGenerator(output_folder=output_dir, tsp_file=yaml_path, **pygen_args).process() + + # Clean up the config file + config_path.unlink() + + return (output_dir, True, "") + except Exception as e: + return (str(config_path), False, str(e)) + + +def render_progress_bar(completed: int, failed: int, total: int, width: int = 40) -> str: + """Render a progress bar with green for success and red for failures.""" + success_count = completed - failed + success_width = round((success_count / total) * width) if total > 0 else 0 + fail_width = round((failed / total) * width) if total > 0 else 0 + empty_width = width - success_width - fail_width + + # ANSI color codes + green_bg = "\033[42m" + red_bg = "\033[41m" + reset = "\033[0m" + dim = "\033[2m" + cyan = "\033[36m" + + success_bar = f"{green_bg}{' ' * success_width}{reset}" + fail_bar = f"{red_bg}{' ' * fail_width}{reset}" if failed > 0 else "" + empty_bar = f"{dim}{'░' * max(0, empty_width)}{reset}" + + percent = round((completed / total) * 100) if total > 0 else 0 + return f"{success_bar}{fail_bar}{empty_bar} {cyan}{percent}%{reset} ({completed}/{total})" + + +def collect_config_files(generated_dir: str, flavor: str) -> list[str]: + """Collect all .tsp-codegen-*.json config files from the generated directory.""" + flavor_dir = Path(generated_dir) / "tests" / "generated" / flavor + if not flavor_dir.exists(): + return [] + + config_files = [] + for pkg_dir in flavor_dir.iterdir(): + if pkg_dir.is_dir(): + for f in pkg_dir.iterdir(): + if f.name.startswith(".tsp-codegen-") and f.name.endswith(".json"): + config_files.append(str(f)) + return config_files + + +def main(): + parser = argparse.ArgumentParser(description="Batch process TypeSpec YAML files") + parser.add_argument( + "--generated-dir", + required=True, + help="Path to the generator directory (config files are in ../tests/generated//)", + ) + parser.add_argument( + "--flavor", + required=True, + help="Flavor to process (azure or unbranded)", + ) + parser.add_argument( + "--jobs", + type=int, + default=4, + help="Number of parallel jobs (default: 4)", + ) + args = parser.parse_args() + + # Discover config files from the generated directory + config_files = collect_config_files(args.generated_dir, args.flavor) + total = len(config_files) + + if total == 0: + print("No config files found, nothing to process") + return + + print(f"Processing {total} specs with {args.jobs} parallel jobs...") + + succeeded = 0 + failed = 0 + failed_specs = [] + output_dirs = [] + is_tty = sys.stdout.isatty() + + def update_progress(): + if is_tty: + sys.stdout.write(f"\r{render_progress_bar(succeeded + failed, failed, total)}") + sys.stdout.flush() + + # Initial progress bar + update_progress() + + # Use ProcessPoolExecutor for true parallelism (bypasses GIL) + with ProcessPoolExecutor(max_workers=args.jobs) as executor: + futures = {executor.submit(process_single_spec, cf): cf for cf in config_files} + + for future in as_completed(futures): + output_dir, success, error = future.result() + if success: + succeeded += 1 + output_dirs.append(output_dir) + else: + failed += 1 + failed_specs.append(f"{output_dir}: {error}") + # Fail-fast: cancel pending futures on first failure + print(f"\n\033[31m[FAIL-FAST] Cancelling remaining tasks after failure...\033[0m") + for f in futures: + f.cancel() + break + update_progress() + + # Clear progress bar line + if is_tty: + sys.stdout.write("\r" + " " * 60 + "\r") + sys.stdout.flush() + + # Print failures at the end + if failed_specs: + print("\n\033[31mFailed specs:\033[0m") + for spec in failed_specs: + print(f" \033[31m•\033[0m {spec}") + + print(f"\nBatch processing complete: {succeeded} succeeded, {failed} failed") + + if failed > 0: + sys.exit(1) + + # Run black formatting after all codegen completes. Running black separately + # avoids duplicating black's import/startup cost in each worker process. + if output_dirs: + from pygen.black import BlackScriptPlugin + + print(f"Formatting {len(output_dirs)} packages with black...") + for d in output_dirs: + BlackScriptPlugin(output_folder=d).process() + + +if __name__ == "__main__": + freeze_support() # Required for Windows multiprocessing + main() diff --git a/packages/typespec-python/eng/scripts/setup/run_tsp.py b/packages/typespec-python/eng/scripts/setup/run_tsp.py index c7700e6e09..6d5d324704 100644 --- a/packages/typespec-python/eng/scripts/setup/run_tsp.py +++ b/packages/typespec-python/eng/scripts/setup/run_tsp.py @@ -9,7 +9,8 @@ from pygen import preprocess, codegen from pygen.utils import parse_args -_ROOT_DIR = Path(__file__).parent.parent +# eng/scripts/setup/run_tsp.py -> need to go up 4 levels to get to package root +_ROOT_DIR = Path(__file__).parent.parent.parent.parent _LOGGER = logging.getLogger(__name__) @@ -26,9 +27,7 @@ try: import debugpy # pylint: disable=import-outside-toplevel except (ImportError, ModuleNotFoundError): - raise SystemExit( - "Please pip install ptvsd in order to use VSCode debugging" - ) + raise SystemExit("Please pip install ptvsd in order to use VSCode debugging") # 5678 is the default attach port in the VS Code debug configurations debugpy.listen(("localhost", 5678)) @@ -37,9 +36,5 @@ # pre-process args, unknown_args = parse_args() - preprocess.PreProcessPlugin( - output_folder=args.output_folder, tsp_file=args.tsp_file, **unknown_args - ).process() - codegen.CodeGenerator( - output_folder=args.output_folder, tsp_file=args.tsp_file, **unknown_args - ).process() + preprocess.PreProcessPlugin(output_folder=args.output_folder, tsp_file=args.tsp_file, **unknown_args).process() + codegen.CodeGenerator(output_folder=args.output_folder, tsp_file=args.tsp_file, **unknown_args).process() diff --git a/packages/typespec-python/eng/scripts/setup/system-requirements.ts b/packages/typespec-python/eng/scripts/setup/system-requirements.ts index 236d14fc1b..f47685db62 100644 --- a/packages/typespec-python/eng/scripts/setup/system-requirements.ts +++ b/packages/typespec-python/eng/scripts/setup/system-requirements.ts @@ -1,5 +1,4 @@ import { ChildProcess, spawn, SpawnOptions } from "child_process"; -import { coerce, satisfies } from "semver"; /* * Copied from @autorest/system-requirements @@ -38,7 +37,7 @@ const execute = ( cp.on("error", (err) => { reject(err); }); - cp.on("close", (code, signal) => + cp.on("close", (code, _signal) => resolve({ stdout: out, stderr: err, @@ -50,12 +49,21 @@ const execute = ( }); }; +// Simple version comparison without semver dependency const versionIsSatisfied = (version: string, requirement: string): boolean => { - const cleanedVersion = coerce(version); - if (!cleanedVersion) { - throw new Error(`Invalid version ${version}.`); + // For now, support only >= requirements since that's what we use + if (requirement.startsWith(">=")) { + const requiredVersion = requirement.substring(2); + return parseVersionNumber(version) >= parseVersionNumber(requiredVersion); } - return satisfies(cleanedVersion, requirement, true); + // Fallback to true for other version requirements + return true; +}; + +const parseVersionNumber = (version: string): number => { + // Parse version like "3.9.0" to a comparable number + const parts = version.split(".").map((p) => parseInt(p.replace(/[^0-9]/g, ""), 10) || 0); + return parts[0] * 10000 + (parts[1] || 0) * 100 + (parts[2] || 0); }; /** @@ -114,7 +122,7 @@ const tryPython = async ( `"${PRINT_PYTHON_VERSION_SCRIPT}"`, ]); return validateVersionRequirement(resolution, result.stdout.trim(), requirement); - } catch (e) { + } catch { return { error: true, ...resolution, diff --git a/packages/typespec-python/eng/scripts/setup/venvtools.py b/packages/typespec-python/eng/scripts/setup/venvtools.py index f15abdd525..15a89fbcaa 100644 --- a/packages/typespec-python/eng/scripts/setup/venvtools.py +++ b/packages/typespec-python/eng/scripts/setup/venvtools.py @@ -8,8 +8,8 @@ import sys from pathlib import Path - -_ROOT_DIR = Path(__file__).parent.parent +# eng/scripts/setup/venvtools.py -> need to go up 4 levels to get to package root +_ROOT_DIR = Path(__file__).parent.parent.parent.parent class ExtendedEnvBuilder(venv.EnvBuilder): @@ -19,6 +19,9 @@ class ExtendedEnvBuilder(venv.EnvBuilder): def __init__(self, *args, **kwargs): self.context = None + if sys.version_info < (3, 9, 0): + # Not supported on Python 3.8, and we don't need it + kwargs.pop("upgrade_deps", None) super().__init__(*args, **kwargs) def ensure_directories(self, env_dir): diff --git a/packages/typespec-python/eng/scripts/sync.ts b/packages/typespec-python/eng/scripts/sync.ts index 6152c7f589..7e5d49ad0c 100644 --- a/packages/typespec-python/eng/scripts/sync.ts +++ b/packages/typespec-python/eng/scripts/sync.ts @@ -66,10 +66,12 @@ const INCLUDES: readonly string[] = [ "ci/regenerate.ts", "ci/regenerate-common.ts", - // Shared setup scripts (invoked by package.json install/prepare hooks) + // Shared setup scripts (invoked by package.json install/prepare hooks + // and by ci/regenerate.ts which spawns run_batch.py). "setup/install.py", "setup/package_manager.py", "setup/prepare.py", + "setup/run_batch.py", "setup/run_tsp.py", "setup/run-python3.ts", "setup/system-requirements.ts", diff --git a/packages/typespec-python/package.json b/packages/typespec-python/package.json index 7c1ae78593..93d73eac70 100644 --- a/packages/typespec-python/package.json +++ b/packages/typespec-python/package.json @@ -37,7 +37,7 @@ "lint:extra": "tsx ./eng/scripts/ci/lint.ts", "format:extra": "tsx ./eng/scripts/ci/format.ts --python", "format:extra:check": "tsx ./eng/scripts/ci/format.ts --python --check", - "regenerate": "tsx ./eng/scripts/regenerate.ts", + "regenerate": "tsx ./eng/scripts/ci/regenerate.ts --emitterName @azure-tools/typespec-python --generatedFolder ./generator", "sync": "tsx ./eng/scripts/sync.ts", "sync:check": "tsx ./eng/scripts/sync.ts --check", "test:python:e2e": "tsx ./eng/scripts/ci/run-tests.ts", From f32768c89ac05eef583e6b374f3551cf11db80b2 Mon Sep 17 00:00:00 2001 From: Yuchao Yan Date: Thu, 7 May 2026 17:26:10 +0800 Subject: [PATCH 03/36] remove tests folder --- packages/typespec-python/.gitignore | 11 + packages/typespec-python/eng/scripts/sync.ts | 232 +++++++-- packages/typespec-python/package.json | 1 + packages/typespec-python/tests/conftest.py | 223 -------- packages/typespec-python/tests/data/image.jpg | Bin 4069 -> 0 bytes packages/typespec-python/tests/data/image.png | Bin 2992 -> 0 bytes .../typespec-python/tests/install_packages.py | 145 ------ .../test_azure_arm_commonproperties_async.py | 94 ---- .../test_azure_arm_largeheader_async.py | 30 -- .../test_azure_arm_nonresource_async.py | 36 -- ...test_azure_arm_operationtemplates_async.py | 205 -------- .../test_azure_arm_resource_async.py | 478 ------------------ ...zure_client_generator_core_access_async.py | 101 ---- ...ent_generator_core_alternate_type_async.py | 73 --- ...generator_core_api_version_header_async.py | 18 - ...t_generator_core_api_version_path_async.py | 18 - ..._generator_core_api_version_query_async.py | 18 - ...nerator_core_client_default_value_async.py | 46 -- ...erator_core_client_initialization_async.py | 58 --- ...nt_generator_core_client_location_async.py | 82 --- ..._deserialize_empty_string_as_null_async.py | 20 - ...ure_client_generator_core_flatten_async.py | 115 ----- ...enerator_core_hierrarchy_building_async.py | 53 -- ...ent_generator_core_next_link_verb_async.py | 28 - ...re_client_generator_core_override_async.py | 106 ---- ...azure_client_generator_core_usage_async.py | 38 -- .../asynctests/test_azure_core_basic_async.py | 76 --- .../test_azure_core_lro_rpc_async.py | 22 - .../test_azure_core_lro_standard_async.py | 39 -- .../asynctests/test_azure_core_model_async.py | 33 -- .../asynctests/test_azure_core_page_async.py | 80 --- .../test_azure_core_scalar_async.py | 41 -- .../test_azure_core_traits_async.py | 87 ---- .../test_azure_encode_duration_async.py | 19 - .../test_azure_example_basic_async.py | 30 -- .../test_azure_payload_pageable_async.py | 19 - ...ce_manager_method_subscription_id_async.py | 248 --------- ...re_resource_manager_multi_service_async.py | 110 ---- ...nager_multi_service_shared_models_async.py | 132 ----- ...special_headers_client_request_id_async.py | 30 -- ...t_azure_versioning_previewversion_async.py | 53 -- .../asynctests/test_client_namespace_async.py | 34 -- .../asynctests/test_client_naming_async.py | 69 --- .../test_client_naming_enum_conflict_async.py | 37 -- .../asynctests/test_client_overload_async.py | 27 - .../asynctests/test_client_structure_async.py | 64 --- ...nt_structure_clientoperationgroup_async.py | 31 -- .../asynctests/test_encode_duration_async.py | 63 --- .../asynctests/test_encode_numeric_async.py | 35 -- .../asynctests/test_parameters_basic_async.py | 24 - .../test_parameters_spread_async.py | 76 --- .../test_payload_content_negotiation_async.py | 37 -- .../test_payload_multipart_async.py | 216 -------- .../test_resiliency_srv_driven_async.py | 130 ----- ...t_serialization_encoded_name_json_async.py | 24 - .../test_service_multi_service_async.py | 31 -- .../asynctests/test_special_words_async.py | 71 --- .../tests/mock_api/azure/conftest.py | 170 ------- .../tests/mock_api/azure/data/image.jpg | Bin 4069 -> 0 bytes .../tests/mock_api/azure/data/image.png | Bin 2992 -> 0 bytes .../azure/test_azure_arm_commonproperties.py | 89 ---- .../azure/test_azure_arm_largeheader.py | 27 - .../azure/test_azure_arm_nonresource.py | 34 -- .../test_azure_arm_operationtemplates.py | 180 ------- .../mock_api/azure/test_azure_arm_resource.py | 436 ---------------- ...test_azure_client_generator_core_access.py | 92 ---- ...re_client_generator_core_alternate_type.py | 69 --- ...lient_generator_core_api_version_header.py | 17 - ..._client_generator_core_api_version_path.py | 17 - ...client_generator_core_api_version_query.py | 17 - ...ent_generator_core_client_default_value.py | 42 -- ...nt_generator_core_client_initialization.py | 51 -- ...e_client_generator_core_client_location.py | 70 --- ...r_core_deserialize_empty_string_as_null.py | 19 - ...est_azure_client_generator_core_flatten.py | 104 ---- ...ient_generator_core_hierrarchy_building.py | 45 -- ...re_client_generator_core_next_link_verb.py | 27 - ...st_azure_client_generator_core_override.py | 102 ---- .../test_azure_client_generator_core_usage.py | 32 -- .../mock_api/azure/test_azure_core_basic.py | 70 --- .../mock_api/azure/test_azure_core_lro_rpc.py | 20 - .../azure/test_azure_core_lro_standard.py | 32 -- .../mock_api/azure/test_azure_core_model.py | 30 -- .../mock_api/azure/test_azure_core_page.py | 71 --- .../mock_api/azure/test_azure_core_scalar.py | 35 -- .../mock_api/azure/test_azure_core_traits.py | 85 ---- .../azure/test_azure_encode_duration.py | 18 - .../azure/test_azure_example_basic.py | 29 -- .../azure/test_azure_payload_pageable.py | 18 - ...resource_manager_method_subscription_id.py | 235 --------- ...st_azure_resource_manager_multi_service.py | 104 ---- ...rce_manager_multi_service_shared_models.py | 128 ----- ...azure_special_headers_client_request_id.py | 29 -- .../test_azure_versioning_previewversion.py | 50 -- .../azure/test_clear_output_folder.py | 23 - .../mock_api/azure/test_client_namespace.py | 32 -- .../mock_api/azure/test_client_naming.py | 57 --- .../azure/test_client_naming_enum_conflict.py | 35 -- .../mock_api/azure/test_client_overload.py | 25 - .../mock_api/azure/test_client_structure.py | 60 --- ...t_client_structure_clientoperationgroup.py | 29 -- .../mock_api/azure/test_encode_duration.py | 60 --- .../mock_api/azure/test_encode_numeric.py | 31 -- .../test_model_base_flatten_compatibility.py | 251 --------- .../mock_api/azure/test_parameters_basic.py | 22 - .../mock_api/azure/test_parameters_spread.py | 66 --- .../azure/test_payload_content_negotiation.py | 33 -- .../mock_api/azure/test_payload_multipart.py | 198 -------- .../azure/test_resiliency_srv_driven.py | 124 ----- .../test_serialization_encoded_name_json.py | 21 - .../azure/test_service_multi_service.py | 29 -- .../mock_api/azure/test_special_words.py | 63 --- .../asynctests/test_authentication_async.py | 140 ----- .../asynctests/test_encode_array_async.py | 139 ----- .../asynctests/test_encode_bytes_async.py | 132 ----- .../asynctests/test_encode_datetime_async.py | 127 ----- .../test_generation_subdir_async.py | 25 - .../asynctests/test_headasboolean_async.py | 35 -- .../test_parameters_body_optionality_async.py | 30 -- ...test_parameters_collection_format_async.py | 38 -- .../asynctests/test_parameters_path_async.py | 24 - .../asynctests/test_parameters_query_async.py | 18 - .../test_payload_json_merge_patch_async.py | 98 ---- .../test_payload_media_type_async.py | 27 - .../asynctests/test_payload_pageable_async.py | 134 ----- .../asynctests/test_payload_xml_async.py | 260 ---------- .../test_response_status_code_range_async.py | 38 -- .../shared/asynctests/test_routes_async.py | 331 ------------ .../test_server_endpoint_not_defined_async.py | 18 - .../test_server_path_multiple_async.py | 25 - .../test_server_path_single_async.py | 18 - ...est_server_versions_not_versioned_async.py | 28 - .../test_server_versions_versioned_async.py | 34 -- ...ecial_headers_conditional_request_async.py | 38 -- ...est_special_headers_repeatability_async.py | 19 - .../test_specs_documentation_async.py | 59 --- .../asynctests/test_streaming_jsonl_async.py | 27 - .../asynctests/test_typetest_array_async.py | 127 ----- .../test_typetest_dictionary_async.py | 98 ---- .../test_typetest_enum_extensible_async.py | 25 - .../test_typetest_enum_fixed_async.py | 27 - .../asynctests/test_typetest_file_async.py | 59 --- .../test_typetest_model_empty_async.py | 32 -- ...el_inheritance_enum_discriminator_async.py | 70 --- ..._inheritance_nested_discriminator_async.py | 85 ---- ...del_inheritance_not_discriminated_async.py | 34 -- ...etest_model_inheritance_recursive_async.py | 34 -- ..._inheritance_single_discriminator_async.py | 67 --- .../test_typetest_model_usage_async.py | 32 -- .../test_typetest_model_visibility_async.py | 47 -- ...est_property_additionalproperties_async.py | 353 ------------- .../test_typetest_property_nullable_async.py | 110 ---- .../test_typetest_property_optional_async.py | 197 -------- ...test_typetest_property_valuetypes_async.py | 315 ------------ .../asynctests/test_typetest_scalar_async.py | 60 --- .../asynctests/test_typetest_union_async.py | 90 ---- .../asynctests/test_versioning_added_async.py | 36 -- .../test_versioning_made_optional_async.py | 21 - .../test_versioning_removed_async.py | 39 -- .../test_versioning_renamed_from_async.py | 29 -- ...rsioning_return_type_changed_from_async.py | 18 - ...test_versioning_type_changed_from_async.py | 22 - .../tests/mock_api/shared/conftest.py | 7 - .../tests/mock_api/shared/data/image.jpg | Bin 4069 -> 0 bytes .../tests/mock_api/shared/data/image.png | Bin 2992 -> 0 bytes .../mock_api/shared/test_authentication.py | 130 ----- .../mock_api/shared/test_encode_array.py | 126 ----- .../mock_api/shared/test_encode_bytes.py | 128 ----- .../mock_api/shared/test_encode_datetime.py | 123 ----- .../mock_api/shared/test_generation_subdir.py | 17 - .../mock_api/shared/test_headasboolean.py | 33 -- .../test_parameters_body_optionality.py | 27 - .../test_parameters_collection_format.py | 33 -- .../mock_api/shared/test_parameters_path.py | 22 - .../mock_api/shared/test_parameters_query.py | 17 - .../tests/mock_api/shared/test_patch.py | 12 - .../shared/test_payload_json_merge_patch.py | 93 ---- .../shared/test_payload_media_type.py | 25 - .../mock_api/shared/test_payload_pageable.py | 99 ---- .../tests/mock_api/shared/test_payload_xml.py | 234 --------- .../shared/test_response_status_code_range.py | 36 -- .../tests/mock_api/shared/test_routes.py | 285 ----------- .../test_server_endpoint_not_defined.py | 17 - .../shared/test_server_path_multiple.py | 21 - .../shared/test_server_path_single.py | 17 - .../test_server_versions_not_versioned.py | 25 - .../shared/test_server_versions_versioned.py | 30 -- ...est_special_headers_conditional_request.py | 34 -- .../test_special_headers_repeatability.py | 18 - .../shared/test_specs_documentation.py | 51 -- .../mock_api/shared/test_streaming_jsonl.py | 25 - .../mock_api/shared/test_typetest_array.py | 111 ---- .../shared/test_typetest_dictionary.py | 86 ---- .../shared/test_typetest_enum_extensible.py | 23 - .../shared/test_typetest_enum_fixed.py | 25 - .../mock_api/shared/test_typetest_file.py | 52 -- .../shared/test_typetest_model_empty.py | 29 -- ...st_model_inheritance_enum_discriminator.py | 58 --- ..._model_inheritance_nested_discriminator.py | 79 --- ...est_model_inheritance_not_discriminated.py | 31 -- ...st_typetest_model_inheritance_recursive.py | 32 -- ..._model_inheritance_single_discriminator.py | 60 --- .../shared/test_typetest_model_usage.py | 28 - .../shared/test_typetest_model_visibility.py | 40 -- ..._typetest_property_additionalproperties.py | 314 ------------ .../shared/test_typetest_property_nullable.py | 102 ---- .../shared/test_typetest_property_optional.py | 174 ------- .../test_typetest_property_valuetypes.py | 286 ----------- .../mock_api/shared/test_typetest_scalar.py | 53 -- .../mock_api/shared/test_typetest_union.py | 80 --- .../test_typetest_union_discriminated.py | 290 ----------- .../mock_api/shared/test_versioning_added.py | 33 -- .../shared/test_versioning_made_optional.py | 20 - .../shared/test_versioning_removed.py | 37 -- .../shared/test_versioning_renamed_from.py | 27 - ...est_versioning_return_type_changed_from.py | 17 - .../test_versioning_type_changed_from.py | 21 - .../shared/unittests/test_parse_pyproject.py | 98 ---- .../asynctests/test_auth_flow_async.py | 19 - .../asynctests/test_encode_duration_async.py | 63 --- .../asynctests/test_encode_numeric_async.py | 35 -- .../asynctests/test_parameters_basic_async.py | 24 - .../test_parameters_spread_async.py | 76 --- .../test_payload_content_negotiation_async.py | 37 -- .../test_payload_multipart_async.py | 218 -------- ...t_serialization_encoded_name_json_async.py | 24 - .../asynctests/test_special_words_async.py | 73 --- .../asynctests/test_unbranded_async.py | 27 - .../tests/mock_api/unbranded/conftest.py | 53 -- .../tests/mock_api/unbranded/data/image.jpg | Bin 4069 -> 0 bytes .../tests/mock_api/unbranded/data/image.png | Bin 2992 -> 0 bytes .../mock_api/unbranded/test_auth_flow.py | 17 - .../unbranded/test_encode_duration.py | 60 --- .../mock_api/unbranded/test_encode_numeric.py | 32 -- .../unbranded/test_parameters_basic.py | 22 - .../unbranded/test_parameters_spread.py | 66 --- .../test_payload_content_negotiation.py | 33 -- .../unbranded/test_payload_multipart.py | 200 -------- .../test_serialization_encoded_name_json.py | 22 - .../mock_api/unbranded/test_special_words.py | 66 --- .../mock_api/unbranded/test_unbranded.py | 59 --- .../tests/requirements/azure.txt | 5 - .../tests/requirements/base.txt | 12 - .../tests/requirements/docs.txt | 7 - .../tests/requirements/lint.txt | 4 - .../tests/requirements/typecheck.txt | 5 - .../tests/requirements/unbranded.txt | 3 - packages/typespec-python/tests/tox.ini | 226 --------- 248 files changed, 190 insertions(+), 17048 deletions(-) create mode 100644 packages/typespec-python/.gitignore delete mode 100644 packages/typespec-python/tests/conftest.py delete mode 100644 packages/typespec-python/tests/data/image.jpg delete mode 100644 packages/typespec-python/tests/data/image.png delete mode 100644 packages/typespec-python/tests/install_packages.py delete mode 100644 packages/typespec-python/tests/mock_api/azure/asynctests/test_azure_arm_commonproperties_async.py delete mode 100644 packages/typespec-python/tests/mock_api/azure/asynctests/test_azure_arm_largeheader_async.py delete mode 100644 packages/typespec-python/tests/mock_api/azure/asynctests/test_azure_arm_nonresource_async.py delete mode 100644 packages/typespec-python/tests/mock_api/azure/asynctests/test_azure_arm_operationtemplates_async.py delete mode 100644 packages/typespec-python/tests/mock_api/azure/asynctests/test_azure_arm_resource_async.py delete mode 100644 packages/typespec-python/tests/mock_api/azure/asynctests/test_azure_client_generator_core_access_async.py delete mode 100644 packages/typespec-python/tests/mock_api/azure/asynctests/test_azure_client_generator_core_alternate_type_async.py delete mode 100644 packages/typespec-python/tests/mock_api/azure/asynctests/test_azure_client_generator_core_api_version_header_async.py delete mode 100644 packages/typespec-python/tests/mock_api/azure/asynctests/test_azure_client_generator_core_api_version_path_async.py delete mode 100644 packages/typespec-python/tests/mock_api/azure/asynctests/test_azure_client_generator_core_api_version_query_async.py delete mode 100644 packages/typespec-python/tests/mock_api/azure/asynctests/test_azure_client_generator_core_client_default_value_async.py delete mode 100644 packages/typespec-python/tests/mock_api/azure/asynctests/test_azure_client_generator_core_client_initialization_async.py delete mode 100644 packages/typespec-python/tests/mock_api/azure/asynctests/test_azure_client_generator_core_client_location_async.py delete mode 100644 packages/typespec-python/tests/mock_api/azure/asynctests/test_azure_client_generator_core_deserialize_empty_string_as_null_async.py delete mode 100644 packages/typespec-python/tests/mock_api/azure/asynctests/test_azure_client_generator_core_flatten_async.py delete mode 100644 packages/typespec-python/tests/mock_api/azure/asynctests/test_azure_client_generator_core_hierrarchy_building_async.py delete mode 100644 packages/typespec-python/tests/mock_api/azure/asynctests/test_azure_client_generator_core_next_link_verb_async.py delete mode 100644 packages/typespec-python/tests/mock_api/azure/asynctests/test_azure_client_generator_core_override_async.py delete mode 100644 packages/typespec-python/tests/mock_api/azure/asynctests/test_azure_client_generator_core_usage_async.py delete mode 100644 packages/typespec-python/tests/mock_api/azure/asynctests/test_azure_core_basic_async.py delete mode 100644 packages/typespec-python/tests/mock_api/azure/asynctests/test_azure_core_lro_rpc_async.py delete mode 100644 packages/typespec-python/tests/mock_api/azure/asynctests/test_azure_core_lro_standard_async.py delete mode 100644 packages/typespec-python/tests/mock_api/azure/asynctests/test_azure_core_model_async.py delete mode 100644 packages/typespec-python/tests/mock_api/azure/asynctests/test_azure_core_page_async.py delete mode 100644 packages/typespec-python/tests/mock_api/azure/asynctests/test_azure_core_scalar_async.py delete mode 100644 packages/typespec-python/tests/mock_api/azure/asynctests/test_azure_core_traits_async.py delete mode 100644 packages/typespec-python/tests/mock_api/azure/asynctests/test_azure_encode_duration_async.py delete mode 100644 packages/typespec-python/tests/mock_api/azure/asynctests/test_azure_example_basic_async.py delete mode 100644 packages/typespec-python/tests/mock_api/azure/asynctests/test_azure_payload_pageable_async.py delete mode 100644 packages/typespec-python/tests/mock_api/azure/asynctests/test_azure_resource_manager_method_subscription_id_async.py delete mode 100644 packages/typespec-python/tests/mock_api/azure/asynctests/test_azure_resource_manager_multi_service_async.py delete mode 100644 packages/typespec-python/tests/mock_api/azure/asynctests/test_azure_resource_manager_multi_service_shared_models_async.py delete mode 100644 packages/typespec-python/tests/mock_api/azure/asynctests/test_azure_special_headers_client_request_id_async.py delete mode 100644 packages/typespec-python/tests/mock_api/azure/asynctests/test_azure_versioning_previewversion_async.py delete mode 100644 packages/typespec-python/tests/mock_api/azure/asynctests/test_client_namespace_async.py delete mode 100644 packages/typespec-python/tests/mock_api/azure/asynctests/test_client_naming_async.py delete mode 100644 packages/typespec-python/tests/mock_api/azure/asynctests/test_client_naming_enum_conflict_async.py delete mode 100644 packages/typespec-python/tests/mock_api/azure/asynctests/test_client_overload_async.py delete mode 100644 packages/typespec-python/tests/mock_api/azure/asynctests/test_client_structure_async.py delete mode 100644 packages/typespec-python/tests/mock_api/azure/asynctests/test_client_structure_clientoperationgroup_async.py delete mode 100644 packages/typespec-python/tests/mock_api/azure/asynctests/test_encode_duration_async.py delete mode 100644 packages/typespec-python/tests/mock_api/azure/asynctests/test_encode_numeric_async.py delete mode 100644 packages/typespec-python/tests/mock_api/azure/asynctests/test_parameters_basic_async.py delete mode 100644 packages/typespec-python/tests/mock_api/azure/asynctests/test_parameters_spread_async.py delete mode 100644 packages/typespec-python/tests/mock_api/azure/asynctests/test_payload_content_negotiation_async.py delete mode 100644 packages/typespec-python/tests/mock_api/azure/asynctests/test_payload_multipart_async.py delete mode 100644 packages/typespec-python/tests/mock_api/azure/asynctests/test_resiliency_srv_driven_async.py delete mode 100644 packages/typespec-python/tests/mock_api/azure/asynctests/test_serialization_encoded_name_json_async.py delete mode 100644 packages/typespec-python/tests/mock_api/azure/asynctests/test_service_multi_service_async.py delete mode 100644 packages/typespec-python/tests/mock_api/azure/asynctests/test_special_words_async.py delete mode 100644 packages/typespec-python/tests/mock_api/azure/conftest.py delete mode 100644 packages/typespec-python/tests/mock_api/azure/data/image.jpg delete mode 100644 packages/typespec-python/tests/mock_api/azure/data/image.png delete mode 100644 packages/typespec-python/tests/mock_api/azure/test_azure_arm_commonproperties.py delete mode 100644 packages/typespec-python/tests/mock_api/azure/test_azure_arm_largeheader.py delete mode 100644 packages/typespec-python/tests/mock_api/azure/test_azure_arm_nonresource.py delete mode 100644 packages/typespec-python/tests/mock_api/azure/test_azure_arm_operationtemplates.py delete mode 100644 packages/typespec-python/tests/mock_api/azure/test_azure_arm_resource.py delete mode 100644 packages/typespec-python/tests/mock_api/azure/test_azure_client_generator_core_access.py delete mode 100644 packages/typespec-python/tests/mock_api/azure/test_azure_client_generator_core_alternate_type.py delete mode 100644 packages/typespec-python/tests/mock_api/azure/test_azure_client_generator_core_api_version_header.py delete mode 100644 packages/typespec-python/tests/mock_api/azure/test_azure_client_generator_core_api_version_path.py delete mode 100644 packages/typespec-python/tests/mock_api/azure/test_azure_client_generator_core_api_version_query.py delete mode 100644 packages/typespec-python/tests/mock_api/azure/test_azure_client_generator_core_client_default_value.py delete mode 100644 packages/typespec-python/tests/mock_api/azure/test_azure_client_generator_core_client_initialization.py delete mode 100644 packages/typespec-python/tests/mock_api/azure/test_azure_client_generator_core_client_location.py delete mode 100644 packages/typespec-python/tests/mock_api/azure/test_azure_client_generator_core_deserialize_empty_string_as_null.py delete mode 100644 packages/typespec-python/tests/mock_api/azure/test_azure_client_generator_core_flatten.py delete mode 100644 packages/typespec-python/tests/mock_api/azure/test_azure_client_generator_core_hierrarchy_building.py delete mode 100644 packages/typespec-python/tests/mock_api/azure/test_azure_client_generator_core_next_link_verb.py delete mode 100644 packages/typespec-python/tests/mock_api/azure/test_azure_client_generator_core_override.py delete mode 100644 packages/typespec-python/tests/mock_api/azure/test_azure_client_generator_core_usage.py delete mode 100644 packages/typespec-python/tests/mock_api/azure/test_azure_core_basic.py delete mode 100644 packages/typespec-python/tests/mock_api/azure/test_azure_core_lro_rpc.py delete mode 100644 packages/typespec-python/tests/mock_api/azure/test_azure_core_lro_standard.py delete mode 100644 packages/typespec-python/tests/mock_api/azure/test_azure_core_model.py delete mode 100644 packages/typespec-python/tests/mock_api/azure/test_azure_core_page.py delete mode 100644 packages/typespec-python/tests/mock_api/azure/test_azure_core_scalar.py delete mode 100644 packages/typespec-python/tests/mock_api/azure/test_azure_core_traits.py delete mode 100644 packages/typespec-python/tests/mock_api/azure/test_azure_encode_duration.py delete mode 100644 packages/typespec-python/tests/mock_api/azure/test_azure_example_basic.py delete mode 100644 packages/typespec-python/tests/mock_api/azure/test_azure_payload_pageable.py delete mode 100644 packages/typespec-python/tests/mock_api/azure/test_azure_resource_manager_method_subscription_id.py delete mode 100644 packages/typespec-python/tests/mock_api/azure/test_azure_resource_manager_multi_service.py delete mode 100644 packages/typespec-python/tests/mock_api/azure/test_azure_resource_manager_multi_service_shared_models.py delete mode 100644 packages/typespec-python/tests/mock_api/azure/test_azure_special_headers_client_request_id.py delete mode 100644 packages/typespec-python/tests/mock_api/azure/test_azure_versioning_previewversion.py delete mode 100644 packages/typespec-python/tests/mock_api/azure/test_clear_output_folder.py delete mode 100644 packages/typespec-python/tests/mock_api/azure/test_client_namespace.py delete mode 100644 packages/typespec-python/tests/mock_api/azure/test_client_naming.py delete mode 100644 packages/typespec-python/tests/mock_api/azure/test_client_naming_enum_conflict.py delete mode 100644 packages/typespec-python/tests/mock_api/azure/test_client_overload.py delete mode 100644 packages/typespec-python/tests/mock_api/azure/test_client_structure.py delete mode 100644 packages/typespec-python/tests/mock_api/azure/test_client_structure_clientoperationgroup.py delete mode 100644 packages/typespec-python/tests/mock_api/azure/test_encode_duration.py delete mode 100644 packages/typespec-python/tests/mock_api/azure/test_encode_numeric.py delete mode 100644 packages/typespec-python/tests/mock_api/azure/test_model_base_flatten_compatibility.py delete mode 100644 packages/typespec-python/tests/mock_api/azure/test_parameters_basic.py delete mode 100644 packages/typespec-python/tests/mock_api/azure/test_parameters_spread.py delete mode 100644 packages/typespec-python/tests/mock_api/azure/test_payload_content_negotiation.py delete mode 100644 packages/typespec-python/tests/mock_api/azure/test_payload_multipart.py delete mode 100644 packages/typespec-python/tests/mock_api/azure/test_resiliency_srv_driven.py delete mode 100644 packages/typespec-python/tests/mock_api/azure/test_serialization_encoded_name_json.py delete mode 100644 packages/typespec-python/tests/mock_api/azure/test_service_multi_service.py delete mode 100644 packages/typespec-python/tests/mock_api/azure/test_special_words.py delete mode 100644 packages/typespec-python/tests/mock_api/shared/asynctests/test_authentication_async.py delete mode 100644 packages/typespec-python/tests/mock_api/shared/asynctests/test_encode_array_async.py delete mode 100644 packages/typespec-python/tests/mock_api/shared/asynctests/test_encode_bytes_async.py delete mode 100644 packages/typespec-python/tests/mock_api/shared/asynctests/test_encode_datetime_async.py delete mode 100644 packages/typespec-python/tests/mock_api/shared/asynctests/test_generation_subdir_async.py delete mode 100644 packages/typespec-python/tests/mock_api/shared/asynctests/test_headasboolean_async.py delete mode 100644 packages/typespec-python/tests/mock_api/shared/asynctests/test_parameters_body_optionality_async.py delete mode 100644 packages/typespec-python/tests/mock_api/shared/asynctests/test_parameters_collection_format_async.py delete mode 100644 packages/typespec-python/tests/mock_api/shared/asynctests/test_parameters_path_async.py delete mode 100644 packages/typespec-python/tests/mock_api/shared/asynctests/test_parameters_query_async.py delete mode 100644 packages/typespec-python/tests/mock_api/shared/asynctests/test_payload_json_merge_patch_async.py delete mode 100644 packages/typespec-python/tests/mock_api/shared/asynctests/test_payload_media_type_async.py delete mode 100644 packages/typespec-python/tests/mock_api/shared/asynctests/test_payload_pageable_async.py delete mode 100644 packages/typespec-python/tests/mock_api/shared/asynctests/test_payload_xml_async.py delete mode 100644 packages/typespec-python/tests/mock_api/shared/asynctests/test_response_status_code_range_async.py delete mode 100644 packages/typespec-python/tests/mock_api/shared/asynctests/test_routes_async.py delete mode 100644 packages/typespec-python/tests/mock_api/shared/asynctests/test_server_endpoint_not_defined_async.py delete mode 100644 packages/typespec-python/tests/mock_api/shared/asynctests/test_server_path_multiple_async.py delete mode 100644 packages/typespec-python/tests/mock_api/shared/asynctests/test_server_path_single_async.py delete mode 100644 packages/typespec-python/tests/mock_api/shared/asynctests/test_server_versions_not_versioned_async.py delete mode 100644 packages/typespec-python/tests/mock_api/shared/asynctests/test_server_versions_versioned_async.py delete mode 100644 packages/typespec-python/tests/mock_api/shared/asynctests/test_special_headers_conditional_request_async.py delete mode 100644 packages/typespec-python/tests/mock_api/shared/asynctests/test_special_headers_repeatability_async.py delete mode 100644 packages/typespec-python/tests/mock_api/shared/asynctests/test_specs_documentation_async.py delete mode 100644 packages/typespec-python/tests/mock_api/shared/asynctests/test_streaming_jsonl_async.py delete mode 100644 packages/typespec-python/tests/mock_api/shared/asynctests/test_typetest_array_async.py delete mode 100644 packages/typespec-python/tests/mock_api/shared/asynctests/test_typetest_dictionary_async.py delete mode 100644 packages/typespec-python/tests/mock_api/shared/asynctests/test_typetest_enum_extensible_async.py delete mode 100644 packages/typespec-python/tests/mock_api/shared/asynctests/test_typetest_enum_fixed_async.py delete mode 100644 packages/typespec-python/tests/mock_api/shared/asynctests/test_typetest_file_async.py delete mode 100644 packages/typespec-python/tests/mock_api/shared/asynctests/test_typetest_model_empty_async.py delete mode 100644 packages/typespec-python/tests/mock_api/shared/asynctests/test_typetest_model_inheritance_enum_discriminator_async.py delete mode 100644 packages/typespec-python/tests/mock_api/shared/asynctests/test_typetest_model_inheritance_nested_discriminator_async.py delete mode 100644 packages/typespec-python/tests/mock_api/shared/asynctests/test_typetest_model_inheritance_not_discriminated_async.py delete mode 100644 packages/typespec-python/tests/mock_api/shared/asynctests/test_typetest_model_inheritance_recursive_async.py delete mode 100644 packages/typespec-python/tests/mock_api/shared/asynctests/test_typetest_model_inheritance_single_discriminator_async.py delete mode 100644 packages/typespec-python/tests/mock_api/shared/asynctests/test_typetest_model_usage_async.py delete mode 100644 packages/typespec-python/tests/mock_api/shared/asynctests/test_typetest_model_visibility_async.py delete mode 100644 packages/typespec-python/tests/mock_api/shared/asynctests/test_typetest_property_additionalproperties_async.py delete mode 100644 packages/typespec-python/tests/mock_api/shared/asynctests/test_typetest_property_nullable_async.py delete mode 100644 packages/typespec-python/tests/mock_api/shared/asynctests/test_typetest_property_optional_async.py delete mode 100644 packages/typespec-python/tests/mock_api/shared/asynctests/test_typetest_property_valuetypes_async.py delete mode 100644 packages/typespec-python/tests/mock_api/shared/asynctests/test_typetest_scalar_async.py delete mode 100644 packages/typespec-python/tests/mock_api/shared/asynctests/test_typetest_union_async.py delete mode 100644 packages/typespec-python/tests/mock_api/shared/asynctests/test_versioning_added_async.py delete mode 100644 packages/typespec-python/tests/mock_api/shared/asynctests/test_versioning_made_optional_async.py delete mode 100644 packages/typespec-python/tests/mock_api/shared/asynctests/test_versioning_removed_async.py delete mode 100644 packages/typespec-python/tests/mock_api/shared/asynctests/test_versioning_renamed_from_async.py delete mode 100644 packages/typespec-python/tests/mock_api/shared/asynctests/test_versioning_return_type_changed_from_async.py delete mode 100644 packages/typespec-python/tests/mock_api/shared/asynctests/test_versioning_type_changed_from_async.py delete mode 100644 packages/typespec-python/tests/mock_api/shared/conftest.py delete mode 100644 packages/typespec-python/tests/mock_api/shared/data/image.jpg delete mode 100644 packages/typespec-python/tests/mock_api/shared/data/image.png delete mode 100644 packages/typespec-python/tests/mock_api/shared/test_authentication.py delete mode 100644 packages/typespec-python/tests/mock_api/shared/test_encode_array.py delete mode 100644 packages/typespec-python/tests/mock_api/shared/test_encode_bytes.py delete mode 100644 packages/typespec-python/tests/mock_api/shared/test_encode_datetime.py delete mode 100644 packages/typespec-python/tests/mock_api/shared/test_generation_subdir.py delete mode 100644 packages/typespec-python/tests/mock_api/shared/test_headasboolean.py delete mode 100644 packages/typespec-python/tests/mock_api/shared/test_parameters_body_optionality.py delete mode 100644 packages/typespec-python/tests/mock_api/shared/test_parameters_collection_format.py delete mode 100644 packages/typespec-python/tests/mock_api/shared/test_parameters_path.py delete mode 100644 packages/typespec-python/tests/mock_api/shared/test_parameters_query.py delete mode 100644 packages/typespec-python/tests/mock_api/shared/test_patch.py delete mode 100644 packages/typespec-python/tests/mock_api/shared/test_payload_json_merge_patch.py delete mode 100644 packages/typespec-python/tests/mock_api/shared/test_payload_media_type.py delete mode 100644 packages/typespec-python/tests/mock_api/shared/test_payload_pageable.py delete mode 100644 packages/typespec-python/tests/mock_api/shared/test_payload_xml.py delete mode 100644 packages/typespec-python/tests/mock_api/shared/test_response_status_code_range.py delete mode 100644 packages/typespec-python/tests/mock_api/shared/test_routes.py delete mode 100644 packages/typespec-python/tests/mock_api/shared/test_server_endpoint_not_defined.py delete mode 100644 packages/typespec-python/tests/mock_api/shared/test_server_path_multiple.py delete mode 100644 packages/typespec-python/tests/mock_api/shared/test_server_path_single.py delete mode 100644 packages/typespec-python/tests/mock_api/shared/test_server_versions_not_versioned.py delete mode 100644 packages/typespec-python/tests/mock_api/shared/test_server_versions_versioned.py delete mode 100644 packages/typespec-python/tests/mock_api/shared/test_special_headers_conditional_request.py delete mode 100644 packages/typespec-python/tests/mock_api/shared/test_special_headers_repeatability.py delete mode 100644 packages/typespec-python/tests/mock_api/shared/test_specs_documentation.py delete mode 100644 packages/typespec-python/tests/mock_api/shared/test_streaming_jsonl.py delete mode 100644 packages/typespec-python/tests/mock_api/shared/test_typetest_array.py delete mode 100644 packages/typespec-python/tests/mock_api/shared/test_typetest_dictionary.py delete mode 100644 packages/typespec-python/tests/mock_api/shared/test_typetest_enum_extensible.py delete mode 100644 packages/typespec-python/tests/mock_api/shared/test_typetest_enum_fixed.py delete mode 100644 packages/typespec-python/tests/mock_api/shared/test_typetest_file.py delete mode 100644 packages/typespec-python/tests/mock_api/shared/test_typetest_model_empty.py delete mode 100644 packages/typespec-python/tests/mock_api/shared/test_typetest_model_inheritance_enum_discriminator.py delete mode 100644 packages/typespec-python/tests/mock_api/shared/test_typetest_model_inheritance_nested_discriminator.py delete mode 100644 packages/typespec-python/tests/mock_api/shared/test_typetest_model_inheritance_not_discriminated.py delete mode 100644 packages/typespec-python/tests/mock_api/shared/test_typetest_model_inheritance_recursive.py delete mode 100644 packages/typespec-python/tests/mock_api/shared/test_typetest_model_inheritance_single_discriminator.py delete mode 100644 packages/typespec-python/tests/mock_api/shared/test_typetest_model_usage.py delete mode 100644 packages/typespec-python/tests/mock_api/shared/test_typetest_model_visibility.py delete mode 100644 packages/typespec-python/tests/mock_api/shared/test_typetest_property_additionalproperties.py delete mode 100644 packages/typespec-python/tests/mock_api/shared/test_typetest_property_nullable.py delete mode 100644 packages/typespec-python/tests/mock_api/shared/test_typetest_property_optional.py delete mode 100644 packages/typespec-python/tests/mock_api/shared/test_typetest_property_valuetypes.py delete mode 100644 packages/typespec-python/tests/mock_api/shared/test_typetest_scalar.py delete mode 100644 packages/typespec-python/tests/mock_api/shared/test_typetest_union.py delete mode 100644 packages/typespec-python/tests/mock_api/shared/test_typetest_union_discriminated.py delete mode 100644 packages/typespec-python/tests/mock_api/shared/test_versioning_added.py delete mode 100644 packages/typespec-python/tests/mock_api/shared/test_versioning_made_optional.py delete mode 100644 packages/typespec-python/tests/mock_api/shared/test_versioning_removed.py delete mode 100644 packages/typespec-python/tests/mock_api/shared/test_versioning_renamed_from.py delete mode 100644 packages/typespec-python/tests/mock_api/shared/test_versioning_return_type_changed_from.py delete mode 100644 packages/typespec-python/tests/mock_api/shared/test_versioning_type_changed_from.py delete mode 100644 packages/typespec-python/tests/mock_api/shared/unittests/test_parse_pyproject.py delete mode 100644 packages/typespec-python/tests/mock_api/unbranded/asynctests/test_auth_flow_async.py delete mode 100644 packages/typespec-python/tests/mock_api/unbranded/asynctests/test_encode_duration_async.py delete mode 100644 packages/typespec-python/tests/mock_api/unbranded/asynctests/test_encode_numeric_async.py delete mode 100644 packages/typespec-python/tests/mock_api/unbranded/asynctests/test_parameters_basic_async.py delete mode 100644 packages/typespec-python/tests/mock_api/unbranded/asynctests/test_parameters_spread_async.py delete mode 100644 packages/typespec-python/tests/mock_api/unbranded/asynctests/test_payload_content_negotiation_async.py delete mode 100644 packages/typespec-python/tests/mock_api/unbranded/asynctests/test_payload_multipart_async.py delete mode 100644 packages/typespec-python/tests/mock_api/unbranded/asynctests/test_serialization_encoded_name_json_async.py delete mode 100644 packages/typespec-python/tests/mock_api/unbranded/asynctests/test_special_words_async.py delete mode 100644 packages/typespec-python/tests/mock_api/unbranded/asynctests/test_unbranded_async.py delete mode 100644 packages/typespec-python/tests/mock_api/unbranded/conftest.py delete mode 100644 packages/typespec-python/tests/mock_api/unbranded/data/image.jpg delete mode 100644 packages/typespec-python/tests/mock_api/unbranded/data/image.png delete mode 100644 packages/typespec-python/tests/mock_api/unbranded/test_auth_flow.py delete mode 100644 packages/typespec-python/tests/mock_api/unbranded/test_encode_duration.py delete mode 100644 packages/typespec-python/tests/mock_api/unbranded/test_encode_numeric.py delete mode 100644 packages/typespec-python/tests/mock_api/unbranded/test_parameters_basic.py delete mode 100644 packages/typespec-python/tests/mock_api/unbranded/test_parameters_spread.py delete mode 100644 packages/typespec-python/tests/mock_api/unbranded/test_payload_content_negotiation.py delete mode 100644 packages/typespec-python/tests/mock_api/unbranded/test_payload_multipart.py delete mode 100644 packages/typespec-python/tests/mock_api/unbranded/test_serialization_encoded_name_json.py delete mode 100644 packages/typespec-python/tests/mock_api/unbranded/test_special_words.py delete mode 100644 packages/typespec-python/tests/mock_api/unbranded/test_unbranded.py delete mode 100644 packages/typespec-python/tests/requirements/azure.txt delete mode 100644 packages/typespec-python/tests/requirements/base.txt delete mode 100644 packages/typespec-python/tests/requirements/docs.txt delete mode 100644 packages/typespec-python/tests/requirements/lint.txt delete mode 100644 packages/typespec-python/tests/requirements/typecheck.txt delete mode 100644 packages/typespec-python/tests/requirements/unbranded.txt delete mode 100644 packages/typespec-python/tests/tox.ini diff --git a/packages/typespec-python/.gitignore b/packages/typespec-python/.gitignore new file mode 100644 index 0000000000..bc2a2860ca --- /dev/null +++ b/packages/typespec-python/.gitignore @@ -0,0 +1,11 @@ +# Test asset directories that are populated at runtime by `pnpm sync` from the +# upstream http-client-python checkout (see eng/scripts/sync.ts INCLUDES). +# These are intentionally not committed; CI runs `pnpm sync` before running +# the Python test suites, and `prepack` runs sync before npm publish. +tests/data/ +tests/mock_api/ +tests/requirements/ +tests/conftest.py +tests/install_packages.py +tests/tox.ini +generator/ diff --git a/packages/typespec-python/eng/scripts/sync.ts b/packages/typespec-python/eng/scripts/sync.ts index 7e5d49ad0c..f0ad59a028 100644 --- a/packages/typespec-python/eng/scripts/sync.ts +++ b/packages/typespec-python/eng/scripts/sync.ts @@ -1,21 +1,25 @@ /* eslint-disable no-console */ /** - * Sync eng/scripts from the upstream http-client-python checkout (sibling - * `core/` repo) into this package's eng/scripts directory. + * Sync files from the upstream http-client-python checkout (sibling `core/` + * repo) into this package. * - * typespec-python is mostly a wrapper around http-client-python, so the build / - * setup / CI helper scripts under eng/ should be kept identical between the two - * packages. This script copies the files from /core/packages/ - * http-client-python/eng/scripts/ into this repo so we don't have to maintain - * duplicate copies by hand. If the core/ checkout isn't present the script - * exits with an informational message and does nothing. + * typespec-python is mostly a wrapper around http-client-python, so most of + * the build / setup / CI helper scripts and shared test assets should be kept + * identical between the two packages. This script copies the files (and + * directories) listed in INCLUDES from + * /core/packages/http-client-python/ + * into + * / + * so we don't have to maintain duplicate copies by hand. If the core/ checkout + * isn't present the script exits with an informational message and does + * nothing. * * Usage: * tsx eng/scripts/sync.ts # write mode: overwrite local files * tsx eng/scripts/sync.ts --check # check mode: exit non-zero on drift (CI) */ import fs from "fs"; -import { dirname, join, sep } from "path"; +import { dirname, join, relative, sep } from "path"; import pc from "picocolors"; import { fileURLToPath } from "url"; import { parseArgs } from "util"; @@ -23,61 +27,101 @@ import { parseArgs } from "util"; const here = dirname(fileURLToPath(import.meta.url)); // eng/scripts/sync.ts -> package root is two levels up const packageRoot = join(here, "..", ".."); -const destEngScripts = join(packageRoot, "eng", "scripts"); // Source lives in the sibling `core/` checkout at the repo root: -// /core/packages/http-client-python/eng/scripts +// /core/packages/http-client-python // packageRoot == /packages/typespec-python, so the repo root is two // levels up from packageRoot. const repoRoot = join(packageRoot, "..", ".."); -const sourceRoot = join( - repoRoot, - "core", - "packages", - "http-client-python", - "eng", - "scripts", -); +const sourceRoot = join(repoRoot, "core", "packages", "http-client-python"); /** - * Files (relative to eng/scripts, POSIX path) that should be synced from the - * upstream @typespec/http-client-python package. Anything not listed here is - * ignored — keeping this an allow-list makes it explicit which files this - * package is willing to inherit from upstream. + * Paths (POSIX, relative to the package root on both sides) that should be + * synced from the upstream @typespec/http-client-python package. + * + * - Entries ending in `/` are directories — every file underneath is copied + * recursively (additive: local-only files in the directory are NOT removed). + * - Other entries are individual files. + * + * Anything not listed here is ignored — keeping this an allow-list makes it + * explicit which files this package is willing to inherit from upstream. * * To pull in a new upstream file, add it here and run `pnpm sync`. */ const INCLUDES: readonly string[] = [ // Shared CI config - "ci/config/mypy.ini", - "ci/config/pylintrc", - "ci/config/pyrightconfig.json", + "eng/scripts/ci/config/mypy.ini", + "eng/scripts/ci/config/pylintrc", + "eng/scripts/ci/config/pyrightconfig.json", // Shared CI runners (invoked by run-tests.ts via tox) - "ci/run_apiview.py", - "ci/run_mypy.py", - "ci/run_pylint.py", - "ci/run_pyright.py", - "ci/run_sphinx_build.py", - "ci/util.py", + "eng/scripts/ci/run_apiview.py", + "eng/scripts/ci/run_mypy.py", + "eng/scripts/ci/run_pylint.py", + "eng/scripts/ci/run_pyright.py", + "eng/scripts/ci/run_sphinx_build.py", + "eng/scripts/ci/util.py", // Regeneration scripts (the local regenerate.ts is intentionally synced from // upstream; regenerate-common.ts is its shared helper module). - "ci/regenerate.ts", - "ci/regenerate-common.ts", + "eng/scripts/ci/regenerate.ts", + "eng/scripts/ci/regenerate-common.ts", // Shared setup scripts (invoked by package.json install/prepare hooks // and by ci/regenerate.ts which spawns run_batch.py). - "setup/install.py", - "setup/package_manager.py", - "setup/prepare.py", - "setup/run_batch.py", - "setup/run_tsp.py", - "setup/run-python3.ts", - "setup/system-requirements.ts", - "setup/venvtools.py", + "eng/scripts/setup/install.py", + "eng/scripts/setup/package_manager.py", + "eng/scripts/setup/prepare.py", + "eng/scripts/setup/run_batch.py", + "eng/scripts/setup/run_tsp.py", + "eng/scripts/setup/run-python3.ts", + "eng/scripts/setup/system-requirements.ts", + "eng/scripts/setup/venvtools.py", + + // Shared test assets. Directory entries (trailing `/`) are recursive and + // **mirror** the upstream layout: files matching upstream are overwritten, + // and local-only files are deleted. The matching directories are + // .gitignored in this package so a fresh CI checkout starts empty and is + // fully populated by `pnpm sync`. Upstream tests are treated as the source + // of truth; any wrapper-specific test must live OUTSIDE these directories + // (e.g. tests/wrapper/) so it isn't pruned by the sync. + "tests/data/", + "tests/mock_api/", + "tests/requirements/", + + // Test driver/helper files at the tests/ root. Each is treated as the + // upstream source of truth — DATA_FOLDER, server-launch logic, lint/test + // tox envs, wheel install algorithms etc. all stay aligned with + // http-client-python. + "tests/conftest.py", + "tests/install_packages.py", + "tests/tox.ini", + + // The pygen Python package. Mirrored from upstream because the tox envs + // (`-e {tox_root}/../generator`) and PYTHONPATH expect this directory to + // exist. Gitignored locally; `pnpm sync` populates it before tests/builds + // and `prepack` runs sync so npm publish still includes it. + "generator/", ]; +/** + * Directory/file names to skip when walking INCLUDES directory entries. Any + * path that has a segment matching one of these names is ignored on both + * sides: not copied from source, and not pruned in dest. This is how we keep + * build artifacts (egg-info, __pycache__, build/, dist/) from polluting the + * sync. + */ +const EXCLUDED_SEGMENTS: ReadonlySet = new Set([ + "__pycache__", + "build", + "dist", + "pygen.egg-info", + ".pytest_cache", + ".mypy_cache", + ".tox", + ".wheels", +]); + const argv = parseArgs({ args: process.argv.slice(2), options: { @@ -91,11 +135,12 @@ if (argv.values.help) { ${pc.bold("Usage:")} tsx eng/scripts/sync.ts [options] ${pc.bold("Description:")} - Copy the files listed in INCLUDES from - /core/packages/http-client-python/eng/scripts/ into this package's - eng/scripts/. Anything not in INCLUDES is left untouched. If the core/ - checkout is not present, the script exits with an informational message and - does nothing. + Copy the files (and recursive directories) listed in INCLUDES from + /core/packages/http-client-python/ into this package, preserving + the same path on both sides. Anything not in INCLUDES is left untouched. + Directory entries are additive — local-only files are not deleted. If the + core/ checkout is not present, the script exits with an informational + message and does nothing. ${pc.bold("Options:")} ${pc.cyan("-c, --check")} Compare only; exit non-zero on any drift (for CI). @@ -123,6 +168,7 @@ interface SyncStats { unchanged: string[]; drifted: string[]; // only populated in --check mode missing: string[]; // listed in INCLUDES but not present in the source package + removed: string[]; // local-only files inside a synced directory (mirror) } function syncFile(srcAbs: string, destAbs: string, relPath: string, stats: SyncStats): void { @@ -144,6 +190,41 @@ function syncFile(srcAbs: string, destAbs: string, relPath: string, stats: SyncS stats.copied.push(relPath); } +function listFilesRecursive(dir: string): string[] { + if (!fs.existsSync(dir)) return []; + const out: string[] = []; + const stack: string[] = [dir]; + while (stack.length) { + const cur = stack.pop()!; + for (const dirent of fs.readdirSync(cur, { withFileTypes: true })) { + if (EXCLUDED_SEGMENTS.has(dirent.name)) continue; + const child = join(cur, dirent.name); + if (dirent.isDirectory()) { + stack.push(child); + } else if (dirent.isFile()) { + out.push(child); + } + } + } + return out; +} + +function removeEmptyDirsUpTo(startDir: string, stopDir: string): void { + let cur = startDir; + while (cur.startsWith(stopDir) && cur !== stopDir) { + try { + if (fs.readdirSync(cur).length === 0) { + fs.rmdirSync(cur); + } else { + return; + } + } catch { + return; + } + cur = dirname(cur); + } +} + function main(): void { if (!fs.existsSync(sourceRoot)) { console.log( @@ -157,26 +238,69 @@ function main(): void { } console.log(pc.bold("Source:") + " " + sourceRoot); - console.log(pc.bold("Destination:") + " " + destEngScripts); + console.log(pc.bold("Destination:") + " " + packageRoot); console.log(pc.bold("Mode:") + " " + (check ? "check (read-only)" : "write")); console.log(""); - const stats: SyncStats = { copied: [], unchanged: [], drifted: [], missing: [] }; + const stats: SyncStats = { copied: [], unchanged: [], drifted: [], missing: [], removed: [] }; - for (const rel of INCLUDES) { + for (const entry of INCLUDES) { + const isDir = entry.endsWith("/"); + const rel = isDir ? entry.slice(0, -1) : entry; const srcAbs = join(sourceRoot, ...rel.split("/")); + if (!fs.existsSync(srcAbs)) { - stats.missing.push(rel); + stats.missing.push(entry); continue; } - const destAbs = join(destEngScripts, ...rel.split("/")); - syncFile(srcAbs, destAbs, toPosix(rel), stats); + + if (isDir) { + // Mirror the source directory: copy everything underneath, AND delete + // any local-only files so the destination becomes a faithful copy of + // the source. These directories are .gitignored, so deletions never + // touch tracked files. + const destDirAbs = join(packageRoot, ...rel.split("/")); + const sourceFiles = listFilesRecursive(srcAbs); + const sourceRelSet = new Set( + sourceFiles.map((f) => toPosix(relative(srcAbs, f))), + ); + + // Step 1: copy source -> dest + for (const srcFile of sourceFiles) { + const relFromDir = toPosix(relative(srcAbs, srcFile)); + const destAbs = join(destDirAbs, ...relFromDir.split("/")); + const relFromPkg = toPosix(relative(packageRoot, destAbs)); + syncFile(srcFile, destAbs, relFromPkg, stats); + } + + // Step 2: prune local-only files + const destFiles = listFilesRecursive(destDirAbs); + for (const destFile of destFiles) { + const relFromDir = toPosix(relative(destDirAbs, destFile)); + if (sourceRelSet.has(relFromDir)) continue; + const relFromPkg = toPosix(relative(packageRoot, destFile)); + if (check) { + stats.drifted.push(relFromPkg + " (local-only)"); + } else { + fs.unlinkSync(destFile); + removeEmptyDirsUpTo(dirname(destFile), destDirAbs); + stats.removed.push(relFromPkg); + } + } + } else { + const destAbs = join(packageRoot, ...rel.split("/")); + syncFile(srcAbs, destAbs, toPosix(rel), stats); + } } if (stats.copied.length) { console.log(pc.green(pc.bold(`Copied (${stats.copied.length}):`))); for (const f of stats.copied) console.log(" " + f); } + if (stats.removed.length) { + console.log(pc.magenta(pc.bold(`Removed local-only (${stats.removed.length}):`))); + for (const f of stats.removed) console.log(" " + f); + } if (stats.drifted.length) { console.log(pc.red(pc.bold(`Drifted (${stats.drifted.length}):`))); for (const f of stats.drifted) console.log(" " + f); @@ -190,7 +314,7 @@ function main(): void { if (check && (stats.drifted.length > 0 || stats.missing.length > 0)) { console.error( pc.red( - `\neng/scripts has drifted from core/packages/http-client-python.\n` + + `\nSynced files have drifted from core/packages/http-client-python.\n` + `Run 'pnpm sync' (or 'tsx eng/scripts/sync.ts') and commit the result.`, ), ); diff --git a/packages/typespec-python/package.json b/packages/typespec-python/package.json index 93d73eac70..4bbe4c7477 100644 --- a/packages/typespec-python/package.json +++ b/packages/typespec-python/package.json @@ -40,6 +40,7 @@ "regenerate": "tsx ./eng/scripts/ci/regenerate.ts --emitterName @azure-tools/typespec-python --generatedFolder ./generator", "sync": "tsx ./eng/scripts/sync.ts", "sync:check": "tsx ./eng/scripts/sync.ts --check", + "prepack": "tsx ./eng/scripts/sync.ts", "test:python:e2e": "tsx ./eng/scripts/ci/run-tests.ts", "regen-docs": "pnpm run build && tspd doc . --enable-experimental --output-dir ./website/src/content/docs/docs/emitters/clients/typespec-python/reference --skip-js" }, diff --git a/packages/typespec-python/tests/conftest.py b/packages/typespec-python/tests/conftest.py deleted file mode 100644 index 2779f7b673..0000000000 --- a/packages/typespec-python/tests/conftest.py +++ /dev/null @@ -1,223 +0,0 @@ -# ------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for -# license information. -# -------------------------------------------------------------------------- -import os -import subprocess -import signal -import time -import urllib.request -import urllib.error -import tempfile -import pytest -import importlib -from pathlib import Path -from filelock import FileLock - -# Root of the typespec-python package -ROOT = Path(__file__).parent.parent -DATA_FOLDER = Path(__file__).parent / "data" - -# Server configuration -SERVER_HOST = "localhost" -SERVER_PORT = 3000 -SERVER_URL = f"http://{SERVER_HOST}:{SERVER_PORT}" - -# Lock file for coordinating server startup across xdist workers -LOCK_FILE = Path(tempfile.gettempdir()) / "typespec_python_test_server.lock" -PID_FILE = Path(tempfile.gettempdir()) / "typespec_python_test_server.pid" - -# Global server process reference (used by hooks) -_server_process = None -_owns_server = False # Track if this process started the server - - -def wait_for_server(url: str, timeout: int = 60, interval: float = 0.5) -> bool: - """Wait for the server to be ready by polling the URL.""" - start_time = time.time() - while time.time() - start_time < timeout: - try: - urllib.request.urlopen(url, timeout=1) - return True - except urllib.error.HTTPError: - # Server is up but returned an error (e.g., 404) - that's fine - return True - except (urllib.error.URLError, OSError): - # Server not reachable yet - time.sleep(interval) - return False - - -def start_server_process(): - """Start the tsp-spector mock API server.""" - azure_http_path = ROOT / "node_modules/@azure-tools/azure-http-specs" - http_path = ROOT / "node_modules/@typespec/http-specs" - - # Determine flavor from environment or current directory - flavor = os.environ.get("FLAVOR", "azure") - - # Use absolute paths with forward slashes (works on all platforms including Windows) - if flavor == "unbranded": - cwd = http_path.resolve() - specs_path = str(cwd / "specs").replace("\\", "/") - cmd = f"npx tsp-spector serve {specs_path}" - else: - cwd = azure_http_path.resolve() - azure_specs = str(cwd / "specs").replace("\\", "/") - http_specs = str((http_path / "specs").resolve()).replace("\\", "/") - cmd = f"npx tsp-spector serve {azure_specs} {http_specs}" - - # Add node_modules/.bin to PATH - env = os.environ.copy() - node_bin = str(ROOT / "node_modules" / ".bin") - env["PATH"] = f"{node_bin}{os.pathsep}{env.get('PATH', '')}" - - if os.name == "nt": - return subprocess.Popen(cmd, shell=True, cwd=str(cwd), env=env) - return subprocess.Popen(cmd, shell=True, cwd=str(cwd), env=env, preexec_fn=os.setsid) - - -def terminate_server_process(process): - """Terminate the mock API server process.""" - if process is None: - return - try: - if os.name == "nt": - # On Windows, use taskkill to kill the entire process tree - # process.kill() only kills the shell, not the child node process - subprocess.run( - ["taskkill", "/F", "/T", "/PID", str(process.pid)], - capture_output=True, - check=False, - ) - else: - os.killpg(os.getpgid(process.pid), signal.SIGTERM) - except ProcessLookupError: - pass # Process already terminated - except Exception: - # Fallback: try basic kill - try: - process.kill() - except Exception: - pass - - -def pytest_configure(config): - """Start the mock server before any tests run. - - Uses file locking to ensure only one process starts the server, - even when running with pytest-xdist. The controller process starts - the server and workers wait for it to be ready. - """ - global _server_process, _owns_server - - # Check if server is already running (e.g., from a previous run or external process) - if wait_for_server(SERVER_URL, timeout=1, interval=0.1): - print(f"Mock API server already running at {SERVER_URL}") - return - - # Use file lock to ensure only one process starts the server - # This handles both xdist workers and multiple test runs - lock = FileLock(str(LOCK_FILE), timeout=120) - - try: - with lock: - # Double-check after acquiring lock (another process may have started it) - if wait_for_server(SERVER_URL, timeout=1, interval=0.1): - print(f"Mock API server already running at {SERVER_URL}") - return - - # We're the first process - start the server - print(f"Starting mock API server...") - _server_process = start_server_process() - _owns_server = True - - # Check if process started successfully - if _server_process.poll() is not None: - pytest.exit(f"Mock API server process exited immediately with code {_server_process.returncode}") - - # Write PID file so other processes know who owns the server - PID_FILE.write_text(str(_server_process.pid)) - - # Wait for server to be ready - if not wait_for_server(SERVER_URL, timeout=60): - if _server_process.poll() is not None: - pytest.exit(f"Mock API server process died with code {_server_process.returncode}") - terminate_server_process(_server_process) - _server_process = None - _owns_server = False - pytest.exit(f"Mock API server failed to start within 60 seconds at {SERVER_URL}") - - print(f"Mock API server ready at {SERVER_URL}") - - except TimeoutError: - # Another process is holding the lock for too long - # Check if server is available anyway - if wait_for_server(SERVER_URL, timeout=5): - print(f"Mock API server available at {SERVER_URL} (started by another process)") - else: - pytest.exit("Timeout waiting for server lock - another process may be stuck") - - -def pytest_unconfigure(config): - """Stop the mock server after all tests complete.""" - global _server_process, _owns_server - - # Only stop the server if this process started it - if not _owns_server: - return - - terminate_server_process(_server_process) - _server_process = None - _owns_server = False - - # Clean up PID file - try: - PID_FILE.unlink(missing_ok=True) - except Exception: - pass - - -@pytest.fixture(scope="session", autouse=True) -def testserver(request): - """Ensure the mock server is ready before tests run. - - The server is started in pytest_configure (controller process). - This fixture just verifies the server is accessible from workers. - """ - if not wait_for_server(SERVER_URL, timeout=30): - pytest.fail(f"Mock API server not available at {SERVER_URL}") - yield - - -@pytest.fixture -def core_library(): - """Import the appropriate core library (azure.core or corehttp).""" - try: - return importlib.import_module("azure.core") - except ModuleNotFoundError: - return importlib.import_module("corehttp") - - -@pytest.fixture -def key_credential(core_library): - """Get the appropriate credential class.""" - try: - return core_library.credentials.AzureKeyCredential - except AttributeError: - return core_library.credentials.ServiceKeyCredential - - -@pytest.fixture -def png_data() -> bytes: - """Load PNG test data.""" - with open(str(DATA_FOLDER / "image.png"), "rb") as file_in: - return file_in.read() - - -@pytest.fixture -def jpg_data() -> bytes: - """Load JPG test data.""" - with open(str(DATA_FOLDER / "image.jpg"), "rb") as file_in: - return file_in.read() diff --git a/packages/typespec-python/tests/data/image.jpg b/packages/typespec-python/tests/data/image.jpg deleted file mode 100644 index b95b3e7b58286ad3e665d98d48b345977f862403..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4069 zcmeHJX;@QN8a_8Gn*#{~QJ4uNv1G6$BrHN6AVrn}mbL^3a4V7!OhA&51QRm!5kx@+ zTNcGZ6cC$Q+;~`GASla}wUxz{#c@GKXr)k4Y@<*!Hx%*D{OB`(hxgoj&v(xGzVDv* zyZ1cLYZx{>23FxAVIcs504RVPFpPlD9#xbBu1V2)YXM|gXB#0R#?0;vho@Ai`n{4K2Z_tc-vVNE8}_H8C|ahaEIl00AM92ow^HM!{MR`W#*d zC>$E^#0bDxN5*4GscV^8g=bC3n`_%`I5%f0?p)~sQ!`sT!n*Yv-gBn@)y2cpYm>JR zD=;WH4t_4#kAFVxjHXs&7-n{@yDwxhGFyQlZNTet7ry*D&GGCKBT{NGO}CV%+x+1&FN z^Dlq-RsZU>kryl_f2RdM|0^#X%nN}+AyHT(F9@M9633y?P7Dk_AQBs&YE5EhnXKJh zc(%6PlpPs~<`z2kKs1OmhoPzVGH-Zu)3MZ>_F zVvR60H(i4HGS)1?$_V@l3~&{b9rK09ND}!zi#oLh#Ro!~r%~ ztf@M>v0>6|AHFNXRdW{F2PwyE*zd{a+%36uhi4yu9aJ^ zpE7`9t8Rioz2KlN=S`ybbp-7ElQg->VN&I!l@n$S;9H_)yZXl$&PTX9ZObWvjhcE$f>gQt?~wSk)wt*@QfJ9e zFelD#>m0AB_sUj(c%Hr(E_yV;phB&=i9g9-)lO~OzQ2==_`u&bT{~<52lxK#Ow_NO zH{&-1-x&aQ;LQ0M(Zy$<1nTsq)xvVR{*&=ztX;IOz6|@z-F$Uf=(W0nyex6{P>FpW z4;0_dipualIew@$bH3M?aaJh~zSVba_s(ZYwY`7uX0rQ=C{sn1g*}wrL&Zt0cwal& z|(+)A&#XhLRoSPH3mt4Ji?-$~1F~yma)AnXu zRaaV$2SjEq$b{PVCY+v+iL;w8BOWVxgqdDst2gCLzog0=vM#q5L^ScNF_ipEjeb6n z1J0h4Y=S>iPa2P#Wgqq@^xWzm>-n^78z*$sXAucKo}EO|0uu3 zLs)^AUypvJF<+QUj|p5L&+NFzk0eJN%fi)?Gy8fd4jBz;gBAkjn_MPYks`G3a33&nP_o zg=l|nT>VF<@}|PZtIypU-TXbb#NA#UwTKA877jAo-sRoA;|O7M!oq~_ndaKA)cm{QH_jPuzCA+J zs!aHNWSYHBYfaj3>w14Gdb?$=t7cDh+;r%rP@Vlr;qGatS1nE0#?Fk+V2@G6gWq0G nRDbTJ{wDPH&YhvRw~$ZQH=nuD@w!Nwq+ZJbRY$2v!^nRCgjEVM diff --git a/packages/typespec-python/tests/data/image.png b/packages/typespec-python/tests/data/image.png deleted file mode 100644 index 42fe8dc14560b0046bf0f3f00b7a471fa0346e36..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2992 zcmaJ>2UJtr5=}ynfPe^6#i)oP2~A3b_#j9P<c=;9z@urf$wEd&r0Smmc~ z4b}n)eX~PAprkO6@Q)ZL0M}MJAZwiOD16}zNDSD?0g_k*{=o$NMUbCNY?07U9S+2S zEZop`b^yBJDZ#-+YAA`O;C(9uFi4PXy{I6N!uB-*+qrI=1#0z#xnpTqM+_2ABESQJ zNP)p{I)S{F2V_P^0xBVx7N9{V941ncbaU9Z2qd7dnGrCJZy~e@a~RgqMFUNu1Zx<< zb>X@&6jVb)!;BJi2rs64KWLg-BsIiteAdnPEGl#*}3jJK)-!qsV_Nx++`r}x@ z0TF8+gdSWM@iR9-HCwYHUBc+WhrO)A2tdz(8Yn{}vv1-5tZHzM{I(Zu9;;%|=s zCVEhVDQFS_C`d#7x~w1M-<>~*W{9LqLSH=UG`#0SvISvT&z^Cv#7@xJSx2aa-|9tm}-z6Hc>u#KDm+I4F>M3G9RmW+_?M2)1;gWo3xcVR@W8PHPH4h8*{++h z8}Y5F9`(=WPeZXH<+|Y0gJnwP5YL?0zo!3|^aN{T{s{OKE?O45QM0I0;1yDN`SND{ zyOg5mp)N5c(u0Esp-E=kfllR0C&k1s@i0GrZRfs5<7!+x0s^%ugM8%*ef;#PiEVR~ zk~180fRXw!|2qMhFy2QQNA)X#rKKLKFql@YS0DB+8Y~M0L6l6MBxAd5adGjcF9c8t zo3^yHG!i%{(t~?+_KjG%t?wg9W@hGn@>d^2zlX4eDsq69+{GOYhow*ZZ9YFY+;qgj z#AWZ^z2xho`YaYJ$mptuez>fhT&9eIf;49^mEC)&XN9ajcTsqPhD7C%d`TOUID=@6 zW~%vaGf31w{D~F5LO*H9Ul5b;M$_L~@5Rf{$YXmij@GSqZ($ztNsv;Z`i@;wgI)yL z`tVD3-D4YatT^h!2`{f7xgFBk(KVv6D=iyOe>q)Zxtu3f1vhZeoRRfQZ3s>DQ~|{c zhLZ7j^pqm{@Kbe|+)KiSAs)dZlW4Rb|0>x!mf7eaT?yRGZFm;h)5lP}0s z)MR+lRu=;7XofSxFZS5kB(Io?U<4$)=j+Ujv-f1z7}jT(U8oBF@c2?YjHZlX3}y?2 zB}I!j)%5LcxOt457x{YKwWQLqjkl*P!m*TD-H`cTuN{_G`e(Occ-dLa=;vA%@*AOg(a(z}6t_crT&EO-&+m4gF>N0h;BXG0?{Bi7 z`CMs0?IQEIN_yrvkTId}4tcQlLFDsm2){A5T)eb!$m;U*9bpNnS{u9Nur=c6{IY zKC28T*@~?E=+fvG1A<0jF;cm0Q(bSl;8d`tTUme#<>4g zLGy3~(+z4auzTu_$wj7=5_bmr4M3i>XprZ8-8A{ z^S%T(i(@^t7G<(wYTc~P^uFuDm}iOCg0RJbylL{6l)E9&xd*ipG|e`)b?b`n)|`3$ z>k`idS@_lp+*>nk7_W2qvLHrYsnN9VjcdkaYxRqWdf5!mZ8vsD^2e%lG>7`oaP1~( z91eF(@?7&4^jE^(0w>-(Xig#TL8J;KX+2YL&fdmGjCA1!I<+uYch0=ri`kM?G=Uz= zYe(%m$g6gpfYRA}M3Wh=PjV`BA|f`Ajz1QY-KfS$+mLC&=*M@CqU0@-843#@s!tp+ z`hXG_$T+w$%ZRc;oA!hozBo{U_AgR)cc2=ist%Tf1!goyZ`H}XSr9&UY zJ^9hCDY9E_U|L$j^3{t+O$rDP^WqxkQ)&F;Eh@Hsx^<};S#~>%t}R_YRkG7OjOT7s&BTd5F;H{&a{d!BS5Vz@RgwkT{dwhcQ zPGno6OlTdu0KU{d<)>5lyi9d5Rz$1ros^mpW_coXd{r;;5w~?!YUHbE$=hL2`F`si x55d?S>E1-idha0G3zgVNNXgr$|KG8qZJn`L2pQ~%2Sy6WZoiY&ZA<_7e*r@k8!Z3; diff --git a/packages/typespec-python/tests/install_packages.py b/packages/typespec-python/tests/install_packages.py deleted file mode 100644 index eea588ffb5..0000000000 --- a/packages/typespec-python/tests/install_packages.py +++ /dev/null @@ -1,145 +0,0 @@ -#!/usr/bin/env python -"""Install generated packages for testing. - -Supports two modes: -1. Build wheels from source dirs into a wheel directory (build command) -2. Install from pre-built wheels via --find-links (instant, no compilation) - -The build step runs once before tox envs start. Each tox env then installs -from pre-built wheels, avoiding redundant source builds across environments. -""" - -import glob -import os -import subprocess -import sys - - -def _find_packages(generated_dir): - """Find all package directories that have pyproject.toml or setup.py.""" - all_dirs = glob.glob(os.path.join(generated_dir, "*")) - return sorted([ - p for p in all_dirs - if os.path.isdir(p) and ( - os.path.exists(os.path.join(p, "pyproject.toml")) or - os.path.exists(os.path.join(p, "setup.py")) - ) - ]) - - -def build_wheels(flavor, tests_dir): - """Build wheels for all packages into a shared directory.""" - generated_dir = os.path.join(tests_dir, "generated", flavor) - wheel_dir = os.path.join(tests_dir, ".wheels", flavor) - os.makedirs(wheel_dir, exist_ok=True) - - packages = _find_packages(generated_dir) - if not packages: - print(f"Warning: No packages found in {generated_dir}") - return - - print(f"Building {len(packages)} wheels for {flavor}...") - - failed = [] - for pkg in packages: - try: - subprocess.run( - ["uv", "build", "--wheel", "--no-build-logs", "--out-dir", wheel_dir, pkg], - check=True, - capture_output=True, - ) - except subprocess.CalledProcessError: - pkg_name = os.path.basename(pkg) - print(f"Warning: Failed to build wheel for {pkg_name}, will install from source") - failed.append(pkg) - - wheel_count = len(glob.glob(os.path.join(wheel_dir, "*.whl"))) - print(f"Built {wheel_count}/{len(packages)} wheels for {flavor}") - if failed: - print(f" Skipped {len(failed)}: {', '.join(os.path.basename(p) for p in failed)}") - - -def install_packages(flavor, tests_dir): - """Install generated packages for the given flavor.""" - generated_dir = os.path.join(tests_dir, "generated", flavor) - wheel_dir = os.path.join(tests_dir, ".wheels", flavor) - - if not os.path.exists(generated_dir): - print(f"Warning: Generated directory does not exist: {generated_dir}") - return - - packages = _find_packages(generated_dir) - if not packages: - print(f"Warning: No packages found in {generated_dir}") - return - - print(f"Installing {len(packages)} packages from {generated_dir}") - - use_wheels = os.path.isdir(wheel_dir) and bool(glob.glob(os.path.join(wheel_dir, "*.whl"))) - use_uv = True - - if use_wheels: - wheel_files = glob.glob(os.path.join(wheel_dir, "*.whl")) - print(f" Using {len(wheel_files)} pre-built wheels from .wheels/{flavor}/") - try: - cmd = ["uv", "pip", "install", "--no-deps", "--no-index", - "--find-links", wheel_dir, "--python", sys.executable] + wheel_files - subprocess.run(cmd, check=True) - print(f"Successfully installed {len(wheel_files)} packages") - return - except FileNotFoundError: - use_uv = False - try: - cmd = [sys.executable, "-m", "pip", "install", "--no-deps", - "--no-index", "--find-links", wheel_dir] + wheel_files - subprocess.run(cmd, check=True) - print(f"Successfully installed {len(wheel_files)} packages") - return - except subprocess.CalledProcessError: - print(" Wheel install failed, falling back to source install") - except subprocess.CalledProcessError: - print(" Wheel install failed, falling back to source install") - - # Fall back to source install - if use_uv: - cmd = ["uv", "pip", "install", "--no-deps", "--python", sys.executable] + packages - else: - cmd = [sys.executable, "-m", "pip", "install", "--no-deps"] + packages - - try: - subprocess.run(cmd, check=True) - print(f"Successfully installed {len(packages)} packages") - except subprocess.CalledProcessError as e: - print(f"Error installing packages: {e}") - sys.exit(1) - except FileNotFoundError: - if use_uv: - print("uv not found, falling back to pip") - cmd = [sys.executable, "-m", "pip", "install", "--no-deps"] + packages - subprocess.run(cmd, check=True) - - -def main(): - if len(sys.argv) < 2: - print("Usage: install_packages.py [tests_dir]") - print(" install_packages.py build [tests_dir]") - sys.exit(1) - - if sys.argv[1] == "build": - if len(sys.argv) < 3: - print("Usage: install_packages.py build [tests_dir]") - sys.exit(1) - flavor = sys.argv[2] - tests_dir = sys.argv[3] if len(sys.argv) > 3 else os.path.dirname(os.path.abspath(__file__)) - build_wheels(flavor, tests_dir) - elif sys.argv[1] in ("azure", "unbranded"): - flavor = sys.argv[1] - tests_dir = sys.argv[2] if len(sys.argv) > 2 else os.path.dirname(os.path.abspath(__file__)) - install_packages(flavor, tests_dir) - else: - print(f"Error: Unknown command or flavor '{sys.argv[1]}'") - sys.exit(1) - - -if __name__ == "__main__": - main() diff --git a/packages/typespec-python/tests/mock_api/azure/asynctests/test_azure_arm_commonproperties_async.py b/packages/typespec-python/tests/mock_api/azure/asynctests/test_azure_arm_commonproperties_async.py deleted file mode 100644 index f5a62b6a86..0000000000 --- a/packages/typespec-python/tests/mock_api/azure/asynctests/test_azure_arm_commonproperties_async.py +++ /dev/null @@ -1,94 +0,0 @@ -# ------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for -# license information. -# -------------------------------------------------------------------------- -import pytest -from azure.resourcemanager.commonproperties.aio import CommonPropertiesClient -from azure.resourcemanager.commonproperties import models -from azure.core import exceptions - -SUBSCRIPTION_ID = "00000000-0000-0000-0000-000000000000" -RESOURCE_GROUP_NAME = "test-rg" - - -@pytest.fixture -async def client(credential, authentication_policy): - async with CommonPropertiesClient( - credential, SUBSCRIPTION_ID, "http://localhost:3000", authentication_policy=authentication_policy - ) as client: - yield client - - -@pytest.mark.asyncio -async def test_managed_identity_get(client): - result = await client.managed_identity.get( - resource_group_name=RESOURCE_GROUP_NAME, managed_identity_tracked_resource_name="identity" - ) - assert result.location == "eastus" - assert result.identity.type == "SystemAssigned" - assert result.properties.provisioning_state == "Succeeded" - - -@pytest.mark.asyncio -async def test_managed_identity_create_with_system_assigned(client): - result = await client.managed_identity.create_with_system_assigned( - resource_group_name=RESOURCE_GROUP_NAME, - managed_identity_tracked_resource_name="identity", - resource=models.ManagedIdentityTrackedResource( - location="eastus", identity=models.ManagedServiceIdentity(type="SystemAssigned") - ), - ) - assert result.location == "eastus" - assert result.identity.type == "SystemAssigned" - assert result.properties.provisioning_state == "Succeeded" - - -@pytest.mark.asyncio -async def test_managed_identity_update_with_user_assigned_and_system_assigned(client): - result = await client.managed_identity.update_with_user_assigned_and_system_assigned( - resource_group_name=RESOURCE_GROUP_NAME, - managed_identity_tracked_resource_name="identity", - properties=models.ManagedIdentityTrackedResource( - location="eastus", - identity=models.ManagedServiceIdentity( - type="SystemAssigned,UserAssigned", - user_assigned_identities={ - "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/test-rg/providers/Microsoft.ManagedIdentity/userAssignedIdentities/id1": models.UserAssignedIdentity() - }, - ), - ), - ) - assert result.location == "eastus" - assert result.identity.type == "SystemAssigned,UserAssigned" - assert result.properties.provisioning_state == "Succeeded" - - -@pytest.mark.asyncio -async def test_error_get_for_predefined_error(client): - try: - await client.error.get_for_predefined_error( - resource_group_name=RESOURCE_GROUP_NAME, - confidential_resource_name="confidential", - ) - except exceptions.ResourceNotFoundError as e: - assert e.status_code == 404 - assert ( - e.error.message - == "The Resource 'Azure.ResourceManager.CommonProperties/confidentialResources/confidential' under resource group 'test-rg' was not found." - ) - - -@pytest.mark.asyncio -async def test_error_create_for_user_defined_error(client): - try: - await client.error.create_for_user_defined_error( - resource_group_name=RESOURCE_GROUP_NAME, - confidential_resource_name="confidential", - resource=models.ConfidentialResource( - location="eastus", properties=models.ConfidentialResourceProperties(username="00") - ), - ) - except exceptions.HttpResponseError as e: - assert e.status_code == 400 - assert e.error.message == "Username should not contain only numbers." diff --git a/packages/typespec-python/tests/mock_api/azure/asynctests/test_azure_arm_largeheader_async.py b/packages/typespec-python/tests/mock_api/azure/asynctests/test_azure_arm_largeheader_async.py deleted file mode 100644 index deac2360db..0000000000 --- a/packages/typespec-python/tests/mock_api/azure/asynctests/test_azure_arm_largeheader_async.py +++ /dev/null @@ -1,30 +0,0 @@ -# ------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for -# license information. -# -------------------------------------------------------------------------- -import pytest -from azure.resourcemanager.largeheader.aio import LargeHeaderClient -from azure.resourcemanager.largeheader import models - -SUBSCRIPTION_ID = "00000000-0000-0000-0000-000000000000" -RESOURCE_GROUP_NAME = "test-rg" - - -@pytest.fixture -async def client(credential, authentication_policy): - async with LargeHeaderClient( - credential, SUBSCRIPTION_ID, "http://localhost:3000", authentication_policy=authentication_policy - ) as client: - yield client - - -@pytest.mark.asyncio -async def test_large_headers_begin_two6_k(client: LargeHeaderClient): - result = await ( - await client.large_headers.begin_two6_k( - resource_group_name=RESOURCE_GROUP_NAME, - large_header_name="header1", - ) - ).result() - assert result == models.CancelResult(succeeded=True) diff --git a/packages/typespec-python/tests/mock_api/azure/asynctests/test_azure_arm_nonresource_async.py b/packages/typespec-python/tests/mock_api/azure/asynctests/test_azure_arm_nonresource_async.py deleted file mode 100644 index 7cbbc763f3..0000000000 --- a/packages/typespec-python/tests/mock_api/azure/asynctests/test_azure_arm_nonresource_async.py +++ /dev/null @@ -1,36 +0,0 @@ -# ------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for -# license information. -# -------------------------------------------------------------------------- -import pytest -from azure.resourcemanager.nonresource.aio import NonResourceClient -from azure.resourcemanager.nonresource import models - -SUBSCRIPTION_ID = "00000000-0000-0000-0000-000000000000" -RESOURCE_GROUP_NAME = "test-rg" - - -@pytest.fixture -async def client(credential, authentication_policy): - async with NonResourceClient( - credential, SUBSCRIPTION_ID, "http://localhost:3000", authentication_policy=authentication_policy - ) as client: - yield client - - -@pytest.mark.asyncio -async def test_non_resource_create(client: NonResourceClient): - result = await client.non_resource_operations.create( - location="eastus", parameter="hello", body=models.NonResource(id="id", name="hello", type="nonResource") - ) - assert result == models.NonResource(id="id", name="hello", type="nonResource") - - -@pytest.mark.asyncio -async def test_non_resource_get(client: NonResourceClient): - result = await client.non_resource_operations.get( - location="eastus", - parameter="hello", - ) - assert result == models.NonResource(id="id", name="hello", type="nonResource") diff --git a/packages/typespec-python/tests/mock_api/azure/asynctests/test_azure_arm_operationtemplates_async.py b/packages/typespec-python/tests/mock_api/azure/asynctests/test_azure_arm_operationtemplates_async.py deleted file mode 100644 index 2c1bc0fc4b..0000000000 --- a/packages/typespec-python/tests/mock_api/azure/asynctests/test_azure_arm_operationtemplates_async.py +++ /dev/null @@ -1,205 +0,0 @@ -# ------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for -# license information. -# -------------------------------------------------------------------------- -import pytest -from azure.resourcemanager.operationtemplates.aio import OperationTemplatesClient -from azure.resourcemanager.operationtemplates import models - -SUBSCRIPTION_ID = "00000000-0000-0000-0000-000000000000" -RESOURCE_GROUP_NAME = "test-rg" - - -@pytest.fixture -async def client(credential, authentication_policy): - async with OperationTemplatesClient( - credential, - SUBSCRIPTION_ID, - "http://localhost:3000", - authentication_policy=authentication_policy, - polling_interval=0, - ) as client: - yield client - - -@pytest.mark.asyncio -async def test_check_name_availability_check_global(client): - result = await client.check_name_availability.check_global( - body=models.CheckNameAvailabilityRequest(name="checkName", type="Microsoft.Web/site") - ) - assert result.name_available == False - assert result.reason == models.CheckNameAvailabilityReason.ALREADY_EXISTS - assert result.message == "Hostname 'checkName' already exists. Please select a different name." - - -@pytest.mark.asyncio -async def test_check_name_availability_check_local(client): - result = await client.check_name_availability.check_local( - location="westus", - body=models.CheckNameAvailabilityRequest(name="checkName", type="Microsoft.Web/site"), - ) - assert result.name_available == False - assert result.reason == models.CheckNameAvailabilityReason.ALREADY_EXISTS - assert result.message == "Hostname 'checkName' already exists. Please select a different name." - - -@pytest.mark.asyncio -async def test_operations_list(client): - result = client.operations.list() - async for operation in result: - assert operation.name == "Microsoft.Compute/virtualMachines/write" - assert operation.display.operation == "Create or Update Virtual Machine." - assert operation.origin == "user,system" - assert operation.action_type == "Internal" - - -@pytest.mark.asyncio -async def test_lro_begin_create_or_replace(client): - result = await ( - await client.lro.begin_create_or_replace( - resource_group_name=RESOURCE_GROUP_NAME, - order_name="order1", - resource=models.Order( - location="eastus", - properties=models.OrderProperties(product_id="product1", amount=1), - ), - ) - ).result() - assert result.name == "order1" - assert ( - result.id - == "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/test-rg/providers/Azure.ResourceManager.OperationTemplates/orders/order1" - ) - assert result.type == "Azure.ResourceManager.Resources/orders" - assert result.location == "eastus" - assert result.system_data.created_by == "AzureSDK" - - -@pytest.mark.asyncio -async def test_lro_begin_export(client): - await ( - await client.lro.begin_export( - resource_group_name=RESOURCE_GROUP_NAME, - order_name="order1", - body=models.ExportRequest(format="csv"), - ) - ).result() - - -@pytest.mark.asyncio -async def test_lro_begin_delete(client): - await ( - await client.lro.begin_delete( - resource_group_name=RESOURCE_GROUP_NAME, - order_name="order1", - ) - ).result() - - -@pytest.mark.asyncio -async def test_optional_body_get(client): - result = await client.optional_body.get( - resource_group_name=RESOURCE_GROUP_NAME, - widget_name="widget1", - ) - assert result.name == "widget1" - assert ( - result.id - == "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/test-rg/providers/Azure.ResourceManager.OperationTemplates/widgets/widget1" - ) - assert result.type == "Azure.ResourceManager.OperationTemplates/widgets" - assert result.location == "eastus" - assert result.properties.name == "widget1" - assert result.properties.description == "A test widget" - assert result.properties.provisioning_state == "Succeeded" - - -@pytest.mark.asyncio -async def test_optional_body_patch_without_body(client): - result = await client.optional_body.patch( - resource_group_name=RESOURCE_GROUP_NAME, - widget_name="widget1", - ) - assert result.name == "widget1" - assert result.properties.name == "widget1" - assert result.properties.description == "A test widget" - - -@pytest.mark.asyncio -async def test_optional_body_patch_with_body(client): - result = await client.optional_body.patch( - resource_group_name=RESOURCE_GROUP_NAME, - widget_name="widget1", - properties=models.Widget( - location="eastus", - properties=models.WidgetProperties(name="updated-widget", description="Updated description"), - ), - ) - assert result.name == "widget1" - assert result.properties.name == "updated-widget" - assert result.properties.description == "Updated description" - - -@pytest.mark.asyncio -async def test_optional_body_post_without_body(client): - result = await client.optional_body.post( - resource_group_name=RESOURCE_GROUP_NAME, - widget_name="widget1", - ) - assert result.result == "Action completed successfully" - - -@pytest.mark.asyncio -async def test_optional_body_post_with_body(client): - result = await client.optional_body.post( - resource_group_name=RESOURCE_GROUP_NAME, - widget_name="widget1", - body=models.ActionRequest(action_type="perform", parameters="test-parameters"), - ) - assert result.result == "Action completed successfully with parameters" - - -@pytest.mark.asyncio -async def test_optional_body_provider_post_without_body(client): - result = await client.optional_body.provider_post() - assert result.total_allowed == 50 - assert result.status == "Changed to default allowance" - - -@pytest.mark.asyncio -async def test_optional_body_provider_post_with_body(client): - result = await client.optional_body.provider_post( - body=models.ChangeAllowanceRequest(total_allowed=100, reason="Increased demand"), - ) - assert result.total_allowed == 100 - assert result.status == "Changed to requested allowance" - - -@pytest.mark.asyncio -async def test_lro_begin_export_array(client): - result = await ( - await client.lro.begin_export_array( - body=models.ExportRequest(format="csv"), - ) - ).result() - assert len(result) == 2 - assert result[0].content == "order1,product1,1" - assert result[1].content == "order2,product2,2" - - -@pytest.mark.asyncio -async def test_lro_paging_begin_post_paging_lro(client): - poller = await client.lro_paging.begin_post_paging_lro( - resource_group_name=RESOURCE_GROUP_NAME, - product_name="default", - ) - result = await poller.result() - items = [item async for item in result] - assert len(items) == 2 - assert items[0].name == "product1" - assert items[0].properties.product_id == "product1" - assert items[0].properties.provisioning_state == "Succeeded" - assert items[1].name == "product2" - assert items[1].properties.product_id == "product2" - assert items[1].properties.provisioning_state == "Succeeded" diff --git a/packages/typespec-python/tests/mock_api/azure/asynctests/test_azure_arm_resource_async.py b/packages/typespec-python/tests/mock_api/azure/asynctests/test_azure_arm_resource_async.py deleted file mode 100644 index 8da75bfe24..0000000000 --- a/packages/typespec-python/tests/mock_api/azure/asynctests/test_azure_arm_resource_async.py +++ /dev/null @@ -1,478 +0,0 @@ -# ------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for -# license information. -# -------------------------------------------------------------------------- -import pytest -from azure.resourcemanager.resources.aio import ResourcesClient -from azure.resourcemanager.resources import models - -SUBSCRIPTION_ID = "00000000-0000-0000-0000-000000000000" -RESOURCE_GROUP_NAME = "test-rg" - - -@pytest.fixture -async def client(credential, authentication_policy): - async with ResourcesClient( - credential, - SUBSCRIPTION_ID, - "http://localhost:3000", - authentication_policy=authentication_policy, - ) as client: - yield client - - -@pytest.mark.asyncio -async def test_client_signature(credential, authentication_policy): - # make sure signautre order is correct - client1 = ResourcesClient( - credential, - SUBSCRIPTION_ID, - "http://localhost:3000", - authentication_policy=authentication_policy, - ) - # make sure signautre name is correct - client2 = ResourcesClient( - credential=credential, - subscription_id=SUBSCRIPTION_ID, - base_url="http://localhost:3000", - authentication_policy=authentication_policy, - ) - for client in [client1, client2]: - # make sure signautre order is correct - await client.top_level.get(RESOURCE_GROUP_NAME, "top") - # make sure signautre name is correct - await client.top_level.get( - resource_group_name=RESOURCE_GROUP_NAME, - top_level_tracked_resource_name="top", - ) - - -@pytest.mark.asyncio -async def test_top_level_begin_create_or_replace(client): - result = await ( - await client.top_level.begin_create_or_replace( - resource_group_name=RESOURCE_GROUP_NAME, - top_level_tracked_resource_name="top", - resource=models.TopLevelTrackedResource( - location="eastus", - properties=models.TopLevelTrackedResourceProperties( - models.TopLevelTrackedResourceProperties(description="valid") - ), - ), - polling_interval=0, # set polling_interval to 0 s to make the test faster since default is 30s - ) - ).result() - assert result.location == "eastus" - assert result.properties.description == "valid" - assert result.properties.provisioning_state == "Succeeded" - assert result.name == "top" - assert result.type == "Azure.ResourceManager.Resources/topLevelTrackedResources" - assert result.system_data.created_by == "AzureSDK" - - -@pytest.mark.asyncio -async def test_top_level_begin_update(client): - result = await ( - await client.top_level.begin_update( - resource_group_name=RESOURCE_GROUP_NAME, - top_level_tracked_resource_name="top", - properties=models.TopLevelTrackedResource( - location="eastus", - properties=models.TopLevelTrackedResourceProperties( - models.TopLevelTrackedResourceProperties(description="valid2") - ), - ), - polling_interval=0, # set polling_interval to 0 s to make the test faster since default is 30s - ) - ).result() - assert result.location == "eastus" - assert result.properties.description == "valid2" - assert result.properties.provisioning_state == "Succeeded" - assert result.name == "top" - assert result.type == "Azure.ResourceManager.Resources/topLevelTrackedResources" - assert result.system_data.created_by == "AzureSDK" - - -@pytest.mark.asyncio -async def test_top_level_begin_delete(client): - await ( - await client.top_level.begin_delete( - resource_group_name=RESOURCE_GROUP_NAME, - top_level_tracked_resource_name="top", - polling_interval=0, # set polling_interval to 0 s to make the test faster since default is 30s - ) - ).result() - - -@pytest.mark.asyncio -async def test_top_level_list_by_resource_group(client): - response = client.top_level.list_by_resource_group( - resource_group_name=RESOURCE_GROUP_NAME, - ) - result = [r async for r in response] - for result in result: - assert result.location == "eastus" - assert result.properties.description == "valid" - assert result.properties.provisioning_state == "Succeeded" - assert result.name == "top" - assert result.type == "Azure.ResourceManager.Resources/topLevelTrackedResources" - assert result.system_data.created_by == "AzureSDK" - - -@pytest.mark.asyncio -async def test_top_level_list_by_subscription(client): - response = client.top_level.list_by_subscription() - result = [r async for r in response] - for result in result: - assert result.location == "eastus" - assert result.properties.description == "valid" - assert result.properties.provisioning_state == "Succeeded" - assert result.name == "top" - assert result.type == "Azure.ResourceManager.Resources/topLevelTrackedResources" - assert result.system_data.created_by == "AzureSDK" - - -@pytest.mark.asyncio -async def test_nested_get(client): - result = await client.nested.get( - resource_group_name=RESOURCE_GROUP_NAME, - top_level_tracked_resource_name="top", - nexted_proxy_resource_name="nested", - ) - assert result.properties.description == "valid" - assert result.properties.provisioning_state == "Succeeded" - assert result.name == "nested" - assert result.type == "Azure.ResourceManager.Resources/topLevelTrackedResources/top/nestedProxyResources" - assert result.system_data.created_by == "AzureSDK" - - -@pytest.mark.asyncio -async def test_nested_begin_create_or_replace(client): - result = await ( - await client.nested.begin_create_or_replace( - resource_group_name=RESOURCE_GROUP_NAME, - top_level_tracked_resource_name="top", - nexted_proxy_resource_name="nested", - resource=models.TopLevelTrackedResource( - properties=models.TopLevelTrackedResourceProperties( - models.TopLevelTrackedResourceProperties(description="valid") - ), - ), - polling_interval=0, # set polling_interval to 0 s to make the test faster since default is 30s - ) - ).result() - assert result.properties.description == "valid" - assert result.properties.provisioning_state == "Succeeded" - assert result.name == "nested" - assert result.type == "Azure.ResourceManager.Resources/topLevelTrackedResources/top/nestedProxyResources" - assert result.system_data.created_by == "AzureSDK" - - -@pytest.mark.asyncio -async def test_nested_begin_update(client): - result = await ( - await client.nested.begin_update( - resource_group_name=RESOURCE_GROUP_NAME, - top_level_tracked_resource_name="top", - nexted_proxy_resource_name="nested", - properties=models.TopLevelTrackedResource( - properties=models.TopLevelTrackedResourceProperties( - models.TopLevelTrackedResourceProperties(description="valid2") - ), - ), - polling_interval=0, # set polling_interval to 0 s to make the test faster since default is 30s - ) - ).result() - assert result.properties.description == "valid2" - assert result.properties.provisioning_state == "Succeeded" - assert result.name == "nested" - assert result.type == "Azure.ResourceManager.Resources/topLevelTrackedResources/top/nestedProxyResources" - assert result.system_data.created_by == "AzureSDK" - - -@pytest.mark.asyncio -async def test_nested_begin_delete(client): - await ( - await client.nested.begin_delete( - resource_group_name=RESOURCE_GROUP_NAME, - top_level_tracked_resource_name="top", - nexted_proxy_resource_name="nested", - polling_interval=0, # set polling_interval to 0 s to make the test faster since default is 30s - ) - ).result() - - -@pytest.mark.asyncio -async def test_nested_list_by_top_level_tracked_resource(client): - response = client.nested.list_by_top_level_tracked_resource( - resource_group_name=RESOURCE_GROUP_NAME, - top_level_tracked_resource_name="top", - ) - result = [r async for r in response] - for result in result: - assert result.properties.description == "valid" - assert result.properties.provisioning_state == "Succeeded" - assert result.name == "nested" - assert result.type == "Azure.ResourceManager.Resources/topLevelTrackedResources/top/nestedProxyResources" - assert result.system_data.created_by == "AzureSDK" - - -@pytest.mark.asyncio -async def test_top_level_action_sync(client): - await client.top_level.action_sync( - resource_group_name=RESOURCE_GROUP_NAME, - top_level_tracked_resource_name="top", - body={"message": "Resource action at top level.", "urgent": True}, - ) - - -@pytest.mark.asyncio -async def test_singleton_get_by_resource_group(client): - result = await client.singleton.get_by_resource_group( - resource_group_name=RESOURCE_GROUP_NAME, - ) - assert result.properties.description == "valid" - assert result.properties.provisioning_state == "Succeeded" - assert result.name == "default" - assert result.type == "Azure.ResourceManager.Resources/singletonTrackedResources" - assert result.system_data.created_by == "AzureSDK" - - -@pytest.mark.asyncio -async def test_singleton_begin_create_or_replace(client): - result = await ( - await client.singleton.begin_create_or_update( - resource_group_name=RESOURCE_GROUP_NAME, - resource=models.SingletonTrackedResource( - location="eastus", - properties=models.SingletonTrackedResourceProperties( - models.SingletonTrackedResourceProperties(description="valid") - ), - ), - ) - ).result() - assert result.properties.description == "valid" - assert result.properties.provisioning_state == "Succeeded" - assert result.name == "default" - assert result.type == "Azure.ResourceManager.Resources/singletonTrackedResources" - assert result.system_data.created_by == "AzureSDK" - - -@pytest.mark.asyncio -async def test_singleton_update(client): - result = await client.singleton.update( - resource_group_name=RESOURCE_GROUP_NAME, - properties=models.SingletonTrackedResource( - location="eastus2", - properties=models.SingletonTrackedResourceProperties( - models.SingletonTrackedResourceProperties(description="valid2") - ), - ), - ) - assert result.properties.description == "valid2" - assert result.properties.provisioning_state == "Succeeded" - assert result.name == "default" - assert result.type == "Azure.ResourceManager.Resources/singletonTrackedResources" - assert result.system_data.created_by == "AzureSDK" - - -@pytest.mark.asyncio -async def test_singleton_list_by_resource_group(client): - response = client.singleton.list_by_resource_group( - resource_group_name=RESOURCE_GROUP_NAME, - ) - result = [r async for r in response] - for result in result: - assert result.properties.description == "valid" - assert result.properties.provisioning_state == "Succeeded" - assert result.name == "default" - assert result.type == "Azure.ResourceManager.Resources/singletonTrackedResources" - assert result.system_data.created_by == "AzureSDK" - - -@pytest.mark.asyncio -@pytest.mark.parametrize( - "scope", - [ - "", - "/subscriptions/00000000-0000-0000-0000-000000000000", - "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/test-rg", - "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/test-rg/providers/Azure.ResourceManager.Resources/topLevelTrackedResources/top", - ], -) -async def test_extensions_resources_begin_create_or_update(client, scope): - result = await ( - await client.extensions_resources.begin_create_or_update( - resource_uri=scope, - extensions_resource_name="extension", - resource=models.ExtensionsResource(properties=models.ExtensionsResourceProperties(description="valid")), - ) - ).result() - assert result.id == f"{scope}/providers/Azure.ResourceManager.Resources/extensionsResources/extension" - assert result.name == "extension" - assert result.type == "Azure.ResourceManager.Resources/extensionsResources" - assert result.properties.description == "valid" - assert result.properties.provisioning_state == "Succeeded" - assert result.system_data.created_by == "AzureSDK" - - -@pytest.mark.asyncio -@pytest.mark.parametrize( - "scope", - [ - "", - "/subscriptions/00000000-0000-0000-0000-000000000000", - "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/test-rg", - "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/test-rg/providers/Azure.ResourceManager.Resources/topLevelTrackedResources/top", - ], -) -async def test_extensions_resources_update(client, scope): - result = await client.extensions_resources.update( - resource_uri=scope, - extensions_resource_name="extension", - properties=models.ExtensionsResource(properties=models.ExtensionsResourceProperties(description="valid2")), - ) - assert result.id == f"{scope}/providers/Azure.ResourceManager.Resources/extensionsResources/extension" - assert result.name == "extension" - assert result.type == "Azure.ResourceManager.Resources/extensionsResources" - assert result.properties.description == "valid2" - assert result.properties.provisioning_state == "Succeeded" - assert result.system_data.created_by == "AzureSDK" - - -@pytest.mark.asyncio -@pytest.mark.parametrize( - "scope", - [ - "", - "/subscriptions/00000000-0000-0000-0000-000000000000", - "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/test-rg", - "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/test-rg/providers/Azure.ResourceManager.Resources/topLevelTrackedResources/top", - ], -) -async def test_extensions_resources_get(client, scope): - result = await client.extensions_resources.get(resource_uri=scope, extensions_resource_name="extension") - assert result.id == f"{scope}/providers/Azure.ResourceManager.Resources/extensionsResources/extension" - assert result.name == "extension" - assert result.type == "Azure.ResourceManager.Resources/extensionsResources" - assert result.properties.description == "valid" - assert result.properties.provisioning_state == "Succeeded" - assert result.system_data.created_by == "AzureSDK" - - -@pytest.mark.asyncio -@pytest.mark.parametrize( - "scope", - [ - "", - "/subscriptions/00000000-0000-0000-0000-000000000000", - "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/test-rg", - "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/test-rg/providers/Azure.ResourceManager.Resources/topLevelTrackedResources/top", - ], -) -async def test_extensions_resources_list_by_scope(client, scope): - response = client.extensions_resources.list_by_scope( - resource_uri=scope, - ) - result = [r async for r in response] - for result in result: - assert result.id == f"{scope}/providers/Azure.ResourceManager.Resources/extensionsResources/extension" - assert result.name == "extension" - assert result.type == "Azure.ResourceManager.Resources/extensionsResources" - assert result.properties.description == "valid" - assert result.properties.provisioning_state == "Succeeded" - assert result.system_data.created_by == "AzureSDK" - - -@pytest.mark.asyncio -@pytest.mark.parametrize( - "scope", - [ - "", - "/subscriptions/00000000-0000-0000-0000-000000000000", - "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/test-rg", - "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/test-rg/providers/Azure.ResourceManager.Resources/topLevelTrackedResources/top", - ], -) -async def test_extensions_resources_delete(client, scope): - await client.extensions_resources.delete(resource_uri=scope, extensions_resource_name="extension") - - -@pytest.mark.asyncio -async def test_location_resources_create_or_update(client): - result = await client.location_resources.create_or_update( - location="eastus", - location_resource_name="resource", - resource=models.LocationResource(properties=models.LocationResourceProperties(description="valid")), - ) - assert ( - result.id - == "/subscriptions/00000000-0000-0000-0000-000000000000/providers/Azure.ResourceManager.Resources/locations/eastus/locationResources/resource" - ) - assert result.name == "resource" - assert result.type == "Azure.ResourceManager.Resources/locationResources" - assert result.properties.description == "valid" - assert result.properties.provisioning_state == "Succeeded" - assert result.system_data.created_by == "AzureSDK" - - -@pytest.mark.asyncio -async def test_location_resources_update(client): - result = await client.location_resources.update( - location="eastus", - location_resource_name="resource", - properties=models.LocationResource(properties=models.LocationResourceProperties(description="valid2")), - ) - assert ( - result.id - == "/subscriptions/00000000-0000-0000-0000-000000000000/providers/Azure.ResourceManager.Resources/locations/eastus/locationResources/resource" - ) - assert result.name == "resource" - assert result.type == "Azure.ResourceManager.Resources/locationResources" - assert result.properties.description == "valid2" - assert result.properties.provisioning_state == "Succeeded" - assert result.system_data.created_by == "AzureSDK" - - -@pytest.mark.asyncio -async def test_location_resources_get(client): - result = await client.location_resources.get( - location="eastus", - location_resource_name="resource", - ) - assert ( - result.id - == "/subscriptions/00000000-0000-0000-0000-000000000000/providers/Azure.ResourceManager.Resources/locations/eastus/locationResources/resource" - ) - assert result.name == "resource" - assert result.type == "Azure.ResourceManager.Resources/locationResources" - assert result.properties.description == "valid" - assert result.properties.provisioning_state == "Succeeded" - assert result.system_data.created_by == "AzureSDK" - - -@pytest.mark.asyncio -async def test_location_resources_delete(client): - await client.location_resources.delete( - location="eastus", - location_resource_name="resource", - ) - - -@pytest.mark.asyncio -async def test_location_resources_list_by_location(client): - response = client.location_resources.list_by_location( - location="eastus", - ) - result = [r async for r in response] - for result in result: - assert ( - result.id - == "/subscriptions/00000000-0000-0000-0000-000000000000/providers/Azure.ResourceManager.Resources/locations/eastus/locationResources/resource" - ) - assert result.name == "resource" - assert result.type == "Azure.ResourceManager.Resources/locationResources" - assert result.properties.description == "valid" - assert result.properties.provisioning_state == "Succeeded" - assert result.system_data.created_by == "AzureSDK" diff --git a/packages/typespec-python/tests/mock_api/azure/asynctests/test_azure_client_generator_core_access_async.py b/packages/typespec-python/tests/mock_api/azure/asynctests/test_azure_client_generator_core_access_async.py deleted file mode 100644 index d1b6728a30..0000000000 --- a/packages/typespec-python/tests/mock_api/azure/asynctests/test_azure_client_generator_core_access_async.py +++ /dev/null @@ -1,101 +0,0 @@ -# ------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for -# license information. -# -------------------------------------------------------------------------- -import pytest -from specs.azure.clientgenerator.core.access.aio import AccessClient -from specs.azure.clientgenerator.core.access import models - - -@pytest.fixture -async def client(): - async with AccessClient() as client: - yield client - - -@pytest.mark.asyncio -async def test_no_decorator_in_public(client: AccessClient): - result = await client.public_operation.no_decorator_in_public(name="sample") - assert result == models.NoDecoratorModelInPublic(name="sample") - - -@pytest.mark.asyncio -async def test_public_decorator_in_public(client: AccessClient): - result = await client.public_operation.public_decorator_in_public(name="sample") - assert result == models.PublicDecoratorModelInPublic(name="sample") - - -@pytest.mark.asyncio -async def test_no_decorator_in_internal(client: AccessClient): - result = await client.internal_operation._no_decorator_in_internal(name="sample") - assert result == models._models.NoDecoratorModelInInternal(name="sample") - - with pytest.raises(ImportError): - from specs.azure.clientgenerator.core.access.models import NoDecoratorModelInInternal - - with pytest.raises(AttributeError): - await client.internal_operation.no_decorator_in_internal(name="sample") - - -@pytest.mark.asyncio -async def test_internal_decorator_in_internal(client: AccessClient): - result = await client.internal_operation._internal_decorator_in_internal(name="sample") - assert result == models._models.InternalDecoratorModelInInternal(name="sample") - - with pytest.raises(ImportError): - from specs.azure.clientgenerator.core.access.models import InternalDecoratorModelInInternal - - with pytest.raises(AttributeError): - await client.internal_operation.internal_decorator_in_internal(name="sample") - - -@pytest.mark.asyncio -async def test_public_decorator_in_internal(client: AccessClient): - result = await client.internal_operation._public_decorator_in_internal(name="sample") - assert result == models.PublicDecoratorModelInInternal(name="sample") - - with pytest.raises(AttributeError): - await client.internal_operation.public_decorator_in_internal(name="sample") - - -@pytest.mark.asyncio -async def test_public(client: AccessClient): - result = await client.shared_model_in_operation.public(name="sample") - assert result == models.SharedModel(name="sample") - - -@pytest.mark.asyncio -async def test_internal(client: AccessClient): - result = await client.shared_model_in_operation._internal(name="sample") - assert result == models.SharedModel(name="sample") - - with pytest.raises(AttributeError): - await client.shared_model_in_operation.internal(name="sample") - - -@pytest.mark.asyncio -async def test_operation(client: AccessClient): - result = await client.relative_model_in_operation._operation(name="Madge") - assert result == models._models.OuterModel(name="Madge", inner=models._models.InnerModel(name="Madge")) - - with pytest.raises(ImportError): - from specs.azure.clientgenerator.core.access.models import OuterModel - - with pytest.raises(ImportError): - from specs.azure.clientgenerator.core.access.models import InnerModel - - with pytest.raises(AttributeError): - await client.shared_model_in_operation.operation(name="Madge") - - -@pytest.mark.asyncio -async def test_discriminator(client: AccessClient): - result = await client.relative_model_in_operation._discriminator(kind="real") - assert result == models._models.RealModel(name="Madge") - - with pytest.raises(ImportError): - from specs.azure.clientgenerator.core.access.models import RealModel - - with pytest.raises(AttributeError): - await client.shared_model_in_operation.discriminator(kind="real") diff --git a/packages/typespec-python/tests/mock_api/azure/asynctests/test_azure_client_generator_core_alternate_type_async.py b/packages/typespec-python/tests/mock_api/azure/asynctests/test_azure_client_generator_core_alternate_type_async.py deleted file mode 100644 index 589aca7960..0000000000 --- a/packages/typespec-python/tests/mock_api/azure/asynctests/test_azure_client_generator_core_alternate_type_async.py +++ /dev/null @@ -1,73 +0,0 @@ -# ------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for -# license information. -# -------------------------------------------------------------------------- -import pytest -import geojson -from specs.azure.clientgenerator.core.alternatetype.aio import AlternateTypeClient -from specs.azure.clientgenerator.core.alternatetype import models - -# Shared test data -PROPERTIES = {"name": "A single point of interest", "category": "landmark", "elevation": 100} - -GEOMETRY = geojson.Point((-122.25, 37.87)) - -FEATURE_ID = "feature-1" - - -@pytest.fixture -async def client(): - async with AlternateTypeClient(endpoint="http://localhost:3000") as client: - yield client - - -@pytest.fixture -def feature_geojson(): - """Shared GeoJSON Feature for tests.""" - return geojson.Feature(type="Feature", geometry=GEOMETRY, properties=PROPERTIES, id=FEATURE_ID) - - -@pytest.mark.asyncio -async def test_external_type_get_model(client: AlternateTypeClient): - """Test getting a Feature object with geometry, properties, and optional id fields.""" - result = await client.external_type.get_model() - - # Validate the response structure based on the TypeSpec example - assert result.type == "Feature" - assert result.geometry.type == "Point" - assert result.geometry.coordinates == [-122.25, 37.87] - assert result.properties == PROPERTIES - assert result.id == FEATURE_ID - - -@pytest.mark.asyncio -async def test_external_type_put_model(client: AlternateTypeClient, feature_geojson): - """Test putting a Feature object in request body.""" - # Should return None (204/empty response) - result = await client.external_type.put_model(body=feature_geojson) - assert result is None - - -@pytest.mark.asyncio -async def test_external_type_get_property(client: AlternateTypeClient): - """Test getting a ModelWithFeatureProperty object with feature and additionalProperty fields.""" - result = await client.external_type.get_property() - - # Validate the response structure based on the TypeSpec example - assert result.feature.type == "Feature" - assert result.feature.geometry.type == "Point" - assert result.feature.geometry.coordinates == [-122.25, 37.87] - assert result.feature.properties == PROPERTIES - assert result.feature.id == FEATURE_ID - assert result.additional_property == "extra" - - -@pytest.mark.asyncio -async def test_external_type_put_property(client: AlternateTypeClient, feature_geojson): - """Test putting a ModelWithFeatureProperty object in request body.""" - model_with_feature = models.ModelWithFeatureProperty(feature=feature_geojson, additional_property="extra") - - # Should return None (204/empty response) - result = await client.external_type.put_property(body=model_with_feature) - assert result is None diff --git a/packages/typespec-python/tests/mock_api/azure/asynctests/test_azure_client_generator_core_api_version_header_async.py b/packages/typespec-python/tests/mock_api/azure/asynctests/test_azure_client_generator_core_api_version_header_async.py deleted file mode 100644 index 7fd89f76d6..0000000000 --- a/packages/typespec-python/tests/mock_api/azure/asynctests/test_azure_client_generator_core_api_version_header_async.py +++ /dev/null @@ -1,18 +0,0 @@ -# ------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for -# license information. -# -------------------------------------------------------------------------- -import pytest -from client.alternateapiversion.service.header.aio import HeaderClient - - -@pytest.fixture -async def client(): - async with HeaderClient(endpoint="http://localhost:3000") as client: - yield client - - -@pytest.mark.asyncio -async def test_header_api_version(client: HeaderClient): - await client.header_api_version() diff --git a/packages/typespec-python/tests/mock_api/azure/asynctests/test_azure_client_generator_core_api_version_path_async.py b/packages/typespec-python/tests/mock_api/azure/asynctests/test_azure_client_generator_core_api_version_path_async.py deleted file mode 100644 index 3b6c99c116..0000000000 --- a/packages/typespec-python/tests/mock_api/azure/asynctests/test_azure_client_generator_core_api_version_path_async.py +++ /dev/null @@ -1,18 +0,0 @@ -# ------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for -# license information. -# -------------------------------------------------------------------------- -import pytest -from client.alternateapiversion.service.path.aio import PathClient - - -@pytest.fixture -async def client(): - async with PathClient(endpoint="http://localhost:3000") as client: - yield client - - -@pytest.mark.asyncio -async def test_path_api_version(client: PathClient): - await client.path_api_version() diff --git a/packages/typespec-python/tests/mock_api/azure/asynctests/test_azure_client_generator_core_api_version_query_async.py b/packages/typespec-python/tests/mock_api/azure/asynctests/test_azure_client_generator_core_api_version_query_async.py deleted file mode 100644 index 3163f9a7c3..0000000000 --- a/packages/typespec-python/tests/mock_api/azure/asynctests/test_azure_client_generator_core_api_version_query_async.py +++ /dev/null @@ -1,18 +0,0 @@ -# ------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for -# license information. -# -------------------------------------------------------------------------- -import pytest -from client.alternateapiversion.service.query.aio import QueryClient - - -@pytest.fixture -async def client(): - async with QueryClient(endpoint="http://localhost:3000") as client: - yield client - - -@pytest.mark.asyncio -async def test_query_api_version(client: QueryClient): - await client.query_api_version() diff --git a/packages/typespec-python/tests/mock_api/azure/asynctests/test_azure_client_generator_core_client_default_value_async.py b/packages/typespec-python/tests/mock_api/azure/asynctests/test_azure_client_generator_core_client_default_value_async.py deleted file mode 100644 index 1d7795bbfc..0000000000 --- a/packages/typespec-python/tests/mock_api/azure/asynctests/test_azure_client_generator_core_client_default_value_async.py +++ /dev/null @@ -1,46 +0,0 @@ -# ------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for -# license information. -# -------------------------------------------------------------------------- -import pytest -from specs.azure.clientgenerator.core.clientdefaultvalue.aio import ClientDefaultValueClient -from specs.azure.clientgenerator.core.clientdefaultvalue.models import ModelWithDefaultValues - - -@pytest.fixture -async def client(): - async with ClientDefaultValueClient() as client: - yield client - - -@pytest.mark.asyncio -async def test_put_model_property(client: ClientDefaultValueClient): - """Test case 1: @clientDefaultValue for model property.""" - body = ModelWithDefaultValues(name="test") - result = await client.put_model_property(body=body) - assert result.name == "test" - assert result.timeout == 30 - assert result.tier == "standard" - assert result.retry is True - - -@pytest.mark.asyncio -async def test_get_operation_parameter(client: ClientDefaultValueClient): - """Test case 2: @clientDefaultValue for operation parameter.""" - # Test with only required parameter (name), defaults should be applied - await client.get_operation_parameter(name="test") - - -@pytest.mark.asyncio -async def test_get_path_parameter(client: ClientDefaultValueClient): - """Test case 3: @clientDefaultValue for first path segment.""" - # Test with only required segment2, segment1 should use default - await client.get_path_parameter(segment2="segment2") - - -@pytest.mark.asyncio -async def test_get_header_parameter(client: ClientDefaultValueClient): - """Test case 4: @clientDefaultValue for header parameters.""" - # Test with default header values - await client.get_header_parameter() diff --git a/packages/typespec-python/tests/mock_api/azure/asynctests/test_azure_client_generator_core_client_initialization_async.py b/packages/typespec-python/tests/mock_api/azure/asynctests/test_azure_client_generator_core_client_initialization_async.py deleted file mode 100644 index 156f87a9a0..0000000000 --- a/packages/typespec-python/tests/mock_api/azure/asynctests/test_azure_client_generator_core_client_initialization_async.py +++ /dev/null @@ -1,58 +0,0 @@ -# ------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for -# license information. -# -------------------------------------------------------------------------- -import pytest -from specs.azure.clientgenerator.core.clientinitialization.default.aio import ( - HeaderParamClient, - MultipleParamsClient, - MixedParamsClient, - PathParamClient, - ParamAliasClient, -) -from specs.azure.clientgenerator.core.clientinitialization.default.models import Input - - -@pytest.mark.asyncio -async def test_header_param_client(): - async with HeaderParamClient("test-name-value") as client: - await client.with_query(id="test-id") - await client.with_body(Input(name="test-name")) - - -@pytest.mark.asyncio -async def test_multiple_params_client(): - async with MultipleParamsClient("test-name-value", "us-west") as client: - await client.with_query(id="test-id") - await client.with_body(Input(name="test-name")) - - -@pytest.mark.asyncio -async def test_mixed_params_client(): - async with MixedParamsClient("test-name-value") as client: - await client.with_query(region="us-west", id="test-id") - await client.with_body(Input(name="test-name"), region="us-west") - - -@pytest.mark.asyncio -async def test_path_param_client(): - async with PathParamClient("sample-blob") as client: - await client.with_query(format="text") - await client.get_standalone() - await client.delete_standalone() - - -@pytest.mark.asyncio -async def test_param_alias_client(): - async with ParamAliasClient("sample-blob") as client: - await client.with_aliased_name() - await client.with_original_name() - - -# @pytest.mark.asyncio -# async def test_parent_child_client(): -# async with ParentClient() as client: -# await client.child_client.with_query() -# await client.child_client.get_standalone() -# await client.child_client.delete_standalone() diff --git a/packages/typespec-python/tests/mock_api/azure/asynctests/test_azure_client_generator_core_client_location_async.py b/packages/typespec-python/tests/mock_api/azure/asynctests/test_azure_client_generator_core_client_location_async.py deleted file mode 100644 index a039f18932..0000000000 --- a/packages/typespec-python/tests/mock_api/azure/asynctests/test_azure_client_generator_core_client_location_async.py +++ /dev/null @@ -1,82 +0,0 @@ -# ------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for -# license information. -# -------------------------------------------------------------------------- -import pytest -from specs.azure.clientgenerator.core.clientlocation.parameter.aio import MoveMethodParameterToClient -from specs.azure.clientgenerator.core.clientlocation.subclient.aio import MoveToExistingSubClient -from specs.azure.clientgenerator.core.clientlocation.newsubclient.aio import MoveToNewSubClient -from specs.azure.clientgenerator.core.clientlocation.rootclient.aio import MoveToRootClient - - -@pytest.fixture -async def move_method_parameter_to_client(): - async with MoveMethodParameterToClient(storage_account="testaccount") as client: - yield client - - -@pytest.fixture -async def move_to_existing_sub_client(): - async with MoveToExistingSubClient() as client: - yield client - - -@pytest.fixture -async def move_to_new_sub_client(): - async with MoveToNewSubClient() as client: - yield client - - -@pytest.fixture -async def move_to_root_client(): - async with MoveToRootClient() as client: - yield client - - -@pytest.mark.asyncio -async def test_move_method_parameter_to_client_blob_operations_get_blob( - move_method_parameter_to_client: MoveMethodParameterToClient, -): - await move_method_parameter_to_client.blob_operations.get_blob(container="testcontainer", blob="testblob.txt") - - -@pytest.mark.asyncio -async def test_move_to_existing_sub_client_user_operations_get_user( - move_to_existing_sub_client: MoveToExistingSubClient, -): - await move_to_existing_sub_client.user_operations.get_user() - - -@pytest.mark.asyncio -async def test_move_to_existing_sub_client_admin_operations_delete_user( - move_to_existing_sub_client: MoveToExistingSubClient, -): - await move_to_existing_sub_client.admin_operations.delete_user() - - -@pytest.mark.asyncio -async def test_move_to_existing_sub_client_admin_operations_get_admin_info( - move_to_existing_sub_client: MoveToExistingSubClient, -): - await move_to_existing_sub_client.admin_operations.get_admin_info() - - -@pytest.mark.asyncio -async def test_move_to_new_sub_client_product_operations_list_products(move_to_new_sub_client: MoveToNewSubClient): - await move_to_new_sub_client.product_operations.list_products() - - -@pytest.mark.asyncio -async def test_move_to_new_sub_client_archive_operations_archive_product(move_to_new_sub_client: MoveToNewSubClient): - await move_to_new_sub_client.archive_operations.archive_product() - - -@pytest.mark.asyncio -async def test_move_to_root_client_resource_operations_get_resource(move_to_root_client: MoveToRootClient): - await move_to_root_client.resource_operations.get_resource() - - -@pytest.mark.asyncio -async def test_move_to_root_client_get_health_status(move_to_root_client: MoveToRootClient): - await move_to_root_client.get_health_status() diff --git a/packages/typespec-python/tests/mock_api/azure/asynctests/test_azure_client_generator_core_deserialize_empty_string_as_null_async.py b/packages/typespec-python/tests/mock_api/azure/asynctests/test_azure_client_generator_core_deserialize_empty_string_as_null_async.py deleted file mode 100644 index fbb4349f5a..0000000000 --- a/packages/typespec-python/tests/mock_api/azure/asynctests/test_azure_client_generator_core_deserialize_empty_string_as_null_async.py +++ /dev/null @@ -1,20 +0,0 @@ -# ------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for -# license information. -# -------------------------------------------------------------------------- -import pytest -from specs.azure.clientgenerator.core.emptystring.aio import DeserializeEmptyStringAsNullClient -from specs.azure.clientgenerator.core.emptystring import models - - -@pytest.fixture -async def client(): - async with DeserializeEmptyStringAsNullClient() as client: - yield client - - -@pytest.mark.asyncio -async def test_get(client: DeserializeEmptyStringAsNullClient): - result = await client.get() - assert result == models.ResponseModel(sample_url="") diff --git a/packages/typespec-python/tests/mock_api/azure/asynctests/test_azure_client_generator_core_flatten_async.py b/packages/typespec-python/tests/mock_api/azure/asynctests/test_azure_client_generator_core_flatten_async.py deleted file mode 100644 index cb044b430f..0000000000 --- a/packages/typespec-python/tests/mock_api/azure/asynctests/test_azure_client_generator_core_flatten_async.py +++ /dev/null @@ -1,115 +0,0 @@ -# ------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for -# license information. -# -------------------------------------------------------------------------- -import pytest -from specs.azure.clientgenerator.core.flattenproperty.aio import FlattenPropertyClient -from specs.azure.clientgenerator.core.flattenproperty.models import ( - ChildFlattenModel, - ChildModel, - FlattenModel, - FlattenUnknownModel, - NestedFlattenModel, - Solution, - SolutionProperties, -) - - -@pytest.fixture -async def client(): - async with FlattenPropertyClient() as client: - yield client - - -# ========== test for spector ========== - - -@pytest.mark.asyncio -async def test_put_flatten_model(client: FlattenPropertyClient): - resp = FlattenModel(name="test", properties=ChildModel(age=1, description="test")) - assert ( - await client.put_flatten_model(FlattenModel(name="foo", properties=ChildModel(age=10, description="bar"))) - == resp - ) - assert await client.put_flatten_model(FlattenModel(name="foo", age=10, description="bar")) == resp - - -@pytest.mark.asyncio -async def test_put_nested_flatten_model(client: FlattenPropertyClient): - # python doesn't support nested flatten model - assert await client.put_nested_flatten_model( - NestedFlattenModel( - name="foo", - properties=ChildFlattenModel(summary="bar", properties=ChildModel(age=10, description="test")), - ) - ) == NestedFlattenModel( - name="test", - properties=ChildFlattenModel(summary="test", properties=ChildModel(age=1, description="foo")), - ) - - -@pytest.mark.asyncio -async def test_put_flatten_unknown_model(client: FlattenPropertyClient): - result = await client.put_flatten_unknown_model(FlattenUnknownModel(name="foo")) - assert result.name == "test" - assert result.properties == {"key1": "value1", "key2": "value2"} - - -@pytest.mark.asyncio -async def test_put_flatten_read_only_model(client: FlattenPropertyClient): - result = await client.put_flatten_read_only_model(Solution(name="foo")) - assert result == Solution( - name="foo", - properties=SolutionProperties(solution_id="solution1", title="Solution Title", content="Solution Content"), - ) - assert result.solution_id == "solution1" - assert result.title == "Solution Title" - assert result.content == "Solution Content" - - -@pytest.mark.asyncio # ============test for compatibility ============ -async def test_dpg_model_common(): - flatten_model = FlattenModel(name="hello", properties=ChildModel(age=0, description="test")) - assert flatten_model.name == "hello" - assert flatten_model.properties.age == 0 - assert flatten_model.properties.description == "test" - - -@pytest.mark.asyncio -async def test_dpg_model_none(): - flatten_model = FlattenModel() - assert flatten_model.name is None - assert flatten_model.properties is None - assert flatten_model.age is None - assert flatten_model.description is None - - -@pytest.mark.asyncio -async def test_dpg_model_compatibility(): - flatten_model = FlattenModel(description="test", age=0) - assert flatten_model.description == "test" - assert flatten_model.age == 0 - assert flatten_model.properties.description == "test" - assert flatten_model.properties.age == 0 - - -@pytest.mark.asyncio -async def test_dpg_model_setattr(): - flatten_model = FlattenModel() - - flatten_model.age = 0 - assert flatten_model.properties.age == 0 - flatten_model.description = "test" - assert flatten_model.properties.description == "test" - - flatten_model.properties.age = 1 - assert flatten_model.age == 1 - flatten_model.properties.description = "test2" - assert flatten_model.description == "test2" - - -@pytest.mark.asyncio -async def test_dpg_model_exception(): - with pytest.raises(AttributeError): - FlattenModel().no_prop diff --git a/packages/typespec-python/tests/mock_api/azure/asynctests/test_azure_client_generator_core_hierrarchy_building_async.py b/packages/typespec-python/tests/mock_api/azure/asynctests/test_azure_client_generator_core_hierrarchy_building_async.py deleted file mode 100644 index b940b639fe..0000000000 --- a/packages/typespec-python/tests/mock_api/azure/asynctests/test_azure_client_generator_core_hierrarchy_building_async.py +++ /dev/null @@ -1,53 +0,0 @@ -# ------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for -# license information. -# -------------------------------------------------------------------------- -import pytest -from specs.azure.clientgenerator.core.hierarchybuilding.aio import HierarchyBuildingClient -from specs.azure.clientgenerator.core.hierarchybuilding.models import ( - Pet, - Dog, -) - - -@pytest.fixture -async def client(): - async with HierarchyBuildingClient() as client: - yield client - - -# ========== test for spector ========== - - -@pytest.mark.asyncio -async def test_update_pet_as_pet(client: HierarchyBuildingClient): - resp = Pet(name="Buddy", trained=True) - assert await client.pet_operations.update_pet_as_pet(Pet(name="Buddy", trained=True)) == resp - - -@pytest.mark.asyncio -async def test_update_dog_as_pet(client: HierarchyBuildingClient): - resp = Dog(name="Rex", trained=True, breed="German Shepherd") - assert await client.pet_operations.update_dog_as_pet(Dog(name="Rex", trained=True, breed="German Shepherd")) == resp - - -@pytest.mark.asyncio -async def test_update_pet_as_animal(client: HierarchyBuildingClient): - resp = Pet(name="Buddy", trained=True) - assert await client.animal_operations.update_pet_as_animal(Pet(name="Buddy", trained=True)) == resp - - -@pytest.mark.asyncio -async def test_update_dog_as_animal(client: HierarchyBuildingClient): - resp = Dog(name="Rex", trained=True, breed="German Shepherd") - assert ( - await client.animal_operations.update_dog_as_animal(Dog(name="Rex", trained=True, breed="German Shepherd")) - == resp - ) - - -@pytest.mark.asyncio -async def test_update_dog_as_dog(client: HierarchyBuildingClient): - resp = Dog(name="Rex", trained=True, breed="German Shepherd") - assert await client.dog_operations.update_dog_as_dog(Dog(name="Rex", trained=True, breed="German Shepherd")) == resp diff --git a/packages/typespec-python/tests/mock_api/azure/asynctests/test_azure_client_generator_core_next_link_verb_async.py b/packages/typespec-python/tests/mock_api/azure/asynctests/test_azure_client_generator_core_next_link_verb_async.py deleted file mode 100644 index 7ce1de3c50..0000000000 --- a/packages/typespec-python/tests/mock_api/azure/asynctests/test_azure_client_generator_core_next_link_verb_async.py +++ /dev/null @@ -1,28 +0,0 @@ -# ------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for -# license information. -# -------------------------------------------------------------------------- -import pytest - -from specs.azure.clientgenerator.core.nextlinkverb.aio import NextLinkVerbClient - - -@pytest.fixture -async def client(): - async with NextLinkVerbClient(endpoint="http://localhost:3000") as client: - yield client - - -def assert_items(items): - assert len(items) == 2 - assert items[0].id == "test1" - assert items[1].id == "test2" - - -@pytest.mark.asyncio -async def test_list_items_next_link_verb(client: NextLinkVerbClient): - # The operation uses POST for nextLink per @nextLinkVerb - pager = client.list_items() - items = [item async for item in pager] - assert_items(items) diff --git a/packages/typespec-python/tests/mock_api/azure/asynctests/test_azure_client_generator_core_override_async.py b/packages/typespec-python/tests/mock_api/azure/asynctests/test_azure_client_generator_core_override_async.py deleted file mode 100644 index 8fa5849b46..0000000000 --- a/packages/typespec-python/tests/mock_api/azure/asynctests/test_azure_client_generator_core_override_async.py +++ /dev/null @@ -1,106 +0,0 @@ -# ------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for -# license information. -# -------------------------------------------------------------------------- -import inspect -import pytest -from specs.azure.clientgenerator.core.override.aio import OverrideClient - - -@pytest.fixture -async def client(): - async with OverrideClient() as client: - yield client - - -@pytest.mark.asyncio -async def test_reorder_parameters(client: OverrideClient): - await client.reorder_parameters.reorder("param1", "param2") - - -@pytest.mark.asyncio -async def test_group_parameters(client: OverrideClient): - await client.group_parameters.group(param1="param1", param2="param2") - - -@pytest.mark.asyncio -async def test_require_optional_parameter(client: OverrideClient): - await client.require_optional_parameter.require_optional("param1", "param2") - - -@pytest.mark.asyncio -async def test_remove_optional_parameter(client: OverrideClient): - # Test with optional param2 provided - await client.remove_optional_parameter.remove_optional("param1", param2="param2") - - -def test_reorder_parameters_unit_async(client: OverrideClient): - # make sure signature name of `reorder_parameters` are ["param1", "param2"] - # Get the reorder method from the reorder_parameters operation - reorder_method = client.reorder_parameters.reorder - - # Inspect the method signature - sig = inspect.signature(reorder_method) - - # Get parameter names excluding 'self' and '**kwargs' - param_names = [ - param_name - for param_name, param in sig.parameters.items() - if param_name not in ("self", "kwargs") and param.kind != param.VAR_KEYWORD - ] - - # Assert that the parameter names are exactly ["param1", "param2"] - assert param_names == ["param1", "param2"], f"Expected parameter names ['param1', 'param2'], but got {param_names}" - - -def test_require_optional_parameter_signature(client: OverrideClient): - # Get the require_optional method - require_optional_method = client.require_optional_parameter.require_optional - - # Inspect the method signature - sig = inspect.signature(require_optional_method) - - # Get parameter details - params = sig.parameters - - # Check that both param1 and param2 are required (no default values) - assert "param1" in params, "param1 should be present in signature" - assert "param2" in params, "param2 should be present in signature" - assert params["param1"].default == params["param1"].empty, "param1 should have no default value" - assert params["param2"].default == params["param2"].empty, "param2 should have no default value" - - -def test_remove_optional_parameter_signature(client: OverrideClient): - """Test that remove_optional_parameter.remove_optional method signature has correct parameters. - - The @override decorator should remove some optional parameters from the method signature. - Only param1 (required) and param2 (optional) should remain. - """ - # Get the remove_optional method - remove_optional_method = client.remove_optional_parameter.remove_optional - - # Inspect the method signature - sig = inspect.signature(remove_optional_method) - - # Get parameter names excluding 'self' and '**kwargs' - param_names = [ - param_name - for param_name, param in sig.parameters.items() - if param_name not in ("self", "kwargs") and param.kind != param.VAR_KEYWORD - ] - - # Should have param1 (required) and param2 (keyword-only optional) - assert "param1" in param_names, "param1 should be present in signature" - assert "param2" in sig.parameters, "param2 should be present in signature" - - # param1 should be required (positional) - assert sig.parameters["param1"].default == sig.parameters["param1"].empty, "param1 should have no default value" - - # param2 should be optional keyword-only with None default - assert sig.parameters["param2"].kind == sig.parameters["param2"].KEYWORD_ONLY, "param2 should be keyword-only" - assert sig.parameters["param2"].default is None, "param2 should have None as default value" - - # param3 and param4 should be removed - assert "param3" not in param_names, "param3 should not be present in signature" - assert "param4" not in param_names, "param4 should not be present in signature" diff --git a/packages/typespec-python/tests/mock_api/azure/asynctests/test_azure_client_generator_core_usage_async.py b/packages/typespec-python/tests/mock_api/azure/asynctests/test_azure_client_generator_core_usage_async.py deleted file mode 100644 index 66c7946d88..0000000000 --- a/packages/typespec-python/tests/mock_api/azure/asynctests/test_azure_client_generator_core_usage_async.py +++ /dev/null @@ -1,38 +0,0 @@ -# ------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for -# license information. -# -------------------------------------------------------------------------- -import pytest -from specs.azure.clientgenerator.core.usage.aio import UsageClient -from specs.azure.clientgenerator.core.usage import models - - -@pytest.fixture -async def client(): - async with UsageClient() as client: - yield client - - -@pytest.mark.asyncio -async def test_input_to_input_output(client: UsageClient): - await client.model_in_operation.input_to_input_output(models.InputModel(name="Madge")) - - -@pytest.mark.asyncio -async def test_output_to_input_output(client: UsageClient): - assert models.OutputModel(name="Madge") == await client.model_in_operation.output_to_input_output() - - -@pytest.mark.asyncio -async def test_model_usage(client: UsageClient): - assert models.RoundTripModel( - result=models.ResultModel(name="Madge") - ) == await client.model_in_operation.model_in_read_only_property(body=models.RoundTripModel()) - - -@pytest.mark.asyncio -async def test_orphan_model_serializable(client: UsageClient): - await client.model_in_operation.orphan_model_serializable( - body=models.OrphanModel(model_name="name", description="desc") - ) diff --git a/packages/typespec-python/tests/mock_api/azure/asynctests/test_azure_core_basic_async.py b/packages/typespec-python/tests/mock_api/azure/asynctests/test_azure_core_basic_async.py deleted file mode 100644 index 87946f37ca..0000000000 --- a/packages/typespec-python/tests/mock_api/azure/asynctests/test_azure_core_basic_async.py +++ /dev/null @@ -1,76 +0,0 @@ -# ------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for -# license information. -# -------------------------------------------------------------------------- -import pytest -from specs.azure.core.basic import models, aio - -VALID_USER = models.User(id=1, name="Madge", etag="11bdc430-65e8-45ad-81d9-8ffa60d55b59") - - -@pytest.fixture -async def client(): - async with aio.BasicClient() as client: - yield client - - -@pytest.mark.asyncio -async def test_create_or_update(client: aio.BasicClient): - result = await client.create_or_update(id=1, resource={"name": "Madge"}) - assert result == VALID_USER - - -@pytest.mark.asyncio -async def test_create_or_replace(client: aio.BasicClient): - result = await client.create_or_replace(id=1, resource={"name": "Madge"}) - assert result == VALID_USER - - -@pytest.mark.asyncio -async def test_get(client: aio.BasicClient): - result = await client.get(id=1) - assert result == VALID_USER - - -@pytest.mark.asyncio -async def test_list(client: aio.BasicClient): - result = client.list( - top=5, - skip=10, - orderby=["id"], - filter="id lt 10", - select=["id", "orders", "etag"], - expand=["orders"], - ) - result = [item async for item in result] - assert len(result) == 2 - assert result[0].id == 1 - assert result[0].name == "Madge" - assert result[0].etag == "11bdc430-65e8-45ad-81d9-8ffa60d55b59" - assert result[0].orders[0].id == 1 - assert result[0].orders[0].user_id == 1 - assert result[0].orders[0].detail == "a recorder" - assert result[1].id == 2 - assert result[1].name == "John" - assert result[1].etag == "11bdc430-65e8-45ad-81d9-8ffa60d55b5a" - assert result[1].orders[0].id == 2 - assert result[1].orders[0].user_id == 2 - assert result[1].orders[0].detail == "a TV" - - -@pytest.mark.asyncio -async def test_delete(client: aio.BasicClient): - await client.delete(id=1) - - -@pytest.mark.asyncio -async def test_export(client: aio.BasicClient): - result = await client.export(id=1, format="json") - assert result == VALID_USER - - -@pytest.mark.asyncio -async def test_export_all_users(client: aio.BasicClient): - result = await client.export_all_users(format="json") - assert result.users[0] == VALID_USER diff --git a/packages/typespec-python/tests/mock_api/azure/asynctests/test_azure_core_lro_rpc_async.py b/packages/typespec-python/tests/mock_api/azure/asynctests/test_azure_core_lro_rpc_async.py deleted file mode 100644 index bc572bf298..0000000000 --- a/packages/typespec-python/tests/mock_api/azure/asynctests/test_azure_core_lro_rpc_async.py +++ /dev/null @@ -1,22 +0,0 @@ -# ------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for -# license information. -# -------------------------------------------------------------------------- -import pytest -from specs.azure.core.lro.rpc.aio import RpcClient -from specs.azure.core.lro.rpc import models - - -@pytest.fixture -async def client(): - async with RpcClient() as client: - yield client - - -@pytest.mark.asyncio -async def test_long_running_rpc(client: RpcClient, async_polling_method): - result = await client.begin_long_running_rpc( - models.GenerationOptions(prompt="text"), polling_interval=0, polling=async_polling_method - ) - assert (await result.result()) == models.GenerationResult(data="text data") diff --git a/packages/typespec-python/tests/mock_api/azure/asynctests/test_azure_core_lro_standard_async.py b/packages/typespec-python/tests/mock_api/azure/asynctests/test_azure_core_lro_standard_async.py deleted file mode 100644 index b9b00668ca..0000000000 --- a/packages/typespec-python/tests/mock_api/azure/asynctests/test_azure_core_lro_standard_async.py +++ /dev/null @@ -1,39 +0,0 @@ -# ------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for -# license information. -# -------------------------------------------------------------------------- -import pytest -from specs.azure.core.lro.standard.aio import StandardClient -from specs.azure.core.lro.standard.models import User, ExportedUser - - -@pytest.fixture -async def client(): - async with StandardClient() as client: - yield client - - -@pytest.mark.asyncio -async def test_lro_core_put(client, async_polling_method): - user = User({"name": "madge", "role": "contributor"}) - result = await ( - await client.begin_create_or_replace( - name=user.name, resource=user, polling_interval=0, polling=async_polling_method - ) - ).result() - assert result == user - - -@pytest.mark.asyncio -async def test_lro_core_delete(client, async_polling_method): - await (await client.begin_delete(name="madge", polling_interval=0, polling=async_polling_method)).result() - - -@pytest.mark.asyncio -async def test_lro_core_export(client, async_polling_method): - export_user = ExportedUser({"name": "madge", "resourceUri": "/users/madge"}) - result = await ( - await client.begin_export(name="madge", format="json", polling_interval=0, polling=async_polling_method) - ).result() - assert result == export_user diff --git a/packages/typespec-python/tests/mock_api/azure/asynctests/test_azure_core_model_async.py b/packages/typespec-python/tests/mock_api/azure/asynctests/test_azure_core_model_async.py deleted file mode 100644 index b2f8eed895..0000000000 --- a/packages/typespec-python/tests/mock_api/azure/asynctests/test_azure_core_model_async.py +++ /dev/null @@ -1,33 +0,0 @@ -# ------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for -# license information. -# -------------------------------------------------------------------------- -import pytest -from specs.azure.core.model.aio import ModelClient -from specs.azure.core.model.models import AzureEmbeddingModel - - -@pytest.fixture -async def client(): - async with ModelClient() as client: - yield client - - -@pytest.mark.asyncio -async def test_azure_core_embedding_vector_post(client: ModelClient): - embedding_model = AzureEmbeddingModel(embedding=[0, 1, 2, 3, 4]) - result = await client.azure_core_embedding_vector.post( - body=embedding_model, - ) - assert result == AzureEmbeddingModel(embedding=[5, 6, 7, 8, 9]) - - -@pytest.mark.asyncio -async def test_azure_core_embedding_vector_put(client: ModelClient): - await client.azure_core_embedding_vector.put(body=[0, 1, 2, 3, 4]) - - -@pytest.mark.asyncio -async def test_azure_core_embedding_vector_get(client: ModelClient): - assert [0, 1, 2, 3, 4] == (await client.azure_core_embedding_vector.get()) diff --git a/packages/typespec-python/tests/mock_api/azure/asynctests/test_azure_core_page_async.py b/packages/typespec-python/tests/mock_api/azure/asynctests/test_azure_core_page_async.py deleted file mode 100644 index 557c044e9e..0000000000 --- a/packages/typespec-python/tests/mock_api/azure/asynctests/test_azure_core_page_async.py +++ /dev/null @@ -1,80 +0,0 @@ -# ------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for -# license information. -# -------------------------------------------------------------------------- -import pytest -from typing import AsyncIterable -from specs.azure.core.page import models, aio - -VALID_USER = models.User(id=1, name="Madge", etag="11bdc430-65e8-45ad-81d9-8ffa60d55b59") - - -@pytest.fixture -async def client(): - async with aio.PageClient() as client: - yield client - - -async def _list_with_page_tests(pager: AsyncIterable[models.User]): - result = [p async for p in pager] - assert len(result) == 1 - assert result[0].id == 1 - assert result[0].name == "Madge" - assert result[0].etag == "11bdc430-65e8-45ad-81d9-8ffa60d55b59" - assert result[0].orders is None - - -@pytest.mark.asyncio -async def test_list_with_page(client: aio.PageClient): - await _list_with_page_tests(client.list_with_page()) - - -@pytest.mark.asyncio -async def test_list_with_custom_page_model(client: aio.PageClient): - await _list_with_page_tests(client.list_with_custom_page_model()) - with pytest.raises(AttributeError): - models.CustomPageModel - - -@pytest.mark.asyncio -async def test_list_with_parameters(client: aio.PageClient): - result = [ - item - async for item in client.list_with_parameters(models.ListItemInputBody(input_name="Madge"), another="Second") - ] - assert len(result) == 1 - assert result[0] == VALID_USER - - -@pytest.mark.asyncio -async def test_two_models_as_page_item(client: aio.PageClient): - result = [item async for item in client.two_models_as_page_item.list_first_item()] - assert len(result) == 1 - assert result[0].id == 1 - - result = [item async for item in client.two_models_as_page_item.list_second_item()] - assert len(result) == 1 - assert result[0].name == "Madge" - - -@pytest.mark.asyncio -async def test_list_with_parameterized_next_link(client: aio.PageClient): - result = [item async for item in client.with_parameterized_next_link(select="name", include_pending=True)] - assert len(result) == 2 - assert result[0].id == 1 - assert result[0].name == "User1" - assert result[1].id == 2 - assert result[1].name == "User2" - - -@pytest.mark.asyncio -async def test_list_with_relative_next_link(client: aio.PageClient): - result = [item async for item in client.with_relative_next_link()] - assert len(result) == 2 - assert result[0].id == 1 - assert result[0].name == "User1" - assert result[0].etag == "11bdc430-65e8-45ad-81d9-8ffa60d55b59" - assert result[1].id == 2 - assert result[1].name == "User2" - assert result[1].etag == "11bdc430-65e8-45ad-81d9-8ffa60d55b59" diff --git a/packages/typespec-python/tests/mock_api/azure/asynctests/test_azure_core_scalar_async.py b/packages/typespec-python/tests/mock_api/azure/asynctests/test_azure_core_scalar_async.py deleted file mode 100644 index 4616cc2b5e..0000000000 --- a/packages/typespec-python/tests/mock_api/azure/asynctests/test_azure_core_scalar_async.py +++ /dev/null @@ -1,41 +0,0 @@ -# ------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for -# license information. -# -------------------------------------------------------------------------- -import pytest -from specs.azure.core.scalar.aio import ScalarClient -from specs.azure.core.scalar import models - - -@pytest.fixture -async def client(): - async with ScalarClient() as client: - yield client - - -@pytest.mark.asyncio -async def test_azure_location_scalar_get(client: ScalarClient): - result = await client.azure_location_scalar.get() - assert result == "eastus" - - -@pytest.mark.asyncio -async def test_azure_location_scalar_put(client: ScalarClient): - await client.azure_location_scalar.put("eastus") - - -@pytest.mark.asyncio -async def test_azure_location_scalar_post(client: ScalarClient): - result = await client.azure_location_scalar.post(models.AzureLocationModel(location="eastus")) - assert result == models.AzureLocationModel(location="eastus") - - -@pytest.mark.asyncio -async def test_azure_location_scalar_header(client: ScalarClient): - await client.azure_location_scalar.header(region="eastus") - - -@pytest.mark.asyncio -async def test_azure_location_scalar_query(client: ScalarClient): - await client.azure_location_scalar.query(region="eastus") diff --git a/packages/typespec-python/tests/mock_api/azure/asynctests/test_azure_core_traits_async.py b/packages/typespec-python/tests/mock_api/azure/asynctests/test_azure_core_traits_async.py deleted file mode 100644 index dca8185442..0000000000 --- a/packages/typespec-python/tests/mock_api/azure/asynctests/test_azure_core_traits_async.py +++ /dev/null @@ -1,87 +0,0 @@ -# ------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for -# license information. -# -------------------------------------------------------------------------- -import functools -from datetime import datetime - -import pytest -from azure.core.exceptions import HttpResponseError -from azure.core import MatchConditions -from specs.azure.core.traits.aio import TraitsClient -from specs.azure.core.traits.models import UserActionParam - - -@pytest.fixture -async def client(): - async with TraitsClient() as client: - yield client - - -@pytest.mark.asyncio -async def test_get(client: TraitsClient, check_client_request_id_header): - async def assert_test_get(**kwargs): - checked = {} - result, header = await client.smoke_test( - id=1, - foo="123", - if_unmodified_since=datetime(year=2022, month=8, day=26, hour=14, minute=38, second=0), - if_modified_since=datetime(year=2021, month=8, day=26, hour=14, minute=38, second=0), - cls=lambda x, y, z: (y, z), - raw_request_hook=functools.partial( - check_client_request_id_header, header="x-ms-client-request-id", checked=checked - ), - **kwargs, - ) - assert result.id == 1 - assert result.name == "Madge" - assert header["ETag"] == "11bdc430-65e8-45ad-81d9-8ffa60d55b59" - assert header["bar"] == "456" - assert header["x-ms-client-request-id"] == checked["x-ms-client-request-id"] - - await assert_test_get(etag="valid", match_condition=MatchConditions.IfNotModified) - await assert_test_get(etag="invalid", match_condition=MatchConditions.IfModified) - with pytest.raises(HttpResponseError): - await assert_test_get() - - -@pytest.mark.asyncio -async def test_repeatable_action(client: TraitsClient, check_repeatability_header): - result, header = await client.repeatable_action( - id=1, - body=UserActionParam(user_action_value="test"), - cls=lambda x, y, z: (y, z), - raw_request_hook=check_repeatability_header, - ) - assert result.user_action_result == "test" - assert header["Repeatability-Result"] == "accepted" - - result, header = await client.repeatable_action( - id=1, - body=UserActionParam(user_action_value="test"), - cls=lambda x, y, z: (y, z), - headers={ - "Repeatability-Request-ID": "5942d803-e3fa-4f96-8f67-607d7bd607f5", - "Repeatability-First-Sent": "Sun, 06 Nov 1994 08:49:37 GMT", - }, - raw_request_hook=check_repeatability_header, - ) - assert result.user_action_result == "test" - assert header["Repeatability-Result"] == "accepted" - - with pytest.raises(HttpResponseError): - await client.repeatable_action( - id=1, - body=UserActionParam(user_action_value="test"), - cls=lambda x, y, z: (y, z), - headers={"Repeatability-Request-ID": "wrong-id"}, - ) - - with pytest.raises(HttpResponseError): - await client.repeatable_action( - id=1, - body=UserActionParam(user_action_value="test"), - cls=lambda x, y, z: (y, z), - headers={"Repeatability-First-Sent": "wrong-datetime"}, - ) diff --git a/packages/typespec-python/tests/mock_api/azure/asynctests/test_azure_encode_duration_async.py b/packages/typespec-python/tests/mock_api/azure/asynctests/test_azure_encode_duration_async.py deleted file mode 100644 index 8a23b94955..0000000000 --- a/packages/typespec-python/tests/mock_api/azure/asynctests/test_azure_encode_duration_async.py +++ /dev/null @@ -1,19 +0,0 @@ -# ------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for -# license information. -# -------------------------------------------------------------------------- -import pytest -from specs.azure.encode.duration.aio import DurationClient -from specs.azure.encode.duration import models - - -@pytest.fixture -async def client(): - async with DurationClient() as client: - yield client - - -@pytest.mark.asyncio -async def test_duration_constant(client: DurationClient): - await client.duration_constant(models.DurationModel(input="1.02:59:59.5000000")) diff --git a/packages/typespec-python/tests/mock_api/azure/asynctests/test_azure_example_basic_async.py b/packages/typespec-python/tests/mock_api/azure/asynctests/test_azure_example_basic_async.py deleted file mode 100644 index 46a66e519d..0000000000 --- a/packages/typespec-python/tests/mock_api/azure/asynctests/test_azure_example_basic_async.py +++ /dev/null @@ -1,30 +0,0 @@ -# ------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for -# license information. -# -------------------------------------------------------------------------- -import pytest -from specs.azure.example.basic.aio import AzureExampleClient -from specs.azure.example.basic.models import ActionRequest, Model - - -@pytest.fixture -async def client(): - async with AzureExampleClient() as client: - yield client - - -@pytest.mark.asyncio -async def test_basic_action(client: AzureExampleClient): - body = ActionRequest( - string_property="text", - model_property=Model(int32_property=1, float32_property=1.5, enum_property="EnumValue1"), - array_property=["item"], - record_property={"record": "value"}, - ) - result = await client.basic_action( - body=body, - query_param="query", - header_param="header", - ) - assert result.string_property == body.string_property diff --git a/packages/typespec-python/tests/mock_api/azure/asynctests/test_azure_payload_pageable_async.py b/packages/typespec-python/tests/mock_api/azure/asynctests/test_azure_payload_pageable_async.py deleted file mode 100644 index 440a4a5117..0000000000 --- a/packages/typespec-python/tests/mock_api/azure/asynctests/test_azure_payload_pageable_async.py +++ /dev/null @@ -1,19 +0,0 @@ -# ------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for -# license information. -# -------------------------------------------------------------------------- -import pytest -from specs.azure.payload.pageable.aio import PageableClient - - -@pytest.fixture -async def client(): - async with PageableClient(endpoint="http://localhost:3000") as client: - yield client - - -@pytest.mark.asyncio -async def test_list(client: PageableClient): - result = [p async for p in client.list(maxpagesize=3)] - assert len(result) == 4 diff --git a/packages/typespec-python/tests/mock_api/azure/asynctests/test_azure_resource_manager_method_subscription_id_async.py b/packages/typespec-python/tests/mock_api/azure/asynctests/test_azure_resource_manager_method_subscription_id_async.py deleted file mode 100644 index 7b96c3c297..0000000000 --- a/packages/typespec-python/tests/mock_api/azure/asynctests/test_azure_resource_manager_method_subscription_id_async.py +++ /dev/null @@ -1,248 +0,0 @@ -# ------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for -# license information. -# -------------------------------------------------------------------------- -import pytest -from azure.resourcemanager.methodsubscriptionid.aio import MethodSubscriptionIdClient -from azure.resourcemanager.methodsubscriptionid import models - -SUBSCRIPTION_ID = "00000000-0000-0000-0000-000000000000" -RESOURCE_GROUP_NAME = "test-rg" - - -@pytest.fixture -async def client(credential, authentication_policy): - async with MethodSubscriptionIdClient( - credential, - SUBSCRIPTION_ID, - "http://localhost:3000", - authentication_policy=authentication_policy, - ) as client: - yield client - - -@pytest.mark.asyncio -async def test_operations_list(client): - """Test Operations.list() endpoint.""" - operations = client.operations.list() - operations_list = [op async for op in operations] - assert len(operations_list) > 0 - - operation = operations_list[0] - assert operation.name == "Azure.ResourceManager.MethodSubscriptionId/services/read" - assert operation.is_data_action is False - assert operation.display.provider == "Azure.ResourceManager.MethodSubscriptionId" - assert operation.display.resource == "services" - assert operation.display.operation == "Lists services" - assert operation.display.description == "Lists registered services" - - -@pytest.mark.asyncio -async def test_two_subscription_resources_method_level_subscription_resource1_operations_get(client): - """Test get operation for SubscriptionResource1 with method-level subscription ID.""" - result = await client.two_subscription_resources_method_level.subscription_resource1_operations.get( - subscription_id=SUBSCRIPTION_ID, - subscription_resource1_name="sub-resource-1", - ) - - assert ( - result.id - == f"/subscriptions/{SUBSCRIPTION_ID}/providers/Azure.ResourceManager.MethodSubscriptionId/subscriptionResource1s/sub-resource-1" - ) - assert result.name == "sub-resource-1" - assert result.type == "Azure.ResourceManager.MethodSubscriptionId/subscriptionResource1s" - assert result.properties.description == "Valid subscription resource 1" - assert result.properties.provisioning_state == "Succeeded" - assert result.system_data.created_by == "AzureSDK" - - -@pytest.mark.asyncio -async def test_two_subscription_resources_method_level_subscription_resource1_operations_put(client): - """Test put operation for SubscriptionResource1 with method-level subscription ID.""" - resource = models.SubscriptionResource1( - properties=models.SubscriptionResource1Properties(description="Valid subscription resource 1") - ) - - result = await client.two_subscription_resources_method_level.subscription_resource1_operations.put( - subscription_id=SUBSCRIPTION_ID, - subscription_resource1_name="sub-resource-1", - resource=resource, - ) - - assert ( - result.id - == f"/subscriptions/{SUBSCRIPTION_ID}/providers/Azure.ResourceManager.MethodSubscriptionId/subscriptionResource1s/sub-resource-1" - ) - assert result.name == "sub-resource-1" - assert result.type == "Azure.ResourceManager.MethodSubscriptionId/subscriptionResource1s" - assert result.properties.description == "Valid subscription resource 1" - assert result.properties.provisioning_state == "Succeeded" - assert result.system_data.created_by == "AzureSDK" - - -@pytest.mark.asyncio -async def test_two_subscription_resources_method_level_subscription_resource1_operations_delete(client): - """Test delete operation for SubscriptionResource1 with method-level subscription ID.""" - await client.two_subscription_resources_method_level.subscription_resource1_operations.delete( - subscription_id=SUBSCRIPTION_ID, - subscription_resource1_name="sub-resource-1", - ) - - -@pytest.mark.asyncio -async def test_two_subscription_resources_method_level_subscription_resource2_operations_get(client): - """Test get operation for SubscriptionResource2 with method-level subscription ID.""" - result = await client.two_subscription_resources_method_level.subscription_resource2_operations.get( - subscription_id=SUBSCRIPTION_ID, - subscription_resource2_name="sub-resource-2", - ) - - assert ( - result.id - == f"/subscriptions/{SUBSCRIPTION_ID}/providers/Azure.ResourceManager.MethodSubscriptionId/subscriptionResource2s/sub-resource-2" - ) - assert result.name == "sub-resource-2" - assert result.type == "Azure.ResourceManager.MethodSubscriptionId/subscriptionResource2s" - assert result.properties.config_value == "test-config" - assert result.properties.provisioning_state == "Succeeded" - assert result.system_data.created_by == "AzureSDK" - - -@pytest.mark.asyncio -async def test_two_subscription_resources_method_level_subscription_resource2_operations_put(client): - """Test put operation for SubscriptionResource2 with method-level subscription ID.""" - resource = models.SubscriptionResource2( - properties=models.SubscriptionResource2Properties(config_value="test-config") - ) - - result = await client.two_subscription_resources_method_level.subscription_resource2_operations.put( - subscription_id=SUBSCRIPTION_ID, - subscription_resource2_name="sub-resource-2", - resource=resource, - ) - - assert ( - result.id - == f"/subscriptions/{SUBSCRIPTION_ID}/providers/Azure.ResourceManager.MethodSubscriptionId/subscriptionResource2s/sub-resource-2" - ) - assert result.name == "sub-resource-2" - assert result.type == "Azure.ResourceManager.MethodSubscriptionId/subscriptionResource2s" - assert result.properties.config_value == "test-config" - assert result.properties.provisioning_state == "Succeeded" - assert result.system_data.created_by == "AzureSDK" - - -@pytest.mark.asyncio -async def test_two_subscription_resources_method_level_subscription_resource2_operations_delete(client): - """Test delete operation for SubscriptionResource2 with method-level subscription ID.""" - await client.two_subscription_resources_method_level.subscription_resource2_operations.delete( - subscription_id=SUBSCRIPTION_ID, - subscription_resource2_name="sub-resource-2", - ) - - -@pytest.mark.asyncio -async def test_mixed_subscription_placement_subscription_resource_operations_get(client): - """Test get operation for SubscriptionResource in mixed placement scenario.""" - result = await client.mixed_subscription_placement.subscription_resource_operations.get( - subscription_id=SUBSCRIPTION_ID, - subscription_resource_name="sub-resource", - ) - - assert ( - result.id - == f"/subscriptions/{SUBSCRIPTION_ID}/providers/Azure.ResourceManager.MethodSubscriptionId/subscriptionResources/sub-resource" - ) - assert result.name == "sub-resource" - assert result.type == "Azure.ResourceManager.MethodSubscriptionId/subscriptionResources" - assert result.properties.subscription_setting == "test-sub-setting" - assert result.properties.provisioning_state == "Succeeded" - assert result.system_data.created_by == "AzureSDK" - - -@pytest.mark.asyncio -async def test_mixed_subscription_placement_subscription_resource_operations_put(client): - """Test put operation for SubscriptionResource in mixed placement scenario.""" - resource = models.SubscriptionResource( - properties=models.SubscriptionResourceProperties(subscription_setting="test-sub-setting") - ) - - result = await client.mixed_subscription_placement.subscription_resource_operations.put( - subscription_id=SUBSCRIPTION_ID, - subscription_resource_name="sub-resource", - resource=resource, - ) - - assert ( - result.id - == f"/subscriptions/{SUBSCRIPTION_ID}/providers/Azure.ResourceManager.MethodSubscriptionId/subscriptionResources/sub-resource" - ) - assert result.name == "sub-resource" - assert result.type == "Azure.ResourceManager.MethodSubscriptionId/subscriptionResources" - assert result.properties.subscription_setting == "test-sub-setting" - assert result.properties.provisioning_state == "Succeeded" - assert result.system_data.created_by == "AzureSDK" - - -@pytest.mark.asyncio -async def test_mixed_subscription_placement_subscription_resource_operations_delete(client): - """Test delete operation for SubscriptionResource in mixed placement scenario.""" - await client.mixed_subscription_placement.subscription_resource_operations.delete( - subscription_id=SUBSCRIPTION_ID, - subscription_resource_name="sub-resource", - ) - - -@pytest.mark.asyncio -async def test_mixed_subscription_placement_resource_group_resource_operations_get(client): - """Test get operation for ResourceGroupResource with client-level subscription ID.""" - result = await client.mixed_subscription_placement.resource_group_resource_operations.get( - resource_group_name=RESOURCE_GROUP_NAME, - resource_group_resource_name="rg-resource", - ) - - assert ( - result.id - == f"/subscriptions/{SUBSCRIPTION_ID}/resourceGroups/{RESOURCE_GROUP_NAME}/providers/Azure.ResourceManager.MethodSubscriptionId/resourceGroupResources/rg-resource" - ) - assert result.name == "rg-resource" - assert result.type == "Azure.ResourceManager.MethodSubscriptionId/resourceGroupResources" - assert result.location == "eastus" - assert result.properties.resource_group_setting == "test-setting" - assert result.properties.provisioning_state == "Succeeded" - assert result.system_data.created_by == "AzureSDK" - - -@pytest.mark.asyncio -async def test_mixed_subscription_placement_resource_group_resource_operations_put(client): - """Test put operation for ResourceGroupResource with client-level subscription ID.""" - resource = models.ResourceGroupResource( - location="eastus", properties=models.ResourceGroupResourceProperties(resource_group_setting="test-setting") - ) - - result = await client.mixed_subscription_placement.resource_group_resource_operations.put( - resource_group_name=RESOURCE_GROUP_NAME, - resource_group_resource_name="rg-resource", - resource=resource, - ) - - assert ( - result.id - == f"/subscriptions/{SUBSCRIPTION_ID}/resourceGroups/{RESOURCE_GROUP_NAME}/providers/Azure.ResourceManager.MethodSubscriptionId/resourceGroupResources/rg-resource" - ) - assert result.name == "rg-resource" - assert result.type == "Azure.ResourceManager.MethodSubscriptionId/resourceGroupResources" - assert result.location == "eastus" - assert result.properties.resource_group_setting == "test-setting" - assert result.properties.provisioning_state == "Succeeded" - assert result.system_data.created_by == "AzureSDK" - - -@pytest.mark.asyncio -async def test_mixed_subscription_placement_resource_group_resource_operations_delete(client): - """Test delete operation for ResourceGroupResource with client-level subscription ID.""" - await client.mixed_subscription_placement.resource_group_resource_operations.delete( - resource_group_name=RESOURCE_GROUP_NAME, - resource_group_resource_name="rg-resource", - ) diff --git a/packages/typespec-python/tests/mock_api/azure/asynctests/test_azure_resource_manager_multi_service_async.py b/packages/typespec-python/tests/mock_api/azure/asynctests/test_azure_resource_manager_multi_service_async.py deleted file mode 100644 index 86af8d31a9..0000000000 --- a/packages/typespec-python/tests/mock_api/azure/asynctests/test_azure_resource_manager_multi_service_async.py +++ /dev/null @@ -1,110 +0,0 @@ -# ------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for -# license information. -# -------------------------------------------------------------------------- -import pytest -from azure.core.exceptions import HttpResponseError -from azure.resourcemanager.multiservice.combined.aio import CombinedClient -from azure.resourcemanager.multiservice.combined.models import VirtualMachine, Disk - - -@pytest.fixture -async def client(credential, authentication_policy): - """Create a Combined async client for testing.""" - return CombinedClient( - credential=credential, - subscription_id="00000000-0000-0000-0000-000000000000", - base_url="http://localhost:3000", - authentication_policy=authentication_policy, - polling_interval=0.1, # Speed up tests by reducing polling interval - ) - - -@pytest.mark.asyncio -async def test_virtual_machines_get(client): - resource_group_name = "test-rg" - vm_name = "vm1" - - with pytest.raises(HttpResponseError): - await client.virtual_machines.get( - resource_group_name=resource_group_name, - vm_name=vm_name, - api_version="av1", # invalid api version shall raise error - ) - - result = await client.virtual_machines.get(resource_group_name=resource_group_name, vm_name=vm_name) - - assert result is not None - assert isinstance(result, VirtualMachine) - assert result.name == vm_name - - -@pytest.mark.asyncio -async def test_virtual_machines_create_or_update(client): - resource_group_name = "test-rg" - vm_name = "vm1" - - vm_resource = VirtualMachine(location="eastus", properties={}) - - with pytest.raises(HttpResponseError): - poller = await client.virtual_machines.begin_create_or_update( - resource_group_name=resource_group_name, - vm_name=vm_name, - resource=vm_resource, - api_version="av1", # invalid api version shall raise error - ) - await poller.result() - - poller = await client.virtual_machines.begin_create_or_update( - resource_group_name=resource_group_name, vm_name=vm_name, resource=vm_resource - ) - - result = await poller.result() - assert result is not None - assert isinstance(result, VirtualMachine) - assert result.location == "eastus" - - -@pytest.mark.asyncio -async def test_disks_get(client): - resource_group_name = "test-rg" - disk_name = "disk1" - with pytest.raises(HttpResponseError): - await client.disks.get( - resource_group_name=resource_group_name, - disk_name=disk_name, - api_version="av1", # invalid api version shall raise error - ) - - result = await client.disks.get(resource_group_name=resource_group_name, disk_name=disk_name) - - assert result is not None - assert isinstance(result, Disk) - assert result.name == disk_name - - -@pytest.mark.asyncio -async def test_disks_create_or_update(client): - resource_group_name = "test-rg" - disk_name = "disk1" - - disk_resource = Disk(location="eastus", properties={}) - - with pytest.raises(HttpResponseError): - poller = await client.disks.begin_create_or_update( - resource_group_name=resource_group_name, - disk_name=disk_name, - resource=disk_resource, - api_version="av1", # invalid api version shall raise error - ) - await poller.result() - - poller = await client.disks.begin_create_or_update( - resource_group_name=resource_group_name, disk_name=disk_name, resource=disk_resource - ) - - result = await poller.result() - assert result is not None - assert isinstance(result, Disk) - assert result.location == "eastus" diff --git a/packages/typespec-python/tests/mock_api/azure/asynctests/test_azure_resource_manager_multi_service_shared_models_async.py b/packages/typespec-python/tests/mock_api/azure/asynctests/test_azure_resource_manager_multi_service_shared_models_async.py deleted file mode 100644 index ee1c21bfbe..0000000000 --- a/packages/typespec-python/tests/mock_api/azure/asynctests/test_azure_resource_manager_multi_service_shared_models_async.py +++ /dev/null @@ -1,132 +0,0 @@ -# ------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for -# license information. -# -------------------------------------------------------------------------- -import pytest -from azure.resourcemanager.multiservicesharedmodels.combined.aio import CombinedClient -from azure.resourcemanager.multiservicesharedmodels.combined.models import ( - VirtualMachine, - VirtualMachineProperties, - StorageAccount, - StorageAccountProperties, - SharedMetadata, -) - - -@pytest.fixture -async def client(credential, authentication_policy): - """Create a Combined async client for testing.""" - return CombinedClient( - credential=credential, - subscription_id="00000000-0000-0000-0000-000000000000", - base_url="http://localhost:3000", - authentication_policy=authentication_policy, - polling_interval=0.1, - ) - - -@pytest.mark.asyncio -async def test_virtual_machines_get(client): - """Test getting a virtual machine with shared metadata.""" - resource_group_name = "test-rg" - vm_name = "vm-shared1" - - result = await client.virtual_machines.get(resource_group_name=resource_group_name, vm_name=vm_name) - - assert result is not None - assert isinstance(result, VirtualMachine) - assert result.name == vm_name - assert result.location == "eastus" - assert result.type == "Microsoft.Compute/virtualMachinesShared" - assert result.properties is not None - assert result.properties.provisioning_state == "Succeeded" - assert result.properties.metadata is not None - assert result.properties.metadata.created_by == "user@example.com" - assert result.properties.metadata.tags == {"environment": "production"} - - -@pytest.mark.asyncio -async def test_virtual_machines_create_or_update(client): - """Test creating or updating a virtual machine with shared metadata.""" - resource_group_name = "test-rg" - vm_name = "vm-shared1" - - vm_resource = VirtualMachine( - location="eastus", - properties=VirtualMachineProperties( - metadata=SharedMetadata( - created_by="user@example.com", - tags={"environment": "production"}, - ), - ), - ) - - poller = await client.virtual_machines.begin_create_or_update( - resource_group_name=resource_group_name, - vm_name=vm_name, - resource=vm_resource, - ) - - result = await poller.result() - assert result is not None - assert isinstance(result, VirtualMachine) - assert result.location == "eastus" - assert result.properties is not None - assert result.properties.provisioning_state == "Succeeded" - assert result.properties.metadata is not None - assert result.properties.metadata.created_by == "user@example.com" - assert result.properties.metadata.tags == {"environment": "production"} - - -@pytest.mark.asyncio -async def test_storage_accounts_get(client): - """Test getting a storage account with shared metadata.""" - resource_group_name = "test-rg" - account_name = "account1" - - result = await client.storage_accounts.get(resource_group_name=resource_group_name, account_name=account_name) - - assert result is not None - assert isinstance(result, StorageAccount) - assert result.name == account_name - assert result.location == "westus" - assert result.type == "Microsoft.Storage/storageAccounts" - assert result.properties is not None - assert result.properties.provisioning_state == "Succeeded" - assert result.properties.metadata is not None - assert result.properties.metadata.created_by == "admin@example.com" - assert result.properties.metadata.tags == {"department": "engineering"} - - -@pytest.mark.asyncio -async def test_storage_accounts_create_or_update(client): - """Test creating or updating a storage account with shared metadata.""" - resource_group_name = "test-rg" - account_name = "account1" - - storage_resource = StorageAccount( - location="westus", - properties=StorageAccountProperties( - metadata=SharedMetadata( - created_by="admin@example.com", - tags={"department": "engineering"}, - ), - ), - ) - - poller = await client.storage_accounts.begin_create_or_update( - resource_group_name=resource_group_name, - account_name=account_name, - resource=storage_resource, - ) - - result = await poller.result() - assert result is not None - assert isinstance(result, StorageAccount) - assert result.location == "westus" - assert result.properties is not None - assert result.properties.provisioning_state == "Succeeded" - assert result.properties.metadata is not None - assert result.properties.metadata.created_by == "admin@example.com" - assert result.properties.metadata.tags == {"department": "engineering"} diff --git a/packages/typespec-python/tests/mock_api/azure/asynctests/test_azure_special_headers_client_request_id_async.py b/packages/typespec-python/tests/mock_api/azure/asynctests/test_azure_special_headers_client_request_id_async.py deleted file mode 100644 index b89ee4b732..0000000000 --- a/packages/typespec-python/tests/mock_api/azure/asynctests/test_azure_special_headers_client_request_id_async.py +++ /dev/null @@ -1,30 +0,0 @@ -# ------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for -# license information. -# -------------------------------------------------------------------------- -import functools - -import pytest - -from azure.specialheaders.xmsclientrequestid.aio import XmsClientRequestIdClient - - -@pytest.fixture -async def client(): - async with XmsClientRequestIdClient() as client: - yield client - - -@pytest.mark.asyncio -async def test_get(client: XmsClientRequestIdClient, check_client_request_id_header): - checked = {} - result, resp = await client.get( - cls=lambda x, y, z: (y, x), - raw_request_hook=functools.partial( - check_client_request_id_header, header="x-ms-client-request-id", checked=checked - ), - ) - assert result is None - assert resp.http_response.headers["x-ms-client-request-id"] == checked["x-ms-client-request-id"] - pass diff --git a/packages/typespec-python/tests/mock_api/azure/asynctests/test_azure_versioning_previewversion_async.py b/packages/typespec-python/tests/mock_api/azure/asynctests/test_azure_versioning_previewversion_async.py deleted file mode 100644 index 512e69c817..0000000000 --- a/packages/typespec-python/tests/mock_api/azure/asynctests/test_azure_versioning_previewversion_async.py +++ /dev/null @@ -1,53 +0,0 @@ -# ------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for -# license information. -# -------------------------------------------------------------------------- -import pytest -from specs.azure.versioning.previewversion.aio import PreviewVersionClient -from specs.azure.versioning.previewversion.models import UpdateWidgetColorRequest - - -@pytest.fixture -async def client(): - async with PreviewVersionClient() as client: - yield client - - -@pytest.fixture -async def stable_client(): - async with PreviewVersionClient(api_version="2024-06-01") as client: - yield client - - -@pytest.mark.asyncio -async def test_get_widget(client: PreviewVersionClient): - result = await client.get_widget(id="widget-123") - assert result.id == "widget-123" - assert result.name == "Sample Widget" - assert result.color == "blue" - - -@pytest.mark.asyncio -async def test_update_widget_color(client: PreviewVersionClient): - color_update = UpdateWidgetColorRequest(color="red") - result = await client.update_widget_color(id="widget-123", color_update=color_update) - assert result.id == "widget-123" - assert result.name == "Sample Widget" - assert result.color == "red" - - with pytest.raises(ValueError): - async with PreviewVersionClient(api_version="2024-06-01") as stable_client: - await stable_client.update_widget_color(id="widget-123", color_update=color_update) - - -@pytest.mark.asyncio -async def test_list_widgets(stable_client: PreviewVersionClient): - result = await stable_client.list_widgets(name="test") - assert len(result.widgets) == 1 - assert result.widgets[0].id == "widget-1" - assert result.widgets[0].name == "test" - - with pytest.raises(ValueError): - async with PreviewVersionClient(api_version="2024-06-01") as client: - await client.list_widgets(name="test", color="test") diff --git a/packages/typespec-python/tests/mock_api/azure/asynctests/test_client_namespace_async.py b/packages/typespec-python/tests/mock_api/azure/asynctests/test_client_namespace_async.py deleted file mode 100644 index adc98e3d56..0000000000 --- a/packages/typespec-python/tests/mock_api/azure/asynctests/test_client_namespace_async.py +++ /dev/null @@ -1,34 +0,0 @@ -# ------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for -# license information. -# -------------------------------------------------------------------------- -import pytest -from client.clientnamespace.aio import ClientNamespaceFirstClient -from client.clientnamespace.first.models import FirstClientResult - -from client.clientnamespace.second.aio import ClientNamespaceSecondClient -from client.clientnamespace.second.models import SecondClientResult -from client.clientnamespace.second.sub.models import SecondClientEnumType - - -@pytest.fixture -async def first_client(): - async with ClientNamespaceFirstClient() as client: - yield client - - -@pytest.fixture -async def second_client(): - async with ClientNamespaceSecondClient() as client: - yield client - - -@pytest.mark.asyncio -async def test_get_first(first_client: ClientNamespaceFirstClient): - assert await first_client.get_first() == FirstClientResult(name="first") - - -@pytest.mark.asyncio -async def test_get_second(second_client: ClientNamespaceSecondClient): - assert await second_client.get_second() == SecondClientResult(type=SecondClientEnumType.SECOND) diff --git a/packages/typespec-python/tests/mock_api/azure/asynctests/test_client_naming_async.py b/packages/typespec-python/tests/mock_api/azure/asynctests/test_client_naming_async.py deleted file mode 100644 index 4ccd786e80..0000000000 --- a/packages/typespec-python/tests/mock_api/azure/asynctests/test_client_naming_async.py +++ /dev/null @@ -1,69 +0,0 @@ -# ------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for -# license information. -# -------------------------------------------------------------------------- -import pytest -from client.naming.main.aio import NamingClient -from client.naming.main import models - - -@pytest.fixture -async def client(): - async with NamingClient() as client: - yield client - - -@pytest.mark.asyncio -async def test_client(client: NamingClient): - await client.property.client(models.ClientNameModel(client_name=True)) - - -@pytest.mark.asyncio -async def test_language(client: NamingClient): - await client.property.language(models.LanguageClientNameModel(python_name=True)) - - -@pytest.mark.asyncio -async def test_compatible_with_encoded_name(client: NamingClient): - await client.property.compatible_with_encoded_name(models.ClientNameAndJsonEncodedNameModel(client_name=True)) - - -@pytest.mark.asyncio -async def test_operation(client: NamingClient): - await client.client_name() - - -@pytest.mark.asyncio -async def test_parameter(client: NamingClient): - await client.parameter(client_name="true") - - -@pytest.mark.asyncio -async def test_header_request(client: NamingClient): - await client.header.request(client_name="true") - - -@pytest.mark.asyncio -async def test_header_response(client: NamingClient): - assert (await client.header.response(cls=lambda x, y, z: z))["default-name"] == "true" - - -@pytest.mark.asyncio -async def test_model_client(client: NamingClient): - await client.model_client.client(models.ClientModel(default_name=True)) - - -@pytest.mark.asyncio -async def test_model_language(client: NamingClient): - await client.model_client.language(models.PythonModel(default_name=True)) - - -@pytest.mark.asyncio -async def test_union_enum_member_name(client: NamingClient): - await client.union_enum.union_enum_member_name(models.ExtensibleEnum.CLIENT_ENUM_VALUE1) - - -@pytest.mark.asyncio -async def test_union_enum_name(client: NamingClient): - await client.union_enum.union_enum_name(models.ClientExtensibleEnum.ENUM_VALUE1) diff --git a/packages/typespec-python/tests/mock_api/azure/asynctests/test_client_naming_enum_conflict_async.py b/packages/typespec-python/tests/mock_api/azure/asynctests/test_client_naming_enum_conflict_async.py deleted file mode 100644 index 27b7731d98..0000000000 --- a/packages/typespec-python/tests/mock_api/azure/asynctests/test_client_naming_enum_conflict_async.py +++ /dev/null @@ -1,37 +0,0 @@ -# ------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for -# license information. -# -------------------------------------------------------------------------- -import pytest -from client.naming.enumconflict.aio import EnumConflictClient -from client.naming.enumconflict.firstnamespace import models as first_models -from client.naming.enumconflict.secondnamespace import models as second_models - - -@pytest.fixture -async def client(): - async with EnumConflictClient() as client: - yield client - - -@pytest.mark.asyncio -async def test_first_operations_first_async(client: EnumConflictClient): - """Test enum with same name in different namespace - first namespace (async).""" - body = first_models.FirstModel(status=first_models.Status.ACTIVE, name="test") - - response = await client.first_operations.first(body=body) - - assert response.status == "active" - assert response.name == "test" - - -@pytest.mark.asyncio -async def test_second_operations_second_async(client: EnumConflictClient): - """Test enum with same name in different namespace - second namespace (async).""" - body = second_models.SecondModel(status=second_models.SecondStatus.RUNNING, description="test description") - - response = await client.second_operations.second(body=body) - - assert response.status == "running" - assert response.description == "test description" diff --git a/packages/typespec-python/tests/mock_api/azure/asynctests/test_client_overload_async.py b/packages/typespec-python/tests/mock_api/azure/asynctests/test_client_overload_async.py deleted file mode 100644 index 4d4e04cbe7..0000000000 --- a/packages/typespec-python/tests/mock_api/azure/asynctests/test_client_overload_async.py +++ /dev/null @@ -1,27 +0,0 @@ -import pytest -from client.overload.aio import OverloadClient - - -class TestClientOverloadAsync: - @pytest.fixture - def client(self): - return OverloadClient(endpoint="http://localhost:3000") - - @pytest.mark.asyncio - async def test_list(self, client: OverloadClient): - result = await client.list() - assert len(result) == 2 - assert result[0]["id"] == "1" - assert result[0]["name"] == "foo" - assert result[0]["scope"] == "car" - assert result[1]["id"] == "2" - assert result[1]["name"] == "bar" - assert result[1]["scope"] == "bike" - - @pytest.mark.asyncio - async def test_list_by_scope(self, client: OverloadClient): - result = await client.list_by_scope("car") - assert len(result) == 1 - assert result[0]["id"] == "1" - assert result[0]["name"] == "foo" - assert result[0]["scope"] == "car" diff --git a/packages/typespec-python/tests/mock_api/azure/asynctests/test_client_structure_async.py b/packages/typespec-python/tests/mock_api/azure/asynctests/test_client_structure_async.py deleted file mode 100644 index fa58bd0f75..0000000000 --- a/packages/typespec-python/tests/mock_api/azure/asynctests/test_client_structure_async.py +++ /dev/null @@ -1,64 +0,0 @@ -# ------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for -# license information. -# -------------------------------------------------------------------------- -import pytest -from client.structure.service.models import ClientType -from client.structure.service.aio import ServiceClient -from client.structure.multiclient.aio import ClientAClient, ClientBClient -from client.structure.renamedoperation.aio import RenamedOperationClient -from client.structure.twooperationgroup.aio import TwoOperationGroupClient - - -@pytest.mark.asyncio -async def test_structure_default(): - client = ServiceClient(endpoint="http://localhost:3000", client=ClientType.DEFAULT) - await client.one() - await client.two() - await client.foo.three() - await client.foo.four() - await client.bar.five() - await client.bar.six() - await client.baz.foo.seven() - await client.qux.eight() - await client.qux.bar.nine() - - -@pytest.mark.asyncio -async def test_structure_multiclient(): - client_a = ClientAClient(endpoint="http://localhost:3000", client=ClientType.MULTI_CLIENT) - await client_a.renamed_one() - await client_a.renamed_three() - await client_a.renamed_five() - - client_b = ClientBClient(endpoint="http://localhost:3000", client=ClientType.MULTI_CLIENT) - await client_b.renamed_two() - await client_b.renamed_four() - await client_b.renamed_six() - - -@pytest.mark.skip(reason="will reopen the cases after upgrade `@azure-tools/typespec-client-generator-core` to 0.67.0") -@pytest.mark.asyncio -async def test_structure_renamed_operation(): - client = RenamedOperationClient(endpoint="http://localhost:3000", client=ClientType.RENAMED_OPERATION) - await client.renamed_one() - await client.renamed_three() - await client.renamed_five() - - await client.renamed_two() - await client.renamed_four() - await client.renamed_six() - - -@pytest.mark.skip(reason="will reopen the cases after upgrade `@azure-tools/typespec-client-generator-core` to 0.67.0") -@pytest.mark.asyncio -async def test_structure_two_operation_group(): - client = TwoOperationGroupClient(endpoint="http://localhost:3000", client=ClientType.TWO_OPERATION_GROUP) - await client.one() - await client.three() - await client.four() - - await client.two() - await client.five() - await client.six() diff --git a/packages/typespec-python/tests/mock_api/azure/asynctests/test_client_structure_clientoperationgroup_async.py b/packages/typespec-python/tests/mock_api/azure/asynctests/test_client_structure_clientoperationgroup_async.py deleted file mode 100644 index 0b3ba88d30..0000000000 --- a/packages/typespec-python/tests/mock_api/azure/asynctests/test_client_structure_clientoperationgroup_async.py +++ /dev/null @@ -1,31 +0,0 @@ -# ------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for -# license information. -# -------------------------------------------------------------------------- -import pytest -from client.structure.clientoperationgroup.models import ClientType -from client.structure.clientoperationgroup.aio import FirstClient, SecondClient - - -@pytest.mark.skip(reason="will reopen the cases after upgrade `@azure-tools/typespec-client-generator-core` to 0.67.0") -@pytest.mark.asyncio -async def test_first_client_operations(): - client = FirstClient(endpoint="http://localhost:3000", client=ClientType.CLIENT_OPERATION_GROUP) - - await client.one() - - await client.two() - await client.three() - - await client.four() - - -@pytest.mark.skip(reason="will reopen the cases after upgrade `@azure-tools/typespec-client-generator-core` to 0.67.0") -@pytest.mark.asyncio -async def test_second_client_operations(): - client = SecondClient(endpoint="http://localhost:3000", client=ClientType.CLIENT_OPERATION_GROUP) - - await client.five() - - await client.six() diff --git a/packages/typespec-python/tests/mock_api/azure/asynctests/test_encode_duration_async.py b/packages/typespec-python/tests/mock_api/azure/asynctests/test_encode_duration_async.py deleted file mode 100644 index 0fca037194..0000000000 --- a/packages/typespec-python/tests/mock_api/azure/asynctests/test_encode_duration_async.py +++ /dev/null @@ -1,63 +0,0 @@ -# ------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for -# license information. -# -------------------------------------------------------------------------- -import datetime - -import pytest -from encode.duration.aio import DurationClient -from encode.duration.models import ( - Int32SecondsDurationProperty, - ISO8601DurationProperty, - FloatSecondsDurationProperty, - DefaultDurationProperty, - FloatSecondsDurationArrayProperty, -) - - -@pytest.fixture -async def client(): - async with DurationClient() as client: - yield client - - -@pytest.mark.asyncio -async def test_query(client: DurationClient): - await client.query.default(input=datetime.timedelta(days=40)) - await client.query.iso8601(input=datetime.timedelta(days=40)) - await client.query.int32_seconds(input=36) - await client.query.int32_seconds_array(input=[36, 47]) - await client.query.float_seconds(input=35.625) - await client.query.float64_seconds(input=35.625) - - -@pytest.mark.asyncio -async def test_property(client: DurationClient): - result = await client.property.default(DefaultDurationProperty(value=datetime.timedelta(days=40))) - assert result.value == datetime.timedelta(days=40) - result = await client.property.default(DefaultDurationProperty(value="P40D")) - assert result.value == datetime.timedelta(days=40) - result = await client.property.iso8601(ISO8601DurationProperty(value=datetime.timedelta(days=40))) - assert result.value == datetime.timedelta(days=40) - result = await client.property.iso8601(ISO8601DurationProperty(value="P40D")) - assert result.value == datetime.timedelta(days=40) - result = await client.property.int32_seconds(Int32SecondsDurationProperty(value=36)) - assert result.value == 36 - result = await client.property.float_seconds(FloatSecondsDurationProperty(value=35.625)) - assert abs(result.value - 35.625) < 0.0001 - result = await client.property.float64_seconds(FloatSecondsDurationProperty(value=35.625)) - assert abs(result.value - 35.625) < 0.0001 - result = await client.property.float_seconds_array(FloatSecondsDurationArrayProperty(value=[35.625, 46.75])) - assert abs(result.value[0] - 35.625) < 0.0001 - assert abs(result.value[1] - 46.75) < 0.0001 - - -@pytest.mark.asyncio -async def test_header(client: DurationClient): - await client.header.default(duration=datetime.timedelta(days=40)) - await client.header.iso8601(duration=datetime.timedelta(days=40)) - await client.header.iso8601_array(duration=[datetime.timedelta(days=40), datetime.timedelta(days=50)]) - await client.header.int32_seconds(duration=36) - await client.header.float_seconds(duration=35.625) - await client.header.float64_seconds(duration=35.625) diff --git a/packages/typespec-python/tests/mock_api/azure/asynctests/test_encode_numeric_async.py b/packages/typespec-python/tests/mock_api/azure/asynctests/test_encode_numeric_async.py deleted file mode 100644 index 7bd8b5e1f5..0000000000 --- a/packages/typespec-python/tests/mock_api/azure/asynctests/test_encode_numeric_async.py +++ /dev/null @@ -1,35 +0,0 @@ -# ------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for -# license information. -# -------------------------------------------------------------------------- -import pytest -from encode.numeric.aio import NumericClient -from encode.numeric import models - - -@pytest.fixture -async def client(): - async with NumericClient() as client: - yield client - - -@pytest.mark.asyncio -async def test_safeint_as_string(client: NumericClient): - result = await client.property.safeint_as_string(models.SafeintAsStringProperty(value=10000000000)) - assert result.value == 10000000000 - assert result["value"] == "10000000000" - - -@pytest.mark.asyncio -async def test_uint32_as_string_optional(client: NumericClient): - result = await client.property.uint32_as_string_optional(models.Uint32AsStringProperty(value=1)) - assert result.value == 1 - assert result["value"] == "1" - - -@pytest.mark.asyncio -async def test_uint8_as_string_optional(client: NumericClient): - result = await client.property.uint8_as_string(models.Uint32AsStringProperty(value=255)) - assert result.value == 255 - assert result["value"] == "255" diff --git a/packages/typespec-python/tests/mock_api/azure/asynctests/test_parameters_basic_async.py b/packages/typespec-python/tests/mock_api/azure/asynctests/test_parameters_basic_async.py deleted file mode 100644 index 969e73a6c8..0000000000 --- a/packages/typespec-python/tests/mock_api/azure/asynctests/test_parameters_basic_async.py +++ /dev/null @@ -1,24 +0,0 @@ -# ------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for -# license information. -# -------------------------------------------------------------------------- -import pytest -from parameters.basic.aio import BasicClient -from parameters.basic.models import User - - -@pytest.fixture -async def client(): - async with BasicClient() as client: - yield client - - -@pytest.mark.asyncio -async def test_explicit_simple(client: BasicClient): - await client.explicit_body.simple(User(name="foo")) - - -@pytest.mark.asyncio -async def test_implicit_simple(client: BasicClient): - await client.implicit_body.simple(name="foo") diff --git a/packages/typespec-python/tests/mock_api/azure/asynctests/test_parameters_spread_async.py b/packages/typespec-python/tests/mock_api/azure/asynctests/test_parameters_spread_async.py deleted file mode 100644 index 74032d8e51..0000000000 --- a/packages/typespec-python/tests/mock_api/azure/asynctests/test_parameters_spread_async.py +++ /dev/null @@ -1,76 +0,0 @@ -# ------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for -# license information. -# -------------------------------------------------------------------------- -import pytest -from parameters.spread.aio import SpreadClient -from parameters.spread.models import BodyParameter - - -@pytest.fixture -async def client(): - async with SpreadClient() as client: - yield client - - -@pytest.mark.asyncio -async def test_model_body(client: SpreadClient): - await client.model.spread_as_request_body(name="foo") - - -@pytest.mark.asyncio -async def test_model_composite_request_only_with_body(client: SpreadClient): - await client.model.spread_composite_request_only_with_body(BodyParameter(name="foo")) - - -@pytest.mark.asyncio -async def test_model_composite_request_without_body(client: SpreadClient): - await client.model.spread_composite_request_without_body(name="foo", test_header="bar") - - -@pytest.mark.asyncio -async def test_model_composite_request(client: SpreadClient): - await client.model.spread_composite_request(name="foo", body=BodyParameter(name="foo"), test_header="bar") - - -@pytest.mark.asyncio -async def test_model_composite_request_mix(client: SpreadClient): - await client.model.spread_composite_request_mix(name="foo", prop="foo", test_header="bar") - - -@pytest.mark.asyncio -async def test_alias_body(client: SpreadClient): - await client.alias.spread_as_request_body(name="foo") - - -@pytest.mark.asyncio -async def test_alias_parameter(client: SpreadClient): - await client.alias.spread_as_request_parameter("1", x_ms_test_header="bar", name="foo") - - -@pytest.mark.asyncio -async def test_alias_multiple_parameter(client: SpreadClient): - await client.alias.spread_with_multiple_parameters( - "1", - x_ms_test_header="bar", - required_string="foo", - required_int_list=[1, 2], - optional_string_list=["foo", "bar"], - optional_int=1, - ) - await client.alias.spread_with_multiple_parameters( - "1", - {"requiredString": "foo", "optionalInt": 1, "requiredIntList": [1, 2], "optionalStringList": ["foo", "bar"]}, - x_ms_test_header="bar", - ) - - -@pytest.mark.asyncio -async def test_inner_model(client: SpreadClient): - await client.alias.spread_parameter_with_inner_model(id="1", x_ms_test_header="bar", body={"name": "foo"}) - - -@pytest.mark.asyncio -async def test_inner_alias(client: SpreadClient): - await client.alias.spread_parameter_with_inner_alias(id="1", x_ms_test_header="bar", body={"name": "foo", "age": 1}) diff --git a/packages/typespec-python/tests/mock_api/azure/asynctests/test_payload_content_negotiation_async.py b/packages/typespec-python/tests/mock_api/azure/asynctests/test_payload_content_negotiation_async.py deleted file mode 100644 index 4c2a11f61a..0000000000 --- a/packages/typespec-python/tests/mock_api/azure/asynctests/test_payload_content_negotiation_async.py +++ /dev/null @@ -1,37 +0,0 @@ -# ------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for -# license information. -# -------------------------------------------------------------------------- -import base64 -import pytest -from payload.contentnegotiation.aio import ContentNegotiationClient -from payload.contentnegotiation.models import PngImageAsJson - - -@pytest.fixture -async def client(): - async with ContentNegotiationClient(endpoint="http://localhost:3000") as client: - yield client - - -@pytest.mark.asyncio -async def test_get_avatar_as_png(client: ContentNegotiationClient, png_data: bytes): - assert b"".join([d async for d in (await client.same_body.get_avatar_as_png())]) == png_data - - -@pytest.mark.asyncio -async def test_get_avatar_as_jpeg(client: ContentNegotiationClient, jpg_data: bytes): - assert b"".join([d async for d in (await client.same_body.get_avatar_as_jpeg())]) == jpg_data - - -@pytest.mark.asyncio -async def test_different_body_get_avatar_as_png(client: ContentNegotiationClient, png_data: bytes): - assert b"".join([d async for d in (await client.different_body.get_avatar_as_png())]) == png_data - - -@pytest.mark.asyncio -async def test_different_body_get_avatar_as_json(client: ContentNegotiationClient, png_data: bytes): - result = await client.different_body.get_avatar_as_json() - expected = PngImageAsJson(content=base64.b64encode(png_data).decode()) - assert result == expected diff --git a/packages/typespec-python/tests/mock_api/azure/asynctests/test_payload_multipart_async.py b/packages/typespec-python/tests/mock_api/azure/asynctests/test_payload_multipart_async.py deleted file mode 100644 index 5cd750c8c0..0000000000 --- a/packages/typespec-python/tests/mock_api/azure/asynctests/test_payload_multipart_async.py +++ /dev/null @@ -1,216 +0,0 @@ -# ------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for -# license information. -# -------------------------------------------------------------------------- -from pathlib import Path -import pytest -from payload.multipart import models -from payload.multipart.aio import MultiPartClient - -JPG = Path(__file__).parent.parent / "data/image.jpg" -PNG = Path(__file__).parent.parent / "data/image.png" - - -@pytest.fixture -async def client(): - async with MultiPartClient(endpoint="http://localhost:3000") as client: - yield client - - -@pytest.mark.asyncio -async def test_anonymous_model(client: MultiPartClient): - await client.form_data.anonymous_model({"profileImage": open(str(JPG), "rb")}) - - -@pytest.mark.asyncio -async def test_basic(client: MultiPartClient): - await client.form_data.basic( - models.MultiPartRequest( - id="123", - profile_image=open(str(JPG), "rb"), - ) - ) - - -@pytest.mark.asyncio -async def test_binary_array_parts(client: MultiPartClient): - await client.form_data.binary_array_parts( - models.BinaryArrayPartsRequest( - id="123", - pictures=[ - open(str(PNG), "rb"), - open(str(PNG), "rb"), - ], - ) - ) - - -@pytest.mark.asyncio -async def test_check_file_name_and_content_type(client: MultiPartClient): - await client.form_data.check_file_name_and_content_type( - models.MultiPartRequest( - id="123", - profile_image=("hello.jpg", open(str(JPG), "rb"), "image/jpg"), - ) - ) - - -@pytest.mark.asyncio -async def test_complex(client: MultiPartClient): - await client.form_data.file_array_and_basic( - models.ComplexPartsRequest( - id="123", - address=models.Address(city="X"), - pictures=[ - open(str(PNG), "rb"), - open(str(PNG), "rb"), - ], - profile_image=open(str(JPG), "rb"), - ) - ) - - -@pytest.mark.asyncio -async def test_json_part(client: MultiPartClient): - await client.form_data.json_part( - models.JsonPartRequest( - address=models.Address(city="X"), - profile_image=open(str(JPG), "rb"), - ) - ) - - -@pytest.mark.asyncio -async def test_multi_binary_parts(client: MultiPartClient): - await client.form_data.multi_binary_parts( - models.MultiBinaryPartsRequest( - profile_image=open(str(JPG), "rb"), - picture=open(str(PNG), "rb"), - ) - ) - await client.form_data.multi_binary_parts( - models.MultiBinaryPartsRequest( - profile_image=open(str(JPG), "rb"), - ) - ) - - -@pytest.mark.asyncio -async def test_file_with_http_part_specific_content_type(client: MultiPartClient): - await client.form_data.http_parts.content_type.image_jpeg_content_type( - models.FileWithHttpPartSpecificContentTypeRequest( - profile_image=("hello.jpg", open(str(JPG), "rb"), "image/jpg"), - ) - ) - - -@pytest.mark.asyncio -async def test_file_with_http_part_required_content_type(client: MultiPartClient): - await client.form_data.http_parts.content_type.required_content_type( - models.FileWithHttpPartRequiredContentTypeRequest( - profile_image=open(str(JPG), "rb"), - ) - ) - - -@pytest.mark.asyncio -async def test_file_with_http_part_optional_content_type(client: MultiPartClient): - # call twice: one with content type, one without - await client.form_data.http_parts.content_type.optional_content_type( - models.FileWithHttpPartOptionalContentTypeRequest( - profile_image=("hello.jpg", open(str(JPG), "rb").read()), - ) - ) - await client.form_data.http_parts.content_type.optional_content_type( - models.FileWithHttpPartOptionalContentTypeRequest( - profile_image=("hello.jpg", open(str(JPG), "rb").read(), "application/octet-stream"), - ) - ) - - -@pytest.mark.asyncio -async def test_complex_with_http_part(client: MultiPartClient): - await client.form_data.http_parts.json_array_and_file_array( - models.ComplexHttpPartsModelRequest( - id="123", - previous_addresses=[ - models.Address(city="Y"), - models.Address(city="Z"), - ], - address=models.Address(city="X"), - pictures=[ - open(str(PNG), "rb"), - open(str(PNG), "rb"), - ], - profile_image=open(str(JPG), "rb"), - ) - ) - - -@pytest.mark.asyncio -async def test_http_parts_non_string_float(client: MultiPartClient): - await client.form_data.http_parts.non_string.float(models.FloatRequest(temperature=0.5)) - - -@pytest.mark.asyncio -async def test_with_wire_name(client: MultiPartClient): - await client.form_data.with_wire_name( - models.MultiPartRequestWithWireName( - identifier="123", - image=open(str(JPG), "rb"), - ) - ) - - -@pytest.mark.asyncio -async def test_optional_parts(client: MultiPartClient): - # First time with only id - await client.form_data.optional_parts( - models.MultiPartOptionalRequest( - id="123", - ) - ) - # Second time with only profileImage - await client.form_data.optional_parts( - models.MultiPartOptionalRequest( - profile_image=open(str(JPG), "rb"), - ) - ) - # Third time with both id and profileImage - await client.form_data.optional_parts( - models.MultiPartOptionalRequest( - id="123", - profile_image=open(str(JPG), "rb"), - ) - ) - - -@pytest.mark.asyncio -async def test_file_upload_file_specific_content_type(client: MultiPartClient): - await client.form_data.file.upload_file_specific_content_type( - models.UploadFileSpecificContentTypeRequest( - file=("image.png", open(str(PNG), "rb"), "image/png"), - ) - ) - - -@pytest.mark.asyncio -async def test_file_upload_file_required_filename(client: MultiPartClient): - await client.form_data.file.upload_file_required_filename( - models.UploadFileRequiredFilenameRequest( - file=("image.png", open(str(PNG), "rb"), "image/png"), - ) - ) - - -@pytest.mark.asyncio -async def test_file_upload_file_array(client: MultiPartClient): - await client.form_data.file.upload_file_array( - models.UploadFileArrayRequest( - files=[ - ("image.png", open(str(PNG), "rb"), "image/png"), - ("image.png", open(str(PNG), "rb"), "image/png"), - ], - ) - ) diff --git a/packages/typespec-python/tests/mock_api/azure/asynctests/test_resiliency_srv_driven_async.py b/packages/typespec-python/tests/mock_api/azure/asynctests/test_resiliency_srv_driven_async.py deleted file mode 100644 index 290e3b68cb..0000000000 --- a/packages/typespec-python/tests/mock_api/azure/asynctests/test_resiliency_srv_driven_async.py +++ /dev/null @@ -1,130 +0,0 @@ -# ------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for -# license information. -# -------------------------------------------------------------------------- -import pytest -from resiliency.srv.driven1.aio import ResiliencyServiceDrivenClient as V1Client -from resiliency.srv.driven2.aio import ResiliencyServiceDrivenClient as V2Client - - -def get_v1_client(service_deployment_version: str, api_version: str = "v1") -> V1Client: - return V1Client( - endpoint="http://localhost:3000", - service_deployment_version=service_deployment_version, - api_version=api_version, - ) - - -def get_v2_client(service_deployment_version: str, api_version: str = "v2") -> V2Client: - return V2Client( - endpoint="http://localhost:3000", - service_deployment_version=service_deployment_version, - api_version=api_version, - ) - - -@pytest.mark.asyncio -async def test_add_optional_param_from_none(): - # old client to old service with api version v1 - async with V1Client(endpoint="http://localhost:3000", service_deployment_version="v1") as client: - await client.from_none() - - # old client to new service with api version v1 - async with V1Client(endpoint="http://localhost:3000", service_deployment_version="v2") as client: - await client.from_none() - - # new client to new service with api version v1 - async with V2Client( - endpoint="http://localhost:3000", - service_deployment_version="v2", - api_version="v1", - ) as client: - await client.from_none() - - # new client to new service with api version v2 - async with V2Client(endpoint="http://localhost:3000", service_deployment_version="v2") as client: - await client.from_none(new_parameter="new") - - -@pytest.mark.asyncio -async def test_add_optional_param_from_one_required(): - # old client to old service with api version v1 - async with V1Client(endpoint="http://localhost:3000", service_deployment_version="v1") as client: - await client.from_one_required(parameter="required") - - # old client to new service with api version v1 - async with V1Client(endpoint="http://localhost:3000", service_deployment_version="v2") as client: - await client.from_one_required(parameter="required") - - # new client to new service with api version v1 - async with V2Client( - endpoint="http://localhost:3000", - service_deployment_version="v2", - api_version="v1", - ) as client: - await client.from_one_required(parameter="required") - - # new client to new service with api version v2 - async with V2Client(endpoint="http://localhost:3000", service_deployment_version="v2") as client: - await client.from_one_required(parameter="required", new_parameter="new") - - -@pytest.mark.asyncio -async def test_add_optional_param_from_one_optional(): - # old client to old service with api version v1 - async with V1Client(endpoint="http://localhost:3000", service_deployment_version="v1") as client: - await client.from_one_optional(parameter="optional") - - # old client to new service with api version v1 - async with V1Client(endpoint="http://localhost:3000", service_deployment_version="v2") as client: - await client.from_one_optional(parameter="optional") - - # new client to new service with api version v1 - async with V2Client( - endpoint="http://localhost:3000", - service_deployment_version="v2", - api_version="v1", - ) as client: - await client.from_one_optional(parameter="optional") - - # new client to new service with api version v2 - async with V2Client(endpoint="http://localhost:3000", service_deployment_version="v2") as client: - await client.from_one_optional(parameter="optional", new_parameter="new") - - -@pytest.mark.asyncio -async def test_break_the_glass(): - from azure.core.rest import HttpRequest - - request = HttpRequest(method="DELETE", url="/add-operation") - async with V1Client( - endpoint="http://localhost:3000", - service_deployment_version="v2", - api_version="v2", - ) as client: - response = await client.send_request(request) - response.raise_for_status() - - -@pytest.mark.asyncio -async def test_add_operation(): - async with V2Client(endpoint="http://localhost:3000", service_deployment_version="v2") as client: - await client.add_operation() - - -@pytest.mark.parametrize( - "func_name, params", - [ - ("from_none", {"new_parameter": "new"}), - ("from_one_optional", {"parameter": "optional", "new_parameter": "new"}), - ("from_one_required", {"parameter": "required", "new_parameter": "new"}), - ("add_operation", {}), - ], -) -@pytest.mark.asyncio -async def test_new_client_with_old_apiversion_call_new_parameter(func_name, params): - client = get_v2_client(service_deployment_version="v2", api_version="v1") - with pytest.raises(ValueError) as ex: - await getattr(client, func_name)(**params) - assert "is not available in API version" in str(ex.value) diff --git a/packages/typespec-python/tests/mock_api/azure/asynctests/test_serialization_encoded_name_json_async.py b/packages/typespec-python/tests/mock_api/azure/asynctests/test_serialization_encoded_name_json_async.py deleted file mode 100644 index 70bfcc77ad..0000000000 --- a/packages/typespec-python/tests/mock_api/azure/asynctests/test_serialization_encoded_name_json_async.py +++ /dev/null @@ -1,24 +0,0 @@ -# ------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for -# license information. -# -------------------------------------------------------------------------- -import pytest -from serialization.encodedname.json.aio import JsonClient -from serialization.encodedname.json import models - - -@pytest.fixture -async def client(): - async with JsonClient() as client: - yield client - - -@pytest.mark.asyncio -async def test_property_send(client: JsonClient): - await client.property.send(models.JsonEncodedNameModel(default_name=True)) - - -@pytest.mark.asyncio -async def test_property_get(client: JsonClient): - assert (await client.property.get()).default_name diff --git a/packages/typespec-python/tests/mock_api/azure/asynctests/test_service_multi_service_async.py b/packages/typespec-python/tests/mock_api/azure/asynctests/test_service_multi_service_async.py deleted file mode 100644 index 07e04285c5..0000000000 --- a/packages/typespec-python/tests/mock_api/azure/asynctests/test_service_multi_service_async.py +++ /dev/null @@ -1,31 +0,0 @@ -# ------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for -# license information. -# -------------------------------------------------------------------------- -import pytest -from azure.core.exceptions import HttpResponseError -from service.multiservice.aio import CombinedClient -from service.multiservice.models import VersionsA, VersionsB - - -@pytest.fixture -def client(): - """Fixture that creates a CombinedClient for testing.""" - return CombinedClient(endpoint="http://localhost:3000") - - -@pytest.mark.asyncio -async def test_service_multi_service_foo(client): - with pytest.raises(HttpResponseError): - await client.foo.test(api_version=VersionsA.AV1) - - await client.foo.test() - - -@pytest.mark.asyncio -async def test_service_multi_service_bar(client): - with pytest.raises(HttpResponseError): - await client.bar.test(api_version=VersionsB.BV1) - - await client.bar.test() diff --git a/packages/typespec-python/tests/mock_api/azure/asynctests/test_special_words_async.py b/packages/typespec-python/tests/mock_api/azure/asynctests/test_special_words_async.py deleted file mode 100644 index 6c01e8f073..0000000000 --- a/packages/typespec-python/tests/mock_api/azure/asynctests/test_special_words_async.py +++ /dev/null @@ -1,71 +0,0 @@ -# ------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for -# license information. -# -------------------------------------------------------------------------- -import pytest -from specialwords.aio import SpecialWordsClient -from specialwords import models - - -@pytest.fixture -async def client(): - async with SpecialWordsClient() as client: - yield client - - -@pytest.mark.asyncio -async def test_operations(client: SpecialWordsClient, special_words): - for sw in special_words: - suffix = "" if sw == "constructor" else "_method" - await getattr(client.operations, sw + suffix)() - - -@pytest.mark.asyncio -async def test_parameter(client: SpecialWordsClient, special_words): - for sw in special_words: - suffix = "" if sw == "constructor" else "_parameter" - await getattr(client.parameters, "with_" + sw)(**{sw + suffix: "ok"}) - await client.parameters.with_cancellation_token(cancellation_token="ok") - - -@pytest.mark.asyncio -async def test_model(client: SpecialWordsClient, special_words): - for sw in special_words: - suffix = "" if sw == "constructor" else "Model" - model = getattr(models, sw.capitalize() + suffix) - await getattr(client.models, "with_" + sw)(model(name="ok")) - - -@pytest.mark.asyncio -async def test_model_properties(client: SpecialWordsClient): - await client.model_properties.same_as_model(models.SameAsModel(same_as_model="ok")) - - -@pytest.mark.asyncio -async def test_model_properties_dict_methods(client: SpecialWordsClient): - await client.model_properties.dict_methods( - body=models.DictMethods( - keys_property="ok", - items_property="ok", - values_property="ok", - popitem_property="ok", - clear_property="ok", - update_property="ok", - setdefault_property="ok", - pop_property="ok", - get_property="ok", - copy_property="ok", - ) - ) - - -@pytest.mark.asyncio -async def test_model_properties_with_list(client: SpecialWordsClient): - await client.model_properties.with_list(models.ModelWithList(list="ok")) - - -@pytest.mark.asyncio -async def test_extensible_strings(client: SpecialWordsClient): - for enum_value in models.ExtensibleString: - assert enum_value == await client.extensible_strings.put_extensible_string_value(body=enum_value) diff --git a/packages/typespec-python/tests/mock_api/azure/conftest.py b/packages/typespec-python/tests/mock_api/azure/conftest.py deleted file mode 100644 index 062e11aeca..0000000000 --- a/packages/typespec-python/tests/mock_api/azure/conftest.py +++ /dev/null @@ -1,170 +0,0 @@ -# ------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for -# license information. -# -------------------------------------------------------------------------- -# Azure-specific fixtures -# Common fixtures (testserver, core_library, key_credential, png_data, jpg_data) -# are inherited from the root tests/conftest.py - -import re -import urllib.parse -import pytest -from typing import Literal, List -from pathlib import Path -from azure.core.rest import HttpRequest - -FILE_FOLDER = Path(__file__).parent - - -_VALID_UUID = re.compile(r"^[0-9a-f]{8}-([0-9a-f]{4}-){3}[0-9a-f]{12}$") -_VALID_RFC7231 = re.compile( - r"^(Mon|Tue|Wed|Thu|Fri|Sat|Sun),\s\d{2}\s" - r"(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)\s\d{4}\s\d{2}:\d{2}:\d{2}\sGMT$" -) - - -def validate_format(value: str, format: Literal["uuid", "rfc7231"]): - if format == "uuid": - assert _VALID_UUID.match(value) - elif format == "rfc7231": - assert _VALID_RFC7231.match(value) - else: - raise ValueError("Unknown format") - - -@pytest.fixture -def check_repeatability_header(): - def func(request): - validate_format(request.http_request.headers["Repeatability-Request-ID"], "uuid") - validate_format(request.http_request.headers["Repeatability-First-Sent"], "rfc7231") - - return func - - -@pytest.fixture -def check_client_request_id_header(): - def func(request, header: str, checked: dict): - validate_format(request.http_request.headers[header], "uuid") - checked[header] = request.http_request.headers[header] - - return func - - -# ================== after azure-core fix, the following code can be removed (begin) ================== - -def update_api_version_of_status_link(status_link: str): - request_params = {} - parsed_status_link = urllib.parse.urlparse(status_link) - request_params = { - key.lower(): [urllib.parse.quote(v) for v in value] - for key, value in urllib.parse.parse_qs(parsed_status_link.query).items() - } - request_params["api-version"] = "2022-12-01-preview" - status_link = urllib.parse.urljoin(status_link, parsed_status_link.path) - return status_link, request_params - - -@pytest.fixture -def polling_method(): - from azure.core.polling.base_polling import LROBasePolling - - class TempLroBasePolling(LROBasePolling): - - def request_status(self, status_link: str): - if self._path_format_arguments: - status_link = self._client.format_url(status_link, **self._path_format_arguments) - status_link, request_params = update_api_version_of_status_link(status_link) - if "request_id" not in self._operation_config: - self._operation_config["request_id"] = self._get_request_id() - - rest_request = HttpRequest("GET", status_link, params=request_params) - return self._client.send_request(rest_request, _return_pipeline_response=True, **self._operation_config) - - return TempLroBasePolling(0) - - -@pytest.fixture -def async_polling_method(): - from azure.core.polling.async_base_polling import AsyncLROBasePolling - - class AsyncTempLroBasePolling(AsyncLROBasePolling): - - async def request_status(self, status_link: str): - if self._path_format_arguments: - status_link = self._client.format_url(status_link, **self._path_format_arguments) - status_link, request_params = update_api_version_of_status_link(status_link) - # Re-inject 'x-ms-client-request-id' while polling - if "request_id" not in self._operation_config: - self._operation_config["request_id"] = self._get_request_id() - - rest_request = HttpRequest("GET", status_link, params=request_params) - return await self._client.send_request( - rest_request, _return_pipeline_response=True, **self._operation_config - ) - - return AsyncTempLroBasePolling(0) - - -# ================== after azure-core fix, the up code can be removed (end) ================== - - -@pytest.fixture() -def credential(): - """I actually don't need anything, since the authentication policy - will bypass it. - """ - - class FakeCredential: - pass - - return FakeCredential() - - -@pytest.fixture() -def authentication_policy(): - from azure.core.pipeline.policies import SansIOHTTPPolicy - - return SansIOHTTPPolicy() - - -SPECIAL_WORDS = [ - "and", - "as", - "assert", - "async", - "await", - "break", - "class", - "constructor", - "continue", - "def", - "del", - "elif", - "else", - "except", - "exec", - "finally", - "for", - "from", - "global", - "if", - "import", - "in", - "is", - "lambda", - "not", - "or", - "pass", - "raise", - "return", - "try", - "while", - "with", - "yield", -] - - -@pytest.fixture -def special_words() -> List[str]: - return SPECIAL_WORDS diff --git a/packages/typespec-python/tests/mock_api/azure/data/image.jpg b/packages/typespec-python/tests/mock_api/azure/data/image.jpg deleted file mode 100644 index b95b3e7b58286ad3e665d98d48b345977f862403..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4069 zcmeHJX;@QN8a_8Gn*#{~QJ4uNv1G6$BrHN6AVrn}mbL^3a4V7!OhA&51QRm!5kx@+ zTNcGZ6cC$Q+;~`GASla}wUxz{#c@GKXr)k4Y@<*!Hx%*D{OB`(hxgoj&v(xGzVDv* zyZ1cLYZx{>23FxAVIcs504RVPFpPlD9#xbBu1V2)YXM|gXB#0R#?0;vho@Ai`n{4K2Z_tc-vVNE8}_H8C|ahaEIl00AM92ow^HM!{MR`W#*d zC>$E^#0bDxN5*4GscV^8g=bC3n`_%`I5%f0?p)~sQ!`sT!n*Yv-gBn@)y2cpYm>JR zD=;WH4t_4#kAFVxjHXs&7-n{@yDwxhGFyQlZNTet7ry*D&GGCKBT{NGO}CV%+x+1&FN z^Dlq-RsZU>kryl_f2RdM|0^#X%nN}+AyHT(F9@M9633y?P7Dk_AQBs&YE5EhnXKJh zc(%6PlpPs~<`z2kKs1OmhoPzVGH-Zu)3MZ>_F zVvR60H(i4HGS)1?$_V@l3~&{b9rK09ND}!zi#oLh#Ro!~r%~ ztf@M>v0>6|AHFNXRdW{F2PwyE*zd{a+%36uhi4yu9aJ^ zpE7`9t8Rioz2KlN=S`ybbp-7ElQg->VN&I!l@n$S;9H_)yZXl$&PTX9ZObWvjhcE$f>gQt?~wSk)wt*@QfJ9e zFelD#>m0AB_sUj(c%Hr(E_yV;phB&=i9g9-)lO~OzQ2==_`u&bT{~<52lxK#Ow_NO zH{&-1-x&aQ;LQ0M(Zy$<1nTsq)xvVR{*&=ztX;IOz6|@z-F$Uf=(W0nyex6{P>FpW z4;0_dipualIew@$bH3M?aaJh~zSVba_s(ZYwY`7uX0rQ=C{sn1g*}wrL&Zt0cwal& z|(+)A&#XhLRoSPH3mt4Ji?-$~1F~yma)AnXu zRaaV$2SjEq$b{PVCY+v+iL;w8BOWVxgqdDst2gCLzog0=vM#q5L^ScNF_ipEjeb6n z1J0h4Y=S>iPa2P#Wgqq@^xWzm>-n^78z*$sXAucKo}EO|0uu3 zLs)^AUypvJF<+QUj|p5L&+NFzk0eJN%fi)?Gy8fd4jBz;gBAkjn_MPYks`G3a33&nP_o zg=l|nT>VF<@}|PZtIypU-TXbb#NA#UwTKA877jAo-sRoA;|O7M!oq~_ndaKA)cm{QH_jPuzCA+J zs!aHNWSYHBYfaj3>w14Gdb?$=t7cDh+;r%rP@Vlr;qGatS1nE0#?Fk+V2@G6gWq0G nRDbTJ{wDPH&YhvRw~$ZQH=nuD@w!Nwq+ZJbRY$2v!^nRCgjEVM diff --git a/packages/typespec-python/tests/mock_api/azure/data/image.png b/packages/typespec-python/tests/mock_api/azure/data/image.png deleted file mode 100644 index 42fe8dc14560b0046bf0f3f00b7a471fa0346e36..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2992 zcmaJ>2UJtr5=}ynfPe^6#i)oP2~A3b_#j9P<c=;9z@urf$wEd&r0Smmc~ z4b}n)eX~PAprkO6@Q)ZL0M}MJAZwiOD16}zNDSD?0g_k*{=o$NMUbCNY?07U9S+2S zEZop`b^yBJDZ#-+YAA`O;C(9uFi4PXy{I6N!uB-*+qrI=1#0z#xnpTqM+_2ABESQJ zNP)p{I)S{F2V_P^0xBVx7N9{V941ncbaU9Z2qd7dnGrCJZy~e@a~RgqMFUNu1Zx<< zb>X@&6jVb)!;BJi2rs64KWLg-BsIiteAdnPEGl#*}3jJK)-!qsV_Nx++`r}x@ z0TF8+gdSWM@iR9-HCwYHUBc+WhrO)A2tdz(8Yn{}vv1-5tZHzM{I(Zu9;;%|=s zCVEhVDQFS_C`d#7x~w1M-<>~*W{9LqLSH=UG`#0SvISvT&z^Cv#7@xJSx2aa-|9tm}-z6Hc>u#KDm+I4F>M3G9RmW+_?M2)1;gWo3xcVR@W8PHPH4h8*{++h z8}Y5F9`(=WPeZXH<+|Y0gJnwP5YL?0zo!3|^aN{T{s{OKE?O45QM0I0;1yDN`SND{ zyOg5mp)N5c(u0Esp-E=kfllR0C&k1s@i0GrZRfs5<7!+x0s^%ugM8%*ef;#PiEVR~ zk~180fRXw!|2qMhFy2QQNA)X#rKKLKFql@YS0DB+8Y~M0L6l6MBxAd5adGjcF9c8t zo3^yHG!i%{(t~?+_KjG%t?wg9W@hGn@>d^2zlX4eDsq69+{GOYhow*ZZ9YFY+;qgj z#AWZ^z2xho`YaYJ$mptuez>fhT&9eIf;49^mEC)&XN9ajcTsqPhD7C%d`TOUID=@6 zW~%vaGf31w{D~F5LO*H9Ul5b;M$_L~@5Rf{$YXmij@GSqZ($ztNsv;Z`i@;wgI)yL z`tVD3-D4YatT^h!2`{f7xgFBk(KVv6D=iyOe>q)Zxtu3f1vhZeoRRfQZ3s>DQ~|{c zhLZ7j^pqm{@Kbe|+)KiSAs)dZlW4Rb|0>x!mf7eaT?yRGZFm;h)5lP}0s z)MR+lRu=;7XofSxFZS5kB(Io?U<4$)=j+Ujv-f1z7}jT(U8oBF@c2?YjHZlX3}y?2 zB}I!j)%5LcxOt457x{YKwWQLqjkl*P!m*TD-H`cTuN{_G`e(Occ-dLa=;vA%@*AOg(a(z}6t_crT&EO-&+m4gF>N0h;BXG0?{Bi7 z`CMs0?IQEIN_yrvkTId}4tcQlLFDsm2){A5T)eb!$m;U*9bpNnS{u9Nur=c6{IY zKC28T*@~?E=+fvG1A<0jF;cm0Q(bSl;8d`tTUme#<>4g zLGy3~(+z4auzTu_$wj7=5_bmr4M3i>XprZ8-8A{ z^S%T(i(@^t7G<(wYTc~P^uFuDm}iOCg0RJbylL{6l)E9&xd*ipG|e`)b?b`n)|`3$ z>k`idS@_lp+*>nk7_W2qvLHrYsnN9VjcdkaYxRqWdf5!mZ8vsD^2e%lG>7`oaP1~( z91eF(@?7&4^jE^(0w>-(Xig#TL8J;KX+2YL&fdmGjCA1!I<+uYch0=ri`kM?G=Uz= zYe(%m$g6gpfYRA}M3Wh=PjV`BA|f`Ajz1QY-KfS$+mLC&=*M@CqU0@-843#@s!tp+ z`hXG_$T+w$%ZRc;oA!hozBo{U_AgR)cc2=ist%Tf1!goyZ`H}XSr9&UY zJ^9hCDY9E_U|L$j^3{t+O$rDP^WqxkQ)&F;Eh@Hsx^<};S#~>%t}R_YRkG7OjOT7s&BTd5F;H{&a{d!BS5Vz@RgwkT{dwhcQ zPGno6OlTdu0KU{d<)>5lyi9d5Rz$1ros^mpW_coXd{r;;5w~?!YUHbE$=hL2`F`si x55d?S>E1-idha0G3zgVNNXgr$|KG8qZJn`L2pQ~%2Sy6WZoiY&ZA<_7e*r@k8!Z3; diff --git a/packages/typespec-python/tests/mock_api/azure/test_azure_arm_commonproperties.py b/packages/typespec-python/tests/mock_api/azure/test_azure_arm_commonproperties.py deleted file mode 100644 index fab853d096..0000000000 --- a/packages/typespec-python/tests/mock_api/azure/test_azure_arm_commonproperties.py +++ /dev/null @@ -1,89 +0,0 @@ -# ------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for -# license information. -# -------------------------------------------------------------------------- -import pytest -from azure.resourcemanager.commonproperties import CommonPropertiesClient -from azure.resourcemanager.commonproperties import models -from azure.core import exceptions - -SUBSCRIPTION_ID = "00000000-0000-0000-0000-000000000000" -RESOURCE_GROUP_NAME = "test-rg" - - -@pytest.fixture -def client(credential, authentication_policy): - with CommonPropertiesClient( - credential, SUBSCRIPTION_ID, "http://localhost:3000", authentication_policy=authentication_policy - ) as client: - yield client - - -def test_managed_identity_get(client): - result = client.managed_identity.get( - resource_group_name=RESOURCE_GROUP_NAME, managed_identity_tracked_resource_name="identity" - ) - assert result.location == "eastus" - assert result.identity.type == "SystemAssigned" - assert result.properties.provisioning_state == "Succeeded" - - -def test_managed_identity_create_with_system_assigned(client): - result = client.managed_identity.create_with_system_assigned( - resource_group_name=RESOURCE_GROUP_NAME, - managed_identity_tracked_resource_name="identity", - resource=models.ManagedIdentityTrackedResource( - location="eastus", identity=models.ManagedServiceIdentity(type="SystemAssigned") - ), - ) - assert result.location == "eastus" - assert result.identity.type == "SystemAssigned" - assert result.properties.provisioning_state == "Succeeded" - - -def test_managed_identity_update_with_user_assigned_and_system_assigned(client): - result = client.managed_identity.update_with_user_assigned_and_system_assigned( - resource_group_name=RESOURCE_GROUP_NAME, - managed_identity_tracked_resource_name="identity", - properties=models.ManagedIdentityTrackedResource( - location="eastus", - identity=models.ManagedServiceIdentity( - type="SystemAssigned,UserAssigned", - user_assigned_identities={ - "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/test-rg/providers/Microsoft.ManagedIdentity/userAssignedIdentities/id1": models.UserAssignedIdentity() - }, - ), - ), - ) - assert result.location == "eastus" - assert result.identity.type == "SystemAssigned,UserAssigned" - assert result.properties.provisioning_state == "Succeeded" - - -def test_error_get_for_predefined_error(client): - try: - client.error.get_for_predefined_error( - resource_group_name=RESOURCE_GROUP_NAME, - confidential_resource_name="confidential", - ) - except exceptions.ResourceNotFoundError as e: - assert e.status_code == 404 - assert ( - e.error.message - == "The Resource 'Azure.ResourceManager.CommonProperties/confidentialResources/confidential' under resource group 'test-rg' was not found." - ) - - -def test_error_create_for_user_defined_error(client): - try: - client.error.create_for_user_defined_error( - resource_group_name=RESOURCE_GROUP_NAME, - confidential_resource_name="confidential", - resource=models.ConfidentialResource( - location="eastus", properties=models.ConfidentialResourceProperties(username="00") - ), - ) - except exceptions.HttpResponseError as e: - assert e.status_code == 400 - assert e.error.message == "Username should not contain only numbers." diff --git a/packages/typespec-python/tests/mock_api/azure/test_azure_arm_largeheader.py b/packages/typespec-python/tests/mock_api/azure/test_azure_arm_largeheader.py deleted file mode 100644 index 9ad6d567e8..0000000000 --- a/packages/typespec-python/tests/mock_api/azure/test_azure_arm_largeheader.py +++ /dev/null @@ -1,27 +0,0 @@ -# ------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for -# license information. -# -------------------------------------------------------------------------- -import pytest -from azure.resourcemanager.largeheader import LargeHeaderClient -from azure.resourcemanager.largeheader import models - -SUBSCRIPTION_ID = "00000000-0000-0000-0000-000000000000" -RESOURCE_GROUP_NAME = "test-rg" - - -@pytest.fixture -def client(credential, authentication_policy): - with LargeHeaderClient( - credential, SUBSCRIPTION_ID, "http://localhost:3000", authentication_policy=authentication_policy - ) as client: - yield client - - -def test_large_headers_begin_two6_k(client: LargeHeaderClient): - result = client.large_headers.begin_two6_k( - resource_group_name=RESOURCE_GROUP_NAME, - large_header_name="header1", - ).result() - assert result == models.CancelResult(succeeded=True) diff --git a/packages/typespec-python/tests/mock_api/azure/test_azure_arm_nonresource.py b/packages/typespec-python/tests/mock_api/azure/test_azure_arm_nonresource.py deleted file mode 100644 index 6fd180f8b2..0000000000 --- a/packages/typespec-python/tests/mock_api/azure/test_azure_arm_nonresource.py +++ /dev/null @@ -1,34 +0,0 @@ -# ------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for -# license information. -# -------------------------------------------------------------------------- -import pytest -from azure.resourcemanager.nonresource import NonResourceClient -from azure.resourcemanager.nonresource import models - -SUBSCRIPTION_ID = "00000000-0000-0000-0000-000000000000" -RESOURCE_GROUP_NAME = "test-rg" - - -@pytest.fixture -def client(credential, authentication_policy): - with NonResourceClient( - credential, SUBSCRIPTION_ID, "http://localhost:3000", authentication_policy=authentication_policy - ) as client: - yield client - - -def test_non_resource_create(client: NonResourceClient): - result = client.non_resource_operations.create( - location="eastus", parameter="hello", body=models.NonResource(id="id", name="hello", type="nonResource") - ) - assert result == models.NonResource(id="id", name="hello", type="nonResource") - - -def test_non_resource_get(client: NonResourceClient): - result = client.non_resource_operations.get( - location="eastus", - parameter="hello", - ) - assert result == models.NonResource(id="id", name="hello", type="nonResource") diff --git a/packages/typespec-python/tests/mock_api/azure/test_azure_arm_operationtemplates.py b/packages/typespec-python/tests/mock_api/azure/test_azure_arm_operationtemplates.py deleted file mode 100644 index c86c95ef4a..0000000000 --- a/packages/typespec-python/tests/mock_api/azure/test_azure_arm_operationtemplates.py +++ /dev/null @@ -1,180 +0,0 @@ -# ------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for -# license information. -# -------------------------------------------------------------------------- -import pytest -from azure.resourcemanager.operationtemplates import OperationTemplatesClient -from azure.resourcemanager.operationtemplates import models - -SUBSCRIPTION_ID = "00000000-0000-0000-0000-000000000000" -RESOURCE_GROUP_NAME = "test-rg" - - -@pytest.fixture -def client(credential, authentication_policy): - with OperationTemplatesClient( - credential, - SUBSCRIPTION_ID, - "http://localhost:3000", - authentication_policy=authentication_policy, - polling_interval=0, - ) as client: - yield client - - -def test_check_name_availability_check_global(client): - result = client.check_name_availability.check_global( - body=models.CheckNameAvailabilityRequest(name="checkName", type="Microsoft.Web/site") - ) - assert result.name_available == False - assert result.reason == models.CheckNameAvailabilityReason.ALREADY_EXISTS - assert result.message == "Hostname 'checkName' already exists. Please select a different name." - - -def test_check_name_availability_check_local(client): - result = client.check_name_availability.check_local( - location="westus", - body=models.CheckNameAvailabilityRequest(name="checkName", type="Microsoft.Web/site"), - ) - assert result.name_available == False - assert result.reason == models.CheckNameAvailabilityReason.ALREADY_EXISTS - assert result.message == "Hostname 'checkName' already exists. Please select a different name." - - -def test_operations_list(client): - result = client.operations.list().next() - assert result.name == "Microsoft.Compute/virtualMachines/write" - assert result.display.operation == "Create or Update Virtual Machine." - assert result.origin == "user,system" - assert result.action_type == "Internal" - - -def test_lro_begin_create_or_replace(client): - result = client.lro.begin_create_or_replace( - resource_group_name=RESOURCE_GROUP_NAME, - order_name="order1", - resource=models.Order( - location="eastus", - properties=models.OrderProperties(product_id="product1", amount=1), - ), - ).result() - assert result.name == "order1" - assert ( - result.id - == "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/test-rg/providers/Azure.ResourceManager.OperationTemplates/orders/order1" - ) - assert result.type == "Azure.ResourceManager.Resources/orders" - assert result.location == "eastus" - assert result.system_data.created_by == "AzureSDK" - - -def test_lro_begin_export(client): - client.lro.begin_export( - resource_group_name=RESOURCE_GROUP_NAME, - order_name="order1", - body=models.ExportRequest(format="csv"), - ).result() - - -def test_lro_begin_delete(client): - client.lro.begin_delete( - resource_group_name=RESOURCE_GROUP_NAME, - order_name="order1", - ).result() - - -def test_optional_body_get(client): - result = client.optional_body.get( - resource_group_name=RESOURCE_GROUP_NAME, - widget_name="widget1", - ) - assert result.name == "widget1" - assert ( - result.id - == "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/test-rg/providers/Azure.ResourceManager.OperationTemplates/widgets/widget1" - ) - assert result.type == "Azure.ResourceManager.OperationTemplates/widgets" - assert result.location == "eastus" - assert result.properties.name == "widget1" - assert result.properties.description == "A test widget" - assert result.properties.provisioning_state == "Succeeded" - - -def test_optional_body_patch_without_body(client): - result = client.optional_body.patch( - resource_group_name=RESOURCE_GROUP_NAME, - widget_name="widget1", - ) - assert result.name == "widget1" - assert result.properties.name == "widget1" - assert result.properties.description == "A test widget" - - -def test_optional_body_patch_with_body(client): - result = client.optional_body.patch( - resource_group_name=RESOURCE_GROUP_NAME, - widget_name="widget1", - properties=models.Widget( - location="eastus", - properties=models.WidgetProperties(name="updated-widget", description="Updated description"), - ), - ) - assert result.name == "widget1" - assert result.properties.name == "updated-widget" - assert result.properties.description == "Updated description" - - -def test_optional_body_post_without_body(client): - result = client.optional_body.post( - resource_group_name=RESOURCE_GROUP_NAME, - widget_name="widget1", - ) - assert result.result == "Action completed successfully" - - -def test_optional_body_post_with_body(client): - result = client.optional_body.post( - resource_group_name=RESOURCE_GROUP_NAME, - widget_name="widget1", - body=models.ActionRequest(action_type="perform", parameters="test-parameters"), - ) - assert result.result == "Action completed successfully with parameters" - - -def test_optional_body_provider_post_without_body(client): - result = client.optional_body.provider_post() - assert result.total_allowed == 50 - assert result.status == "Changed to default allowance" - - -def test_optional_body_provider_post_with_body(client): - result = client.optional_body.provider_post( - body=models.ChangeAllowanceRequest(total_allowed=100, reason="Increased demand"), - ) - assert result.total_allowed == 100 - assert result.status == "Changed to requested allowance" - - -def test_lro_begin_export_array(client): - result = client.lro.begin_export_array( - body=models.ExportRequest(format="csv"), - ).result() - assert len(result) == 2 - assert result[0].content == "order1,product1,1" - assert result[1].content == "order2,product2,2" - - -def test_lro_paging_begin_post_paging_lro(client): - result = client.lro_paging.begin_post_paging_lro( - resource_group_name=RESOURCE_GROUP_NAME, - product_name="default", - ).result() - items = list(result) - assert len(items) == 2 - assert items[0].name == "product1" - assert items[0].properties.product_id == "product1" - assert items[0].properties.provisioning_state == "Succeeded" - assert items[1].name == "product2" - assert items[1].properties.product_id == "product2" - assert items[1].properties.provisioning_state == "Succeeded" diff --git a/packages/typespec-python/tests/mock_api/azure/test_azure_arm_resource.py b/packages/typespec-python/tests/mock_api/azure/test_azure_arm_resource.py deleted file mode 100644 index c34d9a85ae..0000000000 --- a/packages/typespec-python/tests/mock_api/azure/test_azure_arm_resource.py +++ /dev/null @@ -1,436 +0,0 @@ -# ------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for -# license information. -# -------------------------------------------------------------------------- -import pytest -from azure.resourcemanager.resources import ResourcesClient -from azure.resourcemanager.resources import models - -SUBSCRIPTION_ID = "00000000-0000-0000-0000-000000000000" -RESOURCE_GROUP_NAME = "test-rg" - - -@pytest.fixture -def client(credential, authentication_policy): - with ResourcesClient( - credential, - SUBSCRIPTION_ID, - "http://localhost:3000", - authentication_policy=authentication_policy, - ) as client: - yield client - - -def test_client_signature(credential, authentication_policy): - # make sure signautre order is correct - client1 = ResourcesClient( - credential, - SUBSCRIPTION_ID, - "http://localhost:3000", - authentication_policy=authentication_policy, - ) - # make sure signautre name is correct - client2 = ResourcesClient( - credential=credential, - subscription_id=SUBSCRIPTION_ID, - base_url="http://localhost:3000", - authentication_policy=authentication_policy, - ) - for client in [client1, client2]: - # make sure signautre order is correct - client.top_level.get(RESOURCE_GROUP_NAME, "top") - # make sure signautre name is correct - client.top_level.get( - resource_group_name=RESOURCE_GROUP_NAME, - top_level_tracked_resource_name="top", - ) - - -def test_top_level_begin_create_or_replace(client): - result = client.top_level.begin_create_or_replace( - resource_group_name=RESOURCE_GROUP_NAME, - top_level_tracked_resource_name="top", - resource=models.TopLevelTrackedResource( - location="eastus", - properties=models.TopLevelTrackedResourceProperties( - models.TopLevelTrackedResourceProperties(description="valid") - ), - ), - polling_interval=0, # set polling_interval to 0 s to make the test faster since default is 30s - ).result() - assert result.location == "eastus" - assert result.properties.description == "valid" - assert result.properties.provisioning_state == "Succeeded" - assert result.name == "top" - assert result.type == "Azure.ResourceManager.Resources/topLevelTrackedResources" - assert result.system_data.created_by == "AzureSDK" - - -def test_top_level_begin_update(client): - result = client.top_level.begin_update( - resource_group_name=RESOURCE_GROUP_NAME, - top_level_tracked_resource_name="top", - properties=models.TopLevelTrackedResource( - location="eastus", - properties=models.TopLevelTrackedResourceProperties( - models.TopLevelTrackedResourceProperties(description="valid2") - ), - ), - polling_interval=0, # set polling_interval to 0 s to make the test faster since default is 30s - ).result() - assert result.location == "eastus" - assert result.properties.description == "valid2" - assert result.properties.provisioning_state == "Succeeded" - assert result.name == "top" - assert result.type == "Azure.ResourceManager.Resources/topLevelTrackedResources" - assert result.system_data.created_by == "AzureSDK" - - -def test_top_level_begin_delete(client): - client.top_level.begin_delete( - resource_group_name=RESOURCE_GROUP_NAME, - top_level_tracked_resource_name="top", - polling_interval=0, # set polling_interval to 0 s to make the test faster since default is 30s - ).result() - - -def test_top_level_list_by_resource_group(client): - response = client.top_level.list_by_resource_group( - resource_group_name=RESOURCE_GROUP_NAME, - ) - result = [r for r in response] - for result in result: - assert result.location == "eastus" - assert result.properties.description == "valid" - assert result.properties.provisioning_state == "Succeeded" - assert result.name == "top" - assert result.type == "Azure.ResourceManager.Resources/topLevelTrackedResources" - assert result.system_data.created_by == "AzureSDK" - - -def test_top_level_list_by_subscription(client): - response = client.top_level.list_by_subscription() - result = [r for r in response] - for result in result: - assert result.location == "eastus" - assert result.properties.description == "valid" - assert result.properties.provisioning_state == "Succeeded" - assert result.name == "top" - assert result.type == "Azure.ResourceManager.Resources/topLevelTrackedResources" - assert result.system_data.created_by == "AzureSDK" - - -def test_nested_get(client): - result = client.nested.get( - resource_group_name=RESOURCE_GROUP_NAME, - top_level_tracked_resource_name="top", - nexted_proxy_resource_name="nested", - ) - assert result.properties.description == "valid" - assert result.properties.provisioning_state == "Succeeded" - assert result.name == "nested" - assert result.type == "Azure.ResourceManager.Resources/topLevelTrackedResources/top/nestedProxyResources" - assert result.system_data.created_by == "AzureSDK" - - -def test_nested_begin_create_or_replace(client): - result = client.nested.begin_create_or_replace( - resource_group_name=RESOURCE_GROUP_NAME, - top_level_tracked_resource_name="top", - nexted_proxy_resource_name="nested", - resource=models.TopLevelTrackedResource( - properties=models.TopLevelTrackedResourceProperties( - models.TopLevelTrackedResourceProperties(description="valid") - ), - ), - polling_interval=0, # set polling_interval to 0 s to make the test faster since default is 30s - ).result() - assert result.properties.description == "valid" - assert result.properties.provisioning_state == "Succeeded" - assert result.name == "nested" - assert result.type == "Azure.ResourceManager.Resources/topLevelTrackedResources/top/nestedProxyResources" - assert result.system_data.created_by == "AzureSDK" - - -def test_nested_begin_update(client): - result = client.nested.begin_update( - resource_group_name=RESOURCE_GROUP_NAME, - top_level_tracked_resource_name="top", - nexted_proxy_resource_name="nested", - properties=models.TopLevelTrackedResource( - properties=models.TopLevelTrackedResourceProperties( - models.TopLevelTrackedResourceProperties(description="valid2") - ), - ), - polling_interval=0, # set polling_interval to 0 s to make the test faster since default is 30s - ).result() - assert result.properties.description == "valid2" - assert result.properties.provisioning_state == "Succeeded" - assert result.name == "nested" - assert result.type == "Azure.ResourceManager.Resources/topLevelTrackedResources/top/nestedProxyResources" - assert result.system_data.created_by == "AzureSDK" - - -def test_nested_begin_delete(client): - client.nested.begin_delete( - resource_group_name=RESOURCE_GROUP_NAME, - top_level_tracked_resource_name="top", - nexted_proxy_resource_name="nested", - polling_interval=0, # set polling_interval to 0 s to make the test faster since default is 30s - ).result() - - -def test_nested_list_by_top_level_tracked_resource(client): - response = client.nested.list_by_top_level_tracked_resource( - resource_group_name=RESOURCE_GROUP_NAME, - top_level_tracked_resource_name="top", - ) - result = [r for r in response] - for result in result: - assert result.properties.description == "valid" - assert result.properties.provisioning_state == "Succeeded" - assert result.name == "nested" - assert result.type == "Azure.ResourceManager.Resources/topLevelTrackedResources/top/nestedProxyResources" - assert result.system_data.created_by == "AzureSDK" - - -def test_top_level_action_sync(client): - client.top_level.action_sync( - resource_group_name=RESOURCE_GROUP_NAME, - top_level_tracked_resource_name="top", - body={"message": "Resource action at top level.", "urgent": True}, - ) - - -def test_singleton_get_by_resource_group(client): - result = client.singleton.get_by_resource_group( - resource_group_name=RESOURCE_GROUP_NAME, - ) - assert result.properties.description == "valid" - assert result.properties.provisioning_state == "Succeeded" - assert result.name == "default" - assert result.type == "Azure.ResourceManager.Resources/singletonTrackedResources" - assert result.system_data.created_by == "AzureSDK" - - -def test_singleton_begin_create_or_replace(client): - result = client.singleton.begin_create_or_update( - resource_group_name=RESOURCE_GROUP_NAME, - resource=models.SingletonTrackedResource( - location="eastus", - properties=models.SingletonTrackedResourceProperties( - models.SingletonTrackedResourceProperties(description="valid") - ), - ), - ).result() - assert result.properties.description == "valid" - assert result.properties.provisioning_state == "Succeeded" - assert result.name == "default" - assert result.type == "Azure.ResourceManager.Resources/singletonTrackedResources" - assert result.system_data.created_by == "AzureSDK" - - -def test_singleton_update(client): - result = client.singleton.update( - resource_group_name=RESOURCE_GROUP_NAME, - properties=models.SingletonTrackedResource( - location="eastus2", - properties=models.SingletonTrackedResourceProperties( - models.SingletonTrackedResourceProperties(description="valid2") - ), - ), - ) - assert result.properties.description == "valid2" - assert result.properties.provisioning_state == "Succeeded" - assert result.name == "default" - assert result.type == "Azure.ResourceManager.Resources/singletonTrackedResources" - assert result.system_data.created_by == "AzureSDK" - - -def test_singleton_list_by_resource_group(client): - response = client.singleton.list_by_resource_group( - resource_group_name=RESOURCE_GROUP_NAME, - ) - result = [r for r in response] - for result in result: - assert result.properties.description == "valid" - assert result.properties.provisioning_state == "Succeeded" - assert result.name == "default" - assert result.type == "Azure.ResourceManager.Resources/singletonTrackedResources" - assert result.system_data.created_by == "AzureSDK" - - -@pytest.mark.parametrize( - "scope", - [ - "", - "/subscriptions/00000000-0000-0000-0000-000000000000", - "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/test-rg", - "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/test-rg/providers/Azure.ResourceManager.Resources/topLevelTrackedResources/top", - ], -) -def test_extensions_resources_begin_create_or_update(client, scope): - result = client.extensions_resources.begin_create_or_update( - resource_uri=scope, - extensions_resource_name="extension", - resource=models.ExtensionsResource(properties=models.ExtensionsResourceProperties(description="valid")), - ).result() - assert result.id == f"{scope}/providers/Azure.ResourceManager.Resources/extensionsResources/extension" - assert result.name == "extension" - assert result.type == "Azure.ResourceManager.Resources/extensionsResources" - assert result.properties.description == "valid" - assert result.properties.provisioning_state == "Succeeded" - assert result.system_data.created_by == "AzureSDK" - - -@pytest.mark.parametrize( - "scope", - [ - "", - "/subscriptions/00000000-0000-0000-0000-000000000000", - "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/test-rg", - "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/test-rg/providers/Azure.ResourceManager.Resources/topLevelTrackedResources/top", - ], -) -def test_extensions_resources_update(client, scope): - result = client.extensions_resources.update( - resource_uri=scope, - extensions_resource_name="extension", - properties=models.ExtensionsResource(properties=models.ExtensionsResourceProperties(description="valid2")), - ) - assert result.id == f"{scope}/providers/Azure.ResourceManager.Resources/extensionsResources/extension" - assert result.name == "extension" - assert result.type == "Azure.ResourceManager.Resources/extensionsResources" - assert result.properties.description == "valid2" - assert result.properties.provisioning_state == "Succeeded" - assert result.system_data.created_by == "AzureSDK" - - -@pytest.mark.parametrize( - "scope", - [ - "", - "/subscriptions/00000000-0000-0000-0000-000000000000", - "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/test-rg", - "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/test-rg/providers/Azure.ResourceManager.Resources/topLevelTrackedResources/top", - ], -) -def test_extensions_resources_get(client, scope): - result = client.extensions_resources.get(resource_uri=scope, extensions_resource_name="extension") - assert result.id == f"{scope}/providers/Azure.ResourceManager.Resources/extensionsResources/extension" - assert result.name == "extension" - assert result.type == "Azure.ResourceManager.Resources/extensionsResources" - assert result.properties.description == "valid" - assert result.properties.provisioning_state == "Succeeded" - assert result.system_data.created_by == "AzureSDK" - - -@pytest.mark.parametrize( - "scope", - [ - "", - "/subscriptions/00000000-0000-0000-0000-000000000000", - "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/test-rg", - "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/test-rg/providers/Azure.ResourceManager.Resources/topLevelTrackedResources/top", - ], -) -def test_extensions_resources_list(client, scope): - response = client.extensions_resources.list_by_scope( - resource_uri=scope, - ) - result = [r for r in response] - for result in result: - assert result.id == f"{scope}/providers/Azure.ResourceManager.Resources/extensionsResources/extension" - assert result.name == "extension" - assert result.type == "Azure.ResourceManager.Resources/extensionsResources" - assert result.properties.description == "valid" - assert result.properties.provisioning_state == "Succeeded" - assert result.system_data.created_by == "AzureSDK" - - -@pytest.mark.parametrize( - "scope", - [ - "", - "/subscriptions/00000000-0000-0000-0000-000000000000", - "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/test-rg", - "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/test-rg/providers/Azure.ResourceManager.Resources/topLevelTrackedResources/top", - ], -) -def test_extensions_resources_delete(client, scope): - client.extensions_resources.delete(resource_uri=scope, extensions_resource_name="extension") - - -def test_location_resources_create_or_update(client): - result = client.location_resources.create_or_update( - location="eastus", - location_resource_name="resource", - resource=models.LocationResource(properties=models.LocationResourceProperties(description="valid")), - ) - assert ( - result.id - == "/subscriptions/00000000-0000-0000-0000-000000000000/providers/Azure.ResourceManager.Resources/locations/eastus/locationResources/resource" - ) - assert result.name == "resource" - assert result.type == "Azure.ResourceManager.Resources/locationResources" - assert result.properties.description == "valid" - assert result.properties.provisioning_state == "Succeeded" - assert result.system_data.created_by == "AzureSDK" - - -def test_location_resources_update(client): - result = client.location_resources.update( - location="eastus", - location_resource_name="resource", - properties=models.LocationResource(properties=models.LocationResourceProperties(description="valid2")), - ) - assert ( - result.id - == "/subscriptions/00000000-0000-0000-0000-000000000000/providers/Azure.ResourceManager.Resources/locations/eastus/locationResources/resource" - ) - assert result.name == "resource" - assert result.type == "Azure.ResourceManager.Resources/locationResources" - assert result.properties.description == "valid2" - assert result.properties.provisioning_state == "Succeeded" - assert result.system_data.created_by == "AzureSDK" - - -def test_location_resources_get(client): - result = client.location_resources.get( - location="eastus", - location_resource_name="resource", - ) - assert ( - result.id - == "/subscriptions/00000000-0000-0000-0000-000000000000/providers/Azure.ResourceManager.Resources/locations/eastus/locationResources/resource" - ) - assert result.name == "resource" - assert result.type == "Azure.ResourceManager.Resources/locationResources" - assert result.properties.description == "valid" - assert result.properties.provisioning_state == "Succeeded" - assert result.system_data.created_by == "AzureSDK" - - -def test_location_resources_delete(client): - client.location_resources.delete( - location="eastus", - location_resource_name="resource", - ) - - -def test_location_resources_list_by_location(client): - response = client.location_resources.list_by_location( - location="eastus", - ) - result = [r for r in response] - for result in result: - assert ( - result.id - == "/subscriptions/00000000-0000-0000-0000-000000000000/providers/Azure.ResourceManager.Resources/locations/eastus/locationResources/resource" - ) - assert result.name == "resource" - assert result.type == "Azure.ResourceManager.Resources/locationResources" - assert result.properties.description == "valid" - assert result.properties.provisioning_state == "Succeeded" - assert result.system_data.created_by == "AzureSDK" diff --git a/packages/typespec-python/tests/mock_api/azure/test_azure_client_generator_core_access.py b/packages/typespec-python/tests/mock_api/azure/test_azure_client_generator_core_access.py deleted file mode 100644 index ba26314706..0000000000 --- a/packages/typespec-python/tests/mock_api/azure/test_azure_client_generator_core_access.py +++ /dev/null @@ -1,92 +0,0 @@ -# ------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for -# license information. -# -------------------------------------------------------------------------- -import pytest -from specs.azure.clientgenerator.core.access import AccessClient -from specs.azure.clientgenerator.core.access import models - - -@pytest.fixture -def client(): - with AccessClient() as client: - yield client - - -def test_no_decorator_in_public(client: AccessClient): - result = client.public_operation.no_decorator_in_public(name="sample") - assert result == models.NoDecoratorModelInPublic(name="sample") - - -def test_public_decorator_in_public(client: AccessClient): - result = client.public_operation.public_decorator_in_public(name="sample") - assert result == models.PublicDecoratorModelInPublic(name="sample") - - -def test_no_decorator_in_internal(client: AccessClient): - result = client.internal_operation._no_decorator_in_internal(name="sample") - assert result == models._models.NoDecoratorModelInInternal(name="sample") - - with pytest.raises(ImportError): - from specs.azure.clientgenerator.core.access.models import NoDecoratorModelInInternal - - with pytest.raises(AttributeError): - client.internal_operation.no_decorator_in_internal(name="sample") - - -def test_internal_decorator_in_internal(client: AccessClient): - result = client.internal_operation._internal_decorator_in_internal(name="sample") - assert result == models._models.InternalDecoratorModelInInternal(name="sample") - - with pytest.raises(ImportError): - from specs.azure.clientgenerator.core.access.models import InternalDecoratorModelInInternal - - with pytest.raises(AttributeError): - client.internal_operation.internal_decorator_in_internal(name="sample") - - -def test_public_decorator_in_internal(client: AccessClient): - result = client.internal_operation._public_decorator_in_internal(name="sample") - assert result == models.PublicDecoratorModelInInternal(name="sample") - - with pytest.raises(AttributeError): - client.internal_operation.public_decorator_in_internal(name="sample") - - -def test_public(client: AccessClient): - result = client.shared_model_in_operation.public(name="sample") - assert result == models.SharedModel(name="sample") - - -def test_internal(client: AccessClient): - result = client.shared_model_in_operation._internal(name="sample") - assert result == models.SharedModel(name="sample") - - with pytest.raises(AttributeError): - client.shared_model_in_operation.internal(name="sample") - - -def test_operation(client: AccessClient): - result = client.relative_model_in_operation._operation(name="Madge") - assert result == models._models.OuterModel(name="Madge", inner=models._models.InnerModel(name="Madge")) - - with pytest.raises(ImportError): - from specs.azure.clientgenerator.core.access.models import OuterModel - - with pytest.raises(ImportError): - from specs.azure.clientgenerator.core.access.models import InnerModel - - with pytest.raises(AttributeError): - client.shared_model_in_operation.operation(name="sample") - - -def test_discriminator(client: AccessClient): - result = client.relative_model_in_operation._discriminator(kind="real") - assert result == models._models.RealModel(name="Madge") - - with pytest.raises(ImportError): - from specs.azure.clientgenerator.core.access.models import RealModel - - with pytest.raises(AttributeError): - client.shared_model_in_operation.discriminator(kind="real") diff --git a/packages/typespec-python/tests/mock_api/azure/test_azure_client_generator_core_alternate_type.py b/packages/typespec-python/tests/mock_api/azure/test_azure_client_generator_core_alternate_type.py deleted file mode 100644 index c5ae3266c8..0000000000 --- a/packages/typespec-python/tests/mock_api/azure/test_azure_client_generator_core_alternate_type.py +++ /dev/null @@ -1,69 +0,0 @@ -# ------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for -# license information. -# -------------------------------------------------------------------------- -import pytest -import geojson -from specs.azure.clientgenerator.core.alternatetype import AlternateTypeClient -from specs.azure.clientgenerator.core.alternatetype import models - -# Shared test data -PROPERTIES = {"name": "A single point of interest", "category": "landmark", "elevation": 100} - -GEOMETRY = geojson.Point((-122.25, 37.87)) - -FEATURE_ID = "feature-1" - - -@pytest.fixture -def client(): - with AlternateTypeClient(endpoint="http://localhost:3000") as client: - yield client - - -@pytest.fixture -def feature_geojson(): - """Shared GeoJSON Feature for tests.""" - return geojson.Feature(type="Feature", geometry=GEOMETRY, properties=PROPERTIES, id=FEATURE_ID) - - -def test_external_type_get_model(client: AlternateTypeClient): - """Test getting a Feature object with geometry, properties, and optional id fields.""" - result = client.external_type.get_model() - - # Validate the response structure based on the TypeSpec example - assert result.type == "Feature" - assert result.geometry.type == "Point" - assert result.geometry.coordinates == [-122.25, 37.87] - assert result.properties == PROPERTIES - assert result.id == FEATURE_ID - - -def test_external_type_put_model(client: AlternateTypeClient, feature_geojson): - """Test putting a Feature object in request body.""" - # Should return None (204/empty response) - result = client.external_type.put_model(body=feature_geojson) - assert result is None - - -def test_external_type_get_property(client: AlternateTypeClient): - """Test getting a ModelWithFeatureProperty object with feature and additionalProperty fields.""" - result = client.external_type.get_property() - - # Validate the response structure based on the TypeSpec example - assert result.feature.type == "Feature" - assert result.feature.geometry.type == "Point" - assert result.feature.geometry.coordinates == [-122.25, 37.87] - assert result.feature.properties == PROPERTIES - assert result.feature.id == FEATURE_ID - assert result.additional_property == "extra" - - -def test_external_type_put_property(client: AlternateTypeClient, feature_geojson): - """Test putting a ModelWithFeatureProperty object in request body.""" - model_with_feature = models.ModelWithFeatureProperty(feature=feature_geojson, additional_property="extra") - - # Should return None (204/empty response) - result = client.external_type.put_property(body=model_with_feature) - assert result is None diff --git a/packages/typespec-python/tests/mock_api/azure/test_azure_client_generator_core_api_version_header.py b/packages/typespec-python/tests/mock_api/azure/test_azure_client_generator_core_api_version_header.py deleted file mode 100644 index bd15dcbcd2..0000000000 --- a/packages/typespec-python/tests/mock_api/azure/test_azure_client_generator_core_api_version_header.py +++ /dev/null @@ -1,17 +0,0 @@ -# ------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for -# license information. -# -------------------------------------------------------------------------- -import pytest -from client.alternateapiversion.service.header import HeaderClient - - -@pytest.fixture -def client(): - with HeaderClient(endpoint="http://localhost:3000") as client: - yield client - - -def test_header_api_version(client: HeaderClient): - client.header_api_version() diff --git a/packages/typespec-python/tests/mock_api/azure/test_azure_client_generator_core_api_version_path.py b/packages/typespec-python/tests/mock_api/azure/test_azure_client_generator_core_api_version_path.py deleted file mode 100644 index f805e16f9d..0000000000 --- a/packages/typespec-python/tests/mock_api/azure/test_azure_client_generator_core_api_version_path.py +++ /dev/null @@ -1,17 +0,0 @@ -# ------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for -# license information. -# -------------------------------------------------------------------------- -import pytest -from client.alternateapiversion.service.path import PathClient - - -@pytest.fixture -def client(): - with PathClient(endpoint="http://localhost:3000") as client: - yield client - - -def test_path_api_version(client: PathClient): - client.path_api_version() diff --git a/packages/typespec-python/tests/mock_api/azure/test_azure_client_generator_core_api_version_query.py b/packages/typespec-python/tests/mock_api/azure/test_azure_client_generator_core_api_version_query.py deleted file mode 100644 index fbdca33cb8..0000000000 --- a/packages/typespec-python/tests/mock_api/azure/test_azure_client_generator_core_api_version_query.py +++ /dev/null @@ -1,17 +0,0 @@ -# ------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for -# license information. -# -------------------------------------------------------------------------- -import pytest -from client.alternateapiversion.service.query import QueryClient - - -@pytest.fixture -def client(): - with QueryClient(endpoint="http://localhost:3000") as client: - yield client - - -def test_query_api_version(client: QueryClient): - client.query_api_version() diff --git a/packages/typespec-python/tests/mock_api/azure/test_azure_client_generator_core_client_default_value.py b/packages/typespec-python/tests/mock_api/azure/test_azure_client_generator_core_client_default_value.py deleted file mode 100644 index 730c6a74b3..0000000000 --- a/packages/typespec-python/tests/mock_api/azure/test_azure_client_generator_core_client_default_value.py +++ /dev/null @@ -1,42 +0,0 @@ -# ------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for -# license information. -# -------------------------------------------------------------------------- -import pytest -from specs.azure.clientgenerator.core.clientdefaultvalue import ClientDefaultValueClient -from specs.azure.clientgenerator.core.clientdefaultvalue.models import ModelWithDefaultValues - - -@pytest.fixture -def client(): - with ClientDefaultValueClient() as client: - yield client - - -def test_put_model_property(client: ClientDefaultValueClient): - """Test case 1: @clientDefaultValue for model property.""" - body = ModelWithDefaultValues(name="test") - result = client.put_model_property(body=body) - assert result.name == "test" - assert result.timeout == 30 - assert result.tier == "standard" - assert result.retry is True - - -def test_get_operation_parameter(client: ClientDefaultValueClient): - """Test case 2: @clientDefaultValue for operation parameter.""" - # Test with only required parameter (name), defaults should be applied - client.get_operation_parameter(name="test") - - -def test_get_path_parameter(client: ClientDefaultValueClient): - """Test case 3: @clientDefaultValue for first path segment.""" - # Test with only required segment2, segment1 should use default - client.get_path_parameter(segment2="segment2") - - -def test_get_header_parameter(client: ClientDefaultValueClient): - """Test case 4: @clientDefaultValue for header parameters.""" - # Test with default header values - client.get_header_parameter() diff --git a/packages/typespec-python/tests/mock_api/azure/test_azure_client_generator_core_client_initialization.py b/packages/typespec-python/tests/mock_api/azure/test_azure_client_generator_core_client_initialization.py deleted file mode 100644 index 602332210f..0000000000 --- a/packages/typespec-python/tests/mock_api/azure/test_azure_client_generator_core_client_initialization.py +++ /dev/null @@ -1,51 +0,0 @@ -# ------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for -# license information. -# -------------------------------------------------------------------------- -from specs.azure.clientgenerator.core.clientinitialization.default import ( - HeaderParamClient, - MultipleParamsClient, - MixedParamsClient, - PathParamClient, - ParamAliasClient, -) -from specs.azure.clientgenerator.core.clientinitialization.default.models import Input - - -def test_header_param_client(): - with HeaderParamClient("test-name-value") as client: - client.with_query(id="test-id") - client.with_body(Input(name="test-name")) - - -def test_multiple_params_client(): - with MultipleParamsClient("test-name-value", "us-west") as client: - client.with_query(id="test-id") - client.with_body(Input(name="test-name")) - - -def test_mixed_params_client(): - with MixedParamsClient("test-name-value") as client: - client.with_query(region="us-west", id="test-id") - client.with_body(Input(name="test-name"), region="us-west") - - -def test_path_param_client(): - with PathParamClient("sample-blob") as client: - client.with_query(format="text") - client.get_standalone() - client.delete_standalone() - - -def test_param_alias_client(): - with ParamAliasClient("sample-blob") as client: - client.with_aliased_name() - client.with_original_name() - - -# def test_parent_child_client(): -# with ParentClient() as client: -# client.child_client.with_query() -# client.child_client.get_standalone() -# client.child_client.delete_standalone() diff --git a/packages/typespec-python/tests/mock_api/azure/test_azure_client_generator_core_client_location.py b/packages/typespec-python/tests/mock_api/azure/test_azure_client_generator_core_client_location.py deleted file mode 100644 index 954ef99a70..0000000000 --- a/packages/typespec-python/tests/mock_api/azure/test_azure_client_generator_core_client_location.py +++ /dev/null @@ -1,70 +0,0 @@ -# ------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for -# license information. -# -------------------------------------------------------------------------- -import pytest -from specs.azure.clientgenerator.core.clientlocation.parameter import MoveMethodParameterToClient -from specs.azure.clientgenerator.core.clientlocation.subclient import MoveToExistingSubClient -from specs.azure.clientgenerator.core.clientlocation.newsubclient import MoveToNewSubClient -from specs.azure.clientgenerator.core.clientlocation.rootclient import MoveToRootClient - - -@pytest.fixture -def move_method_parameter_to_client(): - with MoveMethodParameterToClient(storage_account="testaccount") as client: - yield client - - -@pytest.fixture -def move_to_existing_sub_client(): - with MoveToExistingSubClient() as client: - yield client - - -@pytest.fixture -def move_to_new_sub_client(): - with MoveToNewSubClient() as client: - yield client - - -@pytest.fixture -def move_to_root_client(): - with MoveToRootClient() as client: - yield client - - -def test_move_method_parameter_to_client_blob_operations_get_blob( - move_method_parameter_to_client: MoveMethodParameterToClient, -): - move_method_parameter_to_client.blob_operations.get_blob(container="testcontainer", blob="testblob.txt") - - -def test_move_to_existing_sub_client_user_operations_get_user(move_to_existing_sub_client: MoveToExistingSubClient): - move_to_existing_sub_client.user_operations.get_user() - - -def test_move_to_existing_sub_client_admin_operations_delete_user(move_to_existing_sub_client: MoveToExistingSubClient): - move_to_existing_sub_client.admin_operations.delete_user() - - -def test_move_to_existing_sub_client_admin_operations_get_admin_info( - move_to_existing_sub_client: MoveToExistingSubClient, -): - move_to_existing_sub_client.admin_operations.get_admin_info() - - -def test_move_to_new_sub_client_product_operations_list_products(move_to_new_sub_client: MoveToNewSubClient): - move_to_new_sub_client.product_operations.list_products() - - -def test_move_to_new_sub_client_archive_operations_archive_product(move_to_new_sub_client: MoveToNewSubClient): - move_to_new_sub_client.archive_operations.archive_product() - - -def test_move_to_root_client_resource_operations_get_resource(move_to_root_client: MoveToRootClient): - move_to_root_client.resource_operations.get_resource() - - -def test_move_to_root_client_get_health_status(move_to_root_client: MoveToRootClient): - move_to_root_client.get_health_status() diff --git a/packages/typespec-python/tests/mock_api/azure/test_azure_client_generator_core_deserialize_empty_string_as_null.py b/packages/typespec-python/tests/mock_api/azure/test_azure_client_generator_core_deserialize_empty_string_as_null.py deleted file mode 100644 index a83be0cd02..0000000000 --- a/packages/typespec-python/tests/mock_api/azure/test_azure_client_generator_core_deserialize_empty_string_as_null.py +++ /dev/null @@ -1,19 +0,0 @@ -# ------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for -# license information. -# -------------------------------------------------------------------------- -import pytest -from specs.azure.clientgenerator.core.emptystring import DeserializeEmptyStringAsNullClient -from specs.azure.clientgenerator.core.emptystring import models - - -@pytest.fixture -def client(): - with DeserializeEmptyStringAsNullClient() as client: - yield client - - -def test_get(client: DeserializeEmptyStringAsNullClient): - result = client.get() - assert result == models.ResponseModel(sample_url="") diff --git a/packages/typespec-python/tests/mock_api/azure/test_azure_client_generator_core_flatten.py b/packages/typespec-python/tests/mock_api/azure/test_azure_client_generator_core_flatten.py deleted file mode 100644 index 30745aae25..0000000000 --- a/packages/typespec-python/tests/mock_api/azure/test_azure_client_generator_core_flatten.py +++ /dev/null @@ -1,104 +0,0 @@ -# ------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for -# license information. -# -------------------------------------------------------------------------- -import pytest -from specs.azure.clientgenerator.core.flattenproperty import FlattenPropertyClient -from specs.azure.clientgenerator.core.flattenproperty.models import ( - ChildFlattenModel, - ChildModel, - FlattenModel, - FlattenUnknownModel, - NestedFlattenModel, - Solution, - SolutionProperties, -) - - -@pytest.fixture -def client(): - with FlattenPropertyClient() as client: - yield client - - -# ========== test for spector ========== - - -def test_put_flatten_model(client: FlattenPropertyClient): - resp = FlattenModel(name="test", properties=ChildModel(age=1, description="test")) - assert client.put_flatten_model(FlattenModel(name="foo", properties=ChildModel(age=10, description="bar"))) == resp - assert client.put_flatten_model(FlattenModel(name="foo", age=10, description="bar")) == resp - - -def test_put_nested_flatten_model(client: FlattenPropertyClient): - # python doesn't support nested flatten model - assert client.put_nested_flatten_model( - NestedFlattenModel( - name="foo", - properties=ChildFlattenModel(summary="bar", properties=ChildModel(age=10, description="test")), - ) - ) == NestedFlattenModel( - name="test", - properties=ChildFlattenModel(summary="test", properties=ChildModel(age=1, description="foo")), - ) - - -def test_put_flatten_unknown_model(client: FlattenPropertyClient): - result = client.put_flatten_unknown_model(FlattenUnknownModel(name="foo")) - assert result.name == "test" - assert result.properties == {"key1": "value1", "key2": "value2"} - - -def test_put_flatten_read_only_model(client: FlattenPropertyClient): - result = client.put_flatten_read_only_model(Solution(name="foo")) - assert result == Solution( - name="foo", - properties=SolutionProperties(solution_id="solution1", title="Solution Title", content="Solution Content"), - ) - assert result.solution_id == "solution1" - assert result.title == "Solution Title" - assert result.content == "Solution Content" - - -# ============test for compatibility ============ -def test_dpg_model_common(): - flatten_model = FlattenModel(name="hello", properties=ChildModel(age=0, description="test")) - assert flatten_model.name == "hello" - assert flatten_model.properties.age == 0 - assert flatten_model.properties.description == "test" - - -def test_dpg_model_none(): - flatten_model = FlattenModel() - assert flatten_model.name is None - assert flatten_model.properties is None - assert flatten_model.age is None - assert flatten_model.description is None - - -def test_dpg_model_compatibility(): - flatten_model = FlattenModel(description="test", age=0) - assert flatten_model.description == "test" - assert flatten_model.age == 0 - assert flatten_model.properties.description == "test" - assert flatten_model.properties.age == 0 - - -def test_dpg_model_setattr(): - flatten_model = FlattenModel() - - flatten_model.age = 0 - assert flatten_model.properties.age == 0 - flatten_model.description = "test" - assert flatten_model.properties.description == "test" - - flatten_model.properties.age = 1 - assert flatten_model.age == 1 - flatten_model.properties.description = "test2" - assert flatten_model.description == "test2" - - -def test_dpg_model_exception(): - with pytest.raises(AttributeError): - FlattenModel().no_prop diff --git a/packages/typespec-python/tests/mock_api/azure/test_azure_client_generator_core_hierrarchy_building.py b/packages/typespec-python/tests/mock_api/azure/test_azure_client_generator_core_hierrarchy_building.py deleted file mode 100644 index f11314f6e9..0000000000 --- a/packages/typespec-python/tests/mock_api/azure/test_azure_client_generator_core_hierrarchy_building.py +++ /dev/null @@ -1,45 +0,0 @@ -# ------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for -# license information. -# -------------------------------------------------------------------------- -import pytest -from specs.azure.clientgenerator.core.hierarchybuilding import HierarchyBuildingClient -from specs.azure.clientgenerator.core.hierarchybuilding.models import ( - Pet, - Dog, -) - - -@pytest.fixture -def client(): - with HierarchyBuildingClient() as client: - yield client - - -# ========== test for spector ========== - - -def test_update_pet_as_pet(client: HierarchyBuildingClient): - resp = Pet(name="Buddy", trained=True) - assert client.pet_operations.update_pet_as_pet(Pet(name="Buddy", trained=True)) == resp - - -def test_update_dog_as_pet(client: HierarchyBuildingClient): - resp = Dog(name="Rex", trained=True, breed="German Shepherd") - assert client.pet_operations.update_dog_as_pet(Dog(name="Rex", trained=True, breed="German Shepherd")) == resp - - -def test_update_pet_as_animal(client: HierarchyBuildingClient): - resp = Pet(name="Buddy", trained=True) - assert client.animal_operations.update_pet_as_animal(Pet(name="Buddy", trained=True)) == resp - - -def test_update_dog_as_animal(client: HierarchyBuildingClient): - resp = Dog(name="Rex", trained=True, breed="German Shepherd") - assert client.animal_operations.update_dog_as_animal(Dog(name="Rex", trained=True, breed="German Shepherd")) == resp - - -def test_update_dog_as_dog(client: HierarchyBuildingClient): - resp = Dog(name="Rex", trained=True, breed="German Shepherd") - assert client.dog_operations.update_dog_as_dog(Dog(name="Rex", trained=True, breed="German Shepherd")) == resp diff --git a/packages/typespec-python/tests/mock_api/azure/test_azure_client_generator_core_next_link_verb.py b/packages/typespec-python/tests/mock_api/azure/test_azure_client_generator_core_next_link_verb.py deleted file mode 100644 index dd8c5a8bbf..0000000000 --- a/packages/typespec-python/tests/mock_api/azure/test_azure_client_generator_core_next_link_verb.py +++ /dev/null @@ -1,27 +0,0 @@ -# ------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for -# license information. -# -------------------------------------------------------------------------- -import pytest - -from specs.azure.clientgenerator.core.nextlinkverb import NextLinkVerbClient - - -@pytest.fixture -def client(): - with NextLinkVerbClient(endpoint="http://localhost:3000") as client: - yield client - - -def assert_items(items): - items = list(items) - assert len(items) == 2 - assert items[0].id == "test1" - assert items[1].id == "test2" - - -def test_list_items_next_link_verb(client: NextLinkVerbClient): - # The operation uses POST for nextLink per @nextLinkVerb - pager = client.list_items() - assert_items(pager) diff --git a/packages/typespec-python/tests/mock_api/azure/test_azure_client_generator_core_override.py b/packages/typespec-python/tests/mock_api/azure/test_azure_client_generator_core_override.py deleted file mode 100644 index 07a83a129f..0000000000 --- a/packages/typespec-python/tests/mock_api/azure/test_azure_client_generator_core_override.py +++ /dev/null @@ -1,102 +0,0 @@ -# ------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for -# license information. -# -------------------------------------------------------------------------- -import inspect -import pytest -from specs.azure.clientgenerator.core.override import OverrideClient - - -@pytest.fixture -def client(): - with OverrideClient() as client: - yield client - - -def test_reorder_parameters(client: OverrideClient): - client.reorder_parameters.reorder("param1", "param2") - - -def test_group_parameters(client: OverrideClient): - client.group_parameters.group(param1="param1", param2="param2") - - -def test_require_optional_parameter(client: OverrideClient): - client.require_optional_parameter.require_optional("param1", "param2") - - -def test_remove_optional_parameter(client: OverrideClient): - # Test with optional param2 provided - client.remove_optional_parameter.remove_optional("param1", param2="param2") - - -# make sure signature name of `reorder_parameters` are ["param1", "param2"] -def test_reorder_parameters_unit(client: OverrideClient): - # Get the reorder method from the reorder_parameters operation - reorder_method = client.reorder_parameters.reorder - - # Inspect the method signature - sig = inspect.signature(reorder_method) - - # Get parameter names excluding 'self' and '**kwargs' - param_names = [ - param_name - for param_name, param in sig.parameters.items() - if param_name not in ("self", "kwargs") and param.kind != param.VAR_KEYWORD - ] - - # Assert that the parameter names are exactly ["param1", "param2"] - assert param_names == ["param1", "param2"], f"Expected parameter names ['param1', 'param2'], but got {param_names}" - - -def test_require_optional_parameter_signature(client: OverrideClient): - # Get the require_optional method - require_optional_method = client.require_optional_parameter.require_optional - - # Inspect the method signature - sig = inspect.signature(require_optional_method) - - # Get parameter details - params = sig.parameters - - # Check that both param1 and param2 are required (no default values) - assert "param1" in params, "param1 should be present in signature" - assert "param2" in params, "param2 should be present in signature" - assert params["param1"].default == params["param1"].empty, "param1 should have no default value" - assert params["param2"].default == params["param2"].empty, "param2 should have no default value" - - -def test_remove_optional_parameter_signature(client: OverrideClient): - """Test that remove_optional_parameter.remove_optional method signature has correct parameters. - - The @override decorator should remove some optional parameters from the method signature. - Only param1 (required) and param2 (optional) should remain. - """ - # Get the remove_optional method - remove_optional_method = client.remove_optional_parameter.remove_optional - - # Inspect the method signature - sig = inspect.signature(remove_optional_method) - - # Get parameter names excluding 'self' and '**kwargs' - param_names = [ - param_name - for param_name, param in sig.parameters.items() - if param_name not in ("self", "kwargs") and param.kind != param.VAR_KEYWORD - ] - - # Should have param1 (required) and param2 (keyword-only optional) - assert "param1" in param_names, "param1 should be present in signature" - assert "param2" in sig.parameters, "param2 should be present in signature" - - # param1 should be required (positional) - assert sig.parameters["param1"].default == sig.parameters["param1"].empty, "param1 should have no default value" - - # param2 should be optional keyword-only with None default - assert sig.parameters["param2"].kind == sig.parameters["param2"].KEYWORD_ONLY, "param2 should be keyword-only" - assert sig.parameters["param2"].default is None, "param2 should have None as default value" - - # param3 and param4 should be removed - assert "param3" not in param_names, "param3 should not be present in signature" - assert "param4" not in param_names, "param4 should not be present in signature" diff --git a/packages/typespec-python/tests/mock_api/azure/test_azure_client_generator_core_usage.py b/packages/typespec-python/tests/mock_api/azure/test_azure_client_generator_core_usage.py deleted file mode 100644 index 0094bef89a..0000000000 --- a/packages/typespec-python/tests/mock_api/azure/test_azure_client_generator_core_usage.py +++ /dev/null @@ -1,32 +0,0 @@ -# ------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for -# license information. -# -------------------------------------------------------------------------- -import pytest -from specs.azure.clientgenerator.core.usage import UsageClient -from specs.azure.clientgenerator.core.usage import models - - -@pytest.fixture -def client(): - with UsageClient() as client: - yield client - - -def test_input_to_input_output(client: UsageClient): - client.model_in_operation.input_to_input_output(models.InputModel(name="Madge")) - - -def test_output_to_input_output(client: UsageClient): - assert models.OutputModel(name="Madge") == client.model_in_operation.output_to_input_output() - - -def test_model_usage(client: UsageClient): - assert models.RoundTripModel( - result=models.ResultModel(name="Madge") - ) == client.model_in_operation.model_in_read_only_property(body=models.RoundTripModel()) - - -def test_orphan_model_serializable(client: UsageClient): - client.model_in_operation.orphan_model_serializable(body=models.OrphanModel(model_name="name", description="desc")) diff --git a/packages/typespec-python/tests/mock_api/azure/test_azure_core_basic.py b/packages/typespec-python/tests/mock_api/azure/test_azure_core_basic.py deleted file mode 100644 index 8ba50795a8..0000000000 --- a/packages/typespec-python/tests/mock_api/azure/test_azure_core_basic.py +++ /dev/null @@ -1,70 +0,0 @@ -# ------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for -# license information. -# -------------------------------------------------------------------------- -import pytest -from specs.azure.core.basic import BasicClient, models - -VALID_USER = models.User(id=1, name="Madge", etag="11bdc430-65e8-45ad-81d9-8ffa60d55b59") - - -@pytest.fixture -def client(): - with BasicClient() as client: - yield client - - -def test_create_or_update(client: BasicClient): - result = client.create_or_update(id=1, resource={"name": "Madge"}) - assert result == VALID_USER - - -def test_create_or_replace(client: BasicClient): - result = client.create_or_replace(id=1, resource={"name": "Madge"}) - assert result == VALID_USER - - -def test_get(client: BasicClient): - result = client.get(id=1) - assert result == VALID_USER - - -def test_list(client: BasicClient): - result = list( - client.list( - top=5, - skip=10, - orderby=["id"], - filter="id lt 10", - select=["id", "orders", "etag"], - expand=["orders"], - ) - ) - assert len(result) == 2 - assert result[0].id == 1 - assert result[0].name == "Madge" - assert result[0].etag == "11bdc430-65e8-45ad-81d9-8ffa60d55b59" - assert result[0].orders[0].id == 1 - assert result[0].orders[0].user_id == 1 - assert result[0].orders[0].detail == "a recorder" - assert result[1].id == 2 - assert result[1].name == "John" - assert result[1].etag == "11bdc430-65e8-45ad-81d9-8ffa60d55b5a" - assert result[1].orders[0].id == 2 - assert result[1].orders[0].user_id == 2 - assert result[1].orders[0].detail == "a TV" - - -def test_delete(client: BasicClient): - client.delete(id=1) - - -def test_export(client: BasicClient): - result = client.export(id=1, format="json") - assert result == VALID_USER - - -def test_export_all_users(client: BasicClient): - result = client.export_all_users(format="json") - assert result.users[0] == VALID_USER diff --git a/packages/typespec-python/tests/mock_api/azure/test_azure_core_lro_rpc.py b/packages/typespec-python/tests/mock_api/azure/test_azure_core_lro_rpc.py deleted file mode 100644 index 7710fd9eb6..0000000000 --- a/packages/typespec-python/tests/mock_api/azure/test_azure_core_lro_rpc.py +++ /dev/null @@ -1,20 +0,0 @@ -# ------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for -# license information. -# -------------------------------------------------------------------------- -import pytest -from specs.azure.core.lro.rpc import RpcClient, models - - -@pytest.fixture -def client(): - with RpcClient() as client: - yield client - - -def test_long_running_rpc(client: RpcClient, polling_method): - result = client.begin_long_running_rpc( - models.GenerationOptions(prompt="text"), polling_interval=0, polling=polling_method - ).result() - assert result == models.GenerationResult(data="text data") diff --git a/packages/typespec-python/tests/mock_api/azure/test_azure_core_lro_standard.py b/packages/typespec-python/tests/mock_api/azure/test_azure_core_lro_standard.py deleted file mode 100644 index c9337e93fa..0000000000 --- a/packages/typespec-python/tests/mock_api/azure/test_azure_core_lro_standard.py +++ /dev/null @@ -1,32 +0,0 @@ -# ------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for -# license information. -# -------------------------------------------------------------------------- -import pytest -from specs.azure.core.lro.standard import StandardClient -from specs.azure.core.lro.standard.models import User, ExportedUser - - -@pytest.fixture -def client(): - with StandardClient() as client: - yield client - - -def test_lro_core_put(client, polling_method): - user = User({"name": "madge", "role": "contributor"}) - result = client.begin_create_or_replace( - name=user.name, resource=user, polling_interval=0, polling=polling_method - ).result() - assert result == user - - -def test_lro_core_delete(client, polling_method): - client.begin_delete(name="madge", polling_interval=0, polling=polling_method).result() - - -def test_lro_core_export(client, polling_method): - export_user = ExportedUser({"name": "madge", "resourceUri": "/users/madge"}) - result = client.begin_export(name="madge", format="json", polling_interval=0, polling=polling_method).result() - assert result == export_user diff --git a/packages/typespec-python/tests/mock_api/azure/test_azure_core_model.py b/packages/typespec-python/tests/mock_api/azure/test_azure_core_model.py deleted file mode 100644 index adca0211e5..0000000000 --- a/packages/typespec-python/tests/mock_api/azure/test_azure_core_model.py +++ /dev/null @@ -1,30 +0,0 @@ -# ------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for -# license information. -# -------------------------------------------------------------------------- -import pytest -from specs.azure.core.model import ModelClient -from specs.azure.core.model.models import AzureEmbeddingModel - - -@pytest.fixture -def client(): - with ModelClient() as client: - yield client - - -def test_azure_core_embedding_vector_post(client: ModelClient): - embedding_model = AzureEmbeddingModel(embedding=[0, 1, 2, 3, 4]) - result = client.azure_core_embedding_vector.post( - body=embedding_model, - ) - assert result == AzureEmbeddingModel(embedding=[5, 6, 7, 8, 9]) - - -def test_azure_core_embedding_vector_put(client: ModelClient): - client.azure_core_embedding_vector.put(body=[0, 1, 2, 3, 4]) - - -def test_azure_core_embedding_vector_get(client: ModelClient): - assert [0, 1, 2, 3, 4] == client.azure_core_embedding_vector.get() diff --git a/packages/typespec-python/tests/mock_api/azure/test_azure_core_page.py b/packages/typespec-python/tests/mock_api/azure/test_azure_core_page.py deleted file mode 100644 index b5837623be..0000000000 --- a/packages/typespec-python/tests/mock_api/azure/test_azure_core_page.py +++ /dev/null @@ -1,71 +0,0 @@ -# ------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for -# license information. -# -------------------------------------------------------------------------- -import pytest -from typing import Iterable -from specs.azure.core.page import PageClient, models - -VALID_USER = models.User(id=1, name="Madge", etag="11bdc430-65e8-45ad-81d9-8ffa60d55b59") - - -@pytest.fixture -def client(): - with PageClient() as client: - yield client - - -def _list_with_page_tests(pager: Iterable[models.User]): - result = list(pager) - assert len(result) == 1 - assert result[0].id == 1 - assert result[0].name == "Madge" - assert result[0].etag == "11bdc430-65e8-45ad-81d9-8ffa60d55b59" - assert result[0].orders is None - - -def test_list_with_page(client: PageClient): - _list_with_page_tests(client.list_with_page()) - - -def test_list_with_custom_page_model(client: PageClient): - _list_with_page_tests(client.list_with_custom_page_model()) - with pytest.raises(AttributeError): - models.CustomPageModel - - -def test_list_with_parameters(client: PageClient): - result = list(client.list_with_parameters(models.ListItemInputBody(input_name="Madge"), another="Second")) - assert len(result) == 1 - assert result[0] == VALID_USER - - -def test_two_models_as_page_item(client: PageClient): - result = list(client.two_models_as_page_item.list_first_item()) - assert len(result) == 1 - assert result[0].id == 1 - - result = list(client.two_models_as_page_item.list_second_item()) - assert len(result) == 1 - assert result[0].name == "Madge" - - -def test_list_with_parameterized_next_link(client: PageClient): - result = list(client.with_parameterized_next_link(select="name", include_pending=True)) - assert len(result) == 2 - assert result[0].id == 1 - assert result[0].name == "User1" - assert result[1].id == 2 - assert result[1].name == "User2" - - -def test_list_with_relative_next_link(client: PageClient): - result = list(client.with_relative_next_link()) - assert len(result) == 2 - assert result[0].id == 1 - assert result[0].name == "User1" - assert result[0].etag == "11bdc430-65e8-45ad-81d9-8ffa60d55b59" - assert result[1].id == 2 - assert result[1].name == "User2" - assert result[1].etag == "11bdc430-65e8-45ad-81d9-8ffa60d55b59" diff --git a/packages/typespec-python/tests/mock_api/azure/test_azure_core_scalar.py b/packages/typespec-python/tests/mock_api/azure/test_azure_core_scalar.py deleted file mode 100644 index 1bca122b36..0000000000 --- a/packages/typespec-python/tests/mock_api/azure/test_azure_core_scalar.py +++ /dev/null @@ -1,35 +0,0 @@ -# ------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for -# license information. -# -------------------------------------------------------------------------- -import pytest -from specs.azure.core.scalar import ScalarClient, models - - -@pytest.fixture -def client(): - with ScalarClient() as client: - yield client - - -def test_azure_location_scalar_get(client: ScalarClient): - result = client.azure_location_scalar.get() - assert result == "eastus" - - -def test_azure_location_scalar_put(client: ScalarClient): - client.azure_location_scalar.put("eastus") - - -def test_azure_location_scalar_post(client: ScalarClient): - result = client.azure_location_scalar.post(models.AzureLocationModel(location="eastus")) - assert result == models.AzureLocationModel(location="eastus") - - -def test_azure_location_scalar_header(client: ScalarClient): - client.azure_location_scalar.header(region="eastus") - - -def test_azure_location_scalar_query(client: ScalarClient): - client.azure_location_scalar.query(region="eastus") diff --git a/packages/typespec-python/tests/mock_api/azure/test_azure_core_traits.py b/packages/typespec-python/tests/mock_api/azure/test_azure_core_traits.py deleted file mode 100644 index 982931efb5..0000000000 --- a/packages/typespec-python/tests/mock_api/azure/test_azure_core_traits.py +++ /dev/null @@ -1,85 +0,0 @@ -# ------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for -# license information. -# -------------------------------------------------------------------------- -import functools -from datetime import datetime - -import pytest -from azure.core.exceptions import HttpResponseError -from azure.core import MatchConditions -from specs.azure.core.traits import TraitsClient -from specs.azure.core.traits.models import UserActionParam - - -@pytest.fixture -def client(): - with TraitsClient() as client: - yield client - - -def test_get(client: TraitsClient, check_client_request_id_header): - def assert_test_get(**kwargs): - checked = {} - result, header = client.smoke_test( - id=1, - foo="123", - if_unmodified_since=datetime(year=2022, month=8, day=26, hour=14, minute=38, second=0), - if_modified_since=datetime(year=2021, month=8, day=26, hour=14, minute=38, second=0), - cls=lambda x, y, z: (y, z), - raw_request_hook=functools.partial( - check_client_request_id_header, header="x-ms-client-request-id", checked=checked - ), - **kwargs, - ) - assert result.id == 1 - assert result.name == "Madge" - assert header["ETag"] == "11bdc430-65e8-45ad-81d9-8ffa60d55b59" - assert header["bar"] == "456" - assert header["x-ms-client-request-id"] == checked["x-ms-client-request-id"] - - assert_test_get(etag="valid", match_condition=MatchConditions.IfNotModified) - assert_test_get(etag="invalid", match_condition=MatchConditions.IfModified) - with pytest.raises(HttpResponseError): - assert_test_get() - - -def test_repeatable_action(client: TraitsClient, check_repeatability_header): - result, header = client.repeatable_action( - id=1, - body=UserActionParam(user_action_value="test"), - cls=lambda x, y, z: (y, z), - raw_request_hook=check_repeatability_header, - ) - assert result.user_action_result == "test" - assert header["Repeatability-Result"] == "accepted" - - result, header = client.repeatable_action( - id=1, - body=UserActionParam(user_action_value="test"), - cls=lambda x, y, z: (y, z), - headers={ - "Repeatability-Request-ID": "5942d803-e3fa-4f96-8f67-607d7bd607f5", - "Repeatability-First-Sent": "Sun, 06 Nov 1994 08:49:37 GMT", - }, - raw_request_hook=check_repeatability_header, - ) - assert result.user_action_result == "test" - assert header["Repeatability-Result"] == "accepted" - - with pytest.raises(HttpResponseError): - client.repeatable_action( - id=1, - body=UserActionParam(user_action_value="test"), - cls=lambda x, y, z: (y, z), - headers={"Repeatability-Request-ID": "wrong-id"}, - ) - - with pytest.raises(HttpResponseError): - client.repeatable_action( - id=1, - body=UserActionParam(user_action_value="test"), - cls=lambda x, y, z: (y, z), - headers={"Repeatability-First-Sent": "wrong-datetime"}, - ) diff --git a/packages/typespec-python/tests/mock_api/azure/test_azure_encode_duration.py b/packages/typespec-python/tests/mock_api/azure/test_azure_encode_duration.py deleted file mode 100644 index 5ee88a6262..0000000000 --- a/packages/typespec-python/tests/mock_api/azure/test_azure_encode_duration.py +++ /dev/null @@ -1,18 +0,0 @@ -# ------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for -# license information. -# -------------------------------------------------------------------------- -import pytest -from specs.azure.encode.duration import DurationClient -from specs.azure.encode.duration import models - - -@pytest.fixture -def client(): - with DurationClient() as client: - yield client - - -def test_duration_constant(client: DurationClient): - client.duration_constant(models.DurationModel(input="1.02:59:59.5000000")) diff --git a/packages/typespec-python/tests/mock_api/azure/test_azure_example_basic.py b/packages/typespec-python/tests/mock_api/azure/test_azure_example_basic.py deleted file mode 100644 index a3b0ee01cd..0000000000 --- a/packages/typespec-python/tests/mock_api/azure/test_azure_example_basic.py +++ /dev/null @@ -1,29 +0,0 @@ -# ------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for -# license information. -# -------------------------------------------------------------------------- -import pytest -from specs.azure.example.basic import AzureExampleClient -from specs.azure.example.basic.models import ActionRequest, Model - - -@pytest.fixture -def client(): - with AzureExampleClient() as client: - yield client - - -def test_basic_action(client: AzureExampleClient): - body = ActionRequest( - string_property="text", - model_property=Model(int32_property=1, float32_property=1.5, enum_property="EnumValue1"), - array_property=["item"], - record_property={"record": "value"}, - ) - result = client.basic_action( - body=body, - query_param="query", - header_param="header", - ) - assert result.string_property == body.string_property diff --git a/packages/typespec-python/tests/mock_api/azure/test_azure_payload_pageable.py b/packages/typespec-python/tests/mock_api/azure/test_azure_payload_pageable.py deleted file mode 100644 index e846ae434c..0000000000 --- a/packages/typespec-python/tests/mock_api/azure/test_azure_payload_pageable.py +++ /dev/null @@ -1,18 +0,0 @@ -# ------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for -# license information. -# -------------------------------------------------------------------------- -import pytest -from specs.azure.payload.pageable import PageableClient - - -@pytest.fixture -def client(): - with PageableClient(endpoint="http://localhost:3000") as client: - yield client - - -def test_list(client: PageableClient): - result = list(client.list(maxpagesize=3)) - assert len(result) == 4 diff --git a/packages/typespec-python/tests/mock_api/azure/test_azure_resource_manager_method_subscription_id.py b/packages/typespec-python/tests/mock_api/azure/test_azure_resource_manager_method_subscription_id.py deleted file mode 100644 index 5f3704a5a1..0000000000 --- a/packages/typespec-python/tests/mock_api/azure/test_azure_resource_manager_method_subscription_id.py +++ /dev/null @@ -1,235 +0,0 @@ -# ------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for -# license information. -# -------------------------------------------------------------------------- -import pytest -from azure.resourcemanager.methodsubscriptionid import MethodSubscriptionIdClient -from azure.resourcemanager.methodsubscriptionid import models - -SUBSCRIPTION_ID = "00000000-0000-0000-0000-000000000000" -RESOURCE_GROUP_NAME = "test-rg" - - -@pytest.fixture -def client(credential, authentication_policy): - with MethodSubscriptionIdClient( - credential, - SUBSCRIPTION_ID, - "http://localhost:3000", - authentication_policy=authentication_policy, - ) as client: - yield client - - -def test_operations_list(client): - """Test Operations.list() endpoint.""" - operations = client.operations.list() - operations_list = [op for op in operations] - assert len(operations_list) > 0 - - operation = operations_list[0] - assert operation.name == "Azure.ResourceManager.MethodSubscriptionId/services/read" - assert operation.is_data_action is False - assert operation.display.provider == "Azure.ResourceManager.MethodSubscriptionId" - assert operation.display.resource == "services" - assert operation.display.operation == "Lists services" - assert operation.display.description == "Lists registered services" - - -def test_two_subscription_resources_method_level_subscription_resource1_operations_get(client): - """Test get operation for SubscriptionResource1 with method-level subscription ID.""" - result = client.two_subscription_resources_method_level.subscription_resource1_operations.get( - subscription_id=SUBSCRIPTION_ID, - subscription_resource1_name="sub-resource-1", - ) - - assert ( - result.id - == f"/subscriptions/{SUBSCRIPTION_ID}/providers/Azure.ResourceManager.MethodSubscriptionId/subscriptionResource1s/sub-resource-1" - ) - assert result.name == "sub-resource-1" - assert result.type == "Azure.ResourceManager.MethodSubscriptionId/subscriptionResource1s" - assert result.properties.description == "Valid subscription resource 1" - assert result.properties.provisioning_state == "Succeeded" - assert result.system_data.created_by == "AzureSDK" - - -def test_two_subscription_resources_method_level_subscription_resource1_operations_put(client): - """Test put operation for SubscriptionResource1 with method-level subscription ID.""" - resource = models.SubscriptionResource1( - properties=models.SubscriptionResource1Properties(description="Valid subscription resource 1") - ) - - result = client.two_subscription_resources_method_level.subscription_resource1_operations.put( - subscription_id=SUBSCRIPTION_ID, - subscription_resource1_name="sub-resource-1", - resource=resource, - ) - - assert ( - result.id - == f"/subscriptions/{SUBSCRIPTION_ID}/providers/Azure.ResourceManager.MethodSubscriptionId/subscriptionResource1s/sub-resource-1" - ) - assert result.name == "sub-resource-1" - assert result.type == "Azure.ResourceManager.MethodSubscriptionId/subscriptionResource1s" - assert result.properties.description == "Valid subscription resource 1" - assert result.properties.provisioning_state == "Succeeded" - assert result.system_data.created_by == "AzureSDK" - - -def test_two_subscription_resources_method_level_subscription_resource1_operations_delete(client): - """Test delete operation for SubscriptionResource1 with method-level subscription ID.""" - client.two_subscription_resources_method_level.subscription_resource1_operations.delete( - subscription_id=SUBSCRIPTION_ID, - subscription_resource1_name="sub-resource-1", - ) - - -def test_two_subscription_resources_method_level_subscription_resource2_operations_get(client): - """Test get operation for SubscriptionResource2 with method-level subscription ID.""" - result = client.two_subscription_resources_method_level.subscription_resource2_operations.get( - subscription_id=SUBSCRIPTION_ID, - subscription_resource2_name="sub-resource-2", - ) - - assert ( - result.id - == f"/subscriptions/{SUBSCRIPTION_ID}/providers/Azure.ResourceManager.MethodSubscriptionId/subscriptionResource2s/sub-resource-2" - ) - assert result.name == "sub-resource-2" - assert result.type == "Azure.ResourceManager.MethodSubscriptionId/subscriptionResource2s" - assert result.properties.config_value == "test-config" - assert result.properties.provisioning_state == "Succeeded" - assert result.system_data.created_by == "AzureSDK" - - -def test_two_subscription_resources_method_level_subscription_resource2_operations_put(client): - """Test put operation for SubscriptionResource2 with method-level subscription ID.""" - resource = models.SubscriptionResource2( - properties=models.SubscriptionResource2Properties(config_value="test-config") - ) - - result = client.two_subscription_resources_method_level.subscription_resource2_operations.put( - subscription_id=SUBSCRIPTION_ID, - subscription_resource2_name="sub-resource-2", - resource=resource, - ) - - assert ( - result.id - == f"/subscriptions/{SUBSCRIPTION_ID}/providers/Azure.ResourceManager.MethodSubscriptionId/subscriptionResource2s/sub-resource-2" - ) - assert result.name == "sub-resource-2" - assert result.type == "Azure.ResourceManager.MethodSubscriptionId/subscriptionResource2s" - assert result.properties.config_value == "test-config" - assert result.properties.provisioning_state == "Succeeded" - assert result.system_data.created_by == "AzureSDK" - - -def test_two_subscription_resources_method_level_subscription_resource2_operations_delete(client): - """Test delete operation for SubscriptionResource2 with method-level subscription ID.""" - client.two_subscription_resources_method_level.subscription_resource2_operations.delete( - subscription_id=SUBSCRIPTION_ID, - subscription_resource2_name="sub-resource-2", - ) - - -def test_mixed_subscription_placement_subscription_resource_operations_get(client): - """Test get operation for SubscriptionResource in mixed placement scenario.""" - result = client.mixed_subscription_placement.subscription_resource_operations.get( - subscription_id=SUBSCRIPTION_ID, - subscription_resource_name="sub-resource", - ) - - assert ( - result.id - == f"/subscriptions/{SUBSCRIPTION_ID}/providers/Azure.ResourceManager.MethodSubscriptionId/subscriptionResources/sub-resource" - ) - assert result.name == "sub-resource" - assert result.type == "Azure.ResourceManager.MethodSubscriptionId/subscriptionResources" - assert result.properties.subscription_setting == "test-sub-setting" - assert result.properties.provisioning_state == "Succeeded" - assert result.system_data.created_by == "AzureSDK" - - -def test_mixed_subscription_placement_subscription_resource_operations_put(client): - """Test put operation for SubscriptionResource in mixed placement scenario.""" - resource = models.SubscriptionResource( - properties=models.SubscriptionResourceProperties(subscription_setting="test-sub-setting") - ) - - result = client.mixed_subscription_placement.subscription_resource_operations.put( - subscription_id=SUBSCRIPTION_ID, - subscription_resource_name="sub-resource", - resource=resource, - ) - - assert ( - result.id - == f"/subscriptions/{SUBSCRIPTION_ID}/providers/Azure.ResourceManager.MethodSubscriptionId/subscriptionResources/sub-resource" - ) - assert result.name == "sub-resource" - assert result.type == "Azure.ResourceManager.MethodSubscriptionId/subscriptionResources" - assert result.properties.subscription_setting == "test-sub-setting" - assert result.properties.provisioning_state == "Succeeded" - assert result.system_data.created_by == "AzureSDK" - - -def test_mixed_subscription_placement_subscription_resource_operations_delete(client): - """Test delete operation for SubscriptionResource in mixed placement scenario.""" - client.mixed_subscription_placement.subscription_resource_operations.delete( - subscription_id=SUBSCRIPTION_ID, - subscription_resource_name="sub-resource", - ) - - -def test_mixed_subscription_placement_resource_group_resource_operations_get(client): - """Test get operation for ResourceGroupResource with client-level subscription ID.""" - result = client.mixed_subscription_placement.resource_group_resource_operations.get( - resource_group_name=RESOURCE_GROUP_NAME, - resource_group_resource_name="rg-resource", - ) - - assert ( - result.id - == f"/subscriptions/{SUBSCRIPTION_ID}/resourceGroups/{RESOURCE_GROUP_NAME}/providers/Azure.ResourceManager.MethodSubscriptionId/resourceGroupResources/rg-resource" - ) - assert result.name == "rg-resource" - assert result.type == "Azure.ResourceManager.MethodSubscriptionId/resourceGroupResources" - assert result.location == "eastus" - assert result.properties.resource_group_setting == "test-setting" - assert result.properties.provisioning_state == "Succeeded" - assert result.system_data.created_by == "AzureSDK" - - -def test_mixed_subscription_placement_resource_group_resource_operations_put(client): - """Test put operation for ResourceGroupResource with client-level subscription ID.""" - resource = models.ResourceGroupResource( - location="eastus", properties=models.ResourceGroupResourceProperties(resource_group_setting="test-setting") - ) - - result = client.mixed_subscription_placement.resource_group_resource_operations.put( - resource_group_name=RESOURCE_GROUP_NAME, - resource_group_resource_name="rg-resource", - resource=resource, - ) - - assert ( - result.id - == f"/subscriptions/{SUBSCRIPTION_ID}/resourceGroups/{RESOURCE_GROUP_NAME}/providers/Azure.ResourceManager.MethodSubscriptionId/resourceGroupResources/rg-resource" - ) - assert result.name == "rg-resource" - assert result.type == "Azure.ResourceManager.MethodSubscriptionId/resourceGroupResources" - assert result.location == "eastus" - assert result.properties.resource_group_setting == "test-setting" - assert result.properties.provisioning_state == "Succeeded" - assert result.system_data.created_by == "AzureSDK" - - -def test_mixed_subscription_placement_resource_group_resource_operations_delete(client): - """Test delete operation for ResourceGroupResource with client-level subscription ID.""" - client.mixed_subscription_placement.resource_group_resource_operations.delete( - resource_group_name=RESOURCE_GROUP_NAME, - resource_group_resource_name="rg-resource", - ) diff --git a/packages/typespec-python/tests/mock_api/azure/test_azure_resource_manager_multi_service.py b/packages/typespec-python/tests/mock_api/azure/test_azure_resource_manager_multi_service.py deleted file mode 100644 index b56d0e4bfd..0000000000 --- a/packages/typespec-python/tests/mock_api/azure/test_azure_resource_manager_multi_service.py +++ /dev/null @@ -1,104 +0,0 @@ -# ------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for -# license information. -# -------------------------------------------------------------------------- -import pytest -from azure.core.exceptions import HttpResponseError -from azure.resourcemanager.multiservice.combined import CombinedClient -from azure.resourcemanager.multiservice.combined.models import VirtualMachine, Disk - - -@pytest.fixture -def client(credential, authentication_policy): - """Create a Combined client for testing.""" - return CombinedClient( - credential=credential, # Will use mock server, no real auth needed - subscription_id="00000000-0000-0000-0000-000000000000", - base_url="http://localhost:3000", - authentication_policy=authentication_policy, - polling_interval=0.1, # Speed up tests by reducing polling interval - ) - - -def test_virtual_machines_get(client): - resource_group_name = "test-rg" - vm_name = "vm1" - - with pytest.raises(HttpResponseError): - client.virtual_machines.get( - resource_group_name=resource_group_name, - vm_name=vm_name, - api_version="av1", # invalid api version shall raise error - ) - - result = client.virtual_machines.get(resource_group_name=resource_group_name, vm_name=vm_name) - - assert result is not None - assert isinstance(result, VirtualMachine) - assert result.name == vm_name - - -def test_virtual_machines_create_or_update(client): - resource_group_name = "test-rg" - vm_name = "vm1" - - vm_resource = VirtualMachine(location="eastus", properties={}) - - with pytest.raises(HttpResponseError): - client.virtual_machines.begin_create_or_update( - resource_group_name=resource_group_name, - vm_name=vm_name, - resource=vm_resource, - api_version="av1", # invalid api version shall raise error - ).result() - - poller = client.virtual_machines.begin_create_or_update( - resource_group_name=resource_group_name, vm_name=vm_name, resource=vm_resource - ) - - result = poller.result() - assert result is not None - assert isinstance(result, VirtualMachine) - assert result.location == "eastus" - - -def test_disks_get(client): - resource_group_name = "test-rg" - disk_name = "disk1" - with pytest.raises(HttpResponseError): - client.disks.get( - resource_group_name=resource_group_name, - disk_name=disk_name, - api_version="av1", # invalid api version shall raise error - ) - - result = client.disks.get(resource_group_name=resource_group_name, disk_name=disk_name) - - assert result is not None - assert isinstance(result, Disk) - assert result.name == disk_name - - -def test_disks_create_or_update(client): - resource_group_name = "test-rg" - disk_name = "disk1" - - disk_resource = Disk(location="eastus", properties={}) - - with pytest.raises(HttpResponseError): - client.disks.begin_create_or_update( - resource_group_name=resource_group_name, - disk_name=disk_name, - resource=disk_resource, - api_version="av1", # invalid api version shall raise error - ).result() - - poller = client.disks.begin_create_or_update( - resource_group_name=resource_group_name, disk_name=disk_name, resource=disk_resource - ) - - result = poller.result() - assert result is not None - assert isinstance(result, Disk) - assert result.location == "eastus" diff --git a/packages/typespec-python/tests/mock_api/azure/test_azure_resource_manager_multi_service_shared_models.py b/packages/typespec-python/tests/mock_api/azure/test_azure_resource_manager_multi_service_shared_models.py deleted file mode 100644 index 0e3f67ebc1..0000000000 --- a/packages/typespec-python/tests/mock_api/azure/test_azure_resource_manager_multi_service_shared_models.py +++ /dev/null @@ -1,128 +0,0 @@ -# ------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for -# license information. -# -------------------------------------------------------------------------- -import pytest -from azure.resourcemanager.multiservicesharedmodels.combined import CombinedClient -from azure.resourcemanager.multiservicesharedmodels.combined.models import ( - VirtualMachine, - VirtualMachineProperties, - StorageAccount, - StorageAccountProperties, - SharedMetadata, -) - - -@pytest.fixture -def client(credential, authentication_policy): - """Create a Combined client for testing.""" - return CombinedClient( - credential=credential, - subscription_id="00000000-0000-0000-0000-000000000000", - base_url="http://localhost:3000", - authentication_policy=authentication_policy, - polling_interval=0.1, - ) - - -def test_virtual_machines_get(client): - """Test getting a virtual machine with shared metadata.""" - resource_group_name = "test-rg" - vm_name = "vm-shared1" - - result = client.virtual_machines.get(resource_group_name=resource_group_name, vm_name=vm_name) - - assert result is not None - assert isinstance(result, VirtualMachine) - assert result.name == vm_name - assert result.location == "eastus" - assert result.type == "Microsoft.Compute/virtualMachinesShared" - assert result.properties is not None - assert result.properties.provisioning_state == "Succeeded" - assert result.properties.metadata is not None - assert result.properties.metadata.created_by == "user@example.com" - assert result.properties.metadata.tags == {"environment": "production"} - - -def test_virtual_machines_create_or_update(client): - """Test creating or updating a virtual machine with shared metadata.""" - resource_group_name = "test-rg" - vm_name = "vm-shared1" - - vm_resource = VirtualMachine( - location="eastus", - properties=VirtualMachineProperties( - metadata=SharedMetadata( - created_by="user@example.com", - tags={"environment": "production"}, - ), - ), - ) - - poller = client.virtual_machines.begin_create_or_update( - resource_group_name=resource_group_name, - vm_name=vm_name, - resource=vm_resource, - ) - - result = poller.result() - assert result is not None - assert isinstance(result, VirtualMachine) - assert result.location == "eastus" - assert result.properties is not None - assert result.properties.provisioning_state == "Succeeded" - assert result.properties.metadata is not None - assert result.properties.metadata.created_by == "user@example.com" - assert result.properties.metadata.tags == {"environment": "production"} - - -def test_storage_accounts_get(client): - """Test getting a storage account with shared metadata.""" - resource_group_name = "test-rg" - account_name = "account1" - - result = client.storage_accounts.get(resource_group_name=resource_group_name, account_name=account_name) - - assert result is not None - assert isinstance(result, StorageAccount) - assert result.name == account_name - assert result.location == "westus" - assert result.type == "Microsoft.Storage/storageAccounts" - assert result.properties is not None - assert result.properties.provisioning_state == "Succeeded" - assert result.properties.metadata is not None - assert result.properties.metadata.created_by == "admin@example.com" - assert result.properties.metadata.tags == {"department": "engineering"} - - -def test_storage_accounts_create_or_update(client): - """Test creating or updating a storage account with shared metadata.""" - resource_group_name = "test-rg" - account_name = "account1" - - storage_resource = StorageAccount( - location="westus", - properties=StorageAccountProperties( - metadata=SharedMetadata( - created_by="admin@example.com", - tags={"department": "engineering"}, - ), - ), - ) - - poller = client.storage_accounts.begin_create_or_update( - resource_group_name=resource_group_name, - account_name=account_name, - resource=storage_resource, - ) - - result = poller.result() - assert result is not None - assert isinstance(result, StorageAccount) - assert result.location == "westus" - assert result.properties is not None - assert result.properties.provisioning_state == "Succeeded" - assert result.properties.metadata is not None - assert result.properties.metadata.created_by == "admin@example.com" - assert result.properties.metadata.tags == {"department": "engineering"} diff --git a/packages/typespec-python/tests/mock_api/azure/test_azure_special_headers_client_request_id.py b/packages/typespec-python/tests/mock_api/azure/test_azure_special_headers_client_request_id.py deleted file mode 100644 index 5a67d578f1..0000000000 --- a/packages/typespec-python/tests/mock_api/azure/test_azure_special_headers_client_request_id.py +++ /dev/null @@ -1,29 +0,0 @@ -# ------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for -# license information. -# -------------------------------------------------------------------------- -import functools - -import pytest - -from azure.specialheaders.xmsclientrequestid import XmsClientRequestIdClient - - -@pytest.fixture -def client(): - with XmsClientRequestIdClient() as client: - yield client - - -def test_get(client: XmsClientRequestIdClient, check_client_request_id_header): - checked = {} - result, resp = client.get( - cls=lambda x, y, z: (y, x), - raw_request_hook=functools.partial( - check_client_request_id_header, header="x-ms-client-request-id", checked=checked - ), - ) - assert result is None - assert resp.http_response.headers["x-ms-client-request-id"] == checked["x-ms-client-request-id"] - pass diff --git a/packages/typespec-python/tests/mock_api/azure/test_azure_versioning_previewversion.py b/packages/typespec-python/tests/mock_api/azure/test_azure_versioning_previewversion.py deleted file mode 100644 index 2bb1cf7c7d..0000000000 --- a/packages/typespec-python/tests/mock_api/azure/test_azure_versioning_previewversion.py +++ /dev/null @@ -1,50 +0,0 @@ -# ------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for -# license information. -# -------------------------------------------------------------------------- -import pytest -from specs.azure.versioning.previewversion import PreviewVersionClient -from specs.azure.versioning.previewversion.models import UpdateWidgetColorRequest - - -@pytest.fixture -def client(): - with PreviewVersionClient() as client: - yield client - - -@pytest.fixture -def stable_client(): - with PreviewVersionClient(api_version="2024-06-01") as client: - yield client - - -def test_get_widget(client: PreviewVersionClient): - result = client.get_widget(id="widget-123") - assert result.id == "widget-123" - assert result.name == "Sample Widget" - assert result.color == "blue" - - -def test_update_widget_color(client: PreviewVersionClient): - color_update = UpdateWidgetColorRequest(color="red") - result = client.update_widget_color(id="widget-123", color_update=color_update) - assert result.id == "widget-123" - assert result.name == "Sample Widget" - assert result.color == "red" - - with pytest.raises(ValueError): - with PreviewVersionClient(api_version="2024-06-01") as stable_client: - stable_client.update_widget_color(id="widget-123", color_update=color_update) - - -def test_list_widgets(stable_client: PreviewVersionClient): - result = stable_client.list_widgets(name="test") - assert len(result.widgets) == 1 - assert result.widgets[0].id == "widget-1" - assert result.widgets[0].name == "test" - - with pytest.raises(ValueError): - with PreviewVersionClient(api_version="2024-06-01") as client: - client.list_widgets(name="test", color="test") diff --git a/packages/typespec-python/tests/mock_api/azure/test_clear_output_folder.py b/packages/typespec-python/tests/mock_api/azure/test_clear_output_folder.py deleted file mode 100644 index 00125fde0d..0000000000 --- a/packages/typespec-python/tests/mock_api/azure/test_clear_output_folder.py +++ /dev/null @@ -1,23 +0,0 @@ -# ------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for -# license information. -# -------------------------------------------------------------------------- -from pathlib import Path - -GENERATED_PATH = Path(__file__).parent.parent.parent.resolve() / "generated" / "azure" - - -def test_clear_output_folder(): - folder = GENERATED_PATH / "authentication-api-key/authentication/apikey/_operations" - assert folder.exists(), "Operations folder should exist" - assert not (folder / "to_be_deleted.py").exists(), "File to_be_deleted.py should be deleted after regeneration" - - if (GENERATED_PATH / "generation-subdir").exists(): - assert (GENERATED_PATH / "generation-subdir/generated_tests").exists() - assert not (GENERATED_PATH / "generation-subdir/generated_tests/to_be_deleted.py").exists() - - assert (GENERATED_PATH / "generation-subdir/generation/subdir/_generated").exists() - assert not (GENERATED_PATH / "generation-subdir/generation/subdir/_generated/to_be_deleted.py").exists() - - assert (GENERATED_PATH / "generation-subdir/generation/subdir/to_be_kept.py").exists() diff --git a/packages/typespec-python/tests/mock_api/azure/test_client_namespace.py b/packages/typespec-python/tests/mock_api/azure/test_client_namespace.py deleted file mode 100644 index da19dba405..0000000000 --- a/packages/typespec-python/tests/mock_api/azure/test_client_namespace.py +++ /dev/null @@ -1,32 +0,0 @@ -# ------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for -# license information. -# -------------------------------------------------------------------------- -import pytest -from client.clientnamespace import ClientNamespaceFirstClient -from client.clientnamespace.first.models import FirstClientResult - -from client.clientnamespace.second import ClientNamespaceSecondClient -from client.clientnamespace.second.models import SecondClientResult -from client.clientnamespace.second.sub.models import SecondClientEnumType - - -@pytest.fixture -def first_client(): - with ClientNamespaceFirstClient() as client: - yield client - - -@pytest.fixture -def second_client(): - with ClientNamespaceSecondClient() as client: - yield client - - -def test_get_first(first_client: ClientNamespaceFirstClient): - assert first_client.get_first() == FirstClientResult(name="first") - - -def test_get_second(second_client: ClientNamespaceSecondClient): - assert second_client.get_second() == SecondClientResult(type=SecondClientEnumType.SECOND) diff --git a/packages/typespec-python/tests/mock_api/azure/test_client_naming.py b/packages/typespec-python/tests/mock_api/azure/test_client_naming.py deleted file mode 100644 index 94ef8c2d3b..0000000000 --- a/packages/typespec-python/tests/mock_api/azure/test_client_naming.py +++ /dev/null @@ -1,57 +0,0 @@ -# ------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for -# license information. -# -------------------------------------------------------------------------- -import pytest -from client.naming.main import NamingClient, models - - -@pytest.fixture -def client(): - with NamingClient() as client: - yield client - - -def test_client(client: NamingClient): - client.property.client(models.ClientNameModel(client_name=True)) - - -def test_language(client: NamingClient): - client.property.language(models.LanguageClientNameModel(python_name=True)) - - -def test_compatible_with_encoded_name(client: NamingClient): - client.property.compatible_with_encoded_name(models.ClientNameAndJsonEncodedNameModel(client_name=True)) - - -def test_operation(client: NamingClient): - client.client_name() - - -def test_parameter(client: NamingClient): - client.parameter(client_name="true") - - -def test_header_request(client: NamingClient): - client.header.request(client_name="true") - - -def test_header_response(client: NamingClient): - assert client.header.response(cls=lambda x, y, z: z)["default-name"] == "true" - - -def test_model_client(client: NamingClient): - client.model_client.client(models.ClientModel(default_name=True)) - - -def test_model_language(client: NamingClient): - client.model_client.language(models.PythonModel(default_name=True)) - - -def test_union_enum_member_name(client: NamingClient): - client.union_enum.union_enum_member_name(models.ExtensibleEnum.CLIENT_ENUM_VALUE1) - - -def test_union_enum_name(client: NamingClient): - client.union_enum.union_enum_name(models.ClientExtensibleEnum.ENUM_VALUE1) diff --git a/packages/typespec-python/tests/mock_api/azure/test_client_naming_enum_conflict.py b/packages/typespec-python/tests/mock_api/azure/test_client_naming_enum_conflict.py deleted file mode 100644 index f32415a361..0000000000 --- a/packages/typespec-python/tests/mock_api/azure/test_client_naming_enum_conflict.py +++ /dev/null @@ -1,35 +0,0 @@ -# ------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for -# license information. -# -------------------------------------------------------------------------- -import pytest -from client.naming.enumconflict import EnumConflictClient -from client.naming.enumconflict.firstnamespace import models as first_models -from client.naming.enumconflict.secondnamespace import models as second_models - - -@pytest.fixture -def client(): - with EnumConflictClient() as client: - yield client - - -def test_first_operations_first(client: EnumConflictClient): - """Test enum with same name in different namespace - first namespace.""" - body = first_models.FirstModel(status=first_models.Status.ACTIVE, name="test") - - response = client.first_operations.first(body=body) - - assert response.status == "active" - assert response.name == "test" - - -def test_second_operations_second(client: EnumConflictClient): - """Test enum with same name in different namespace - second namespace.""" - body = second_models.SecondModel(status=second_models.SecondStatus.RUNNING, description="test description") - - response = client.second_operations.second(body=body) - - assert response.status == "running" - assert response.description == "test description" diff --git a/packages/typespec-python/tests/mock_api/azure/test_client_overload.py b/packages/typespec-python/tests/mock_api/azure/test_client_overload.py deleted file mode 100644 index 24d74549d7..0000000000 --- a/packages/typespec-python/tests/mock_api/azure/test_client_overload.py +++ /dev/null @@ -1,25 +0,0 @@ -import pytest -from client.overload import OverloadClient - - -class TestClientOverload: - @pytest.fixture - def client(self): - return OverloadClient(endpoint="http://localhost:3000") - - def test_list(self, client: OverloadClient): - result = client.list() - assert len(result) == 2 - assert result[0]["id"] == "1" - assert result[0]["name"] == "foo" - assert result[0]["scope"] == "car" - assert result[1]["id"] == "2" - assert result[1]["name"] == "bar" - assert result[1]["scope"] == "bike" - - def test_list_by_scope(self, client: OverloadClient): - result = client.list_by_scope("car") - assert len(result) == 1 - assert result[0]["id"] == "1" - assert result[0]["name"] == "foo" - assert result[0]["scope"] == "car" diff --git a/packages/typespec-python/tests/mock_api/azure/test_client_structure.py b/packages/typespec-python/tests/mock_api/azure/test_client_structure.py deleted file mode 100644 index e83d1ce6d6..0000000000 --- a/packages/typespec-python/tests/mock_api/azure/test_client_structure.py +++ /dev/null @@ -1,60 +0,0 @@ -# ------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for -# license information. -# -------------------------------------------------------------------------- -import pytest -from client.structure.service.models import ClientType -from client.structure.service import ServiceClient -from client.structure.multiclient import ClientAClient, ClientBClient -from client.structure.renamedoperation import RenamedOperationClient -from client.structure.twooperationgroup import TwoOperationGroupClient - - -def test_structure_default(): - client = ServiceClient(endpoint="http://localhost:3000", client=ClientType.DEFAULT) - client.one() - client.two() - client.foo.three() - client.foo.four() - client.bar.five() - client.bar.six() - client.baz.foo.seven() - client.qux.eight() - client.qux.bar.nine() - - -def test_structure_multiclient(): - client_a = ClientAClient(endpoint="http://localhost:3000", client=ClientType.MULTI_CLIENT) - client_a.renamed_one() - client_a.renamed_three() - client_a.renamed_five() - - client_b = ClientBClient(endpoint="http://localhost:3000", client=ClientType.MULTI_CLIENT) - client_b.renamed_two() - client_b.renamed_four() - client_b.renamed_six() - - -@pytest.mark.skip(reason="will reopen the cases after upgrade `@azure-tools/typespec-client-generator-core` to 0.67.0") -def test_structure_renamed_operation(): - client = RenamedOperationClient(endpoint="http://localhost:3000", client=ClientType.RENAMED_OPERATION) - client.renamed_one() - client.renamed_three() - client.renamed_five() - - client.renamed_two() - client.renamed_four() - client.renamed_six() - - -@pytest.mark.skip(reason="will reopen the cases after upgrade `@azure-tools/typespec-client-generator-core` to 0.67.0") -def test_structure_two_operation_group(): - client = TwoOperationGroupClient(endpoint="http://localhost:3000", client=ClientType.TWO_OPERATION_GROUP) - client.one() - client.three() - client.four() - - client.two() - client.five() - client.six() diff --git a/packages/typespec-python/tests/mock_api/azure/test_client_structure_clientoperationgroup.py b/packages/typespec-python/tests/mock_api/azure/test_client_structure_clientoperationgroup.py deleted file mode 100644 index aa6d3c8a90..0000000000 --- a/packages/typespec-python/tests/mock_api/azure/test_client_structure_clientoperationgroup.py +++ /dev/null @@ -1,29 +0,0 @@ -# ------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for -# license information. -# -------------------------------------------------------------------------- -import pytest -from client.structure.clientoperationgroup.models import ClientType -from client.structure.clientoperationgroup import FirstClient, SecondClient - - -@pytest.mark.skip(reason="will reopen the cases after upgrade `@azure-tools/typespec-client-generator-core` to 0.67.0") -def test_first_client_operations(): - client = FirstClient(endpoint="http://localhost:3000", client=ClientType.CLIENT_OPERATION_GROUP) - - client.one() - - client.two() - client.three() - - client.four() - - -@pytest.mark.skip(reason="will reopen the cases after upgrade `@azure-tools/typespec-client-generator-core` to 0.67.0") -def test_second_client_operations(): - client = SecondClient(endpoint="http://localhost:3000", client=ClientType.CLIENT_OPERATION_GROUP) - - client.five() - - client.six() diff --git a/packages/typespec-python/tests/mock_api/azure/test_encode_duration.py b/packages/typespec-python/tests/mock_api/azure/test_encode_duration.py deleted file mode 100644 index db0e29416f..0000000000 --- a/packages/typespec-python/tests/mock_api/azure/test_encode_duration.py +++ /dev/null @@ -1,60 +0,0 @@ -# ------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for -# license information. -# -------------------------------------------------------------------------- -import datetime - -import pytest -from encode.duration import DurationClient -from encode.duration.models import ( - Int32SecondsDurationProperty, - ISO8601DurationProperty, - FloatSecondsDurationProperty, - DefaultDurationProperty, - FloatSecondsDurationArrayProperty, -) - - -@pytest.fixture -def client(): - with DurationClient() as client: - yield client - - -def test_query(client: DurationClient): - client.query.default(input=datetime.timedelta(days=40)) - client.query.iso8601(input=datetime.timedelta(days=40)) - client.query.int32_seconds(input=36) - client.query.int32_seconds_array(input=[36, 47]) - client.query.float_seconds(input=35.625) - client.query.float64_seconds(input=35.625) - - -def test_property(client: DurationClient): - result = client.property.default(DefaultDurationProperty(value=datetime.timedelta(days=40))) - assert result.value == datetime.timedelta(days=40) - result = client.property.default(DefaultDurationProperty(value="P40D")) - assert result.value == datetime.timedelta(days=40) - result = client.property.iso8601(ISO8601DurationProperty(value=datetime.timedelta(days=40))) - assert result.value == datetime.timedelta(days=40) - result = client.property.iso8601(ISO8601DurationProperty(value="P40D")) - assert result.value == datetime.timedelta(days=40) - result = client.property.int32_seconds(Int32SecondsDurationProperty(value=36)) - assert result.value == 36 - result = client.property.float_seconds(FloatSecondsDurationProperty(value=35.625)) - assert abs(result.value - 35.625) < 0.0001 - result = client.property.float64_seconds(FloatSecondsDurationProperty(value=35.625)) - assert abs(result.value - 35.625) < 0.0001 - result = client.property.float_seconds_array(FloatSecondsDurationArrayProperty(value=[35.625, 46.75])) - assert abs(result.value[0] - 35.625) < 0.0001 - assert abs(result.value[1] - 46.75) < 0.0001 - - -def test_header(client: DurationClient): - client.header.default(duration=datetime.timedelta(days=40)) - client.header.iso8601(duration=datetime.timedelta(days=40)) - client.header.iso8601_array(duration=[datetime.timedelta(days=40), datetime.timedelta(days=50)]) - client.header.int32_seconds(duration=36) - client.header.float_seconds(duration=35.625) - client.header.float64_seconds(duration=35.625) diff --git a/packages/typespec-python/tests/mock_api/azure/test_encode_numeric.py b/packages/typespec-python/tests/mock_api/azure/test_encode_numeric.py deleted file mode 100644 index b0dff4af5c..0000000000 --- a/packages/typespec-python/tests/mock_api/azure/test_encode_numeric.py +++ /dev/null @@ -1,31 +0,0 @@ -# ------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for -# license information. -# -------------------------------------------------------------------------- -import pytest -from encode.numeric import NumericClient, models - - -@pytest.fixture -def client(): - with NumericClient() as client: - yield client - - -def test_safeint_as_string(client: NumericClient): - result = client.property.safeint_as_string(models.SafeintAsStringProperty(value=10000000000)) - assert result.value == 10000000000 - assert result["value"] == "10000000000" - - -def test_uint32_as_string_optional(client: NumericClient): - result = client.property.uint32_as_string_optional(models.Uint32AsStringProperty(value=1)) - assert result.value == 1 - assert result["value"] == "1" - - -def test_uint8_as_string_optional(client: NumericClient): - result = client.property.uint8_as_string(models.Uint32AsStringProperty(value=255)) - assert result.value == 255 - assert result["value"] == "255" diff --git a/packages/typespec-python/tests/mock_api/azure/test_model_base_flatten_compatibility.py b/packages/typespec-python/tests/mock_api/azure/test_model_base_flatten_compatibility.py deleted file mode 100644 index 538b03a953..0000000000 --- a/packages/typespec-python/tests/mock_api/azure/test_model_base_flatten_compatibility.py +++ /dev/null @@ -1,251 +0,0 @@ -# ------------------------------------ -# Copyright (c) Microsoft Corporation. -# Licensed under the MIT License. -# ------------------------------------ -import datetime -from typing import ( - Any, - Mapping, - Optional, - overload, -) - -from specs.azure.clientgenerator.core.flattenproperty._utils.model_base import ( - Model, - rest_field, -) -from azure.core.serialization import attribute_list - - -class ModelProperty(Model): - """This is a test model.""" - - value: str = rest_field() - """Required.""" - - @overload - def __init__( - self, - *, - value: str, - ) -> None: ... - - @overload - def __init__(self, mapping: Mapping[str, Any]) -> None: - """ - :param mapping: raw JSON to initialize the model. - :type mapping: Mapping[str, Any] - """ - - def __init__(self, *args: Any, **kwargs: Any) -> None: - super().__init__(*args, **kwargs) - - -class ChildModel(Model): - """This is the child model to be flattened. - - :ivar description: Required. - :vartype description: str - :ivar age: Required. - :vartype age: int - """ - - description: str = rest_field() - """Required.""" - age: int = rest_field() - """Required.""" - model_property: "ModelProperty" = rest_field(name="modelProperty") - """Required.""" - datetime_default: datetime.datetime = rest_field(name="datetimeDefault") - datetime_rfc3339: datetime.datetime = rest_field(name="datetimeRfc3339", format="rfc3339") - datetime_rfc7231: datetime.datetime = rest_field(name="datetimeRfc7231", format="rfc7231") - datetime_unix_timestamp: datetime.datetime = rest_field(name="datetimeUnixTimestamp", format="unix-timestamp") - - @overload - def __init__( - self, - *, - description: str, - age: int, - model_property: "ModelProperty", - datetime_default: datetime.datetime, - datetime_rfc3339: datetime.datetime, - datetime_rfc7231: datetime.datetime, - datetime_unix_timestamp: datetime.datetime, - ) -> None: ... - - @overload - def __init__(self, mapping: Mapping[str, Any]) -> None: - """ - :param mapping: raw JSON to initialize the model. - :type mapping: Mapping[str, Any] - """ - - def __init__(self, *args: Any, **kwargs: Any) -> None: - super().__init__(*args, **kwargs) - - -class FlattenModel(Model): - """This is the model with one level of flattening.""" - - name: str = rest_field() - """Required.""" - properties: "ChildModel" = rest_field() - """Required.""" - - __flattened_items = [ - "description", - "age", - "model_property", - "datetime_default", - "datetime_rfc3339", - "datetime_rfc7231", - "datetime_unix_timestamp", - ] - - @overload - def __init__( - self, - *, - name: str, - properties: "ChildModel", - ) -> None: ... - - @overload - def __init__(self, mapping: Mapping[str, Any]) -> None: - """ - :param mapping: raw JSON to initialize the model. - :type mapping: Mapping[str, Any] - """ - - def __init__(self, *args: Any, **kwargs: Any) -> None: - _flattened_input = {k: kwargs.pop(k) for k in kwargs.keys() & self.__flattened_items} - super().__init__(*args, **kwargs) - for k, v in _flattened_input.items(): - setattr(self, k, v) - - def __getattr__(self, name: str) -> Any: - if name in self.__flattened_items: - if self.properties is None: - return None - return getattr(self.properties, name) - raise AttributeError(f"'{self.__class__.__name__}' object has no attribute '{name}'") - - def __setattr__(self, key: str, value: Any) -> None: - if key in self.__flattened_items: - if self.properties is None: - self.properties = self._attr_to_rest_field["properties"]._class_type() - setattr(self.properties, key, value) - else: - super().__setattr__(key, value) - - -def test_model_initialization(): - model = FlattenModel( - name="test", - description="a description", - age=30, - model_property=ModelProperty(value="test value"), - datetime_default=datetime.datetime(2023, 1, 12, 0, 0, 0, tzinfo=datetime.timezone.utc), - datetime_rfc3339=datetime.datetime(2023, 1, 12, 0, 0, 0, tzinfo=datetime.timezone.utc), - datetime_rfc7231=datetime.datetime(2023, 1, 12, 0, 0, 0, tzinfo=datetime.timezone.utc), - datetime_unix_timestamp=datetime.datetime(2023, 1, 12, 0, 0, 0, tzinfo=datetime.timezone.utc), - ) - - assert model.name == "test" - - assert model.description == "a description" - assert model.properties.description == "a description" - - assert model.age == 30 - assert model.properties.age == 30 - - assert model.model_property.value == "test value" - assert model.properties.model_property == ModelProperty(value="test value") - assert model.properties.model_property.value == "test value" - - assert model.datetime_default == datetime.datetime(2023, 1, 12, 0, 0, 0, tzinfo=datetime.timezone.utc) - assert model.properties.datetime_default == datetime.datetime(2023, 1, 12, 0, 0, 0, tzinfo=datetime.timezone.utc) - assert model.properties["datetimeDefault"] == "2023-01-12T00:00:00Z" - - assert model.datetime_rfc3339 == datetime.datetime(2023, 1, 12, 0, 0, 0, tzinfo=datetime.timezone.utc) - assert model.properties.datetime_rfc3339 == datetime.datetime(2023, 1, 12, 0, 0, 0, tzinfo=datetime.timezone.utc) - assert model.properties["datetimeRfc3339"] == "2023-01-12T00:00:00Z" - - assert model.datetime_rfc7231 == datetime.datetime(2023, 1, 12, 0, 0, 0, tzinfo=datetime.timezone.utc) - assert model.properties.datetime_rfc7231 == datetime.datetime(2023, 1, 12, 0, 0, 0, tzinfo=datetime.timezone.utc) - assert model.properties["datetimeRfc7231"] == "Thu, 12 Jan 2023 00:00:00 GMT" - - assert model.datetime_unix_timestamp == datetime.datetime(2023, 1, 12, 0, 0, 0, tzinfo=datetime.timezone.utc) - assert model.properties.datetime_unix_timestamp == datetime.datetime( - 2023, 1, 12, 0, 0, 0, tzinfo=datetime.timezone.utc - ) - assert model.properties["datetimeUnixTimestamp"] == 1673481600 - - -class FlattenModelWithOptionalProperties(Model): - """This is the model with one level of flattening and optional properties.""" - - name: str = rest_field() - """Required.""" - properties: Optional["ModelProperty"] = rest_field() - """Optional.""" - - __flattened_items = ["value"] - - @overload - def __init__( - self, - *, - name: str, - properties: Optional["ModelProperty"], - ) -> None: ... - - @overload - def __init__(self, mapping: Mapping[str, Any]) -> None: - """ - :param mapping: raw JSON to initialize the model. - :type mapping: Mapping[str, Any] - """ - - def __init__(self, *args: Any, **kwargs: Any) -> None: - _flattened_input = {k: kwargs.pop(k) for k in kwargs.keys() & self.__flattened_items} - super().__init__(*args, **kwargs) - for k, v in _flattened_input.items(): - setattr(self, k, v) - - def __getattr__(self, name: str) -> Any: - if name in self.__flattened_items: - if self.properties is None: - return None - return getattr(self.properties, name) - raise AttributeError(f"'{self.__class__.__name__}' object has no attribute '{name}'") - - def __setattr__(self, key: str, value: Any) -> None: - if key in self.__flattened_items: - if self.properties is None: - self.properties = self._attr_to_rest_field["properties"]._class_type() - setattr(self.properties, key, value) - else: - super().__setattr__(key, value) - - -def test_model_with_optional_properties_initialization(): - model = FlattenModelWithOptionalProperties( - name="test", - value="test value", - ) - - assert model.name == "test" - - assert model.value == "test value" - assert model.properties.value == "test value" - - -def test_model_with_optional_properties_attribute_list(): - model = FlattenModelWithOptionalProperties( - name="test", - ) - - attrs = attribute_list(model) - assert sorted(attrs) == sorted(["name", "value"]) diff --git a/packages/typespec-python/tests/mock_api/azure/test_parameters_basic.py b/packages/typespec-python/tests/mock_api/azure/test_parameters_basic.py deleted file mode 100644 index 922bc1d629..0000000000 --- a/packages/typespec-python/tests/mock_api/azure/test_parameters_basic.py +++ /dev/null @@ -1,22 +0,0 @@ -# ------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for -# license information. -# -------------------------------------------------------------------------- -import pytest -from parameters.basic import BasicClient -from parameters.basic.models import User - - -@pytest.fixture -def client(): - with BasicClient() as client: - yield client - - -def test_explicit_simple(client: BasicClient): - client.explicit_body.simple(User(name="foo")) - - -def test_implicit_simple(client: BasicClient): - client.implicit_body.simple(name="foo") diff --git a/packages/typespec-python/tests/mock_api/azure/test_parameters_spread.py b/packages/typespec-python/tests/mock_api/azure/test_parameters_spread.py deleted file mode 100644 index c205034971..0000000000 --- a/packages/typespec-python/tests/mock_api/azure/test_parameters_spread.py +++ /dev/null @@ -1,66 +0,0 @@ -# ------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for -# license information. -# -------------------------------------------------------------------------- -import pytest -from parameters.spread import SpreadClient -from parameters.spread.models import BodyParameter - - -@pytest.fixture -def client(): - with SpreadClient() as client: - yield client - - -def test_model_body(client: SpreadClient): - client.model.spread_as_request_body(name="foo") - - -def test_model_composite_request_only_with_body(client: SpreadClient): - client.model.spread_composite_request_only_with_body(BodyParameter(name="foo")) - - -def test_model_composite_request_without_body(client: SpreadClient): - client.model.spread_composite_request_without_body(name="foo", test_header="bar") - - -def test_model_composite_request(client: SpreadClient): - client.model.spread_composite_request(name="foo", body=BodyParameter(name="foo"), test_header="bar") - - -def test_model_composite_request_mix(client: SpreadClient): - client.model.spread_composite_request_mix(name="foo", prop="foo", test_header="bar") - - -def test_alias_body(client: SpreadClient): - client.alias.spread_as_request_body(name="foo") - - -def test_alias_parameter(client: SpreadClient): - client.alias.spread_as_request_parameter("1", x_ms_test_header="bar", name="foo") - - -def test_alias_multiple_parameter(client: SpreadClient): - client.alias.spread_with_multiple_parameters( - "1", - x_ms_test_header="bar", - required_string="foo", - required_int_list=[1, 2], - optional_string_list=["foo", "bar"], - optional_int=1, - ) - client.alias.spread_with_multiple_parameters( - "1", - {"requiredString": "foo", "optionalInt": 1, "requiredIntList": [1, 2], "optionalStringList": ["foo", "bar"]}, - x_ms_test_header="bar", - ) - - -def test_inner_model(client: SpreadClient): - client.alias.spread_parameter_with_inner_model(id="1", x_ms_test_header="bar", body={"name": "foo"}) - - -def test_inner_alias(client: SpreadClient): - client.alias.spread_parameter_with_inner_alias(id="1", x_ms_test_header="bar", body={"name": "foo", "age": 1}) diff --git a/packages/typespec-python/tests/mock_api/azure/test_payload_content_negotiation.py b/packages/typespec-python/tests/mock_api/azure/test_payload_content_negotiation.py deleted file mode 100644 index 27fa1ba25f..0000000000 --- a/packages/typespec-python/tests/mock_api/azure/test_payload_content_negotiation.py +++ /dev/null @@ -1,33 +0,0 @@ -# ------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for -# license information. -# -------------------------------------------------------------------------- -import base64 -import pytest -from payload.contentnegotiation import ContentNegotiationClient -from payload.contentnegotiation.models import PngImageAsJson - - -@pytest.fixture -def client(): - with ContentNegotiationClient(endpoint="http://localhost:3000") as client: - yield client - - -def test_get_avatar_as_png(client: ContentNegotiationClient, png_data: bytes): - assert b"".join(client.same_body.get_avatar_as_png()) == png_data - - -def test_get_avatar_as_jpeg(client: ContentNegotiationClient, jpg_data: bytes): - assert b"".join(client.same_body.get_avatar_as_jpeg()) == jpg_data - - -def test_different_body_get_avatar_as_png(client: ContentNegotiationClient, png_data: bytes): - assert b"".join(client.different_body.get_avatar_as_png()) == png_data - - -def test_different_body_get_avatar_as_json(client: ContentNegotiationClient, png_data: bytes): - result = client.different_body.get_avatar_as_json() - expected = PngImageAsJson(content=base64.b64encode(png_data).decode()) - assert result == expected diff --git a/packages/typespec-python/tests/mock_api/azure/test_payload_multipart.py b/packages/typespec-python/tests/mock_api/azure/test_payload_multipart.py deleted file mode 100644 index d99780920f..0000000000 --- a/packages/typespec-python/tests/mock_api/azure/test_payload_multipart.py +++ /dev/null @@ -1,198 +0,0 @@ -# ------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for -# license information. -# -------------------------------------------------------------------------- -from pathlib import Path -import pytest -from payload.multipart import MultiPartClient, models - -JPG = Path(__file__).parent / "data/image.jpg" -PNG = Path(__file__).parent / "data/image.png" - - -@pytest.fixture -def client(): - with MultiPartClient(endpoint="http://localhost:3000") as client: - yield client - - -def test_anonymous_model(client: MultiPartClient): - client.form_data.anonymous_model({"profileImage": open(str(JPG), "rb")}) - - -def test_basic(client: MultiPartClient): - client.form_data.basic( - models.MultiPartRequest( - id="123", - profile_image=open(str(JPG), "rb"), - ) - ) - - -def test_binary_array_parts(client: MultiPartClient): - client.form_data.binary_array_parts( - models.BinaryArrayPartsRequest( - id="123", - pictures=[ - open(str(PNG), "rb"), - open(str(PNG), "rb"), - ], - ) - ) - - -def test_check_file_name_and_content_type(client: MultiPartClient): - client.form_data.check_file_name_and_content_type( - models.MultiPartRequest( - id="123", - profile_image=("hello.jpg", open(str(JPG), "rb"), "image/jpg"), - ) - ) - - -def test_complex(client: MultiPartClient): - client.form_data.file_array_and_basic( - models.ComplexPartsRequest( - id="123", - address=models.Address(city="X"), - pictures=[ - open(str(PNG), "rb"), - open(str(PNG), "rb"), - ], - profile_image=open(str(JPG), "rb"), - ) - ) - - -def test_json_part(client: MultiPartClient): - client.form_data.json_part( - models.JsonPartRequest( - address=models.Address(city="X"), - profile_image=open(str(JPG), "rb"), - ) - ) - - -def test_multi_binary_parts(client: MultiPartClient): - client.form_data.multi_binary_parts( - models.MultiBinaryPartsRequest( - profile_image=open(str(JPG), "rb"), - picture=open(str(PNG), "rb"), - ) - ) - client.form_data.multi_binary_parts( - models.MultiBinaryPartsRequest( - profile_image=open(str(JPG), "rb"), - ) - ) - - -def test_file_with_http_part_specific_content_type(client: MultiPartClient): - client.form_data.http_parts.content_type.image_jpeg_content_type( - models.FileWithHttpPartSpecificContentTypeRequest( - profile_image=("hello.jpg", open(str(JPG), "rb"), "image/jpg"), - ) - ) - - -def test_file_with_http_part_required_content_type(client: MultiPartClient): - client.form_data.http_parts.content_type.required_content_type( - models.FileWithHttpPartRequiredContentTypeRequest( - profile_image=open(str(JPG), "rb"), - ) - ) - - -def test_file_with_http_part_optional_content_type(client: MultiPartClient): - # call twice: one with content type, one without - client.form_data.http_parts.content_type.optional_content_type( - models.FileWithHttpPartOptionalContentTypeRequest( - profile_image=("hello.jpg", open(str(JPG), "rb").read()), - ) - ) - client.form_data.http_parts.content_type.optional_content_type( - models.FileWithHttpPartOptionalContentTypeRequest( - profile_image=("hello.jpg", open(str(JPG), "rb").read(), "application/octet-stream"), - ) - ) - - -def test_complex_with_http_part(client: MultiPartClient): - client.form_data.http_parts.json_array_and_file_array( - models.ComplexHttpPartsModelRequest( - id="123", - previous_addresses=[ - models.Address(city="Y"), - models.Address(city="Z"), - ], - address=models.Address(city="X"), - pictures=[ - open(str(PNG), "rb"), - open(str(PNG), "rb"), - ], - profile_image=open(str(JPG), "rb"), - ) - ) - - -def test_http_parts_non_string_float(client: MultiPartClient): - client.form_data.http_parts.non_string.float(models.FloatRequest(temperature=0.5)) - - -def test_with_wire_name(client: MultiPartClient): - client.form_data.with_wire_name( - models.MultiPartRequestWithWireName( - identifier="123", - image=open(str(JPG), "rb"), - ) - ) - - -def test_optional_parts(client: MultiPartClient): - # First time with only id - client.form_data.optional_parts( - models.MultiPartOptionalRequest( - id="123", - ) - ) - # Second time with only profileImage - client.form_data.optional_parts( - models.MultiPartOptionalRequest( - profile_image=open(str(JPG), "rb"), - ) - ) - # Third time with both id and profileImage - client.form_data.optional_parts( - models.MultiPartOptionalRequest( - id="123", - profile_image=open(str(JPG), "rb"), - ) - ) - - -def test_file_upload_file_specific_content_type(client: MultiPartClient): - client.form_data.file.upload_file_specific_content_type( - models.UploadFileSpecificContentTypeRequest( - file=("image.png", open(str(PNG), "rb"), "image/png"), - ) - ) - - -def test_file_upload_file_required_filename(client: MultiPartClient): - client.form_data.file.upload_file_required_filename( - models.UploadFileRequiredFilenameRequest( - file=("image.png", open(str(PNG), "rb"), "image/png"), - ) - ) - - -def test_file_upload_file_array(client: MultiPartClient): - client.form_data.file.upload_file_array( - models.UploadFileArrayRequest( - files=[ - ("image.png", open(str(PNG), "rb"), "image/png"), - ("image.png", open(str(PNG), "rb"), "image/png"), - ], - ) - ) diff --git a/packages/typespec-python/tests/mock_api/azure/test_resiliency_srv_driven.py b/packages/typespec-python/tests/mock_api/azure/test_resiliency_srv_driven.py deleted file mode 100644 index a7f3f9a1e5..0000000000 --- a/packages/typespec-python/tests/mock_api/azure/test_resiliency_srv_driven.py +++ /dev/null @@ -1,124 +0,0 @@ -# ------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for -# license information. -# -------------------------------------------------------------------------- -import pytest -from resiliency.srv.driven1 import ResiliencyServiceDrivenClient as V1Client -from resiliency.srv.driven2 import ResiliencyServiceDrivenClient as V2Client - - -def get_v1_client(service_deployment_version: str, api_version: str = "v1") -> V1Client: - return V1Client( - endpoint="http://localhost:3000", - service_deployment_version=service_deployment_version, - api_version=api_version, - ) - - -def get_v2_client(service_deployment_version: str, api_version: str = "v2") -> V2Client: - return V2Client( - endpoint="http://localhost:3000", - service_deployment_version=service_deployment_version, - api_version=api_version, - ) - - -def test_add_optional_param_from_none(): - # old client to old service with api version v1 - with V1Client(endpoint="http://localhost:3000", service_deployment_version="v1") as client: - client.from_none() - - # old client to new service with api version v1 - with V1Client(endpoint="http://localhost:3000", service_deployment_version="v2") as client: - client.from_none() - - # new client to new service with api version v1 - with V2Client( - endpoint="http://localhost:3000", - service_deployment_version="v2", - api_version="v1", - ) as client: - client.from_none() - - # new client to new service with api version v2 - with V2Client(endpoint="http://localhost:3000", service_deployment_version="v2") as client: - client.from_none(new_parameter="new") - - -def test_add_optional_param_from_one_required(): - # old client to old service with api version v1 - with V1Client(endpoint="http://localhost:3000", service_deployment_version="v1") as client: - client.from_one_required(parameter="required") - - # old client to new service with api version v1 - with V1Client(endpoint="http://localhost:3000", service_deployment_version="v2") as client: - client.from_one_required(parameter="required") - - # new client to new service with api version v1 - with V2Client( - endpoint="http://localhost:3000", - service_deployment_version="v2", - api_version="v1", - ) as client: - client.from_one_required(parameter="required") - - # new client to new service with api version v2 - with V2Client(endpoint="http://localhost:3000", service_deployment_version="v2") as client: - client.from_one_required(parameter="required", new_parameter="new") - - -def test_add_optional_param_from_one_optional(): - # old client to old service with api version v1 - with V1Client(endpoint="http://localhost:3000", service_deployment_version="v1") as client: - client.from_one_optional(parameter="optional") - - # old client to new service with api version v1 - with V1Client(endpoint="http://localhost:3000", service_deployment_version="v2") as client: - client.from_one_optional(parameter="optional") - - # new client to new service with api version v1 - with V2Client( - endpoint="http://localhost:3000", - service_deployment_version="v2", - api_version="v1", - ) as client: - client.from_one_optional(parameter="optional") - - # new client to new service with api version v2 - with V2Client(endpoint="http://localhost:3000", service_deployment_version="v2") as client: - client.from_one_optional(parameter="optional", new_parameter="new") - - -def test_break_the_glass(): - from azure.core.rest import HttpRequest - - request = HttpRequest(method="DELETE", url="/add-operation") - with V1Client( - endpoint="http://localhost:3000", - service_deployment_version="v2", - api_version="v2", - ) as client: - response = client.send_request(request) - response.raise_for_status() - - -def test_add_operation(): - with V2Client(endpoint="http://localhost:3000", service_deployment_version="v2") as client: - client.add_operation() - - -@pytest.mark.parametrize( - "func_name, params", - [ - ("from_none", {"new_parameter": "new"}), - ("from_one_optional", {"parameter": "optional", "new_parameter": "new"}), - ("from_one_required", {"parameter": "required", "new_parameter": "new"}), - ("add_operation", {}), - ], -) -def test_new_client_with_old_apiversion_call_new_parameter(func_name, params): - client = get_v2_client(service_deployment_version="v2", api_version="v1") - with pytest.raises(ValueError) as ex: - getattr(client, func_name)(**params) - assert "is not available in API version" in str(ex.value) diff --git a/packages/typespec-python/tests/mock_api/azure/test_serialization_encoded_name_json.py b/packages/typespec-python/tests/mock_api/azure/test_serialization_encoded_name_json.py deleted file mode 100644 index 0f61ce86f2..0000000000 --- a/packages/typespec-python/tests/mock_api/azure/test_serialization_encoded_name_json.py +++ /dev/null @@ -1,21 +0,0 @@ -# ------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for -# license information. -# -------------------------------------------------------------------------- -import pytest -from serialization.encodedname.json import JsonClient, models - - -@pytest.fixture -def client(): - with JsonClient() as client: - yield client - - -def test_property_send(client: JsonClient): - client.property.send(models.JsonEncodedNameModel(default_name=True)) - - -def test_property_get(client: JsonClient): - assert client.property.get().default_name diff --git a/packages/typespec-python/tests/mock_api/azure/test_service_multi_service.py b/packages/typespec-python/tests/mock_api/azure/test_service_multi_service.py deleted file mode 100644 index 4a1f9f7803..0000000000 --- a/packages/typespec-python/tests/mock_api/azure/test_service_multi_service.py +++ /dev/null @@ -1,29 +0,0 @@ -# ------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for -# license information. -# -------------------------------------------------------------------------- -import pytest -from azure.core.exceptions import HttpResponseError -from service.multiservice import CombinedClient -from service.multiservice.models import VersionsA, VersionsB - - -@pytest.fixture -def client(): - """Fixture that creates a CombinedClient for testing.""" - return CombinedClient(endpoint="http://localhost:3000") - - -def test_service_multi_service_foo(client): - with pytest.raises(HttpResponseError): - client.foo.test(api_version=VersionsA.AV1) - - client.foo.test() - - -def test_service_multi_service_bar(client): - with pytest.raises(HttpResponseError): - client.bar.test(api_version=VersionsB.BV1) - - client.bar.test() diff --git a/packages/typespec-python/tests/mock_api/azure/test_special_words.py b/packages/typespec-python/tests/mock_api/azure/test_special_words.py deleted file mode 100644 index ab23b59409..0000000000 --- a/packages/typespec-python/tests/mock_api/azure/test_special_words.py +++ /dev/null @@ -1,63 +0,0 @@ -# ------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for -# license information. -# -------------------------------------------------------------------------- -import pytest -from specialwords import SpecialWordsClient, models - - -@pytest.fixture -def client(): - with SpecialWordsClient() as client: - yield client - - -def test_operations(client: SpecialWordsClient, special_words): - for sw in special_words: - suffix = "" if sw == "constructor" else "_method" - getattr(client.operations, sw + suffix)() - - -def test_parameter(client: SpecialWordsClient, special_words): - for sw in special_words: - suffix = "" if sw == "constructor" else "_parameter" - getattr(client.parameters, "with_" + sw)(**{sw + suffix: "ok"}) - client.parameters.with_cancellation_token(cancellation_token="ok") - - -def test_model(client: SpecialWordsClient, special_words): - for sw in special_words: - suffix = "" if sw == "constructor" else "Model" - model = getattr(models, sw.capitalize() + suffix) - getattr(client.models, "with_" + sw)(model(name="ok")) - - -def test_model_properties(client: SpecialWordsClient): - client.model_properties.same_as_model(models.SameAsModel(same_as_model="ok")) - - -def test_model_properties_dict_methods(client: SpecialWordsClient): - client.model_properties.dict_methods( - body=models.DictMethods( - keys_property="ok", - items_property="ok", - values_property="ok", - popitem_property="ok", - clear_property="ok", - update_property="ok", - setdefault_property="ok", - pop_property="ok", - get_property="ok", - copy_property="ok", - ) - ) - - -def test_model_properties_with_list(client: SpecialWordsClient): - client.model_properties.with_list(models.ModelWithList(list="ok")) - - -def test_extensible_strings(client: SpecialWordsClient): - for enum_value in models.ExtensibleString: - assert enum_value == client.extensible_strings.put_extensible_string_value(body=enum_value) diff --git a/packages/typespec-python/tests/mock_api/shared/asynctests/test_authentication_async.py b/packages/typespec-python/tests/mock_api/shared/asynctests/test_authentication_async.py deleted file mode 100644 index 2276efaf9c..0000000000 --- a/packages/typespec-python/tests/mock_api/shared/asynctests/test_authentication_async.py +++ /dev/null @@ -1,140 +0,0 @@ -# ------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for -# license information. -# -------------------------------------------------------------------------- -import pytest -from authentication.apikey.aio import ApiKeyClient -from authentication.http.custom.aio import CustomClient -from authentication.oauth2.aio import OAuth2Client -from authentication.union.aio import UnionClient -from setuppy.authentication.union.aio import UnionClient as SetuppyUnionClient -from authentication.noauth.union.aio import UnionClient as NoauthUnionClient - -# Utilities functions - - -@pytest.fixture -async def api_key_client(key_credential): - client = None - - def _build_client(client_type, key: str = "valid-key"): - client = client_type(key_credential(key)) - return client - - yield _build_client - if client: - await client.close() - - -@pytest.fixture() -def token_credential(core_library): - class FakeCredential: - @staticmethod - async def get_token(*scopes): - return core_library.credentials.AccessToken(token="".join(scopes), expires_on=1800) - - @staticmethod - async def get_token_info(*scopes, **kwargs): - return core_library.credentials.AccessTokenInfo(token="".join(scopes), expires_on=1800) - - return FakeCredential() - - -@pytest.fixture -async def oauth2_client(token_credential): - client = None - - def _build_client(client_type): - client = client_type(token_credential) - return client - - yield _build_client - if client: - await client.close() - - -@pytest.fixture -async def http_custom_client(key_credential): - client = None - - def _build_client(key: str = "valid-key"): - client = CustomClient(key_credential(key)) - return client - - yield _build_client - if client: - await client.close() - - -# Tests - - -@pytest.mark.asyncio -async def test_api_key_valid(api_key_client): - client = api_key_client(ApiKeyClient) - await client.valid() - - -@pytest.mark.asyncio -async def test_api_key_invalid(api_key_client, core_library): - client = api_key_client(ApiKeyClient, "invalid-key") - with pytest.raises(core_library.exceptions.HttpResponseError) as ex: - await client.invalid() - assert ex.value.status_code == 403 - assert ex.value.reason == "Forbidden" - - -@pytest.mark.asyncio -async def test_oauth2_valid(oauth2_client): - client = oauth2_client(OAuth2Client) - await client.valid(enforce_https=False) - - -@pytest.mark.asyncio -async def test_oauth2_invalid(oauth2_client, core_library): - client = oauth2_client(OAuth2Client) - with pytest.raises(core_library.exceptions.HttpResponseError) as ex: - await client.invalid(enforce_https=False) - assert ex.value.status_code == 403 - - -@pytest.mark.asyncio -@pytest.mark.parametrize("union_client_type", [UnionClient, SetuppyUnionClient]) -async def test_union_keyvalid(api_key_client, union_client_type): - client = api_key_client(union_client_type) - await client.valid_key() - - -@pytest.mark.asyncio -@pytest.mark.parametrize("union_client_type", [UnionClient, SetuppyUnionClient]) -async def test_union_tokenvalid(oauth2_client, union_client_type): - client = oauth2_client(union_client_type) - await client.valid_token(enforce_https=False) - - -@pytest.mark.asyncio -async def test_noauth_union_valid_no_auth(): - client = NoauthUnionClient() - await client.valid_no_auth() - - -@pytest.mark.asyncio -async def test_noauth_union_valid_token(oauth2_client): - client = oauth2_client(NoauthUnionClient) - await client.valid_token(enforce_https=False) - - -@pytest.mark.asyncio -async def test_http_custom_valid(http_custom_client): - client = http_custom_client() - await client.valid() - - -@pytest.mark.asyncio -async def test_http_custom_invalid(http_custom_client, core_library): - client = http_custom_client(key="invalid-key") - with pytest.raises(core_library.exceptions.HttpResponseError) as ex: - await client.invalid() - assert ex.value.status_code == 403 - assert ex.value.reason == "Forbidden" diff --git a/packages/typespec-python/tests/mock_api/shared/asynctests/test_encode_array_async.py b/packages/typespec-python/tests/mock_api/shared/asynctests/test_encode_array_async.py deleted file mode 100644 index 925780cd4a..0000000000 --- a/packages/typespec-python/tests/mock_api/shared/asynctests/test_encode_array_async.py +++ /dev/null @@ -1,139 +0,0 @@ -# ------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for -# license information. -# -------------------------------------------------------------------------- - -import pytest -from encode.array.aio import ArrayClient -from encode.array import models - - -@pytest.fixture -async def client(): - async with ArrayClient() as client: - yield client - - -@pytest.mark.asyncio -async def test_comma_delimited(client: ArrayClient): - body = models.CommaDelimitedArrayProperty(value=["blue", "red", "green"]) - result = await client.property.comma_delimited(body) - assert result.value == ["blue", "red", "green"] - - -@pytest.mark.asyncio -async def test_space_delimited(client: ArrayClient): - body = models.SpaceDelimitedArrayProperty(value=["blue", "red", "green"]) - result = await client.property.space_delimited(body) - assert result.value == ["blue", "red", "green"] - - -@pytest.mark.asyncio -async def test_pipe_delimited(client: ArrayClient): - body = models.PipeDelimitedArrayProperty(value=["blue", "red", "green"]) - result = await client.property.pipe_delimited(body) - assert result.value == ["blue", "red", "green"] - - -@pytest.mark.asyncio -async def test_newline_delimited(client: ArrayClient): - body = models.NewlineDelimitedArrayProperty(value=["blue", "red", "green"]) - result = await client.property.newline_delimited(body) - assert result.value == ["blue", "red", "green"] - - -@pytest.mark.asyncio -async def test_enum_comma_delimited(client: ArrayClient): - body = models.CommaDelimitedEnumArrayProperty(value=[models.Colors.BLUE, models.Colors.RED, models.Colors.GREEN]) - result = await client.property.enum_comma_delimited(body) - assert result.value == [models.Colors.BLUE, models.Colors.RED, models.Colors.GREEN] - - -@pytest.mark.asyncio -async def test_enum_space_delimited(client: ArrayClient): - body = models.SpaceDelimitedEnumArrayProperty(value=[models.Colors.BLUE, models.Colors.RED, models.Colors.GREEN]) - result = await client.property.enum_space_delimited(body) - assert result.value == [models.Colors.BLUE, models.Colors.RED, models.Colors.GREEN] - - -@pytest.mark.asyncio -async def test_enum_pipe_delimited(client: ArrayClient): - body = models.PipeDelimitedEnumArrayProperty(value=[models.Colors.BLUE, models.Colors.RED, models.Colors.GREEN]) - result = await client.property.enum_pipe_delimited(body) - assert result.value == [models.Colors.BLUE, models.Colors.RED, models.Colors.GREEN] - - -@pytest.mark.asyncio -async def test_enum_newline_delimited(client: ArrayClient): - body = models.NewlineDelimitedEnumArrayProperty(value=[models.Colors.BLUE, models.Colors.RED, models.Colors.GREEN]) - result = await client.property.enum_newline_delimited(body) - assert result.value == [models.Colors.BLUE, models.Colors.RED, models.Colors.GREEN] - - -@pytest.mark.asyncio -async def test_extensible_enum_comma_delimited(client: ArrayClient): - body = models.CommaDelimitedExtensibleEnumArrayProperty( - value=[ - models.ColorsExtensibleEnum.BLUE, - models.ColorsExtensibleEnum.RED, - models.ColorsExtensibleEnum.GREEN, - ] - ) - result = await client.property.extensible_enum_comma_delimited(body) - assert result.value == [ - models.ColorsExtensibleEnum.BLUE, - models.ColorsExtensibleEnum.RED, - models.ColorsExtensibleEnum.GREEN, - ] - - -@pytest.mark.asyncio -async def test_extensible_enum_space_delimited(client: ArrayClient): - body = models.SpaceDelimitedExtensibleEnumArrayProperty( - value=[ - models.ColorsExtensibleEnum.BLUE, - models.ColorsExtensibleEnum.RED, - models.ColorsExtensibleEnum.GREEN, - ] - ) - result = await client.property.extensible_enum_space_delimited(body) - assert result.value == [ - models.ColorsExtensibleEnum.BLUE, - models.ColorsExtensibleEnum.RED, - models.ColorsExtensibleEnum.GREEN, - ] - - -@pytest.mark.asyncio -async def test_extensible_enum_pipe_delimited(client: ArrayClient): - body = models.PipeDelimitedExtensibleEnumArrayProperty( - value=[ - models.ColorsExtensibleEnum.BLUE, - models.ColorsExtensibleEnum.RED, - models.ColorsExtensibleEnum.GREEN, - ] - ) - result = await client.property.extensible_enum_pipe_delimited(body) - assert result.value == [ - models.ColorsExtensibleEnum.BLUE, - models.ColorsExtensibleEnum.RED, - models.ColorsExtensibleEnum.GREEN, - ] - - -@pytest.mark.asyncio -async def test_extensible_enum_newline_delimited(client: ArrayClient): - body = models.NewlineDelimitedExtensibleEnumArrayProperty( - value=[ - models.ColorsExtensibleEnum.BLUE, - models.ColorsExtensibleEnum.RED, - models.ColorsExtensibleEnum.GREEN, - ] - ) - result = await client.property.extensible_enum_newline_delimited(body) - assert result.value == [ - models.ColorsExtensibleEnum.BLUE, - models.ColorsExtensibleEnum.RED, - models.ColorsExtensibleEnum.GREEN, - ] diff --git a/packages/typespec-python/tests/mock_api/shared/asynctests/test_encode_bytes_async.py b/packages/typespec-python/tests/mock_api/shared/asynctests/test_encode_bytes_async.py deleted file mode 100644 index 584b277edd..0000000000 --- a/packages/typespec-python/tests/mock_api/shared/asynctests/test_encode_bytes_async.py +++ /dev/null @@ -1,132 +0,0 @@ -# ------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for -# license information. -# -------------------------------------------------------------------------- -import pytest -from pathlib import Path -from encode.bytes.aio import BytesClient -from encode.bytes.models import ( - DefaultBytesProperty, - Base64urlBytesProperty, - Base64BytesProperty, - Base64urlArrayBytesProperty, -) - -FILE_FOLDER = Path(__file__).parent.parent - - -@pytest.fixture -async def client(): - async with BytesClient() as client: - yield client - - -@pytest.mark.asyncio -async def test_query(client: BytesClient): - await client.query.default( - value=bytes("test", "utf-8"), - ) - await client.query.base64( - value=bytes("test", "utf-8"), - ) - await client.query.base64_url( - value=bytes("test", "utf-8"), - ) - await client.query.base64_url_array( - value=[ - bytes("test", "utf-8"), - bytes("test", "utf-8"), - ], - ) - - -@pytest.mark.asyncio -async def test_property(client: BytesClient): - result = await client.property.default( - DefaultBytesProperty( - value=bytes("test", "utf-8"), - ) - ) - assert result.value == bytes("test", "utf-8") - - result = await client.property.base64( - Base64BytesProperty( - value=bytes("test", "utf-8"), - ) - ) - assert result.value == bytes("test", "utf-8") - - result = await client.property.base64_url( - Base64urlBytesProperty( - value=bytes("test", "utf-8"), - ) - ) - assert result.value == bytes("test", "utf-8") - - result = await client.property.base64_url_array( - Base64urlArrayBytesProperty( - value=[ - bytes("test", "utf-8"), - bytes("test", "utf-8"), - ], - ) - ) - assert result.value == [ - bytes("test", "utf-8"), - bytes("test", "utf-8"), - ] - - -@pytest.mark.asyncio -async def test_header(client: BytesClient): - await client.header.default( - value=bytes("test", "utf-8"), - ) - await client.header.base64( - value=bytes("test", "utf-8"), - ) - await client.header.base64_url( - value=bytes("test", "utf-8"), - ) - await client.header.base64_url_array( - value=[ - bytes("test", "utf-8"), - bytes("test", "utf-8"), - ], - ) - - -@pytest.fixture -def png_data() -> bytes: - with open(str(FILE_FOLDER / "data/image.png"), "rb") as file_in: - return file_in.read() - - -@pytest.mark.asyncio -async def test_request_body(client: BytesClient, png_data: bytes): - await client.request_body.default( - value=png_data, - ) - await client.request_body.octet_stream( - value=png_data, - ) - await client.request_body.custom_content_type( - value=png_data, - ) - await client.request_body.base64( - value=bytes("test", "utf-8"), - ) - await client.request_body.base64_url( - value=bytes("test", "utf-8"), - ) - - -@pytest.mark.asyncio -async def test_response_body(client: BytesClient, png_data: bytes): - expected = b"test" - assert b"".join([d async for d in (await client.response_body.default())]) == png_data - assert expected == await client.response_body.base64() - assert b"".join([d async for d in (await client.response_body.octet_stream())]) == png_data - assert b"".join([d async for d in (await client.response_body.custom_content_type())]) == png_data - assert expected == await client.response_body.base64_url() diff --git a/packages/typespec-python/tests/mock_api/shared/asynctests/test_encode_datetime_async.py b/packages/typespec-python/tests/mock_api/shared/asynctests/test_encode_datetime_async.py deleted file mode 100644 index 1249b8e8f3..0000000000 --- a/packages/typespec-python/tests/mock_api/shared/asynctests/test_encode_datetime_async.py +++ /dev/null @@ -1,127 +0,0 @@ -# ------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for -# license information. -# -------------------------------------------------------------------------- -import datetime - -import pytest -from encode.datetime.aio import DatetimeClient -from encode.datetime.models import ( - DefaultDatetimeProperty, - Rfc3339DatetimeProperty, - Rfc7231DatetimeProperty, - UnixTimestampDatetimeProperty, - UnixTimestampArrayDatetimeProperty, -) - - -@pytest.fixture -async def client(): - async with DatetimeClient() as client: - yield client - - -@pytest.mark.asyncio -async def test_query(client: DatetimeClient): - await client.query.default( - value=datetime.datetime(2022, 8, 26, 18, 38, 0, tzinfo=datetime.timezone.utc), - ) - await client.query.rfc3339( - value=datetime.datetime(2022, 8, 26, 18, 38, 0, tzinfo=datetime.timezone.utc), - ) - await client.query.rfc7231( - value=datetime.datetime(2022, 8, 26, 14, 38, 0, tzinfo=datetime.timezone.utc), - ) - await client.query.unix_timestamp( - value=datetime.datetime(2023, 6, 12, 10, 47, 44, tzinfo=datetime.timezone.utc), - ) - await client.query.unix_timestamp_array( - value=[ - datetime.datetime(2023, 6, 12, 10, 47, 44, tzinfo=datetime.timezone.utc), - datetime.datetime(2023, 6, 14, 9, 17, 36, tzinfo=datetime.timezone.utc), - ], - ) - - -@pytest.mark.asyncio -async def test_property(client: DatetimeClient): - result = await client.property.default( - DefaultDatetimeProperty( - value=datetime.datetime(2022, 8, 26, 18, 38, 0, tzinfo=datetime.timezone.utc), - ) - ) - assert result.value == datetime.datetime(2022, 8, 26, 18, 38, 0, tzinfo=datetime.timezone.utc) - - result = await client.property.rfc3339( - Rfc3339DatetimeProperty( - value=datetime.datetime(2022, 8, 26, 18, 38, 0, tzinfo=datetime.timezone.utc), - ) - ) - assert result.value == datetime.datetime(2022, 8, 26, 18, 38, 0, tzinfo=datetime.timezone.utc) - - result = await client.property.rfc7231( - Rfc7231DatetimeProperty( - value=datetime.datetime(2022, 8, 26, 14, 38, 0, tzinfo=datetime.timezone.utc), - ) - ) - assert result.value == datetime.datetime(2022, 8, 26, 14, 38, 0, tzinfo=datetime.timezone.utc) - - result = await client.property.unix_timestamp( - UnixTimestampDatetimeProperty( - value=datetime.datetime(2023, 6, 12, 10, 47, 44, tzinfo=datetime.timezone.utc), - ) - ) - assert result.value == datetime.datetime(2023, 6, 12, 10, 47, 44, tzinfo=datetime.timezone.utc) - - result = await client.property.unix_timestamp_array( - UnixTimestampArrayDatetimeProperty( - value=[ - datetime.datetime(2023, 6, 12, 10, 47, 44, tzinfo=datetime.timezone.utc), - datetime.datetime(2023, 6, 14, 9, 17, 36, tzinfo=datetime.timezone.utc), - ], - ) - ) - assert result.value == [ - datetime.datetime(2023, 6, 12, 10, 47, 44, tzinfo=datetime.timezone.utc), - datetime.datetime(2023, 6, 14, 9, 17, 36, tzinfo=datetime.timezone.utc), - ] - - -@pytest.mark.asyncio -async def test_header(client: DatetimeClient): - await client.header.default( - value=datetime.datetime(2022, 8, 26, 14, 38, 0, tzinfo=datetime.timezone.utc), - ) - await client.header.rfc3339( - value=datetime.datetime(2022, 8, 26, 18, 38, 0, tzinfo=datetime.timezone.utc), - ) - await client.header.rfc7231( - value=datetime.datetime(2022, 8, 26, 14, 38, 0, tzinfo=datetime.timezone.utc), - ) - await client.header.unix_timestamp( - value=datetime.datetime(2023, 6, 12, 10, 47, 44, tzinfo=datetime.timezone.utc), - ) - await client.header.unix_timestamp_array( - value=[ - datetime.datetime(2023, 6, 12, 10, 47, 44, tzinfo=datetime.timezone.utc), - datetime.datetime(2023, 6, 14, 9, 17, 36, tzinfo=datetime.timezone.utc), - ] - ) - - -@pytest.mark.asyncio -async def test_response_header(client: DatetimeClient): - cls = lambda x, y, z: z - assert (await client.response_header.default(cls=cls))["value"] == datetime.datetime( - 2022, 8, 26, 14, 38, 0, tzinfo=datetime.timezone.utc - ) - assert (await client.response_header.rfc3339(cls=cls))["value"] == datetime.datetime( - 2022, 8, 26, 18, 38, 0, tzinfo=datetime.timezone.utc - ) - assert (await client.response_header.rfc7231(cls=cls))["value"] == datetime.datetime( - 2022, 8, 26, 14, 38, 0, tzinfo=datetime.timezone.utc - ) - assert (await client.response_header.unix_timestamp(cls=cls))["value"] == datetime.datetime( - 2023, 6, 12, 10, 47, 44, tzinfo=datetime.timezone.utc - ) diff --git a/packages/typespec-python/tests/mock_api/shared/asynctests/test_generation_subdir_async.py b/packages/typespec-python/tests/mock_api/shared/asynctests/test_generation_subdir_async.py deleted file mode 100644 index 4fd9e7496e..0000000000 --- a/packages/typespec-python/tests/mock_api/shared/asynctests/test_generation_subdir_async.py +++ /dev/null @@ -1,25 +0,0 @@ -# ------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for -# license information. -# -------------------------------------------------------------------------- -import pytest -import pytest_asyncio -from generation.subdir._generated.aio import RecursiveClient -from generation.subdir._generated.models import Extension - - -@pytest_asyncio.fixture -async def client(): - async with RecursiveClient() as client: - yield client - - -@pytest.mark.asyncio -async def test_custom_method(client: RecursiveClient): - assert await client.get() == Extension( - { - "level": 0, - "extension": [{"level": 1, "extension": [{"level": 2}]}, {"level": 1}], - } - ) diff --git a/packages/typespec-python/tests/mock_api/shared/asynctests/test_headasboolean_async.py b/packages/typespec-python/tests/mock_api/shared/asynctests/test_headasboolean_async.py deleted file mode 100644 index c0f6919871..0000000000 --- a/packages/typespec-python/tests/mock_api/shared/asynctests/test_headasboolean_async.py +++ /dev/null @@ -1,35 +0,0 @@ -# ------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for -# license information. -# -------------------------------------------------------------------------- -import pytest -from headasbooleantrue.aio import VisibilityClient as HeadAsBooleanTrueClient -from headasbooleantrue import models as models_true - -from headasbooleanfalse.aio import VisibilityClient as HeadAsBooleanFalseClient -from headasbooleanfalse import models as models_false - - -@pytest.fixture -async def client_true(): - async with HeadAsBooleanTrueClient() as client: - yield client - - -@pytest.fixture -async def client_false(): - async with HeadAsBooleanFalseClient() as client: - yield client - - -@pytest.mark.asyncio -async def test_head_true(client_true): - body = models_true.VisibilityModel() - assert await client_true.head_model(body, query_prop=123) == True - - -@pytest.mark.asyncio -async def test_head_false(client_false): - body = models_false.VisibilityModel() - assert await client_false.head_model(body, query_prop=123) is None diff --git a/packages/typespec-python/tests/mock_api/shared/asynctests/test_parameters_body_optionality_async.py b/packages/typespec-python/tests/mock_api/shared/asynctests/test_parameters_body_optionality_async.py deleted file mode 100644 index 7c6bbe82c8..0000000000 --- a/packages/typespec-python/tests/mock_api/shared/asynctests/test_parameters_body_optionality_async.py +++ /dev/null @@ -1,30 +0,0 @@ -# ------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for -# license information. -# -------------------------------------------------------------------------- -import pytest -from parameters.bodyoptionality.aio import BodyOptionalityClient -from parameters.bodyoptionality.models import BodyModel - - -@pytest.fixture -async def client(): - async with BodyOptionalityClient() as client: - yield client - - -@pytest.mark.asyncio -async def test_required_explicit(client: BodyOptionalityClient): - await client.required_explicit(BodyModel(name="foo")) - - -@pytest.mark.asyncio -async def test_required_implicit(client: BodyOptionalityClient): - await client.required_implicit(name="foo") - - -@pytest.mark.asyncio -async def test_optional_explicit(client: BodyOptionalityClient): - await client.optional_explicit.set(BodyModel(name="foo")) - await client.optional_explicit.omit() diff --git a/packages/typespec-python/tests/mock_api/shared/asynctests/test_parameters_collection_format_async.py b/packages/typespec-python/tests/mock_api/shared/asynctests/test_parameters_collection_format_async.py deleted file mode 100644 index c3ae969807..0000000000 --- a/packages/typespec-python/tests/mock_api/shared/asynctests/test_parameters_collection_format_async.py +++ /dev/null @@ -1,38 +0,0 @@ -# ------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for -# license information. -# -------------------------------------------------------------------------- -import pytest -from parameters.collectionformat.aio import CollectionFormatClient - - -@pytest.fixture -async def client(): - async with CollectionFormatClient() as client: - yield client - - -@pytest.mark.asyncio -async def test_query_multi(client: CollectionFormatClient): - await client.query.multi(colors=["blue", "red", "green"]) - - -@pytest.mark.asyncio -async def test_query_csv(client: CollectionFormatClient): - await client.query.csv(colors=["blue", "red", "green"]) - - -@pytest.mark.asyncio -async def test_query_pipes(client: CollectionFormatClient): - await client.query.pipes(colors=["blue", "red", "green"]) - - -@pytest.mark.asyncio -async def test_query_ssv(client: CollectionFormatClient): - await client.query.ssv(colors=["blue", "red", "green"]) - - -@pytest.mark.asyncio -async def test_csv_header(client: CollectionFormatClient): - await client.header.csv(colors=["blue", "red", "green"]) diff --git a/packages/typespec-python/tests/mock_api/shared/asynctests/test_parameters_path_async.py b/packages/typespec-python/tests/mock_api/shared/asynctests/test_parameters_path_async.py deleted file mode 100644 index eeef36a301..0000000000 --- a/packages/typespec-python/tests/mock_api/shared/asynctests/test_parameters_path_async.py +++ /dev/null @@ -1,24 +0,0 @@ -# ------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for -# license information. -# -------------------------------------------------------------------------- -import pytest -from parameters.path.aio import PathClient - - -@pytest.fixture -async def client(): - async with PathClient() as client: - yield client - - -@pytest.mark.asyncio -async def test_normal(client: PathClient): - await client.normal("foo") - - -@pytest.mark.asyncio -async def test_optional(client: PathClient): - await client.optional() - await client.optional(name="foo") diff --git a/packages/typespec-python/tests/mock_api/shared/asynctests/test_parameters_query_async.py b/packages/typespec-python/tests/mock_api/shared/asynctests/test_parameters_query_async.py deleted file mode 100644 index d5879ebdc2..0000000000 --- a/packages/typespec-python/tests/mock_api/shared/asynctests/test_parameters_query_async.py +++ /dev/null @@ -1,18 +0,0 @@ -# ------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for -# license information. -# -------------------------------------------------------------------------- -import pytest -from parameters.query.aio import QueryClient - - -@pytest.fixture -async def client(): - async with QueryClient() as client: - yield client - - -@pytest.mark.asyncio -async def test_constant(client: QueryClient): - await client.constant.post() diff --git a/packages/typespec-python/tests/mock_api/shared/asynctests/test_payload_json_merge_patch_async.py b/packages/typespec-python/tests/mock_api/shared/asynctests/test_payload_json_merge_patch_async.py deleted file mode 100644 index e276944be3..0000000000 --- a/packages/typespec-python/tests/mock_api/shared/asynctests/test_payload_json_merge_patch_async.py +++ /dev/null @@ -1,98 +0,0 @@ -# ------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for -# license information. -# -------------------------------------------------------------------------- -import pytest -from payload.jsonmergepatch.aio import JsonMergePatchClient -from payload.jsonmergepatch.models import InnerModel, Resource, ResourcePatch - -try: - from azure.core.serialization import NULL -except ImportError: - from corehttp.serialization import NULL - - -@pytest.fixture -async def client(): - async with JsonMergePatchClient(endpoint="http://localhost:3000") as client: - yield client - - -@pytest.mark.asyncio -async def test_create_resource(client: JsonMergePatchClient): - inner_madge = InnerModel(name="InnerMadge", description="innerDesc") - create_resource = Resource( - name="Madge", - description="desc", - map={"key": inner_madge}, - array=[inner_madge], - int_value=1, - float_value=1.25, - inner_model=inner_madge, - int_array=[1, 2, 3], - ) - response = await client.create_resource(create_resource) - assert response == create_resource - - -@pytest.mark.asyncio -async def test_update_resource_model_input(client: JsonMergePatchClient): - update_resource = ResourcePatch( - description=NULL, - map={"key": InnerModel(description=NULL), "key2": NULL}, - array=NULL, - int_value=NULL, - float_value=NULL, - inner_model=NULL, - int_array=NULL, - ) - response = await client.update_resource(update_resource) - assert response == Resource(name="Madge", map={"key": InnerModel(name="InnerMadge")}) - - -@pytest.mark.asyncio -async def test_update_resource_raw_input(client: JsonMergePatchClient): - response = await client.update_resource( - { - "description": None, - "map": {"key": {"description": None}, "key2": None}, - "array": None, - "intValue": None, - "floatValue": None, - "innerModel": None, - "intArray": None, - } - ) - assert response == Resource(name="Madge", map={"key": InnerModel(name="InnerMadge")}) - - -@pytest.mark.asyncio -async def test_update_optional_resource_model_input(client: JsonMergePatchClient): - update_resource = ResourcePatch( - description=NULL, - map={"key": InnerModel(description=NULL), "key2": NULL}, - array=NULL, - int_value=NULL, - float_value=NULL, - inner_model=NULL, - int_array=NULL, - ) - response = await client.update_optional_resource(update_resource) - assert response == Resource(name="Madge", map={"key": InnerModel(name="InnerMadge")}) - - -@pytest.mark.asyncio -async def test_update_optional_resource_raw_input(client: JsonMergePatchClient): - response = await client.update_optional_resource( - { - "description": None, - "map": {"key": {"description": None}, "key2": None}, - "array": None, - "intValue": None, - "floatValue": None, - "innerModel": None, - "intArray": None, - } - ) - assert response == Resource(name="Madge", map={"key": InnerModel(name="InnerMadge")}) diff --git a/packages/typespec-python/tests/mock_api/shared/asynctests/test_payload_media_type_async.py b/packages/typespec-python/tests/mock_api/shared/asynctests/test_payload_media_type_async.py deleted file mode 100644 index d783e6ac61..0000000000 --- a/packages/typespec-python/tests/mock_api/shared/asynctests/test_payload_media_type_async.py +++ /dev/null @@ -1,27 +0,0 @@ -# ------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for -# license information. -# -------------------------------------------------------------------------- -import pytest -from payload.mediatype.aio import MediaTypeClient - - -@pytest.fixture -async def client(): - async with MediaTypeClient(endpoint="http://localhost:3000") as client: - yield client - - -@pytest.mark.asyncio -async def test_json(client: MediaTypeClient): - data = "foo" - await client.string_body.send_as_json(data) - assert await client.string_body.get_as_json() == data - - -@pytest.mark.asyncio -async def test_text(client: MediaTypeClient): - data = "{cat}" - await client.string_body.send_as_text(data) - assert await client.string_body.get_as_text() == data diff --git a/packages/typespec-python/tests/mock_api/shared/asynctests/test_payload_pageable_async.py b/packages/typespec-python/tests/mock_api/shared/asynctests/test_payload_pageable_async.py deleted file mode 100644 index f0994df97b..0000000000 --- a/packages/typespec-python/tests/mock_api/shared/asynctests/test_payload_pageable_async.py +++ /dev/null @@ -1,134 +0,0 @@ -# ------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for -# license information. -# -------------------------------------------------------------------------- -import pytest -from payload.pageable.aio import PageableClient -from payload.pageable.serverdrivenpagination.alternateinitialverb.models import Filter - - -@pytest.fixture -async def client(): - async with PageableClient(endpoint="http://localhost:3000") as client: - yield client - - -def assert_result(result): - assert len(result) == 4 - assert result[0].id == "1" - assert result[1].id == "2" - assert result[2].id == "3" - assert result[3].id == "4" - assert result[0].name == "dog" - assert result[1].name == "cat" - assert result[2].name == "bird" - assert result[3].name == "fish" - - -@pytest.mark.asyncio -async def test_link(client: PageableClient): - result = [p async for p in client.server_driven_pagination.link()] - assert_result(result) - - -@pytest.mark.asyncio -async def test_link_string(client: PageableClient): - result = [p async for p in client.server_driven_pagination.link_string()] - assert_result(result) - - -@pytest.mark.asyncio -async def test_request_query_response_body(client: PageableClient): - result = [ - p - async for p in client.server_driven_pagination.continuation_token.request_query_response_body( - foo="foo", bar="bar" - ) - ] - assert_result(result) - - -@pytest.mark.asyncio -async def test_request_header_response_body(client: PageableClient): - result = [ - p - async for p in client.server_driven_pagination.continuation_token.request_header_response_body( - foo="foo", bar="bar" - ) - ] - assert_result(result) - - -@pytest.mark.asyncio -async def test_request_query_response_header(client: PageableClient): - result = [ - p - async for p in client.server_driven_pagination.continuation_token.request_query_response_header( - foo="foo", bar="bar" - ) - ] - assert_result(result) - - -@pytest.mark.asyncio -async def test_request_header_response_header(client: PageableClient): - result = [ - p - async for p in client.server_driven_pagination.continuation_token.request_query_response_header( - foo="foo", bar="bar" - ) - ] - assert_result(result) - - -@pytest.mark.asyncio -async def test_nested_link(client: PageableClient): - result = [p async for p in client.server_driven_pagination.nested_link()] - assert_result(result) - - -@pytest.mark.asyncio -async def test_request_query_nested_response_body(client: PageableClient): - result = [ - p - async for p in client.server_driven_pagination.continuation_token.request_query_nested_response_body( - foo="foo", bar="bar" - ) - ] - assert_result(result) - - -@pytest.mark.asyncio -async def test_request_header_nested_response_body(client: PageableClient): - result = [ - p - async for p in client.server_driven_pagination.continuation_token.request_header_nested_response_body( - foo="foo", bar="bar" - ) - ] - assert_result(result) - - -@pytest.mark.asyncio -async def test_list_without_continuation(client: PageableClient): - result = [p async for p in client.page_size.list_without_continuation()] - assert_result(result) - - -@pytest.mark.asyncio -async def test_xml_pagination_list_with_continuation(client: PageableClient): - result = [p async for p in client.xml_pagination.list_with_continuation()] - assert_result(result) - - -@pytest.mark.asyncio -async def test_xml_pagination_list_with_next_link(client: PageableClient): - result = [p async for p in client.xml_pagination.list_with_next_link()] - assert_result(result) - - -@pytest.mark.asyncio -async def test_alternate_initial_verb_post(client: PageableClient): - result = [p async for p in client.server_driven_pagination.alternate_initial_verb.post(Filter(filter="foo eq bar"))] - assert_result(result) diff --git a/packages/typespec-python/tests/mock_api/shared/asynctests/test_payload_xml_async.py b/packages/typespec-python/tests/mock_api/shared/asynctests/test_payload_xml_async.py deleted file mode 100644 index 6cf981a0e4..0000000000 --- a/packages/typespec-python/tests/mock_api/shared/asynctests/test_payload_xml_async.py +++ /dev/null @@ -1,260 +0,0 @@ -# ------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for -# license information. -# -------------------------------------------------------------------------- -import datetime -import pytest -from payload.xml.aio import XmlClient -from payload.xml.models import ( - Author, - Book, - SimpleModel, - ModelWithSimpleArrays, - ModelWithArrayOfModel, - ModelWithAttributes, - ModelWithUnwrappedArray, - ModelWithUnwrappedModelArray, - ModelWithRenamedArrays, - ModelWithRenamedProperty, - ModelWithRenamedAttribute, - ModelWithRenamedNestedModel, - ModelWithRenamedWrappedModelArray, - ModelWithRenamedUnwrappedModelArray, - ModelWithRenamedWrappedAndItemModelArray, - ModelWithOptionalField, - ModelWithRenamedFields, - ModelWithEmptyArray, - ModelWithText, - ModelWithDictionary, - ModelWithEncodedNames, - ModelWithEnum, - ModelWithDatetime, - ModelWithNamespace, - ModelWithNamespaceOnProperties, - ModelWithNestedModel, - ModelWithWrappedPrimitiveCustomItemNames, -) - - -@pytest.fixture -async def client(): - async with XmlClient(endpoint="http://localhost:3000") as client: - yield client - - -@pytest.mark.asyncio -async def test_simple_model(client: XmlClient): - model = SimpleModel(name="foo", age=123) - assert await client.simple_model_value.get() == model - await client.simple_model_value.put(model) - - -@pytest.mark.asyncio -async def test_model_with_renamed_property(client: XmlClient): - model = ModelWithRenamedProperty(title="foo", author="bar") - assert await client.model_with_renamed_property_value.get() == model - await client.model_with_renamed_property_value.put(model) - - -@pytest.mark.asyncio -async def test_model_with_simple_arrays(client: XmlClient): - model = ModelWithSimpleArrays(colors=["red", "green", "blue"], counts=[1, 2]) - assert await client.model_with_simple_arrays_value.get() == model - await client.model_with_simple_arrays_value.put(model) - - -@pytest.mark.asyncio -async def test_model_with_wrapped_primitive_custom_item_names(client: XmlClient): - model = ModelWithWrappedPrimitiveCustomItemNames(tags=["fiction", "classic"]) - assert await client.model_with_wrapped_primitive_custom_item_names_value.get() == model - await client.model_with_wrapped_primitive_custom_item_names_value.put(model) - - -@pytest.mark.asyncio -async def test_model_with_array_of_model(client: XmlClient): - model = ModelWithArrayOfModel( - items_property=[ - SimpleModel(name="foo", age=123), - SimpleModel(name="bar", age=456), - ] - ) - assert await client.model_with_array_of_model_value.get() == model - await client.model_with_array_of_model_value.put(model) - - -@pytest.mark.asyncio -async def test_model_with_unwrapped_model_array(client: XmlClient): - model = ModelWithUnwrappedModelArray( - items_property=[ - SimpleModel(name="foo", age=123), - SimpleModel(name="bar", age=456), - ] - ) - assert await client.model_with_unwrapped_model_array_value.get() == model - await client.model_with_unwrapped_model_array_value.put(model) - - -@pytest.mark.asyncio -async def test_model_with_renamed_wrapped_model_array(client: XmlClient): - model = ModelWithRenamedWrappedModelArray( - items_property=[ - SimpleModel(name="foo", age=123), - SimpleModel(name="bar", age=456), - ] - ) - assert await client.model_with_renamed_wrapped_model_array_value.get() == model - await client.model_with_renamed_wrapped_model_array_value.put(model) - - -@pytest.mark.asyncio -async def test_model_with_renamed_unwrapped_model_array(client: XmlClient): - model = ModelWithRenamedUnwrappedModelArray( - items_property=[ - SimpleModel(name="foo", age=123), - SimpleModel(name="bar", age=456), - ] - ) - assert await client.model_with_renamed_unwrapped_model_array_value.get() == model - await client.model_with_renamed_unwrapped_model_array_value.put(model) - - -@pytest.mark.asyncio -async def test_model_with_renamed_wrapped_and_item_model_array(client: XmlClient): - model = ModelWithRenamedWrappedAndItemModelArray( - books=[ - Book(title="The Great Gatsby"), - Book(title="Les Miserables"), - ] - ) - assert await client.model_with_renamed_wrapped_and_item_model_array_value.get() == model - await client.model_with_renamed_wrapped_and_item_model_array_value.put(model) - - -@pytest.mark.asyncio -async def test_model_with_attributes(client: XmlClient): - model = ModelWithAttributes(id1=123, id2="foo", enabled=True) - assert await client.model_with_attributes_value.get() == model - await client.model_with_attributes_value.put(model) - - -@pytest.mark.asyncio -async def test_model_with_renamed_attribute(client: XmlClient): - model = ModelWithRenamedAttribute(id=123, title="The Great Gatsby", author="F. Scott Fitzgerald") - assert await client.model_with_renamed_attribute_value.get() == model - await client.model_with_renamed_attribute_value.put(model) - - -@pytest.mark.asyncio -async def test_model_with_unwrapped_array(client: XmlClient): - model = ModelWithUnwrappedArray(colors=["red", "green", "blue"], counts=[1, 2]) - assert await client.model_with_unwrapped_array_value.get() == model - await client.model_with_unwrapped_array_value.put(model) - - -@pytest.mark.asyncio -async def test_model_with_renamed_arrays(client: XmlClient): - model = ModelWithRenamedArrays(colors=["red", "green", "blue"], counts=[1, 2]) - assert await client.model_with_renamed_arrays_value.get() == model - await client.model_with_renamed_arrays_value.put(model) - - -@pytest.mark.asyncio -async def test_model_with_optional_field(client: XmlClient): - model = ModelWithOptionalField(item="widget") - assert await client.model_with_optional_field_value.get() == model - await client.model_with_optional_field_value.put(model) - - -@pytest.mark.asyncio -async def test_model_with_nested_model(client: XmlClient): - model = ModelWithNestedModel(nested=SimpleModel(name="foo", age=123)) - assert await client.model_with_nested_model_value.get() == model - await client.model_with_nested_model_value.put(model) - - -@pytest.mark.asyncio -async def test_model_with_renamed_nested_model(client: XmlClient): - model = ModelWithRenamedNestedModel(author=Author(name="foo")) - assert await client.model_with_renamed_nested_model_value.get() == model - await client.model_with_renamed_nested_model_value.put(model) - - -@pytest.mark.asyncio -async def test_model_with_renamed_fields(client: XmlClient): - model = ModelWithRenamedFields( - input_data=SimpleModel(name="foo", age=123), - output_data=SimpleModel(name="bar", age=456), - ) - assert await client.model_with_renamed_fields_value.get() == model - await client.model_with_renamed_fields_value.put(model) - - -@pytest.mark.asyncio -async def test_model_with_empty_array(client: XmlClient): - model = ModelWithEmptyArray(items_property=[]) - assert await client.model_with_empty_array_value.get() == model - await client.model_with_empty_array_value.put(model) - - -@pytest.mark.asyncio -async def test_model_with_text(client: XmlClient): - model = ModelWithText(language="foo", content="\n This is some text.\n") - assert await client.model_with_text_value.get() == model - await client.model_with_text_value.put(model) - - -@pytest.mark.asyncio -async def test_model_with_dictionary(client: XmlClient): - model = ModelWithDictionary(metadata={"Color": "blue", "Count": "123", "Enabled": "false"}) - assert await client.model_with_dictionary_value.get() == model - await client.model_with_dictionary_value.put(model) - - -@pytest.mark.asyncio -async def test_model_with_encoded_names(client: XmlClient): - model = ModelWithEncodedNames(model_data=SimpleModel(name="foo", age=123), colors=["red", "green", "blue"]) - assert await client.model_with_encoded_names_value.get() == model - await client.model_with_encoded_names_value.put(model) - - -@pytest.mark.asyncio -async def test_model_with_enum(client: XmlClient): - model = ModelWithEnum(status="success") - assert await client.model_with_enum_value.get() == model - await client.model_with_enum_value.put(model) - - -@pytest.mark.asyncio -async def test_model_with_datetime(client: XmlClient): - model = ModelWithDatetime( - rfc3339=datetime.datetime(2022, 8, 26, 18, 38, 0, tzinfo=datetime.timezone.utc), - rfc7231=datetime.datetime(2022, 8, 26, 14, 38, 0, tzinfo=datetime.timezone.utc), - ) - result = await client.model_with_datetime_value.get() - assert result.rfc3339 == model.rfc3339 - assert result.rfc7231 == model.rfc7231 - await client.model_with_datetime_value.put(model) - - -@pytest.mark.asyncio -async def test_model_with_namespace(client: XmlClient): - model = ModelWithNamespace(id=123, title="The Great Gatsby") - assert await client.model_with_namespace_value.get() == model - await client.model_with_namespace_value.put(model) - - -@pytest.mark.asyncio -async def test_model_with_namespace_on_properties(client: XmlClient): - model = ModelWithNamespaceOnProperties(id=123, title="The Great Gatsby", author="F. Scott Fitzgerald") - assert await client.model_with_namespace_on_properties_value.get() == model - await client.model_with_namespace_on_properties_value.put(model) - - -@pytest.mark.asyncio -async def test_xml_error_value(client: XmlClient, core_library): - with pytest.raises(core_library.exceptions.HttpResponseError) as ex: - await client.xml_error_value.get() - assert ex.value.status_code == 400 - assert ex.value.model.message == "Something went wrong" - assert ex.value.model.code == 400 diff --git a/packages/typespec-python/tests/mock_api/shared/asynctests/test_response_status_code_range_async.py b/packages/typespec-python/tests/mock_api/shared/asynctests/test_response_status_code_range_async.py deleted file mode 100644 index 3d6faa0c1f..0000000000 --- a/packages/typespec-python/tests/mock_api/shared/asynctests/test_response_status_code_range_async.py +++ /dev/null @@ -1,38 +0,0 @@ -# ------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for -# license information. -# -------------------------------------------------------------------------- -import pytest -from response.statuscoderange.aio import StatusCodeRangeClient -from response.statuscoderange.models import ErrorInRange, NotFoundError - - -@pytest.fixture -async def client(): - async with StatusCodeRangeClient(endpoint="http://localhost:3000") as client: - yield client - - -@pytest.mark.asyncio -async def test_error_response_status_code_in_range(client: StatusCodeRangeClient): - with pytest.raises(Exception) as exc_info: - await client.error_response_status_code_in_range() - - error = exc_info.value.model - assert isinstance(error, ErrorInRange) - assert error.code == "request-header-too-large" - assert error.message == "Request header too large" - assert exc_info.value.response.status_code == 494 - - -@pytest.mark.asyncio -async def test_error_response_status_code_404(client: StatusCodeRangeClient): - with pytest.raises(Exception) as exc_info: - await client.error_response_status_code404() - - error = exc_info.value.model - assert isinstance(error, NotFoundError) - assert error.code == "not-found" - assert error.resource_id == "resource1" - assert exc_info.value.response.status_code == 404 diff --git a/packages/typespec-python/tests/mock_api/shared/asynctests/test_routes_async.py b/packages/typespec-python/tests/mock_api/shared/asynctests/test_routes_async.py deleted file mode 100644 index 277e57be3a..0000000000 --- a/packages/typespec-python/tests/mock_api/shared/asynctests/test_routes_async.py +++ /dev/null @@ -1,331 +0,0 @@ -# ------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for -# license information. -# -------------------------------------------------------------------------- -import pytest -from routes.aio import RoutesClient - - -@pytest.fixture -async def client(): - async with RoutesClient() as client: - yield client - - -@pytest.mark.asyncio -async def test_fixed(client: RoutesClient): - await client.fixed() - - -@pytest.mark.asyncio -async def test_in_interface_fixed(client: RoutesClient): - await client.in_interface.fixed() - - -@pytest.mark.asyncio -async def test_path_parameters_template_only(client: RoutesClient): - await client.path_parameters.template_only( - param="a", - ) - - -@pytest.mark.asyncio -async def test_path_parameters_explicit(client: RoutesClient): - await client.path_parameters.explicit( - param="a", - ) - - -@pytest.mark.asyncio -async def test_path_parameters_annotation_only(client: RoutesClient): - await client.path_parameters.annotation_only( - param="a", - ) - - -@pytest.mark.asyncio -async def test_path_parameters_reserved_expansion_template(client: RoutesClient): - await client.path_parameters.reserved_expansion.template( - param="foo/bar baz", - ) - - -@pytest.mark.asyncio -async def test_path_parameters_reserved_expansion_annotation(client: RoutesClient): - await client.path_parameters.reserved_expansion.annotation( - param="foo/bar baz", - ) - - -# @pytest.mark.asyncio -# async def test_path_parameters_simple_expansion_standard_primitive(client: RoutesClient): -# await client.path_parameters.simple_expansion.standard.primitive( -# param="a", -# ) - - -# @pytest.mark.asyncio -# async def test_path_parameters_simple_expansion_standard_array(client: RoutesClient): -# await client.path_parameters.simple_expansion.standard.array( -# param=["a", "b"], -# ) - - -# @pytest.mark.asyncio -# async def test_path_parameters_simple_expansion_standard_record(client: RoutesClient): -# await client.path_parameters.simple_expansion.standard.record( -# param={"a": 1, "b": 2}, -# ) - - -# @pytest.mark.asyncio -# async def test_path_parameters_simple_expansion_explode_primitive(client: RoutesClient): -# await client.path_parameters.simple_expansion.explode.primitive( -# param="a", -# ) - - -# @pytest.mark.asyncio -# async def test_path_parameters_simple_expansion_explode_array(client: RoutesClient): -# await client.path_parameters.simple_expansion.explode.array( -# param=["a", "b"], -# ) - - -# @pytest.mark.asyncio -# async def test_path_parameters_simple_expansion_explode_record(client: RoutesClient): -# await client.path_parameters.simple_expansion.explode.record( -# param={"a": 1, "b": 2}, -# ) - - -# @pytest.mark.asyncio -# async def test_path_parameters_path_expansion_standard_primitive(client: RoutesClient): -# await client.path_parameters.path_expansion.standard.primitive( -# param="a", -# ) - - -# @pytest.mark.asyncio -# async def test_path_parameters_path_expansion_standard_array(client: RoutesClient): -# await client.path_parameters.path_expansion.standard.array( -# param=["a", "b"], -# ) - - -# @pytest.mark.asyncio -# async def test_path_parameters_path_expansion_standard_record(client: RoutesClient): -# await client.path_parameters.path_expansion.standard.record( -# param={"a": 1, "b": 2}, -# ) - - -# @pytest.mark.asyncio -# async def test_path_parameters_path_expansion_explode_primitive(client: RoutesClient): -# await client.path_parameters.path_expansion.explode.primitive( -# param="a", -# ) - - -# @pytest.mark.asyncio -# async def test_path_parameters_path_expansion_explode_array(client: RoutesClient): -# await client.path_parameters.path_expansion.explode.array( -# param=["a", "b"], -# ) - - -# @pytest.mark.asyncio -# async def test_path_parameters_path_expansion_explode_record(client: RoutesClient): -# await client.path_parameters.path_expansion.explode.record( -# param={"a": 1, "b": 2}, -# ) - - -# @pytest.mark.asyncio -# async def test_path_parameters_label_expansion_standard_primitive(client: RoutesClient): -# await client.path_parameters.label_expansion.standard.primitive( -# param="a", -# ) - - -# @pytest.mark.asyncio -# async def test_path_parameters_label_expansion_standard_array(client: RoutesClient): -# await client.path_parameters.label_expansion.standard.array( -# param=["a", "b"], -# ) - - -# @pytest.mark.asyncio -# async def test_path_parameters_label_expansion_standard_record(client: RoutesClient): -# await client.path_parameters.label_expansion.standard.record( -# param={"a": 1, "b": 2}, -# ) - - -# @pytest.mark.asyncio -# async def test_path_parameters_label_expansion_explode_primitive(client: RoutesClient): -# await client.path_parameters.label_expansion.explode.primitive( -# param="a", -# ) - - -# @pytest.mark.asyncio -# async def test_path_parameters_label_expansion_explode_array(client: RoutesClient): -# await client.path_parameters.label_expansion.explode.array( -# param=["a", "b"], -# ) - - -# @pytest.mark.asyncio -# async def test_path_parameters_label_expansion_explode_record(client: RoutesClient): -# await client.path_parameters.label_expansion.explode.record( -# param={"a": 1, "b": 2}, -# ) - - -# @pytest.mark.asyncio -# async def test_path_parameters_matrix_expansion_standard_primitive(client: RoutesClient): -# await client.path_parameters.matrix_expansion.standard.primitive( -# param="a", -# ) - - -# @pytest.mark.asyncio -# async def test_path_parameters_matrix_expansion_standard_array(client: RoutesClient): -# await client.path_parameters.matrix_expansion.standard.array( -# param=["a", "b"], -# ) - - -# @pytest.mark.asyncio -# async def test_path_parameters_matrix_expansion_standard_record(client: RoutesClient): -# await client.path_parameters.matrix_expansion.standard.record( -# param={"a": 1, "b": 2}, -# ) - - -# @pytest.mark.asyncio -# async def test_path_parameters_matrix_expansion_explode_primitive(client: RoutesClient): -# await client.path_parameters.matrix_expansion.explode.primitive( -# param="a", -# ) - - -# @pytest.mark.asyncio -# async def test_path_parameters_matrix_expansion_explode_array(client: RoutesClient): -# await client.path_parameters.matrix_expansion.explode.array( -# param=["a", "b"], -# ) - - -# @pytest.mark.asyncio -# async def test_path_parameters_matrix_expansion_explode_record(client: RoutesClient): -# await client.path_parameters.matrix_expansion.explode.record( -# param={"a": 1, "b": 2}, -# ) - - -@pytest.mark.asyncio -async def test_query_parameters_template_only(client: RoutesClient): - await client.query_parameters.template_only( - param="a", - ) - - -@pytest.mark.asyncio -async def test_query_parameters_explicit(client: RoutesClient): - await client.query_parameters.explicit( - param="a", - ) - - -@pytest.mark.asyncio -async def test_query_parameters_annotation_only(client: RoutesClient): - await client.query_parameters.annotation_only( - param="a", - ) - - -@pytest.mark.asyncio -async def test_query_parameters_query_expansion_standard_primitive(client: RoutesClient): - await client.query_parameters.query_expansion.standard.primitive( - param="a", - ) - - -# @pytest.mark.asyncio -# async def test_query_parameters_query_expansion_standard_array(client: RoutesClient): -# await client.query_parameters.query_expansion.standard.array( -# param=["a", "b"], -# ) - - -# @pytest.mark.asyncio -# async def test_query_parameters_query_expansion_standard_record(client: RoutesClient): -# await client.query_parameters.query_expansion.standard.record( -# param={"a": 1, "b": 2}, -# ) - - -@pytest.mark.asyncio -async def test_query_parameters_query_expansion_explode_primitive(client: RoutesClient): - await client.query_parameters.query_expansion.explode.primitive( - param="a", - ) - - -# @pytest.mark.asyncio -# async def test_query_parameters_query_expansion_explode_array(client: RoutesClient): -# await client.query_parameters.query_expansion.explode.array( -# param=["a", "b"], -# ) - - -# @pytest.mark.asyncio -# async def test_query_parameters_query_expansion_explode_record(client: RoutesClient): -# await client.query_parameters.query_expansion.explode.record( -# param={"a": 1, "b": 2}, -# ) - - -@pytest.mark.asyncio -async def test_query_parameters_query_continuation_standard_primitive(client: RoutesClient): - await client.query_parameters.query_continuation.standard.primitive( - param="a", - ) - - -# @pytest.mark.asyncio -# async def test_query_parameters_query_continuation_standard_array(client: RoutesClient): -# await client.query_parameters.query_continuation.standard.array( -# param=["a", "b"], -# ) - - -# @pytest.mark.asyncio -# async def test_query_parameters_query_continuation_standard_record(client: RoutesClient): -# await client.query_parameters.query_continuation.standard.record( -# param={"a": 1, "b": 2}, -# ) - - -@pytest.mark.asyncio -async def test_query_parameters_query_continuation_explode_primitive(client: RoutesClient): - await client.query_parameters.query_continuation.explode.primitive( - param="a", - ) - - -# @pytest.mark.asyncio -# async def test_query_parameters_query_continuation_explode_array(client: RoutesClient): -# await client.query_parameters.query_continuation.explode.array( -# param=["a", "b"], -# ) - - -# @pytest.mark.asyncio -# async def test_query_parameters_query_continuation_explode_record(client: RoutesClient): -# await client.query_parameters.query_continuation.explode.record( -# param={"a": 1, "b": 2}, -# ) diff --git a/packages/typespec-python/tests/mock_api/shared/asynctests/test_server_endpoint_not_defined_async.py b/packages/typespec-python/tests/mock_api/shared/asynctests/test_server_endpoint_not_defined_async.py deleted file mode 100644 index 148e61dd5c..0000000000 --- a/packages/typespec-python/tests/mock_api/shared/asynctests/test_server_endpoint_not_defined_async.py +++ /dev/null @@ -1,18 +0,0 @@ -# ------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for -# license information. -# -------------------------------------------------------------------------- -import pytest -from server.endpoint.notdefined.aio import NotDefinedClient - - -@pytest.fixture -async def client(): - async with NotDefinedClient(endpoint="http://localhost:3000") as client: - yield client - - -@pytest.mark.asyncio -async def test_valid(client: NotDefinedClient): - assert await client.valid() is True diff --git a/packages/typespec-python/tests/mock_api/shared/asynctests/test_server_path_multiple_async.py b/packages/typespec-python/tests/mock_api/shared/asynctests/test_server_path_multiple_async.py deleted file mode 100644 index bcdc53dd4f..0000000000 --- a/packages/typespec-python/tests/mock_api/shared/asynctests/test_server_path_multiple_async.py +++ /dev/null @@ -1,25 +0,0 @@ -# ------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for -# license information. -# -------------------------------------------------------------------------- -import pytest -from server.path.multiple.aio import MultipleClient - - -@pytest.fixture -async def client(): - async with MultipleClient(endpoint="http://localhost:3000") as client: - yield client - - -@pytest.mark.asyncio -async def test_no_operation_params(client: MultipleClient): - # await client.no_operation_params() - pass - - -@pytest.mark.asyncio -async def test_with_operation_path_param(client: MultipleClient): - # await client.with_operation_path_param(keyword="test") - pass diff --git a/packages/typespec-python/tests/mock_api/shared/asynctests/test_server_path_single_async.py b/packages/typespec-python/tests/mock_api/shared/asynctests/test_server_path_single_async.py deleted file mode 100644 index d6ebe479f8..0000000000 --- a/packages/typespec-python/tests/mock_api/shared/asynctests/test_server_path_single_async.py +++ /dev/null @@ -1,18 +0,0 @@ -# ------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for -# license information. -# -------------------------------------------------------------------------- -import pytest -from server.path.single.aio import SingleClient - - -@pytest.fixture -async def client(): - async with SingleClient(endpoint="http://localhost:3000") as client: - yield client - - -@pytest.mark.asyncio -async def test_my_op(client): - assert await client.my_op() is True diff --git a/packages/typespec-python/tests/mock_api/shared/asynctests/test_server_versions_not_versioned_async.py b/packages/typespec-python/tests/mock_api/shared/asynctests/test_server_versions_not_versioned_async.py deleted file mode 100644 index 738364b6e4..0000000000 --- a/packages/typespec-python/tests/mock_api/shared/asynctests/test_server_versions_not_versioned_async.py +++ /dev/null @@ -1,28 +0,0 @@ -# ------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for -# license information. -# -------------------------------------------------------------------------- -import pytest -from server.versions.notversioned.aio import NotVersionedClient - - -@pytest.fixture -async def client(): - async with NotVersionedClient(endpoint="http://localhost:3000") as client: - yield client - - -@pytest.mark.asyncio -async def test_without_api_version(client: NotVersionedClient): - await client.without_api_version() - - -@pytest.mark.asyncio -async def test_with_query_api_version(client: NotVersionedClient): - await client.with_query_api_version(api_version="v1.0") - - -@pytest.mark.asyncio -async def test_with_path_api_version(client: NotVersionedClient): - await client.with_path_api_version(api_version="v1.0") diff --git a/packages/typespec-python/tests/mock_api/shared/asynctests/test_server_versions_versioned_async.py b/packages/typespec-python/tests/mock_api/shared/asynctests/test_server_versions_versioned_async.py deleted file mode 100644 index 53e7d194f4..0000000000 --- a/packages/typespec-python/tests/mock_api/shared/asynctests/test_server_versions_versioned_async.py +++ /dev/null @@ -1,34 +0,0 @@ -# ------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for -# license information. -# -------------------------------------------------------------------------- -import pytest -from server.versions.versioned.aio import VersionedClient - - -@pytest.fixture -async def client(): - async with VersionedClient(endpoint="http://localhost:3000") as client: - yield client - - -@pytest.mark.asyncio -async def test_without_api_version(client: VersionedClient): - await client.without_api_version() - - -@pytest.mark.asyncio -async def test_with_query_api_version(client: VersionedClient): - await client.with_query_api_version() - - -@pytest.mark.asyncio -async def test_with_path_api_version(client: VersionedClient): - await client.with_path_api_version() - - -@pytest.mark.asyncio -async def test_with_query_old_api_version(): - async with VersionedClient(endpoint="http://localhost:3000", api_version="2021-01-01-preview") as client: - await client.with_query_old_api_version() diff --git a/packages/typespec-python/tests/mock_api/shared/asynctests/test_special_headers_conditional_request_async.py b/packages/typespec-python/tests/mock_api/shared/asynctests/test_special_headers_conditional_request_async.py deleted file mode 100644 index e65b9d4e33..0000000000 --- a/packages/typespec-python/tests/mock_api/shared/asynctests/test_special_headers_conditional_request_async.py +++ /dev/null @@ -1,38 +0,0 @@ -# ------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for -# license information. -# -------------------------------------------------------------------------- -import pytest -import datetime -from specialheaders.conditionalrequest.aio import ConditionalRequestClient - - -@pytest.fixture -async def client(): - async with ConditionalRequestClient() as client: - yield client - - -@pytest.mark.asyncio -async def test_post_if_match(core_library, client: ConditionalRequestClient): - await client.post_if_match(etag="valid", match_condition=core_library.MatchConditions.IfNotModified) - - -@pytest.mark.asyncio -async def test_post_if_none_match(core_library, client: ConditionalRequestClient): - await client.post_if_none_match(etag="invalid", match_condition=core_library.MatchConditions.IfModified) - - -@pytest.mark.asyncio -async def test_head_if_modified_since(client: ConditionalRequestClient): - await client.head_if_modified_since( - if_modified_since=datetime.datetime(2022, 8, 26, 14, 38, 0, tzinfo=datetime.timezone.utc) - ) - - -@pytest.mark.asyncio -async def test_post_if_unmodified_since(client: ConditionalRequestClient): - await client.post_if_unmodified_since( - if_unmodified_since=datetime.datetime(2022, 8, 26, 14, 38, 0, tzinfo=datetime.timezone.utc) - ) diff --git a/packages/typespec-python/tests/mock_api/shared/asynctests/test_special_headers_repeatability_async.py b/packages/typespec-python/tests/mock_api/shared/asynctests/test_special_headers_repeatability_async.py deleted file mode 100644 index dbf74414e1..0000000000 --- a/packages/typespec-python/tests/mock_api/shared/asynctests/test_special_headers_repeatability_async.py +++ /dev/null @@ -1,19 +0,0 @@ -# ------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for -# license information. -# -------------------------------------------------------------------------- -import pytest -from specialheaders.repeatability.aio import RepeatabilityClient - - -@pytest.fixture -async def client(): - async with RepeatabilityClient() as client: - yield client - - -@pytest.mark.asyncio -async def test_immediate_success(client: RepeatabilityClient): - cls = lambda x, y, z: z - assert (await client.immediate_success(cls=cls))["Repeatability-Result"] == "accepted" diff --git a/packages/typespec-python/tests/mock_api/shared/asynctests/test_specs_documentation_async.py b/packages/typespec-python/tests/mock_api/shared/asynctests/test_specs_documentation_async.py deleted file mode 100644 index 12e4cb2e5a..0000000000 --- a/packages/typespec-python/tests/mock_api/shared/asynctests/test_specs_documentation_async.py +++ /dev/null @@ -1,59 +0,0 @@ -# ------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for -# license information. -# -------------------------------------------------------------------------- - -import pytest -from specs.documentation.aio import DocumentationClient -from specs.documentation import models - - -@pytest.fixture -async def client(): - async with DocumentationClient(endpoint="http://localhost:3000") as client: - yield client - - -class TestLists: - @pytest.mark.asyncio - async def test_bullet_points_op(self, client: DocumentationClient): - # GET /documentation/lists/bullet-points/op - # Expected: 204 No Content - await client.lists.bullet_points_op() - - @pytest.mark.asyncio - async def test_bullet_points_model(self, client: DocumentationClient): - # POST /documentation/lists/bullet-points/model - # Expected request body: {"input": {"prop": "Simple"}} - # Expected: 200 OK - await client.lists.bullet_points_model(input=models.BulletPointsModel(prop="Simple")) - - # Also test with JSON - await client.lists.bullet_points_model(body={"input": {"prop": "Simple"}}) - - @pytest.mark.asyncio - async def test_numbered(self, client: DocumentationClient): - # GET /documentation/lists/numbered - # Expected: 204 No Content - await client.lists.numbered() - - -class TestTextFormatting: - @pytest.mark.asyncio - async def test_bold_text(self, client: DocumentationClient): - # GET /documentation/text-formatting/bold - # Expected: 204 No Content - await client.text_formatting.bold_text() - - @pytest.mark.asyncio - async def test_italic_text(self, client: DocumentationClient): - # GET /documentation/text-formatting/italic - # Expected: 204 No Content - await client.text_formatting.italic_text() - - @pytest.mark.asyncio - async def test_combined_formatting(self, client: DocumentationClient): - # GET /documentation/text-formatting/combined - # Expected: 204 No Content - await client.text_formatting.combined_formatting() diff --git a/packages/typespec-python/tests/mock_api/shared/asynctests/test_streaming_jsonl_async.py b/packages/typespec-python/tests/mock_api/shared/asynctests/test_streaming_jsonl_async.py deleted file mode 100644 index 803215abd9..0000000000 --- a/packages/typespec-python/tests/mock_api/shared/asynctests/test_streaming_jsonl_async.py +++ /dev/null @@ -1,27 +0,0 @@ -# ------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for -# license information. -# -------------------------------------------------------------------------- -import pytest - -from streaming.jsonl.aio import JsonlClient - - -@pytest.fixture -async def client(): - async with JsonlClient(endpoint="http://localhost:3000") as client: - yield client - - -JSONL = b'{"desc": "one"}\n{"desc": "two"}\n{"desc": "three"}' - - -@pytest.mark.asyncio -async def test_basic_send(client: JsonlClient): - await client.basic.send(JSONL) - - -@pytest.mark.asyncio -async def test_basic_recv(client: JsonlClient): - assert b"".join([d async for d in (await client.basic.receive())]) == JSONL diff --git a/packages/typespec-python/tests/mock_api/shared/asynctests/test_typetest_array_async.py b/packages/typespec-python/tests/mock_api/shared/asynctests/test_typetest_array_async.py deleted file mode 100644 index 180887ea76..0000000000 --- a/packages/typespec-python/tests/mock_api/shared/asynctests/test_typetest_array_async.py +++ /dev/null @@ -1,127 +0,0 @@ -# ------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for -# license information. -# -------------------------------------------------------------------------- - -import pytest -import isodate -from typetest.array.aio import ArrayClient -from typetest.array import models - - -@pytest.fixture -async def client(): - async with ArrayClient() as client: - yield client - - -@pytest.mark.asyncio -async def test_boolean_value(client: ArrayClient): - assert await client.boolean_value.get() == [True, False] - await client.boolean_value.put([True, False]) - - -@pytest.mark.asyncio -async def test_datetime_value(client: ArrayClient): - assert await client.datetime_value.get() == [isodate.parse_datetime("2022-08-26T18:38:00Z")] - await client.datetime_value.put([isodate.parse_datetime("2022-08-26T18:38:00Z")]) - - -@pytest.mark.asyncio -async def test_duration_value(client: ArrayClient): - assert await client.duration_value.get() == [isodate.parse_duration("P123DT22H14M12.011S")] - await client.duration_value.put([isodate.parse_duration("P123DT22H14M12.011S")]) - - -@pytest.mark.asyncio -async def test_float32_value(client: ArrayClient): - assert await client.float32_value.get() == [43.125] - await client.float32_value.put([43.125]) - - -@pytest.mark.asyncio -async def test_int32_value(client: ArrayClient): - assert await client.int32_value.get() == [1, 2] - await client.int32_value.put([1, 2]) - - -@pytest.mark.asyncio -async def test_int64_value(client: ArrayClient): - assert await client.int64_value.get() == [2**53 - 1, -(2**53 - 1)] - await client.int64_value.put([2**53 - 1, -(2**53 - 1)]) - - -@pytest.mark.asyncio -async def test_model_value(client: ArrayClient): - assert await client.model_value.get() == [ - models.InnerModel(property="hello"), - models.InnerModel(property="world"), - ] - # test list[model] - await client.model_value.put( - [ - models.InnerModel(property="hello"), - models.InnerModel(property="world"), - ] - ) - - # test list[JSON] - await client.model_value.put( - [ - {"property": "hello"}, - {"property": "world"}, - ] - ) - - -@pytest.mark.asyncio -async def test_nullable_boolean_value(client: ArrayClient): - assert await client.nullable_boolean_value.get() == [True, None, False] - await client.nullable_boolean_value.put([True, None, False]) - - -@pytest.mark.asyncio -async def test_nullable_float_value(client: ArrayClient): - assert await client.nullable_float_value.get() == [1.25, None, 3.0] - await client.nullable_float_value.put([1.25, None, 3.0]) - - -@pytest.mark.asyncio -async def test_nullable_int32_value(client: ArrayClient): - assert await client.nullable_int32_value.get() == [1, None, 3] - await client.nullable_int32_value.put([1, None, 3]) - - -@pytest.mark.asyncio -async def test_nullable_model_value(client: ArrayClient): - assert await client.nullable_model_value.get() == [ - models.InnerModel(property="hello"), - None, - models.InnerModel(property="world"), - ] - await client.nullable_model_value.put( - [ - models.InnerModel(property="hello"), - None, - models.InnerModel(property="world"), - ] - ) - - -@pytest.mark.asyncio -async def test_nullable_string_value(client: ArrayClient): - assert await client.nullable_string_value.get() == ["hello", None, "world"] - await client.nullable_string_value.put(["hello", None, "world"]) - - -@pytest.mark.asyncio -async def test_string_value(client: ArrayClient): - assert await client.string_value.get() == ["hello", ""] - await client.string_value.put(["hello", ""]) - - -@pytest.mark.asyncio -async def test_unknown_value(client: ArrayClient): - assert await client.unknown_value.get() == [1, "hello", None] - await client.unknown_value.put([1, "hello", None]) diff --git a/packages/typespec-python/tests/mock_api/shared/asynctests/test_typetest_dictionary_async.py b/packages/typespec-python/tests/mock_api/shared/asynctests/test_typetest_dictionary_async.py deleted file mode 100644 index 364868b235..0000000000 --- a/packages/typespec-python/tests/mock_api/shared/asynctests/test_typetest_dictionary_async.py +++ /dev/null @@ -1,98 +0,0 @@ -# ------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for -# license information. -# -------------------------------------------------------------------------- -import pytest -from typetest.dictionary import models -from typetest.dictionary.aio import DictionaryClient -import isodate - - -@pytest.fixture -async def client(): - async with DictionaryClient() as client: - yield client - - -@pytest.mark.asyncio -async def test_boolean_value(client: DictionaryClient): - value = {"k1": True, "k2": False} - assert await client.boolean_value.get() == value - await client.boolean_value.put(value) - - -@pytest.mark.asyncio -async def test_datetime_value(client: DictionaryClient): - value = {"k1": isodate.parse_datetime("2022-08-26T18:38:00Z")} - assert await client.datetime_value.get() == value - await client.datetime_value.put(value) - - -@pytest.mark.asyncio -async def test_duration_value(client: DictionaryClient): - value = {"k1": isodate.parse_duration("P123DT22H14M12.011S")} - assert await client.duration_value.get() == value - await client.duration_value.put(value) - - -@pytest.mark.asyncio -async def test_float32_value(client: DictionaryClient): - value = {"k1": 43.125} - assert await client.float32_value.get() == value - await client.float32_value.put(value) - - -@pytest.mark.asyncio -async def test_int32_value(client: DictionaryClient): - value = {"k1": 1, "k2": 2} - assert await client.int32_value.get() == value - await client.int32_value.put(value) - - -@pytest.mark.asyncio -async def test_int64_value(client: DictionaryClient): - value = {"k1": 2**53 - 1, "k2": -(2**53 - 1)} - assert await client.int64_value.get() == value - await client.int64_value.put(value) - - -@pytest.mark.asyncio -async def test_model_value(client: DictionaryClient): - value = { - "k1": models.InnerModel(property="hello"), - "k2": models.InnerModel(property="world"), - } - assert await client.model_value.get() == value - await client.model_value.put(value) - - -@pytest.mark.asyncio -async def test_nullable_float_value(client: DictionaryClient): - value = {"k1": 1.25, "k2": 0.5, "k3": None} - assert await client.nullable_float_value.get() == value - await client.nullable_float_value.put(value) - - -@pytest.mark.asyncio -async def test_recursive_model_value(client: DictionaryClient): - value = { - "k1": models.InnerModel(property="hello", children={}), - "k2": models.InnerModel(property="world", children={"k2.1": models.InnerModel(property="inner world")}), - } - assert await client.recursive_model_value.get() == value - await client.recursive_model_value.put(value) - - -@pytest.mark.asyncio -async def test_string_value(client: DictionaryClient): - value = {"k1": "hello", "k2": ""} - assert await client.string_value.get() == value - await client.string_value.put(value) - - -@pytest.mark.asyncio -async def test_unknown_value(client: DictionaryClient): - value = {"k1": 1, "k2": "hello", "k3": None} - assert await client.unknown_value.get() == value - await client.unknown_value.put(value) diff --git a/packages/typespec-python/tests/mock_api/shared/asynctests/test_typetest_enum_extensible_async.py b/packages/typespec-python/tests/mock_api/shared/asynctests/test_typetest_enum_extensible_async.py deleted file mode 100644 index 75fca822dd..0000000000 --- a/packages/typespec-python/tests/mock_api/shared/asynctests/test_typetest_enum_extensible_async.py +++ /dev/null @@ -1,25 +0,0 @@ -# ------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for -# license information. -# -------------------------------------------------------------------------- -import pytest -from typetest.enum.extensible import models, aio - - -@pytest.fixture -async def client(): - async with aio.ExtensibleClient() as client: - yield client - - -@pytest.mark.asyncio -async def test_known_value(client): - assert await client.string.get_known_value() == models.DaysOfWeekExtensibleEnum.MONDAY - await client.string.put_known_value(models.DaysOfWeekExtensibleEnum.MONDAY) - - -@pytest.mark.asyncio -async def test_unknown_value(client): - assert await client.string.get_unknown_value() == "Weekend" - await client.string.put_unknown_value("Weekend") diff --git a/packages/typespec-python/tests/mock_api/shared/asynctests/test_typetest_enum_fixed_async.py b/packages/typespec-python/tests/mock_api/shared/asynctests/test_typetest_enum_fixed_async.py deleted file mode 100644 index de17f194b6..0000000000 --- a/packages/typespec-python/tests/mock_api/shared/asynctests/test_typetest_enum_fixed_async.py +++ /dev/null @@ -1,27 +0,0 @@ -# ------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for -# license information. -# -------------------------------------------------------------------------- -import pytest -from typetest.enum.fixed import aio, models - - -@pytest.fixture -async def client(): - async with aio.FixedClient() as client: - yield client - - -@pytest.mark.asyncio -async def test_known_value(client): - assert await client.string.get_known_value() == models.DaysOfWeekEnum.MONDAY - await client.string.put_known_value(models.DaysOfWeekEnum.MONDAY) - - -@pytest.mark.asyncio -async def test_unknown_value(client: aio.FixedClient, core_library): - try: - await client.string.put_unknown_value("Weekend") - except core_library.exceptions.HttpResponseError as err: - assert err.status_code == 500 diff --git a/packages/typespec-python/tests/mock_api/shared/asynctests/test_typetest_file_async.py b/packages/typespec-python/tests/mock_api/shared/asynctests/test_typetest_file_async.py deleted file mode 100644 index 6fa9132a6b..0000000000 --- a/packages/typespec-python/tests/mock_api/shared/asynctests/test_typetest_file_async.py +++ /dev/null @@ -1,59 +0,0 @@ -# ------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for -# license information. -# -------------------------------------------------------------------------- -# after we support Http.File case, enable these tests again - - -# import json - -# import pytest -# from typetest.file.aio import FileClient - - -# @pytest.fixture -# async def client(): -# async with FileClient(endpoint="http://localhost:3000") as client: -# yield client - - -# @pytest.mark.asyncio -# async def test_upload_file_specific_content_type(client: FileClient, png_data: bytes): -# await client.body.upload_file_specific_content_type(png_data) - - -# # Do not support this case for now -# # @pytest.mark.asyncio -# # async def test_upload_file_json_content_type(client: FileClient): -# # await client.body.upload_file_json_content_type(json.dumps({"message": "test file content"}).encode()) - - -# # although result is expected but actually there is deserialization issue -# # @pytest.mark.asyncio -# # async def test_download_file_json_content_type(client: FileClient): -# # result = await client.body.download_file_json_content_type() -# # assert result == {"message": "test file content"} - - -# @pytest.mark.asyncio -# async def test_download_file_specific_content_type(client: FileClient, png_data: bytes): -# result = b"".join([d async for d in (await client.body.download_file_specific_content_type())]) -# assert result == png_data - - -# @pytest.mark.asyncio -# async def test_download_file_multiple_content_types(client: FileClient, png_data: bytes): -# result = b"".join([d async for d in (await client.body.download_file_multiple_content_types())]) -# assert result == png_data - - -# @pytest.mark.asyncio -# async def test_upload_file_default_content_type(client: FileClient, png_data: bytes): -# await client.body.upload_file_default_content_type(png_data, content_type="image/png") - - -# @pytest.mark.asyncio -# async def test_download_file_default_content_type(client: FileClient, png_data: bytes): -# result = b"".join([d async for d in (await client.body.download_file_default_content_type())]) -# assert result == png_data diff --git a/packages/typespec-python/tests/mock_api/shared/asynctests/test_typetest_model_empty_async.py b/packages/typespec-python/tests/mock_api/shared/asynctests/test_typetest_model_empty_async.py deleted file mode 100644 index b5518c5e90..0000000000 --- a/packages/typespec-python/tests/mock_api/shared/asynctests/test_typetest_model_empty_async.py +++ /dev/null @@ -1,32 +0,0 @@ -# ------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for -# license information. -# -------------------------------------------------------------------------- -import pytest -from typetest.model.empty.aio import EmptyClient -from typetest.model.empty.models import EmptyInput, EmptyOutput, EmptyInputOutput - - -@pytest.fixture -async def client(): - async with EmptyClient() as client: - yield client - - -@pytest.mark.asyncio -async def test_put(client: EmptyClient): - await client.put_empty(EmptyInput()) - await client.put_empty({}) - - -@pytest.mark.asyncio -async def test_get(client: EmptyClient): - assert await client.get_empty() == EmptyOutput() - assert await client.get_empty() == {} - - -@pytest.mark.asyncio -async def test_post_round(client: EmptyClient): - assert await client.post_round_trip_empty(EmptyInputOutput()) == EmptyInputOutput() - assert await client.post_round_trip_empty({}) == {} diff --git a/packages/typespec-python/tests/mock_api/shared/asynctests/test_typetest_model_inheritance_enum_discriminator_async.py b/packages/typespec-python/tests/mock_api/shared/asynctests/test_typetest_model_inheritance_enum_discriminator_async.py deleted file mode 100644 index 0a72d5465e..0000000000 --- a/packages/typespec-python/tests/mock_api/shared/asynctests/test_typetest_model_inheritance_enum_discriminator_async.py +++ /dev/null @@ -1,70 +0,0 @@ -# ------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for -# license information. -# -------------------------------------------------------------------------- -import pytest -from typetest.model.enumdiscriminator.aio import EnumDiscriminatorClient -from typetest.model.enumdiscriminator import models - - -@pytest.fixture -async def client(): - async with EnumDiscriminatorClient() as client: - yield client - - -@pytest.fixture -def valid_body(): - return models.Golden(weight=10) - - -@pytest.fixture -def valid_fixed_body(): - return models.Cobra(length=10) - - -@pytest.mark.asyncio -async def test_get_extensible_model(client: EnumDiscriminatorClient, valid_body: models.Dog): - assert await client.get_extensible_model() == valid_body - assert isinstance(await client.get_extensible_model(), models.Golden) - - -@pytest.mark.asyncio -async def test_put_extensible_model(client: EnumDiscriminatorClient, valid_body: models.Dog): - await client.put_extensible_model(valid_body) - - -@pytest.mark.asyncio -async def test_get_extensible_model_missing_discriminator( - client: EnumDiscriminatorClient, -): - assert await client.get_extensible_model_missing_discriminator() == models.Dog(weight=10) - - -@pytest.mark.asyncio -async def test_get_extensible_model_wrong_discriminator( - client: EnumDiscriminatorClient, -): - assert await client.get_extensible_model_wrong_discriminator() == models.Dog(weight=8, kind="wrongKind") - - -@pytest.mark.asyncio -async def test_get_fixed_model(client: EnumDiscriminatorClient, valid_fixed_body: models.Snake): - assert await client.get_fixed_model() == valid_fixed_body - assert isinstance(await client.get_fixed_model(), models.Cobra) - - -@pytest.mark.asyncio -async def test_put_fixed_model(client: EnumDiscriminatorClient, valid_fixed_body: models.Snake): - await client.put_fixed_model(valid_fixed_body) - - -@pytest.mark.asyncio -async def test_get_fixed_model_missing_discriminator(client: EnumDiscriminatorClient): - assert await client.get_fixed_model_missing_discriminator() == models.Snake(length=10) - - -@pytest.mark.asyncio -async def test_get_fixed_model_wrong_discriminator(client: EnumDiscriminatorClient): - assert await client.get_fixed_model_wrong_discriminator() == models.Snake(length=8, kind="wrongKind") diff --git a/packages/typespec-python/tests/mock_api/shared/asynctests/test_typetest_model_inheritance_nested_discriminator_async.py b/packages/typespec-python/tests/mock_api/shared/asynctests/test_typetest_model_inheritance_nested_discriminator_async.py deleted file mode 100644 index c641f25eb8..0000000000 --- a/packages/typespec-python/tests/mock_api/shared/asynctests/test_typetest_model_inheritance_nested_discriminator_async.py +++ /dev/null @@ -1,85 +0,0 @@ -# ------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for -# license information. -# -------------------------------------------------------------------------- -import pytest -from typetest.model.nesteddiscriminator.aio import NestedDiscriminatorClient -from typetest.model.nesteddiscriminator.models import GoblinShark, Salmon, Fish - - -@pytest.fixture -async def client(): - async with NestedDiscriminatorClient() as client: - yield client - - -@pytest.fixture -async def valid_body(): - return GoblinShark(age=1) - - -@pytest.mark.asyncio -async def test_get_model(client, valid_body): - assert await client.get_model() == valid_body - assert isinstance(await client.get_model(), GoblinShark) - - -@pytest.mark.asyncio -async def test_put_model(client, valid_body): - await client.put_model(valid_body) - - -@pytest.fixture -async def valid_recursive_body(): - return Salmon( - { - "age": 1, - "kind": "salmon", - "partner": {"age": 2, "kind": "shark", "sharktype": "saw"}, - "friends": [ - { - "age": 2, - "kind": "salmon", - "partner": {"age": 3, "kind": "salmon"}, - "hate": { - "key1": {"age": 4, "kind": "salmon"}, - "key2": {"age": 2, "kind": "shark", "sharktype": "goblin"}, - }, - }, - {"age": 3, "kind": "shark", "sharktype": "goblin"}, - ], - "hate": { - "key3": {"age": 3, "kind": "shark", "sharktype": "saw"}, - "key4": { - "age": 2, - "kind": "salmon", - "friends": [ - {"age": 1, "kind": "salmon"}, - {"age": 4, "kind": "shark", "sharktype": "goblin"}, - ], - }, - }, - } - ) - - -@pytest.mark.asyncio -async def test_get_recursive_model(client, valid_recursive_body): - assert valid_recursive_body == await client.get_recursive_model() - assert isinstance(await client.get_recursive_model(), Salmon) - - -@pytest.mark.asyncio -async def test_put_recursive_model(client, valid_recursive_body): - await client.put_recursive_model(valid_recursive_body) - - -@pytest.mark.asyncio -async def test_get_missing_discriminator(client): - assert await client.get_missing_discriminator() == Fish(age=1) - - -@pytest.mark.asyncio -async def test_get_wrong_discriminator(client): - assert await client.get_wrong_discriminator() == Fish(age=1, kind="wrongKind") diff --git a/packages/typespec-python/tests/mock_api/shared/asynctests/test_typetest_model_inheritance_not_discriminated_async.py b/packages/typespec-python/tests/mock_api/shared/asynctests/test_typetest_model_inheritance_not_discriminated_async.py deleted file mode 100644 index 7e7ce09695..0000000000 --- a/packages/typespec-python/tests/mock_api/shared/asynctests/test_typetest_model_inheritance_not_discriminated_async.py +++ /dev/null @@ -1,34 +0,0 @@ -# ------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for -# license information. -# -------------------------------------------------------------------------- -import pytest -from typetest.model.notdiscriminated.aio import NotDiscriminatedClient -from typetest.model.notdiscriminated.models import Siamese - - -@pytest.fixture -async def client(): - async with NotDiscriminatedClient() as client: - yield client - - -@pytest.fixture -async def valid_body(): - return Siamese(name="abc", age=32, smart=True) - - -@pytest.mark.asyncio -async def test_get_valid(client, valid_body): - assert await client.get_valid() == valid_body - - -@pytest.mark.asyncio -async def test_post_valid(client, valid_body): - await client.post_valid(valid_body) - - -@pytest.mark.asyncio -async def test_put_valid(client, valid_body): - assert valid_body == await client.put_valid(valid_body) diff --git a/packages/typespec-python/tests/mock_api/shared/asynctests/test_typetest_model_inheritance_recursive_async.py b/packages/typespec-python/tests/mock_api/shared/asynctests/test_typetest_model_inheritance_recursive_async.py deleted file mode 100644 index aea6f1bb9e..0000000000 --- a/packages/typespec-python/tests/mock_api/shared/asynctests/test_typetest_model_inheritance_recursive_async.py +++ /dev/null @@ -1,34 +0,0 @@ -# ------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for -# license information. -# -------------------------------------------------------------------------- -import pytest -from typetest.model.recursive.aio import RecursiveClient -from typetest.model.recursive.models import Extension - - -@pytest.fixture -async def client(): - async with RecursiveClient() as client: - yield client - - -@pytest.fixture -async def expected(): - return Extension( - { - "level": 0, - "extension": [{"level": 1, "extension": [{"level": 2}]}, {"level": 1}], - } - ) - - -@pytest.mark.asyncio -async def test_put(client: RecursiveClient, expected: Extension): - await client.put(expected) - - -@pytest.mark.asyncio -async def test_get(client: RecursiveClient, expected: Extension): - assert await client.get() == expected diff --git a/packages/typespec-python/tests/mock_api/shared/asynctests/test_typetest_model_inheritance_single_discriminator_async.py b/packages/typespec-python/tests/mock_api/shared/asynctests/test_typetest_model_inheritance_single_discriminator_async.py deleted file mode 100644 index dc98cd81c9..0000000000 --- a/packages/typespec-python/tests/mock_api/shared/asynctests/test_typetest_model_inheritance_single_discriminator_async.py +++ /dev/null @@ -1,67 +0,0 @@ -# ------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for -# license information. -# -------------------------------------------------------------------------- -import pytest -from typetest.model.singlediscriminator.aio import SingleDiscriminatorClient -from typetest.model.singlediscriminator.models import Sparrow, Eagle, Bird, Dinosaur - - -@pytest.fixture -async def client(): - async with SingleDiscriminatorClient() as client: - yield client - - -@pytest.fixture -async def valid_body(): - return Sparrow(wingspan=1) - - -@pytest.mark.asyncio -async def test_get_model(client, valid_body): - assert await client.get_model() == valid_body - - -@pytest.mark.asyncio -async def test_put_model(client, valid_body): - await client.put_model(valid_body) - - -@pytest.fixture -async def recursive_body(): - return Eagle( - { - "wingspan": 5, - "kind": "eagle", - "partner": {"wingspan": 2, "kind": "goose"}, - "friends": [{"wingspan": 2, "kind": "seagull"}], - "hate": {"key3": {"wingspan": 1, "kind": "sparrow"}}, - } - ) - - -@pytest.mark.asyncio -async def test_get_recursive_model(client, recursive_body): - assert await client.get_recursive_model() == recursive_body - - -@pytest.mark.asyncio -async def test_put_recursive_model(client, recursive_body): - await client.put_recursive_model(recursive_body) - - -@pytest.mark.asyncio -async def test_get_missing_discriminator(client): - assert await client.get_missing_discriminator() == Bird(wingspan=1) - - -@pytest.mark.asyncio -async def test_get_wrong_discriminator(client): - assert await client.get_wrong_discriminator() == Bird(wingspan=1, kind="wrongKind") - - -@pytest.mark.asyncio -async def test_get_legacy_model(client): - assert await client.get_legacy_model() == Dinosaur(size=20, kind="t-rex") diff --git a/packages/typespec-python/tests/mock_api/shared/asynctests/test_typetest_model_usage_async.py b/packages/typespec-python/tests/mock_api/shared/asynctests/test_typetest_model_usage_async.py deleted file mode 100644 index bcebeaec20..0000000000 --- a/packages/typespec-python/tests/mock_api/shared/asynctests/test_typetest_model_usage_async.py +++ /dev/null @@ -1,32 +0,0 @@ -# ------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for -# license information. -# -------------------------------------------------------------------------- -import pytest -from typetest.model.usage import models -from typetest.model.usage.aio import UsageClient - - -@pytest.fixture -async def client(): - async with UsageClient() as client: - yield client - - -@pytest.mark.asyncio -async def test_input(client: UsageClient): - input = models.InputRecord(required_prop="example-value") - assert await client.input(input) is None - - -@pytest.mark.asyncio -async def test_output(client: UsageClient): - output = models.OutputRecord(required_prop="example-value") - assert output == await client.output() - - -@pytest.mark.asyncio -async def test_input_and_output(client: UsageClient): - input_output = models.InputOutputRecord(required_prop="example-value") - assert input_output == await client.input_and_output(input_output) diff --git a/packages/typespec-python/tests/mock_api/shared/asynctests/test_typetest_model_visibility_async.py b/packages/typespec-python/tests/mock_api/shared/asynctests/test_typetest_model_visibility_async.py deleted file mode 100644 index 27fb23df8a..0000000000 --- a/packages/typespec-python/tests/mock_api/shared/asynctests/test_typetest_model_visibility_async.py +++ /dev/null @@ -1,47 +0,0 @@ -# ------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for -# license information. -# -------------------------------------------------------------------------- -import pytest -from typetest.model.visibility.aio import VisibilityClient -from typetest.model.visibility import models - - -@pytest.fixture -async def client(): - async with VisibilityClient() as client: - yield client - - -@pytest.mark.asyncio -async def test_get_model(client): - result = await client.get_model(models.VisibilityModel(), query_prop=123) - assert result == models.VisibilityModel(read_prop="abc") - - -@pytest.mark.asyncio -async def test_put_model(client): - await client.put_model(models.VisibilityModel(create_prop=["foo", "bar"], update_prop=[1, 2])) - - -@pytest.mark.asyncio -async def test_patch_model(client): - await client.patch_model(models.VisibilityModel(update_prop=[1, 2])) - - -@pytest.mark.asyncio -async def test_post_model(client): - await client.post_model(models.VisibilityModel(create_prop=["foo", "bar"])) - - -@pytest.mark.asyncio -async def test_delete_model(client): - await client.delete_model(models.VisibilityModel(delete_prop=True)) - - -@pytest.mark.asyncio -async def test_put_read_only_model(client): - await client.put_read_only_model( - models.ReadOnlyModel(optional_nullable_int_list=[1, 2], optional_string_record={"foo", "bar"}) - ) diff --git a/packages/typespec-python/tests/mock_api/shared/asynctests/test_typetest_property_additionalproperties_async.py b/packages/typespec-python/tests/mock_api/shared/asynctests/test_typetest_property_additionalproperties_async.py deleted file mode 100644 index 2109ea3179..0000000000 --- a/packages/typespec-python/tests/mock_api/shared/asynctests/test_typetest_property_additionalproperties_async.py +++ /dev/null @@ -1,353 +0,0 @@ -# ------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for -# license information. -# -------------------------------------------------------------------------- -import pytest -from typetest.property.additionalproperties import models -from typetest.property.additionalproperties.aio import AdditionalPropertiesClient - - -@pytest.fixture -async def client(): - async with AdditionalPropertiesClient() as client: - yield client - - -@pytest.mark.asyncio -async def test_extends_different_spread_float(client: AdditionalPropertiesClient): - body = models.DifferentSpreadFloatDerived({"name": "abc", "prop": 43.125, "derivedProp": 43.125}) - assert await client.extends_different_spread_float.get() == body - await client.extends_different_spread_float.put(body) - - -@pytest.mark.asyncio -async def test_extends_different_spread_model(client: AdditionalPropertiesClient): - body = models.DifferentSpreadModelDerived( - {"knownProp": "abc", "prop": {"state": "ok"}, "derivedProp": {"state": "ok"}} - ) - assert await client.extends_different_spread_model.get() == body - await client.extends_different_spread_model.put(body) - - -@pytest.mark.asyncio -async def test_extends_different_spread_model_array(client: AdditionalPropertiesClient): - body = models.DifferentSpreadModelArrayDerived( - { - "knownProp": "abc", - "prop": [{"state": "ok"}, {"state": "ok"}], - "derivedProp": [{"state": "ok"}, {"state": "ok"}], - } - ) - assert await client.extends_different_spread_model_array.get() == body - await client.extends_different_spread_model_array.put(body) - - -@pytest.mark.asyncio -async def test_extends_different_spread_string(client: AdditionalPropertiesClient): - body = models.DifferentSpreadStringDerived({"id": 43.125, "prop": "abc", "derivedProp": "abc"}) - assert await client.extends_different_spread_string.get() == body - await client.extends_different_spread_string.put(body) - - -@pytest.mark.asyncio -async def test_extends_float(client: AdditionalPropertiesClient): - body = models.ExtendsFloatAdditionalProperties({"id": 43.125, "prop": 43.125}) - assert await client.extends_float.get() == body - await client.extends_float.put(body) - - -@pytest.mark.asyncio -async def test_extends_model(client: AdditionalPropertiesClient): - body = models.ExtendsModelAdditionalProperties({"knownProp": {"state": "ok"}, "prop": {"state": "ok"}}) - assert await client.extends_model.get() == body - await client.extends_model.put(body) - - -@pytest.mark.asyncio -async def test_extends_model_array(client: AdditionalPropertiesClient): - body = models.ExtendsModelArrayAdditionalProperties( - { - "knownProp": [{"state": "ok"}, {"state": "ok"}], - "prop": [{"state": "ok"}, {"state": "ok"}], - } - ) - assert await client.extends_model_array.get() == body - await client.extends_model_array.put(body) - - -@pytest.mark.asyncio -async def test_extends_string(client: AdditionalPropertiesClient): - body = models.ExtendsStringAdditionalProperties({"name": "ExtendsStringAdditionalProperties", "prop": "abc"}) - assert await client.extends_string.get() == body - await client.extends_string.put(body) - - -@pytest.mark.asyncio -async def test_extends_unknown(client: AdditionalPropertiesClient): - body = models.ExtendsUnknownAdditionalProperties( - { - "name": "ExtendsUnknownAdditionalProperties", - "prop1": 32, - "prop2": True, - "prop3": "abc", - } - ) - assert await client.extends_unknown.get() == body - await client.extends_unknown.put(body) - - -@pytest.mark.asyncio -async def test_extends_unknown_derived(client: AdditionalPropertiesClient): - body = models.ExtendsUnknownAdditionalPropertiesDerived( - { - "name": "ExtendsUnknownAdditionalProperties", - "index": 314, - "age": 2.71875, - "prop1": 32, - "prop2": True, - "prop3": "abc", - } - ) - assert await client.extends_unknown_derived.get() == body - await client.extends_unknown_derived.put(body) - - -@pytest.mark.asyncio -async def test_extends_unknown_discriminated(client: AdditionalPropertiesClient): - body = models.ExtendsUnknownAdditionalPropertiesDiscriminatedDerived( - { - "kind": "derived", - "name": "Derived", - "index": 314, - "age": 2.71875, - "prop1": 32, - "prop2": True, - "prop3": "abc", - } - ) - assert await client.extends_unknown_discriminated.get() == body - await client.extends_unknown_discriminated.put(body) - - -@pytest.mark.asyncio -async def test_is_float(client: AdditionalPropertiesClient): - body = models.IsFloatAdditionalProperties({"id": 43.125, "prop": 43.125}) - assert await client.is_float.get() == body - await client.is_float.put(body) - - -@pytest.mark.asyncio -async def test_is_model(client: AdditionalPropertiesClient): - body = models.IsModelAdditionalProperties({"knownProp": {"state": "ok"}, "prop": {"state": "ok"}}) - assert await client.is_model.get() == body - await client.is_model.put(body) - - -@pytest.mark.asyncio -async def test_is_model_array(client: AdditionalPropertiesClient): - body = models.IsModelArrayAdditionalProperties( - { - "knownProp": [{"state": "ok"}, {"state": "ok"}], - "prop": [{"state": "ok"}, {"state": "ok"}], - } - ) - assert await client.is_model_array.get() == body - await client.is_model_array.put(body) - - -@pytest.mark.asyncio -async def test_is_string(client: AdditionalPropertiesClient): - body = models.IsStringAdditionalProperties({"name": "IsStringAdditionalProperties", "prop": "abc"}) - assert await client.is_string.get() == body - await client.is_string.put(body) - - -@pytest.mark.asyncio -async def test_is_unknown(client: AdditionalPropertiesClient): - body = models.IsUnknownAdditionalProperties( - { - "name": "IsUnknownAdditionalProperties", - "prop1": 32, - "prop2": True, - "prop3": "abc", - } - ) - assert await client.is_unknown.get() == body - await client.is_unknown.put(body) - - -@pytest.mark.asyncio -async def test_is_unknown_derived(client: AdditionalPropertiesClient): - body = models.IsUnknownAdditionalPropertiesDerived( - { - "name": "IsUnknownAdditionalProperties", - "index": 314, - "age": 2.71875, - "prop1": 32, - "prop2": True, - "prop3": "abc", - } - ) - assert await client.is_unknown_derived.get() == body - await client.is_unknown_derived.put(body) - - -@pytest.mark.asyncio -async def test_is_unknown_discriminated(client: AdditionalPropertiesClient): - body = models.IsUnknownAdditionalPropertiesDiscriminatedDerived( - { - "kind": "derived", - "name": "Derived", - "index": 314, - "age": 2.71875, - "prop1": 32, - "prop2": True, - "prop3": "abc", - } - ) - assert await client.is_unknown_discriminated.get() == body - await client.is_unknown_discriminated.put(body) - - -@pytest.mark.asyncio -async def test_multiple_spread(client: AdditionalPropertiesClient): - body = {"flag": True, "prop1": "abc", "prop2": 43.125} - assert await client.multiple_spread.get() == body - await client.multiple_spread.put(body) - - -@pytest.mark.asyncio -async def test_spread_different_float(client: AdditionalPropertiesClient): - body = {"name": "abc", "prop": 43.125} - assert await client.spread_different_float.get() == body - await client.spread_different_float.put(body) - - -@pytest.mark.asyncio -async def test_spread_different_model(client: AdditionalPropertiesClient): - body = {"knownProp": "abc", "prop": {"state": "ok"}} - assert await client.spread_different_model.get() == body - await client.spread_different_model.put(body) - - -@pytest.mark.asyncio -async def test_spread_different_model_array(client: AdditionalPropertiesClient): - body = {"knownProp": "abc", "prop": [{"state": "ok"}, {"state": "ok"}]} - assert await client.spread_different_model_array.get() == body - await client.spread_different_model_array.put(body) - - -@pytest.mark.asyncio -async def test_spread_different_string(client: AdditionalPropertiesClient): - body = {"id": 43.125, "prop": "abc"} - assert await client.spread_different_string.get() == body - await client.spread_different_string.put(body) - - -@pytest.mark.asyncio -async def test_spread_model(client: AdditionalPropertiesClient): - body = {"knownProp": {"state": "ok"}, "prop": {"state": "ok"}} - assert await client.spread_model.get() == body - await client.spread_model.put(body) - - -@pytest.mark.asyncio -async def test_spread_model_array(client: AdditionalPropertiesClient): - body = { - "knownProp": [{"state": "ok"}, {"state": "ok"}], - "prop": [{"state": "ok"}, {"state": "ok"}], - } - assert await client.spread_model_array.get() == body - await client.spread_model_array.put(body) - - -@pytest.mark.skip(reason="https://github.com/microsoft/typespec/pull/6425") -@pytest.mark.asyncio -async def test_spread_record_discriminated_union(client: AdditionalPropertiesClient): - body = { - "name": "abc", - "prop1": {"fooProp": "abc", "kind": "kind0"}, - "prop2": { - "end": "2021-01-02T00:00:00Z", - "kind": "kind1", - "start": "2021-01-01T00:00:00Z", - }, - } - assert await client.spread_record_discriminated_union.get() == body - await client.spread_record_discriminated_union.put(body) - - -@pytest.mark.asyncio -async def test_spread_record_non_discriminated_union( - client: AdditionalPropertiesClient, -): - body = { - "name": "abc", - "prop1": {"kind": "kind0", "fooProp": "abc"}, - "prop2": { - "kind": "kind1", - "start": "2021-01-01T00:00:00Z", - "end": "2021-01-02T00:00:00Z", - }, - } - assert await client.spread_record_non_discriminated_union.get() == body - await client.spread_record_non_discriminated_union.put(body) - - -@pytest.mark.asyncio -async def test_spread_record_non_discriminated_union2( - client: AdditionalPropertiesClient, -): - body = { - "name": "abc", - "prop1": {"kind": "kind1", "start": "2021-01-01T00:00:00Z"}, - "prop2": { - "kind": "kind1", - "start": "2021-01-01T00:00:00Z", - "end": "2021-01-02T00:00:00Z", - }, - } - assert await client.spread_record_non_discriminated_union2.get() == body - await client.spread_record_non_discriminated_union2.put(body) - - -@pytest.mark.asyncio -async def test_spread_record_non_discriminated_union3( - client: AdditionalPropertiesClient, -): - body = { - "name": "abc", - "prop1": [ - {"kind": "kind1", "start": "2021-01-01T00:00:00Z"}, - {"kind": "kind1", "start": "2021-01-01T00:00:00Z"}, - ], - "prop2": { - "kind": "kind1", - "start": "2021-01-01T00:00:00Z", - "end": "2021-01-02T00:00:00Z", - }, - } - assert await client.spread_record_non_discriminated_union3.get() == body - await client.spread_record_non_discriminated_union3.put(body) - - -@pytest.mark.asyncio -async def test_spread_record_union(client: AdditionalPropertiesClient): - body = {"flag": True, "prop1": "abc", "prop2": 43.125} - assert await client.spread_record_union.get() == body - await client.spread_record_union.put(body) - - -@pytest.mark.asyncio -async def test_spread_string(client: AdditionalPropertiesClient): - body = {"name": "SpreadSpringRecord", "prop": "abc"} - assert await client.spread_string.get() == body - await client.spread_string.put(body) - - -@pytest.mark.asyncio -async def test_spread_float(client: AdditionalPropertiesClient): - body = {"id": 43.125, "prop": 43.125} - assert await client.spread_float.get() == body - await client.spread_float.put(body) diff --git a/packages/typespec-python/tests/mock_api/shared/asynctests/test_typetest_property_nullable_async.py b/packages/typespec-python/tests/mock_api/shared/asynctests/test_typetest_property_nullable_async.py deleted file mode 100644 index a5dc132211..0000000000 --- a/packages/typespec-python/tests/mock_api/shared/asynctests/test_typetest_property_nullable_async.py +++ /dev/null @@ -1,110 +0,0 @@ -# cspell: ignore Hdvcmxk -# ------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for -# license information. -# -------------------------------------------------------------------------- -import json -import pytest -from typetest.property.nullable import models -from typetest.property.nullable.aio import NullableClient -from typetest.property.nullable._utils.model_base import ( # pylint: disable=protected-access - SdkJSONEncoder, -) - -try: - from corehttp.serialization import NULL -except ImportError: - from azure.core.serialization import NULL - - -@pytest.fixture -async def client(): - async with NullableClient() as client: - yield client - - -@pytest.mark.asyncio -async def test_bytes(client: NullableClient): - non_null_model = models.BytesProperty(required_property="foo", nullable_property="aGVsbG8sIHdvcmxkIQ==") - non_model = models.BytesProperty(required_property="foo", nullable_property=NULL) - assert '{"requiredProperty": "foo", "nullableProperty": null}' == json.dumps(non_model, cls=SdkJSONEncoder) - assert await client.bytes.get_non_null() == non_null_model - assert (await client.bytes.get_null())["nullableProperty"] is None - await client.bytes.patch_non_null(body=non_null_model) - await client.bytes.patch_null(body=non_model) - - -@pytest.mark.asyncio -async def test_collections_byte(client: NullableClient): - non_null_model = models.CollectionsByteProperty( - required_property="foo", - nullable_property=["aGVsbG8sIHdvcmxkIQ==", "aGVsbG8sIHdvcmxkIQ=="], - ) - non_model = models.CollectionsByteProperty(required_property="foo", nullable_property=NULL) - assert '{"requiredProperty": "foo", "nullableProperty": null}' == json.dumps(non_model, cls=SdkJSONEncoder) - assert await client.collections_byte.get_non_null() == non_null_model - assert (await client.collections_byte.get_null())["nullableProperty"] is None - await client.collections_byte.patch_non_null(body=non_null_model) - await client.collections_byte.patch_null(body=non_model) - - -@pytest.mark.asyncio -async def test_collections_model(client: NullableClient): - non_null_model = models.CollectionsModelProperty( - required_property="foo", - nullable_property=[ - models.InnerModel(property="hello"), - models.InnerModel(property="world"), - ], - ) - non_model = models.CollectionsModelProperty(required_property="foo", nullable_property=NULL) - assert '{"requiredProperty": "foo", "nullableProperty": null}' == json.dumps(non_model, cls=SdkJSONEncoder) - assert await client.collections_model.get_non_null() == non_null_model - assert (await client.collections_model.get_null())["nullableProperty"] is None - await client.collections_model.patch_non_null(body=non_null_model) - await client.collections_model.patch_null(body=non_model) - - -@pytest.mark.asyncio -async def test_collections_string(client: NullableClient): - non_null_model = models.CollectionsStringProperty(required_property="foo", nullable_property=["hello", "world"]) - non_model = models.CollectionsStringProperty(required_property="foo", nullable_property=NULL) - assert '{"requiredProperty": "foo", "nullableProperty": null}' == json.dumps(non_model, cls=SdkJSONEncoder) - assert await client.collections_string.get_non_null() == non_null_model - assert (await client.collections_string.get_null())["nullableProperty"] is None - await client.collections_string.patch_non_null(body=non_null_model) - await client.collections_string.patch_null(body=non_model) - - -@pytest.mark.asyncio -async def test_datetime(client: NullableClient): - non_null_model = models.DatetimeProperty(required_property="foo", nullable_property="2022-08-26T18:38:00Z") - non_model = models.DatetimeProperty(required_property="foo", nullable_property=NULL) - assert '{"requiredProperty": "foo", "nullableProperty": null}' == json.dumps(non_model, cls=SdkJSONEncoder) - assert await client.datetime.get_non_null() == non_null_model - assert (await client.datetime.get_null())["nullableProperty"] is None - await client.datetime.patch_non_null(body=non_null_model) - await client.datetime.patch_null(body=non_model) - - -@pytest.mark.asyncio -async def test_duration(client: NullableClient): - non_null_model = models.DurationProperty(required_property="foo", nullable_property="P123DT22H14M12.011S") - non_model = models.DurationProperty(required_property="foo", nullable_property=NULL) - assert '{"requiredProperty": "foo", "nullableProperty": null}' == json.dumps(non_model, cls=SdkJSONEncoder) - assert await client.duration.get_non_null() == non_null_model - assert (await client.duration.get_null())["nullableProperty"] is None - await client.duration.patch_non_null(body=non_null_model) - await client.duration.patch_null(body=non_model) - - -@pytest.mark.asyncio -async def test_string(client: NullableClient): - non_null_model = models.StringProperty(required_property="foo", nullable_property="hello") - non_model = models.StringProperty(required_property="foo", nullable_property=NULL) - assert '{"requiredProperty": "foo", "nullableProperty": null}' == json.dumps(non_model, cls=SdkJSONEncoder) - assert await client.string.get_non_null() == non_null_model - assert (await client.string.get_null())["nullableProperty"] is None - await client.string.patch_non_null(body=non_null_model) - await client.string.patch_null(body=non_model) diff --git a/packages/typespec-python/tests/mock_api/shared/asynctests/test_typetest_property_optional_async.py b/packages/typespec-python/tests/mock_api/shared/asynctests/test_typetest_property_optional_async.py deleted file mode 100644 index e7ec09d005..0000000000 --- a/packages/typespec-python/tests/mock_api/shared/asynctests/test_typetest_property_optional_async.py +++ /dev/null @@ -1,197 +0,0 @@ -# cspell: ignore Hdvcmxk -# ------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for -# license information. -# -------------------------------------------------------------------------- -from typing import Any -import pytest -from typetest.property.optional import models -from typetest.property.optional.aio import OptionalClient - - -@pytest.fixture -async def client(): - async with OptionalClient() as client: - yield client - - -@pytest.mark.asyncio -async def test_boolean_literal(client): - body = models.BooleanLiteralProperty(property=True) - assert await client.boolean_literal.get_all() == body - assert await client.boolean_literal.get_default() == models.BooleanLiteralProperty() - await client.boolean_literal.put_all(body) - await client.boolean_literal.put_default(models.BooleanLiteralProperty()) - - -@pytest.mark.asyncio -async def test_bytes(client): - body = models.BytesProperty(property="aGVsbG8sIHdvcmxkIQ==") - assert await client.bytes.get_all() == body - assert await client.bytes.get_default() == models.BytesProperty() - await client.bytes.put_all(body) - await client.bytes.put_default(models.BytesProperty()) - - -@pytest.mark.asyncio -async def test_collections_byte(client): - body = models.CollectionsByteProperty(property=["aGVsbG8sIHdvcmxkIQ==", "aGVsbG8sIHdvcmxkIQ=="]) - assert await client.collections_byte.get_all() == body - assert await client.collections_byte.get_default() == models.CollectionsByteProperty() - await client.collections_byte.put_all(body) - await client.collections_byte.put_default(models.CollectionsByteProperty()) - - -@pytest.mark.asyncio -async def test_collections_model(client): - body = models.CollectionsModelProperty( - property=[ - models.StringProperty(property="hello"), - models.StringProperty(property="world"), - ] - ) - assert await client.collections_model.get_all() == body - assert await client.collections_model.get_default() == models.CollectionsModelProperty() - await client.collections_model.put_all(body) - await client.collections_model.put_default(models.CollectionsModelProperty()) - - -@pytest.mark.asyncio -async def test_datetime(client): - body = models.DatetimeProperty(property="2022-08-26T18:38:00Z") - assert await client.datetime.get_all() == body - assert await client.datetime.get_default() == models.DatetimeProperty() - await client.datetime.put_all(body) - await client.datetime.put_default(models.DatetimeProperty()) - - -@pytest.mark.asyncio -async def test_duration(client): - body = models.DurationProperty(property="P123DT22H14M12.011S") - assert await client.duration.get_all() == body - assert await client.duration.get_default() == models.DurationProperty() - await client.duration.put_all(body) - await client.duration.put_default(models.DurationProperty()) - - -@pytest.mark.asyncio -async def test_float_literal(client): - body = models.FloatLiteralProperty(property=1.25) - assert await client.float_literal.get_all() == body - assert await client.float_literal.get_default() == models.FloatLiteralProperty() - await client.float_literal.put_all(body) - await client.float_literal.put_default(models.FloatLiteralProperty()) - - -@pytest.mark.asyncio -async def test_int_literal(client): - body = models.IntLiteralProperty(property=1) - assert await client.int_literal.get_all() == body - assert await client.int_literal.get_default() == models.IntLiteralProperty() - await client.int_literal.put_all(body) - await client.int_literal.put_default(models.IntLiteralProperty()) - - -@pytest.mark.asyncio -async def test_plaindate(client): - body = models.PlainDateProperty(property="2022-12-12") - assert await client.plain_date.get_all() == body - - -@pytest.mark.asyncio -async def test_plaindate(client): - assert await client.plain_date.get_default() == models.PlainDateProperty() - - -@pytest.mark.asyncio -async def test_plaindate(client): - body = models.PlainDateProperty(property="2022-12-12") - await client.plain_date.put_all(body) - - -@pytest.mark.asyncio -async def test_plaindate(client): - await client.plain_date.put_default(models.PlainDateProperty()) - - -@pytest.mark.asyncio -async def test_plaintime(client): - body = models.PlainTimeProperty(property="13:06:12") - assert await client.plain_time.get_all() == body - - -@pytest.mark.asyncio -async def test_plaintime(client): - assert await client.plain_time.get_default() == models.PlainTimeProperty() - - -@pytest.mark.asyncio -async def test_plaintime(client): - body = models.PlainTimeProperty(property="13:06:12") - await client.plain_time.put_all(body) - - -@pytest.mark.asyncio -async def test_plaintime(client): - await client.plain_time.put_default(models.PlainTimeProperty()) - - -@pytest.mark.asyncio -async def test_required_and_optional(client): - all_body = { - "optionalProperty": "hello", - "requiredProperty": 42, - } - required_only_body = { - "requiredProperty": 42, - } - assert await client.required_and_optional.get_all() == all_body - assert await client.required_and_optional.get_required_only() == required_only_body - await client.required_and_optional.put_all(all_body) - await client.required_and_optional.put_required_only(required_only_body) - - -@pytest.mark.asyncio -async def test_string(client): - body = models.StringProperty(property="hello") - assert await client.string.get_all() == body - assert await client.string.get_default() == models.StringProperty() - await client.string.put_all(body) - await client.string.put_default(models.StringProperty()) - - -@pytest.mark.asyncio -async def test_string_literal(client): - body = models.StringLiteralProperty(property="hello") - assert await client.string_literal.get_all() == body - assert await client.string_literal.get_default() == models.StringLiteralProperty() - await client.string_literal.put_all(body) - await client.string_literal.put_default(models.StringLiteralProperty()) - - -@pytest.mark.asyncio -async def test_union_float_literal(client): - body = models.UnionFloatLiteralProperty(property=2.375) - assert await client.union_float_literal.get_all() == body - assert await client.union_float_literal.get_default() == models.UnionFloatLiteralProperty() - await client.union_float_literal.put_all(body) - await client.union_float_literal.put_default(models.UnionFloatLiteralProperty()) - - -@pytest.mark.asyncio -async def test_union_int_literal(client): - body = models.UnionIntLiteralProperty(property=2) - assert await client.union_int_literal.get_all() == body - assert await client.union_int_literal.get_default() == models.UnionIntLiteralProperty() - await client.union_int_literal.put_all(body) - await client.union_int_literal.put_default(models.UnionIntLiteralProperty()) - - -@pytest.mark.asyncio -async def test_union_string_literal(client): - body = models.UnionStringLiteralProperty(property="world") - assert await client.union_string_literal.get_all() == body - assert await client.union_string_literal.get_default() == models.UnionStringLiteralProperty() - await client.union_string_literal.put_all(body) - await client.union_string_literal.put_default(models.UnionStringLiteralProperty()) diff --git a/packages/typespec-python/tests/mock_api/shared/asynctests/test_typetest_property_valuetypes_async.py b/packages/typespec-python/tests/mock_api/shared/asynctests/test_typetest_property_valuetypes_async.py deleted file mode 100644 index 1b7566c573..0000000000 --- a/packages/typespec-python/tests/mock_api/shared/asynctests/test_typetest_property_valuetypes_async.py +++ /dev/null @@ -1,315 +0,0 @@ -# cspell: ignore Hdvcmxk -# ------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for -# license information. -# -------------------------------------------------------------------------- -import decimal - -import pytest -import datetime -from typetest.property.valuetypes import models -from typetest.property.valuetypes.aio import ValueTypesClient - - -@pytest.fixture -async def client(): - async with ValueTypesClient() as client: - yield client - - -@pytest.mark.asyncio -async def test_boolean(client: ValueTypesClient): - body = models.BooleanProperty(property=True) - assert body.property == body["property"] - await client.boolean.put(body) - - resp = await client.boolean.get() - assert resp.property == resp["property"] == True - - -@pytest.mark.asyncio -async def test_boolean_literal(client: ValueTypesClient): - body = models.BooleanLiteralProperty(property=True) - assert body.property == body["property"] - await client.boolean_literal.put(body) - - resp = await client.boolean_literal.get() - assert resp.property == resp["property"] == True - - -@pytest.mark.asyncio -async def test_bytes(client: ValueTypesClient): - body = models.BytesProperty(property=b"hello, world!") - assert body.property == b"hello, world!" - assert body["property"] == "aGVsbG8sIHdvcmxkIQ==" - await client.bytes.put(body) - - resp = await client.bytes.get() - assert resp.property == b"hello, world!" - assert resp["property"] == "aGVsbG8sIHdvcmxkIQ==" - - -@pytest.mark.asyncio -async def test_collections_int(client: ValueTypesClient): - body = models.CollectionsIntProperty(property=[1, 2]) - assert body.property == body["property"] - await client.collections_int.put(body) - - resp = await client.collections_int.get() - assert resp.property == resp["property"] == [1, 2] - - -@pytest.mark.asyncio -async def test_collections_model(client: ValueTypesClient): - body = models.CollectionsModelProperty(property=[{"property": "hello"}, {"property": "world"}]) - assert body.property[0].property == body["property"][0]["property"] - await client.collections_model.put(body) - - resp = await client.collections_model.get() - assert resp.property[1].property == resp["property"][1]["property"] - - -@pytest.mark.asyncio -async def test_collections_string(client: ValueTypesClient): - body = models.CollectionsStringProperty(property=["hello", "world"]) - assert body.property == body["property"] - await client.collections_string.put(body) - - resp = await client.collections_string.get() - assert resp.property == resp["property"] == ["hello", "world"] - - -@pytest.mark.asyncio -async def test_datetime(client): - received_body = await client.datetime.get() - assert received_body == {"property": "2022-08-26T18:38:00Z"} - assert received_body.property.year == 2022 - assert received_body.property.month == 8 - assert received_body.property.day == 26 - assert received_body.property.hour == 18 - assert received_body.property.minute == 38 - - await client.datetime.put(models.DatetimeProperty(property=datetime.datetime(2022, 8, 26, hour=18, minute=38))) - - -@pytest.mark.asyncio -async def test_decimal(client: ValueTypesClient): - body = models.DecimalProperty(property=decimal.Decimal("0.33333")) - assert body.property == decimal.Decimal("0.33333") - assert body["property"] == 0.33333 - await client.decimal.put(body) - - resp = await client.decimal.get() - assert resp.property == decimal.Decimal("0.33333") - assert resp["property"] == 0.33333 - - -@pytest.mark.asyncio -async def test_decimal128(client: ValueTypesClient): - body = models.Decimal128Property(property=decimal.Decimal("0.33333")) - assert body.property == decimal.Decimal("0.33333") - assert body["property"] == 0.33333 - await client.decimal128.put(body) - - resp = await client.decimal128.get() - assert resp.property == decimal.Decimal("0.33333") - assert resp["property"] == 0.33333 - - -@pytest.mark.asyncio -async def test_dictionary_string(client: ValueTypesClient): - body = models.DictionaryStringProperty(property={"k1": "hello", "k2": "world"}) - assert body.property == body["property"] - await client.dictionary_string.put(body) - - resp = await client.dictionary_string.get() - assert resp.property == resp["property"] == {"k1": "hello", "k2": "world"} - - -@pytest.mark.asyncio -async def test_duration(client: ValueTypesClient): - body = models.DurationProperty(property="P123DT22H14M12.011S") - assert body.property == datetime.timedelta(days=123, seconds=80052, microseconds=11000) - assert body["property"] == "P123DT22H14M12.011S" - await client.duration.put(body) - - resp = await client.duration.get() - assert resp.property == datetime.timedelta(days=123, seconds=80052, microseconds=11000) - assert resp["property"] == "P123DT22H14M12.011S" - - -@pytest.mark.asyncio -async def test_enum(client: ValueTypesClient): - body = models.EnumProperty(property=models.InnerEnum.VALUE_ONE) - assert body.property == body["property"] - await client.enum.put(body) - - resp = await client.enum.get() - assert resp.property == resp["property"] == "ValueOne" - - -@pytest.mark.asyncio -async def test_extensible_enum(client: ValueTypesClient): - body = models.ExtensibleEnumProperty(property="UnknownValue") - assert body.property == body["property"] - await client.extensible_enum.put(body) - - resp = await client.extensible_enum.get() - assert resp.property == resp["property"] == "UnknownValue" - - -@pytest.mark.asyncio -async def test_float(client: ValueTypesClient): - body = models.FloatProperty(property=43.125) - assert body.property == body["property"] - await client.float.put(body) - - resp = await client.float.get() - assert resp.property == resp["property"] == 43.125 - - -@pytest.mark.asyncio -async def test_float_literal(client: ValueTypesClient): - body = models.FloatLiteralProperty(property=43.125) - assert body.property == body["property"] - await client.float_literal.put(body) - - resp = await client.float_literal.get() - assert resp.property == resp["property"] == 43.125 - - -@pytest.mark.asyncio -async def test_int(client: ValueTypesClient): - body = models.IntProperty(property=42) - assert body.property == body["property"] - await client.int_operations.put(body) - - resp = await client.int_operations.get() - assert resp.property == resp["property"] == 42 - - -@pytest.mark.asyncio -async def test_int_literal(client: ValueTypesClient): - body = models.IntLiteralProperty(property=42) - assert body.property == body["property"] - await client.int_literal.put(body) - - resp = await client.int_literal.get() - assert resp.property == resp["property"] == 42 - - -@pytest.mark.asyncio -async def test_model(client: ValueTypesClient): - body = models.ModelProperty(property={"property": "hello"}) - assert body.property.property == body["property"]["property"] - await client.model.put(body) - - resp = await client.model.get() - assert resp.property.property == resp["property"]["property"] - - -@pytest.mark.asyncio -async def test_never(client: ValueTypesClient): - assert await client.never.get() == models.NeverProperty() - await client.never.put(models.NeverProperty()) - - -@pytest.mark.asyncio -async def test_string(client: ValueTypesClient): - body = models.StringProperty(property="hello") - assert body.property == body["property"] - await client.string.put(body) - - resp = await client.string.get() - assert resp.property == resp["property"] == "hello" - - -@pytest.mark.asyncio -async def test_string_literal(client: ValueTypesClient): - body = models.StringLiteralProperty(property="hello") - assert body.property == body["property"] - await client.string_literal.put(body) - - resp = await client.string_literal.get() - assert resp.property == resp["property"] == "hello" - - -@pytest.mark.asyncio -async def test_union_enum_value(client: ValueTypesClient): - body = models.UnionEnumValueProperty(property=models.ExtendedEnum.ENUM_VALUE2) - assert body.property == body["property"] - await client.union_enum_value.put(body) - - resp = await client.union_enum_value.get() - assert resp.property == resp["property"] == "value2" - - -@pytest.mark.asyncio -async def test_union_float_literal(client: ValueTypesClient): - body = models.UnionFloatLiteralProperty(property=46.875) - assert body.property == body["property"] - await client.union_float_literal.put(body) - - resp = await client.union_float_literal.get() - assert resp.property == resp["property"] == 46.875 - - -@pytest.mark.asyncio -async def test_union_int_literal(client: ValueTypesClient): - body = models.UnionIntLiteralProperty(property=42) - assert body.property == body["property"] - await client.union_int_literal.put(body) - - resp = await client.union_int_literal.get() - assert resp.property == resp["property"] == 42 - - -@pytest.mark.asyncio -async def test_union_string_literal(client: ValueTypesClient): - body = models.UnionStringLiteralProperty(property="world") - assert body.property == body["property"] - await client.union_string_literal.put(body) - - resp = await client.union_string_literal.get() - assert resp.property == resp["property"] == "world" - - -@pytest.mark.asyncio -async def test_unknown_array(client: ValueTypesClient): - body = models.UnknownArrayProperty(property=["hello", "world"]) - assert body.property == body["property"] - await client.unknown_array.put(body) - - resp = await client.unknown_array.get() - assert resp.property == resp["property"] == ["hello", "world"] - - -@pytest.mark.asyncio -async def test_unknown_dict(client: ValueTypesClient): - body = models.UnknownDictProperty(property={"k1": "hello", "k2": 42}) - assert body.property == body["property"] - await client.unknown_dict.put(body) - - resp = await client.unknown_dict.get() - assert resp.property == resp["property"] == {"k1": "hello", "k2": 42} - - -@pytest.mark.asyncio -async def test_unknown_int(client: ValueTypesClient): - body = models.UnknownIntProperty(property=42) - assert body.property == body["property"] - await client.unknown_int.put(body) - - resp = await client.unknown_int.get() - assert resp.property == resp["property"] == 42 - - -@pytest.mark.asyncio -async def test_unknown_string(client: ValueTypesClient): - body = models.UnknownStringProperty(property="hello") - assert body.property == body["property"] - await client.unknown_string.put(body) - - resp = await client.unknown_string.get() - assert resp.property == resp["property"] == "hello" diff --git a/packages/typespec-python/tests/mock_api/shared/asynctests/test_typetest_scalar_async.py b/packages/typespec-python/tests/mock_api/shared/asynctests/test_typetest_scalar_async.py deleted file mode 100644 index 3e2b308f8b..0000000000 --- a/packages/typespec-python/tests/mock_api/shared/asynctests/test_typetest_scalar_async.py +++ /dev/null @@ -1,60 +0,0 @@ -# ------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for -# license information. -# -------------------------------------------------------------------------- -import decimal -from functools import reduce - -import pytest -from typetest.scalar.aio import ScalarClient - - -@pytest.fixture -async def client(): - async with ScalarClient() as client: - yield client - - -@pytest.mark.asyncio -async def test_scalar_string(client: ScalarClient): - assert await client.string.get() == "test" - await client.string.put("test") - - -@pytest.mark.asyncio -async def test_scalar_boolean(client: ScalarClient): - assert await client.boolean.get() == True - await client.boolean.put(True) - - -@pytest.mark.asyncio -async def test_scalar_unknown(client: ScalarClient): - assert await client.unknown.get() == "test" - await client.unknown.put("test") - - -@pytest.mark.asyncio -async def test_decimal128_type(client: ScalarClient): - assert await client.decimal128_type.response_body() == decimal.Decimal("0.33333") - await client.decimal128_type.request_body(decimal.Decimal("0.33333")) - await client.decimal128_type.request_parameter(value=decimal.Decimal("0.33333")) - - -@pytest.mark.asyncio -async def test_decimal_type(client: ScalarClient): - assert await client.decimal_type.response_body() == decimal.Decimal("0.33333") - await client.decimal_type.request_body(decimal.Decimal("0.33333")) - await client.decimal_type.request_parameter(value=decimal.Decimal("0.33333")) - - -@pytest.mark.asyncio -async def test_decimal128_verify(client: ScalarClient): - prepare = await client.decimal128_verify.prepare_verify() - await client.decimal128_verify.verify(reduce(lambda x, y: x + y, prepare)) - - -@pytest.mark.asyncio -async def test_decimal_verify(client: ScalarClient): - prepare = await client.decimal_verify.prepare_verify() - await client.decimal_verify.verify(reduce(lambda x, y: x + y, prepare)) diff --git a/packages/typespec-python/tests/mock_api/shared/asynctests/test_typetest_union_async.py b/packages/typespec-python/tests/mock_api/shared/asynctests/test_typetest_union_async.py deleted file mode 100644 index 9e738701f4..0000000000 --- a/packages/typespec-python/tests/mock_api/shared/asynctests/test_typetest_union_async.py +++ /dev/null @@ -1,90 +0,0 @@ -# ------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for -# license information. -# -------------------------------------------------------------------------- -import pytest -from typetest.union.aio import UnionClient -from typetest.union import models - - -@pytest.fixture -async def client(): - async with UnionClient() as client: - yield client - - -@pytest.mark.asyncio -async def test_enums_only(client: UnionClient): - value = models.EnumsOnlyCases(lr="right", ud="up") - assert (await client.enums_only.get()) == {"prop": value} - await client.enums_only.send(prop=value) - - -@pytest.mark.asyncio -async def test_floats_only(client: UnionClient): - value = 2.2 - assert (await client.floats_only.get()) == {"prop": value} - await client.floats_only.send(prop=value) - - -@pytest.mark.asyncio -async def test_ints_only(client: UnionClient): - value = 2 - assert (await client.ints_only.get()) == {"prop": value} - await client.ints_only.send(prop=value) - - -@pytest.mark.asyncio -async def test_mixed_literals(client: UnionClient): - value = models.MixedLiteralsCases(string_literal="a", int_literal=2, float_literal=3.3, boolean_literal=True) - assert (await client.mixed_literals.get()) == {"prop": value} - await client.mixed_literals.send(prop=value) - - -@pytest.mark.asyncio -async def test_mixed_types(client: UnionClient): - value = models.MixedTypesCases( - model=models.Cat(name="test"), - literal="a", - int_property=2, - boolean=True, - array=[models.Cat(name="test"), "a", 2, True], - ) - assert (await client.mixed_types.get()) == {"prop": value} - await client.mixed_types.send(prop=value) - - -@pytest.mark.asyncio -async def test_models_only(client: UnionClient): - value = models.Cat(name="test") - assert (await client.models_only.get()) == {"prop": value} - await client.models_only.send(prop=value) - - -@pytest.mark.asyncio -async def test_string_and_array(client: UnionClient): - value = models.StringAndArrayCases(string="test", array=["test1", "test2"]) - assert (await client.string_and_array.get()) == {"prop": value} - await client.string_and_array.send(prop=value) - - -@pytest.mark.asyncio -async def test_string_extensible(client: UnionClient): - value = "custom" - assert (await client.string_extensible.get()) == {"prop": value} - await client.string_extensible.send(prop=value) - - -@pytest.mark.asyncio -async def test_string_extensible_named(client: UnionClient): - value = "custom" - assert (await client.string_extensible_named.get()) == {"prop": value} - await client.string_extensible_named.send(prop=value) - - -@pytest.mark.asyncio -async def test_strings_only(client: UnionClient): - value = "b" - assert (await client.strings_only.get()) == {"prop": value} - await client.strings_only.send(prop=value) diff --git a/packages/typespec-python/tests/mock_api/shared/asynctests/test_versioning_added_async.py b/packages/typespec-python/tests/mock_api/shared/asynctests/test_versioning_added_async.py deleted file mode 100644 index 27e78a8892..0000000000 --- a/packages/typespec-python/tests/mock_api/shared/asynctests/test_versioning_added_async.py +++ /dev/null @@ -1,36 +0,0 @@ -# ------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for -# license information. -# -------------------------------------------------------------------------- -import pytest -from versioning.added.aio import AddedClient -from versioning.added.models import ModelV1, ModelV2, EnumV1, EnumV2 - - -@pytest.fixture -async def client(): - async with AddedClient(endpoint="http://localhost:3000", version="v2") as client: - yield client - - -@pytest.mark.asyncio -async def test_v1(client: AddedClient): - assert await client.v1( - ModelV1(prop="foo", enum_prop=EnumV1.ENUM_MEMBER_V2, union_prop=10), - header_v2="bar", - ) == ModelV1(prop="foo", enum_prop=EnumV1.ENUM_MEMBER_V2, union_prop=10) - - -@pytest.mark.asyncio -async def test_v2(client: AddedClient): - assert await client.v2(ModelV2(prop="foo", enum_prop=EnumV2.ENUM_MEMBER, union_prop="bar")) == ModelV2( - prop="foo", enum_prop=EnumV2.ENUM_MEMBER, union_prop="bar" - ) - - -@pytest.mark.asyncio -async def test_interface_v2(client: AddedClient): - assert await client.interface_v2.v2_in_interface( - ModelV2(prop="foo", enum_prop=EnumV2.ENUM_MEMBER, union_prop="bar") - ) == ModelV2(prop="foo", enum_prop=EnumV2.ENUM_MEMBER, union_prop="bar") diff --git a/packages/typespec-python/tests/mock_api/shared/asynctests/test_versioning_made_optional_async.py b/packages/typespec-python/tests/mock_api/shared/asynctests/test_versioning_made_optional_async.py deleted file mode 100644 index 27ec811cae..0000000000 --- a/packages/typespec-python/tests/mock_api/shared/asynctests/test_versioning_made_optional_async.py +++ /dev/null @@ -1,21 +0,0 @@ -# ------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for -# license information. -# -------------------------------------------------------------------------- -import pytest -from versioning.madeoptional.aio import MadeOptionalClient -from versioning.madeoptional.models import TestModel - - -@pytest.fixture -async def client(): - async with MadeOptionalClient(endpoint="http://localhost:3000", version="v2") as client: - yield client - - -@pytest.mark.asyncio -async def test(client: MadeOptionalClient): - assert await client.test( - TestModel(prop="foo"), - ) == TestModel(prop="foo") diff --git a/packages/typespec-python/tests/mock_api/shared/asynctests/test_versioning_removed_async.py b/packages/typespec-python/tests/mock_api/shared/asynctests/test_versioning_removed_async.py deleted file mode 100644 index 5442c56e6c..0000000000 --- a/packages/typespec-python/tests/mock_api/shared/asynctests/test_versioning_removed_async.py +++ /dev/null @@ -1,39 +0,0 @@ -# ------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for -# license information. -# -------------------------------------------------------------------------- -import pytest -from versioning.removed.aio import RemovedClient -from versioning.removed.models import ModelV2, EnumV2, ModelV3, EnumV3 - - -@pytest.fixture -async def client(): - async with RemovedClient(endpoint="http://localhost:3000", version="v2") as client: - yield client - - -@pytest.mark.asyncio -async def test_v2(client: RemovedClient): - assert await client.v2(ModelV2(prop="foo", enum_prop=EnumV2.ENUM_MEMBER_V2, union_prop="bar")) == ModelV2( - prop="foo", enum_prop=EnumV2.ENUM_MEMBER_V2, union_prop="bar" - ) - - -@pytest.mark.asyncio -async def test_model_v3(): - async with RemovedClient(endpoint="http://localhost:3000", version="v1") as client1: - model1 = ModelV3(id="123", enum_prop=EnumV3.ENUM_MEMBER_V1) - result = await client1.model_v3(model1) - assert result == model1 - - async with RemovedClient(endpoint="http://localhost:3000", version="v2preview") as client2: - model2 = ModelV3(id="123") - result = await client2.model_v3(model2) - assert result == model2 - - async with RemovedClient(endpoint="http://localhost:3000", version="v2") as client3: - model3 = ModelV3(id="123", enum_prop=EnumV3.ENUM_MEMBER_V1) - result = await client3.model_v3(model3) - assert result == model3 diff --git a/packages/typespec-python/tests/mock_api/shared/asynctests/test_versioning_renamed_from_async.py b/packages/typespec-python/tests/mock_api/shared/asynctests/test_versioning_renamed_from_async.py deleted file mode 100644 index 46ef588f65..0000000000 --- a/packages/typespec-python/tests/mock_api/shared/asynctests/test_versioning_renamed_from_async.py +++ /dev/null @@ -1,29 +0,0 @@ -# ------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for -# license information. -# -------------------------------------------------------------------------- -import pytest -from versioning.renamedfrom.aio import RenamedFromClient -from versioning.renamedfrom.models import NewModel, NewEnum - - -@pytest.fixture -async def client(): - async with RenamedFromClient(endpoint="http://localhost:3000", version="v2") as client: - yield client - - -@pytest.mark.asyncio -async def test_new_op(client: RenamedFromClient): - assert await client.new_op( - NewModel(new_prop="foo", enum_prop=NewEnum.NEW_ENUM_MEMBER, union_prop=10), - new_query="bar", - ) == NewModel(new_prop="foo", enum_prop=NewEnum.NEW_ENUM_MEMBER, union_prop=10) - - -@pytest.mark.asyncio -async def test_new_interface_test(client: RenamedFromClient): - assert await client.new_interface.new_op_in_new_interface( - NewModel(new_prop="foo", enum_prop=NewEnum.NEW_ENUM_MEMBER, union_prop=10) - ) == NewModel(new_prop="foo", enum_prop=NewEnum.NEW_ENUM_MEMBER, union_prop=10) diff --git a/packages/typespec-python/tests/mock_api/shared/asynctests/test_versioning_return_type_changed_from_async.py b/packages/typespec-python/tests/mock_api/shared/asynctests/test_versioning_return_type_changed_from_async.py deleted file mode 100644 index 80eefecbe2..0000000000 --- a/packages/typespec-python/tests/mock_api/shared/asynctests/test_versioning_return_type_changed_from_async.py +++ /dev/null @@ -1,18 +0,0 @@ -# ------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for -# license information. -# -------------------------------------------------------------------------- -import pytest -from versioning.returntypechangedfrom.aio import ReturnTypeChangedFromClient - - -@pytest.fixture -async def client(): - async with ReturnTypeChangedFromClient(endpoint="http://localhost:3000", version="v2") as client: - yield client - - -@pytest.mark.asyncio -async def test(client: ReturnTypeChangedFromClient): - assert await client.test("test") == "test" diff --git a/packages/typespec-python/tests/mock_api/shared/asynctests/test_versioning_type_changed_from_async.py b/packages/typespec-python/tests/mock_api/shared/asynctests/test_versioning_type_changed_from_async.py deleted file mode 100644 index 2374bd1f55..0000000000 --- a/packages/typespec-python/tests/mock_api/shared/asynctests/test_versioning_type_changed_from_async.py +++ /dev/null @@ -1,22 +0,0 @@ -# ------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for -# license information. -# -------------------------------------------------------------------------- -import pytest -from versioning.typechangedfrom.aio import TypeChangedFromClient -from versioning.typechangedfrom.models import TestModel - - -@pytest.fixture -async def client(): - async with TypeChangedFromClient(endpoint="http://localhost:3000", version="v2") as client: - yield client - - -@pytest.mark.asyncio -async def test(client: TypeChangedFromClient): - assert await client.test( - TestModel(prop="foo", changed_prop="bar"), - param="baz", - ) == TestModel(prop="foo", changed_prop="bar") diff --git a/packages/typespec-python/tests/mock_api/shared/conftest.py b/packages/typespec-python/tests/mock_api/shared/conftest.py deleted file mode 100644 index 6b55185794..0000000000 --- a/packages/typespec-python/tests/mock_api/shared/conftest.py +++ /dev/null @@ -1,7 +0,0 @@ -# ------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for -# license information. -# -------------------------------------------------------------------------- -# Shared fixtures are inherited from the root tests/conftest.py -# This file can contain additional shared fixtures if needed diff --git a/packages/typespec-python/tests/mock_api/shared/data/image.jpg b/packages/typespec-python/tests/mock_api/shared/data/image.jpg deleted file mode 100644 index b95b3e7b58286ad3e665d98d48b345977f862403..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4069 zcmeHJX;@QN8a_8Gn*#{~QJ4uNv1G6$BrHN6AVrn}mbL^3a4V7!OhA&51QRm!5kx@+ zTNcGZ6cC$Q+;~`GASla}wUxz{#c@GKXr)k4Y@<*!Hx%*D{OB`(hxgoj&v(xGzVDv* zyZ1cLYZx{>23FxAVIcs504RVPFpPlD9#xbBu1V2)YXM|gXB#0R#?0;vho@Ai`n{4K2Z_tc-vVNE8}_H8C|ahaEIl00AM92ow^HM!{MR`W#*d zC>$E^#0bDxN5*4GscV^8g=bC3n`_%`I5%f0?p)~sQ!`sT!n*Yv-gBn@)y2cpYm>JR zD=;WH4t_4#kAFVxjHXs&7-n{@yDwxhGFyQlZNTet7ry*D&GGCKBT{NGO}CV%+x+1&FN z^Dlq-RsZU>kryl_f2RdM|0^#X%nN}+AyHT(F9@M9633y?P7Dk_AQBs&YE5EhnXKJh zc(%6PlpPs~<`z2kKs1OmhoPzVGH-Zu)3MZ>_F zVvR60H(i4HGS)1?$_V@l3~&{b9rK09ND}!zi#oLh#Ro!~r%~ ztf@M>v0>6|AHFNXRdW{F2PwyE*zd{a+%36uhi4yu9aJ^ zpE7`9t8Rioz2KlN=S`ybbp-7ElQg->VN&I!l@n$S;9H_)yZXl$&PTX9ZObWvjhcE$f>gQt?~wSk)wt*@QfJ9e zFelD#>m0AB_sUj(c%Hr(E_yV;phB&=i9g9-)lO~OzQ2==_`u&bT{~<52lxK#Ow_NO zH{&-1-x&aQ;LQ0M(Zy$<1nTsq)xvVR{*&=ztX;IOz6|@z-F$Uf=(W0nyex6{P>FpW z4;0_dipualIew@$bH3M?aaJh~zSVba_s(ZYwY`7uX0rQ=C{sn1g*}wrL&Zt0cwal& z|(+)A&#XhLRoSPH3mt4Ji?-$~1F~yma)AnXu zRaaV$2SjEq$b{PVCY+v+iL;w8BOWVxgqdDst2gCLzog0=vM#q5L^ScNF_ipEjeb6n z1J0h4Y=S>iPa2P#Wgqq@^xWzm>-n^78z*$sXAucKo}EO|0uu3 zLs)^AUypvJF<+QUj|p5L&+NFzk0eJN%fi)?Gy8fd4jBz;gBAkjn_MPYks`G3a33&nP_o zg=l|nT>VF<@}|PZtIypU-TXbb#NA#UwTKA877jAo-sRoA;|O7M!oq~_ndaKA)cm{QH_jPuzCA+J zs!aHNWSYHBYfaj3>w14Gdb?$=t7cDh+;r%rP@Vlr;qGatS1nE0#?Fk+V2@G6gWq0G nRDbTJ{wDPH&YhvRw~$ZQH=nuD@w!Nwq+ZJbRY$2v!^nRCgjEVM diff --git a/packages/typespec-python/tests/mock_api/shared/data/image.png b/packages/typespec-python/tests/mock_api/shared/data/image.png deleted file mode 100644 index 42fe8dc14560b0046bf0f3f00b7a471fa0346e36..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2992 zcmaJ>2UJtr5=}ynfPe^6#i)oP2~A3b_#j9P<c=;9z@urf$wEd&r0Smmc~ z4b}n)eX~PAprkO6@Q)ZL0M}MJAZwiOD16}zNDSD?0g_k*{=o$NMUbCNY?07U9S+2S zEZop`b^yBJDZ#-+YAA`O;C(9uFi4PXy{I6N!uB-*+qrI=1#0z#xnpTqM+_2ABESQJ zNP)p{I)S{F2V_P^0xBVx7N9{V941ncbaU9Z2qd7dnGrCJZy~e@a~RgqMFUNu1Zx<< zb>X@&6jVb)!;BJi2rs64KWLg-BsIiteAdnPEGl#*}3jJK)-!qsV_Nx++`r}x@ z0TF8+gdSWM@iR9-HCwYHUBc+WhrO)A2tdz(8Yn{}vv1-5tZHzM{I(Zu9;;%|=s zCVEhVDQFS_C`d#7x~w1M-<>~*W{9LqLSH=UG`#0SvISvT&z^Cv#7@xJSx2aa-|9tm}-z6Hc>u#KDm+I4F>M3G9RmW+_?M2)1;gWo3xcVR@W8PHPH4h8*{++h z8}Y5F9`(=WPeZXH<+|Y0gJnwP5YL?0zo!3|^aN{T{s{OKE?O45QM0I0;1yDN`SND{ zyOg5mp)N5c(u0Esp-E=kfllR0C&k1s@i0GrZRfs5<7!+x0s^%ugM8%*ef;#PiEVR~ zk~180fRXw!|2qMhFy2QQNA)X#rKKLKFql@YS0DB+8Y~M0L6l6MBxAd5adGjcF9c8t zo3^yHG!i%{(t~?+_KjG%t?wg9W@hGn@>d^2zlX4eDsq69+{GOYhow*ZZ9YFY+;qgj z#AWZ^z2xho`YaYJ$mptuez>fhT&9eIf;49^mEC)&XN9ajcTsqPhD7C%d`TOUID=@6 zW~%vaGf31w{D~F5LO*H9Ul5b;M$_L~@5Rf{$YXmij@GSqZ($ztNsv;Z`i@;wgI)yL z`tVD3-D4YatT^h!2`{f7xgFBk(KVv6D=iyOe>q)Zxtu3f1vhZeoRRfQZ3s>DQ~|{c zhLZ7j^pqm{@Kbe|+)KiSAs)dZlW4Rb|0>x!mf7eaT?yRGZFm;h)5lP}0s z)MR+lRu=;7XofSxFZS5kB(Io?U<4$)=j+Ujv-f1z7}jT(U8oBF@c2?YjHZlX3}y?2 zB}I!j)%5LcxOt457x{YKwWQLqjkl*P!m*TD-H`cTuN{_G`e(Occ-dLa=;vA%@*AOg(a(z}6t_crT&EO-&+m4gF>N0h;BXG0?{Bi7 z`CMs0?IQEIN_yrvkTId}4tcQlLFDsm2){A5T)eb!$m;U*9bpNnS{u9Nur=c6{IY zKC28T*@~?E=+fvG1A<0jF;cm0Q(bSl;8d`tTUme#<>4g zLGy3~(+z4auzTu_$wj7=5_bmr4M3i>XprZ8-8A{ z^S%T(i(@^t7G<(wYTc~P^uFuDm}iOCg0RJbylL{6l)E9&xd*ipG|e`)b?b`n)|`3$ z>k`idS@_lp+*>nk7_W2qvLHrYsnN9VjcdkaYxRqWdf5!mZ8vsD^2e%lG>7`oaP1~( z91eF(@?7&4^jE^(0w>-(Xig#TL8J;KX+2YL&fdmGjCA1!I<+uYch0=ri`kM?G=Uz= zYe(%m$g6gpfYRA}M3Wh=PjV`BA|f`Ajz1QY-KfS$+mLC&=*M@CqU0@-843#@s!tp+ z`hXG_$T+w$%ZRc;oA!hozBo{U_AgR)cc2=ist%Tf1!goyZ`H}XSr9&UY zJ^9hCDY9E_U|L$j^3{t+O$rDP^WqxkQ)&F;Eh@Hsx^<};S#~>%t}R_YRkG7OjOT7s&BTd5F;H{&a{d!BS5Vz@RgwkT{dwhcQ zPGno6OlTdu0KU{d<)>5lyi9d5Rz$1ros^mpW_coXd{r;;5w~?!YUHbE$=hL2`F`si x55d?S>E1-idha0G3zgVNNXgr$|KG8qZJn`L2pQ~%2Sy6WZoiY&ZA<_7e*r@k8!Z3; diff --git a/packages/typespec-python/tests/mock_api/shared/test_authentication.py b/packages/typespec-python/tests/mock_api/shared/test_authentication.py deleted file mode 100644 index aaa000a85c..0000000000 --- a/packages/typespec-python/tests/mock_api/shared/test_authentication.py +++ /dev/null @@ -1,130 +0,0 @@ -# ------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for -# license information. -# -------------------------------------------------------------------------- -import pytest -from authentication.apikey import ApiKeyClient -from authentication.oauth2 import OAuth2Client -from authentication.union import UnionClient -from setuppy.authentication.union import UnionClient as SetuppyUnionClient -from authentication.noauth.union import UnionClient as NoauthUnionClient -from authentication.http.custom import CustomClient - -# Utilities functions - - -@pytest.fixture -def api_key_client(key_credential): - client = None - - def _build_client(client_type, key: str = "valid-key"): - client = client_type(key_credential(key)) - return client - - yield _build_client - if client: - client.close() - - -@pytest.fixture -def token_credential(core_library): - class FakeCredential: - @staticmethod - def get_token(*scopes): - return core_library.credentials.AccessToken(token="".join(scopes), expires_on=1800) - - @staticmethod - def get_token_info(*scopes, **kwargs): - return core_library.credentials.AccessTokenInfo(token="".join(scopes), expires_on=1800) - - return FakeCredential() - - -@pytest.fixture -def oauth2_client(token_credential): - client = None - - def _build_client(client_type): - client = client_type(token_credential) - return client - - yield _build_client - if client: - client.close() - - -@pytest.fixture -def http_custom_client(key_credential): - client = None - - def _build_client(key: str = "valid-key"): - client = CustomClient(key_credential(key)) - return client - - yield _build_client - if client: - client.close() - - -# Tests - - -def test_api_key_valid(api_key_client): - client = api_key_client(ApiKeyClient) - client.valid() - - -def test_api_key_invalid(api_key_client, core_library): - client = api_key_client(ApiKeyClient, "invalid-key") - with pytest.raises(core_library.exceptions.HttpResponseError) as ex: - client.invalid() - assert ex.value.status_code == 403 - assert ex.value.reason == "Forbidden" - - -def test_oauth2_valid(oauth2_client): - client = oauth2_client(OAuth2Client) - client.valid(enforce_https=False) - - -def test_oauth2_invalid(oauth2_client, core_library): - client = oauth2_client(OAuth2Client) - with pytest.raises(core_library.exceptions.HttpResponseError) as ex: - client.invalid(enforce_https=False) - assert ex.value.status_code == 403 - - -@pytest.mark.parametrize("union_client_type", [UnionClient, SetuppyUnionClient]) -def test_union_keyvalid(api_key_client, union_client_type): - client = api_key_client(union_client_type) - client.valid_key() - - -@pytest.mark.parametrize("union_client_type", [UnionClient, SetuppyUnionClient]) -def test_union_tokenvalid(oauth2_client, union_client_type): - client = oauth2_client(union_client_type) - client.valid_token(enforce_https=False) - - -def test_noauth_union_valid_no_auth(): - client = NoauthUnionClient() - client.valid_no_auth() - - -def test_noauth_union_valid_token(oauth2_client): - client = oauth2_client(NoauthUnionClient) - client.valid_token(enforce_https=False) - - -def test_http_custom_valid(http_custom_client): - client = http_custom_client() - client.valid() - - -def test_http_custom_invalid(http_custom_client, core_library): - client = http_custom_client("invalid-key") - with pytest.raises(core_library.exceptions.HttpResponseError) as ex: - client.invalid() - assert ex.value.status_code == 403 - assert ex.value.reason == "Forbidden" diff --git a/packages/typespec-python/tests/mock_api/shared/test_encode_array.py b/packages/typespec-python/tests/mock_api/shared/test_encode_array.py deleted file mode 100644 index a09a05a793..0000000000 --- a/packages/typespec-python/tests/mock_api/shared/test_encode_array.py +++ /dev/null @@ -1,126 +0,0 @@ -# ------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for -# license information. -# -------------------------------------------------------------------------- - -import pytest -from encode.array import ArrayClient, models - - -@pytest.fixture -def client(): - with ArrayClient() as client: - yield client - - -def test_comma_delimited(client: ArrayClient): - body = models.CommaDelimitedArrayProperty(value=["blue", "red", "green"]) - result = client.property.comma_delimited(body) - assert result.value == ["blue", "red", "green"] - - -def test_space_delimited(client: ArrayClient): - body = models.SpaceDelimitedArrayProperty(value=["blue", "red", "green"]) - result = client.property.space_delimited(body) - assert result.value == ["blue", "red", "green"] - - -def test_pipe_delimited(client: ArrayClient): - body = models.PipeDelimitedArrayProperty(value=["blue", "red", "green"]) - result = client.property.pipe_delimited(body) - assert result.value == ["blue", "red", "green"] - - -def test_newline_delimited(client: ArrayClient): - body = models.NewlineDelimitedArrayProperty(value=["blue", "red", "green"]) - result = client.property.newline_delimited(body) - assert result.value == ["blue", "red", "green"] - - -def test_enum_comma_delimited(client: ArrayClient): - body = models.CommaDelimitedEnumArrayProperty(value=[models.Colors.BLUE, models.Colors.RED, models.Colors.GREEN]) - result = client.property.enum_comma_delimited(body) - assert result.value == [models.Colors.BLUE, models.Colors.RED, models.Colors.GREEN] - - -def test_enum_space_delimited(client: ArrayClient): - body = models.SpaceDelimitedEnumArrayProperty(value=[models.Colors.BLUE, models.Colors.RED, models.Colors.GREEN]) - result = client.property.enum_space_delimited(body) - assert result.value == [models.Colors.BLUE, models.Colors.RED, models.Colors.GREEN] - - -def test_enum_pipe_delimited(client: ArrayClient): - body = models.PipeDelimitedEnumArrayProperty(value=[models.Colors.BLUE, models.Colors.RED, models.Colors.GREEN]) - result = client.property.enum_pipe_delimited(body) - assert result.value == [models.Colors.BLUE, models.Colors.RED, models.Colors.GREEN] - - -def test_enum_newline_delimited(client: ArrayClient): - body = models.NewlineDelimitedEnumArrayProperty(value=[models.Colors.BLUE, models.Colors.RED, models.Colors.GREEN]) - result = client.property.enum_newline_delimited(body) - assert result.value == [models.Colors.BLUE, models.Colors.RED, models.Colors.GREEN] - - -def test_extensible_enum_comma_delimited(client: ArrayClient): - body = models.CommaDelimitedExtensibleEnumArrayProperty( - value=[ - models.ColorsExtensibleEnum.BLUE, - models.ColorsExtensibleEnum.RED, - models.ColorsExtensibleEnum.GREEN, - ] - ) - result = client.property.extensible_enum_comma_delimited(body) - assert result.value == [ - models.ColorsExtensibleEnum.BLUE, - models.ColorsExtensibleEnum.RED, - models.ColorsExtensibleEnum.GREEN, - ] - - -def test_extensible_enum_space_delimited(client: ArrayClient): - body = models.SpaceDelimitedExtensibleEnumArrayProperty( - value=[ - models.ColorsExtensibleEnum.BLUE, - models.ColorsExtensibleEnum.RED, - models.ColorsExtensibleEnum.GREEN, - ] - ) - result = client.property.extensible_enum_space_delimited(body) - assert result.value == [ - models.ColorsExtensibleEnum.BLUE, - models.ColorsExtensibleEnum.RED, - models.ColorsExtensibleEnum.GREEN, - ] - - -def test_extensible_enum_pipe_delimited(client: ArrayClient): - body = models.PipeDelimitedExtensibleEnumArrayProperty( - value=[ - models.ColorsExtensibleEnum.BLUE, - models.ColorsExtensibleEnum.RED, - models.ColorsExtensibleEnum.GREEN, - ] - ) - result = client.property.extensible_enum_pipe_delimited(body) - assert result.value == [ - models.ColorsExtensibleEnum.BLUE, - models.ColorsExtensibleEnum.RED, - models.ColorsExtensibleEnum.GREEN, - ] - - -def test_extensible_enum_newline_delimited(client: ArrayClient): - body = models.NewlineDelimitedExtensibleEnumArrayProperty( - value=[ - models.ColorsExtensibleEnum.BLUE, - models.ColorsExtensibleEnum.RED, - models.ColorsExtensibleEnum.GREEN, - ] - ) - result = client.property.extensible_enum_newline_delimited(body) - assert result.value == [ - models.ColorsExtensibleEnum.BLUE, - models.ColorsExtensibleEnum.RED, - models.ColorsExtensibleEnum.GREEN, - ] diff --git a/packages/typespec-python/tests/mock_api/shared/test_encode_bytes.py b/packages/typespec-python/tests/mock_api/shared/test_encode_bytes.py deleted file mode 100644 index 2ca75a22c3..0000000000 --- a/packages/typespec-python/tests/mock_api/shared/test_encode_bytes.py +++ /dev/null @@ -1,128 +0,0 @@ -# ------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for -# license information. -# -------------------------------------------------------------------------- -from pathlib import Path - -import pytest -from encode.bytes import BytesClient -from encode.bytes.models import ( - DefaultBytesProperty, - Base64urlBytesProperty, - Base64BytesProperty, - Base64urlArrayBytesProperty, -) - -FILE_FOLDER = Path(__file__).parent - - -@pytest.fixture -def client(): - with BytesClient() as client: - yield client - - -def test_query(client: BytesClient): - client.query.default( - value=bytes("test", "utf-8"), - ) - client.query.base64( - value=bytes("test", "utf-8"), - ) - client.query.base64_url( - value=bytes("test", "utf-8"), - ) - client.query.base64_url_array( - value=[ - bytes("test", "utf-8"), - bytes("test", "utf-8"), - ], - ) - - -def test_property(client: BytesClient): - result = client.property.default( - DefaultBytesProperty( - value=bytes("test", "utf-8"), - ) - ) - assert result.value == bytes("test", "utf-8") - - result = client.property.base64( - Base64BytesProperty( - value=bytes("test", "utf-8"), - ) - ) - assert result.value == bytes("test", "utf-8") - - result = client.property.base64_url( - Base64urlBytesProperty( - value=bytes("test", "utf-8"), - ) - ) - assert result.value == bytes("test", "utf-8") - - result = client.property.base64_url_array( - Base64urlArrayBytesProperty( - value=[ - bytes("test", "utf-8"), - bytes("test", "utf-8"), - ], - ) - ) - assert result.value == [ - bytes("test", "utf-8"), - bytes("test", "utf-8"), - ] - - -def test_header(client: BytesClient): - client.header.default( - value=bytes("test", "utf-8"), - ) - client.header.base64( - value=bytes("test", "utf-8"), - ) - client.header.base64_url( - value=bytes("test", "utf-8"), - ) - client.header.base64_url_array( - value=[ - bytes("test", "utf-8"), - bytes("test", "utf-8"), - ], - ) - - -@pytest.fixture -def png_data() -> bytes: - with open(str(FILE_FOLDER / "data/image.png"), "rb") as file_in: - return file_in.read() - - -def test_request_body(client: BytesClient, png_data: bytes): - client.request_body.default( - value=png_data, - ) - client.request_body.octet_stream( - value=png_data, - ) - client.request_body.custom_content_type( - value=png_data, - ) - client.request_body.base64( - value=bytes("test", "utf-8"), - ) - client.request_body.base64_url( - value=bytes("test", "utf-8"), - ) - - -def test_response_body(client: BytesClient, png_data: bytes): - expected = b"test" - assert b"".join(client.response_body.default()) == png_data - assert expected == client.response_body.base64() - assert b"".join(client.response_body.octet_stream()) == png_data - assert b"".join(client.response_body.custom_content_type()) == png_data - assert expected == client.response_body.base64_url() diff --git a/packages/typespec-python/tests/mock_api/shared/test_encode_datetime.py b/packages/typespec-python/tests/mock_api/shared/test_encode_datetime.py deleted file mode 100644 index 46b32f9734..0000000000 --- a/packages/typespec-python/tests/mock_api/shared/test_encode_datetime.py +++ /dev/null @@ -1,123 +0,0 @@ -# ------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for -# license information. -# -------------------------------------------------------------------------- -import datetime - -import pytest -from encode.datetime import DatetimeClient -from encode.datetime.models import ( - DefaultDatetimeProperty, - Rfc3339DatetimeProperty, - Rfc7231DatetimeProperty, - UnixTimestampDatetimeProperty, - UnixTimestampArrayDatetimeProperty, -) - - -@pytest.fixture -def client(): - with DatetimeClient() as client: - yield client - - -def test_query(client: DatetimeClient): - client.query.default( - value=datetime.datetime(2022, 8, 26, 18, 38, 0, tzinfo=datetime.timezone.utc), - ) - client.query.rfc3339( - value=datetime.datetime(2022, 8, 26, 18, 38, 0, tzinfo=datetime.timezone.utc), - ) - client.query.rfc7231( - value=datetime.datetime(2022, 8, 26, 14, 38, 0, tzinfo=datetime.timezone.utc), - ) - client.query.unix_timestamp( - value=datetime.datetime(2023, 6, 12, 10, 47, 44, tzinfo=datetime.timezone.utc), - ) - client.query.unix_timestamp_array( - value=[ - datetime.datetime(2023, 6, 12, 10, 47, 44, tzinfo=datetime.timezone.utc), - datetime.datetime(2023, 6, 14, 9, 17, 36, tzinfo=datetime.timezone.utc), - ], - ) - - -def test_property(client: DatetimeClient): - result = client.property.default( - DefaultDatetimeProperty( - value=datetime.datetime(2022, 8, 26, 18, 38, 0, tzinfo=datetime.timezone.utc), - ) - ) - assert result.value == datetime.datetime(2022, 8, 26, 18, 38, 0, tzinfo=datetime.timezone.utc) - - result = client.property.rfc3339( - Rfc3339DatetimeProperty( - value=datetime.datetime(2022, 8, 26, 18, 38, 0, tzinfo=datetime.timezone.utc), - ) - ) - assert result.value == datetime.datetime(2022, 8, 26, 18, 38, 0, tzinfo=datetime.timezone.utc) - - result = client.property.rfc7231( - Rfc7231DatetimeProperty( - value=datetime.datetime(2022, 8, 26, 14, 38, 0, tzinfo=datetime.timezone.utc), - ) - ) - assert result.value == datetime.datetime(2022, 8, 26, 14, 38, 0, tzinfo=datetime.timezone.utc) - - result = client.property.unix_timestamp( - UnixTimestampDatetimeProperty( - value=datetime.datetime(2023, 6, 12, 10, 47, 44, tzinfo=datetime.timezone.utc), - ) - ) - assert result.value == datetime.datetime(2023, 6, 12, 10, 47, 44, tzinfo=datetime.timezone.utc) - - result = client.property.unix_timestamp_array( - UnixTimestampArrayDatetimeProperty( - value=[ - datetime.datetime(2023, 6, 12, 10, 47, 44, tzinfo=datetime.timezone.utc), - datetime.datetime(2023, 6, 14, 9, 17, 36, tzinfo=datetime.timezone.utc), - ], - ) - ) - assert result.value == [ - datetime.datetime(2023, 6, 12, 10, 47, 44, tzinfo=datetime.timezone.utc), - datetime.datetime(2023, 6, 14, 9, 17, 36, tzinfo=datetime.timezone.utc), - ] - - -def test_header(client: DatetimeClient): - client.header.default( - value=datetime.datetime(2022, 8, 26, 14, 38, 0, tzinfo=datetime.timezone.utc), - ) - client.header.rfc3339( - value=datetime.datetime(2022, 8, 26, 18, 38, 0, tzinfo=datetime.timezone.utc), - ) - client.header.rfc7231( - value=datetime.datetime(2022, 8, 26, 14, 38, 0, tzinfo=datetime.timezone.utc), - ) - client.header.unix_timestamp( - value=datetime.datetime(2023, 6, 12, 10, 47, 44, tzinfo=datetime.timezone.utc), - ) - client.header.unix_timestamp_array( - value=[ - datetime.datetime(2023, 6, 12, 10, 47, 44, tzinfo=datetime.timezone.utc), - datetime.datetime(2023, 6, 14, 9, 17, 36, tzinfo=datetime.timezone.utc), - ] - ) - - -def test_response_header(client: DatetimeClient): - cls = lambda x, y, z: z - assert client.response_header.default(cls=cls)["value"] == datetime.datetime( - 2022, 8, 26, 14, 38, 0, tzinfo=datetime.timezone.utc - ) - assert client.response_header.rfc3339(cls=cls)["value"] == datetime.datetime( - 2022, 8, 26, 18, 38, 0, tzinfo=datetime.timezone.utc - ) - assert client.response_header.rfc7231(cls=cls)["value"] == datetime.datetime( - 2022, 8, 26, 14, 38, 0, tzinfo=datetime.timezone.utc - ) - assert client.response_header.unix_timestamp(cls=cls)["value"] == datetime.datetime( - 2023, 6, 12, 10, 47, 44, tzinfo=datetime.timezone.utc - ) diff --git a/packages/typespec-python/tests/mock_api/shared/test_generation_subdir.py b/packages/typespec-python/tests/mock_api/shared/test_generation_subdir.py deleted file mode 100644 index 661fbaecf2..0000000000 --- a/packages/typespec-python/tests/mock_api/shared/test_generation_subdir.py +++ /dev/null @@ -1,17 +0,0 @@ -# ------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for -# license information. -# -------------------------------------------------------------------------- -from generation.subdir._generated import RecursiveClient -from generation.subdir._generated.models import Extension - - -def test_custom_method(): - client = RecursiveClient() - assert client.get() == Extension( - { - "level": 0, - "extension": [{"level": 1, "extension": [{"level": 2}]}, {"level": 1}], - } - ) diff --git a/packages/typespec-python/tests/mock_api/shared/test_headasboolean.py b/packages/typespec-python/tests/mock_api/shared/test_headasboolean.py deleted file mode 100644 index c26d63d39f..0000000000 --- a/packages/typespec-python/tests/mock_api/shared/test_headasboolean.py +++ /dev/null @@ -1,33 +0,0 @@ -# ------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for -# license information. -# -------------------------------------------------------------------------- -import pytest -from headasbooleantrue import VisibilityClient as HeadAsBooleanTrueClient -from headasbooleantrue import models as models_true - -from headasbooleanfalse import VisibilityClient as HeadAsBooleanFalseClient -from headasbooleanfalse import models as models_false - - -@pytest.fixture -def client_true(): - with HeadAsBooleanTrueClient() as client: - yield client - - -@pytest.fixture -def client_false(): - with HeadAsBooleanFalseClient() as client: - yield client - - -def test_head_true(client_true): - body = models_true.VisibilityModel() - assert client_true.head_model(body, query_prop=123) == True - - -def test_head_false(client_false): - body = models_false.VisibilityModel() - assert client_false.head_model(body, query_prop=123) is None diff --git a/packages/typespec-python/tests/mock_api/shared/test_parameters_body_optionality.py b/packages/typespec-python/tests/mock_api/shared/test_parameters_body_optionality.py deleted file mode 100644 index 66ea0a9fea..0000000000 --- a/packages/typespec-python/tests/mock_api/shared/test_parameters_body_optionality.py +++ /dev/null @@ -1,27 +0,0 @@ -# ------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for -# license information. -# -------------------------------------------------------------------------- -import pytest -from parameters.bodyoptionality import BodyOptionalityClient -from parameters.bodyoptionality.models import BodyModel - - -@pytest.fixture -def client(): - with BodyOptionalityClient() as client: - yield client - - -def test_required_explicit(client: BodyOptionalityClient): - client.required_explicit(BodyModel(name="foo")) - - -def test_required_implicit(client: BodyOptionalityClient): - client.required_implicit(name="foo") - - -def test_optional_explicit(client: BodyOptionalityClient): - client.optional_explicit.set(BodyModel(name="foo")) - client.optional_explicit.omit() diff --git a/packages/typespec-python/tests/mock_api/shared/test_parameters_collection_format.py b/packages/typespec-python/tests/mock_api/shared/test_parameters_collection_format.py deleted file mode 100644 index 283a7080f7..0000000000 --- a/packages/typespec-python/tests/mock_api/shared/test_parameters_collection_format.py +++ /dev/null @@ -1,33 +0,0 @@ -# ------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for -# license information. -# -------------------------------------------------------------------------- -import pytest -from parameters.collectionformat import CollectionFormatClient - - -@pytest.fixture -def client(): - with CollectionFormatClient() as client: - yield client - - -def test_query_multi(client: CollectionFormatClient): - client.query.multi(colors=["blue", "red", "green"]) - - -def test_query_csv(client: CollectionFormatClient): - client.query.csv(colors=["blue", "red", "green"]) - - -def test_query_pipes(client: CollectionFormatClient): - client.query.pipes(colors=["blue", "red", "green"]) - - -def test_query_ssv(client: CollectionFormatClient): - client.query.ssv(colors=["blue", "red", "green"]) - - -def test_csv_header(client: CollectionFormatClient): - client.header.csv(colors=["blue", "red", "green"]) diff --git a/packages/typespec-python/tests/mock_api/shared/test_parameters_path.py b/packages/typespec-python/tests/mock_api/shared/test_parameters_path.py deleted file mode 100644 index 71c6257e67..0000000000 --- a/packages/typespec-python/tests/mock_api/shared/test_parameters_path.py +++ /dev/null @@ -1,22 +0,0 @@ -# ------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for -# license information. -# -------------------------------------------------------------------------- -import pytest -from parameters.path import PathClient - - -@pytest.fixture -def client(): - with PathClient() as client: - yield client - - -def test_normal(client: PathClient): - client.normal("foo") - - -def test_optional(client: PathClient): - client.optional() - client.optional(name="foo") diff --git a/packages/typespec-python/tests/mock_api/shared/test_parameters_query.py b/packages/typespec-python/tests/mock_api/shared/test_parameters_query.py deleted file mode 100644 index 64f0e62c57..0000000000 --- a/packages/typespec-python/tests/mock_api/shared/test_parameters_query.py +++ /dev/null @@ -1,17 +0,0 @@ -# ------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for -# license information. -# -------------------------------------------------------------------------- -import pytest -from parameters.query import QueryClient - - -@pytest.fixture -def client(): - with QueryClient() as client: - yield client - - -def test_constant(client: QueryClient): - client.constant.post() diff --git a/packages/typespec-python/tests/mock_api/shared/test_patch.py b/packages/typespec-python/tests/mock_api/shared/test_patch.py deleted file mode 100644 index fc92290a71..0000000000 --- a/packages/typespec-python/tests/mock_api/shared/test_patch.py +++ /dev/null @@ -1,12 +0,0 @@ -# ------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for -# license information. -# -------------------------------------------------------------------------- - - -def test_patch_mixin_operation_group_in_operations_folder(key_credential): - from authentication.apikey import ApiKeyClient, aio - - assert hasattr(ApiKeyClient(key_credential), "patch_added_operation") - assert hasattr(aio.ApiKeyClient(key_credential), "patch_added_operation") diff --git a/packages/typespec-python/tests/mock_api/shared/test_payload_json_merge_patch.py b/packages/typespec-python/tests/mock_api/shared/test_payload_json_merge_patch.py deleted file mode 100644 index d4dcbedc03..0000000000 --- a/packages/typespec-python/tests/mock_api/shared/test_payload_json_merge_patch.py +++ /dev/null @@ -1,93 +0,0 @@ -# ------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for -# license information. -# -------------------------------------------------------------------------- -import pytest -from payload.jsonmergepatch import JsonMergePatchClient -from payload.jsonmergepatch.models import InnerModel, Resource, ResourcePatch - -try: - from azure.core.serialization import NULL -except ImportError: - from corehttp.serialization import NULL - - -@pytest.fixture -def client(): - with JsonMergePatchClient(endpoint="http://localhost:3000") as client: - yield client - - -def test_create_resource(client: JsonMergePatchClient): - inner_madge = InnerModel(name="InnerMadge", description="innerDesc") - create_resource = Resource( - name="Madge", - description="desc", - map={"key": inner_madge}, - array=[inner_madge], - int_value=1, - float_value=1.25, - inner_model=inner_madge, - int_array=[1, 2, 3], - ) - response = client.create_resource(create_resource) - assert response == create_resource - - -def test_update_resource_model_input(client: JsonMergePatchClient): - update_resource = ResourcePatch( - description=NULL, - map={"key": InnerModel(description=NULL), "key2": NULL}, - array=NULL, - int_value=NULL, - float_value=NULL, - inner_model=NULL, - int_array=NULL, - ) - response = client.update_resource(update_resource) - assert response == Resource(name="Madge", map={"key": InnerModel(name="InnerMadge")}) - - -def test_update_resource_raw_input(client: JsonMergePatchClient): - response = client.update_resource( - { - "description": None, - "map": {"key": {"description": None}, "key2": None}, - "array": None, - "intValue": None, - "floatValue": None, - "innerModel": None, - "intArray": None, - } - ) - assert response == Resource(name="Madge", map={"key": InnerModel(name="InnerMadge")}) - - -def test_update_optional_resource_model_input(client: JsonMergePatchClient): - update_resource = ResourcePatch( - description=NULL, - map={"key": InnerModel(description=NULL), "key2": NULL}, - array=NULL, - int_value=NULL, - float_value=NULL, - inner_model=NULL, - int_array=NULL, - ) - response = client.update_optional_resource(update_resource) - assert response == Resource(name="Madge", map={"key": InnerModel(name="InnerMadge")}) - - -def test_update_optional_resource_raw_input(client: JsonMergePatchClient): - response = client.update_optional_resource( - { - "description": None, - "map": {"key": {"description": None}, "key2": None}, - "array": None, - "intValue": None, - "floatValue": None, - "innerModel": None, - "intArray": None, - } - ) - assert response == Resource(name="Madge", map={"key": InnerModel(name="InnerMadge")}) diff --git a/packages/typespec-python/tests/mock_api/shared/test_payload_media_type.py b/packages/typespec-python/tests/mock_api/shared/test_payload_media_type.py deleted file mode 100644 index 72bc9425fc..0000000000 --- a/packages/typespec-python/tests/mock_api/shared/test_payload_media_type.py +++ /dev/null @@ -1,25 +0,0 @@ -# ------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for -# license information. -# -------------------------------------------------------------------------- -import pytest -from payload.mediatype import MediaTypeClient - - -@pytest.fixture -def client(): - with MediaTypeClient(endpoint="http://localhost:3000") as client: - yield client - - -def test_json(client: MediaTypeClient): - data = "foo" - client.string_body.send_as_json(data) - assert client.string_body.get_as_json() == data - - -def test_text(client: MediaTypeClient): - data = "{cat}" - client.string_body.send_as_text(data) - assert client.string_body.get_as_text() == data diff --git a/packages/typespec-python/tests/mock_api/shared/test_payload_pageable.py b/packages/typespec-python/tests/mock_api/shared/test_payload_pageable.py deleted file mode 100644 index 7aaf8e0ce3..0000000000 --- a/packages/typespec-python/tests/mock_api/shared/test_payload_pageable.py +++ /dev/null @@ -1,99 +0,0 @@ -# ------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for -# license information. -# -------------------------------------------------------------------------- -import pytest -from payload.pageable import PageableClient -from payload.pageable.serverdrivenpagination.alternateinitialverb.models import Filter - - -@pytest.fixture -def client(): - with PageableClient(endpoint="http://localhost:3000") as client: - yield client - - -def assert_result(result): - assert len(result) == 4 - assert result[0].id == "1" - assert result[1].id == "2" - assert result[2].id == "3" - assert result[3].id == "4" - assert result[0].name == "dog" - assert result[1].name == "cat" - assert result[2].name == "bird" - assert result[3].name == "fish" - - -def test_link(client: PageableClient): - result = list(client.server_driven_pagination.link()) - assert_result(result) - - -def test_link_string(client: PageableClient): - result = list(client.server_driven_pagination.link_string()) - assert_result(result) - - -def test_request_query_response_body(client: PageableClient): - result = list(client.server_driven_pagination.continuation_token.request_query_response_body(foo="foo", bar="bar")) - assert_result(result) - - -def test_request_header_response_body(client: PageableClient): - result = list(client.server_driven_pagination.continuation_token.request_header_response_body(foo="foo", bar="bar")) - assert_result(result) - - -def test_request_query_response_header(client: PageableClient): - result = list( - client.server_driven_pagination.continuation_token.request_query_response_header(foo="foo", bar="bar") - ) - assert_result(result) - - -def test_request_header_response_header(client: PageableClient): - result = list( - client.server_driven_pagination.continuation_token.request_header_response_header(foo="foo", bar="bar") - ) - assert_result(result) - - -def test_nested_link(client: PageableClient): - result = list(client.server_driven_pagination.nested_link()) - assert_result(result) - - -def test_request_query_nested_response_body(client: PageableClient): - result = list( - client.server_driven_pagination.continuation_token.request_query_nested_response_body(foo="foo", bar="bar") - ) - assert_result(result) - - -def test_request_header_nested_response_body(client: PageableClient): - result = list( - client.server_driven_pagination.continuation_token.request_header_nested_response_body(foo="foo", bar="bar") - ) - assert_result(result) - - -def test_list_without_continuation(client: PageableClient): - result = list(client.page_size.list_without_continuation()) - assert_result(result) - - -def test_xml_pagination_list_with_continuation(client: PageableClient): - result = list(client.xml_pagination.list_with_continuation()) - assert_result(result) - - -def test_xml_pagination_list_with_next_link(client: PageableClient): - result = list(client.xml_pagination.list_with_next_link()) - assert_result(result) - - -def test_alternate_initial_verb_post(client: PageableClient): - result = list(client.server_driven_pagination.alternate_initial_verb.post(Filter(filter="foo eq bar"))) - assert_result(result) diff --git a/packages/typespec-python/tests/mock_api/shared/test_payload_xml.py b/packages/typespec-python/tests/mock_api/shared/test_payload_xml.py deleted file mode 100644 index e301ff0a1e..0000000000 --- a/packages/typespec-python/tests/mock_api/shared/test_payload_xml.py +++ /dev/null @@ -1,234 +0,0 @@ -# ------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for -# license information. -# -------------------------------------------------------------------------- -import datetime -import pytest -from payload.xml import XmlClient -from payload.xml.models import ( - Author, - Book, - SimpleModel, - ModelWithSimpleArrays, - ModelWithArrayOfModel, - ModelWithAttributes, - ModelWithUnwrappedArray, - ModelWithUnwrappedModelArray, - ModelWithRenamedArrays, - ModelWithRenamedProperty, - ModelWithRenamedAttribute, - ModelWithRenamedNestedModel, - ModelWithRenamedWrappedModelArray, - ModelWithRenamedUnwrappedModelArray, - ModelWithRenamedWrappedAndItemModelArray, - ModelWithOptionalField, - ModelWithRenamedFields, - ModelWithEmptyArray, - ModelWithText, - ModelWithDictionary, - ModelWithEncodedNames, - ModelWithEnum, - ModelWithDatetime, - ModelWithNamespace, - ModelWithNamespaceOnProperties, - ModelWithNestedModel, - ModelWithWrappedPrimitiveCustomItemNames, -) - - -@pytest.fixture -def client(): - with XmlClient(endpoint="http://localhost:3000") as client: - yield client - - -def test_simple_model(client: XmlClient): - model = SimpleModel(name="foo", age=123) - assert client.simple_model_value.get() == model - client.simple_model_value.put(model) - - -def test_model_with_renamed_property(client: XmlClient): - model = ModelWithRenamedProperty(title="foo", author="bar") - assert client.model_with_renamed_property_value.get() == model - client.model_with_renamed_property_value.put(model) - - -def test_model_with_simple_arrays(client: XmlClient): - model = ModelWithSimpleArrays(colors=["red", "green", "blue"], counts=[1, 2]) - assert client.model_with_simple_arrays_value.get() == model - client.model_with_simple_arrays_value.put(model) - - -def test_model_with_wrapped_primitive_custom_item_names(client: XmlClient): - model = ModelWithWrappedPrimitiveCustomItemNames(tags=["fiction", "classic"]) - assert client.model_with_wrapped_primitive_custom_item_names_value.get() == model - client.model_with_wrapped_primitive_custom_item_names_value.put(model) - - -def test_model_with_array_of_model(client: XmlClient): - model = ModelWithArrayOfModel( - items_property=[ - SimpleModel(name="foo", age=123), - SimpleModel(name="bar", age=456), - ] - ) - assert client.model_with_array_of_model_value.get() == model - client.model_with_array_of_model_value.put(model) - - -def test_model_with_unwrapped_model_array(client: XmlClient): - model = ModelWithUnwrappedModelArray( - items_property=[ - SimpleModel(name="foo", age=123), - SimpleModel(name="bar", age=456), - ] - ) - assert client.model_with_unwrapped_model_array_value.get() == model - client.model_with_unwrapped_model_array_value.put(model) - - -def test_model_with_renamed_wrapped_model_array(client: XmlClient): - model = ModelWithRenamedWrappedModelArray( - items_property=[ - SimpleModel(name="foo", age=123), - SimpleModel(name="bar", age=456), - ] - ) - assert client.model_with_renamed_wrapped_model_array_value.get() == model - client.model_with_renamed_wrapped_model_array_value.put(model) - - -def test_model_with_renamed_unwrapped_model_array(client: XmlClient): - model = ModelWithRenamedUnwrappedModelArray( - items_property=[ - SimpleModel(name="foo", age=123), - SimpleModel(name="bar", age=456), - ] - ) - assert client.model_with_renamed_unwrapped_model_array_value.get() == model - client.model_with_renamed_unwrapped_model_array_value.put(model) - - -def test_model_with_renamed_wrapped_and_item_model_array(client: XmlClient): - model = ModelWithRenamedWrappedAndItemModelArray( - books=[ - Book(title="The Great Gatsby"), - Book(title="Les Miserables"), - ] - ) - assert client.model_with_renamed_wrapped_and_item_model_array_value.get() == model - client.model_with_renamed_wrapped_and_item_model_array_value.put(model) - - -def test_model_with_attributes(client: XmlClient): - model = ModelWithAttributes(id1=123, id2="foo", enabled=True) - assert client.model_with_attributes_value.get() == model - client.model_with_attributes_value.put(model) - - -def test_model_with_renamed_attribute(client: XmlClient): - model = ModelWithRenamedAttribute(id=123, title="The Great Gatsby", author="F. Scott Fitzgerald") - assert client.model_with_renamed_attribute_value.get() == model - client.model_with_renamed_attribute_value.put(model) - - -def test_model_with_unwrapped_array(client: XmlClient): - model = ModelWithUnwrappedArray(colors=["red", "green", "blue"], counts=[1, 2]) - assert client.model_with_unwrapped_array_value.get() == model - client.model_with_unwrapped_array_value.put(model) - - -def test_model_with_renamed_arrays(client: XmlClient): - model = ModelWithRenamedArrays(colors=["red", "green", "blue"], counts=[1, 2]) - assert client.model_with_renamed_arrays_value.get() == model - client.model_with_renamed_arrays_value.put(model) - - -def test_model_with_optional_field(client: XmlClient): - model = ModelWithOptionalField(item="widget") - assert client.model_with_optional_field_value.get() == model - client.model_with_optional_field_value.put(model) - - -def test_model_with_nested_model(client: XmlClient): - model = ModelWithNestedModel(nested=SimpleModel(name="foo", age=123)) - assert client.model_with_nested_model_value.get() == model - client.model_with_nested_model_value.put(model) - - -def test_model_with_renamed_nested_model(client: XmlClient): - model = ModelWithRenamedNestedModel(author=Author(name="foo")) - assert client.model_with_renamed_nested_model_value.get() == model - client.model_with_renamed_nested_model_value.put(model) - - -def test_model_with_renamed_fields(client: XmlClient): - model = ModelWithRenamedFields( - input_data=SimpleModel(name="foo", age=123), - output_data=SimpleModel(name="bar", age=456), - ) - assert client.model_with_renamed_fields_value.get() == model - client.model_with_renamed_fields_value.put(model) - - -def test_model_with_empty_array(client: XmlClient): - model = ModelWithEmptyArray(items_property=[]) - assert client.model_with_empty_array_value.get() == model - client.model_with_empty_array_value.put(model) - - -def test_model_with_text(client: XmlClient): - model = ModelWithText(language="foo", content="\n This is some text.\n") - assert client.model_with_text_value.get() == model - client.model_with_text_value.put(model) - - -def test_model_with_dictionary(client: XmlClient): - model = ModelWithDictionary(metadata={"Color": "blue", "Count": "123", "Enabled": "false"}) - assert client.model_with_dictionary_value.get() == model - client.model_with_dictionary_value.put(model) - - -def test_model_with_encoded_names(client: XmlClient): - model = ModelWithEncodedNames(model_data=SimpleModel(name="foo", age=123), colors=["red", "green", "blue"]) - assert client.model_with_encoded_names_value.get() == model - client.model_with_encoded_names_value.put(model) - - -def test_model_with_enum(client: XmlClient): - model = ModelWithEnum(status="success") - assert client.model_with_enum_value.get() == model - client.model_with_enum_value.put(model) - - -def test_model_with_datetime(client: XmlClient): - model = ModelWithDatetime( - rfc3339=datetime.datetime(2022, 8, 26, 18, 38, 0, tzinfo=datetime.timezone.utc), - rfc7231=datetime.datetime(2022, 8, 26, 14, 38, 0, tzinfo=datetime.timezone.utc), - ) - result = client.model_with_datetime_value.get() - assert result.rfc3339 == model.rfc3339 - assert result.rfc7231 == model.rfc7231 - client.model_with_datetime_value.put(model) - - -def test_model_with_namespace(client: XmlClient): - model = ModelWithNamespace(id=123, title="The Great Gatsby") - assert client.model_with_namespace_value.get() == model - client.model_with_namespace_value.put(model) - - -def test_model_with_namespace_on_properties(client: XmlClient): - model = ModelWithNamespaceOnProperties(id=123, title="The Great Gatsby", author="F. Scott Fitzgerald") - assert client.model_with_namespace_on_properties_value.get() == model - client.model_with_namespace_on_properties_value.put(model) - - -def test_xml_error_value(client: XmlClient, core_library): - with pytest.raises(core_library.exceptions.HttpResponseError) as ex: - client.xml_error_value.get() - assert ex.value.status_code == 400 - assert ex.value.model.message == "Something went wrong" - assert ex.value.model.code == 400 diff --git a/packages/typespec-python/tests/mock_api/shared/test_response_status_code_range.py b/packages/typespec-python/tests/mock_api/shared/test_response_status_code_range.py deleted file mode 100644 index 247e095472..0000000000 --- a/packages/typespec-python/tests/mock_api/shared/test_response_status_code_range.py +++ /dev/null @@ -1,36 +0,0 @@ -# ------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for -# license information. -# -------------------------------------------------------------------------- -import pytest -from response.statuscoderange import StatusCodeRangeClient -from response.statuscoderange.models import ErrorInRange, NotFoundError - - -@pytest.fixture -def client(): - with StatusCodeRangeClient(endpoint="http://localhost:3000") as client: - yield client - - -def test_error_response_status_code_in_range(client: StatusCodeRangeClient): - with pytest.raises(Exception) as exc_info: - client.error_response_status_code_in_range() - - error = exc_info.value.model - assert isinstance(error, ErrorInRange) - assert error.code == "request-header-too-large" - assert error.message == "Request header too large" - assert exc_info.value.response.status_code == 494 - - -def test_error_response_status_code_404(client: StatusCodeRangeClient): - with pytest.raises(Exception) as exc_info: - client.error_response_status_code404() - - error = exc_info.value.model - assert isinstance(error, NotFoundError) - assert error.code == "not-found" - assert error.resource_id == "resource1" - assert exc_info.value.response.status_code == 404 diff --git a/packages/typespec-python/tests/mock_api/shared/test_routes.py b/packages/typespec-python/tests/mock_api/shared/test_routes.py deleted file mode 100644 index e1058d0665..0000000000 --- a/packages/typespec-python/tests/mock_api/shared/test_routes.py +++ /dev/null @@ -1,285 +0,0 @@ -# ------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for -# license information. -# -------------------------------------------------------------------------- -import pytest -from routes import RoutesClient - - -@pytest.fixture -def client(): - with RoutesClient() as client: - yield client - - -def test_fixed(client: RoutesClient): - client.fixed() - - -def test_in_interface_fixed(client: RoutesClient): - client.in_interface.fixed() - - -def test_path_parameters_template_only(client: RoutesClient): - client.path_parameters.template_only( - param="a", - ) - - -def test_path_parameters_explicit(client: RoutesClient): - client.path_parameters.explicit( - param="a", - ) - - -def test_path_parameters_annotation_only(client: RoutesClient): - client.path_parameters.annotation_only( - param="a", - ) - - -def test_path_parameters_reserved_expansion_template(client: RoutesClient): - client.path_parameters.reserved_expansion.template( - param="foo/bar baz", - ) - - -def test_path_parameters_reserved_expansion_annotation(client: RoutesClient): - client.path_parameters.reserved_expansion.annotation( - param="foo/bar baz", - ) - - -# def test_path_parameters_simple_expansion_standard_primitive(client: RoutesClient): -# client.path_parameters.simple_expansion.standard.primitive( -# param="a", -# ) - - -# def test_path_parameters_simple_expansion_standard_array(client: RoutesClient): -# client.path_parameters.simple_expansion.standard.array( -# param=["a", "b"], -# ) - - -# def test_path_parameters_simple_expansion_standard_record(client: RoutesClient): -# client.path_parameters.simple_expansion.standard.record( -# param={"a": 1, "b": 2}, -# ) - - -# def test_path_parameters_simple_expansion_explode_primitive(client: RoutesClient): -# client.path_parameters.simple_expansion.explode.primitive( -# param="a", -# ) - - -# def test_path_parameters_simple_expansion_explode_array(client: RoutesClient): -# client.path_parameters.simple_expansion.explode.array( -# param=["a", "b"], -# ) - - -# def test_path_parameters_simple_expansion_explode_record(client: RoutesClient): -# client.path_parameters.simple_expansion.explode.record( -# param={"a": 1, "b": 2}, -# ) - - -# def test_path_parameters_path_expansion_standard_primitive(client: RoutesClient): -# client.path_parameters.path_expansion.standard.primitive( -# param="a", -# ) - - -# def test_path_parameters_path_expansion_standard_array(client: RoutesClient): -# client.path_parameters.path_expansion.standard.array( -# param=["a", "b"], -# ) - - -# def test_path_parameters_path_expansion_standard_record(client: RoutesClient): -# client.path_parameters.path_expansion.standard.record( -# param={"a": 1, "b": 2}, -# ) - - -# def test_path_parameters_path_expansion_explode_primitive(client: RoutesClient): -# client.path_parameters.path_expansion.explode.primitive( -# param="a", -# ) - - -# def test_path_parameters_path_expansion_explode_array(client: RoutesClient): -# client.path_parameters.path_expansion.explode.array( -# param=["a", "b"], -# ) - - -# def test_path_parameters_path_expansion_explode_record(client: RoutesClient): -# client.path_parameters.path_expansion.explode.record( -# param={"a": 1, "b": 2}, -# ) - - -# def test_path_parameters_label_expansion_standard_primitive(client: RoutesClient): -# client.path_parameters.label_expansion.standard.primitive( -# param="a", -# ) - - -# def test_path_parameters_label_expansion_standard_array(client: RoutesClient): -# client.path_parameters.label_expansion.standard.array( -# param=["a", "b"], -# ) - - -# def test_path_parameters_label_expansion_standard_record(client: RoutesClient): -# client.path_parameters.label_expansion.standard.record( -# param={"a": 1, "b": 2}, -# ) - - -# def test_path_parameters_label_expansion_explode_primitive(client: RoutesClient): -# client.path_parameters.label_expansion.explode.primitive( -# param="a", -# ) - - -# def test_path_parameters_label_expansion_explode_array(client: RoutesClient): -# client.path_parameters.label_expansion.explode.array( -# param=["a", "b"], -# ) - - -# def test_path_parameters_label_expansion_explode_record(client: RoutesClient): -# client.path_parameters.label_expansion.explode.record( -# param={"a": 1, "b": 2}, -# ) - - -# def test_path_parameters_matrix_expansion_standard_primitive(client: RoutesClient): -# client.path_parameters.matrix_expansion.standard.primitive( -# param="a", -# ) - - -# def test_path_parameters_matrix_expansion_standard_array(client: RoutesClient): -# client.path_parameters.matrix_expansion.standard.array( -# param=["a", "b"], -# ) - - -# def test_path_parameters_matrix_expansion_standard_record(client: RoutesClient): -# client.path_parameters.matrix_expansion.standard.record( -# param={"a": 1, "b": 2}, -# ) - - -# def test_path_parameters_matrix_expansion_explode_primitive(client: RoutesClient): -# client.path_parameters.matrix_expansion.explode.primitive( -# param="a", -# ) - - -# def test_path_parameters_matrix_expansion_explode_array(client: RoutesClient): -# client.path_parameters.matrix_expansion.explode.array( -# param=["a", "b"], -# ) - - -# def test_path_parameters_matrix_expansion_explode_record(client: RoutesClient): -# client.path_parameters.matrix_expansion.explode.record( -# param={"a": 1, "b": 2}, -# ) - - -def test_query_parameters_template_only(client: RoutesClient): - client.query_parameters.template_only( - param="a", - ) - - -def test_query_parameters_explicit(client: RoutesClient): - client.query_parameters.explicit( - param="a", - ) - - -def test_query_parameters_annotation_only(client: RoutesClient): - client.query_parameters.annotation_only( - param="a", - ) - - -def test_query_parameters_query_expansion_standard_primitive(client: RoutesClient): - client.query_parameters.query_expansion.standard.primitive( - param="a", - ) - - -# def test_query_parameters_query_expansion_standard_array(client: RoutesClient): -# client.query_parameters.query_expansion.standard.array( -# param=["a", "b"], -# ) - - -# def test_query_parameters_query_expansion_standard_record(client: RoutesClient): -# client.query_parameters.query_expansion.standard.record( -# param={"a": 1, "b": 2}, -# ) - - -def test_query_parameters_query_expansion_explode_primitive(client: RoutesClient): - client.query_parameters.query_expansion.explode.primitive( - param="a", - ) - - -# def test_query_parameters_query_expansion_explode_array(client: RoutesClient): -# client.query_parameters.query_expansion.explode.array( -# param=["a", "b"], -# ) - - -# def test_query_parameters_query_expansion_explode_record(client: RoutesClient): -# client.query_parameters.query_expansion.explode.record( -# param={"a": 1, "b": 2}, -# ) - - -def test_query_parameters_query_continuation_standard_primitive(client: RoutesClient): - client.query_parameters.query_continuation.standard.primitive( - param="a", - ) - - -# def test_query_parameters_query_continuation_standard_array(client: RoutesClient): -# client.query_parameters.query_continuation.standard.array( -# param=["a", "b"], -# ) - - -# def test_query_parameters_query_continuation_standard_record(client: RoutesClient): -# client.query_parameters.query_continuation.standard.record( -# param={"a": 1, "b": 2}, -# ) - - -def test_query_parameters_query_continuation_explode_primitive(client: RoutesClient): - client.query_parameters.query_continuation.explode.primitive( - param="a", - ) - - -# def test_query_parameters_query_continuation_explode_array(client: RoutesClient): -# client.query_parameters.query_continuation.explode.array( -# param=["a", "b"], -# ) - - -# def test_query_parameters_query_continuation_explode_record(client: RoutesClient): -# client.query_parameters.query_continuation.explode.record( -# param={"a": 1, "b": 2}, -# ) diff --git a/packages/typespec-python/tests/mock_api/shared/test_server_endpoint_not_defined.py b/packages/typespec-python/tests/mock_api/shared/test_server_endpoint_not_defined.py deleted file mode 100644 index 432542dd95..0000000000 --- a/packages/typespec-python/tests/mock_api/shared/test_server_endpoint_not_defined.py +++ /dev/null @@ -1,17 +0,0 @@ -# ------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for -# license information. -# -------------------------------------------------------------------------- -import pytest -from server.endpoint.notdefined import NotDefinedClient - - -@pytest.fixture -def client(): - with NotDefinedClient(endpoint="http://localhost:3000") as client: - yield client - - -def test_valid(client: NotDefinedClient): - assert client.valid() is True diff --git a/packages/typespec-python/tests/mock_api/shared/test_server_path_multiple.py b/packages/typespec-python/tests/mock_api/shared/test_server_path_multiple.py deleted file mode 100644 index 2a697f142f..0000000000 --- a/packages/typespec-python/tests/mock_api/shared/test_server_path_multiple.py +++ /dev/null @@ -1,21 +0,0 @@ -# ------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for -# license information. -# -------------------------------------------------------------------------- -import pytest -from server.path.multiple import MultipleClient - - -@pytest.fixture -def client(): - with MultipleClient(endpoint="http://localhost:3000") as client: - yield client - - -def test_no_operation_params(client: MultipleClient): - client.no_operation_params() - - -def test_with_operation_path_param(client: MultipleClient): - client.with_operation_path_param(keyword="test") diff --git a/packages/typespec-python/tests/mock_api/shared/test_server_path_single.py b/packages/typespec-python/tests/mock_api/shared/test_server_path_single.py deleted file mode 100644 index 0ef66c1d0b..0000000000 --- a/packages/typespec-python/tests/mock_api/shared/test_server_path_single.py +++ /dev/null @@ -1,17 +0,0 @@ -# ------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for -# license information. -# -------------------------------------------------------------------------- -import pytest -from server.path.single import SingleClient - - -@pytest.fixture -def client(): - with SingleClient(endpoint="http://localhost:3000") as client: - yield client - - -def test_my_op(client): - assert client.my_op() is True diff --git a/packages/typespec-python/tests/mock_api/shared/test_server_versions_not_versioned.py b/packages/typespec-python/tests/mock_api/shared/test_server_versions_not_versioned.py deleted file mode 100644 index 9d68cd9d48..0000000000 --- a/packages/typespec-python/tests/mock_api/shared/test_server_versions_not_versioned.py +++ /dev/null @@ -1,25 +0,0 @@ -# ------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for -# license information. -# -------------------------------------------------------------------------- -import pytest -from server.versions.notversioned import NotVersionedClient - - -@pytest.fixture -def client(): - with NotVersionedClient(endpoint="http://localhost:3000") as client: - yield client - - -def test_without_api_version(client: NotVersionedClient): - client.without_api_version() - - -def test_with_query_api_version(client: NotVersionedClient): - client.with_query_api_version(api_version="v1.0") - - -def test_with_path_api_version(client: NotVersionedClient): - client.with_path_api_version(api_version="v1.0") diff --git a/packages/typespec-python/tests/mock_api/shared/test_server_versions_versioned.py b/packages/typespec-python/tests/mock_api/shared/test_server_versions_versioned.py deleted file mode 100644 index 00b7fcd192..0000000000 --- a/packages/typespec-python/tests/mock_api/shared/test_server_versions_versioned.py +++ /dev/null @@ -1,30 +0,0 @@ -# ------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for -# license information. -# -------------------------------------------------------------------------- -import pytest -from server.versions.versioned import VersionedClient - - -@pytest.fixture -def client(): - with VersionedClient(endpoint="http://localhost:3000") as client: - yield client - - -def test_without_api_version(client: VersionedClient): - client.without_api_version() - - -def test_with_query_api_version(client: VersionedClient): - client.with_query_api_version() - - -def test_with_path_api_version(client: VersionedClient): - client.with_path_api_version() - - -def test_with_query_old_api_version(): - with VersionedClient(endpoint="http://localhost:3000", api_version="2021-01-01-preview") as client: - client.with_query_old_api_version() diff --git a/packages/typespec-python/tests/mock_api/shared/test_special_headers_conditional_request.py b/packages/typespec-python/tests/mock_api/shared/test_special_headers_conditional_request.py deleted file mode 100644 index f476a1db9d..0000000000 --- a/packages/typespec-python/tests/mock_api/shared/test_special_headers_conditional_request.py +++ /dev/null @@ -1,34 +0,0 @@ -# ------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for -# license information. -# -------------------------------------------------------------------------- -import pytest -import datetime -from specialheaders.conditionalrequest import ConditionalRequestClient - - -@pytest.fixture -def client(): - with ConditionalRequestClient() as client: - yield client - - -def test_post_if_match(core_library, client: ConditionalRequestClient): - client.post_if_match(etag="valid", match_condition=core_library.MatchConditions.IfNotModified) - - -def test_post_if_none_match(core_library, client: ConditionalRequestClient): - client.post_if_none_match(etag="invalid", match_condition=core_library.MatchConditions.IfModified) - - -def test_head_if_modified_since(client: ConditionalRequestClient): - client.head_if_modified_since( - if_modified_since=datetime.datetime(2022, 8, 26, 14, 38, 0, tzinfo=datetime.timezone.utc) - ) - - -def test_post_if_unmodified_since(client: ConditionalRequestClient): - client.post_if_unmodified_since( - if_unmodified_since=datetime.datetime(2022, 8, 26, 14, 38, 0, tzinfo=datetime.timezone.utc) - ) diff --git a/packages/typespec-python/tests/mock_api/shared/test_special_headers_repeatability.py b/packages/typespec-python/tests/mock_api/shared/test_special_headers_repeatability.py deleted file mode 100644 index b35c8a1f16..0000000000 --- a/packages/typespec-python/tests/mock_api/shared/test_special_headers_repeatability.py +++ /dev/null @@ -1,18 +0,0 @@ -# ------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for -# license information. -# -------------------------------------------------------------------------- -import pytest -from specialheaders.repeatability import RepeatabilityClient - - -@pytest.fixture -def client(): - with RepeatabilityClient() as client: - yield client - - -def test_immediate_success(client: RepeatabilityClient): - cls = lambda x, y, z: z - assert client.immediate_success(cls=cls)["Repeatability-Result"] == "accepted" diff --git a/packages/typespec-python/tests/mock_api/shared/test_specs_documentation.py b/packages/typespec-python/tests/mock_api/shared/test_specs_documentation.py deleted file mode 100644 index 2f956dd75f..0000000000 --- a/packages/typespec-python/tests/mock_api/shared/test_specs_documentation.py +++ /dev/null @@ -1,51 +0,0 @@ -# ------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for -# license information. -# -------------------------------------------------------------------------- - -import pytest -from specs.documentation import DocumentationClient, models - - -@pytest.fixture -def client(): - with DocumentationClient(endpoint="http://localhost:3000") as client: - yield client - - -class TestLists: - def test_bullet_points_op(self, client: DocumentationClient): - # GET /documentation/lists/bullet-points/op - # Expected: 204 No Content - client.lists.bullet_points_op() - - def test_bullet_points_model(self, client: DocumentationClient): - # POST /documentation/lists/bullet-points/model - # Expected: 200 OK - client.lists.bullet_points_model(input=models.BulletPointsModel(prop="Simple")) - - # Also test with JSON - client.lists.bullet_points_model(body={"input": {"prop": "Simple"}}) - - def test_numbered(self, client: DocumentationClient): - # GET /documentation/lists/numbered - # Expected: 204 No Content - client.lists.numbered() - - -class TestTextFormatting: - def test_bold_text(self, client: DocumentationClient): - # GET /documentation/text-formatting/bold - # Expected: 204 No Content - client.text_formatting.bold_text() - - def test_italic_text(self, client: DocumentationClient): - # GET /documentation/text-formatting/italic - # Expected: 204 No Content - client.text_formatting.italic_text() - - def test_combined_formatting(self, client: DocumentationClient): - # GET /documentation/text-formatting/combined - # Expected: 204 No Content - client.text_formatting.combined_formatting() diff --git a/packages/typespec-python/tests/mock_api/shared/test_streaming_jsonl.py b/packages/typespec-python/tests/mock_api/shared/test_streaming_jsonl.py deleted file mode 100644 index 494c17a349..0000000000 --- a/packages/typespec-python/tests/mock_api/shared/test_streaming_jsonl.py +++ /dev/null @@ -1,25 +0,0 @@ -# ------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for -# license information. -# -------------------------------------------------------------------------- -import pytest - -from streaming.jsonl import JsonlClient - - -@pytest.fixture -def client(): - with JsonlClient(endpoint="http://localhost:3000") as client: - yield client - - -JSONL = b'{"desc": "one"}\n{"desc": "two"}\n{"desc": "three"}' - - -def test_basic_send(client: JsonlClient): - client.basic.send(JSONL) - - -def test_basic_recv(client: JsonlClient): - assert b"".join(client.basic.receive()) == JSONL diff --git a/packages/typespec-python/tests/mock_api/shared/test_typetest_array.py b/packages/typespec-python/tests/mock_api/shared/test_typetest_array.py deleted file mode 100644 index 0c3c0f3f06..0000000000 --- a/packages/typespec-python/tests/mock_api/shared/test_typetest_array.py +++ /dev/null @@ -1,111 +0,0 @@ -# ------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for -# license information. -# -------------------------------------------------------------------------- - -import pytest -import isodate -from typetest.array import ArrayClient, models - - -@pytest.fixture -def client(): - with ArrayClient() as client: - yield client - - -def test_boolean_value(client: ArrayClient): - assert client.boolean_value.get() == [True, False] - client.boolean_value.put([True, False]) - - -def test_datetime_value(client: ArrayClient): - assert client.datetime_value.get() == [isodate.parse_datetime("2022-08-26T18:38:00Z")] - client.datetime_value.put([isodate.parse_datetime("2022-08-26T18:38:00Z")]) - - -def test_duration_value(client: ArrayClient): - assert client.duration_value.get() == [isodate.parse_duration("P123DT22H14M12.011S")] - client.duration_value.put([isodate.parse_duration("P123DT22H14M12.011S")]) - - -def test_float32_value(client: ArrayClient): - assert client.float32_value.get() == [43.125] - client.float32_value.put([43.125]) - - -def test_int32_value(client: ArrayClient): - assert client.int32_value.get() == [1, 2] - client.int32_value.put([1, 2]) - - -def test_int64_value(client: ArrayClient): - assert client.int64_value.get() == [2**53 - 1, -(2**53 - 1)] - client.int64_value.put([2**53 - 1, -(2**53 - 1)]) - - -def test_model_value(client: ArrayClient): - assert client.model_value.get() == [ - models.InnerModel(property="hello"), - models.InnerModel(property="world"), - ] - # test list[model] - client.model_value.put( - [ - models.InnerModel(property="hello"), - models.InnerModel(property="world"), - ] - ) - # test list[JSON] - client.model_value.put( - [ - {"property": "hello"}, - {"property": "world"}, - ] - ) - - -def test_nullable_boolean_value(client: ArrayClient): - assert client.nullable_boolean_value.get() == [True, None, False] - client.nullable_boolean_value.put([True, None, False]) - - -def test_nullable_float_value(client: ArrayClient): - assert client.nullable_float_value.get() == [1.25, None, 3.0] - client.nullable_float_value.put([1.25, None, 3.0]) - - -def test_nullable_int32_value(client: ArrayClient): - assert client.nullable_int32_value.get() == [1, None, 3] - client.nullable_int32_value.put([1, None, 3]) - - -def test_nullable_model_value(client: ArrayClient): - assert client.nullable_model_value.get() == [ - models.InnerModel(property="hello"), - None, - models.InnerModel(property="world"), - ] - client.nullable_model_value.put( - [ - models.InnerModel(property="hello"), - None, - models.InnerModel(property="world"), - ] - ) - - -def test_nullable_string_value(client: ArrayClient): - assert client.nullable_string_value.get() == ["hello", None, "world"] - client.nullable_string_value.put(["hello", None, "world"]) - - -def test_string_value(client: ArrayClient): - assert client.string_value.get() == ["hello", ""] - client.string_value.put(["hello", ""]) - - -def test_unknown_value(client: ArrayClient): - assert client.unknown_value.get() == [1, "hello", None] - client.unknown_value.put([1, "hello", None]) diff --git a/packages/typespec-python/tests/mock_api/shared/test_typetest_dictionary.py b/packages/typespec-python/tests/mock_api/shared/test_typetest_dictionary.py deleted file mode 100644 index 98fb416547..0000000000 --- a/packages/typespec-python/tests/mock_api/shared/test_typetest_dictionary.py +++ /dev/null @@ -1,86 +0,0 @@ -# ------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for -# license information. -# -------------------------------------------------------------------------- -import pytest -from typetest.dictionary import DictionaryClient, models -import isodate - - -@pytest.fixture -def client(): - with DictionaryClient() as client: - yield client - - -def test_boolean_value(client: DictionaryClient): - value = {"k1": True, "k2": False} - assert client.boolean_value.get() == value - client.boolean_value.put(value) - - -def test_datetime_value(client: DictionaryClient): - value = {"k1": isodate.parse_datetime("2022-08-26T18:38:00Z")} - assert client.datetime_value.get() == value - client.datetime_value.put(value) - - -def test_duration_value(client: DictionaryClient): - value = {"k1": isodate.parse_duration("P123DT22H14M12.011S")} - assert client.duration_value.get() == value - client.duration_value.put(value) - - -def test_float32_value(client: DictionaryClient): - value = {"k1": 43.125} - assert client.float32_value.get() == value - client.float32_value.put(value) - - -def test_int32_value(client: DictionaryClient): - value = {"k1": 1, "k2": 2} - assert client.int32_value.get() == value - client.int32_value.put(value) - - -def test_int64_value(client: DictionaryClient): - value = {"k1": 2**53 - 1, "k2": -(2**53 - 1)} - assert client.int64_value.get() == value - client.int64_value.put(value) - - -def test_model_value(client: DictionaryClient): - value = { - "k1": models.InnerModel(property="hello"), - "k2": models.InnerModel(property="world"), - } - assert client.model_value.get() == value - client.model_value.put(value) - - -def test_nullable_float_value(client: DictionaryClient): - value = {"k1": 1.25, "k2": 0.5, "k3": None} - assert client.nullable_float_value.get() == value - client.nullable_float_value.put(value) - - -def test_recursive_model_value(client: DictionaryClient): - value = { - "k1": models.InnerModel(property="hello", children={}), - "k2": models.InnerModel(property="world", children={"k2.1": models.InnerModel(property="inner world")}), - } - assert client.recursive_model_value.get() == value - client.recursive_model_value.put(value) - - -def test_string_value(client: DictionaryClient): - value = {"k1": "hello", "k2": ""} - assert client.string_value.get() == value - client.string_value.put(value) - - -def test_unknown_value(client: DictionaryClient): - value = {"k1": 1, "k2": "hello", "k3": None} - assert client.unknown_value.get() == value - client.unknown_value.put(value) diff --git a/packages/typespec-python/tests/mock_api/shared/test_typetest_enum_extensible.py b/packages/typespec-python/tests/mock_api/shared/test_typetest_enum_extensible.py deleted file mode 100644 index b6bcf593e6..0000000000 --- a/packages/typespec-python/tests/mock_api/shared/test_typetest_enum_extensible.py +++ /dev/null @@ -1,23 +0,0 @@ -# ------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for -# license information. -# -------------------------------------------------------------------------- -import pytest -from typetest.enum.extensible import ExtensibleClient, models - - -@pytest.fixture -def client(): - with ExtensibleClient() as client: - yield client - - -def test_known_value(client): - assert client.string.get_known_value() == models.DaysOfWeekExtensibleEnum.MONDAY - client.string.put_known_value(models.DaysOfWeekExtensibleEnum.MONDAY) - - -def test_unknown_value(client): - assert client.string.get_unknown_value() == "Weekend" - client.string.put_unknown_value("Weekend") diff --git a/packages/typespec-python/tests/mock_api/shared/test_typetest_enum_fixed.py b/packages/typespec-python/tests/mock_api/shared/test_typetest_enum_fixed.py deleted file mode 100644 index 0d085d0200..0000000000 --- a/packages/typespec-python/tests/mock_api/shared/test_typetest_enum_fixed.py +++ /dev/null @@ -1,25 +0,0 @@ -# ------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for -# license information. -# -------------------------------------------------------------------------- -import pytest -from typetest.enum.fixed import FixedClient, models - - -@pytest.fixture -def client(): - with FixedClient() as client: - yield client - - -def test_known_value(client): - assert client.string.get_known_value() == models.DaysOfWeekEnum.MONDAY - client.string.put_known_value(models.DaysOfWeekEnum.MONDAY) - - -def test_unknown_value(client: FixedClient, core_library): - try: - client.string.put_unknown_value("Weekend") - except core_library.exceptions.HttpResponseError as err: - assert err.status_code == 500 diff --git a/packages/typespec-python/tests/mock_api/shared/test_typetest_file.py b/packages/typespec-python/tests/mock_api/shared/test_typetest_file.py deleted file mode 100644 index 1503b0b580..0000000000 --- a/packages/typespec-python/tests/mock_api/shared/test_typetest_file.py +++ /dev/null @@ -1,52 +0,0 @@ -# ------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for -# license information. -# -------------------------------------------------------------------------- - -# after we support Http.File case, enable these tests again - -# import json - -# import pytest -# from typetest.file import FileClient - - -# @pytest.fixture -# def client(): -# with FileClient(endpoint="http://localhost:3000") as client: -# yield client - - -# def test_upload_file_specific_content_type(client: FileClient, png_data: bytes): -# client.body.upload_file_specific_content_type(png_data) - - -# # Do not support this case for now -# # def test_upload_file_json_content_type(client: FileClient): -# # client.body.upload_file_json_content_type(json.dumps({"message": "test file content"}).encode()) - - -# # although result is expected but actually there is deserialization issue -# # def test_download_file_json_content_type(client: FileClient): -# # result = client.body.download_file_json_content_type() -# # assert result == {"message": "test file content"} - - -# def test_download_file_specific_content_type(client: FileClient, png_data: bytes): -# result = b"".join(client.body.download_file_specific_content_type()) -# assert result == png_data - - -# def test_download_file_multiple_content_types(client: FileClient, png_data: bytes): -# result = b"".join(client.body.download_file_multiple_content_types()) -# assert result == png_data - - -# def test_upload_file_default_content_type(client: FileClient, png_data: bytes): -# client.body.upload_file_default_content_type(png_data, content_type="image/png") - - -# def test_download_file_default_content_type(client: FileClient, png_data: bytes): -# result = b"".join(client.body.download_file_default_content_type()) -# assert result == png_data diff --git a/packages/typespec-python/tests/mock_api/shared/test_typetest_model_empty.py b/packages/typespec-python/tests/mock_api/shared/test_typetest_model_empty.py deleted file mode 100644 index 1ef7fcb5e2..0000000000 --- a/packages/typespec-python/tests/mock_api/shared/test_typetest_model_empty.py +++ /dev/null @@ -1,29 +0,0 @@ -# ------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for -# license information. -# -------------------------------------------------------------------------- -import pytest -from typetest.model.empty import EmptyClient -from typetest.model.empty.models import EmptyInput, EmptyOutput, EmptyInputOutput - - -@pytest.fixture -def client(): - with EmptyClient() as client: - yield client - - -def test_put(client: EmptyClient): - client.put_empty(EmptyInput()) - client.put_empty({}) - - -def test_get(client: EmptyClient): - assert client.get_empty() == EmptyOutput() - assert client.get_empty() == {} - - -def test_post_round(client: EmptyClient): - assert client.post_round_trip_empty(EmptyInputOutput()) == EmptyInputOutput() - assert client.post_round_trip_empty({}) == {} diff --git a/packages/typespec-python/tests/mock_api/shared/test_typetest_model_inheritance_enum_discriminator.py b/packages/typespec-python/tests/mock_api/shared/test_typetest_model_inheritance_enum_discriminator.py deleted file mode 100644 index 6d752166b4..0000000000 --- a/packages/typespec-python/tests/mock_api/shared/test_typetest_model_inheritance_enum_discriminator.py +++ /dev/null @@ -1,58 +0,0 @@ -# ------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for -# license information. -# -------------------------------------------------------------------------- -import pytest -from typetest.model.enumdiscriminator import EnumDiscriminatorClient -from typetest.model.enumdiscriminator import models - - -@pytest.fixture -def client(): - with EnumDiscriminatorClient() as client: - yield client - - -@pytest.fixture -def valid_body(): - return models.Golden(weight=10) - - -@pytest.fixture -def valid_fixed_body(): - return models.Cobra(length=10) - - -def test_get_extensible_model(client: EnumDiscriminatorClient, valid_body: models.Dog): - assert client.get_extensible_model() == valid_body - assert isinstance(client.get_extensible_model(), models.Golden) - - -def test_put_extensible_model(client: EnumDiscriminatorClient, valid_body: models.Dog): - client.put_extensible_model(valid_body) - - -def test_get_extensible_model_missing_discriminator(client: EnumDiscriminatorClient): - assert client.get_extensible_model_missing_discriminator() == models.Dog(weight=10) - - -def test_get_extensible_model_wrong_discriminator(client: EnumDiscriminatorClient): - assert client.get_extensible_model_wrong_discriminator() == models.Dog(weight=8, kind="wrongKind") - - -def test_get_fixed_model(client: EnumDiscriminatorClient, valid_fixed_body: models.Snake): - assert client.get_fixed_model() == valid_fixed_body - assert isinstance(client.get_fixed_model(), models.Cobra) - - -def test_put_fixed_model(client: EnumDiscriminatorClient, valid_fixed_body: models.Snake): - client.put_fixed_model(valid_fixed_body) - - -def test_get_fixed_model_missing_discriminator(client: EnumDiscriminatorClient): - assert client.get_fixed_model_missing_discriminator() == models.Snake(length=10) - - -def test_get_fixed_model_wrong_discriminator(client: EnumDiscriminatorClient): - assert client.get_fixed_model_wrong_discriminator() == models.Snake(length=8, kind="wrongKind") diff --git a/packages/typespec-python/tests/mock_api/shared/test_typetest_model_inheritance_nested_discriminator.py b/packages/typespec-python/tests/mock_api/shared/test_typetest_model_inheritance_nested_discriminator.py deleted file mode 100644 index 8ea1366afa..0000000000 --- a/packages/typespec-python/tests/mock_api/shared/test_typetest_model_inheritance_nested_discriminator.py +++ /dev/null @@ -1,79 +0,0 @@ -# ------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for -# license information. -# -------------------------------------------------------------------------- -import pytest -from typetest.model.nesteddiscriminator import NestedDiscriminatorClient -from typetest.model.nesteddiscriminator.models import GoblinShark, Salmon, Fish - - -@pytest.fixture -def client(): - with NestedDiscriminatorClient() as client: - yield client - - -@pytest.fixture -def valid_body(): - return GoblinShark(age=1) - - -def test_get_model(client, valid_body): - assert client.get_model() == valid_body - assert isinstance(client.get_model(), GoblinShark) - - -def test_put_model(client, valid_body): - client.put_model(valid_body) - - -@pytest.fixture -def valid_recursive_body(): - return Salmon( - { - "age": 1, - "kind": "salmon", - "partner": {"age": 2, "kind": "shark", "sharktype": "saw"}, - "friends": [ - { - "age": 2, - "kind": "salmon", - "partner": {"age": 3, "kind": "salmon"}, - "hate": { - "key1": {"age": 4, "kind": "salmon"}, - "key2": {"age": 2, "kind": "shark", "sharktype": "goblin"}, - }, - }, - {"age": 3, "kind": "shark", "sharktype": "goblin"}, - ], - "hate": { - "key3": {"age": 3, "kind": "shark", "sharktype": "saw"}, - "key4": { - "age": 2, - "kind": "salmon", - "friends": [ - {"age": 1, "kind": "salmon"}, - {"age": 4, "kind": "shark", "sharktype": "goblin"}, - ], - }, - }, - } - ) - - -def test_get_recursive_model(client, valid_recursive_body): - assert valid_recursive_body == client.get_recursive_model() - assert isinstance(client.get_recursive_model(), Salmon) - - -def test_put_recursive_model(client, valid_recursive_body): - client.put_recursive_model(valid_recursive_body) - - -def test_get_missing_discriminator(client): - assert client.get_missing_discriminator() == Fish(age=1) - - -def test_get_wrong_discriminator(client): - assert client.get_wrong_discriminator() == Fish(age=1, kind="wrongKind") diff --git a/packages/typespec-python/tests/mock_api/shared/test_typetest_model_inheritance_not_discriminated.py b/packages/typespec-python/tests/mock_api/shared/test_typetest_model_inheritance_not_discriminated.py deleted file mode 100644 index e9a1fa4752..0000000000 --- a/packages/typespec-python/tests/mock_api/shared/test_typetest_model_inheritance_not_discriminated.py +++ /dev/null @@ -1,31 +0,0 @@ -# ------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for -# license information. -# -------------------------------------------------------------------------- -import pytest -from typetest.model.notdiscriminated import NotDiscriminatedClient -from typetest.model.notdiscriminated.models import Siamese - - -@pytest.fixture -def client(): - with NotDiscriminatedClient() as client: - yield client - - -@pytest.fixture -def valid_body(): - return Siamese(name="abc", age=32, smart=True) - - -def test_get_valid(client, valid_body): - assert client.get_valid() == valid_body - - -def test_post_valid(client, valid_body): - client.post_valid(valid_body) - - -def test_put_valid(client, valid_body): - assert valid_body == client.put_valid(valid_body) diff --git a/packages/typespec-python/tests/mock_api/shared/test_typetest_model_inheritance_recursive.py b/packages/typespec-python/tests/mock_api/shared/test_typetest_model_inheritance_recursive.py deleted file mode 100644 index 1aa0758e34..0000000000 --- a/packages/typespec-python/tests/mock_api/shared/test_typetest_model_inheritance_recursive.py +++ /dev/null @@ -1,32 +0,0 @@ -# ------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for -# license information. -# -------------------------------------------------------------------------- -import pytest -from typetest.model.recursive import RecursiveClient -from typetest.model.recursive.models import Extension - - -@pytest.fixture -def client(): - with RecursiveClient() as client: - yield client - - -@pytest.fixture -def expected(): - return Extension( - { - "level": 0, - "extension": [{"level": 1, "extension": [{"level": 2}]}, {"level": 1}], - } - ) - - -def test_put(client: RecursiveClient, expected: Extension): - client.put(expected) - - -def test_get(client: RecursiveClient, expected: Extension): - assert client.get() == expected diff --git a/packages/typespec-python/tests/mock_api/shared/test_typetest_model_inheritance_single_discriminator.py b/packages/typespec-python/tests/mock_api/shared/test_typetest_model_inheritance_single_discriminator.py deleted file mode 100644 index 86435d5486..0000000000 --- a/packages/typespec-python/tests/mock_api/shared/test_typetest_model_inheritance_single_discriminator.py +++ /dev/null @@ -1,60 +0,0 @@ -# ------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for -# license information. -# -------------------------------------------------------------------------- -import pytest -from typetest.model.singlediscriminator import SingleDiscriminatorClient -from typetest.model.singlediscriminator.models import Sparrow, Eagle, Bird, Dinosaur - - -@pytest.fixture -def client(): - with SingleDiscriminatorClient() as client: - yield client - - -@pytest.fixture -def valid_body(): - return Sparrow(wingspan=1) - - -def test_get_model(client, valid_body): - assert client.get_model() == valid_body - - -def test_put_model(client, valid_body): - client.put_model(valid_body) - - -@pytest.fixture -def recursive_body(): - return Eagle( - { - "wingspan": 5, - "kind": "eagle", - "partner": {"wingspan": 2, "kind": "goose"}, - "friends": [{"wingspan": 2, "kind": "seagull"}], - "hate": {"key3": {"wingspan": 1, "kind": "sparrow"}}, - } - ) - - -def test_get_recursive_model(client, recursive_body): - assert client.get_recursive_model() == recursive_body - - -def test_put_recursive_model(client, recursive_body): - client.put_recursive_model(recursive_body) - - -def test_get_missing_discriminator(client): - assert client.get_missing_discriminator() == Bird(wingspan=1) - - -def test_get_wrong_discriminator(client): - assert client.get_wrong_discriminator() == Bird(wingspan=1, kind="wrongKind") - - -def test_get_legacy_model(client): - assert client.get_legacy_model() == Dinosaur(size=20, kind="t-rex") diff --git a/packages/typespec-python/tests/mock_api/shared/test_typetest_model_usage.py b/packages/typespec-python/tests/mock_api/shared/test_typetest_model_usage.py deleted file mode 100644 index c9ef0e63e7..0000000000 --- a/packages/typespec-python/tests/mock_api/shared/test_typetest_model_usage.py +++ /dev/null @@ -1,28 +0,0 @@ -# ------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for -# license information. -# -------------------------------------------------------------------------- -import pytest -from typetest.model.usage import UsageClient, models - - -@pytest.fixture -def client(): - with UsageClient() as client: - yield client - - -def test_input(client: UsageClient): - input = models.InputRecord(required_prop="example-value") - assert client.input(input) is None - - -def test_output(client: UsageClient): - output = models.OutputRecord(required_prop="example-value") - assert output == client.output() - - -def test_input_and_output(client: UsageClient): - input_output = models.InputOutputRecord(required_prop="example-value") - assert input_output == client.input_and_output(input_output) diff --git a/packages/typespec-python/tests/mock_api/shared/test_typetest_model_visibility.py b/packages/typespec-python/tests/mock_api/shared/test_typetest_model_visibility.py deleted file mode 100644 index c6f4695f2f..0000000000 --- a/packages/typespec-python/tests/mock_api/shared/test_typetest_model_visibility.py +++ /dev/null @@ -1,40 +0,0 @@ -# ------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for -# license information. -# -------------------------------------------------------------------------- -import pytest -from typetest.model.visibility import VisibilityClient, models - - -@pytest.fixture -def client(): - with VisibilityClient() as client: - yield client - - -def test_get_model(client): - result = client.get_model(models.VisibilityModel(), query_prop=123) - assert result == models.VisibilityModel(read_prop="abc") - - -def test_put_model(client): - client.put_model(models.VisibilityModel(create_prop=["foo", "bar"], update_prop=[1, 2])) - - -def test_patch_model(client): - client.patch_model(models.VisibilityModel(update_prop=[1, 2])) - - -def test_post_model(client): - client.post_model(models.VisibilityModel(create_prop=["foo", "bar"])) - - -def test_delete_model(client): - client.delete_model(models.VisibilityModel(delete_prop=True)) - - -def test_put_read_only_model(client): - client.put_read_only_model( - models.ReadOnlyModel(optional_nullable_int_list=[1, 2], optional_string_record={"foo", "bar"}) - ) diff --git a/packages/typespec-python/tests/mock_api/shared/test_typetest_property_additionalproperties.py b/packages/typespec-python/tests/mock_api/shared/test_typetest_property_additionalproperties.py deleted file mode 100644 index 45445d9c42..0000000000 --- a/packages/typespec-python/tests/mock_api/shared/test_typetest_property_additionalproperties.py +++ /dev/null @@ -1,314 +0,0 @@ -# ------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for -# license information. -# -------------------------------------------------------------------------- -import pytest -from typetest.property.additionalproperties import AdditionalPropertiesClient, models - - -@pytest.fixture -def client(): - with AdditionalPropertiesClient() as client: - yield client - - -def test_extends_different_spread_float(client: AdditionalPropertiesClient): - body = models.DifferentSpreadFloatDerived({"name": "abc", "prop": 43.125, "derivedProp": 43.125}) - assert client.extends_different_spread_float.get() == body - client.extends_different_spread_float.put(body) - - -def test_extends_different_spread_model(client: AdditionalPropertiesClient): - body = models.DifferentSpreadModelDerived( - {"knownProp": "abc", "prop": {"state": "ok"}, "derivedProp": {"state": "ok"}} - ) - assert client.extends_different_spread_model.get() == body - client.extends_different_spread_model.put(body) - - -def test_extends_different_spread_model_array(client: AdditionalPropertiesClient): - body = models.DifferentSpreadModelArrayDerived( - { - "knownProp": "abc", - "prop": [{"state": "ok"}, {"state": "ok"}], - "derivedProp": [{"state": "ok"}, {"state": "ok"}], - } - ) - assert client.extends_different_spread_model_array.get() == body - client.extends_different_spread_model_array.put(body) - - -def test_extends_different_spread_string(client: AdditionalPropertiesClient): - body = models.DifferentSpreadStringDerived({"id": 43.125, "prop": "abc", "derivedProp": "abc"}) - assert client.extends_different_spread_string.get() == body - client.extends_different_spread_string.put(body) - - -def test_extends_float(client: AdditionalPropertiesClient): - body = models.ExtendsFloatAdditionalProperties({"id": 43.125, "prop": 43.125}) - assert client.extends_float.get() == body - client.extends_float.put(body) - - -def test_extends_model(client: AdditionalPropertiesClient): - body = models.ExtendsModelAdditionalProperties({"knownProp": {"state": "ok"}, "prop": {"state": "ok"}}) - assert client.extends_model.get() == body - client.extends_model.put(body) - - -def test_extends_model_array(client: AdditionalPropertiesClient): - body = models.ExtendsModelArrayAdditionalProperties( - { - "knownProp": [{"state": "ok"}, {"state": "ok"}], - "prop": [{"state": "ok"}, {"state": "ok"}], - } - ) - assert client.extends_model_array.get() == body - client.extends_model_array.put(body) - - -def test_extends_string(client: AdditionalPropertiesClient): - body = models.ExtendsStringAdditionalProperties({"name": "ExtendsStringAdditionalProperties", "prop": "abc"}) - assert client.extends_string.get() == body - client.extends_string.put(body) - - -def test_extends_unknown(client: AdditionalPropertiesClient): - body = models.ExtendsUnknownAdditionalProperties( - { - "name": "ExtendsUnknownAdditionalProperties", - "prop1": 32, - "prop2": True, - "prop3": "abc", - } - ) - assert client.extends_unknown.get() == body - client.extends_unknown.put(body) - - -def test_extends_unknown_derived(client: AdditionalPropertiesClient): - body = models.ExtendsUnknownAdditionalPropertiesDerived( - { - "name": "ExtendsUnknownAdditionalProperties", - "index": 314, - "age": 2.71875, - "prop1": 32, - "prop2": True, - "prop3": "abc", - } - ) - assert client.extends_unknown_derived.get() == body - client.extends_unknown_derived.put(body) - - -def test_extends_unknown_discriminated(client: AdditionalPropertiesClient): - body = models.ExtendsUnknownAdditionalPropertiesDiscriminatedDerived( - { - "kind": "derived", - "name": "Derived", - "index": 314, - "age": 2.71875, - "prop1": 32, - "prop2": True, - "prop3": "abc", - } - ) - assert client.extends_unknown_discriminated.get() == body - client.extends_unknown_discriminated.put(body) - - -def test_is_float(client: AdditionalPropertiesClient): - body = models.IsFloatAdditionalProperties({"id": 43.125, "prop": 43.125}) - assert client.is_float.get() == body - client.is_float.put(body) - - -def test_is_model(client: AdditionalPropertiesClient): - body = models.IsModelAdditionalProperties({"knownProp": {"state": "ok"}, "prop": {"state": "ok"}}) - assert client.is_model.get() == body - client.is_model.put(body) - - -def test_is_model_array(client: AdditionalPropertiesClient): - body = models.IsModelArrayAdditionalProperties( - { - "knownProp": [{"state": "ok"}, {"state": "ok"}], - "prop": [{"state": "ok"}, {"state": "ok"}], - } - ) - assert client.is_model_array.get() == body - client.is_model_array.put(body) - - -def test_is_string(client: AdditionalPropertiesClient): - body = models.IsStringAdditionalProperties({"name": "IsStringAdditionalProperties", "prop": "abc"}) - assert client.is_string.get() == body - client.is_string.put(body) - - -def test_is_unknown(client: AdditionalPropertiesClient): - body = models.IsUnknownAdditionalProperties( - { - "name": "IsUnknownAdditionalProperties", - "prop1": 32, - "prop2": True, - "prop3": "abc", - } - ) - assert client.is_unknown.get() == body - client.is_unknown.put(body) - - -def test_is_unknown_derived(client: AdditionalPropertiesClient): - body = models.IsUnknownAdditionalPropertiesDerived( - { - "name": "IsUnknownAdditionalProperties", - "index": 314, - "age": 2.71875, - "prop1": 32, - "prop2": True, - "prop3": "abc", - } - ) - assert client.is_unknown_derived.get() == body - client.is_unknown_derived.put(body) - - -def test_is_unknown_discriminated(client: AdditionalPropertiesClient): - body = models.IsUnknownAdditionalPropertiesDiscriminatedDerived( - { - "kind": "derived", - "name": "Derived", - "index": 314, - "age": 2.71875, - "prop1": 32, - "prop2": True, - "prop3": "abc", - } - ) - assert client.is_unknown_discriminated.get() == body - client.is_unknown_discriminated.put(body) - - -def test_multiple_spread(client: AdditionalPropertiesClient): - body = {"flag": True, "prop1": "abc", "prop2": 43.125} - assert client.multiple_spread.get() == body - client.multiple_spread.put(body) - - -def test_spread_different_float(client: AdditionalPropertiesClient): - body = {"name": "abc", "prop": 43.125} - assert client.spread_different_float.get() == body - client.spread_different_float.put(body) - - -def test_spread_different_model(client: AdditionalPropertiesClient): - body = {"knownProp": "abc", "prop": {"state": "ok"}} - assert client.spread_different_model.get() == body - client.spread_different_model.put(body) - - -def test_spread_different_model_array(client: AdditionalPropertiesClient): - body = {"knownProp": "abc", "prop": [{"state": "ok"}, {"state": "ok"}]} - assert client.spread_different_model_array.get() == body - client.spread_different_model_array.put(body) - - -def test_spread_different_string(client: AdditionalPropertiesClient): - body = {"id": 43.125, "prop": "abc"} - assert client.spread_different_string.get() == body - client.spread_different_string.put(body) - - -def test_spread_model(client: AdditionalPropertiesClient): - body = {"knownProp": {"state": "ok"}, "prop": {"state": "ok"}} - assert client.spread_model.get() == body - client.spread_model.put(body) - - -def test_spread_model_array(client: AdditionalPropertiesClient): - body = { - "knownProp": [{"state": "ok"}, {"state": "ok"}], - "prop": [{"state": "ok"}, {"state": "ok"}], - } - assert client.spread_model_array.get() == body - client.spread_model_array.put(body) - - -@pytest.mark.skip(reason="https://github.com/microsoft/typespec/pull/6425") -def test_spread_record_discriminated_union(client: AdditionalPropertiesClient): - body = { - "name": "abc", - "prop1": {"fooProp": "abc", "kind": "kind0"}, - "prop2": { - "end": "2021-01-02T00:00:00Z", - "kind": "kind1", - "start": "2021-01-01T00:00:00Z", - }, - } - assert client.spread_record_discriminated_union.get() == body - client.spread_record_discriminated_union.put(body) - - -def test_spread_record_non_discriminated_union(client: AdditionalPropertiesClient): - body = { - "name": "abc", - "prop1": {"kind": "kind0", "fooProp": "abc"}, - "prop2": { - "kind": "kind1", - "start": "2021-01-01T00:00:00Z", - "end": "2021-01-02T00:00:00Z", - }, - } - assert client.spread_record_non_discriminated_union.get() == body - client.spread_record_non_discriminated_union.put(body) - - -def test_spread_record_non_discriminated_union2(client: AdditionalPropertiesClient): - body = { - "name": "abc", - "prop1": {"kind": "kind1", "start": "2021-01-01T00:00:00Z"}, - "prop2": { - "kind": "kind1", - "start": "2021-01-01T00:00:00Z", - "end": "2021-01-02T00:00:00Z", - }, - } - assert client.spread_record_non_discriminated_union2.get() == body - client.spread_record_non_discriminated_union2.put(body) - - -def test_spread_record_non_discriminated_union3(client: AdditionalPropertiesClient): - body = { - "name": "abc", - "prop1": [ - {"kind": "kind1", "start": "2021-01-01T00:00:00Z"}, - {"kind": "kind1", "start": "2021-01-01T00:00:00Z"}, - ], - "prop2": { - "kind": "kind1", - "start": "2021-01-01T00:00:00Z", - "end": "2021-01-02T00:00:00Z", - }, - } - assert client.spread_record_non_discriminated_union3.get() == body - client.spread_record_non_discriminated_union3.put(body) - - -def test_spread_record_union(client: AdditionalPropertiesClient): - body = {"flag": True, "prop1": "abc", "prop2": 43.125} - assert client.spread_record_union.get() == body - client.spread_record_union.put(body) - - -def test_spread_string(client: AdditionalPropertiesClient): - body = {"name": "SpreadSpringRecord", "prop": "abc"} - assert client.spread_string.get() == body - client.spread_string.put(body) - - -def test_spread_float(client: AdditionalPropertiesClient): - body = {"id": 43.125, "prop": 43.125} - assert client.spread_float.get() == body - client.spread_float.put(body) diff --git a/packages/typespec-python/tests/mock_api/shared/test_typetest_property_nullable.py b/packages/typespec-python/tests/mock_api/shared/test_typetest_property_nullable.py deleted file mode 100644 index dcf3a44954..0000000000 --- a/packages/typespec-python/tests/mock_api/shared/test_typetest_property_nullable.py +++ /dev/null @@ -1,102 +0,0 @@ -# cspell: ignore Hdvcmxk -# ------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for -# license information. -# -------------------------------------------------------------------------- -import json -import pytest -from typetest.property.nullable import NullableClient, models -from typetest.property.nullable._utils.model_base import ( # pylint: disable=protected-access - SdkJSONEncoder, -) - -try: - from corehttp.serialization import NULL -except ImportError: - from azure.core.serialization import NULL - - -@pytest.fixture -def client(): - with NullableClient() as client: - yield client - - -def test_bytes(client: NullableClient): - non_null_model = models.BytesProperty(required_property="foo", nullable_property="aGVsbG8sIHdvcmxkIQ==") - non_model = models.BytesProperty(required_property="foo", nullable_property=NULL) - assert '{"requiredProperty": "foo", "nullableProperty": null}' == json.dumps(non_model, cls=SdkJSONEncoder) - assert client.bytes.get_non_null() == non_null_model - assert client.bytes.get_null()["nullableProperty"] is None - client.bytes.patch_non_null(body=non_null_model) - client.bytes.patch_null(body=non_model) - - -def test_collections_byte(client: NullableClient): - non_null_model = models.CollectionsByteProperty( - required_property="foo", - nullable_property=["aGVsbG8sIHdvcmxkIQ==", "aGVsbG8sIHdvcmxkIQ=="], - ) - non_model = models.CollectionsByteProperty(required_property="foo", nullable_property=NULL) - assert '{"requiredProperty": "foo", "nullableProperty": null}' == json.dumps(non_model, cls=SdkJSONEncoder) - assert client.collections_byte.get_non_null() == non_null_model - assert client.collections_byte.get_null()["nullableProperty"] is None - client.collections_byte.patch_non_null(body=non_null_model) - client.collections_byte.patch_null(body=non_model) - - -def test_collections_model(client: NullableClient): - non_null_model = models.CollectionsModelProperty( - required_property="foo", - nullable_property=[ - models.InnerModel(property="hello"), - models.InnerModel(property="world"), - ], - ) - non_model = models.CollectionsModelProperty(required_property="foo", nullable_property=NULL) - assert '{"requiredProperty": "foo", "nullableProperty": null}' == json.dumps(non_model, cls=SdkJSONEncoder) - assert client.collections_model.get_non_null() == non_null_model - assert client.collections_model.get_null()["nullableProperty"] is None - client.collections_model.patch_non_null(body=non_null_model) - client.collections_model.patch_null(body=non_model) - - -def test_collections_string(client: NullableClient): - non_null_model = models.CollectionsStringProperty(required_property="foo", nullable_property=["hello", "world"]) - non_model = models.CollectionsStringProperty(required_property="foo", nullable_property=NULL) - assert '{"requiredProperty": "foo", "nullableProperty": null}' == json.dumps(non_model, cls=SdkJSONEncoder) - assert client.collections_string.get_non_null() == non_null_model - assert client.collections_string.get_null()["nullableProperty"] is None - client.collections_string.patch_non_null(body=non_null_model) - client.collections_string.patch_null(body=non_model) - - -def test_datetime(client: NullableClient): - non_null_model = models.DatetimeProperty(required_property="foo", nullable_property="2022-08-26T18:38:00Z") - non_model = models.DatetimeProperty(required_property="foo", nullable_property=NULL) - assert '{"requiredProperty": "foo", "nullableProperty": null}' == json.dumps(non_model, cls=SdkJSONEncoder) - assert client.datetime.get_non_null() == non_null_model - assert client.datetime.get_null()["nullableProperty"] is None - client.datetime.patch_non_null(body=non_null_model) - client.datetime.patch_null(body=non_model) - - -def test_duration(client: NullableClient): - non_null_model = models.DurationProperty(required_property="foo", nullable_property="P123DT22H14M12.011S") - non_model = models.DurationProperty(required_property="foo", nullable_property=NULL) - assert '{"requiredProperty": "foo", "nullableProperty": null}' == json.dumps(non_model, cls=SdkJSONEncoder) - assert client.duration.get_non_null() == non_null_model - assert client.duration.get_null()["nullableProperty"] is None - client.duration.patch_non_null(body=non_null_model) - client.duration.patch_null(body=non_model) - - -def test_string(client: NullableClient): - non_null_model = models.StringProperty(required_property="foo", nullable_property="hello") - non_model = models.StringProperty(required_property="foo", nullable_property=NULL) - assert '{"requiredProperty": "foo", "nullableProperty": null}' == json.dumps(non_model, cls=SdkJSONEncoder) - assert client.string.get_non_null() == non_null_model - assert client.string.get_null()["nullableProperty"] is None - client.string.patch_non_null(body=non_null_model) - client.string.patch_null(body=non_model) diff --git a/packages/typespec-python/tests/mock_api/shared/test_typetest_property_optional.py b/packages/typespec-python/tests/mock_api/shared/test_typetest_property_optional.py deleted file mode 100644 index 84836538d0..0000000000 --- a/packages/typespec-python/tests/mock_api/shared/test_typetest_property_optional.py +++ /dev/null @@ -1,174 +0,0 @@ -# cspell: ignore Hdvcmxk -# ------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for -# license information. -# -------------------------------------------------------------------------- -from typing import Any -import pytest -from typetest.property.optional import OptionalClient, models - - -@pytest.fixture -def client(): - with OptionalClient() as client: - yield client - - -def test_boolean_literal(client): - body = models.BooleanLiteralProperty(property=True) - assert client.boolean_literal.get_all() == body - assert client.boolean_literal.get_default() == models.BooleanLiteralProperty() - client.boolean_literal.put_all(body) - client.boolean_literal.put_default(models.BooleanLiteralProperty()) - - -def test_bytes(client): - body = models.BytesProperty(property="aGVsbG8sIHdvcmxkIQ==") - assert client.bytes.get_all() == body - assert client.bytes.get_default() == models.BytesProperty() - client.bytes.put_all(body) - client.bytes.put_default(models.BytesProperty()) - - -def test_collections_byte(client): - body = models.CollectionsByteProperty(property=["aGVsbG8sIHdvcmxkIQ==", "aGVsbG8sIHdvcmxkIQ=="]) - assert client.collections_byte.get_all() == body - assert client.collections_byte.get_default() == models.CollectionsByteProperty() - client.collections_byte.put_all(body) - client.collections_byte.put_default(models.CollectionsByteProperty()) - - -def test_collections_model(client): - body = models.CollectionsModelProperty( - property=[ - models.StringProperty(property="hello"), - models.StringProperty(property="world"), - ] - ) - assert client.collections_model.get_all() == body - assert client.collections_model.get_default() == models.CollectionsModelProperty() - client.collections_model.put_all(body) - client.collections_model.put_default(models.CollectionsModelProperty()) - - -def test_datetime(client): - body = models.DatetimeProperty(property="2022-08-26T18:38:00Z") - assert client.datetime.get_all() == body - assert client.datetime.get_default() == models.DatetimeProperty() - client.datetime.put_all(body) - client.datetime.put_default(models.DatetimeProperty()) - - -def test_duration(client): - body = models.DurationProperty(property="P123DT22H14M12.011S") - assert client.duration.get_all() == body - assert client.duration.get_default() == models.DurationProperty() - client.duration.put_all(body) - client.duration.put_default(models.DurationProperty()) - - -def test_float_literal(client): - body = models.FloatLiteralProperty(property=1.25) - assert client.float_literal.get_all() == body - assert client.float_literal.get_default() == models.FloatLiteralProperty() - client.float_literal.put_all(body) - client.float_literal.put_default(models.FloatLiteralProperty()) - - -def test_int_literal(client): - body = models.IntLiteralProperty(property=1) - assert client.int_literal.get_all() == body - assert client.int_literal.get_default() == models.IntLiteralProperty() - client.int_literal.put_all(body) - client.int_literal.put_default(models.IntLiteralProperty()) - - -def test_plaindate_get_all(client): - body = models.PlainDateProperty(property="2022-12-12") - assert client.plain_date.get_all() == body - - -def test_plaindate_get_default(client): - assert client.plain_date.get_default() == models.PlainDateProperty() - - -def test_plaindate_put_all(client): - body = models.PlainDateProperty(property="2022-12-12") - client.plain_date.put_all(body) - - -def test_plaindate_put_default(client): - client.plain_date.put_default(models.PlainDateProperty()) - - -def test_plaintime_get_all(client): - body = models.PlainTimeProperty(property="13:06:12") - assert client.plain_time.get_all() == body - - -def test_plaintime_get_default(client): - assert client.plain_time.get_default() == models.PlainTimeProperty() - - -def test_plaintime_put_all(client): - body = models.PlainTimeProperty(property="13:06:12") - client.plain_time.put_all(body) - - -def test_plaintime_put_default(client): - client.plain_time.put_default(models.PlainTimeProperty()) - - -def test_required_and_optional(client): - all_body = { - "optionalProperty": "hello", - "requiredProperty": 42, - } - required_only_body = { - "requiredProperty": 42, - } - assert client.required_and_optional.get_all() == all_body - assert client.required_and_optional.get_required_only() == required_only_body - client.required_and_optional.put_all(all_body) - client.required_and_optional.put_required_only(required_only_body) - - -def test_string(client): - body = models.StringProperty(property="hello") - assert client.string.get_all() == body - assert client.string.get_default() == models.StringProperty() - client.string.put_all(body) - client.string.put_default(models.StringProperty()) - - -def test_string_literal(client): - body = models.StringLiteralProperty(property="hello") - assert client.string_literal.get_all() == body - assert client.string_literal.get_default() == models.StringLiteralProperty() - client.string_literal.put_all(body) - client.string_literal.put_default(models.StringLiteralProperty()) - - -def test_union_float_literal(client): - body = models.UnionFloatLiteralProperty(property=2.375) - assert client.union_float_literal.get_all() == body - assert client.union_float_literal.get_default() == models.UnionFloatLiteralProperty() - client.union_float_literal.put_all(body) - client.union_float_literal.put_default(models.UnionFloatLiteralProperty()) - - -def test_union_int_literal(client): - body = models.UnionIntLiteralProperty(property=2) - assert client.union_int_literal.get_all() == body - assert client.union_int_literal.get_default() == models.UnionIntLiteralProperty() - client.union_int_literal.put_all(body) - client.union_int_literal.put_default(models.UnionIntLiteralProperty()) - - -def test_union_string_literal(client): - body = models.UnionStringLiteralProperty(property="world") - assert client.union_string_literal.get_all() == body - assert client.union_string_literal.get_default() == models.UnionStringLiteralProperty() - client.union_string_literal.put_all(body) - client.union_string_literal.put_default(models.UnionStringLiteralProperty()) diff --git a/packages/typespec-python/tests/mock_api/shared/test_typetest_property_valuetypes.py b/packages/typespec-python/tests/mock_api/shared/test_typetest_property_valuetypes.py deleted file mode 100644 index faabc4c707..0000000000 --- a/packages/typespec-python/tests/mock_api/shared/test_typetest_property_valuetypes.py +++ /dev/null @@ -1,286 +0,0 @@ -# cspell: ignore Hdvcmxk -# ------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for -# license information. -# -------------------------------------------------------------------------- -from calendar import c -import decimal - -import pytest -import datetime -from typetest.property.valuetypes import ValueTypesClient, models - - -@pytest.fixture -def client(): - with ValueTypesClient() as client: - yield client - - -def test_boolean(client: ValueTypesClient): - body = models.BooleanProperty(property=True) - assert body.property == body["property"] - client.boolean.put(body) - - resp = client.boolean.get() - assert resp.property == resp["property"] == True - - -def test_boolean_literal(client: ValueTypesClient): - body = models.BooleanLiteralProperty(property=True) - assert body.property == body["property"] - client.boolean_literal.put(body) - - resp = client.boolean_literal.get() - assert resp.property == resp["property"] == True - - -def test_bytes(client: ValueTypesClient): - body = models.BytesProperty(property=b"hello, world!") - assert body.property == b"hello, world!" - assert body["property"] == "aGVsbG8sIHdvcmxkIQ==" - client.bytes.put(body) - - resp = client.bytes.get() - assert resp.property == b"hello, world!" - assert resp["property"] == "aGVsbG8sIHdvcmxkIQ==" - - -def test_collections_int(client: ValueTypesClient): - body = models.CollectionsIntProperty(property=[1, 2]) - assert body.property == body["property"] - client.collections_int.put(body) - - resp = client.collections_int.get() - assert resp.property == resp["property"] == [1, 2] - - -def test_collections_model(client: ValueTypesClient): - body = models.CollectionsModelProperty(property=[{"property": "hello"}, {"property": "world"}]) - assert body.property[0].property == body["property"][0]["property"] - client.collections_model.put(body) - - resp = client.collections_model.get() - assert resp.property[1].property == resp["property"][1]["property"] - - -def test_collections_string(client: ValueTypesClient): - body = models.CollectionsStringProperty(property=["hello", "world"]) - assert body.property == body["property"] - client.collections_string.put(body) - - resp = client.collections_string.get() - assert resp.property == resp["property"] == ["hello", "world"] - - -def test_datetime(client): - received_body = client.datetime.get() - assert received_body == {"property": "2022-08-26T18:38:00Z"} - assert received_body.property.year == 2022 - assert received_body.property.month == 8 - assert received_body.property.day == 26 - assert received_body.property.hour == 18 - assert received_body.property.minute == 38 - - client.datetime.put(models.DatetimeProperty(property=datetime.datetime(2022, 8, 26, hour=18, minute=38))) - - -def test_decimal(client: ValueTypesClient): - body = models.DecimalProperty(property=decimal.Decimal("0.33333")) - assert body.property == decimal.Decimal("0.33333") - assert body["property"] == 0.33333 - client.decimal.put(body) - - resp = client.decimal.get() - assert resp.property == decimal.Decimal("0.33333") - assert resp["property"] == 0.33333 - - -def test_decimal128(client: ValueTypesClient): - body = models.Decimal128Property(property=decimal.Decimal("0.33333")) - assert body.property == decimal.Decimal("0.33333") - assert body["property"] == 0.33333 - client.decimal128.put(body) - - resp = client.decimal128.get() - assert resp.property == decimal.Decimal("0.33333") - assert resp["property"] == 0.33333 - - -def test_dictionary_string(client: ValueTypesClient): - body = models.DictionaryStringProperty(property={"k1": "hello", "k2": "world"}) - assert body.property == body["property"] - client.dictionary_string.put(body) - - resp = client.dictionary_string.get() - assert resp.property == resp["property"] == {"k1": "hello", "k2": "world"} - - -def test_duration(client: ValueTypesClient): - body = models.DurationProperty(property="P123DT22H14M12.011S") - assert body.property == datetime.timedelta(days=123, seconds=80052, microseconds=11000) - assert body["property"] == "P123DT22H14M12.011S" - client.duration.put(body) - - resp = client.duration.get() - assert resp.property == datetime.timedelta(days=123, seconds=80052, microseconds=11000) - assert resp["property"] == "P123DT22H14M12.011S" - - -def test_enum(client: ValueTypesClient): - body = models.EnumProperty(property=models.InnerEnum.VALUE_ONE) - assert body.property == body["property"] - client.enum.put(body) - - resp = client.enum.get() - assert resp.property == resp["property"] == "ValueOne" - - -def test_extensible_enum(client: ValueTypesClient): - body = models.ExtensibleEnumProperty(property="UnknownValue") - assert body.property == body["property"] - client.extensible_enum.put(body) - - resp = client.extensible_enum.get() - assert resp.property == resp["property"] == "UnknownValue" - - -def test_float(client: ValueTypesClient): - body = models.FloatProperty(property=43.125) - assert body.property == body["property"] - client.float.put(body) - - resp = client.float.get() - assert resp.property == resp["property"] == 43.125 - - -def test_float_literal(client: ValueTypesClient): - body = models.FloatLiteralProperty(property=43.125) - assert body.property == body["property"] - client.float_literal.put(body) - - resp = client.float_literal.get() - assert resp.property == resp["property"] == 43.125 - - -def test_int(client: ValueTypesClient): - body = models.IntProperty(property=42) - assert body.property == body["property"] - client.int_operations.put(body) - - resp = client.int_operations.get() - assert resp.property == resp["property"] == 42 - - -def test_int_literal(client: ValueTypesClient): - body = models.IntLiteralProperty(property=42) - assert body.property == body["property"] - client.int_literal.put(body) - - resp = client.int_literal.get() - assert resp.property == resp["property"] == 42 - - -def test_model(client: ValueTypesClient): - body = models.ModelProperty(property={"property": "hello"}) - assert body.property.property == body["property"]["property"] - client.model.put(body) - - resp = client.model.get() - assert resp.property.property == resp["property"]["property"] - - -def test_never(client: ValueTypesClient): - assert client.never.get() == models.NeverProperty() - client.never.put(models.NeverProperty()) - - -def test_string(client: ValueTypesClient): - body = models.StringProperty(property="hello") - assert body.property == body["property"] - client.string.put(body) - - resp = client.string.get() - assert resp.property == resp["property"] == "hello" - - -def test_string_literal(client: ValueTypesClient): - body = models.StringLiteralProperty(property="hello") - assert body.property == body["property"] - client.string_literal.put(body) - - resp = client.string_literal.get() - assert resp.property == resp["property"] == "hello" - - -def test_union_enum_value(client: ValueTypesClient): - body = models.UnionEnumValueProperty(property=models.ExtendedEnum.ENUM_VALUE2) - assert body.property == body["property"] - client.union_enum_value.put(body) - - resp = client.union_enum_value.get() - assert resp.property == resp["property"] == "value2" - - -def test_union_float_literal(client: ValueTypesClient): - body = models.UnionFloatLiteralProperty(property=46.875) - assert body.property == body["property"] - client.union_float_literal.put(body) - - resp = client.union_float_literal.get() - assert resp.property == resp["property"] == 46.875 - - -def test_union_int_literal(client: ValueTypesClient): - body = models.UnionIntLiteralProperty(property=42) - assert body.property == body["property"] - client.union_int_literal.put(body) - - resp = client.union_int_literal.get() - assert resp.property == resp["property"] == 42 - - -def test_union_string_literal(client: ValueTypesClient): - body = models.UnionStringLiteralProperty(property="world") - assert body.property == body["property"] - client.union_string_literal.put(body) - - resp = client.union_string_literal.get() - assert resp.property == resp["property"] == "world" - - -def test_unknown_array(client: ValueTypesClient): - body = models.UnknownArrayProperty(property=["hello", "world"]) - assert body.property == body["property"] - client.unknown_array.put(body) - - resp = client.unknown_array.get() - assert resp.property == resp["property"] == ["hello", "world"] - - -def test_unknown_dict(client: ValueTypesClient): - body = models.UnknownDictProperty(property={"k1": "hello", "k2": 42}) - assert body.property == body["property"] - client.unknown_dict.put(body) - - resp = client.unknown_dict.get() - assert resp.property == resp["property"] == {"k1": "hello", "k2": 42} - - -def test_unknown_int(client: ValueTypesClient): - body = models.UnknownIntProperty(property=42) - assert body.property == body["property"] - client.unknown_int.put(body) - - resp = client.unknown_int.get() - assert resp.property == resp["property"] == 42 - - -def test_unknown_string(client: ValueTypesClient): - body = models.UnknownStringProperty(property="hello") - assert body.property == body["property"] - client.unknown_string.put(body) - - resp = client.unknown_string.get() - assert resp.property == resp["property"] == "hello" diff --git a/packages/typespec-python/tests/mock_api/shared/test_typetest_scalar.py b/packages/typespec-python/tests/mock_api/shared/test_typetest_scalar.py deleted file mode 100644 index 32a1583ac1..0000000000 --- a/packages/typespec-python/tests/mock_api/shared/test_typetest_scalar.py +++ /dev/null @@ -1,53 +0,0 @@ -# ------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for -# license information. -# -------------------------------------------------------------------------- -import decimal -from functools import reduce - -import pytest -from typetest.scalar import ScalarClient - - -@pytest.fixture -def client(): - with ScalarClient() as client: - yield client - - -def test_scalar_string(client: ScalarClient): - assert client.string.get() == "test" - client.string.put("test") - - -def test_scalar_boolean(client: ScalarClient): - assert client.boolean.get() == True - client.boolean.put(True) - - -def test_scalar_unknown(client: ScalarClient): - assert client.unknown.get() == "test" - client.unknown.put("test") - - -def test_decimal128_type(client: ScalarClient): - assert client.decimal128_type.response_body() == decimal.Decimal("0.33333") - client.decimal128_type.request_body(decimal.Decimal("0.33333")) - client.decimal128_type.request_parameter(value=decimal.Decimal("0.33333")) - - -def test_decimal_type(client: ScalarClient): - assert client.decimal_type.response_body() == decimal.Decimal("0.33333") - client.decimal_type.request_body(decimal.Decimal("0.33333")) - client.decimal_type.request_parameter(value=decimal.Decimal("0.33333")) - - -def test_decimal128_verify(client: ScalarClient): - prepare = client.decimal128_verify.prepare_verify() - client.decimal128_verify.verify(reduce(lambda x, y: x + y, prepare)) - - -def test_decimal_verify(client: ScalarClient): - prepare = client.decimal_verify.prepare_verify() - client.decimal_verify.verify(reduce(lambda x, y: x + y, prepare)) diff --git a/packages/typespec-python/tests/mock_api/shared/test_typetest_union.py b/packages/typespec-python/tests/mock_api/shared/test_typetest_union.py deleted file mode 100644 index 3ca676d10a..0000000000 --- a/packages/typespec-python/tests/mock_api/shared/test_typetest_union.py +++ /dev/null @@ -1,80 +0,0 @@ -# ------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for -# license information. -# -------------------------------------------------------------------------- -import pytest -from typetest.union import UnionClient -from typetest.union import models - - -@pytest.fixture -def client(): - with UnionClient() as client: - yield client - - -def test_enums_only(client: UnionClient): - value = models.EnumsOnlyCases(lr="right", ud="up") - assert client.enums_only.get() == {"prop": value} - client.enums_only.send(prop=value) - - -def test_floats_only(client: UnionClient): - value = 2.2 - assert client.floats_only.get() == {"prop": value} - client.floats_only.send(prop=value) - - -def test_ints_only(client: UnionClient): - value = 2 - assert client.ints_only.get() == {"prop": value} - client.ints_only.send(prop=value) - - -def test_mixed_literals(client: UnionClient): - value = models.MixedLiteralsCases(string_literal="a", int_literal=2, float_literal=3.3, boolean_literal=True) - assert client.mixed_literals.get() == {"prop": value} - client.mixed_literals.send(prop=value) - - -def test_mixed_types(client: UnionClient): - value = models.MixedTypesCases( - model=models.Cat(name="test"), - literal="a", - int_property=2, - boolean=True, - array=[models.Cat(name="test"), "a", 2, True], - ) - assert client.mixed_types.get() == {"prop": value} - client.mixed_types.send(prop=value) - - -def test_models_only(client: UnionClient): - value = models.Cat(name="test") - assert client.models_only.get() == {"prop": value} - client.models_only.send(prop=value) - - -def test_string_and_array(client: UnionClient): - value = models.StringAndArrayCases(string="test", array=["test1", "test2"]) - assert client.string_and_array.get() == {"prop": value} - client.string_and_array.send(prop=value) - - -def test_string_extensible(client: UnionClient): - value = "custom" - assert client.string_extensible.get() == {"prop": value} - client.string_extensible.send(prop=value) - - -def test_string_extensible_named(client: UnionClient): - value = "custom" - assert client.string_extensible_named.get() == {"prop": value} - client.string_extensible_named.send(prop=value) - - -def test_strings_only(client: UnionClient): - value = "b" - assert client.strings_only.get() == {"prop": value} - client.strings_only.send(prop=value) diff --git a/packages/typespec-python/tests/mock_api/shared/test_typetest_union_discriminated.py b/packages/typespec-python/tests/mock_api/shared/test_typetest_union_discriminated.py deleted file mode 100644 index 2b031c9fef..0000000000 --- a/packages/typespec-python/tests/mock_api/shared/test_typetest_union_discriminated.py +++ /dev/null @@ -1,290 +0,0 @@ -# ------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for -# license information. -# -------------------------------------------------------------------------- -import pytest -from typetest.discriminatedunion import DiscriminatedClient -from typetest.discriminatedunion import models - - -@pytest.fixture -def client(): - with DiscriminatedClient() as client: - yield client - - -@pytest.fixture -def cat_body(): - """Cat model for testing.""" - return models.Cat(name="Whiskers", meow=True) - - -@pytest.fixture -def dog_body(): - """Dog model for testing.""" - return models.Dog(name="Rex", bark=False) - - -# Tests for No Envelope / Default (inline discriminator with "kind") -@pytest.mark.skip(reason="After completely support discriminated unions, enable these tests") -class TestNoEnvelopeDefault: - """Test discriminated union with inline discriminator (no envelope).""" - - def test_get_default_cat(self, client: DiscriminatedClient, cat_body: models.Cat): - """Test getting cat with default (no query param or kind=cat). - - Expected response: - { - "kind": "cat", - "name": "Whiskers", - "meow": true - } - """ - result = client.no_envelope.default.get() - assert result == cat_body - assert isinstance(result, models.Cat) - - def test_get_with_kind_cat(self, client: DiscriminatedClient, cat_body: models.Cat): - """Test getting cat with kind=cat query parameter. - - Expected response: - { - "kind": "cat", - "name": "Whiskers", - "meow": true - } - """ - result = client.no_envelope.default.get(kind="cat") - assert result == cat_body - assert isinstance(result, models.Cat) - - def test_get_with_kind_dog(self, client: DiscriminatedClient, dog_body: models.Dog): - """Test getting dog with kind=dog query parameter. - - Expected response: - { - "kind": "dog", - "name": "Rex", - "bark": false - } - """ - result = client.no_envelope.default.get(kind="dog") - assert result == dog_body - assert isinstance(result, models.Dog) - - def test_put_cat(self, client: DiscriminatedClient, cat_body: models.Cat): - """Test sending cat with inline discriminator. - - Expected request: - { - "kind": "cat", - "name": "Whiskers", - "meow": true - } - """ - result = client.no_envelope.default.put(cat_body) - assert result == cat_body - assert isinstance(result, models.Cat) - - -# Tests for No Envelope / Custom Discriminator (inline with custom "type" property) -@pytest.mark.skip(reason="After completely support discriminated unions, enable these tests") -class TestNoEnvelopeCustomDiscriminator: - """Test discriminated union with inline discriminator and custom discriminator property name.""" - - def test_get_default_cat(self, client: DiscriminatedClient, cat_body: models.Cat): - """Test getting cat with default (no query param or type=cat). - - Expected response: - { - "type": "cat", - "name": "Whiskers", - "meow": true - } - """ - result = client.no_envelope.custom_discriminator.get() - assert result == cat_body - assert isinstance(result, models.Cat) - - def test_get_with_type_cat(self, client: DiscriminatedClient, cat_body: models.Cat): - """Test getting cat with type=cat query parameter. - - Expected response: - { - "type": "cat", - "name": "Whiskers", - "meow": true - } - """ - result = client.no_envelope.custom_discriminator.get(type="cat") - assert result == cat_body - assert isinstance(result, models.Cat) - - def test_get_with_type_dog(self, client: DiscriminatedClient, dog_body: models.Dog): - """Test getting dog with type=dog query parameter. - - Expected response: - { - "type": "dog", - "name": "Rex", - "bark": false - } - """ - result = client.no_envelope.custom_discriminator.get(type="dog") - assert result == dog_body - assert isinstance(result, models.Dog) - - def test_put_cat(self, client: DiscriminatedClient, cat_body: models.Cat): - """Test sending cat with inline custom discriminator. - - Expected request: - { - "type": "cat", - "name": "Whiskers", - "meow": true - } - """ - result = client.no_envelope.custom_discriminator.put(cat_body) - assert result == cat_body - assert isinstance(result, models.Cat) - - -# Tests for Envelope / Object / Default (envelope with "kind" and "value") -@pytest.mark.skip(reason="After completely support discriminated unions, enable these tests") -class TestEnvelopeObjectDefault: - """Test discriminated union with default envelope serialization.""" - - def test_get_default_cat(self, client: DiscriminatedClient, cat_body: models.Cat): - """Test getting cat with default (no query param or kind=cat). - - Expected response: - { - "kind": "cat", - "value": { - "name": "Whiskers", - "meow": true - } - } - """ - result = client.envelope.object.default.get() - assert result == cat_body - assert isinstance(result, models.Cat) - - def test_get_with_kind_cat(self, client: DiscriminatedClient, cat_body: models.Cat): - """Test getting cat with kind=cat query parameter. - - Expected response: - { - "kind": "cat", - "value": { - "name": "Whiskers", - "meow": true - } - } - """ - result = client.envelope.object.default.get(kind="cat") - assert result == cat_body - assert isinstance(result, models.Cat) - - def test_get_with_kind_dog(self, client: DiscriminatedClient, dog_body: models.Dog): - """Test getting dog with kind=dog query parameter. - - Expected response: - { - "kind": "dog", - "value": { - "name": "Rex", - "bark": false - } - } - """ - result = client.envelope.object.default.get(kind="dog") - assert result == dog_body - assert isinstance(result, models.Dog) - - def test_put_cat(self, client: DiscriminatedClient, cat_body: models.Cat): - """Test sending cat with envelope serialization. - - Expected request: - { - "kind": "cat", - "value": { - "name": "Whiskers", - "meow": true - } - } - """ - result = client.envelope.object.default.put(cat_body) - assert result == cat_body - assert isinstance(result, models.Cat) - - -# Tests for Envelope / Object / Custom Properties (envelope with custom "petType" and "petData") -@pytest.mark.skip(reason="After completely support discriminated unions, enable these tests") -class TestEnvelopeObjectCustomProperties: - """Test discriminated union with custom property names in envelope.""" - - def test_get_default_cat(self, client: DiscriminatedClient, cat_body: models.Cat): - """Test getting cat with default (no query param or petType=cat). - - Expected response: - { - "petType": "cat", - "petData": { - "name": "Whiskers", - "meow": true - } - } - """ - result = client.envelope.object.custom_properties.get() - assert result == cat_body - assert isinstance(result, models.Cat) - - def test_get_with_pet_type_cat(self, client: DiscriminatedClient, cat_body: models.Cat): - """Test getting cat with petType=cat query parameter. - - Expected response: - { - "petType": "cat", - "petData": { - "name": "Whiskers", - "meow": true - } - } - """ - result = client.envelope.object.custom_properties.get(pet_type="cat") - assert result == cat_body - assert isinstance(result, models.Cat) - - def test_get_with_pet_type_dog(self, client: DiscriminatedClient, dog_body: models.Dog): - """Test getting dog with petType=dog query parameter. - - Expected response: - { - "petType": "dog", - "petData": { - "name": "Rex", - "bark": false - } - } - """ - result = client.envelope.object.custom_properties.get(pet_type="dog") - assert result == dog_body - assert isinstance(result, models.Dog) - - def test_put_cat(self, client: DiscriminatedClient, cat_body: models.Cat): - """Test sending cat with custom property names in envelope. - - Expected request: - { - "petType": "cat", - "petData": { - "name": "Whiskers", - "meow": true - } - } - """ - result = client.envelope.object.custom_properties.put(cat_body) - assert result == cat_body - assert isinstance(result, models.Cat) diff --git a/packages/typespec-python/tests/mock_api/shared/test_versioning_added.py b/packages/typespec-python/tests/mock_api/shared/test_versioning_added.py deleted file mode 100644 index c51b159cba..0000000000 --- a/packages/typespec-python/tests/mock_api/shared/test_versioning_added.py +++ /dev/null @@ -1,33 +0,0 @@ -# ------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for -# license information. -# -------------------------------------------------------------------------- -import pytest -from versioning.added import AddedClient -from versioning.added.models import ModelV1, ModelV2, EnumV1, EnumV2 - - -@pytest.fixture -def client(): - with AddedClient(endpoint="http://localhost:3000", version="v2") as client: - yield client - - -def test_v1(client: AddedClient): - assert client.v1( - ModelV1(prop="foo", enum_prop=EnumV1.ENUM_MEMBER_V2, union_prop=10), - header_v2="bar", - ) == ModelV1(prop="foo", enum_prop=EnumV1.ENUM_MEMBER_V2, union_prop=10) - - -def test_v2(client: AddedClient): - assert client.v2(ModelV2(prop="foo", enum_prop=EnumV2.ENUM_MEMBER, union_prop="bar")) == ModelV2( - prop="foo", enum_prop=EnumV2.ENUM_MEMBER, union_prop="bar" - ) - - -def test_interface_v2(client: AddedClient): - assert client.interface_v2.v2_in_interface( - ModelV2(prop="foo", enum_prop=EnumV2.ENUM_MEMBER, union_prop="bar") - ) == ModelV2(prop="foo", enum_prop=EnumV2.ENUM_MEMBER, union_prop="bar") diff --git a/packages/typespec-python/tests/mock_api/shared/test_versioning_made_optional.py b/packages/typespec-python/tests/mock_api/shared/test_versioning_made_optional.py deleted file mode 100644 index 52099a04b7..0000000000 --- a/packages/typespec-python/tests/mock_api/shared/test_versioning_made_optional.py +++ /dev/null @@ -1,20 +0,0 @@ -# ------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for -# license information. -# -------------------------------------------------------------------------- -import pytest -from versioning.madeoptional import MadeOptionalClient -from versioning.madeoptional.models import TestModel - - -@pytest.fixture -def client(): - with MadeOptionalClient(endpoint="http://localhost:3000", version="v2") as client: - yield client - - -def test(client: MadeOptionalClient): - assert client.test( - TestModel(prop="foo"), - ) == TestModel(prop="foo") diff --git a/packages/typespec-python/tests/mock_api/shared/test_versioning_removed.py b/packages/typespec-python/tests/mock_api/shared/test_versioning_removed.py deleted file mode 100644 index ad5fb01d1a..0000000000 --- a/packages/typespec-python/tests/mock_api/shared/test_versioning_removed.py +++ /dev/null @@ -1,37 +0,0 @@ -# ------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for -# license information. -# -------------------------------------------------------------------------- -import pytest -from versioning.removed import RemovedClient -from versioning.removed.models import ModelV2, EnumV2, ModelV3, EnumV3 - - -@pytest.fixture -def client(): - with RemovedClient(endpoint="http://localhost:3000", version="v2") as client: - yield client - - -def test_v2(client: RemovedClient): - assert client.v2(ModelV2(prop="foo", enum_prop=EnumV2.ENUM_MEMBER_V2, union_prop="bar")) == ModelV2( - prop="foo", enum_prop=EnumV2.ENUM_MEMBER_V2, union_prop="bar" - ) - - -def test_model_v3(): - client1 = RemovedClient(endpoint="http://localhost:3000", version="v1") - model1 = ModelV3(id="123", enum_prop=EnumV3.ENUM_MEMBER_V1) - result = client1.model_v3(model1) - assert result == model1 - - client2 = RemovedClient(endpoint="http://localhost:3000", version="v2preview") - model2 = ModelV3(id="123") - result = client2.model_v3(model2) - assert result == model2 - - client3 = RemovedClient(endpoint="http://localhost:3000", version="v2") - model3 = ModelV3(id="123", enum_prop=EnumV3.ENUM_MEMBER_V1) - result = client3.model_v3(model3) - assert result == model3 diff --git a/packages/typespec-python/tests/mock_api/shared/test_versioning_renamed_from.py b/packages/typespec-python/tests/mock_api/shared/test_versioning_renamed_from.py deleted file mode 100644 index d81f258713..0000000000 --- a/packages/typespec-python/tests/mock_api/shared/test_versioning_renamed_from.py +++ /dev/null @@ -1,27 +0,0 @@ -# ------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for -# license information. -# -------------------------------------------------------------------------- -import pytest -from versioning.renamedfrom import RenamedFromClient -from versioning.renamedfrom.models import NewModel, NewEnum - - -@pytest.fixture -def client(): - with RenamedFromClient(endpoint="http://localhost:3000", version="v2") as client: - yield client - - -def test_new_op(client: RenamedFromClient): - assert client.new_op( - NewModel(new_prop="foo", enum_prop=NewEnum.NEW_ENUM_MEMBER, union_prop=10), - new_query="bar", - ) == NewModel(new_prop="foo", enum_prop=NewEnum.NEW_ENUM_MEMBER, union_prop=10) - - -def test_new_interface_test(client: RenamedFromClient): - assert client.new_interface.new_op_in_new_interface( - NewModel(new_prop="foo", enum_prop=NewEnum.NEW_ENUM_MEMBER, union_prop=10) - ) == NewModel(new_prop="foo", enum_prop=NewEnum.NEW_ENUM_MEMBER, union_prop=10) diff --git a/packages/typespec-python/tests/mock_api/shared/test_versioning_return_type_changed_from.py b/packages/typespec-python/tests/mock_api/shared/test_versioning_return_type_changed_from.py deleted file mode 100644 index 92decc7204..0000000000 --- a/packages/typespec-python/tests/mock_api/shared/test_versioning_return_type_changed_from.py +++ /dev/null @@ -1,17 +0,0 @@ -# ------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for -# license information. -# -------------------------------------------------------------------------- -import pytest -from versioning.returntypechangedfrom import ReturnTypeChangedFromClient - - -@pytest.fixture -def client(): - with ReturnTypeChangedFromClient(endpoint="http://localhost:3000", version="v2") as client: - yield client - - -def test(client: ReturnTypeChangedFromClient): - assert client.test("test") == "test" diff --git a/packages/typespec-python/tests/mock_api/shared/test_versioning_type_changed_from.py b/packages/typespec-python/tests/mock_api/shared/test_versioning_type_changed_from.py deleted file mode 100644 index e10742a815..0000000000 --- a/packages/typespec-python/tests/mock_api/shared/test_versioning_type_changed_from.py +++ /dev/null @@ -1,21 +0,0 @@ -# ------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for -# license information. -# -------------------------------------------------------------------------- -import pytest -from versioning.typechangedfrom import TypeChangedFromClient -from versioning.typechangedfrom.models import TestModel - - -@pytest.fixture -def client(): - with TypeChangedFromClient(endpoint="http://localhost:3000", version="v2") as client: - yield client - - -def test(client: TypeChangedFromClient): - assert client.test( - TestModel(prop="foo", changed_prop="bar"), - param="baz", - ) == TestModel(prop="foo", changed_prop="bar") diff --git a/packages/typespec-python/tests/mock_api/shared/unittests/test_parse_pyproject.py b/packages/typespec-python/tests/mock_api/shared/unittests/test_parse_pyproject.py deleted file mode 100644 index 1d843bbc4d..0000000000 --- a/packages/typespec-python/tests/mock_api/shared/unittests/test_parse_pyproject.py +++ /dev/null @@ -1,98 +0,0 @@ -from pathlib import Path -from typing import Dict, Any - -import pytest - -try: - import tomllib -except ImportError: - import tomli as tomllib - - -def check_no_setup_py(package_path: str) -> None: - """ - Check that setup.py does not exist in the package directory. - - Args: - package_path: Relative path to the package directory - - Raises: - AssertionError: If setup.py exists in the package directory - """ - package_dir = Path(__file__).parent / package_path - setup_py_path = package_dir / "setup.py" - - assert not setup_py_path.exists(), f"setup.py should not exist at {setup_py_path} when using pyproject.toml" - - -def get_pyproject_section(package_path: str, section_name: str) -> Dict[str, Any]: - """ - Get a specific section from a package's pyproject.toml file. - - Args: - package_path: Relative path to the package directory containing pyproject.toml - section_name: Dot-separated section name (e.g., "tool.azure-sdk-build") - - Returns: - Dictionary containing the section data - - Raises: - AssertionError: If pyproject.toml not found or section missing - """ - try: - # Convert to absolute path and find pyproject.toml - package_dir = Path(__file__).parent / package_path - pyproject_path = package_dir / "pyproject.toml" - - # Assert pyproject.toml exists - assert pyproject_path.exists(), f"pyproject.toml not found at {pyproject_path}" - - # Parse pyproject.toml - with open(pyproject_path, "rb") as f: - data = tomllib.load(f) - - # Check that the project name matches the folder name - if "project" in data and "name" in data["project"]: - expected_name = package_dir.name - actual_name = data["project"]["name"] - assert ( - actual_name == expected_name - ), f"Project name '{actual_name}' in pyproject.toml does not match folder name '{expected_name}'" - - # Navigate to the requested section - section_parts = section_name.split(".") - current_data = data - - for part in section_parts: - assert ( - part in current_data - ), f"pyproject.toml does not contain [{'.'.join(section_parts[:section_parts.index(part)+1])}] section" - current_data = current_data[part] - - return current_data - - except Exception as e: - raise AssertionError(f"Error checking pyproject.toml at '{package_path}': {e}") - - -@pytest.mark.skip(reason="Generator does not yet produce [tool.azure-sdk-build] section") -def test_azure_sdk_build(): - """Test that authentication-union packages have pyproject.toml with [tool.azure-sdk-build] pyright = false.""" - - # Need to check the file directly, since installed distribution metadata won't include custom sections. - test_paths = ["../../../generated/azure/authentication-union"] - - for package_path in test_paths: - # First check that setup.py doesn't exist - check_no_setup_py(package_path) - - # Get the [tool.azure-sdk-build] section - azure_sdk_build = get_pyproject_section(package_path, "tool.azure-sdk-build") - - # Check for pyright = false - assert ( - "pyright" in azure_sdk_build - ), f"[tool.azure-sdk-build] section does not contain 'pyright' setting in {package_path}" - assert ( - azure_sdk_build["pyright"] is False - ), f"Expected pyright = false, but got pyright = {azure_sdk_build['pyright']} in {package_path}" diff --git a/packages/typespec-python/tests/mock_api/unbranded/asynctests/test_auth_flow_async.py b/packages/typespec-python/tests/mock_api/unbranded/asynctests/test_auth_flow_async.py deleted file mode 100644 index 5ad8263c4b..0000000000 --- a/packages/typespec-python/tests/mock_api/unbranded/asynctests/test_auth_flow_async.py +++ /dev/null @@ -1,19 +0,0 @@ -# ------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for -# license information. -# -------------------------------------------------------------------------- -import pytest -from authentication.oauth2.aio import OAuth2Client - - -@pytest.mark.asyncio -async def test_oauth2_auth_flows(): - oauth2_client = OAuth2Client("fake_credential") - assert oauth2_client._config.authentication_policy._auth_flows == [ - { - "authorizationUrl": "https://login.microsoftonline.com/common/oauth2/authorize", - "scopes": [{"value": "https://security.microsoft.com/.default"}], - "type": "implicit", - } - ] diff --git a/packages/typespec-python/tests/mock_api/unbranded/asynctests/test_encode_duration_async.py b/packages/typespec-python/tests/mock_api/unbranded/asynctests/test_encode_duration_async.py deleted file mode 100644 index f14c436a8f..0000000000 --- a/packages/typespec-python/tests/mock_api/unbranded/asynctests/test_encode_duration_async.py +++ /dev/null @@ -1,63 +0,0 @@ -# ------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for -# license information. -# -------------------------------------------------------------------------- -import datetime - -import pytest -from encode.duration.aio import DurationClient -from encode.duration.property.models import ( - Int32SecondsDurationProperty, - ISO8601DurationProperty, - FloatSecondsDurationProperty, - DefaultDurationProperty, - FloatSecondsDurationArrayProperty, -) - - -@pytest.fixture -async def client(): - async with DurationClient() as client: - yield client - - -@pytest.mark.asyncio -async def test_query(client: DurationClient): - await client.query.default(input=datetime.timedelta(days=40)) - await client.query.iso8601(input=datetime.timedelta(days=40)) - await client.query.int32_seconds(input=36) - await client.query.int32_seconds_array(input=[36, 47]) - await client.query.float_seconds(input=35.625) - await client.query.float64_seconds(input=35.625) - - -@pytest.mark.asyncio -async def test_property(client: DurationClient): - result = await client.property.default(DefaultDurationProperty(value=datetime.timedelta(days=40))) - assert result.value == datetime.timedelta(days=40) - result = await client.property.default(DefaultDurationProperty(value="P40D")) - assert result.value == datetime.timedelta(days=40) - result = await client.property.iso8601(ISO8601DurationProperty(value=datetime.timedelta(days=40))) - assert result.value == datetime.timedelta(days=40) - result = await client.property.iso8601(ISO8601DurationProperty(value="P40D")) - assert result.value == datetime.timedelta(days=40) - result = await client.property.int32_seconds(Int32SecondsDurationProperty(value=36)) - assert result.value == 36 - result = await client.property.float_seconds(FloatSecondsDurationProperty(value=35.625)) - assert abs(result.value - 35.625) < 0.0001 - result = await client.property.float64_seconds(FloatSecondsDurationProperty(value=35.625)) - assert abs(result.value - 35.625) < 0.0001 - result = await client.property.float_seconds_array(FloatSecondsDurationArrayProperty(value=[35.625, 46.75])) - assert abs(result.value[0] - 35.625) < 0.0001 - assert abs(result.value[1] - 46.75) < 0.0001 - - -@pytest.mark.asyncio -async def test_header(client: DurationClient): - await client.header.default(duration=datetime.timedelta(days=40)) - await client.header.iso8601(duration=datetime.timedelta(days=40)) - await client.header.iso8601_array(duration=[datetime.timedelta(days=40), datetime.timedelta(days=50)]) - await client.header.int32_seconds(duration=36) - await client.header.float_seconds(duration=35.625) - await client.header.float64_seconds(duration=35.625) diff --git a/packages/typespec-python/tests/mock_api/unbranded/asynctests/test_encode_numeric_async.py b/packages/typespec-python/tests/mock_api/unbranded/asynctests/test_encode_numeric_async.py deleted file mode 100644 index 19e4f619f2..0000000000 --- a/packages/typespec-python/tests/mock_api/unbranded/asynctests/test_encode_numeric_async.py +++ /dev/null @@ -1,35 +0,0 @@ -# ------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for -# license information. -# -------------------------------------------------------------------------- -import pytest -from encode.numeric.aio import NumericClient -from encode.numeric.property import models - - -@pytest.fixture -async def client(): - async with NumericClient() as client: - yield client - - -@pytest.mark.asyncio -async def test_safeint_as_string(client: NumericClient): - result = await client.property.safeint_as_string(models.SafeintAsStringProperty(value=10000000000)) - assert result.value == 10000000000 - assert result["value"] == "10000000000" - - -@pytest.mark.asyncio -async def test_uint32_as_string_optional(client: NumericClient): - result = await client.property.uint32_as_string_optional(models.Uint32AsStringProperty(value=1)) - assert result.value == 1 - assert result["value"] == "1" - - -@pytest.mark.asyncio -async def test_uint8_as_string_optional(client: NumericClient): - result = await client.property.uint8_as_string(models.Uint32AsStringProperty(value=255)) - assert result.value == 255 - assert result["value"] == "255" diff --git a/packages/typespec-python/tests/mock_api/unbranded/asynctests/test_parameters_basic_async.py b/packages/typespec-python/tests/mock_api/unbranded/asynctests/test_parameters_basic_async.py deleted file mode 100644 index 81a0deecdd..0000000000 --- a/packages/typespec-python/tests/mock_api/unbranded/asynctests/test_parameters_basic_async.py +++ /dev/null @@ -1,24 +0,0 @@ -# ------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for -# license information. -# -------------------------------------------------------------------------- -import pytest -from parameters.basic.aio import BasicClient -from parameters.basic.explicitbody.models import User - - -@pytest.fixture -async def client(): - async with BasicClient() as client: - yield client - - -@pytest.mark.asyncio -async def test_explicit_simple(client: BasicClient): - await client.explicit_body.simple(User(name="foo")) - - -@pytest.mark.asyncio -async def test_implicit_simple(client: BasicClient): - await client.implicit_body.simple(name="foo") diff --git a/packages/typespec-python/tests/mock_api/unbranded/asynctests/test_parameters_spread_async.py b/packages/typespec-python/tests/mock_api/unbranded/asynctests/test_parameters_spread_async.py deleted file mode 100644 index 89f3cec481..0000000000 --- a/packages/typespec-python/tests/mock_api/unbranded/asynctests/test_parameters_spread_async.py +++ /dev/null @@ -1,76 +0,0 @@ -# ------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for -# license information. -# -------------------------------------------------------------------------- -import pytest -from parameters.spread.aio import SpreadClient -from parameters.spread.model.models import BodyParameter - - -@pytest.fixture -async def client(): - async with SpreadClient() as client: - yield client - - -@pytest.mark.asyncio -async def test_model_body(client: SpreadClient): - await client.model.spread_as_request_body(name="foo") - - -@pytest.mark.asyncio -async def test_model_composite_request_only_with_body(client: SpreadClient): - await client.model.spread_composite_request_only_with_body(BodyParameter(name="foo")) - - -@pytest.mark.asyncio -async def test_model_composite_request_without_body(client: SpreadClient): - await client.model.spread_composite_request_without_body(name="foo", test_header="bar") - - -@pytest.mark.asyncio -async def test_model_composite_request(client: SpreadClient): - await client.model.spread_composite_request(name="foo", body=BodyParameter(name="foo"), test_header="bar") - - -@pytest.mark.asyncio -async def test_model_composite_request_mix(client: SpreadClient): - await client.model.spread_composite_request_mix(name="foo", prop="foo", test_header="bar") - - -@pytest.mark.asyncio -async def test_alias_body(client: SpreadClient): - await client.alias.spread_as_request_body(name="foo") - - -@pytest.mark.asyncio -async def test_alias_parameter(client: SpreadClient): - await client.alias.spread_as_request_parameter("1", x_ms_test_header="bar", name="foo") - - -@pytest.mark.asyncio -async def test_alias_multiple_parameter(client: SpreadClient): - await client.alias.spread_with_multiple_parameters( - "1", - x_ms_test_header="bar", - required_string="foo", - required_int_list=[1, 2], - optional_string_list=["foo", "bar"], - optional_int=1, - ) - await client.alias.spread_with_multiple_parameters( - "1", - {"requiredString": "foo", "optionalInt": 1, "requiredIntList": [1, 2], "optionalStringList": ["foo", "bar"]}, - x_ms_test_header="bar", - ) - - -@pytest.mark.asyncio -async def test_inner_model(client: SpreadClient): - await client.alias.spread_parameter_with_inner_model(id="1", x_ms_test_header="bar", body={"name": "foo"}) - - -@pytest.mark.asyncio -async def test_inner_alias(client: SpreadClient): - await client.alias.spread_parameter_with_inner_alias(id="1", x_ms_test_header="bar", body={"name": "foo", "age": 1}) diff --git a/packages/typespec-python/tests/mock_api/unbranded/asynctests/test_payload_content_negotiation_async.py b/packages/typespec-python/tests/mock_api/unbranded/asynctests/test_payload_content_negotiation_async.py deleted file mode 100644 index 27db476d9c..0000000000 --- a/packages/typespec-python/tests/mock_api/unbranded/asynctests/test_payload_content_negotiation_async.py +++ /dev/null @@ -1,37 +0,0 @@ -# ------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for -# license information. -# -------------------------------------------------------------------------- -import base64 -import pytest -from payload.contentnegotiation.aio import ContentNegotiationClient -from payload.contentnegotiation.differentbody.models import PngImageAsJson - - -@pytest.fixture -async def client(): - async with ContentNegotiationClient(endpoint="http://localhost:3000") as client: - yield client - - -@pytest.mark.asyncio -async def test_get_avatar_as_png(client: ContentNegotiationClient, png_data: bytes): - assert b"".join([d async for d in (await client.same_body.get_avatar_as_png())]) == png_data - - -@pytest.mark.asyncio -async def test_get_avatar_as_jpeg(client: ContentNegotiationClient, jpg_data: bytes): - assert b"".join([d async for d in (await client.same_body.get_avatar_as_jpeg())]) == jpg_data - - -@pytest.mark.asyncio -async def test_different_body_get_avatar_as_png(client: ContentNegotiationClient, png_data: bytes): - assert b"".join([d async for d in (await client.different_body.get_avatar_as_png())]) == png_data - - -@pytest.mark.asyncio -async def test_different_body_get_avatar_as_json(client: ContentNegotiationClient, png_data: bytes): - result = await client.different_body.get_avatar_as_json() - expected = PngImageAsJson(content=base64.b64encode(png_data).decode()) - assert result == expected diff --git a/packages/typespec-python/tests/mock_api/unbranded/asynctests/test_payload_multipart_async.py b/packages/typespec-python/tests/mock_api/unbranded/asynctests/test_payload_multipart_async.py deleted file mode 100644 index 4a1a6a9ced..0000000000 --- a/packages/typespec-python/tests/mock_api/unbranded/asynctests/test_payload_multipart_async.py +++ /dev/null @@ -1,218 +0,0 @@ -# ------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for -# license information. -# -------------------------------------------------------------------------- -from pathlib import Path -import pytest -from payload.multipart import models -from payload.multipart.aio import MultiPartClient -from payload.multipart.formdata.httpparts.nonstring.models import FloatRequest -from payload.multipart.formdata.file import models as file_models - -JPG = Path(__file__).parent.parent / "data/image.jpg" -PNG = Path(__file__).parent.parent / "data/image.png" - - -@pytest.fixture -async def client(): - async with MultiPartClient(endpoint="http://localhost:3000") as client: - yield client - - -@pytest.mark.asyncio -async def test_anonymous_model(client: MultiPartClient): - await client.form_data.anonymous_model({"profileImage": open(str(JPG), "rb")}) - - -@pytest.mark.asyncio -async def test_basic(client: MultiPartClient): - await client.form_data.basic( - models.MultiPartRequest( - id="123", - profile_image=open(str(JPG), "rb"), - ) - ) - - -@pytest.mark.asyncio -async def test_binary_array_parts(client: MultiPartClient): - await client.form_data.binary_array_parts( - models.BinaryArrayPartsRequest( - id="123", - pictures=[ - open(str(PNG), "rb"), - open(str(PNG), "rb"), - ], - ) - ) - - -@pytest.mark.asyncio -async def test_check_file_name_and_content_type(client: MultiPartClient): - await client.form_data.check_file_name_and_content_type( - models.MultiPartRequest( - id="123", - profile_image=("hello.jpg", open(str(JPG), "rb"), "image/jpg"), - ) - ) - - -@pytest.mark.asyncio -async def test_complex(client: MultiPartClient): - await client.form_data.file_array_and_basic( - models.ComplexPartsRequest( - id="123", - address=models.Address(city="X"), - pictures=[ - open(str(PNG), "rb"), - open(str(PNG), "rb"), - ], - profile_image=open(str(JPG), "rb"), - ) - ) - - -@pytest.mark.asyncio -async def test_json_part(client: MultiPartClient): - await client.form_data.json_part( - models.JsonPartRequest( - address=models.Address(city="X"), - profile_image=open(str(JPG), "rb"), - ) - ) - - -@pytest.mark.asyncio -async def test_multi_binary_parts(client: MultiPartClient): - await client.form_data.multi_binary_parts( - models.MultiBinaryPartsRequest( - profile_image=open(str(JPG), "rb"), - picture=open(str(PNG), "rb"), - ) - ) - await client.form_data.multi_binary_parts( - models.MultiBinaryPartsRequest( - profile_image=open(str(JPG), "rb"), - ) - ) - - -@pytest.mark.asyncio -async def test_file_with_http_part_specific_content_type(client: MultiPartClient): - await client.form_data.http_parts.content_type.image_jpeg_content_type( - models.FileWithHttpPartSpecificContentTypeRequest( - profile_image=("hello.jpg", open(str(JPG), "rb"), "image/jpg"), - ) - ) - - -@pytest.mark.asyncio -async def test_file_with_http_part_required_content_type(client: MultiPartClient): - await client.form_data.http_parts.content_type.required_content_type( - models.FileWithHttpPartRequiredContentTypeRequest( - profile_image=open(str(JPG), "rb"), - ) - ) - - -@pytest.mark.asyncio -async def test_file_with_http_part_optional_content_type(client: MultiPartClient): - # call twice: one with content type, one without - await client.form_data.http_parts.content_type.optional_content_type( - models.FileWithHttpPartOptionalContentTypeRequest( - profile_image=("hello.jpg", open(str(JPG), "rb").read()), - ) - ) - await client.form_data.http_parts.content_type.optional_content_type( - models.FileWithHttpPartOptionalContentTypeRequest( - profile_image=("hello.jpg", open(str(JPG), "rb").read(), "application/octet-stream"), - ) - ) - - -@pytest.mark.asyncio -async def test_complex_with_http_part(client: MultiPartClient): - await client.form_data.http_parts.json_array_and_file_array( - models.ComplexHttpPartsModelRequest( - id="123", - previous_addresses=[ - models.Address(city="Y"), - models.Address(city="Z"), - ], - address=models.Address(city="X"), - pictures=[ - open(str(PNG), "rb"), - open(str(PNG), "rb"), - ], - profile_image=open(str(JPG), "rb"), - ) - ) - - -@pytest.mark.asyncio -async def test_http_parts_non_string_float(client: MultiPartClient): - await client.form_data.http_parts.non_string.float(FloatRequest(temperature=0.5)) - - -@pytest.mark.asyncio -async def test_with_wire_name(client: MultiPartClient): - await client.form_data.with_wire_name( - models.MultiPartRequestWithWireName( - identifier="123", - image=open(str(JPG), "rb"), - ) - ) - - -@pytest.mark.asyncio -async def test_optional_parts(client: MultiPartClient): - # First time with only id - await client.form_data.optional_parts( - models.MultiPartOptionalRequest( - id="123", - ) - ) - # Second time with only profileImage - await client.form_data.optional_parts( - models.MultiPartOptionalRequest( - profile_image=open(str(JPG), "rb"), - ) - ) - # Third time with both id and profileImage - await client.form_data.optional_parts( - models.MultiPartOptionalRequest( - id="123", - profile_image=open(str(JPG), "rb"), - ) - ) - - -@pytest.mark.asyncio -async def test_file_upload_file_specific_content_type(client: MultiPartClient): - await client.form_data.file.upload_file_specific_content_type( - file_models.UploadFileSpecificContentTypeRequest( - file=("image.png", open(str(PNG), "rb"), "image/png"), - ) - ) - - -@pytest.mark.asyncio -async def test_file_upload_file_required_filename(client: MultiPartClient): - await client.form_data.file.upload_file_required_filename( - file_models.UploadFileRequiredFilenameRequest( - file=("image.png", open(str(PNG), "rb"), "image/png"), - ) - ) - - -@pytest.mark.asyncio -async def test_file_upload_file_array(client: MultiPartClient): - await client.form_data.file.upload_file_array( - file_models.UploadFileArrayRequest( - files=[ - ("image.png", open(str(PNG), "rb"), "image/png"), - ("image.png", open(str(PNG), "rb"), "image/png"), - ], - ) - ) diff --git a/packages/typespec-python/tests/mock_api/unbranded/asynctests/test_serialization_encoded_name_json_async.py b/packages/typespec-python/tests/mock_api/unbranded/asynctests/test_serialization_encoded_name_json_async.py deleted file mode 100644 index 7234c7e253..0000000000 --- a/packages/typespec-python/tests/mock_api/unbranded/asynctests/test_serialization_encoded_name_json_async.py +++ /dev/null @@ -1,24 +0,0 @@ -# ------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for -# license information. -# -------------------------------------------------------------------------- -import pytest -from serialization.encodedname.json.aio import JsonClient -from serialization.encodedname.json.property import models - - -@pytest.fixture -async def client(): - async with JsonClient() as client: - yield client - - -@pytest.mark.asyncio -async def test_property_send(client: JsonClient): - await client.property.send(models.JsonEncodedNameModel(default_name=True)) - - -@pytest.mark.asyncio -async def test_property_get(client: JsonClient): - assert (await client.property.get()).default_name diff --git a/packages/typespec-python/tests/mock_api/unbranded/asynctests/test_special_words_async.py b/packages/typespec-python/tests/mock_api/unbranded/asynctests/test_special_words_async.py deleted file mode 100644 index 112533fa2d..0000000000 --- a/packages/typespec-python/tests/mock_api/unbranded/asynctests/test_special_words_async.py +++ /dev/null @@ -1,73 +0,0 @@ -# ------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for -# license information. -# -------------------------------------------------------------------------- -import pytest -from specialwords.aio import SpecialWordsClient -from specialwords.models import models -from specialwords.modelproperties import models as model_properties_models -from specialwords.extensiblestrings import models as extensible_strings_models - - -@pytest.fixture -async def client(): - async with SpecialWordsClient() as client: - yield client - - -@pytest.mark.asyncio -async def test_operations(client: SpecialWordsClient, special_words): - for sw in special_words: - suffix = "" if sw == "constructor" else "_method" - await getattr(client.operations, sw + suffix)() - - -@pytest.mark.asyncio -async def test_parameter(client: SpecialWordsClient, special_words): - for sw in special_words: - suffix = "" if sw == "constructor" else "_parameter" - await getattr(client.parameters, "with_" + sw)(**{sw + suffix: "ok"}) - await client.parameters.with_cancellation_token(cancellation_token="ok") - - -@pytest.mark.asyncio -async def test_model(client: SpecialWordsClient, special_words): - for sw in special_words: - suffix = "" if sw == "constructor" else "Model" - model = getattr(models, sw.capitalize() + suffix) - await getattr(client.models, "with_" + sw)(model(name="ok")) - - -@pytest.mark.asyncio -async def test_model_properties(client: SpecialWordsClient): - await client.model_properties.same_as_model(model_properties_models.SameAsModel(same_as_model="ok")) - - -@pytest.mark.asyncio -async def test_model_properties_dict_methods(client: SpecialWordsClient): - await client.model_properties.dict_methods( - body=model_properties_models.DictMethods( - keys_property="ok", - items_property="ok", - values_property="ok", - popitem_property="ok", - clear_property="ok", - update_property="ok", - setdefault_property="ok", - pop_property="ok", - get_property="ok", - copy_property="ok", - ) - ) - - -@pytest.mark.asyncio -async def test_model_properties_with_list(client: SpecialWordsClient): - await client.model_properties.with_list(model_properties_models.ModelWithList(list="ok")) - - -@pytest.mark.asyncio -async def test_extensible_strings(client: SpecialWordsClient): - for enum_value in extensible_strings_models.ExtensibleString: - assert enum_value == await client.extensible_strings.put_extensible_string_value(body=enum_value) diff --git a/packages/typespec-python/tests/mock_api/unbranded/asynctests/test_unbranded_async.py b/packages/typespec-python/tests/mock_api/unbranded/asynctests/test_unbranded_async.py deleted file mode 100644 index 139d323cf3..0000000000 --- a/packages/typespec-python/tests/mock_api/unbranded/asynctests/test_unbranded_async.py +++ /dev/null @@ -1,27 +0,0 @@ -# ------------------------------------ -# Copyright (c) Microsoft Corporation. -# Licensed under the MIT License. -# ------------------------------------ -import traceback -import pytest -from typetest.scalar.aio import ScalarClient -from corehttp.exceptions import HttpResponseError - - -@pytest.fixture -async def client(): - async with ScalarClient() as client: - yield client - - -@pytest.mark.asyncio -async def test_track_back(client: ScalarClient): - try: - await client.string.put("to raise exception") - except HttpResponseError: - track_back = traceback.format_exc().lower() - # Filter out file path lines (contain repo path which may include "azure"/"microsoft") - lines = [line for line in track_back.split("\n") if not line.strip().startswith("file ")] - filtered = "\n".join(lines) - assert "azure" not in filtered - assert "microsoft" not in filtered diff --git a/packages/typespec-python/tests/mock_api/unbranded/conftest.py b/packages/typespec-python/tests/mock_api/unbranded/conftest.py deleted file mode 100644 index a94535b690..0000000000 --- a/packages/typespec-python/tests/mock_api/unbranded/conftest.py +++ /dev/null @@ -1,53 +0,0 @@ -# ------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for -# license information. -# -------------------------------------------------------------------------- -# Unbranded-specific fixtures -# Common fixtures (testserver, core_library, key_credential, png_data, jpg_data) -# are inherited from the root tests/conftest.py - -import pytest -from typing import List - - -SPECIAL_WORDS = [ - "and", - "as", - "assert", - "async", - "await", - "break", - "class", - "constructor", - "continue", - "def", - "del", - "elif", - "else", - "except", - "exec", - "finally", - "for", - "from", - "global", - "if", - "import", - "in", - "is", - "lambda", - "not", - "or", - "pass", - "raise", - "return", - "try", - "while", - "with", - "yield", -] - - -@pytest.fixture -def special_words() -> List[str]: - return SPECIAL_WORDS diff --git a/packages/typespec-python/tests/mock_api/unbranded/data/image.jpg b/packages/typespec-python/tests/mock_api/unbranded/data/image.jpg deleted file mode 100644 index b95b3e7b58286ad3e665d98d48b345977f862403..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4069 zcmeHJX;@QN8a_8Gn*#{~QJ4uNv1G6$BrHN6AVrn}mbL^3a4V7!OhA&51QRm!5kx@+ zTNcGZ6cC$Q+;~`GASla}wUxz{#c@GKXr)k4Y@<*!Hx%*D{OB`(hxgoj&v(xGzVDv* zyZ1cLYZx{>23FxAVIcs504RVPFpPlD9#xbBu1V2)YXM|gXB#0R#?0;vho@Ai`n{4K2Z_tc-vVNE8}_H8C|ahaEIl00AM92ow^HM!{MR`W#*d zC>$E^#0bDxN5*4GscV^8g=bC3n`_%`I5%f0?p)~sQ!`sT!n*Yv-gBn@)y2cpYm>JR zD=;WH4t_4#kAFVxjHXs&7-n{@yDwxhGFyQlZNTet7ry*D&GGCKBT{NGO}CV%+x+1&FN z^Dlq-RsZU>kryl_f2RdM|0^#X%nN}+AyHT(F9@M9633y?P7Dk_AQBs&YE5EhnXKJh zc(%6PlpPs~<`z2kKs1OmhoPzVGH-Zu)3MZ>_F zVvR60H(i4HGS)1?$_V@l3~&{b9rK09ND}!zi#oLh#Ro!~r%~ ztf@M>v0>6|AHFNXRdW{F2PwyE*zd{a+%36uhi4yu9aJ^ zpE7`9t8Rioz2KlN=S`ybbp-7ElQg->VN&I!l@n$S;9H_)yZXl$&PTX9ZObWvjhcE$f>gQt?~wSk)wt*@QfJ9e zFelD#>m0AB_sUj(c%Hr(E_yV;phB&=i9g9-)lO~OzQ2==_`u&bT{~<52lxK#Ow_NO zH{&-1-x&aQ;LQ0M(Zy$<1nTsq)xvVR{*&=ztX;IOz6|@z-F$Uf=(W0nyex6{P>FpW z4;0_dipualIew@$bH3M?aaJh~zSVba_s(ZYwY`7uX0rQ=C{sn1g*}wrL&Zt0cwal& z|(+)A&#XhLRoSPH3mt4Ji?-$~1F~yma)AnXu zRaaV$2SjEq$b{PVCY+v+iL;w8BOWVxgqdDst2gCLzog0=vM#q5L^ScNF_ipEjeb6n z1J0h4Y=S>iPa2P#Wgqq@^xWzm>-n^78z*$sXAucKo}EO|0uu3 zLs)^AUypvJF<+QUj|p5L&+NFzk0eJN%fi)?Gy8fd4jBz;gBAkjn_MPYks`G3a33&nP_o zg=l|nT>VF<@}|PZtIypU-TXbb#NA#UwTKA877jAo-sRoA;|O7M!oq~_ndaKA)cm{QH_jPuzCA+J zs!aHNWSYHBYfaj3>w14Gdb?$=t7cDh+;r%rP@Vlr;qGatS1nE0#?Fk+V2@G6gWq0G nRDbTJ{wDPH&YhvRw~$ZQH=nuD@w!Nwq+ZJbRY$2v!^nRCgjEVM diff --git a/packages/typespec-python/tests/mock_api/unbranded/data/image.png b/packages/typespec-python/tests/mock_api/unbranded/data/image.png deleted file mode 100644 index 42fe8dc14560b0046bf0f3f00b7a471fa0346e36..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2992 zcmaJ>2UJtr5=}ynfPe^6#i)oP2~A3b_#j9P<c=;9z@urf$wEd&r0Smmc~ z4b}n)eX~PAprkO6@Q)ZL0M}MJAZwiOD16}zNDSD?0g_k*{=o$NMUbCNY?07U9S+2S zEZop`b^yBJDZ#-+YAA`O;C(9uFi4PXy{I6N!uB-*+qrI=1#0z#xnpTqM+_2ABESQJ zNP)p{I)S{F2V_P^0xBVx7N9{V941ncbaU9Z2qd7dnGrCJZy~e@a~RgqMFUNu1Zx<< zb>X@&6jVb)!;BJi2rs64KWLg-BsIiteAdnPEGl#*}3jJK)-!qsV_Nx++`r}x@ z0TF8+gdSWM@iR9-HCwYHUBc+WhrO)A2tdz(8Yn{}vv1-5tZHzM{I(Zu9;;%|=s zCVEhVDQFS_C`d#7x~w1M-<>~*W{9LqLSH=UG`#0SvISvT&z^Cv#7@xJSx2aa-|9tm}-z6Hc>u#KDm+I4F>M3G9RmW+_?M2)1;gWo3xcVR@W8PHPH4h8*{++h z8}Y5F9`(=WPeZXH<+|Y0gJnwP5YL?0zo!3|^aN{T{s{OKE?O45QM0I0;1yDN`SND{ zyOg5mp)N5c(u0Esp-E=kfllR0C&k1s@i0GrZRfs5<7!+x0s^%ugM8%*ef;#PiEVR~ zk~180fRXw!|2qMhFy2QQNA)X#rKKLKFql@YS0DB+8Y~M0L6l6MBxAd5adGjcF9c8t zo3^yHG!i%{(t~?+_KjG%t?wg9W@hGn@>d^2zlX4eDsq69+{GOYhow*ZZ9YFY+;qgj z#AWZ^z2xho`YaYJ$mptuez>fhT&9eIf;49^mEC)&XN9ajcTsqPhD7C%d`TOUID=@6 zW~%vaGf31w{D~F5LO*H9Ul5b;M$_L~@5Rf{$YXmij@GSqZ($ztNsv;Z`i@;wgI)yL z`tVD3-D4YatT^h!2`{f7xgFBk(KVv6D=iyOe>q)Zxtu3f1vhZeoRRfQZ3s>DQ~|{c zhLZ7j^pqm{@Kbe|+)KiSAs)dZlW4Rb|0>x!mf7eaT?yRGZFm;h)5lP}0s z)MR+lRu=;7XofSxFZS5kB(Io?U<4$)=j+Ujv-f1z7}jT(U8oBF@c2?YjHZlX3}y?2 zB}I!j)%5LcxOt457x{YKwWQLqjkl*P!m*TD-H`cTuN{_G`e(Occ-dLa=;vA%@*AOg(a(z}6t_crT&EO-&+m4gF>N0h;BXG0?{Bi7 z`CMs0?IQEIN_yrvkTId}4tcQlLFDsm2){A5T)eb!$m;U*9bpNnS{u9Nur=c6{IY zKC28T*@~?E=+fvG1A<0jF;cm0Q(bSl;8d`tTUme#<>4g zLGy3~(+z4auzTu_$wj7=5_bmr4M3i>XprZ8-8A{ z^S%T(i(@^t7G<(wYTc~P^uFuDm}iOCg0RJbylL{6l)E9&xd*ipG|e`)b?b`n)|`3$ z>k`idS@_lp+*>nk7_W2qvLHrYsnN9VjcdkaYxRqWdf5!mZ8vsD^2e%lG>7`oaP1~( z91eF(@?7&4^jE^(0w>-(Xig#TL8J;KX+2YL&fdmGjCA1!I<+uYch0=ri`kM?G=Uz= zYe(%m$g6gpfYRA}M3Wh=PjV`BA|f`Ajz1QY-KfS$+mLC&=*M@CqU0@-843#@s!tp+ z`hXG_$T+w$%ZRc;oA!hozBo{U_AgR)cc2=ist%Tf1!goyZ`H}XSr9&UY zJ^9hCDY9E_U|L$j^3{t+O$rDP^WqxkQ)&F;Eh@Hsx^<};S#~>%t}R_YRkG7OjOT7s&BTd5F;H{&a{d!BS5Vz@RgwkT{dwhcQ zPGno6OlTdu0KU{d<)>5lyi9d5Rz$1ros^mpW_coXd{r;;5w~?!YUHbE$=hL2`F`si x55d?S>E1-idha0G3zgVNNXgr$|KG8qZJn`L2pQ~%2Sy6WZoiY&ZA<_7e*r@k8!Z3; diff --git a/packages/typespec-python/tests/mock_api/unbranded/test_auth_flow.py b/packages/typespec-python/tests/mock_api/unbranded/test_auth_flow.py deleted file mode 100644 index 4aa857b020..0000000000 --- a/packages/typespec-python/tests/mock_api/unbranded/test_auth_flow.py +++ /dev/null @@ -1,17 +0,0 @@ -# ------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for -# license information. -# -------------------------------------------------------------------------- -from authentication.oauth2 import OAuth2Client - - -def test_oauth2_auth_flows(): - oauth2_client = OAuth2Client("fake_credential") - assert oauth2_client._config.authentication_policy._auth_flows == [ - { - "authorizationUrl": "https://login.microsoftonline.com/common/oauth2/authorize", - "scopes": [{"value": "https://security.microsoft.com/.default"}], - "type": "implicit", - } - ] diff --git a/packages/typespec-python/tests/mock_api/unbranded/test_encode_duration.py b/packages/typespec-python/tests/mock_api/unbranded/test_encode_duration.py deleted file mode 100644 index 6025a3670d..0000000000 --- a/packages/typespec-python/tests/mock_api/unbranded/test_encode_duration.py +++ /dev/null @@ -1,60 +0,0 @@ -# ------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for -# license information. -# -------------------------------------------------------------------------- -import datetime - -import pytest -from encode.duration import DurationClient -from encode.duration.property.models import ( - Int32SecondsDurationProperty, - ISO8601DurationProperty, - FloatSecondsDurationProperty, - DefaultDurationProperty, - FloatSecondsDurationArrayProperty, -) - - -@pytest.fixture -def client(): - with DurationClient() as client: - yield client - - -def test_query(client: DurationClient): - client.query.default(input=datetime.timedelta(days=40)) - client.query.iso8601(input=datetime.timedelta(days=40)) - client.query.int32_seconds(input=36) - client.query.int32_seconds_array(input=[36, 47]) - client.query.float_seconds(input=35.625) - client.query.float64_seconds(input=35.625) - - -def test_property(client: DurationClient): - result = client.property.default(DefaultDurationProperty(value=datetime.timedelta(days=40))) - assert result.value == datetime.timedelta(days=40) - result = client.property.default(DefaultDurationProperty(value="P40D")) - assert result.value == datetime.timedelta(days=40) - result = client.property.iso8601(ISO8601DurationProperty(value=datetime.timedelta(days=40))) - assert result.value == datetime.timedelta(days=40) - result = client.property.iso8601(ISO8601DurationProperty(value="P40D")) - assert result.value == datetime.timedelta(days=40) - result = client.property.int32_seconds(Int32SecondsDurationProperty(value=36)) - assert result.value == 36 - result = client.property.float_seconds(FloatSecondsDurationProperty(value=35.625)) - assert abs(result.value - 35.625) < 0.0001 - result = client.property.float64_seconds(FloatSecondsDurationProperty(value=35.625)) - assert abs(result.value - 35.625) < 0.0001 - result = client.property.float_seconds_array(FloatSecondsDurationArrayProperty(value=[35.625, 46.75])) - assert abs(result.value[0] - 35.625) < 0.0001 - assert abs(result.value[1] - 46.75) < 0.0001 - - -def test_header(client: DurationClient): - client.header.default(duration=datetime.timedelta(days=40)) - client.header.iso8601(duration=datetime.timedelta(days=40)) - client.header.iso8601_array(duration=[datetime.timedelta(days=40), datetime.timedelta(days=50)]) - client.header.int32_seconds(duration=36) - client.header.float_seconds(duration=35.625) - client.header.float64_seconds(duration=35.625) diff --git a/packages/typespec-python/tests/mock_api/unbranded/test_encode_numeric.py b/packages/typespec-python/tests/mock_api/unbranded/test_encode_numeric.py deleted file mode 100644 index cf5468ef89..0000000000 --- a/packages/typespec-python/tests/mock_api/unbranded/test_encode_numeric.py +++ /dev/null @@ -1,32 +0,0 @@ -# ------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for -# license information. -# -------------------------------------------------------------------------- -import pytest -from encode.numeric import NumericClient -from encode.numeric.property import models - - -@pytest.fixture -def client(): - with NumericClient() as client: - yield client - - -def test_safeint_as_string(client: NumericClient): - result = client.property.safeint_as_string(models.SafeintAsStringProperty(value=10000000000)) - assert result.value == 10000000000 - assert result["value"] == "10000000000" - - -def test_uint32_as_string_optional(client: NumericClient): - result = client.property.uint32_as_string_optional(models.Uint32AsStringProperty(value=1)) - assert result.value == 1 - assert result["value"] == "1" - - -def test_uint8_as_string_optional(client: NumericClient): - result = client.property.uint8_as_string(models.Uint32AsStringProperty(value=255)) - assert result.value == 255 - assert result["value"] == "255" diff --git a/packages/typespec-python/tests/mock_api/unbranded/test_parameters_basic.py b/packages/typespec-python/tests/mock_api/unbranded/test_parameters_basic.py deleted file mode 100644 index c6e82422e0..0000000000 --- a/packages/typespec-python/tests/mock_api/unbranded/test_parameters_basic.py +++ /dev/null @@ -1,22 +0,0 @@ -# ------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for -# license information. -# -------------------------------------------------------------------------- -import pytest -from parameters.basic import BasicClient -from parameters.basic.explicitbody.models import User - - -@pytest.fixture -def client(): - with BasicClient() as client: - yield client - - -def test_explicit_simple(client: BasicClient): - client.explicit_body.simple(User(name="foo")) - - -def test_implicit_simple(client: BasicClient): - client.implicit_body.simple(name="foo") diff --git a/packages/typespec-python/tests/mock_api/unbranded/test_parameters_spread.py b/packages/typespec-python/tests/mock_api/unbranded/test_parameters_spread.py deleted file mode 100644 index ff649a40ed..0000000000 --- a/packages/typespec-python/tests/mock_api/unbranded/test_parameters_spread.py +++ /dev/null @@ -1,66 +0,0 @@ -# ------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for -# license information. -# -------------------------------------------------------------------------- -import pytest -from parameters.spread import SpreadClient -from parameters.spread.model.models import BodyParameter - - -@pytest.fixture -def client(): - with SpreadClient() as client: - yield client - - -def test_model_body(client: SpreadClient): - client.model.spread_as_request_body(name="foo") - - -def test_model_composite_request_only_with_body(client: SpreadClient): - client.model.spread_composite_request_only_with_body(BodyParameter(name="foo")) - - -def test_model_composite_request_without_body(client: SpreadClient): - client.model.spread_composite_request_without_body(name="foo", test_header="bar") - - -def test_model_composite_request(client: SpreadClient): - client.model.spread_composite_request(name="foo", body=BodyParameter(name="foo"), test_header="bar") - - -def test_model_composite_request_mix(client: SpreadClient): - client.model.spread_composite_request_mix(name="foo", prop="foo", test_header="bar") - - -def test_alias_body(client: SpreadClient): - client.alias.spread_as_request_body(name="foo") - - -def test_alias_parameter(client: SpreadClient): - client.alias.spread_as_request_parameter("1", x_ms_test_header="bar", name="foo") - - -def test_alias_multiple_parameter(client: SpreadClient): - client.alias.spread_with_multiple_parameters( - "1", - x_ms_test_header="bar", - required_string="foo", - required_int_list=[1, 2], - optional_string_list=["foo", "bar"], - optional_int=1, - ) - client.alias.spread_with_multiple_parameters( - "1", - {"requiredString": "foo", "optionalInt": 1, "requiredIntList": [1, 2], "optionalStringList": ["foo", "bar"]}, - x_ms_test_header="bar", - ) - - -def test_inner_model(client: SpreadClient): - client.alias.spread_parameter_with_inner_model(id="1", x_ms_test_header="bar", body={"name": "foo"}) - - -def test_inner_alias(client: SpreadClient): - client.alias.spread_parameter_with_inner_alias(id="1", x_ms_test_header="bar", body={"name": "foo", "age": 1}) diff --git a/packages/typespec-python/tests/mock_api/unbranded/test_payload_content_negotiation.py b/packages/typespec-python/tests/mock_api/unbranded/test_payload_content_negotiation.py deleted file mode 100644 index e683de73a0..0000000000 --- a/packages/typespec-python/tests/mock_api/unbranded/test_payload_content_negotiation.py +++ /dev/null @@ -1,33 +0,0 @@ -# ------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for -# license information. -# -------------------------------------------------------------------------- -import base64 -import pytest -from payload.contentnegotiation import ContentNegotiationClient -from payload.contentnegotiation.differentbody.models import PngImageAsJson - - -@pytest.fixture -def client(): - with ContentNegotiationClient(endpoint="http://localhost:3000") as client: - yield client - - -def test_get_avatar_as_png(client: ContentNegotiationClient, png_data: bytes): - assert b"".join(client.same_body.get_avatar_as_png()) == png_data - - -def test_get_avatar_as_jpeg(client: ContentNegotiationClient, jpg_data: bytes): - assert b"".join(client.same_body.get_avatar_as_jpeg()) == jpg_data - - -def test_different_body_get_avatar_as_png(client: ContentNegotiationClient, png_data: bytes): - assert b"".join(client.different_body.get_avatar_as_png()) == png_data - - -def test_different_body_get_avatar_as_json(client: ContentNegotiationClient, png_data: bytes): - result = client.different_body.get_avatar_as_json() - expected = PngImageAsJson(content=base64.b64encode(png_data).decode()) - assert result == expected diff --git a/packages/typespec-python/tests/mock_api/unbranded/test_payload_multipart.py b/packages/typespec-python/tests/mock_api/unbranded/test_payload_multipart.py deleted file mode 100644 index f4cba4ec27..0000000000 --- a/packages/typespec-python/tests/mock_api/unbranded/test_payload_multipart.py +++ /dev/null @@ -1,200 +0,0 @@ -# ------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for -# license information. -# -------------------------------------------------------------------------- -from pathlib import Path -import pytest -from payload.multipart import MultiPartClient, models -from payload.multipart.formdata.httpparts.nonstring.models import FloatRequest -from payload.multipart.formdata.file import models as file_models - -JPG = Path(__file__).parent / "data/image.jpg" -PNG = Path(__file__).parent / "data/image.png" - - -@pytest.fixture -def client(): - with MultiPartClient(endpoint="http://localhost:3000") as client: - yield client - - -def test_anonymous_model(client: MultiPartClient): - client.form_data.anonymous_model({"profileImage": open(str(JPG), "rb")}) - - -def test_basic(client: MultiPartClient): - client.form_data.basic( - models.MultiPartRequest( - id="123", - profile_image=open(str(JPG), "rb"), - ) - ) - - -def test_binary_array_parts(client: MultiPartClient): - client.form_data.binary_array_parts( - models.BinaryArrayPartsRequest( - id="123", - pictures=[ - open(str(PNG), "rb"), - open(str(PNG), "rb"), - ], - ) - ) - - -def test_check_file_name_and_content_type(client: MultiPartClient): - client.form_data.check_file_name_and_content_type( - models.MultiPartRequest( - id="123", - profile_image=("hello.jpg", open(str(JPG), "rb"), "image/jpg"), - ) - ) - - -def test_complex(client: MultiPartClient): - client.form_data.file_array_and_basic( - models.ComplexPartsRequest( - id="123", - address=models.Address(city="X"), - pictures=[ - open(str(PNG), "rb"), - open(str(PNG), "rb"), - ], - profile_image=open(str(JPG), "rb"), - ) - ) - - -def test_json_part(client: MultiPartClient): - client.form_data.json_part( - models.JsonPartRequest( - address=models.Address(city="X"), - profile_image=open(str(JPG), "rb"), - ) - ) - - -def test_multi_binary_parts(client: MultiPartClient): - client.form_data.multi_binary_parts( - models.MultiBinaryPartsRequest( - profile_image=open(str(JPG), "rb"), - picture=open(str(PNG), "rb"), - ) - ) - client.form_data.multi_binary_parts( - models.MultiBinaryPartsRequest( - profile_image=open(str(JPG), "rb"), - ) - ) - - -def test_file_with_http_part_specific_content_type(client: MultiPartClient): - client.form_data.http_parts.content_type.image_jpeg_content_type( - models.FileWithHttpPartSpecificContentTypeRequest( - profile_image=("hello.jpg", open(str(JPG), "rb"), "image/jpg"), - ) - ) - - -def test_file_with_http_part_required_content_type(client: MultiPartClient): - client.form_data.http_parts.content_type.required_content_type( - models.FileWithHttpPartRequiredContentTypeRequest( - profile_image=open(str(JPG), "rb"), - ) - ) - - -def test_file_with_http_part_optional_content_type(client: MultiPartClient): - # call twice: one with content type, one without - client.form_data.http_parts.content_type.optional_content_type( - models.FileWithHttpPartOptionalContentTypeRequest( - profile_image=("hello.jpg", open(str(JPG), "rb").read()), - ) - ) - client.form_data.http_parts.content_type.optional_content_type( - models.FileWithHttpPartOptionalContentTypeRequest( - profile_image=("hello.jpg", open(str(JPG), "rb").read(), "application/octet-stream"), - ) - ) - - -def test_complex_with_http_part(client: MultiPartClient): - client.form_data.http_parts.json_array_and_file_array( - models.ComplexHttpPartsModelRequest( - id="123", - previous_addresses=[ - models.Address(city="Y"), - models.Address(city="Z"), - ], - address=models.Address(city="X"), - pictures=[ - open(str(PNG), "rb"), - open(str(PNG), "rb"), - ], - profile_image=open(str(JPG), "rb"), - ) - ) - - -def test_http_parts_non_string_float(client: MultiPartClient): - client.form_data.http_parts.non_string.float(FloatRequest(temperature=0.5)) - - -def test_with_wire_name(client: MultiPartClient): - client.form_data.with_wire_name( - models.MultiPartRequestWithWireName( - identifier="123", - image=open(str(JPG), "rb"), - ) - ) - - -def test_optional_parts(client: MultiPartClient): - # First time with only id - client.form_data.optional_parts( - models.MultiPartOptionalRequest( - id="123", - ) - ) - # Second time with only profileImage - client.form_data.optional_parts( - models.MultiPartOptionalRequest( - profile_image=open(str(JPG), "rb"), - ) - ) - # Third time with both id and profileImage - client.form_data.optional_parts( - models.MultiPartOptionalRequest( - id="123", - profile_image=open(str(JPG), "rb"), - ) - ) - - -def test_file_upload_file_specific_content_type(client: MultiPartClient): - client.form_data.file.upload_file_specific_content_type( - file_models.UploadFileSpecificContentTypeRequest( - file=("image.png", open(str(PNG), "rb"), "image/png"), - ) - ) - - -def test_file_upload_file_required_filename(client: MultiPartClient): - client.form_data.file.upload_file_required_filename( - file_models.UploadFileRequiredFilenameRequest( - file=("image.png", open(str(PNG), "rb"), "image/png"), - ) - ) - - -def test_file_upload_file_array(client: MultiPartClient): - client.form_data.file.upload_file_array( - file_models.UploadFileArrayRequest( - files=[ - ("image.png", open(str(PNG), "rb"), "image/png"), - ("image.png", open(str(PNG), "rb"), "image/png"), - ], - ) - ) diff --git a/packages/typespec-python/tests/mock_api/unbranded/test_serialization_encoded_name_json.py b/packages/typespec-python/tests/mock_api/unbranded/test_serialization_encoded_name_json.py deleted file mode 100644 index 8642e94b14..0000000000 --- a/packages/typespec-python/tests/mock_api/unbranded/test_serialization_encoded_name_json.py +++ /dev/null @@ -1,22 +0,0 @@ -# ------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for -# license information. -# -------------------------------------------------------------------------- -import pytest -from serialization.encodedname.json import JsonClient -from serialization.encodedname.json.property import models - - -@pytest.fixture -def client(): - with JsonClient() as client: - yield client - - -def test_property_send(client: JsonClient): - client.property.send(models.JsonEncodedNameModel(default_name=True)) - - -def test_property_get(client: JsonClient): - assert client.property.get().default_name diff --git a/packages/typespec-python/tests/mock_api/unbranded/test_special_words.py b/packages/typespec-python/tests/mock_api/unbranded/test_special_words.py deleted file mode 100644 index 83269cc1e4..0000000000 --- a/packages/typespec-python/tests/mock_api/unbranded/test_special_words.py +++ /dev/null @@ -1,66 +0,0 @@ -# ------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for -# license information. -# -------------------------------------------------------------------------- -import pytest -from specialwords import SpecialWordsClient -from specialwords.models import models -from specialwords.modelproperties import models as model_properties_models -from specialwords.extensiblestrings import models as extensible_strings_models - - -@pytest.fixture -def client(): - with SpecialWordsClient() as client: - yield client - - -def test_operations(client: SpecialWordsClient, special_words): - for sw in special_words: - suffix = "" if sw == "constructor" else "_method" - getattr(client.operations, sw + suffix)() - - -def test_parameter(client: SpecialWordsClient, special_words): - for sw in special_words: - suffix = "" if sw == "constructor" else "_parameter" - getattr(client.parameters, "with_" + sw)(**{sw + suffix: "ok"}) - client.parameters.with_cancellation_token(cancellation_token="ok") - - -def test_model(client: SpecialWordsClient, special_words): - for sw in special_words: - suffix = "" if sw == "constructor" else "Model" - model = getattr(models, sw.capitalize() + suffix) - getattr(client.models, "with_" + sw)(model(name="ok")) - - -def test_model_properties(client: SpecialWordsClient): - client.model_properties.same_as_model(model_properties_models.SameAsModel(same_as_model="ok")) - - -def test_model_properties_dict_methods(client: SpecialWordsClient): - client.model_properties.dict_methods( - body=model_properties_models.DictMethods( - keys_property="ok", - items_property="ok", - values_property="ok", - popitem_property="ok", - clear_property="ok", - update_property="ok", - setdefault_property="ok", - pop_property="ok", - get_property="ok", - copy_property="ok", - ) - ) - - -def test_model_properties_with_list(client: SpecialWordsClient): - client.model_properties.with_list(model_properties_models.ModelWithList(list="ok")) - - -def test_extensible_strings(client: SpecialWordsClient): - for enum_value in extensible_strings_models.ExtensibleString: - assert enum_value == client.extensible_strings.put_extensible_string_value(body=enum_value) diff --git a/packages/typespec-python/tests/mock_api/unbranded/test_unbranded.py b/packages/typespec-python/tests/mock_api/unbranded/test_unbranded.py deleted file mode 100644 index 681d55785a..0000000000 --- a/packages/typespec-python/tests/mock_api/unbranded/test_unbranded.py +++ /dev/null @@ -1,59 +0,0 @@ -# ------------------------------------ -# Copyright (c) Microsoft Corporation. -# Licensed under the MIT License. -# ------------------------------------ -import os -import re -from subprocess import getoutput -from pathlib import Path -import traceback -from importlib import import_module -import pytest -from typetest.scalar import ScalarClient -from corehttp.exceptions import HttpResponseError - - -@pytest.fixture -def client(): - with ScalarClient() as client: - yield client - - -def test_module(): - with pytest.raises(ModuleNotFoundError): - import_module("azure") - - -def test_track_back(client: ScalarClient): - try: - client.string.put("to raise exception") - except HttpResponseError: - track_back = traceback.format_exc().lower() - # Filter out file path lines (contain repo path which may include "azure"/"microsoft") - lines = [line for line in track_back.split("\n") if not line.strip().startswith("file ")] - filtered = "\n".join(lines) - assert "azure" not in filtered - assert "microsoft" not in filtered - - -def check_sensitive_word(folder: Path, word: str) -> str: - special_folders = ["__pycache__", "pytest_cache"] - if os.name == "nt": - skip_folders = "|".join(special_folders) - output = getoutput( - f"powershell \"ls -r -Path {folder} | where fullname -notmatch '{skip_folders}' | Select-String -Pattern '{word}'\"" - ).replace("\\", "/") - else: - skip_folders = "{" + ",".join(special_folders) + "}" - output = getoutput(f"grep -ri --exclude-dir={skip_folders} {word} {folder}") - - result = set() - for item in re.findall(f"{folder.as_posix()}[^:]+", output.replace("\n", "")): - result.add(Path(item).relative_to(folder).parts[0]) - return sorted(list(result)) - - -def test_sensitive_word(): - """Verify unbranded generated code doesn't contain Azure-specific branding.""" - check_folder = (Path(os.path.dirname(__file__)) / "../../generated/unbranded").resolve() - assert [] == check_sensitive_word(check_folder, "azure") diff --git a/packages/typespec-python/tests/requirements/azure.txt b/packages/typespec-python/tests/requirements/azure.txt deleted file mode 100644 index 7dd647dfe0..0000000000 --- a/packages/typespec-python/tests/requirements/azure.txt +++ /dev/null @@ -1,5 +0,0 @@ -# Azure SDK dependencies --r base.txt -azure-core>=1.30.0 -azure-mgmt-core>=1.6.0 -geojson>=3.0.0 diff --git a/packages/typespec-python/tests/requirements/base.txt b/packages/typespec-python/tests/requirements/base.txt deleted file mode 100644 index 9331a4a1d8..0000000000 --- a/packages/typespec-python/tests/requirements/base.txt +++ /dev/null @@ -1,12 +0,0 @@ -# Base test dependencies -pytest==8.3.2 -pytest-xdist>=3.5.0 -pytest-asyncio>=0.14.0 -aiohttp -coverage==7.6.1 -colorama==0.4.6 -isodate>=0.6.1 -typing-extensions>=4.6.0 -tox>=4.16.0 -tox-uv>=1.0.0 -filelock>=3.12.0 diff --git a/packages/typespec-python/tests/requirements/docs.txt b/packages/typespec-python/tests/requirements/docs.txt deleted file mode 100644 index 7839a0e726..0000000000 --- a/packages/typespec-python/tests/requirements/docs.txt +++ /dev/null @@ -1,7 +0,0 @@ -# Documentation dependencies --r base.txt -pip -sphinx>=7.0.0 -sphinx_rtd_theme>=2.0.0 -myst_parser>=2.0.0 -sphinxcontrib-jquery>=4.1 diff --git a/packages/typespec-python/tests/requirements/lint.txt b/packages/typespec-python/tests/requirements/lint.txt deleted file mode 100644 index 2a9896f8d7..0000000000 --- a/packages/typespec-python/tests/requirements/lint.txt +++ /dev/null @@ -1,4 +0,0 @@ -# Linting dependencies --r base.txt -pylint==4.0.4 -black==24.8.0 diff --git a/packages/typespec-python/tests/requirements/typecheck.txt b/packages/typespec-python/tests/requirements/typecheck.txt deleted file mode 100644 index 6e09ee898c..0000000000 --- a/packages/typespec-python/tests/requirements/typecheck.txt +++ /dev/null @@ -1,5 +0,0 @@ -# Type checking dependencies --r base.txt -pyright==1.1.407 -mypy==1.19.1 -types-PyYAML==6.0.12.8 diff --git a/packages/typespec-python/tests/requirements/unbranded.txt b/packages/typespec-python/tests/requirements/unbranded.txt deleted file mode 100644 index 73749e218c..0000000000 --- a/packages/typespec-python/tests/requirements/unbranded.txt +++ /dev/null @@ -1,3 +0,0 @@ -# Unbranded SDK dependencies --r base.txt -corehttp[requests] diff --git a/packages/typespec-python/tests/tox.ini b/packages/typespec-python/tests/tox.ini deleted file mode 100644 index 3007a8069c..0000000000 --- a/packages/typespec-python/tests/tox.ini +++ /dev/null @@ -1,226 +0,0 @@ -[tox] -envlist = test-{azure,unbranded}, lint-{azure,unbranded}, mypy-{azure,unbranded}, pyright-{azure,unbranded}, apiview-{azure,unbranded}, sphinx-{azure,unbranded} -skipsdist = True -isolated_build = True -requires = tox-uv - -[testenv] -deps = - -r {tox_root}/requirements/base.txt -setenv = - FLAVOR = {envname} -passenv = - FOLDER -allowlist_externals = - pytest - uv - -# ============================================================================= -# Test environments -# ============================================================================= - -[testenv:test-azure] -description = Run tests for Azure flavor -setenv = - {[testenv]setenv} - FLAVOR = azure -deps = - {[testenv]deps} - -r {tox_root}/requirements/azure.txt -commands = - python {tox_root}/install_packages.py azure {tox_root} - pytest mock_api/azure mock_api/shared -v -n auto {posargs} - -[testenv:test-unbranded] -description = Run tests for unbranded flavor -setenv = - {[testenv]setenv} - FLAVOR = unbranded -deps = - {[testenv]deps} - -r {tox_root}/requirements/unbranded.txt -commands = - python {tox_root}/install_packages.py unbranded {tox_root} - pytest mock_api/unbranded mock_api/shared -v -n auto {posargs} - -# ============================================================================= -# Lint environments -# ============================================================================= - -[testenv:lint-azure] -description = Run linting for Azure flavor -basepython = python3.12 -setenv = - {[testenv]setenv} - FLAVOR = azure -deps = - -r {tox_root}/requirements/lint.txt - -r {tox_root}/requirements/azure.txt -commands = - uv pip install azure-pylint-guidelines-checker==0.5.2 --index-url="https://pkgs.dev.azure.com/azure-sdk/public/_packaging/azure-sdk-for-python/pypi/simple/" - python {tox_root}/install_packages.py azure {tox_root} - python {tox_root}/../eng/scripts/ci/run_pylint.py -t azure -s generated {posargs} - -[testenv:lint-unbranded] -description = Run linting for unbranded flavor -basepython = python3.12 -setenv = - {[testenv]setenv} - FLAVOR = unbranded -deps = - -r {tox_root}/requirements/lint.txt - -r {tox_root}/requirements/unbranded.txt -commands = - uv pip install azure-pylint-guidelines-checker==0.5.2 --index-url="https://pkgs.dev.azure.com/azure-sdk/public/_packaging/azure-sdk-for-python/pypi/simple/" - python {tox_root}/install_packages.py unbranded {tox_root} - python {tox_root}/../eng/scripts/ci/run_pylint.py -t unbranded -s generated {posargs} - -# ============================================================================= -# Type checking environments -# ============================================================================= - -[testenv:mypy-azure] -description = Run mypy type checking for Azure flavor -setenv = - {[testenv]setenv} - FLAVOR = azure -deps = - -r {tox_root}/requirements/typecheck.txt - -r {tox_root}/requirements/azure.txt -commands = - python {tox_root}/install_packages.py azure {tox_root} - python {tox_root}/../eng/scripts/ci/run_mypy.py -t azure -s generated {posargs} - -[testenv:mypy-unbranded] -description = Run mypy type checking for unbranded flavor -setenv = - {[testenv]setenv} - FLAVOR = unbranded -deps = - -r {tox_root}/requirements/typecheck.txt - -r {tox_root}/requirements/unbranded.txt -commands = - python {tox_root}/install_packages.py unbranded {tox_root} - python {tox_root}/../eng/scripts/ci/run_mypy.py -t unbranded -s generated {posargs} - -[testenv:pyright-azure] -description = Run pyright type checking for Azure flavor -setenv = - {[testenv]setenv} - FLAVOR = azure -deps = - -r {tox_root}/requirements/typecheck.txt - -r {tox_root}/requirements/azure.txt -commands = - python {tox_root}/install_packages.py azure {tox_root} - python {tox_root}/../eng/scripts/ci/run_pyright.py -t azure -s generated {posargs} - -[testenv:pyright-unbranded] -description = Run pyright type checking for unbranded flavor -setenv = - {[testenv]setenv} - FLAVOR = unbranded -deps = - -r {tox_root}/requirements/typecheck.txt - -r {tox_root}/requirements/unbranded.txt -commands = - python {tox_root}/install_packages.py unbranded {tox_root} - python {tox_root}/../eng/scripts/ci/run_pyright.py -t unbranded -s generated {posargs} - -# ============================================================================= -# Documentation environments (apiview and sphinx split for parallelism) -# ============================================================================= - -[testenv:apiview-azure] -description = Run apiview validation for Azure flavor -basepython = python3.12 -setenv = - {[testenv]setenv} - FLAVOR = azure -deps = - -r {tox_root}/requirements/docs.txt -commands = - pip install apiview-stub-generator>=0.3.19 pylint-guidelines-checker --no-deps --index-url="https://pkgs.dev.azure.com/azure-sdk/public/_packaging/azure-sdk-for-python/pypi/simple/" - pip install astroid charset-normalizer pylint pkginfo - python {tox_root}/install_packages.py azure {tox_root} - python {tox_root}/../eng/scripts/ci/run_apiview.py -t azure -s generated {posargs} - -[testenv:apiview-unbranded] -description = Run apiview validation for unbranded flavor -basepython = python3.12 -setenv = - {[testenv]setenv} - FLAVOR = unbranded -deps = - -r {tox_root}/requirements/docs.txt -commands = - pip install apiview-stub-generator>=0.3.19 pylint-guidelines-checker --no-deps --index-url="https://pkgs.dev.azure.com/azure-sdk/public/_packaging/azure-sdk-for-python/pypi/simple/" - pip install astroid charset-normalizer pylint pkginfo - python {tox_root}/install_packages.py unbranded {tox_root} - python {tox_root}/../eng/scripts/ci/run_apiview.py -t unbranded -s generated {posargs} - -[testenv:sphinx-azure] -description = Run sphinx docstring validation for Azure flavor -basepython = python3.12 -setenv = - {[testenv]setenv} - FLAVOR = azure -deps = - -r {tox_root}/requirements/docs.txt - -r {tox_root}/requirements/azure.txt -commands = - python {tox_root}/install_packages.py azure {tox_root} - python {tox_root}/../eng/scripts/ci/run_sphinx_build.py -t azure -s generated {posargs} - -[testenv:sphinx-unbranded] -description = Run sphinx docstring validation for unbranded flavor -basepython = python3.12 -setenv = - {[testenv]setenv} - FLAVOR = unbranded -deps = - -r {tox_root}/requirements/docs.txt - -r {tox_root}/requirements/unbranded.txt -commands = - python {tox_root}/install_packages.py unbranded {tox_root} - python {tox_root}/../eng/scripts/ci/run_sphinx_build.py -t unbranded -s generated {posargs} - -# ============================================================================= -# CI environments (combines all checks) -# ============================================================================= - -[testenv:ci-azure] -description = Run full CI for Azure flavor -basepython = python3.12 -setenv = - {[testenv]setenv} - FLAVOR = azure -deps = - -r {tox_root}/requirements/lint.txt - -r {tox_root}/requirements/typecheck.txt - -r {tox_root}/requirements/azure.txt -commands = - uv pip install azure-pylint-guidelines-checker==0.5.2 --index-url="https://pkgs.dev.azure.com/azure-sdk/public/_packaging/azure-sdk-for-python/pypi/simple/" - python {tox_root}/install_packages.py azure {tox_root} - pytest mock_api/azure mock_api/shared -v -n auto - python {tox_root}/../eng/scripts/ci/run_pylint.py -t azure -s generated - python {tox_root}/../eng/scripts/ci/run_mypy.py -t azure -s generated - python {tox_root}/../eng/scripts/ci/run_pyright.py -t azure -s generated - -[testenv:ci-unbranded] -description = Run full CI for unbranded flavor -basepython = python3.12 -setenv = - {[testenv]setenv} - FLAVOR = unbranded -deps = - -r {tox_root}/requirements/lint.txt - -r {tox_root}/requirements/typecheck.txt - -r {tox_root}/requirements/unbranded.txt -commands = - uv pip install azure-pylint-guidelines-checker==0.5.2 --index-url="https://pkgs.dev.azure.com/azure-sdk/public/_packaging/azure-sdk-for-python/pypi/simple/" - python {tox_root}/install_packages.py unbranded {tox_root} - pytest mock_api/unbranded mock_api/shared -v -n auto - python {tox_root}/../eng/scripts/ci/run_pylint.py -t unbranded -s generated - python {tox_root}/../eng/scripts/ci/run_mypy.py -t unbranded -s generated - python {tox_root}/../eng/scripts/ci/run_pyright.py -t unbranded -s generated From 4037f6527cb455fc324478a7086951c706dec5ac Mon Sep 17 00:00:00 2001 From: Yuchao Yan Date: Thu, 7 May 2026 17:29:37 +0800 Subject: [PATCH 04/36] remove tests folder --- .../apikey/_operations/_patch.py | 36 ----------- .../apikey/aio/_operations/_patch.py | 36 ----------- .../core/alternatetype/models/_patch.py | 60 ------------------- .../apikey/_operations/_patch.py | 36 ----------- .../apikey/aio/_operations/_patch.py | 36 ----------- packages/typespec-python/tests/pytest.ini | 3 - 6 files changed, 207 deletions(-) delete mode 100644 packages/typespec-python/tests/generated/azure/authentication-api-key/authentication/apikey/_operations/_patch.py delete mode 100644 packages/typespec-python/tests/generated/azure/authentication-api-key/authentication/apikey/aio/_operations/_patch.py delete mode 100644 packages/typespec-python/tests/generated/azure/azure-client-generator-core-alternate-type/specs/azure/clientgenerator/core/alternatetype/models/_patch.py delete mode 100644 packages/typespec-python/tests/generated/unbranded/authentication-api-key/authentication/apikey/_operations/_patch.py delete mode 100644 packages/typespec-python/tests/generated/unbranded/authentication-api-key/authentication/apikey/aio/_operations/_patch.py delete mode 100644 packages/typespec-python/tests/pytest.ini diff --git a/packages/typespec-python/tests/generated/azure/authentication-api-key/authentication/apikey/_operations/_patch.py b/packages/typespec-python/tests/generated/azure/authentication-api-key/authentication/apikey/_operations/_patch.py deleted file mode 100644 index fc4fac79b3..0000000000 --- a/packages/typespec-python/tests/generated/azure/authentication-api-key/authentication/apikey/_operations/_patch.py +++ /dev/null @@ -1,36 +0,0 @@ -# coding=utf-8 - -"""Customize generated code here. - -Follow our quickstart for examples: https://aka.ms/azsdk/python/dpcodegen/python/customize -""" -from typing import List - -from ._operations import _ApiKeyClientOperationsMixin as Generated - - -class _ApiKeyClientOperationsMixin(Generated): - - def patch_added_operation(self) -> bool: - """This is a placeholder for the operation that was added in the patch. - - This method is a no-op and does not perform any action. - - :return: Always returns True. - :rtype: bool - """ - return True - - -__all__: List[str] = [ - "_ApiKeyClientOperationsMixin" -] # Add all objects you want publicly available to users at this package level - - -def patch_sdk(): - """Do not remove from this file. - - `patch_sdk` is a last resort escape hatch that allows you to do customizations - you can't accomplish using the techniques described in - https://aka.ms/azsdk/python/dpcodegen/python/customize - """ diff --git a/packages/typespec-python/tests/generated/azure/authentication-api-key/authentication/apikey/aio/_operations/_patch.py b/packages/typespec-python/tests/generated/azure/authentication-api-key/authentication/apikey/aio/_operations/_patch.py deleted file mode 100644 index fc4fac79b3..0000000000 --- a/packages/typespec-python/tests/generated/azure/authentication-api-key/authentication/apikey/aio/_operations/_patch.py +++ /dev/null @@ -1,36 +0,0 @@ -# coding=utf-8 - -"""Customize generated code here. - -Follow our quickstart for examples: https://aka.ms/azsdk/python/dpcodegen/python/customize -""" -from typing import List - -from ._operations import _ApiKeyClientOperationsMixin as Generated - - -class _ApiKeyClientOperationsMixin(Generated): - - def patch_added_operation(self) -> bool: - """This is a placeholder for the operation that was added in the patch. - - This method is a no-op and does not perform any action. - - :return: Always returns True. - :rtype: bool - """ - return True - - -__all__: List[str] = [ - "_ApiKeyClientOperationsMixin" -] # Add all objects you want publicly available to users at this package level - - -def patch_sdk(): - """Do not remove from this file. - - `patch_sdk` is a last resort escape hatch that allows you to do customizations - you can't accomplish using the techniques described in - https://aka.ms/azsdk/python/dpcodegen/python/customize - """ diff --git a/packages/typespec-python/tests/generated/azure/azure-client-generator-core-alternate-type/specs/azure/clientgenerator/core/alternatetype/models/_patch.py b/packages/typespec-python/tests/generated/azure/azure-client-generator-core-alternate-type/specs/azure/clientgenerator/core/alternatetype/models/_patch.py deleted file mode 100644 index fa513da4c0..0000000000 --- a/packages/typespec-python/tests/generated/azure/azure-client-generator-core-alternate-type/specs/azure/clientgenerator/core/alternatetype/models/_patch.py +++ /dev/null @@ -1,60 +0,0 @@ -# coding=utf-8 -# -------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for license information. -# -------------------------------------------------------------------------- -"""Customize generated code here. - -Follow our quickstart for examples: https://aka.ms/azsdk/python/dpcodegen/python/customize -""" -from typing import Type -import geojson -from .._utils.model_base import TYPE_HANDLER_REGISTRY - - -@TYPE_HANDLER_REGISTRY.register_serializer(geojson.Feature) -def feature_serializer(obj: geojson.Feature) -> dict: - """Serialize a geojson.Feature to a dict. - - :param obj: The geojson.Feature object to serialize. - :type obj: geojson.Feature - :return: The serialized feature as a dictionary. - :rtype: dict - """ - return { - "type": obj.type, - "geometry": {"type": obj.geometry.type, "coordinates": obj.geometry.coordinates}, - "properties": obj.properties, - "id": obj.id, - } - - -@TYPE_HANDLER_REGISTRY.register_deserializer(geojson.Feature) -def feature_deserializer(cls: Type[geojson.Feature], data: dict) -> geojson.Feature: - """Deserialize a dict to a geojson.Feature. - - :param data: The dictionary data to deserialize. - :type data: dict - :return: The deserialized geojson.Feature object. - :rtype: geojson.Feature - """ - return cls( - type=data.get("type"), - geometry=geojson.geometry.Geometry( - type=data["geometry"].get("type"), coordinates=data["geometry"].get("coordinates") - ), - properties=data.get("properties"), - id=data.get("id"), - ) - - -__all__: list[str] = [] # Add all objects you want publicly available to users at this package level - - -def patch_sdk(): - """Do not remove from this file. - - `patch_sdk` is a last resort escape hatch that allows you to do customizations - you can't accomplish using the techniques described in - https://aka.ms/azsdk/python/dpcodegen/python/customize - """ diff --git a/packages/typespec-python/tests/generated/unbranded/authentication-api-key/authentication/apikey/_operations/_patch.py b/packages/typespec-python/tests/generated/unbranded/authentication-api-key/authentication/apikey/_operations/_patch.py deleted file mode 100644 index fc4fac79b3..0000000000 --- a/packages/typespec-python/tests/generated/unbranded/authentication-api-key/authentication/apikey/_operations/_patch.py +++ /dev/null @@ -1,36 +0,0 @@ -# coding=utf-8 - -"""Customize generated code here. - -Follow our quickstart for examples: https://aka.ms/azsdk/python/dpcodegen/python/customize -""" -from typing import List - -from ._operations import _ApiKeyClientOperationsMixin as Generated - - -class _ApiKeyClientOperationsMixin(Generated): - - def patch_added_operation(self) -> bool: - """This is a placeholder for the operation that was added in the patch. - - This method is a no-op and does not perform any action. - - :return: Always returns True. - :rtype: bool - """ - return True - - -__all__: List[str] = [ - "_ApiKeyClientOperationsMixin" -] # Add all objects you want publicly available to users at this package level - - -def patch_sdk(): - """Do not remove from this file. - - `patch_sdk` is a last resort escape hatch that allows you to do customizations - you can't accomplish using the techniques described in - https://aka.ms/azsdk/python/dpcodegen/python/customize - """ diff --git a/packages/typespec-python/tests/generated/unbranded/authentication-api-key/authentication/apikey/aio/_operations/_patch.py b/packages/typespec-python/tests/generated/unbranded/authentication-api-key/authentication/apikey/aio/_operations/_patch.py deleted file mode 100644 index fc4fac79b3..0000000000 --- a/packages/typespec-python/tests/generated/unbranded/authentication-api-key/authentication/apikey/aio/_operations/_patch.py +++ /dev/null @@ -1,36 +0,0 @@ -# coding=utf-8 - -"""Customize generated code here. - -Follow our quickstart for examples: https://aka.ms/azsdk/python/dpcodegen/python/customize -""" -from typing import List - -from ._operations import _ApiKeyClientOperationsMixin as Generated - - -class _ApiKeyClientOperationsMixin(Generated): - - def patch_added_operation(self) -> bool: - """This is a placeholder for the operation that was added in the patch. - - This method is a no-op and does not perform any action. - - :return: Always returns True. - :rtype: bool - """ - return True - - -__all__: List[str] = [ - "_ApiKeyClientOperationsMixin" -] # Add all objects you want publicly available to users at this package level - - -def patch_sdk(): - """Do not remove from this file. - - `patch_sdk` is a last resort escape hatch that allows you to do customizations - you can't accomplish using the techniques described in - https://aka.ms/azsdk/python/dpcodegen/python/customize - """ diff --git a/packages/typespec-python/tests/pytest.ini b/packages/typespec-python/tests/pytest.ini deleted file mode 100644 index c8c9c7579d..0000000000 --- a/packages/typespec-python/tests/pytest.ini +++ /dev/null @@ -1,3 +0,0 @@ -[pytest] -asyncio_mode = auto -asyncio_default_fixture_loop_scope = function From fb02678d13f19332982457b15c301fec249ac413 Mon Sep 17 00:00:00 2001 From: Yuchao Yan Date: Thu, 7 May 2026 17:30:12 +0800 Subject: [PATCH 05/36] update --- packages/typespec-python/eng/scripts/sync.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/packages/typespec-python/eng/scripts/sync.ts b/packages/typespec-python/eng/scripts/sync.ts index f0ad59a028..210f4ad4a7 100644 --- a/packages/typespec-python/eng/scripts/sync.ts +++ b/packages/typespec-python/eng/scripts/sync.ts @@ -63,9 +63,8 @@ const INCLUDES: readonly string[] = [ "eng/scripts/ci/util.py", // Regeneration scripts (the local regenerate.ts is intentionally synced from - // upstream; regenerate-common.ts is its shared helper module). + // upstream). "eng/scripts/ci/regenerate.ts", - "eng/scripts/ci/regenerate-common.ts", // Shared setup scripts (invoked by package.json install/prepare hooks // and by ci/regenerate.ts which spawns run_batch.py). From d13cc81789d5ee2bf59bc3e36cd89c4afea7d07c Mon Sep 17 00:00:00 2001 From: Yuchao Yan Date: Fri, 8 May 2026 10:55:26 +0800 Subject: [PATCH 06/36] update --- .../eng/scripts/ci/regenerate.ts | 442 ++++++------------ packages/typespec-python/eng/scripts/sync.ts | 4 - packages/typespec-python/package.json | 2 +- 3 files changed, 140 insertions(+), 308 deletions(-) diff --git a/packages/typespec-python/eng/scripts/ci/regenerate.ts b/packages/typespec-python/eng/scripts/ci/regenerate.ts index a65230db57..7d47f00182 100644 --- a/packages/typespec-python/eng/scripts/ci/regenerate.ts +++ b/packages/typespec-python/eng/scripts/ci/regenerate.ts @@ -7,15 +7,81 @@ */ import { compile, NodeHost } from "@typespec/compiler"; -import { execSync } from "child_process"; -import { existsSync, rmSync } from "fs"; -import { access, mkdir, readdir, writeFile } from "fs/promises"; +import { promises, rmSync } from "fs"; import { platform } from "os"; import { dirname, join, relative, resolve } from "path"; import pc from "picocolors"; import { fileURLToPath } from "url"; import { parseArgs } from "util"; +// ---- Shared constants ---- + +const SKIP_SPECS: string[] = ["type/file"]; + +const SpecialFlags: Record> = { + azure: { + "generate-test": true, + "generate-sample": true, + }, +}; + +function toPosix(dir: string): string { + return dir.replace(/\\/g, "/"); +} + +interface RegenerateFlags { + flavor: string; + debug: boolean; + name?: string; +} + +async function getSubdirectories(baseDir: string, flags: RegenerateFlags): Promise { + const subdirectories: string[] = []; + + async function searchDir(currentDir: string) { + const items = await promises.readdir(currentDir, { withFileTypes: true }); + + const promisesArray = items.map(async (item) => { + const subDirPath = join(currentDir, item.name); + if (item.isDirectory()) { + const mainTspPath = join(subDirPath, "main.tsp"); + const clientTspPath = join(subDirPath, "client.tsp"); + + const mainTspRelativePath = toPosix(relative(baseDir, mainTspPath)); + + if (SKIP_SPECS.some((skipSpec) => mainTspRelativePath.includes(skipSpec))) return; + + const hasMainTsp = await promises + .access(mainTspPath) + .then(() => true) + .catch(() => false); + const hasClientTsp = await promises + .access(clientTspPath) + .then(() => true) + .catch(() => false); + + if (mainTspRelativePath.toLowerCase().includes(flags.name || "")) { + if (mainTspRelativePath.includes("resiliency/srv-driven")) { + subdirectories.push(resolve(subDirPath, "old.tsp")); + } + if (hasClientTsp) { + subdirectories.push(resolve(subDirPath, "client.tsp")); + } else if (hasMainTsp) { + subdirectories.push(resolve(subDirPath, "main.tsp")); + } + } + + await searchDir(subDirPath); + } + }); + + await Promise.all(promisesArray); + } + + await searchDir(baseDir); + return subdirectories; +} + // Parse arguments const argv = parseArgs({ args: process.argv.slice(2), @@ -23,9 +89,6 @@ const argv = parseArgs({ flavor: { type: "string", short: "f" }, name: { type: "string", short: "n" }, debug: { type: "boolean", short: "d" }, - pluginDir: { type: "string" }, - emitterName: { type: "string" }, - generatedFolder: { type: "string" }, jobs: { type: "string", short: "j" }, help: { type: "boolean", short: "h" }, }, @@ -45,10 +108,6 @@ ${pc.bold("Options:")} ${pc.cyan("-n, --name ")} Filter packages by name pattern (case-insensitive substring match). - Examples: - --name xml Regenerate packages containing "xml" - --name authentication Regenerate authentication packages - --name type/array Regenerate the type/array package ${pc.cyan("-d, --debug")} Enable debug output during regeneration. @@ -68,37 +127,22 @@ ${pc.bold("Examples:")} ${pc.dim("# Regenerate a specific package by name")} tsx regenerate.ts --flavor azure --name authentication-api-key - - ${pc.dim("# Regenerate with more parallelism")} - tsx regenerate.ts --jobs 50 `); process.exit(0); } -// ---- Shared constants ---- - -const SKIP_SPECS: string[] = ["type/file", "service/multiple-services"]; - -const SpecialFlags: Record> = { - azure: { - "generate-test": true, - "generate-sample": true, - }, -}; +// Get paths +const SCRIPT_DIR = dirname(fileURLToPath(import.meta.url)); +const PLUGIN_DIR = resolve(SCRIPT_DIR, "../../../"); +const AZURE_HTTP_SPECS = resolve(PLUGIN_DIR, "node_modules/@azure-tools/azure-http-specs/specs"); +const HTTP_SPECS = resolve(PLUGIN_DIR, "node_modules/@typespec/http-specs/specs"); +const EMITTER_NAME = "@azure-tools/typespec-python"; -function toPosix(dir: string): string { - return dir.replace(/\\/g, "/"); +function isAzureSpec(specPath: string): boolean { + return specPath.startsWith(AZURE_HTTP_SPECS); } -interface RegenerateFlags { - flavor: string; - debug: boolean; - name?: string; - pyodide?: boolean; -} - -// ---- Base emitter options ---- - +// Emitter options const AZURE_EMITTER_OPTIONS: Record | Record[]> = { "azure/client-generator-core/access": { namespace: "specs.azure.clientgenerator.core.access", @@ -118,6 +162,12 @@ const AZURE_EMITTER_OPTIONS: Record | Record | Record | Record | Record[]> = { @@ -303,7 +352,6 @@ const EMITTER_OPTIONS: Record | Record | Record { - const subdirectories: string[] = []; - - async function searchDir(currentDir: string) { - const items = await readdir(currentDir, { withFileTypes: true }); - - const promisesArray = items.map(async (item) => { - const subDirPath = join(currentDir, item.name); - if (item.isDirectory()) { - const mainTspPath = join(subDirPath, "main.tsp"); - const clientTspPath = join(subDirPath, "client.tsp"); - - const mainTspRelativePath = toPosix(relative(baseDir, mainTspPath)); - - if (SKIP_SPECS.some((skipSpec) => mainTspRelativePath.includes(skipSpec))) return; - - const hasMainTsp = await access(mainTspPath) - .then(() => true) - .catch(() => false); - const hasClientTsp = await access(clientTspPath) - .then(() => true) - .catch(() => false); - - if (mainTspRelativePath.toLowerCase().includes(flags.name || "")) { - if (mainTspRelativePath.includes("resiliency/srv-driven")) { - subdirectories.push(resolve(subDirPath, "old.tsp")); - } - if (hasClientTsp) { - subdirectories.push(resolve(subDirPath, "client.tsp")); - } else if (hasMainTsp) { - subdirectories.push(resolve(subDirPath, "main.tsp")); - } - } - - await searchDir(subDirPath); - } - }); - - await Promise.all(promisesArray); - } - - await searchDir(baseDir); - return subdirectories; -} - -async function preprocess(flavor: string, generatedFolder: string): Promise { - if (flavor === "azure") { - const testsGeneratedDir = resolve(generatedFolder, "../tests/generated/azure"); - - const DELETE_CONTENT = "# This file is to be deleted after regeneration"; - const DELETE_FILE = "to_be_deleted.py"; - const entries: { folder: string[]; file: string; content: string }[] = [ - { - folder: ["authentication-api-key", "authentication", "apikey", "_operations"], - file: DELETE_FILE, - content: DELETE_CONTENT, - }, - { - folder: ["generation-subdir", "generation", "subdir", "_generated"], - file: DELETE_FILE, - content: DELETE_CONTENT, - }, - { - folder: ["generation-subdir", "generated_tests"], - file: DELETE_FILE, - content: DELETE_CONTENT, - }, - { - folder: ["generation-subdir", "generation", "subdir"], - file: "to_be_kept.py", - content: "# This file is to be kept after regeneration", - }, - ]; - - await Promise.all( - entries.map(async ({ folder, file, content }) => { - const targetFolder = join(testsGeneratedDir, ...folder); - await mkdir(targetFolder, { recursive: true }); - await writeFile(join(targetFolder, file), content); - }), - ); - } -} - -// Get paths -const SCRIPT_DIR = dirname(fileURLToPath(import.meta.url)); -const PLUGIN_DIR = argv.values.pluginDir - ? resolve(argv.values.pluginDir) - : resolve(SCRIPT_DIR, "../../../"); -const AZURE_HTTP_SPECS = resolve(PLUGIN_DIR, "node_modules/@azure-tools/azure-http-specs/specs"); -const HTTP_SPECS = resolve(PLUGIN_DIR, "node_modules/@typespec/http-specs/specs"); -const GENERATED_FOLDER = argv.values.generatedFolder - ? resolve(argv.values.generatedFolder) - : resolve(PLUGIN_DIR, "generator"); -const EMITTER_NAME = argv.values.emitterName || "@typespec/http-client-python"; - interface CompileTask { spec: string; outputDir: string; @@ -487,13 +430,6 @@ interface TaskGroup { tasks: CompileTask[]; } -// Check whether a spec path belongs to azure-http-specs (vs standard http-specs). -// Using "azure-http-specs" instead of "azure" to avoid false positives when the -// working directory path contains "azure" (e.g. azure-sdk-for-python). -function isAzureSpec(spec: string): boolean { - return spec.includes("azure-http-specs"); -} - function defaultPackageName(spec: string): string { const specDir = isAzureSpec(spec) ? AZURE_HTTP_SPECS : HTTP_SPECS; return toPosix(relative(specDir, dirname(spec))) @@ -519,21 +455,19 @@ function buildTaskGroups(specs: string[], flags: RegenerateFlags): TaskGroup[] { const tasks: CompileTask[] = []; for (const emitterConfig of getEmitterOptions(spec, flags.flavor)) { - // Apply flavor defaults first, then per-spec options so they can override (e.g., "generate-test": "false") - const options: Record = {}; + const options: Record = { ...emitterConfig }; + + // Add flavor-specific options + options["flavor"] = flags.flavor; for (const [k, v] of Object.entries(SpecialFlags[flags.flavor] ?? {})) { options[k] = v; } - Object.assign(options, emitterConfig); - - // Add flavor - options["flavor"] = flags.flavor; // Set output directory - use tests/generated// structure const packageName = (options["package-name"] as string) || defaultPackageName(spec); const outputDir = (options["emitter-output-dir"] as string) || - toPosix(`${GENERATED_FOLDER}/../tests/generated/${flags.flavor}/${packageName}`); + toPosix(`${PLUGIN_DIR}/tests/generated/${flags.flavor}/${packageName}`); options["emitter-output-dir"] = outputDir; // Debug mode @@ -544,9 +478,6 @@ function buildTaskGroups(specs: string[], flags: RegenerateFlags): TaskGroup[] { // Examples directory options["examples-dir"] = toPosix(join(dirname(spec), "examples")); - // Emit YAML only - Python processing is batched after all specs compile - options["emit-yaml-only"] = true; - tasks.push({ spec, outputDir, options }); } @@ -587,25 +518,6 @@ async function compileSpec(task: CompileTask): Promise<{ success: boolean; error } } -function renderProgressBar( - completed: number, - failed: number, - total: number, - width: number = 40, -): string { - const successCount = completed - failed; - const successWidth = Math.round((successCount / total) * width); - const failWidth = Math.round((failed / total) * width); - const emptyWidth = width - successWidth - failWidth; - - const successBar = pc.bgGreen(" ".repeat(successWidth)); - const failBar = failed > 0 ? pc.bgRed(" ".repeat(failWidth)) : ""; - const emptyBar = pc.dim("░".repeat(Math.max(0, emptyWidth))); - - const percent = Math.round((completed / total) * 100); - return `${successBar}${failBar}${emptyBar} ${pc.cyan(`${percent}%`)} (${completed}/${total})`; -} - async function runParallel(groups: TaskGroup[], maxJobs: number): Promise> { const results = new Map(); const executing: Set> = new Set(); @@ -613,20 +525,6 @@ async function runParallel(groups: TaskGroup[], maxJobs: number): Promise sum + g.tasks.length, 0); let completed = 0; - let failed = 0; - const failedSpecs: string[] = []; - - // Check if we're in a TTY for progress bar updates - const isTTY = process.stdout.isTTY; - - const updateProgress = () => { - if (isTTY) { - process.stdout.write(`\r${renderProgressBar(completed, failed, totalTasks)}`); - } - }; - - // Initial progress bar - updateProgress(); for (const group of groups) { // Each group runs as a unit - tasks within a group run sequentially @@ -639,17 +537,19 @@ async function runParallel(groups: TaskGroup[], maxJobs: number): Promise 0) { - console.log(pc.red(`\nFailed specs:`)); - for (const spec of failedSpecs) { - console.log(pc.red(` • ${spec}`)); - } - } - return results; } -async function collectConfigFiles(generatedDir: string, flavor: string): Promise { - const flavorDir = join(generatedDir, "..", "tests", "generated", flavor); - try { - await access(flavorDir); - } catch { - return []; - } - - const configFiles: string[] = []; - for (const pkg of await readdir(flavorDir, { withFileTypes: true })) { - if (pkg.isDirectory()) { - const pkgDir = join(flavorDir, pkg.name); - for (const file of await readdir(pkgDir)) { - if (file.startsWith(".tsp-codegen-") && file.endsWith(".json")) { - configFiles.push(join(pkgDir, file)); - } - } - } - } - return configFiles; -} - -function runBatchPythonProcessing(flavor: string, configCount: number, jobs: number): boolean { - if (configCount === 0) return true; - - console.log(pc.cyan(`\nRunning batch Python processing on ${configCount} specs...`)); +// Preprocess: create files that should be deleted after regeneration (for testing) +async function preprocess(flavor: string): Promise { + if (flavor === "azure") { + const generalParts = [PLUGIN_DIR, "tests", "generated", "azure"]; + const authFile = join( + ...generalParts, + "authentication-api-key", + "authentication", + "apikey", + "_operations", + "to_be_deleted.py", + ); + await promises.mkdir(dirname(authFile), { recursive: true }); + await promises.writeFile(authFile, "# This file is to be deleted after regeneration"); - // Find Python venv - let venvPath = join(PLUGIN_DIR, "venv"); - if (existsSync(join(venvPath, "bin"))) { - venvPath = join(venvPath, "bin", "python"); - } else if (existsSync(join(venvPath, "Scripts"))) { - venvPath = join(venvPath, "Scripts", "python.exe"); - } else { - console.error(pc.red("Python venv not found")); - return false; - } + const folderParts = [...generalParts, "generation-subdir"]; + const genFile = join(...folderParts, "generation", "subdir", "_generated", "to_be_deleted.py"); + await promises.mkdir(dirname(genFile), { recursive: true }); + await promises.writeFile(genFile, "# This file is to be deleted after regeneration"); - const batchScript = join(PLUGIN_DIR, "eng", "scripts", "setup", "run_batch.py"); + const testFile = join(...folderParts, "generated_tests", "to_be_deleted.py"); + await promises.mkdir(dirname(testFile), { recursive: true }); + await promises.writeFile(testFile, "# This file is to be kept after regeneration"); - try { - // Pass directory and flavor instead of individual config files to avoid command line length limits on Windows - execSync( - `"${venvPath}" "${batchScript}" --generated-dir "${PLUGIN_DIR}" --flavor ${flavor} --jobs ${jobs}`, - { - stdio: "inherit", - cwd: PLUGIN_DIR, - }, - ); - return true; - } catch { - return false; + const keptFile = join(...folderParts, "generation", "subdir", "to_be_kept.py"); + await promises.mkdir(dirname(keptFile), { recursive: true }); + await promises.writeFile(keptFile, "# This file is to be kept after regeneration"); } } @@ -749,7 +610,7 @@ async function regenerateFlavor( const flags: RegenerateFlags = { flavor, debug, name }; // Preprocess - await preprocess(flavor, GENERATED_FOLDER); + await preprocess(flavor); // Collect specs const azureSpecs = flavor === "azure" ? await getSubdirectories(AZURE_HTTP_SPECS, flags) : []; @@ -763,46 +624,21 @@ async function regenerateFlavor( console.log(pc.cyan(`Found ${allSpecs.length} specs (${totalTasks} total tasks) to compile`)); console.log(pc.cyan(`Using ${jobs} parallel jobs\n`)); - // Run compilation (emits YAML only) + // Run compilation const startTime = performance.now(); const results = await runParallel(groups, jobs); - const compileTime = (performance.now() - startTime) / 1000; + const duration = (performance.now() - startTime) / 1000; - // Summary for TypeSpec compilation + // Summary const succeeded = Array.from(results.values()).filter((v) => v).length; - const compileFailed = results.size - succeeded; - - console.log( - pc.cyan( - `\nTypeSpec compilation: ${succeeded} succeeded, ${compileFailed} failed (${compileTime.toFixed(1)}s)`, - ), - ); - - if (compileFailed > 0) { - console.log(pc.red(`Skipping Python processing due to compilation failures`)); - return false; - } - - // Batch process all specs with Python - const pyStartTime = performance.now(); - const configCount = (await collectConfigFiles(GENERATED_FOLDER, flavor)).length; - // Use fewer Python jobs since Python processing is heavier - const pyJobs = Math.max(4, jobs); - const pySuccess = runBatchPythonProcessing(flavor, configCount, pyJobs); - const pyTime = (performance.now() - pyStartTime) / 1000; - - const totalTime = (performance.now() - startTime) / 1000; + const failed = results.size - succeeded; console.log(pc.cyan(`\n${"=".repeat(60)}`)); - console.log(pc.cyan(`Results: ${succeeded} specs processed`)); - console.log( - pc.cyan( - ` TypeSpec: ${compileTime.toFixed(1)}s | Python: ${pyTime.toFixed(1)}s | Total: ${totalTime.toFixed(1)}s`, - ), - ); + console.log(pc.cyan(`Results: ${succeeded} succeeded, ${failed} failed`)); + console.log(pc.cyan(`Time: ${duration.toFixed(1)}s`)); console.log(pc.cyan(`${"=".repeat(60)}\n`)); - return pySuccess; + return failed === 0; } async function main() { diff --git a/packages/typespec-python/eng/scripts/sync.ts b/packages/typespec-python/eng/scripts/sync.ts index 210f4ad4a7..b682e01c94 100644 --- a/packages/typespec-python/eng/scripts/sync.ts +++ b/packages/typespec-python/eng/scripts/sync.ts @@ -62,10 +62,6 @@ const INCLUDES: readonly string[] = [ "eng/scripts/ci/run_sphinx_build.py", "eng/scripts/ci/util.py", - // Regeneration scripts (the local regenerate.ts is intentionally synced from - // upstream). - "eng/scripts/ci/regenerate.ts", - // Shared setup scripts (invoked by package.json install/prepare hooks // and by ci/regenerate.ts which spawns run_batch.py). "eng/scripts/setup/install.py", diff --git a/packages/typespec-python/package.json b/packages/typespec-python/package.json index 4bbe4c7477..2762370bf0 100644 --- a/packages/typespec-python/package.json +++ b/packages/typespec-python/package.json @@ -37,7 +37,7 @@ "lint:extra": "tsx ./eng/scripts/ci/lint.ts", "format:extra": "tsx ./eng/scripts/ci/format.ts --python", "format:extra:check": "tsx ./eng/scripts/ci/format.ts --python --check", - "regenerate": "tsx ./eng/scripts/ci/regenerate.ts --emitterName @azure-tools/typespec-python --generatedFolder ./generator", + "regenerate": "tsx ./eng/scripts/ci/regenerate.ts", "sync": "tsx ./eng/scripts/sync.ts", "sync:check": "tsx ./eng/scripts/sync.ts --check", "prepack": "tsx ./eng/scripts/sync.ts", From e9b6f3d0e60f81a686cff63162dd134c172384d2 Mon Sep 17 00:00:00 2001 From: Yuchao Yan Date: Fri, 8 May 2026 11:24:54 +0800 Subject: [PATCH 07/36] update --- .../eng/scripts/ci/regenerate.ts | 447 ++++++++++++------ packages/typespec-python/eng/scripts/sync.ts | 68 ++- 2 files changed, 375 insertions(+), 140 deletions(-) diff --git a/packages/typespec-python/eng/scripts/ci/regenerate.ts b/packages/typespec-python/eng/scripts/ci/regenerate.ts index 7d47f00182..fc9dd46abb 100644 --- a/packages/typespec-python/eng/scripts/ci/regenerate.ts +++ b/packages/typespec-python/eng/scripts/ci/regenerate.ts @@ -7,81 +7,15 @@ */ import { compile, NodeHost } from "@typespec/compiler"; -import { promises, rmSync } from "fs"; +import { execSync } from "child_process"; +import { existsSync, rmSync } from "fs"; +import { access, mkdir, readdir, writeFile } from "fs/promises"; import { platform } from "os"; import { dirname, join, relative, resolve } from "path"; import pc from "picocolors"; import { fileURLToPath } from "url"; import { parseArgs } from "util"; -// ---- Shared constants ---- - -const SKIP_SPECS: string[] = ["type/file"]; - -const SpecialFlags: Record> = { - azure: { - "generate-test": true, - "generate-sample": true, - }, -}; - -function toPosix(dir: string): string { - return dir.replace(/\\/g, "/"); -} - -interface RegenerateFlags { - flavor: string; - debug: boolean; - name?: string; -} - -async function getSubdirectories(baseDir: string, flags: RegenerateFlags): Promise { - const subdirectories: string[] = []; - - async function searchDir(currentDir: string) { - const items = await promises.readdir(currentDir, { withFileTypes: true }); - - const promisesArray = items.map(async (item) => { - const subDirPath = join(currentDir, item.name); - if (item.isDirectory()) { - const mainTspPath = join(subDirPath, "main.tsp"); - const clientTspPath = join(subDirPath, "client.tsp"); - - const mainTspRelativePath = toPosix(relative(baseDir, mainTspPath)); - - if (SKIP_SPECS.some((skipSpec) => mainTspRelativePath.includes(skipSpec))) return; - - const hasMainTsp = await promises - .access(mainTspPath) - .then(() => true) - .catch(() => false); - const hasClientTsp = await promises - .access(clientTspPath) - .then(() => true) - .catch(() => false); - - if (mainTspRelativePath.toLowerCase().includes(flags.name || "")) { - if (mainTspRelativePath.includes("resiliency/srv-driven")) { - subdirectories.push(resolve(subDirPath, "old.tsp")); - } - if (hasClientTsp) { - subdirectories.push(resolve(subDirPath, "client.tsp")); - } else if (hasMainTsp) { - subdirectories.push(resolve(subDirPath, "main.tsp")); - } - } - - await searchDir(subDirPath); - } - }); - - await Promise.all(promisesArray); - } - - await searchDir(baseDir); - return subdirectories; -} - // Parse arguments const argv = parseArgs({ args: process.argv.slice(2), @@ -89,7 +23,11 @@ const argv = parseArgs({ flavor: { type: "string", short: "f" }, name: { type: "string", short: "n" }, debug: { type: "boolean", short: "d" }, + pluginDir: { type: "string" }, + emitterName: { type: "string" }, + generatedFolder: { type: "string" }, jobs: { type: "string", short: "j" }, + singlePhase: { type: "boolean" }, help: { type: "boolean", short: "h" }, }, }); @@ -108,6 +46,10 @@ ${pc.bold("Options:")} ${pc.cyan("-n, --name ")} Filter packages by name pattern (case-insensitive substring match). + Examples: + --name xml Regenerate packages containing "xml" + --name authentication Regenerate authentication packages + --name type/array Regenerate the type/array package ${pc.cyan("-d, --debug")} Enable debug output during regeneration. @@ -127,22 +69,37 @@ ${pc.bold("Examples:")} ${pc.dim("# Regenerate a specific package by name")} tsx regenerate.ts --flavor azure --name authentication-api-key + + ${pc.dim("# Regenerate with more parallelism")} + tsx regenerate.ts --jobs 50 `); process.exit(0); } -// Get paths -const SCRIPT_DIR = dirname(fileURLToPath(import.meta.url)); -const PLUGIN_DIR = resolve(SCRIPT_DIR, "../../../"); -const AZURE_HTTP_SPECS = resolve(PLUGIN_DIR, "node_modules/@azure-tools/azure-http-specs/specs"); -const HTTP_SPECS = resolve(PLUGIN_DIR, "node_modules/@typespec/http-specs/specs"); -const EMITTER_NAME = "@azure-tools/typespec-python"; +// ---- Shared constants ---- + +const SKIP_SPECS: string[] = ["type/file", "service/multiple-services"]; -function isAzureSpec(specPath: string): boolean { - return specPath.startsWith(AZURE_HTTP_SPECS); +const SpecialFlags: Record> = { + azure: { + "generate-test": true, + "generate-sample": true, + }, +}; + +function toPosix(dir: string): string { + return dir.replace(/\\/g, "/"); } -// Emitter options +interface RegenerateFlags { + flavor: string; + debug: boolean; + name?: string; + pyodide?: boolean; +} + +// ---- Base emitter options ---- + const AZURE_EMITTER_OPTIONS: Record | Record[]> = { "azure/client-generator-core/access": { namespace: "specs.azure.clientgenerator.core.access", @@ -162,12 +119,6 @@ const AZURE_EMITTER_OPTIONS: Record | Record | Record | Record | Record[]> = { @@ -352,6 +304,7 @@ const EMITTER_OPTIONS: Record | Record | Record { + const subdirectories: string[] = []; + + async function searchDir(currentDir: string) { + const items = await readdir(currentDir, { withFileTypes: true }); + + const promisesArray = items.map(async (item) => { + const subDirPath = join(currentDir, item.name); + if (item.isDirectory()) { + const mainTspPath = join(subDirPath, "main.tsp"); + const clientTspPath = join(subDirPath, "client.tsp"); + + const mainTspRelativePath = toPosix(relative(baseDir, mainTspPath)); + + if (SKIP_SPECS.some((skipSpec) => mainTspRelativePath.includes(skipSpec))) return; + + const hasMainTsp = await access(mainTspPath) + .then(() => true) + .catch(() => false); + const hasClientTsp = await access(clientTspPath) + .then(() => true) + .catch(() => false); + + if (mainTspRelativePath.toLowerCase().includes(flags.name || "")) { + if (mainTspRelativePath.includes("resiliency/srv-driven")) { + subdirectories.push(resolve(subDirPath, "old.tsp")); + } + if (hasClientTsp) { + subdirectories.push(resolve(subDirPath, "client.tsp")); + } else if (hasMainTsp) { + subdirectories.push(resolve(subDirPath, "main.tsp")); + } + } + + await searchDir(subDirPath); + } + }); + + await Promise.all(promisesArray); + } + + await searchDir(baseDir); + return subdirectories; +} + +async function preprocess(flavor: string, generatedFolder: string): Promise { + if (flavor === "azure") { + const testsGeneratedDir = resolve(generatedFolder, "../tests/generated/azure"); + + const DELETE_CONTENT = "# This file is to be deleted after regeneration"; + const DELETE_FILE = "to_be_deleted.py"; + const entries: { folder: string[]; file: string; content: string }[] = [ + { + folder: ["authentication-api-key", "authentication", "apikey", "_operations"], + file: DELETE_FILE, + content: DELETE_CONTENT, + }, + { + folder: ["generation-subdir", "generation", "subdir", "_generated"], + file: DELETE_FILE, + content: DELETE_CONTENT, + }, + { + folder: ["generation-subdir", "generated_tests"], + file: DELETE_FILE, + content: DELETE_CONTENT, + }, + { + folder: ["generation-subdir", "generation", "subdir"], + file: "to_be_kept.py", + content: "# This file is to be kept after regeneration", + }, + ]; + + await Promise.all( + entries.map(async ({ folder, file, content }) => { + const targetFolder = join(testsGeneratedDir, ...folder); + await mkdir(targetFolder, { recursive: true }); + await writeFile(join(targetFolder, file), content); + }), + ); + } +} + +// Get paths +const SCRIPT_DIR = dirname(fileURLToPath(import.meta.url)); +const PLUGIN_DIR = argv.values.pluginDir + ? resolve(argv.values.pluginDir) + : resolve(SCRIPT_DIR, "../../../"); +const AZURE_HTTP_SPECS = resolve(PLUGIN_DIR, "node_modules/@azure-tools/azure-http-specs/specs"); +const HTTP_SPECS = resolve(PLUGIN_DIR, "node_modules/@typespec/http-specs/specs"); +const GENERATED_FOLDER = argv.values.generatedFolder + ? resolve(argv.values.generatedFolder) + : resolve(PLUGIN_DIR, "generator"); +const EMITTER_NAME = argv.values.emitterName || "@typespec/http-client-python"; + interface CompileTask { spec: string; outputDir: string; @@ -430,6 +488,13 @@ interface TaskGroup { tasks: CompileTask[]; } +// Check whether a spec path belongs to azure-http-specs (vs standard http-specs). +// Using "azure-http-specs" instead of "azure" to avoid false positives when the +// working directory path contains "azure" (e.g. azure-sdk-for-python). +function isAzureSpec(spec: string): boolean { + return spec.includes("azure-http-specs"); +} + function defaultPackageName(spec: string): string { const specDir = isAzureSpec(spec) ? AZURE_HTTP_SPECS : HTTP_SPECS; return toPosix(relative(specDir, dirname(spec))) @@ -455,19 +520,21 @@ function buildTaskGroups(specs: string[], flags: RegenerateFlags): TaskGroup[] { const tasks: CompileTask[] = []; for (const emitterConfig of getEmitterOptions(spec, flags.flavor)) { - const options: Record = { ...emitterConfig }; - - // Add flavor-specific options - options["flavor"] = flags.flavor; + // Apply flavor defaults first, then per-spec options so they can override (e.g., "generate-test": "false") + const options: Record = {}; for (const [k, v] of Object.entries(SpecialFlags[flags.flavor] ?? {})) { options[k] = v; } + Object.assign(options, emitterConfig); + + // Add flavor + options["flavor"] = flags.flavor; // Set output directory - use tests/generated// structure const packageName = (options["package-name"] as string) || defaultPackageName(spec); const outputDir = (options["emitter-output-dir"] as string) || - toPosix(`${PLUGIN_DIR}/tests/generated/${flags.flavor}/${packageName}`); + toPosix(`${GENERATED_FOLDER}/../tests/generated/${flags.flavor}/${packageName}`); options["emitter-output-dir"] = outputDir; // Debug mode @@ -478,6 +545,11 @@ function buildTaskGroups(specs: string[], flags: RegenerateFlags): TaskGroup[] { // Examples directory options["examples-dir"] = toPosix(join(dirname(spec), "examples")); + // Emit YAML only - Python processing is batched after all specs compile + if (!argv.values.singlePhase) { + options["emit-yaml-only"] = true; + } + tasks.push({ spec, outputDir, options }); } @@ -518,6 +590,25 @@ async function compileSpec(task: CompileTask): Promise<{ success: boolean; error } } +function renderProgressBar( + completed: number, + failed: number, + total: number, + width: number = 40, +): string { + const successCount = completed - failed; + const successWidth = Math.round((successCount / total) * width); + const failWidth = Math.round((failed / total) * width); + const emptyWidth = width - successWidth - failWidth; + + const successBar = pc.bgGreen(" ".repeat(successWidth)); + const failBar = failed > 0 ? pc.bgRed(" ".repeat(failWidth)) : ""; + const emptyBar = pc.dim("░".repeat(Math.max(0, emptyWidth))); + + const percent = Math.round((completed / total) * 100); + return `${successBar}${failBar}${emptyBar} ${pc.cyan(`${percent}%`)} (${completed}/${total})`; +} + async function runParallel(groups: TaskGroup[], maxJobs: number): Promise> { const results = new Map(); const executing: Set> = new Set(); @@ -525,6 +616,20 @@ async function runParallel(groups: TaskGroup[], maxJobs: number): Promise sum + g.tasks.length, 0); let completed = 0; + let failed = 0; + const failedSpecs: string[] = []; + + // Check if we're in a TTY for progress bar updates + const isTTY = process.stdout.isTTY; + + const updateProgress = () => { + if (isTTY) { + process.stdout.write(`\r${renderProgressBar(completed, failed, totalTasks)}`); + } + }; + + // Initial progress bar + updateProgress(); for (const group of groups) { // Each group runs as a unit - tasks within a group run sequentially @@ -537,19 +642,17 @@ async function runParallel(groups: TaskGroup[], maxJobs: number): Promise 0) { + console.log(pc.red(`\nFailed specs:`)); + for (const spec of failedSpecs) { + console.log(pc.red(` • ${spec}`)); + } + } + return results; } -// Preprocess: create files that should be deleted after regeneration (for testing) -async function preprocess(flavor: string): Promise { - if (flavor === "azure") { - const generalParts = [PLUGIN_DIR, "tests", "generated", "azure"]; - const authFile = join( - ...generalParts, - "authentication-api-key", - "authentication", - "apikey", - "_operations", - "to_be_deleted.py", - ); - await promises.mkdir(dirname(authFile), { recursive: true }); - await promises.writeFile(authFile, "# This file is to be deleted after regeneration"); +async function collectConfigFiles(generatedDir: string, flavor: string): Promise { + const flavorDir = join(generatedDir, "..", "tests", "generated", flavor); + try { + await access(flavorDir); + } catch { + return []; + } - const folderParts = [...generalParts, "generation-subdir"]; - const genFile = join(...folderParts, "generation", "subdir", "_generated", "to_be_deleted.py"); - await promises.mkdir(dirname(genFile), { recursive: true }); - await promises.writeFile(genFile, "# This file is to be deleted after regeneration"); + const configFiles: string[] = []; + for (const pkg of await readdir(flavorDir, { withFileTypes: true })) { + if (pkg.isDirectory()) { + const pkgDir = join(flavorDir, pkg.name); + for (const file of await readdir(pkgDir)) { + if (file.startsWith(".tsp-codegen-") && file.endsWith(".json")) { + configFiles.push(join(pkgDir, file)); + } + } + } + } + return configFiles; +} + +function runBatchPythonProcessing(flavor: string, configCount: number, jobs: number): boolean { + if (configCount === 0) return true; + + console.log(pc.cyan(`\nRunning batch Python processing on ${configCount} specs...`)); + + // Find Python venv + let venvPath = join(PLUGIN_DIR, "venv"); + if (existsSync(join(venvPath, "bin"))) { + venvPath = join(venvPath, "bin", "python"); + } else if (existsSync(join(venvPath, "Scripts"))) { + venvPath = join(venvPath, "Scripts", "python.exe"); + } else { + console.error(pc.red("Python venv not found")); + return false; + } - const testFile = join(...folderParts, "generated_tests", "to_be_deleted.py"); - await promises.mkdir(dirname(testFile), { recursive: true }); - await promises.writeFile(testFile, "# This file is to be kept after regeneration"); + const batchScript = join(PLUGIN_DIR, "eng", "scripts", "setup", "run_batch.py"); - const keptFile = join(...folderParts, "generation", "subdir", "to_be_kept.py"); - await promises.mkdir(dirname(keptFile), { recursive: true }); - await promises.writeFile(keptFile, "# This file is to be kept after regeneration"); + try { + // Pass directory and flavor instead of individual config files to avoid command line length limits on Windows + execSync( + `"${venvPath}" "${batchScript}" --generated-dir "${PLUGIN_DIR}" --flavor ${flavor} --jobs ${jobs}`, + { + stdio: "inherit", + cwd: PLUGIN_DIR, + }, + ); + return true; + } catch { + return false; } } @@ -610,7 +752,7 @@ async function regenerateFlavor( const flags: RegenerateFlags = { flavor, debug, name }; // Preprocess - await preprocess(flavor); + await preprocess(flavor, GENERATED_FOLDER); // Collect specs const azureSpecs = flavor === "azure" ? await getSubdirectories(AZURE_HTTP_SPECS, flags) : []; @@ -624,21 +766,48 @@ async function regenerateFlavor( console.log(pc.cyan(`Found ${allSpecs.length} specs (${totalTasks} total tasks) to compile`)); console.log(pc.cyan(`Using ${jobs} parallel jobs\n`)); - // Run compilation + // Run compilation (emits YAML only) const startTime = performance.now(); const results = await runParallel(groups, jobs); - const duration = (performance.now() - startTime) / 1000; + const compileTime = (performance.now() - startTime) / 1000; - // Summary + // Summary for TypeSpec compilation const succeeded = Array.from(results.values()).filter((v) => v).length; - const failed = results.size - succeeded; + const compileFailed = results.size - succeeded; + + console.log( + pc.cyan( + `\nTypeSpec compilation: ${succeeded} succeeded, ${compileFailed} failed (${compileTime.toFixed(1)}s)`, + ), + ); + + if (compileFailed > 0) { + console.log(pc.red(`Skipping Python processing due to compilation failures`)); + return false; + } + + // Batch process all specs with Python + const pyStartTime = performance.now(); + const configCount = (await collectConfigFiles(GENERATED_FOLDER, flavor)).length; + // Use fewer Python jobs since Python processing is heavier + const pyJobs = Math.max(4, jobs); + const pySuccess = argv.values.singlePhase + ? true + : runBatchPythonProcessing(flavor, configCount, pyJobs); + const pyTime = (performance.now() - pyStartTime) / 1000; + + const totalTime = (performance.now() - startTime) / 1000; console.log(pc.cyan(`\n${"=".repeat(60)}`)); - console.log(pc.cyan(`Results: ${succeeded} succeeded, ${failed} failed`)); - console.log(pc.cyan(`Time: ${duration.toFixed(1)}s`)); + console.log(pc.cyan(`Results: ${succeeded} specs processed`)); + console.log( + pc.cyan( + ` TypeSpec: ${compileTime.toFixed(1)}s | Python: ${pyTime.toFixed(1)}s | Total: ${totalTime.toFixed(1)}s`, + ), + ); console.log(pc.cyan(`${"=".repeat(60)}\n`)); - return failed === 0; + return pySuccess; } async function main() { diff --git a/packages/typespec-python/eng/scripts/sync.ts b/packages/typespec-python/eng/scripts/sync.ts index b682e01c94..445dbbb33e 100644 --- a/packages/typespec-python/eng/scripts/sync.ts +++ b/packages/typespec-python/eng/scripts/sync.ts @@ -62,6 +62,13 @@ const INCLUDES: readonly string[] = [ "eng/scripts/ci/run_sphinx_build.py", "eng/scripts/ci/util.py", + // The two-phase upstream regenerate.ts is patched at sync time (see + // POST_PROCESS) to add a `--single-phase` flag that bypasses the YAML + + // batched-Python pipeline. The wrapper's `regenerate` npm script passes + // that flag so we keep the in-process emit path that is faster for the + // azure-only / Windows / smaller-spec-set wrapper case. + "eng/scripts/ci/regenerate.ts", + // Shared setup scripts (invoked by package.json install/prepare hooks // and by ci/regenerate.ts which spawns run_batch.py). "eng/scripts/setup/install.py", @@ -106,6 +113,61 @@ const INCLUDES: readonly string[] = [ * build artifacts (egg-info, __pycache__, build/, dist/) from polluting the * sync. */ +/** + * Post-process hooks applied to specific synced files after copying. The + * transform runs against the source bytes; the resulting buffer is what gets + * compared with (and written to) the local file. Use sparingly — every patch + * is local divergence we have to maintain. + * + * Why we patch eng/scripts/ci/regenerate.ts: + * Upstream's regenerate.ts uses a two-phase pipeline (TypeSpec compile emits + * YAML only; then a single batched Python subprocess reads the YAMLs and + * writes the final .py files). That amortizes Python-startup cost across + * many specs and pays off when both `azure` and `unbranded` flavors are + * regenerated together. typespec-python only ever regenerates the `azure` + * flavor, with a smaller spec set, on Windows — the fixed subprocess + + * YAML round-trip cost ends up slower than just letting the emitter write + * .py files in-process. This patch adds a `--single-phase` flag that + * bypasses both `emit-yaml-only` and `runBatchPythonProcessing`. The + * wrapper's `regenerate` npm script passes `--single-phase`. + */ +const POST_PROCESS: Record Buffer> = { + "eng/scripts/ci/regenerate.ts": (buf) => Buffer.from(patchRegenerateTs(buf.toString("utf8")), "utf8"), +}; + +function patchRegenerateTs(src: string): string { + let out = src; + + const argvBefore = ` jobs: { type: "string", short: "j" },\n help: { type: "boolean", short: "h" },`; + const argvAfter = ` jobs: { type: "string", short: "j" },\n singlePhase: { type: "boolean" },\n help: { type: "boolean", short: "h" },`; + if (!out.includes(argvAfter)) { + if (!out.includes(argvBefore)) { + throw new Error("regenerate.ts patch: argv anchor not found (upstream changed shape)"); + } + out = out.replace(argvBefore, argvAfter); + } + + const yamlBefore = ` // Emit YAML only - Python processing is batched after all specs compile\n options["emit-yaml-only"] = true;`; + const yamlAfter = ` // Emit YAML only - Python processing is batched after all specs compile\n if (!argv.values.singlePhase) {\n options["emit-yaml-only"] = true;\n }`; + if (!out.includes(yamlAfter)) { + if (!out.includes(yamlBefore)) { + throw new Error("regenerate.ts patch: emit-yaml-only anchor not found"); + } + out = out.replace(yamlBefore, yamlAfter); + } + + const batchBefore = ` const pySuccess = runBatchPythonProcessing(flavor, configCount, pyJobs);`; + const batchAfter = ` const pySuccess = argv.values.singlePhase\n ? true\n : runBatchPythonProcessing(flavor, configCount, pyJobs);`; + if (!out.includes(batchAfter)) { + if (!out.includes(batchBefore)) { + throw new Error("regenerate.ts patch: runBatchPythonProcessing anchor not found"); + } + out = out.replace(batchBefore, batchAfter); + } + + return out; +} + const EXCLUDED_SEGMENTS: ReadonlySet = new Set([ "__pycache__", "build", @@ -167,7 +229,11 @@ interface SyncStats { } function syncFile(srcAbs: string, destAbs: string, relPath: string, stats: SyncStats): void { - const srcBuf = fs.readFileSync(srcAbs); + let srcBuf = fs.readFileSync(srcAbs); + const transform = POST_PROCESS[toPosix(relPath)]; + if (transform) { + srcBuf = transform(srcBuf); + } const destBuf = readBytes(destAbs); if (destBuf && destBuf.equals(srcBuf)) { From 5e46f46118282a3b80f912ae3853fa213542da84 Mon Sep 17 00:00:00 2001 From: Yuchao Yan Date: Fri, 8 May 2026 13:28:13 +0800 Subject: [PATCH 08/36] update --- .../eng/scripts/ci/regenerate-common.ts | 746 +++++++++++++++++ .../eng/scripts/ci/regenerate.ts | 754 ++---------------- packages/typespec-python/eng/scripts/sync.ts | 74 +- 3 files changed, 802 insertions(+), 772 deletions(-) create mode 100644 packages/typespec-python/eng/scripts/ci/regenerate-common.ts diff --git a/packages/typespec-python/eng/scripts/ci/regenerate-common.ts b/packages/typespec-python/eng/scripts/ci/regenerate-common.ts new file mode 100644 index 0000000000..58d1a3d8c2 --- /dev/null +++ b/packages/typespec-python/eng/scripts/ci/regenerate-common.ts @@ -0,0 +1,746 @@ +/* eslint-disable no-console */ +/** + * Shared helpers, types, constants, and data tables used by `regenerate.ts`. + * + * This file is meant to be **byte-identical** between this package and the + * upstream `@typespec/http-client-python`. typespec-python syncs it from + * /core/packages/http-client-python/eng/scripts/ci/regenerate-common.ts + * via `pnpm sync`. + * + * Per-repo divergence (paths, emitter name, single-phase vs two-phase + * orchestration, argv/help text) lives in each repo's own `regenerate.ts`, + * which builds a `RegenerateContext` and feeds it into the helpers exported + * from this module. + */ + +import { compile, NodeHost } from "@typespec/compiler"; +import { execSync } from "child_process"; +import { existsSync, rmSync } from "fs"; +import { access, cp, mkdir, mkdtemp, readdir, writeFile } from "fs/promises"; +import { tmpdir } from "os"; +import { dirname, join, relative, resolve } from "path"; +import pc from "picocolors"; + +// ---- Public types ---- + +export interface RegenerateFlags { + flavor: string; + debug: boolean; + name?: string; +} + +export interface CompileTask { + spec: string; + outputDir: string; + options: Record; +} + +// Group of tasks for the same spec that must run sequentially +export interface TaskGroup { + spec: string; + tasks: CompileTask[]; +} + +/** + * Per-repo context injected into the helpers below. Every value is repo + * specific and must be supplied by the caller's `regenerate.ts`. + */ +export interface RegenerateContext { + /** Absolute path to the package root (the dir containing `package.json`). */ + pluginDir: string; + /** Absolute path to the azure-http-specs `specs/` dir. */ + azureHttpSpecs: string; + /** Absolute path to the http-specs `specs/` dir. */ + httpSpecs: string; + /** Absolute path to where generated SDKs should go (e.g. `/generator`). */ + generatedFolder: string; + /** Emitter name to invoke (e.g. `@azure-tools/typespec-python`). */ + emitterName: string; +} + +/** + * Optional knobs for `buildTaskGroups`. Kept here so the call site in each + * repo's `regenerate.ts` can opt into the upstream two-phase pipeline + * (`emitYamlOnly: true`) or the single-phase pipeline (default). + */ +export interface BuildTaskGroupsOptions { + /** If true, ask the emitter to write YAML only and skip Python codegen. */ + emitYamlOnly?: boolean; +} + +// ---- Public constants ---- + +export const SKIP_SPECS: string[] = ["type/file", "service/multiple-services"]; + +export const SpecialFlags: Record> = { + azure: { + "generate-test": true, + "generate-sample": true, + }, +}; + +// ---- Spec-specific emitter option overrides ---- + +export const AZURE_EMITTER_OPTIONS: Record< + string, + Record | Record[] +> = { + "azure/client-generator-core/access": { + namespace: "specs.azure.clientgenerator.core.access", + }, + "azure/client-generator-core/alternate-type": { + namespace: "specs.azure.clientgenerator.core.alternatetype", + }, + "azure/client-generator-core/api-version": { + namespace: "specs.azure.clientgenerator.core.apiversion", + }, + "azure/client-generator-core/client-initialization/default": { + namespace: "specs.azure.clientgenerator.core.clientinitialization.default", + }, + "azure/client-generator-core/client-initialization/individually": { + namespace: "specs.azure.clientgenerator.core.clientinitialization.individually", + }, + "azure/client-generator-core/client-initialization/individuallyParent": { + namespace: "specs.azure.clientgenerator.core.clientinitialization.individuallyparent", + }, + "azure/client-generator-core/client-location": { + namespace: "specs.azure.clientgenerator.core.clientlocation", + }, + "azure/client-generator-core/deserialize-empty-string-as-null": { + namespace: "specs.azure.clientgenerator.core.emptystring", + }, + "azure/client-generator-core/flatten-property": { + namespace: "specs.azure.clientgenerator.core.flattenproperty", + }, + "azure/client-generator-core/usage": { + namespace: "specs.azure.clientgenerator.core.usage", + }, + "azure/client-generator-core/client-doc": { + namespace: "specs.azure.clientgenerator.core.clientdoc", + }, + "azure/client-generator-core/override": { + namespace: "specs.azure.clientgenerator.core.override", + }, + "azure/client-generator-core/hierarchy-building": { + namespace: "specs.azure.clientgenerator.core.hierarchybuilding", + }, + "azure/core/basic": { + namespace: "specs.azure.core.basic", + }, + "azure/core/lro/rpc": { + namespace: "specs.azure.core.lro.rpc", + }, + "azure/core/lro/standard": { + namespace: "specs.azure.core.lro.standard", + }, + "azure/core/model": { + namespace: "specs.azure.core.model", + }, + "azure/core/page": { + namespace: "specs.azure.core.page", + }, + "azure/core/scalar": { + namespace: "specs.azure.core.scalar", + }, + "azure/core/traits": { + namespace: "specs.azure.core.traits", + }, + "azure/encode/duration": { + namespace: "specs.azure.encode.duration", + }, + "azure/example/basic": { + namespace: "specs.azure.example.basic", + }, + "azure/payload/pageable": { + namespace: "specs.azure.payload.pageable", + }, + "azure/versioning/previewVersion": { + namespace: "specs.azure.versioning.previewversion", + }, + "client/structure/default": { + namespace: "client.structure.service", + }, + "client/structure/multi-client": { + "package-name": "client-structure-multiclient", + namespace: "client.structure.multiclient", + }, + "client/structure/renamed-operation": { + "package-name": "client-structure-renamedoperation", + namespace: "client.structure.renamedoperation", + }, + "client/structure/two-operation-group": { + "package-name": "client-structure-twooperationgroup", + namespace: "client.structure.twooperationgroup", + }, + "client/naming": { + namespace: "client.naming.main", + }, + "client/overload": { + namespace: "client.overload", + }, + "encode/duration": { + namespace: "encode.duration", + }, + "encode/numeric": { + namespace: "encode.numeric", + }, + "parameters/basic": { + namespace: "parameters.basic", + }, + "parameters/spread": { + namespace: "parameters.spread", + }, + "payload/content-negotiation": { + namespace: "payload.contentnegotiation", + }, + "payload/multipart": { + namespace: "payload.multipart", + }, + "serialization/encoded-name/json": { + namespace: "serialization.encodedname.json", + }, + "special-words": { + namespace: "specialwords", + }, + "service/multi-service": { + namespace: "service.multiservice", + }, + "client/structure/client-operation-group": { + "package-name": "client-structure-clientoperationgroup", + namespace: "client.structure.clientoperationgroup", + }, +}; + +export const EMITTER_OPTIONS: Record< + string, + Record | Record[] +> = { + "resiliency/srv-driven/old.tsp": { + "package-name": "resiliency-srv-driven1", + namespace: "resiliency.srv.driven1", + "package-mode": "azure-dataplane", + "package-pprint-name": "ResiliencySrvDriven1", + }, + "resiliency/srv-driven": { + "package-name": "resiliency-srv-driven2", + namespace: "resiliency.srv.driven2", + "package-mode": "azure-dataplane", + "package-pprint-name": "ResiliencySrvDriven2", + }, + "authentication/api-key": { + "clear-output-folder": "true", + }, + "authentication/http/custom": { + "package-name": "authentication-http-custom", + namespace: "authentication.http.custom", + "package-pprint-name": "Authentication Http Custom", + }, + "authentication/union": [ + { + "package-name": "authentication-union", + namespace: "authentication.union", + }, + { + "package-name": "setuppy-authentication-union", + namespace: "setuppy.authentication.union", + "keep-setup-py": "true", + }, + ], + "type/array": { + "package-name": "typetest-array", + namespace: "typetest.array", + }, + "type/dictionary": { + "package-name": "typetest-dictionary", + namespace: "typetest.dictionary", + }, + "type/enum/extensible": { + "package-name": "typetest-enum-extensible", + namespace: "typetest.enum.extensible", + }, + "type/enum/fixed": { + "package-name": "typetest-enum-fixed", + namespace: "typetest.enum.fixed", + }, + "type/model/empty": { + "package-name": "typetest-model-empty", + namespace: "typetest.model.empty", + }, + "type/model/inheritance/enum-discriminator": { + "package-name": "typetest-model-enumdiscriminator", + namespace: "typetest.model.enumdiscriminator", + }, + "type/model/inheritance/nested-discriminator": { + "package-name": "typetest-model-nesteddiscriminator", + namespace: "typetest.model.nesteddiscriminator", + }, + "type/model/inheritance/not-discriminated": { + "package-name": "typetest-model-notdiscriminated", + namespace: "typetest.model.notdiscriminated", + }, + "type/model/inheritance/single-discriminator": { + "package-name": "typetest-model-singlediscriminator", + namespace: "typetest.model.singlediscriminator", + }, + "type/model/inheritance/recursive": [ + { + "package-name": "typetest-model-recursive", + namespace: "typetest.model.recursive", + }, + { + "package-name": "generation-subdir", + namespace: "generation.subdir", + "generation-subdir": "_generated", + "generate-test": "false", + "clear-output-folder": "true", + }, + ], + "type/model/usage": { + "package-name": "typetest-model-usage", + namespace: "typetest.model.usage", + }, + "type/model/visibility": [ + { + "package-name": "typetest-model-visibility", + namespace: "typetest.model.visibility", + }, + { + "package-name": "headasbooleantrue", + namespace: "headasbooleantrue", + "head-as-boolean": "true", + }, + { + "package-name": "headasbooleanfalse", + namespace: "headasbooleanfalse", + "head-as-boolean": "false", + }, + ], + "type/property/nullable": { + "package-name": "typetest-property-nullable", + namespace: "typetest.property.nullable", + }, + "type/property/optionality": { + "package-name": "typetest-property-optional", + namespace: "typetest.property.optional", + }, + "type/property/additional-properties": { + "package-name": "typetest-property-additionalproperties", + namespace: "typetest.property.additionalproperties", + }, + "type/scalar": { + "package-name": "typetest-scalar", + namespace: "typetest.scalar", + }, + "type/property/value-types": { + "package-name": "typetest-property-valuetypes", + namespace: "typetest.property.valuetypes", + }, + "type/union": { + "package-name": "typetest-union", + namespace: "typetest.union", + }, + "type/union/discriminated": { + "package-name": "typetest-discriminatedunion", + namespace: "typetest.discriminatedunion", + }, + "type/file": { + "package-name": "typetest-file", + namespace: "typetest.file", + }, + documentation: { + "package-name": "specs-documentation", + namespace: "specs.documentation", + }, + "versioning/added": [ + { + "package-name": "versioning-added", + namespace: "versioning.added", + }, + { + "package-name": "generation-subdir2", + namespace: "generation.subdir2", + "generate-test": "false", + "generation-subdir": "_generated", + }, + ], +}; + +// ---- Public helpers ---- + +export function toPosix(p: string): string { + return p.replace(/\\/g, "/"); +} + +/** + * Whether a spec path belongs to azure-http-specs (vs standard http-specs). + * Uses the `azure-http-specs` substring rather than `azure` to avoid false + * positives when the working-dir path itself contains "azure" (e.g. + * azure-sdk-for-python). + */ +export function isAzureSpec(spec: string): boolean { + return spec.includes("azure-http-specs"); +} + +export function defaultPackageName(spec: string, ctx: RegenerateContext): string { + const specDir = isAzureSpec(spec) ? ctx.azureHttpSpecs : ctx.httpSpecs; + return toPosix(relative(specDir, dirname(spec))) + .replace(/\//g, "-") + .toLowerCase(); +} + +export function getEmitterOptions( + spec: string, + flavor: string, + ctx: RegenerateContext, +): Record[] { + const specDir = isAzureSpec(spec) ? ctx.azureHttpSpecs : ctx.httpSpecs; + const relativeSpec = toPosix(relative(specDir, spec)); + const key = relativeSpec.includes("resiliency/srv-driven/old.tsp") + ? relativeSpec + : dirname(relativeSpec); + const emitterOpts = + EMITTER_OPTIONS[key] || (flavor === "azure" ? AZURE_EMITTER_OPTIONS[key] : [{}]) || [{}]; + return Array.isArray(emitterOpts) ? emitterOpts : [emitterOpts]; +} + +/** + * Walk `baseDir` and collect every TypeSpec entry-point file that the + * regenerator should compile (handles `client.tsp`, `main.tsp`, and the + * special `resiliency/srv-driven/old.tsp` case). + */ +export async function getSubdirectories( + baseDir: string, + flags: RegenerateFlags, +): Promise { + const subdirectories: string[] = []; + + async function searchDir(currentDir: string) { + const items = await readdir(currentDir, { withFileTypes: true }); + + const promisesArray = items.map(async (item) => { + const subDirPath = join(currentDir, item.name); + if (item.isDirectory()) { + const mainTspPath = join(subDirPath, "main.tsp"); + const clientTspPath = join(subDirPath, "client.tsp"); + + const mainTspRelativePath = toPosix(relative(baseDir, mainTspPath)); + + if (SKIP_SPECS.some((skipSpec) => mainTspRelativePath.includes(skipSpec))) return; + + const hasMainTsp = await access(mainTspPath) + .then(() => true) + .catch(() => false); + const hasClientTsp = await access(clientTspPath) + .then(() => true) + .catch(() => false); + + if (mainTspRelativePath.toLowerCase().includes(flags.name || "")) { + if (mainTspRelativePath.includes("resiliency/srv-driven")) { + subdirectories.push(resolve(subDirPath, "old.tsp")); + } + if (hasClientTsp) { + subdirectories.push(resolve(subDirPath, "client.tsp")); + } else if (hasMainTsp) { + subdirectories.push(resolve(subDirPath, "main.tsp")); + } + } + + await searchDir(subDirPath); + } + }); + + await Promise.all(promisesArray); + } + + await searchDir(baseDir); + return subdirectories; +} + +export function buildTaskGroups( + specs: string[], + flags: RegenerateFlags, + ctx: RegenerateContext, + options: BuildTaskGroupsOptions = {}, +): TaskGroup[] { + const groups: TaskGroup[] = []; + + for (const spec of specs) { + const tasks: CompileTask[] = []; + + for (const emitterConfig of getEmitterOptions(spec, flags.flavor, ctx)) { + // Apply flavor defaults first, then per-spec options so they can override + // (e.g. "generate-test": "false") + const opts: Record = {}; + for (const [k, v] of Object.entries(SpecialFlags[flags.flavor] ?? {})) { + opts[k] = v; + } + Object.assign(opts, emitterConfig); + + opts["flavor"] = flags.flavor; + + // Set output directory - tests/generated// structure. + // Always anchored at /../tests/generated regardless of + // pluginDir, so generator-only checkouts work too. + const packageName = (opts["package-name"] as string) || defaultPackageName(spec, ctx); + const outputDir = + (opts["emitter-output-dir"] as string) || + toPosix(`${ctx.generatedFolder}/../tests/generated/${flags.flavor}/${packageName}`); + opts["emitter-output-dir"] = outputDir; + + if (flags.debug) { + opts["debug"] = true; + } + + opts["examples-dir"] = toPosix(join(dirname(spec), "examples")); + + if (options.emitYamlOnly) { + // Emit YAML only - Python processing is batched after all specs compile. + opts["emit-yaml-only"] = true; + } + + tasks.push({ spec, outputDir, options: opts }); + } + + groups.push({ spec, tasks }); + } + + return groups; +} + +export async function compileSpec( + task: CompileTask, + ctx: RegenerateContext, +): Promise<{ success: boolean; error?: string }> { + const { spec, outputDir, options } = task; + + try { + const compilerOptions = { + emit: [ctx.pluginDir], + options: { + [ctx.emitterName]: options, + }, + }; + + const program = await compile(NodeHost, spec, compilerOptions); + + if (program.hasError()) { + const errors = program.diagnostics + .filter((d) => d.severity === "error") + .map((d) => d.message) + .join("\n"); + return { success: false, error: errors }; + } + + return { success: true }; + } catch (err) { + rmSync(outputDir, { recursive: true, force: true }); + return { success: false, error: String(err) }; + } +} + +export function renderProgressBar( + completed: number, + failed: number, + total: number, + width: number = 40, +): string { + const successCount = completed - failed; + const successWidth = Math.round((successCount / total) * width); + const failWidth = Math.round((failed / total) * width); + const emptyWidth = width - successWidth - failWidth; + + const successBar = pc.bgGreen(" ".repeat(successWidth)); + const failBar = failed > 0 ? pc.bgRed(" ".repeat(failWidth)) : ""; + const emptyBar = pc.dim("░".repeat(Math.max(0, emptyWidth))); + + const percent = Math.round((completed / total) * 100); + return `${successBar}${failBar}${emptyBar} ${pc.cyan(`${percent}%`)} (${completed}/${total})`; +} + +export async function runParallel( + groups: TaskGroup[], + maxJobs: number, + ctx: RegenerateContext, +): Promise> { + const results = new Map(); + const executing: Set> = new Set(); + + const totalTasks = groups.reduce((sum, g) => sum + g.tasks.length, 0); + let completed = 0; + let failed = 0; + const failedSpecs: string[] = []; + + const isTTY = process.stdout.isTTY; + + const updateProgress = () => { + if (isTTY) { + process.stdout.write(`\r${renderProgressBar(completed, failed, totalTasks)}`); + } + }; + + updateProgress(); + + for (const group of groups) { + // Each group runs as a unit - tasks within a group run sequentially + // to avoid state pollution. Different groups run in parallel. + const runGroup = async () => { + const specDir = isAzureSpec(group.spec) ? ctx.azureHttpSpecs : ctx.httpSpecs; + const shortName = toPosix(relative(specDir, dirname(group.spec))); + + let groupSuccess = true; + for (const task of group.tasks) { + const packageName = (task.options["package-name"] as string) || shortName; + + const result = await compileSpec(task, ctx); + completed++; + + if (!result.success) { + failed++; + failedSpecs.push(`${packageName}: ${result.error}`); + groupSuccess = false; + } + + updateProgress(); + } + + results.set(group.spec, groupSuccess); + }; + + const p = runGroup().finally(() => executing.delete(p)); + executing.add(p); + + if (executing.size >= maxJobs) { + await Promise.race(executing); + } + } + + await Promise.all(executing); + + if (isTTY) { + process.stdout.write("\r" + " ".repeat(60) + "\r"); + } + + if (failedSpecs.length > 0) { + console.log(pc.red(`\nFailed specs:`)); + for (const spec of failedSpecs) { + console.log(pc.red(` • ${spec}`)); + } + } + + return results; +} + +/** + * Pre-create the marker files that the test harness expects to find before + * regeneration so it can verify they're cleared/preserved correctly. + */ +export async function preprocess(flavor: string, generatedFolder: string): Promise { + if (flavor !== "azure") return; + + const testsGeneratedDir = resolve(generatedFolder, "../tests/generated/azure"); + + const DELETE_CONTENT = "# This file is to be deleted after regeneration"; + const KEEP_CONTENT = "# This file is to be kept after regeneration"; + const DELETE_FILE = "to_be_deleted.py"; + const entries: { folder: string[]; file: string; content: string }[] = [ + { + folder: ["authentication-api-key", "authentication", "apikey", "_operations"], + file: DELETE_FILE, + content: DELETE_CONTENT, + }, + { + folder: ["generation-subdir", "generation", "subdir", "_generated"], + file: DELETE_FILE, + content: DELETE_CONTENT, + }, + { + folder: ["generation-subdir", "generated_tests"], + file: DELETE_FILE, + content: DELETE_CONTENT, + }, + { + folder: ["generation-subdir", "generation", "subdir"], + file: "to_be_kept.py", + content: KEEP_CONTENT, + }, + ]; + + await Promise.all( + entries.map(async ({ folder, file, content }) => { + const targetFolder = join(testsGeneratedDir, ...folder); + await mkdir(targetFolder, { recursive: true }); + await writeFile(join(targetFolder, file), content); + }), + ); +} + +/** + * Resets the `tests/generated/{azure,unbranded}` baseline by sparse-checking-out + * `eng/tools/emitter/gen` from the Azure/azure-sdk-for-python repo, then + * deleting a couple of fully-generated package folders so regeneration has to + * recreate them from scratch (smoke test of full-emit path). + * + * `generatedFolder` is the per-repo `generator/` directory; baseline lands at + * `/../tests/generated`. + */ +export async function prepareBaselineOfGeneratedCode(generatedFolder: string): Promise { + const repoUrl = "https://github.com/Azure/azure-sdk-for-python.git"; + const branch = "main"; + const sourceSubdir = "eng/tools/emitter/gen"; + const testsGeneratedDir = resolve(generatedFolder, "../tests/generated"); + + console.log(pc.cyan(`\n${"=".repeat(60)}`)); + console.log(pc.cyan(`Resetting baseline from ${repoUrl} (${branch}/${sourceSubdir})`)); + console.log(pc.cyan(`${"=".repeat(60)}\n`)); + + // Wipe tests/generated + if (existsSync(testsGeneratedDir)) { + console.log(pc.dim(`Removing ${testsGeneratedDir}`)); + rmSync(testsGeneratedDir, { recursive: true, force: true }); + } + + // Sparse-checkout the baseline folder into a temp directory + const tempDir = await mkdtemp(join(tmpdir(), "azsdk-baseline-")); + try { + console.log(pc.dim(`Cloning into ${tempDir}`)); + const run = (cmd: string) => + execSync(cmd, { cwd: tempDir, stdio: ["ignore", "ignore", "inherit"] }); + + run(`git init`); + run(`git remote add origin ${repoUrl}`); + run(`git config core.sparseCheckout true`); + run(`git sparse-checkout init --cone`); + run(`git sparse-checkout set ${sourceSubdir}`); + run(`git fetch --depth 1 origin ${branch}`); + run(`git checkout FETCH_HEAD`); + + const sourceRoot = join(tempDir, ...sourceSubdir.split("/")); + for (const flavor of ["azure", "unbranded"]) { + const src = join(sourceRoot, flavor); + const dest = join(testsGeneratedDir, flavor); + if (!existsSync(src)) { + console.warn(pc.yellow(`Baseline folder not found: ${src}`)); + continue; + } + console.log(pc.dim(`Copying ${flavor}/ -> ${dest}`)); + await cp(src, dest, { recursive: true }); + } + + console.log(pc.green(`Baseline reset complete.\n`)); + } finally { + rmSync(tempDir, { recursive: true, force: true }); + } + + // Delete a couple of fully-generated package folders so regeneration has to + // recreate them from scratch (smoke test of full-emit path). + const targetsToDelete = [ + join(testsGeneratedDir, "azure", "authentication-http-custom"), + join(testsGeneratedDir, "unbranded", "encode-array"), + ]; + for (const target of targetsToDelete) { + if (existsSync(target)) { + console.log(pc.dim(`Deleting ${target}`)); + rmSync(target, { recursive: true, force: true }); + } + } +} diff --git a/packages/typespec-python/eng/scripts/ci/regenerate.ts b/packages/typespec-python/eng/scripts/ci/regenerate.ts index fc9dd46abb..f35bc24a48 100644 --- a/packages/typespec-python/eng/scripts/ci/regenerate.ts +++ b/packages/typespec-python/eng/scripts/ci/regenerate.ts @@ -3,20 +3,31 @@ * Regenerates Python SDK code from TypeSpec definitions. * * Uses in-process TypeSpec compilation to avoid subprocess spawning overhead. - * This is significantly faster than spawning `tsp compile` for each spec. + * Specs are compiled in parallel and the emitter writes the final `.py` files + * directly inside the same process — no YAML-only intermediate, no batched + * Python subprocess. This single-phase pipeline is faster for the wrapper + * use-case (azure flavor only, smaller spec set, Windows). + * + * Shared helpers/data live in `regenerate-common.ts` and are kept identical + * with the upstream `@typespec/http-client-python` copy via `pnpm sync`. */ -import { compile, NodeHost } from "@typespec/compiler"; -import { execSync } from "child_process"; -import { existsSync, rmSync } from "fs"; -import { access, mkdir, readdir, writeFile } from "fs/promises"; import { platform } from "os"; -import { dirname, join, relative, resolve } from "path"; +import { dirname, resolve } from "path"; import pc from "picocolors"; import { fileURLToPath } from "url"; import { parseArgs } from "util"; -// Parse arguments +import { + buildTaskGroups, + getSubdirectories, + prepareBaselineOfGeneratedCode, + preprocess, + RegenerateContext, + RegenerateFlags, + runParallel, +} from "./regenerate-common.js"; + const argv = parseArgs({ args: process.argv.slice(2), options: { @@ -27,7 +38,6 @@ const argv = parseArgs({ emitterName: { type: "string" }, generatedFolder: { type: "string" }, jobs: { type: "string", short: "j" }, - singlePhase: { type: "boolean" }, help: { type: "boolean", short: "h" }, }, }); @@ -37,8 +47,9 @@ if (argv.values.help) { ${pc.bold("Usage:")} tsx regenerate.ts [options] ${pc.bold("Description:")} - Regenerates Python SDK code from TypeSpec definitions using in-process compilation. - This avoids spawning a new Node.js process for each spec, making it significantly faster. + Regenerates Python SDK code from TypeSpec definitions using in-process + compilation. This avoids spawning a new Node.js process for each spec, + making it significantly faster. ${pc.bold("Options:")} ${pc.cyan("-f, --flavor ")} @@ -76,395 +87,8 @@ ${pc.bold("Examples:")} process.exit(0); } -// ---- Shared constants ---- - -const SKIP_SPECS: string[] = ["type/file", "service/multiple-services"]; - -const SpecialFlags: Record> = { - azure: { - "generate-test": true, - "generate-sample": true, - }, -}; - -function toPosix(dir: string): string { - return dir.replace(/\\/g, "/"); -} - -interface RegenerateFlags { - flavor: string; - debug: boolean; - name?: string; - pyodide?: boolean; -} - -// ---- Base emitter options ---- - -const AZURE_EMITTER_OPTIONS: Record | Record[]> = { - "azure/client-generator-core/access": { - namespace: "specs.azure.clientgenerator.core.access", - }, - "azure/client-generator-core/alternate-type": { - namespace: "specs.azure.clientgenerator.core.alternatetype", - }, - "azure/client-generator-core/api-version": { - namespace: "specs.azure.clientgenerator.core.apiversion", - }, - "azure/client-generator-core/client-initialization/default": { - namespace: "specs.azure.clientgenerator.core.clientinitialization.default", - }, - "azure/client-generator-core/client-initialization/individually": { - namespace: "specs.azure.clientgenerator.core.clientinitialization.individually", - }, - "azure/client-generator-core/client-initialization/individuallyParent": { - namespace: "specs.azure.clientgenerator.core.clientinitialization.individuallyparent", - }, - "azure/client-generator-core/client-location": { - namespace: "specs.azure.clientgenerator.core.clientlocation", - }, - "azure/client-generator-core/deserialize-empty-string-as-null": { - namespace: "specs.azure.clientgenerator.core.emptystring", - }, - "azure/client-generator-core/flatten-property": { - namespace: "specs.azure.clientgenerator.core.flattenproperty", - }, - "azure/client-generator-core/usage": { - namespace: "specs.azure.clientgenerator.core.usage", - }, - "azure/client-generator-core/client-doc": { - namespace: "specs.azure.clientgenerator.core.clientdoc", - }, - "azure/client-generator-core/override": { - namespace: "specs.azure.clientgenerator.core.override", - }, - "azure/client-generator-core/hierarchy-building": { - namespace: "specs.azure.clientgenerator.core.hierarchybuilding", - }, - "azure/core/basic": { - namespace: "specs.azure.core.basic", - }, - "azure/core/lro/rpc": { - namespace: "specs.azure.core.lro.rpc", - }, - "azure/core/lro/standard": { - namespace: "specs.azure.core.lro.standard", - }, - "azure/core/model": { - namespace: "specs.azure.core.model", - }, - "azure/core/page": { - namespace: "specs.azure.core.page", - }, - "azure/core/scalar": { - namespace: "specs.azure.core.scalar", - }, - "azure/core/traits": { - namespace: "specs.azure.core.traits", - }, - "azure/encode/duration": { - namespace: "specs.azure.encode.duration", - }, - "azure/example/basic": { - namespace: "specs.azure.example.basic", - }, - "azure/payload/pageable": { - namespace: "specs.azure.payload.pageable", - }, - "azure/versioning/previewVersion": { - namespace: "specs.azure.versioning.previewversion", - }, - "client/structure/default": { - namespace: "client.structure.service", - }, - "client/structure/multi-client": { - "package-name": "client-structure-multiclient", - namespace: "client.structure.multiclient", - }, - "client/structure/renamed-operation": { - "package-name": "client-structure-renamedoperation", - namespace: "client.structure.renamedoperation", - }, - "client/structure/two-operation-group": { - "package-name": "client-structure-twooperationgroup", - namespace: "client.structure.twooperationgroup", - }, - "client/naming": { - namespace: "client.naming.main", - }, - "client/overload": { - namespace: "client.overload", - }, - "encode/duration": { - namespace: "encode.duration", - }, - "encode/numeric": { - namespace: "encode.numeric", - }, - "parameters/basic": { - namespace: "parameters.basic", - }, - "parameters/spread": { - namespace: "parameters.spread", - }, - "payload/content-negotiation": { - namespace: "payload.contentnegotiation", - }, - "payload/multipart": { - namespace: "payload.multipart", - }, - "serialization/encoded-name/json": { - namespace: "serialization.encodedname.json", - }, - "special-words": { - namespace: "specialwords", - }, - "service/multi-service": { - namespace: "service.multiservice", - }, - "client/structure/client-operation-group": { - "package-name": "client-structure-clientoperationgroup", - namespace: "client.structure.clientoperationgroup", - }, -}; - -const EMITTER_OPTIONS: Record | Record[]> = { - "resiliency/srv-driven/old.tsp": { - "package-name": "resiliency-srv-driven1", - namespace: "resiliency.srv.driven1", - "package-mode": "azure-dataplane", - "package-pprint-name": "ResiliencySrvDriven1", - }, - "resiliency/srv-driven": { - "package-name": "resiliency-srv-driven2", - namespace: "resiliency.srv.driven2", - "package-mode": "azure-dataplane", - "package-pprint-name": "ResiliencySrvDriven2", - }, - "authentication/api-key": { - "clear-output-folder": "true", - }, - "authentication/http/custom": { - "package-name": "authentication-http-custom", - namespace: "authentication.http.custom", - "package-pprint-name": "Authentication Http Custom", - }, - "authentication/union": [ - { - "package-name": "authentication-union", - namespace: "authentication.union", - }, - { - "package-name": "setuppy-authentication-union", - namespace: "setuppy.authentication.union", - "keep-setup-py": "true", - }, - ], - "type/array": { - "package-name": "typetest-array", - namespace: "typetest.array", - }, - "type/dictionary": { - "package-name": "typetest-dictionary", - namespace: "typetest.dictionary", - }, - "type/enum/extensible": { - "package-name": "typetest-enum-extensible", - namespace: "typetest.enum.extensible", - }, - "type/enum/fixed": { - "package-name": "typetest-enum-fixed", - namespace: "typetest.enum.fixed", - }, - "type/model/empty": { - "package-name": "typetest-model-empty", - namespace: "typetest.model.empty", - }, - "type/model/inheritance/enum-discriminator": { - "package-name": "typetest-model-enumdiscriminator", - namespace: "typetest.model.enumdiscriminator", - }, - "type/model/inheritance/nested-discriminator": { - "package-name": "typetest-model-nesteddiscriminator", - namespace: "typetest.model.nesteddiscriminator", - }, - "type/model/inheritance/not-discriminated": { - "package-name": "typetest-model-notdiscriminated", - namespace: "typetest.model.notdiscriminated", - }, - "type/model/inheritance/single-discriminator": { - "package-name": "typetest-model-singlediscriminator", - namespace: "typetest.model.singlediscriminator", - }, - "type/model/inheritance/recursive": [ - { - "package-name": "typetest-model-recursive", - namespace: "typetest.model.recursive", - }, - { - "package-name": "generation-subdir", - namespace: "generation.subdir", - "generation-subdir": "_generated", - "generate-test": "false", - "clear-output-folder": "true", - }, - ], - "type/model/usage": { - "package-name": "typetest-model-usage", - namespace: "typetest.model.usage", - }, - "type/model/visibility": [ - { - "package-name": "typetest-model-visibility", - namespace: "typetest.model.visibility", - }, - { - "package-name": "headasbooleantrue", - namespace: "headasbooleantrue", - "head-as-boolean": "true", - }, - { - "package-name": "headasbooleanfalse", - namespace: "headasbooleanfalse", - "head-as-boolean": "false", - }, - ], - "type/property/nullable": { - "package-name": "typetest-property-nullable", - namespace: "typetest.property.nullable", - }, - "type/property/optionality": { - "package-name": "typetest-property-optional", - namespace: "typetest.property.optional", - }, - "type/property/additional-properties": { - "package-name": "typetest-property-additionalproperties", - namespace: "typetest.property.additionalproperties", - }, - "type/scalar": { - "package-name": "typetest-scalar", - namespace: "typetest.scalar", - }, - "type/property/value-types": { - "package-name": "typetest-property-valuetypes", - namespace: "typetest.property.valuetypes", - }, - "type/union": { - "package-name": "typetest-union", - namespace: "typetest.union", - }, - "type/union/discriminated": { - "package-name": "typetest-discriminatedunion", - namespace: "typetest.discriminatedunion", - }, - "type/file": { - "package-name": "typetest-file", - namespace: "typetest.file", - }, - documentation: { - "package-name": "specs-documentation", - namespace: "specs.documentation", - }, - "versioning/added": [ - { - "package-name": "versioning-added", - namespace: "versioning.added", - }, - { - "package-name": "generation-subdir2", - namespace: "generation.subdir2", - "generate-test": "false", - "generation-subdir": "_generated", - }, - ], -}; - -// ---- Shared utility functions ---- - -async function getSubdirectories(baseDir: string, flags: RegenerateFlags): Promise { - const subdirectories: string[] = []; - - async function searchDir(currentDir: string) { - const items = await readdir(currentDir, { withFileTypes: true }); - - const promisesArray = items.map(async (item) => { - const subDirPath = join(currentDir, item.name); - if (item.isDirectory()) { - const mainTspPath = join(subDirPath, "main.tsp"); - const clientTspPath = join(subDirPath, "client.tsp"); - - const mainTspRelativePath = toPosix(relative(baseDir, mainTspPath)); - - if (SKIP_SPECS.some((skipSpec) => mainTspRelativePath.includes(skipSpec))) return; - - const hasMainTsp = await access(mainTspPath) - .then(() => true) - .catch(() => false); - const hasClientTsp = await access(clientTspPath) - .then(() => true) - .catch(() => false); - - if (mainTspRelativePath.toLowerCase().includes(flags.name || "")) { - if (mainTspRelativePath.includes("resiliency/srv-driven")) { - subdirectories.push(resolve(subDirPath, "old.tsp")); - } - if (hasClientTsp) { - subdirectories.push(resolve(subDirPath, "client.tsp")); - } else if (hasMainTsp) { - subdirectories.push(resolve(subDirPath, "main.tsp")); - } - } - - await searchDir(subDirPath); - } - }); - - await Promise.all(promisesArray); - } - - await searchDir(baseDir); - return subdirectories; -} - -async function preprocess(flavor: string, generatedFolder: string): Promise { - if (flavor === "azure") { - const testsGeneratedDir = resolve(generatedFolder, "../tests/generated/azure"); - - const DELETE_CONTENT = "# This file is to be deleted after regeneration"; - const DELETE_FILE = "to_be_deleted.py"; - const entries: { folder: string[]; file: string; content: string }[] = [ - { - folder: ["authentication-api-key", "authentication", "apikey", "_operations"], - file: DELETE_FILE, - content: DELETE_CONTENT, - }, - { - folder: ["generation-subdir", "generation", "subdir", "_generated"], - file: DELETE_FILE, - content: DELETE_CONTENT, - }, - { - folder: ["generation-subdir", "generated_tests"], - file: DELETE_FILE, - content: DELETE_CONTENT, - }, - { - folder: ["generation-subdir", "generation", "subdir"], - file: "to_be_kept.py", - content: "# This file is to be kept after regeneration", - }, - ]; - - await Promise.all( - entries.map(async ({ folder, file, content }) => { - const targetFolder = join(testsGeneratedDir, ...folder); - await mkdir(targetFolder, { recursive: true }); - await writeFile(join(targetFolder, file), content); - }), - ); - } -} - -// Get paths +// Resolve repo-specific paths. PLUGIN_DIR defaults to two levels above this +// file (eng/scripts/ci -> eng/scripts -> eng -> packageRoot). const SCRIPT_DIR = dirname(fileURLToPath(import.meta.url)); const PLUGIN_DIR = argv.values.pluginDir ? resolve(argv.values.pluginDir) @@ -474,270 +98,15 @@ const HTTP_SPECS = resolve(PLUGIN_DIR, "node_modules/@typespec/http-specs/specs" const GENERATED_FOLDER = argv.values.generatedFolder ? resolve(argv.values.generatedFolder) : resolve(PLUGIN_DIR, "generator"); -const EMITTER_NAME = argv.values.emitterName || "@typespec/http-client-python"; - -interface CompileTask { - spec: string; - outputDir: string; - options: Record; -} - -// Group of tasks for the same spec that must run sequentially -interface TaskGroup { - spec: string; - tasks: CompileTask[]; -} - -// Check whether a spec path belongs to azure-http-specs (vs standard http-specs). -// Using "azure-http-specs" instead of "azure" to avoid false positives when the -// working directory path contains "azure" (e.g. azure-sdk-for-python). -function isAzureSpec(spec: string): boolean { - return spec.includes("azure-http-specs"); -} - -function defaultPackageName(spec: string): string { - const specDir = isAzureSpec(spec) ? AZURE_HTTP_SPECS : HTTP_SPECS; - return toPosix(relative(specDir, dirname(spec))) - .replace(/\//g, "-") - .toLowerCase(); -} - -function getEmitterOptions(spec: string, flavor: string): Record[] { - const specDir = isAzureSpec(spec) ? AZURE_HTTP_SPECS : HTTP_SPECS; - const relativeSpec = toPosix(relative(specDir, spec)); - const key = relativeSpec.includes("resiliency/srv-driven/old.tsp") - ? relativeSpec - : dirname(relativeSpec); - const emitterOpts = EMITTER_OPTIONS[key] || - (flavor === "azure" ? AZURE_EMITTER_OPTIONS[key] : [{}]) || [{}]; - return Array.isArray(emitterOpts) ? emitterOpts : [emitterOpts]; -} - -function buildTaskGroups(specs: string[], flags: RegenerateFlags): TaskGroup[] { - const groups: TaskGroup[] = []; - - for (const spec of specs) { - const tasks: CompileTask[] = []; - - for (const emitterConfig of getEmitterOptions(spec, flags.flavor)) { - // Apply flavor defaults first, then per-spec options so they can override (e.g., "generate-test": "false") - const options: Record = {}; - for (const [k, v] of Object.entries(SpecialFlags[flags.flavor] ?? {})) { - options[k] = v; - } - Object.assign(options, emitterConfig); - - // Add flavor - options["flavor"] = flags.flavor; - - // Set output directory - use tests/generated// structure - const packageName = (options["package-name"] as string) || defaultPackageName(spec); - const outputDir = - (options["emitter-output-dir"] as string) || - toPosix(`${GENERATED_FOLDER}/../tests/generated/${flags.flavor}/${packageName}`); - options["emitter-output-dir"] = outputDir; - - // Debug mode - if (flags.debug) { - options["debug"] = true; - } - - // Examples directory - options["examples-dir"] = toPosix(join(dirname(spec), "examples")); - - // Emit YAML only - Python processing is batched after all specs compile - if (!argv.values.singlePhase) { - options["emit-yaml-only"] = true; - } - - tasks.push({ spec, outputDir, options }); - } - - groups.push({ spec, tasks }); - } - - return groups; -} - -async function compileSpec(task: CompileTask): Promise<{ success: boolean; error?: string }> { - const { spec, outputDir, options } = task; - - try { - // Build compiler options - const compilerOptions = { - emit: [PLUGIN_DIR], - options: { - [EMITTER_NAME]: options, - }, - }; - - // Compile using TypeSpec compiler directly (no subprocess) - const program = await compile(NodeHost, spec, compilerOptions); - - if (program.hasError()) { - const errors = program.diagnostics - .filter((d) => d.severity === "error") - .map((d) => d.message) - .join("\n"); - return { success: false, error: errors }; - } - - return { success: true }; - } catch (err) { - // Clean up on error - rmSync(outputDir, { recursive: true, force: true }); - return { success: false, error: String(err) }; - } -} - -function renderProgressBar( - completed: number, - failed: number, - total: number, - width: number = 40, -): string { - const successCount = completed - failed; - const successWidth = Math.round((successCount / total) * width); - const failWidth = Math.round((failed / total) * width); - const emptyWidth = width - successWidth - failWidth; - - const successBar = pc.bgGreen(" ".repeat(successWidth)); - const failBar = failed > 0 ? pc.bgRed(" ".repeat(failWidth)) : ""; - const emptyBar = pc.dim("░".repeat(Math.max(0, emptyWidth))); - - const percent = Math.round((completed / total) * 100); - return `${successBar}${failBar}${emptyBar} ${pc.cyan(`${percent}%`)} (${completed}/${total})`; -} - -async function runParallel(groups: TaskGroup[], maxJobs: number): Promise> { - const results = new Map(); - const executing: Set> = new Set(); - - // Count total tasks for progress - const totalTasks = groups.reduce((sum, g) => sum + g.tasks.length, 0); - let completed = 0; - let failed = 0; - const failedSpecs: string[] = []; - - // Check if we're in a TTY for progress bar updates - const isTTY = process.stdout.isTTY; - - const updateProgress = () => { - if (isTTY) { - process.stdout.write(`\r${renderProgressBar(completed, failed, totalTasks)}`); - } - }; - - // Initial progress bar - updateProgress(); - - for (const group of groups) { - // Each group runs as a unit - tasks within a group run sequentially - // But different groups can run in parallel - const runGroup = async () => { - const specDir = isAzureSpec(group.spec) ? AZURE_HTTP_SPECS : HTTP_SPECS; - const shortName = toPosix(relative(specDir, dirname(group.spec))); - - // Run all tasks in this group sequentially to avoid state pollution - let groupSuccess = true; - for (const task of group.tasks) { - const packageName = (task.options["package-name"] as string) || shortName; - - const result = await compileSpec(task); - completed++; - - if (!result.success) { - failed++; - failedSpecs.push(`${packageName}: ${result.error}`); - groupSuccess = false; - } - - updateProgress(); - } - - results.set(group.spec, groupSuccess); - }; - - const p = runGroup().finally(() => executing.delete(p)); - executing.add(p); - - if (executing.size >= maxJobs) { - await Promise.race(executing); - } - } - - await Promise.all(executing); - - // Clear progress bar line and print final status - if (isTTY) { - process.stdout.write("\r" + " ".repeat(60) + "\r"); - } - - // Print failures at the end - if (failedSpecs.length > 0) { - console.log(pc.red(`\nFailed specs:`)); - for (const spec of failedSpecs) { - console.log(pc.red(` • ${spec}`)); - } - } - - return results; -} - -async function collectConfigFiles(generatedDir: string, flavor: string): Promise { - const flavorDir = join(generatedDir, "..", "tests", "generated", flavor); - try { - await access(flavorDir); - } catch { - return []; - } - - const configFiles: string[] = []; - for (const pkg of await readdir(flavorDir, { withFileTypes: true })) { - if (pkg.isDirectory()) { - const pkgDir = join(flavorDir, pkg.name); - for (const file of await readdir(pkgDir)) { - if (file.startsWith(".tsp-codegen-") && file.endsWith(".json")) { - configFiles.push(join(pkgDir, file)); - } - } - } - } - return configFiles; -} - -function runBatchPythonProcessing(flavor: string, configCount: number, jobs: number): boolean { - if (configCount === 0) return true; - - console.log(pc.cyan(`\nRunning batch Python processing on ${configCount} specs...`)); - - // Find Python venv - let venvPath = join(PLUGIN_DIR, "venv"); - if (existsSync(join(venvPath, "bin"))) { - venvPath = join(venvPath, "bin", "python"); - } else if (existsSync(join(venvPath, "Scripts"))) { - venvPath = join(venvPath, "Scripts", "python.exe"); - } else { - console.error(pc.red("Python venv not found")); - return false; - } - - const batchScript = join(PLUGIN_DIR, "eng", "scripts", "setup", "run_batch.py"); - - try { - // Pass directory and flavor instead of individual config files to avoid command line length limits on Windows - execSync( - `"${venvPath}" "${batchScript}" --generated-dir "${PLUGIN_DIR}" --flavor ${flavor} --jobs ${jobs}`, - { - stdio: "inherit", - cwd: PLUGIN_DIR, - }, - ); - return true; - } catch { - return false; - } -} +const EMITTER_NAME = argv.values.emitterName || "@azure-tools/typespec-python"; + +const ctx: RegenerateContext = { + pluginDir: PLUGIN_DIR, + azureHttpSpecs: AZURE_HTTP_SPECS, + httpSpecs: HTTP_SPECS, + generatedFolder: GENERATED_FOLDER, + emitterName: EMITTER_NAME, +}; async function regenerateFlavor( flavor: string, @@ -751,78 +120,46 @@ async function regenerateFlavor( const flags: RegenerateFlags = { flavor, debug, name }; - // Preprocess await preprocess(flavor, GENERATED_FOLDER); - // Collect specs const azureSpecs = flavor === "azure" ? await getSubdirectories(AZURE_HTTP_SPECS, flags) : []; const standardSpecs = await getSubdirectories(HTTP_SPECS, flags); const allSpecs = [...azureSpecs, ...standardSpecs]; - // Build task groups (tasks for same spec run sequentially to avoid state pollution) - const groups = buildTaskGroups(allSpecs, flags); + const groups = buildTaskGroups(allSpecs, flags, ctx); const totalTasks = groups.reduce((sum, g) => sum + g.tasks.length, 0); console.log(pc.cyan(`Found ${allSpecs.length} specs (${totalTasks} total tasks) to compile`)); console.log(pc.cyan(`Using ${jobs} parallel jobs\n`)); - // Run compilation (emits YAML only) const startTime = performance.now(); - const results = await runParallel(groups, jobs); - const compileTime = (performance.now() - startTime) / 1000; + const results = await runParallel(groups, jobs, ctx); + const duration = (performance.now() - startTime) / 1000; - // Summary for TypeSpec compilation const succeeded = Array.from(results.values()).filter((v) => v).length; - const compileFailed = results.size - succeeded; - - console.log( - pc.cyan( - `\nTypeSpec compilation: ${succeeded} succeeded, ${compileFailed} failed (${compileTime.toFixed(1)}s)`, - ), - ); - - if (compileFailed > 0) { - console.log(pc.red(`Skipping Python processing due to compilation failures`)); - return false; - } - - // Batch process all specs with Python - const pyStartTime = performance.now(); - const configCount = (await collectConfigFiles(GENERATED_FOLDER, flavor)).length; - // Use fewer Python jobs since Python processing is heavier - const pyJobs = Math.max(4, jobs); - const pySuccess = argv.values.singlePhase - ? true - : runBatchPythonProcessing(flavor, configCount, pyJobs); - const pyTime = (performance.now() - pyStartTime) / 1000; - - const totalTime = (performance.now() - startTime) / 1000; + const failed = results.size - succeeded; console.log(pc.cyan(`\n${"=".repeat(60)}`)); - console.log(pc.cyan(`Results: ${succeeded} specs processed`)); - console.log( - pc.cyan( - ` TypeSpec: ${compileTime.toFixed(1)}s | Python: ${pyTime.toFixed(1)}s | Total: ${totalTime.toFixed(1)}s`, - ), - ); + console.log(pc.cyan(`Results: ${succeeded} succeeded, ${failed} failed`)); + console.log(pc.cyan(`Time: ${duration.toFixed(1)}s`)); console.log(pc.cyan(`${"=".repeat(60)}\n`)); - return pySuccess; + return failed === 0; } -async function main() { +async function main(): Promise { const isWindows = platform() === "win32"; const flavor = argv.values.flavor; const name = argv.values.name; const debug = argv.values.debug ?? false; - // Windows has slower file system operations and process spawning, - // so use fewer parallel jobs to avoid I/O contention and memory pressure + // Windows has slower file system operations and process spawning, so use + // fewer parallel jobs to avoid I/O contention and memory pressure. const defaultJobs = isWindows ? 10 : 30; const jobs = argv.values.jobs ? parseInt(argv.values.jobs, 10) : defaultJobs; console.log(pc.cyan(`\nRegeneration config:`)); console.log(pc.cyan(` Platform: ${isWindows ? "Windows" : "Unix"}`)); - console.log(pc.cyan(` Mode: in-process compilation`)); + console.log(pc.cyan(` Mode: in-process compilation (single-phase)`)); console.log(pc.cyan(` Jobs: ${jobs}`)); if (name) { console.log(pc.cyan(` Filter: ${name}`)); @@ -832,10 +169,11 @@ async function main() { const startTime = performance.now(); let success: boolean; + await prepareBaselineOfGeneratedCode(GENERATED_FOLDER); + if (flavor) { success = await regenerateFlavor(flavor, name, debug, jobs); } else { - // Both flavors const azureSuccess = await regenerateFlavor("azure", name, debug, jobs); const unbrandedSuccess = await regenerateFlavor("unbranded", name, debug, jobs); success = azureSuccess && unbrandedSuccess; @@ -852,6 +190,6 @@ async function main() { } main().catch((err) => { - console.error(pc.red(`Fatal error: ${err}`)); + console.error(pc.red(`\nUnexpected error: ${String(err)}`)); process.exit(1); }); diff --git a/packages/typespec-python/eng/scripts/sync.ts b/packages/typespec-python/eng/scripts/sync.ts index 445dbbb33e..1107a2d622 100644 --- a/packages/typespec-python/eng/scripts/sync.ts +++ b/packages/typespec-python/eng/scripts/sync.ts @@ -62,12 +62,10 @@ const INCLUDES: readonly string[] = [ "eng/scripts/ci/run_sphinx_build.py", "eng/scripts/ci/util.py", - // The two-phase upstream regenerate.ts is patched at sync time (see - // POST_PROCESS) to add a `--single-phase` flag that bypasses the YAML + - // batched-Python pipeline. The wrapper's `regenerate` npm script passes - // that flag so we keep the in-process emit path that is faster for the - // azure-only / Windows / smaller-spec-set wrapper case. - "eng/scripts/ci/regenerate.ts", + // Shared regenerate helpers/data tables. Per-repo orchestration (paths, + // emitter name, single-phase vs two-phase pipeline, argv/help) lives in + // each repo's own `regenerate.ts` and is intentionally *not* synced. + "eng/scripts/ci/regenerate-common.ts", // Shared setup scripts (invoked by package.json install/prepare hooks // and by ci/regenerate.ts which spawns run_batch.py). @@ -114,60 +112,12 @@ const INCLUDES: readonly string[] = [ * sync. */ /** - * Post-process hooks applied to specific synced files after copying. The - * transform runs against the source bytes; the resulting buffer is what gets - * compared with (and written to) the local file. Use sparingly — every patch - * is local divergence we have to maintain. - * - * Why we patch eng/scripts/ci/regenerate.ts: - * Upstream's regenerate.ts uses a two-phase pipeline (TypeSpec compile emits - * YAML only; then a single batched Python subprocess reads the YAMLs and - * writes the final .py files). That amortizes Python-startup cost across - * many specs and pays off when both `azure` and `unbranded` flavors are - * regenerated together. typespec-python only ever regenerates the `azure` - * flavor, with a smaller spec set, on Windows — the fixed subprocess + - * YAML round-trip cost ends up slower than just letting the emitter write - * .py files in-process. This patch adds a `--single-phase` flag that - * bypasses both `emit-yaml-only` and `runBatchPythonProcessing`. The - * wrapper's `regenerate` npm script passes `--single-phase`. + * Directory/file names to skip when walking INCLUDES directory entries. Any + * path that has a segment matching one of these names is ignored on both + * sides: not copied from source, and not pruned in dest. This is how we keep + * build artifacts (egg-info, __pycache__, build/, dist/) from polluting the + * sync. */ -const POST_PROCESS: Record Buffer> = { - "eng/scripts/ci/regenerate.ts": (buf) => Buffer.from(patchRegenerateTs(buf.toString("utf8")), "utf8"), -}; - -function patchRegenerateTs(src: string): string { - let out = src; - - const argvBefore = ` jobs: { type: "string", short: "j" },\n help: { type: "boolean", short: "h" },`; - const argvAfter = ` jobs: { type: "string", short: "j" },\n singlePhase: { type: "boolean" },\n help: { type: "boolean", short: "h" },`; - if (!out.includes(argvAfter)) { - if (!out.includes(argvBefore)) { - throw new Error("regenerate.ts patch: argv anchor not found (upstream changed shape)"); - } - out = out.replace(argvBefore, argvAfter); - } - - const yamlBefore = ` // Emit YAML only - Python processing is batched after all specs compile\n options["emit-yaml-only"] = true;`; - const yamlAfter = ` // Emit YAML only - Python processing is batched after all specs compile\n if (!argv.values.singlePhase) {\n options["emit-yaml-only"] = true;\n }`; - if (!out.includes(yamlAfter)) { - if (!out.includes(yamlBefore)) { - throw new Error("regenerate.ts patch: emit-yaml-only anchor not found"); - } - out = out.replace(yamlBefore, yamlAfter); - } - - const batchBefore = ` const pySuccess = runBatchPythonProcessing(flavor, configCount, pyJobs);`; - const batchAfter = ` const pySuccess = argv.values.singlePhase\n ? true\n : runBatchPythonProcessing(flavor, configCount, pyJobs);`; - if (!out.includes(batchAfter)) { - if (!out.includes(batchBefore)) { - throw new Error("regenerate.ts patch: runBatchPythonProcessing anchor not found"); - } - out = out.replace(batchBefore, batchAfter); - } - - return out; -} - const EXCLUDED_SEGMENTS: ReadonlySet = new Set([ "__pycache__", "build", @@ -229,11 +179,7 @@ interface SyncStats { } function syncFile(srcAbs: string, destAbs: string, relPath: string, stats: SyncStats): void { - let srcBuf = fs.readFileSync(srcAbs); - const transform = POST_PROCESS[toPosix(relPath)]; - if (transform) { - srcBuf = transform(srcBuf); - } + const srcBuf = fs.readFileSync(srcAbs); const destBuf = readBytes(destAbs); if (destBuf && destBuf.equals(srcBuf)) { From e740a1ac0a8062019638726d20801b62607cd2ec Mon Sep 17 00:00:00 2001 From: Yuchao Yan Date: Fri, 8 May 2026 13:34:14 +0800 Subject: [PATCH 09/36] update --- .../eng/scripts/setup/install.py | 49 +---- .../eng/scripts/setup/package_manager.py | 21 +- .../eng/scripts/setup/prepare.py | 13 +- .../eng/scripts/setup/run-python3.ts | 9 +- .../eng/scripts/setup/run_batch.py | 199 ------------------ .../eng/scripts/setup/run_tsp.py | 15 +- .../eng/scripts/setup/system-requirements.ts | 22 +- .../eng/scripts/setup/venvtools.py | 7 +- packages/typespec-python/eng/scripts/sync.ts | 14 +- 9 files changed, 54 insertions(+), 295 deletions(-) delete mode 100644 packages/typespec-python/eng/scripts/setup/run_batch.py diff --git a/packages/typespec-python/eng/scripts/setup/install.py b/packages/typespec-python/eng/scripts/setup/install.py index 487acc67b1..cdeba45e97 100644 --- a/packages/typespec-python/eng/scripts/setup/install.py +++ b/packages/typespec-python/eng/scripts/setup/install.py @@ -7,57 +7,22 @@ # -------------------------------------------------------------------------- import sys -if not sys.version_info >= (3, 10, 0): - print( - "Warning: Autorest for Python extension requires Python 3.10 at least. We will run your code with Pyodide since your Python version isn't adequate." - ) - sys.exit(2) # Exit code 2 for inadequate environment +if not sys.version_info >= (3, 9, 0): + raise Exception("Autorest for Python extension requires Python 3.9 at least") try: from package_manager import detect_package_manager, PackageManagerNotFoundError detect_package_manager() # Just check if we have a package manager except (ImportError, ModuleNotFoundError, PackageManagerNotFoundError): - print( - "Warning: Your Python installation doesn't have a suitable package manager (pip or uv) available. We will run your code with Pyodide since your Python environment isn't adequate." + raise Exception( + "Your Python installation doesn't have a suitable package manager (pip or uv) available" ) - sys.exit(2) # Exit code 2 for inadequate environment try: import venv -except (ImportError, ModuleNotFoundError): - print( - "Warning: Your Python installation doesn't have venv available. We will run your code with Pyodide since your Python version isn't adequate." - ) - sys.exit(2) # Exit code 2 for inadequate environment - - -# Now we have a package manager (uv or pip) and Py >= 3.10, go to work -# At this point, both Python and package manager are confirmed to be available -# Any failures from here should fail the npm install, not fallback to Pyodide - -from pathlib import Path - -# eng/scripts/setup/install.py -> need to go up 4 levels to get to package root -_ROOT_DIR = Path(__file__).parent.parent.parent.parent - - -def main(): - venv_path = _ROOT_DIR / "venv" - - # Create virtual environment using package manager abstraction - from package_manager import create_venv_with_package_manager, install_packages - - try: - venv_context = create_venv_with_package_manager(venv_path) - - # Install required packages - install_packages handles package manager logic - install_packages([f"{_ROOT_DIR}/generator"], venv_context, cwd=_ROOT_DIR) - except Exception as e: - # Since Python and package manager are available, any failure here should fail the npm install - print(f"Error: Installation failed despite Python and package manager being available: {e}") - sys.exit(1) # Exit code 1 for installation failure +except ImportError: + raise Exception("Your Python installation doesn't have venv available") -if __name__ == "__main__": - main() +# Now we have a package manager (uv or pip) and Py >= 3.9 and check is over diff --git a/packages/typespec-python/eng/scripts/setup/package_manager.py b/packages/typespec-python/eng/scripts/setup/package_manager.py index 3b6698279d..c6bd178fb5 100644 --- a/packages/typespec-python/eng/scripts/setup/package_manager.py +++ b/packages/typespec-python/eng/scripts/setup/package_manager.py @@ -25,7 +25,7 @@ def _check_command_available(command: str) -> bool: try: subprocess.run([command, "--version"], capture_output=True, check=True) return True - except (subprocess.CalledProcessError, FileNotFoundError, PermissionError): + except (subprocess.CalledProcessError, FileNotFoundError): return False @@ -48,12 +48,16 @@ def detect_package_manager() -> str: # As a last resort, try using python -m pip try: - subprocess.run([sys.executable, "-m", "pip", "--version"], capture_output=True, check=True) + subprocess.run( + [sys.executable, "-m", "pip", "--version"], capture_output=True, check=True + ) return "python -m pip" - except (subprocess.CalledProcessError, FileNotFoundError, PermissionError): + except (subprocess.CalledProcessError, FileNotFoundError): pass - raise PackageManagerNotFoundError("No suitable package manager found. Please install either uv or pip.") + raise PackageManagerNotFoundError( + "No suitable package manager found. Please install either uv or pip." + ) def get_install_command(package_manager: str, venv_context=None) -> list: @@ -85,7 +89,9 @@ def get_install_command(package_manager: str, venv_context=None) -> list: raise ValueError(f"Unknown package manager: {package_manager}") -def install_packages(packages: list, venv_context=None, package_manager: str = None, cwd: Path = None) -> None: +def install_packages( + packages: list, venv_context=None, package_manager: str = None +) -> None: """Install packages using the available package manager. Args: @@ -99,10 +105,7 @@ def install_packages(packages: list, venv_context=None, package_manager: str = N install_cmd = get_install_command(package_manager, venv_context) try: - if cwd: - subprocess.check_call(install_cmd + packages, cwd=cwd) - else: - subprocess.check_call(install_cmd + packages) + subprocess.check_call(install_cmd + packages) except subprocess.CalledProcessError as e: raise RuntimeError(f"Failed to install packages with {package_manager}: {e}") diff --git a/packages/typespec-python/eng/scripts/setup/prepare.py b/packages/typespec-python/eng/scripts/setup/prepare.py index 6e6de3d547..045442ffb6 100644 --- a/packages/typespec-python/eng/scripts/setup/prepare.py +++ b/packages/typespec-python/eng/scripts/setup/prepare.py @@ -7,28 +7,25 @@ # -------------------------------------------------------------------------- import sys -if not sys.version_info >= (3, 10, 0): - raise Warning( - "Autorest for Python extension requires Python 3.10 at least. We will run your code with Pyodide since your Python version isn't adequate." - ) +if not sys.version_info >= (3, 9, 0): + raise Exception("Autorest for Python extension requires Python 3.9 at least") from pathlib import Path from package_manager import create_venv_with_package_manager, install_packages -# eng/scripts/setup/prepare.py -> need to go up 4 levels to get to package root _ROOT_DIR = Path(__file__).parent.parent.parent.parent def main(): venv_path = _ROOT_DIR / "venv" - venv_preexists = venv_path.exists() - assert venv_preexists # Otherwise install was not done + # Create virtual environment using package manager abstraction + from package_manager import create_venv_with_package_manager, install_packages venv_context = create_venv_with_package_manager(venv_path) try: - install_packages(["-r", f"{_ROOT_DIR}/generator/dev_requirements.txt"], venv_context, cwd=_ROOT_DIR) + install_packages(["-r", f"{_ROOT_DIR}/dev_requirements.txt"], venv_context) except FileNotFoundError as e: raise ValueError(e.filename) diff --git a/packages/typespec-python/eng/scripts/setup/run-python3.ts b/packages/typespec-python/eng/scripts/setup/run-python3.ts index 422a28be73..8e3b51d9f4 100644 --- a/packages/typespec-python/eng/scripts/setup/run-python3.ts +++ b/packages/typespec-python/eng/scripts/setup/run-python3.ts @@ -9,12 +9,17 @@ import cp from "child_process"; import { patchPythonPath } from "./system-requirements.js"; -export async function runPython3(...args: string[]) { +async function runPython3(...args: string[]) { const command = await patchPythonPath(["python", ...args], { - version: ">=3.10", + version: ">=3.9", environmentVariable: "AUTOREST_PYTHON_EXE", }); cp.execSync(command.join(" "), { stdio: [0, 1, 2], }); } + +runPython3(...process.argv.slice(2)).catch((err) => { + console.error(err.toString()); // eslint-disable-line no-console + process.exit(1); +}); diff --git a/packages/typespec-python/eng/scripts/setup/run_batch.py b/packages/typespec-python/eng/scripts/setup/run_batch.py deleted file mode 100644 index 6d6bef5b0d..0000000000 --- a/packages/typespec-python/eng/scripts/setup/run_batch.py +++ /dev/null @@ -1,199 +0,0 @@ -# ------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for -# license information. -# -------------------------------------------------------------------------- -""" -Batch process multiple TypeSpec YAML files in a single Python process. -This avoids the overhead of spawning a new Python process for each spec. -""" - -import argparse -import json -import sys -import os -from pathlib import Path -from concurrent.futures import ProcessPoolExecutor, as_completed -from multiprocessing import freeze_support - -# Add the generator to the path -_ROOT_DIR = Path(__file__).parent.parent.parent.parent -sys.path.insert(0, str(_ROOT_DIR / "generator")) - - -def process_single_spec(config_path_str: str) -> tuple[str, bool, str]: - """Process a single spec from its config file. - - Returns: (output_dir, success, error_message) - """ - # Import inside function for multiprocessing compatibility - from pygen import preprocess, codegen - - config_path = Path(config_path_str) - try: - with open(config_path, "r", encoding="utf-8") as f: - config = json.load(f) - - yaml_path = config["yamlPath"] - command_args = config["commandArgs"] - output_dir = config["outputDir"] - - # Pass command args directly to pygen - pygen expects hyphenated keys - # Remove keys that shouldn't be passed to pygen. - # Also coerce the string values "true"/"false" to real booleans, matching the behavior - # of pygen.utils.parse_args (the CLI path). Without this, the emitter passes string - # "false" for flags like keep-setup-py, which is truthy in Python and causes pygen to - # take the wrong branch (e.g. generating setup.py instead of pyproject.toml). - def _coerce(value): - if value == "true": - return True - if value == "false": - return False - return value - - pygen_args = { - k: _coerce(v) for k, v in command_args.items() if k not in ["emit-yaml-only"] - } - - # Run preprocess and codegen (black is batched at the end for performance) - preprocess.PreProcessPlugin(output_folder=output_dir, tsp_file=yaml_path, **pygen_args).process() - - codegen.CodeGenerator(output_folder=output_dir, tsp_file=yaml_path, **pygen_args).process() - - # Clean up the config file - config_path.unlink() - - return (output_dir, True, "") - except Exception as e: - return (str(config_path), False, str(e)) - - -def render_progress_bar(completed: int, failed: int, total: int, width: int = 40) -> str: - """Render a progress bar with green for success and red for failures.""" - success_count = completed - failed - success_width = round((success_count / total) * width) if total > 0 else 0 - fail_width = round((failed / total) * width) if total > 0 else 0 - empty_width = width - success_width - fail_width - - # ANSI color codes - green_bg = "\033[42m" - red_bg = "\033[41m" - reset = "\033[0m" - dim = "\033[2m" - cyan = "\033[36m" - - success_bar = f"{green_bg}{' ' * success_width}{reset}" - fail_bar = f"{red_bg}{' ' * fail_width}{reset}" if failed > 0 else "" - empty_bar = f"{dim}{'░' * max(0, empty_width)}{reset}" - - percent = round((completed / total) * 100) if total > 0 else 0 - return f"{success_bar}{fail_bar}{empty_bar} {cyan}{percent}%{reset} ({completed}/{total})" - - -def collect_config_files(generated_dir: str, flavor: str) -> list[str]: - """Collect all .tsp-codegen-*.json config files from the generated directory.""" - flavor_dir = Path(generated_dir) / "tests" / "generated" / flavor - if not flavor_dir.exists(): - return [] - - config_files = [] - for pkg_dir in flavor_dir.iterdir(): - if pkg_dir.is_dir(): - for f in pkg_dir.iterdir(): - if f.name.startswith(".tsp-codegen-") and f.name.endswith(".json"): - config_files.append(str(f)) - return config_files - - -def main(): - parser = argparse.ArgumentParser(description="Batch process TypeSpec YAML files") - parser.add_argument( - "--generated-dir", - required=True, - help="Path to the generator directory (config files are in ../tests/generated//)", - ) - parser.add_argument( - "--flavor", - required=True, - help="Flavor to process (azure or unbranded)", - ) - parser.add_argument( - "--jobs", - type=int, - default=4, - help="Number of parallel jobs (default: 4)", - ) - args = parser.parse_args() - - # Discover config files from the generated directory - config_files = collect_config_files(args.generated_dir, args.flavor) - total = len(config_files) - - if total == 0: - print("No config files found, nothing to process") - return - - print(f"Processing {total} specs with {args.jobs} parallel jobs...") - - succeeded = 0 - failed = 0 - failed_specs = [] - output_dirs = [] - is_tty = sys.stdout.isatty() - - def update_progress(): - if is_tty: - sys.stdout.write(f"\r{render_progress_bar(succeeded + failed, failed, total)}") - sys.stdout.flush() - - # Initial progress bar - update_progress() - - # Use ProcessPoolExecutor for true parallelism (bypasses GIL) - with ProcessPoolExecutor(max_workers=args.jobs) as executor: - futures = {executor.submit(process_single_spec, cf): cf for cf in config_files} - - for future in as_completed(futures): - output_dir, success, error = future.result() - if success: - succeeded += 1 - output_dirs.append(output_dir) - else: - failed += 1 - failed_specs.append(f"{output_dir}: {error}") - # Fail-fast: cancel pending futures on first failure - print(f"\n\033[31m[FAIL-FAST] Cancelling remaining tasks after failure...\033[0m") - for f in futures: - f.cancel() - break - update_progress() - - # Clear progress bar line - if is_tty: - sys.stdout.write("\r" + " " * 60 + "\r") - sys.stdout.flush() - - # Print failures at the end - if failed_specs: - print("\n\033[31mFailed specs:\033[0m") - for spec in failed_specs: - print(f" \033[31m•\033[0m {spec}") - - print(f"\nBatch processing complete: {succeeded} succeeded, {failed} failed") - - if failed > 0: - sys.exit(1) - - # Run black formatting after all codegen completes. Running black separately - # avoids duplicating black's import/startup cost in each worker process. - if output_dirs: - from pygen.black import BlackScriptPlugin - - print(f"Formatting {len(output_dirs)} packages with black...") - for d in output_dirs: - BlackScriptPlugin(output_folder=d).process() - - -if __name__ == "__main__": - freeze_support() # Required for Windows multiprocessing - main() diff --git a/packages/typespec-python/eng/scripts/setup/run_tsp.py b/packages/typespec-python/eng/scripts/setup/run_tsp.py index 6d5d324704..c7700e6e09 100644 --- a/packages/typespec-python/eng/scripts/setup/run_tsp.py +++ b/packages/typespec-python/eng/scripts/setup/run_tsp.py @@ -9,8 +9,7 @@ from pygen import preprocess, codegen from pygen.utils import parse_args -# eng/scripts/setup/run_tsp.py -> need to go up 4 levels to get to package root -_ROOT_DIR = Path(__file__).parent.parent.parent.parent +_ROOT_DIR = Path(__file__).parent.parent _LOGGER = logging.getLogger(__name__) @@ -27,7 +26,9 @@ try: import debugpy # pylint: disable=import-outside-toplevel except (ImportError, ModuleNotFoundError): - raise SystemExit("Please pip install ptvsd in order to use VSCode debugging") + raise SystemExit( + "Please pip install ptvsd in order to use VSCode debugging" + ) # 5678 is the default attach port in the VS Code debug configurations debugpy.listen(("localhost", 5678)) @@ -36,5 +37,9 @@ # pre-process args, unknown_args = parse_args() - preprocess.PreProcessPlugin(output_folder=args.output_folder, tsp_file=args.tsp_file, **unknown_args).process() - codegen.CodeGenerator(output_folder=args.output_folder, tsp_file=args.tsp_file, **unknown_args).process() + preprocess.PreProcessPlugin( + output_folder=args.output_folder, tsp_file=args.tsp_file, **unknown_args + ).process() + codegen.CodeGenerator( + output_folder=args.output_folder, tsp_file=args.tsp_file, **unknown_args + ).process() diff --git a/packages/typespec-python/eng/scripts/setup/system-requirements.ts b/packages/typespec-python/eng/scripts/setup/system-requirements.ts index f47685db62..236d14fc1b 100644 --- a/packages/typespec-python/eng/scripts/setup/system-requirements.ts +++ b/packages/typespec-python/eng/scripts/setup/system-requirements.ts @@ -1,4 +1,5 @@ import { ChildProcess, spawn, SpawnOptions } from "child_process"; +import { coerce, satisfies } from "semver"; /* * Copied from @autorest/system-requirements @@ -37,7 +38,7 @@ const execute = ( cp.on("error", (err) => { reject(err); }); - cp.on("close", (code, _signal) => + cp.on("close", (code, signal) => resolve({ stdout: out, stderr: err, @@ -49,21 +50,12 @@ const execute = ( }); }; -// Simple version comparison without semver dependency const versionIsSatisfied = (version: string, requirement: string): boolean => { - // For now, support only >= requirements since that's what we use - if (requirement.startsWith(">=")) { - const requiredVersion = requirement.substring(2); - return parseVersionNumber(version) >= parseVersionNumber(requiredVersion); + const cleanedVersion = coerce(version); + if (!cleanedVersion) { + throw new Error(`Invalid version ${version}.`); } - // Fallback to true for other version requirements - return true; -}; - -const parseVersionNumber = (version: string): number => { - // Parse version like "3.9.0" to a comparable number - const parts = version.split(".").map((p) => parseInt(p.replace(/[^0-9]/g, ""), 10) || 0); - return parts[0] * 10000 + (parts[1] || 0) * 100 + (parts[2] || 0); + return satisfies(cleanedVersion, requirement, true); }; /** @@ -122,7 +114,7 @@ const tryPython = async ( `"${PRINT_PYTHON_VERSION_SCRIPT}"`, ]); return validateVersionRequirement(resolution, result.stdout.trim(), requirement); - } catch { + } catch (e) { return { error: true, ...resolution, diff --git a/packages/typespec-python/eng/scripts/setup/venvtools.py b/packages/typespec-python/eng/scripts/setup/venvtools.py index 15a89fbcaa..f15abdd525 100644 --- a/packages/typespec-python/eng/scripts/setup/venvtools.py +++ b/packages/typespec-python/eng/scripts/setup/venvtools.py @@ -8,8 +8,8 @@ import sys from pathlib import Path -# eng/scripts/setup/venvtools.py -> need to go up 4 levels to get to package root -_ROOT_DIR = Path(__file__).parent.parent.parent.parent + +_ROOT_DIR = Path(__file__).parent.parent class ExtendedEnvBuilder(venv.EnvBuilder): @@ -19,9 +19,6 @@ class ExtendedEnvBuilder(venv.EnvBuilder): def __init__(self, *args, **kwargs): self.context = None - if sys.version_info < (3, 9, 0): - # Not supported on Python 3.8, and we don't need it - kwargs.pop("upgrade_deps", None) super().__init__(*args, **kwargs) def ensure_directories(self, env_dir): diff --git a/packages/typespec-python/eng/scripts/sync.ts b/packages/typespec-python/eng/scripts/sync.ts index 1107a2d622..67eb831359 100644 --- a/packages/typespec-python/eng/scripts/sync.ts +++ b/packages/typespec-python/eng/scripts/sync.ts @@ -67,16 +67,10 @@ const INCLUDES: readonly string[] = [ // each repo's own `regenerate.ts` and is intentionally *not* synced. "eng/scripts/ci/regenerate-common.ts", - // Shared setup scripts (invoked by package.json install/prepare hooks - // and by ci/regenerate.ts which spawns run_batch.py). - "eng/scripts/setup/install.py", - "eng/scripts/setup/package_manager.py", - "eng/scripts/setup/prepare.py", - "eng/scripts/setup/run_batch.py", - "eng/scripts/setup/run_tsp.py", - "eng/scripts/setup/run-python3.ts", - "eng/scripts/setup/system-requirements.ts", - "eng/scripts/setup/venvtools.py", + // NOTE: eng/scripts/setup/* is intentionally NOT synced. Those scripts + // (install.py, prepare.py, venvtools.py, etc.) diverged from upstream's + // http-client-python build/test pipeline; the typespec-python wrapper + // owns its own copies. // Shared test assets. Directory entries (trailing `/`) are recursive and // **mirror** the upstream layout: files matching upstream are overwritten, From 7b1e6bdca2bd7a69114ad9803ccf9f5a9162472b Mon Sep 17 00:00:00 2001 From: Yuchao Yan Date: Fri, 8 May 2026 13:37:08 +0800 Subject: [PATCH 10/36] update --- packages/typespec-python/package.json | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/typespec-python/package.json b/packages/typespec-python/package.json index 2762370bf0..0df286cb89 100644 --- a/packages/typespec-python/package.json +++ b/packages/typespec-python/package.json @@ -40,7 +40,6 @@ "regenerate": "tsx ./eng/scripts/ci/regenerate.ts", "sync": "tsx ./eng/scripts/sync.ts", "sync:check": "tsx ./eng/scripts/sync.ts --check", - "prepack": "tsx ./eng/scripts/sync.ts", "test:python:e2e": "tsx ./eng/scripts/ci/run-tests.ts", "regen-docs": "pnpm run build && tspd doc . --enable-experimental --output-dir ./website/src/content/docs/docs/emitters/clients/typespec-python/reference --skip-js" }, From 5da25667b7aa0409f61bde370d6aa17f3182d2e8 Mon Sep 17 00:00:00 2001 From: Yuchao Yan Date: Fri, 8 May 2026 08:23:06 +0000 Subject: [PATCH 11/36] format --- .../eng/scripts/ci/regenerate-common.ts | 15 ++++++++------- packages/typespec-python/eng/scripts/sync.ts | 8 +++----- 2 files changed, 11 insertions(+), 12 deletions(-) diff --git a/packages/typespec-python/eng/scripts/ci/regenerate-common.ts b/packages/typespec-python/eng/scripts/ci/regenerate-common.ts index 58d1a3d8c2..f21c401361 100644 --- a/packages/typespec-python/eng/scripts/ci/regenerate-common.ts +++ b/packages/typespec-python/eng/scripts/ci/regenerate-common.ts @@ -70,7 +70,11 @@ export interface BuildTaskGroupsOptions { // ---- Public constants ---- -export const SKIP_SPECS: string[] = ["type/file", "service/multiple-services"]; +export const SKIP_SPECS: string[] = [ + "type/file", + "service/multiple-services", + "azure/client-generator-core/response-as-bool", +]; export const SpecialFlags: Record> = { azure: { @@ -211,10 +215,7 @@ export const AZURE_EMITTER_OPTIONS: Record< }, }; -export const EMITTER_OPTIONS: Record< - string, - Record | Record[] -> = { +export const EMITTER_OPTIONS: Record | Record[]> = { "resiliency/srv-driven/old.tsp": { "package-name": "resiliency-srv-driven1", namespace: "resiliency.srv.driven1", @@ -398,8 +399,8 @@ export function getEmitterOptions( const key = relativeSpec.includes("resiliency/srv-driven/old.tsp") ? relativeSpec : dirname(relativeSpec); - const emitterOpts = - EMITTER_OPTIONS[key] || (flavor === "azure" ? AZURE_EMITTER_OPTIONS[key] : [{}]) || [{}]; + const emitterOpts = EMITTER_OPTIONS[key] || + (flavor === "azure" ? AZURE_EMITTER_OPTIONS[key] : [{}]) || [{}]; return Array.isArray(emitterOpts) ? emitterOpts : [emitterOpts]; } diff --git a/packages/typespec-python/eng/scripts/sync.ts b/packages/typespec-python/eng/scripts/sync.ts index 67eb831359..6201a9a570 100644 --- a/packages/typespec-python/eng/scripts/sync.ts +++ b/packages/typespec-python/eng/scripts/sync.ts @@ -238,9 +238,9 @@ function main(): void { process.exit(0); } - console.log(pc.bold("Source:") + " " + sourceRoot); + console.log(pc.bold("Source:") + " " + sourceRoot); console.log(pc.bold("Destination:") + " " + packageRoot); - console.log(pc.bold("Mode:") + " " + (check ? "check (read-only)" : "write")); + console.log(pc.bold("Mode:") + " " + (check ? "check (read-only)" : "write")); console.log(""); const stats: SyncStats = { copied: [], unchanged: [], drifted: [], missing: [], removed: [] }; @@ -262,9 +262,7 @@ function main(): void { // touch tracked files. const destDirAbs = join(packageRoot, ...rel.split("/")); const sourceFiles = listFilesRecursive(srcAbs); - const sourceRelSet = new Set( - sourceFiles.map((f) => toPosix(relative(srcAbs, f))), - ); + const sourceRelSet = new Set(sourceFiles.map((f) => toPosix(relative(srcAbs, f)))); // Step 1: copy source -> dest for (const srcFile of sourceFiles) { From 374d32654fb8ac893620bb7eb6cedcf309949b10 Mon Sep 17 00:00:00 2001 From: Yuchao Yan Date: Fri, 8 May 2026 08:34:49 +0000 Subject: [PATCH 12/36] update sync --- packages/typespec-python/eng/scripts/sync.ts | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/packages/typespec-python/eng/scripts/sync.ts b/packages/typespec-python/eng/scripts/sync.ts index 6201a9a570..ffd77dc1cb 100644 --- a/packages/typespec-python/eng/scripts/sync.ts +++ b/packages/typespec-python/eng/scripts/sync.ts @@ -98,13 +98,6 @@ const INCLUDES: readonly string[] = [ "generator/", ]; -/** - * Directory/file names to skip when walking INCLUDES directory entries. Any - * path that has a segment matching one of these names is ignored on both - * sides: not copied from source, and not pruned in dest. This is how we keep - * build artifacts (egg-info, __pycache__, build/, dist/) from polluting the - * sync. - */ /** * Directory/file names to skip when walking INCLUDES directory entries. Any * path that has a segment matching one of these names is ignored on both @@ -212,7 +205,10 @@ function listFilesRecursive(dir: string): string[] { function removeEmptyDirsUpTo(startDir: string, stopDir: string): void { let cur = startDir; - while (cur.startsWith(stopDir) && cur !== stopDir) { + while (cur !== stopDir) { + const rel = relative(stopDir, cur); + // Bail if we've walked outside stopDir (rel starts with "..") or reached it (rel === ""). + if (rel === "" || rel.startsWith("..")) return; try { if (fs.readdirSync(cur).length === 0) { fs.rmdirSync(cur); From a5861e78117439120ca8dcc75dbed2f08509b9fb Mon Sep 17 00:00:00 2001 From: Yuchao Yan Date: Fri, 8 May 2026 08:38:42 +0000 Subject: [PATCH 13/36] update codeowner for typespec-python --- .github/CODEOWNERS | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 05bf6e066a..fec17276c3 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -1,6 +1,8 @@ -* @bterlson @markcowl @allenjzhang @timotheeguerin +* @bterlson @markcowl @timotheeguerin /packages/typespec-client-generator-core @lmazuel @m-nash @iscai-msft @srnagar @joheredi /packages/azure-http-specs/specs/ @iscai-msft @lmazuel @m-nash @joheredi @srnagar @weidongxu-microsoft @tadelesh @jhendrixMSFT /docs/howtos/DataPlane*/ @lmazuel @m-nash @iscai-msft @srnagar @joheredi + +/packages/typespec-python @iscai-msft @msyyc @tadelesh From a6fba3ebbc442c206f978b0d3c96fc8575740896 Mon Sep 17 00:00:00 2001 From: Yuchao Yan Date: Fri, 8 May 2026 16:56:21 +0800 Subject: [PATCH 14/36] update sync script --- packages/typespec-python/dev_requirements.txt | 16 ++--- packages/typespec-python/eng/scripts/sync.ts | 68 +++++++++++++++++++ 2 files changed, 76 insertions(+), 8 deletions(-) diff --git a/packages/typespec-python/dev_requirements.txt b/packages/typespec-python/dev_requirements.txt index 3327859bfd..57e26e4363 100644 --- a/packages/typespec-python/dev_requirements.txt +++ b/packages/typespec-python/dev_requirements.txt @@ -1,16 +1,16 @@ # shall keep aligned with dev_requirements.txt of @typspec/http-client-python -pyright==1.1.391 -pylint==3.2.7 -tox==4.23.2 +pyright==1.1.407 +pylint==4.0.4 +tox==4.16.0 tox-uv -mypy==1.13.0 +mypy==1.19.1 colorama==0.4.6 -debugpy==1.8.12 -pytest==8.3.4 +debugpy==1.8.2 +pytest==8.3.2 coverage==7.6.1 -black==24.8.0 +black==26.3.1 ptvsd==4.3.2 -types-PyYAML==6.0.12.20241230 +types-PyYAML==6.0.12.8 # additional dependency needed for development setuptools diff --git a/packages/typespec-python/eng/scripts/sync.ts b/packages/typespec-python/eng/scripts/sync.ts index ffd77dc1cb..db0357afb1 100644 --- a/packages/typespec-python/eng/scripts/sync.ts +++ b/packages/typespec-python/eng/scripts/sync.ts @@ -165,6 +165,65 @@ interface SyncStats { removed: string[]; // local-only files inside a synced directory (mirror) } +/** + * Merge upstream dependencies into this package's top-level + * dev_requirements.txt + * + * This is NOT a full copy. The wrapper file is split on the marker line + * `# additional dependency needed for development` + * Everything BEFORE the marker is replaced verbatim with the contents of + * /eng/scripts/ci/dev_requirements.txt + * Everything from the marker onwards (wrapper-specific deps such as + * `setuptools`) is preserved untouched. If the wrapper file lacks the + * marker, the upstream content simply replaces the whole file. + */ +function syncDevRequirements(srcAbs: string, destAbs: string, stats: SyncStats): void { + const relPath = "dev_requirements.txt"; + + if (!fs.existsSync(srcAbs)) { + stats.missing.push("eng/scripts/ci/dev_requirements.txt"); + return; + } + if (!fs.existsSync(destAbs)) { + stats.missing.push(relPath); + return; + } + + const srcText = fs.readFileSync(srcAbs, "utf8"); + const destText = fs.readFileSync(destAbs, "utf8"); + + // Preserve any leading comment block ("title") of the wrapper file -- the + // run of `#`-prefixed lines at the very top, before the first non-comment + // line. + const destLines = destText.split(/\r?\n/); + const titleLines: string[] = []; + for (const line of destLines) { + if (line.trim().startsWith("#")) titleLines.push(line); + else break; + } + const title = titleLines.length ? titleLines.join("\n") + "\n" : ""; + + const MARKER_RE = /^#\s*additional dependency/im; + const match = MARKER_RE.exec(destText); + // If marker is missing, the upstream content (with title) becomes the whole + // file. Otherwise, keep the marker line and everything after it as-is, with + // a single blank line between the upstream block and the wrapper-only tail. + const tail = match ? destText.slice(match.index) : ""; + const upstream = srcText.endsWith("\n") ? srcText : srcText + "\n"; + const newText = tail ? title + upstream + "\n" + tail : title + upstream; + + if (newText === destText) { + stats.unchanged.push(relPath); + return; + } + if (check) { + stats.drifted.push(relPath); + return; + } + fs.writeFileSync(destAbs, newText, "utf8"); + stats.copied.push(relPath); +} + function syncFile(srcAbs: string, destAbs: string, relPath: string, stats: SyncStats): void { const srcBuf = fs.readFileSync(srcAbs); const destBuf = readBytes(destAbs); @@ -288,6 +347,15 @@ function main(): void { } } + // Special-case merge (NOT a full copy): pull dependency lines from upstream's + // eng/scripts/ci/dev_requirements.txt into this package's top-level + // dev_requirements.txt while preserving wrapper-only deps and comments. + syncDevRequirements( + join(sourceRoot, "eng", "scripts", "ci", "dev_requirements.txt"), + join(packageRoot, "dev_requirements.txt"), + stats, + ); + if (stats.copied.length) { console.log(pc.green(pc.bold(`Copied (${stats.copied.length}):`))); for (const f of stats.copied) console.log(" " + f); From 20afd6c8a25ea8fd4f174a746889f96f46b33d7e Mon Sep 17 00:00:00 2001 From: Yuchao Yan Date: Fri, 8 May 2026 16:59:19 +0800 Subject: [PATCH 15/36] Update .gitignore --- packages/typespec-python/.gitignore | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/typespec-python/.gitignore b/packages/typespec-python/.gitignore index bc2a2860ca..6b33ec15ac 100644 --- a/packages/typespec-python/.gitignore +++ b/packages/typespec-python/.gitignore @@ -1,7 +1,7 @@ # Test asset directories that are populated at runtime by `pnpm sync` from the # upstream http-client-python checkout (see eng/scripts/sync.ts INCLUDES). # These are intentionally not committed; CI runs `pnpm sync` before running -# the Python test suites, and `prepack` runs sync before npm publish. +# the Python test suites. tests/data/ tests/mock_api/ tests/requirements/ From ee7f737988006a7f6675d87f42f1d73cd42b776b Mon Sep 17 00:00:00 2001 From: Yuchao Yan Date: Fri, 8 May 2026 17:04:05 +0800 Subject: [PATCH 16/36] Update run-python3.ts --- packages/typespec-python/eng/scripts/setup/run-python3.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/typespec-python/eng/scripts/setup/run-python3.ts b/packages/typespec-python/eng/scripts/setup/run-python3.ts index 8e3b51d9f4..9c5d9499ed 100644 --- a/packages/typespec-python/eng/scripts/setup/run-python3.ts +++ b/packages/typespec-python/eng/scripts/setup/run-python3.ts @@ -14,7 +14,8 @@ async function runPython3(...args: string[]) { version: ">=3.9", environmentVariable: "AUTOREST_PYTHON_EXE", }); - cp.execSync(command.join(" "), { + const [cmd, ...cmdArgs] = command; + cp.execFileSync(cmd, cmdArgs, { stdio: [0, 1, 2], }); } From 7167e87243a48d6ee8a8c9fed1761f35d90efb7a Mon Sep 17 00:00:00 2001 From: Yuchao Yan Date: Fri, 8 May 2026 17:08:15 +0800 Subject: [PATCH 17/36] add changelog --- .chronus/changes/python-update-eng-2026-4-8-17-7-57.md | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 .chronus/changes/python-update-eng-2026-4-8-17-7-57.md diff --git a/.chronus/changes/python-update-eng-2026-4-8-17-7-57.md b/.chronus/changes/python-update-eng-2026-4-8-17-7-57.md new file mode 100644 index 0000000000..3efbe497cf --- /dev/null +++ b/.chronus/changes/python-update-eng-2026-4-8-17-7-57.md @@ -0,0 +1,7 @@ +--- +changeKind: internal +packages: + - "@azure-tools/typespec-python" +--- + +Simplify eng system for typespec-python \ No newline at end of file From 890479a6f1aa3f8157c7426f7e053e9afbab7897 Mon Sep 17 00:00:00 2001 From: Yuchao Yan Date: Fri, 8 May 2026 17:17:51 +0800 Subject: [PATCH 18/36] format --- packages/typespec-python/eng/scripts/setup/venvtools.py | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/typespec-python/eng/scripts/setup/venvtools.py b/packages/typespec-python/eng/scripts/setup/venvtools.py index f15abdd525..c733957dc9 100644 --- a/packages/typespec-python/eng/scripts/setup/venvtools.py +++ b/packages/typespec-python/eng/scripts/setup/venvtools.py @@ -8,7 +8,6 @@ import sys from pathlib import Path - _ROOT_DIR = Path(__file__).parent.parent From 4ad8b90a7fbf1920c7afd250a7f1d473eb64641b Mon Sep 17 00:00:00 2001 From: Yuchao Yan Date: Fri, 8 May 2026 17:30:25 +0800 Subject: [PATCH 19/36] update --- packages/typespec-python/eng/scripts/sync.ts | 3 +-- packages/typespec-python/package.json | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/packages/typespec-python/eng/scripts/sync.ts b/packages/typespec-python/eng/scripts/sync.ts index db0357afb1..fcee05cfb0 100644 --- a/packages/typespec-python/eng/scripts/sync.ts +++ b/packages/typespec-python/eng/scripts/sync.ts @@ -93,8 +93,7 @@ const INCLUDES: readonly string[] = [ // The pygen Python package. Mirrored from upstream because the tox envs // (`-e {tox_root}/../generator`) and PYTHONPATH expect this directory to - // exist. Gitignored locally; `pnpm sync` populates it before tests/builds - // and `prepack` runs sync so npm publish still includes it. + // exist. Gitignored locally; `pnpm sync` populates it before tests/builds. "generator/", ]; diff --git a/packages/typespec-python/package.json b/packages/typespec-python/package.json index 0df286cb89..a8a9eb82bd 100644 --- a/packages/typespec-python/package.json +++ b/packages/typespec-python/package.json @@ -37,7 +37,7 @@ "lint:extra": "tsx ./eng/scripts/ci/lint.ts", "format:extra": "tsx ./eng/scripts/ci/format.ts --python", "format:extra:check": "tsx ./eng/scripts/ci/format.ts --python --check", - "regenerate": "tsx ./eng/scripts/ci/regenerate.ts", + "regenerate": "pnpm run sync && tsx ./eng/scripts/ci/regenerate.ts", "sync": "tsx ./eng/scripts/sync.ts", "sync:check": "tsx ./eng/scripts/sync.ts --check", "test:python:e2e": "tsx ./eng/scripts/ci/run-tests.ts", From 86253dfebf1972a0f4891b99854905ce292c6422 Mon Sep 17 00:00:00 2001 From: Yuchao Yan Date: Sat, 9 May 2026 10:58:31 +0800 Subject: [PATCH 20/36] update setup-python --- .github/actions/setup-python/action.yml | 2 -- 1 file changed, 2 deletions(-) diff --git a/.github/actions/setup-python/action.yml b/.github/actions/setup-python/action.yml index f20e08594f..514100641b 100644 --- a/.github/actions/setup-python/action.yml +++ b/.github/actions/setup-python/action.yml @@ -7,5 +7,3 @@ runs: steps: - name: Setup mise uses: jdx/mise-action@1648a7812b9aeae629881980618f079932869151 # v4.0.1 - with: - install_args: "python uv" From 003f6d48c262952173f6b0fade5074ec7bcfef67 Mon Sep 17 00:00:00 2001 From: Yuchao Yan Date: Sat, 9 May 2026 11:11:25 +0800 Subject: [PATCH 21/36] pin uv version --- mise.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mise.toml b/mise.toml index d56c43d222..b9df20cfaf 100644 --- a/mise.toml +++ b/mise.toml @@ -1,3 +1,3 @@ [tools] python = "3.12" -uv = "latest" +uv = "0.11.12" From 6b0f35ae3b0a4fae8b47bac1797e8a728e1fdcb2 Mon Sep 17 00:00:00 2001 From: Yuchao Yan Date: Sat, 9 May 2026 11:30:49 +0800 Subject: [PATCH 22/36] Revert "pin uv version" This reverts commit 003f6d48c262952173f6b0fade5074ec7bcfef67. --- mise.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mise.toml b/mise.toml index b9df20cfaf..d56c43d222 100644 --- a/mise.toml +++ b/mise.toml @@ -1,3 +1,3 @@ [tools] python = "3.12" -uv = "0.11.12" +uv = "latest" From aff58bf101117dfc62d28324b0492133403a6c30 Mon Sep 17 00:00:00 2001 From: Yuchao Yan Date: Sat, 9 May 2026 11:30:55 +0800 Subject: [PATCH 23/36] Revert "update setup-python" This reverts commit 86253dfebf1972a0f4891b99854905ce292c6422. --- .github/actions/setup-python/action.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/actions/setup-python/action.yml b/.github/actions/setup-python/action.yml index 514100641b..f20e08594f 100644 --- a/.github/actions/setup-python/action.yml +++ b/.github/actions/setup-python/action.yml @@ -7,3 +7,5 @@ runs: steps: - name: Setup mise uses: jdx/mise-action@1648a7812b9aeae629881980618f079932869151 # v4.0.1 + with: + install_args: "python uv" From bde5c8d1630969310c1eace3b65f961f6aa7c9fc Mon Sep 17 00:00:00 2001 From: Yuchao Yan Date: Sat, 9 May 2026 11:31:45 +0800 Subject: [PATCH 24/36] Restore Azure's working install_packages.py and exclude from sync Upstream http-client-python's tests/install_packages.py invokes 'uv pip wheel', which is not a real uv subcommand in any released uv version (verified against uv 0.5.0 and 0.11.x source: the PipCommand enum has no Wheel variant). Syncing it into the wrapper broke the 'Pre-build wheels' CI step. Restore the working version from origin/main (which uses 'uv build --wheel ...' per package with proper CalledProcessError handling) and remove the file from sync.ts INCLUDES so it stops being overwritten. A comment in sync.ts explains why and notes to re-include once the upstream script is fixed. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- packages/typespec-python/.gitignore | 1 - packages/typespec-python/eng/scripts/sync.ts | 9 +- .../typespec-python/tests/install_packages.py | 145 ++++++++++++++++++ 3 files changed, 151 insertions(+), 4 deletions(-) create mode 100644 packages/typespec-python/tests/install_packages.py diff --git a/packages/typespec-python/.gitignore b/packages/typespec-python/.gitignore index 6b33ec15ac..4b8e9ff276 100644 --- a/packages/typespec-python/.gitignore +++ b/packages/typespec-python/.gitignore @@ -6,6 +6,5 @@ tests/data/ tests/mock_api/ tests/requirements/ tests/conftest.py -tests/install_packages.py tests/tox.ini generator/ diff --git a/packages/typespec-python/eng/scripts/sync.ts b/packages/typespec-python/eng/scripts/sync.ts index fcee05cfb0..a3b285d761 100644 --- a/packages/typespec-python/eng/scripts/sync.ts +++ b/packages/typespec-python/eng/scripts/sync.ts @@ -85,10 +85,13 @@ const INCLUDES: readonly string[] = [ // Test driver/helper files at the tests/ root. Each is treated as the // upstream source of truth — DATA_FOLDER, server-launch logic, lint/test - // tox envs, wheel install algorithms etc. all stay aligned with - // http-client-python. + // tox envs etc. stay aligned with http-client-python. + // + // tests/install_packages.py is intentionally NOT synced: upstream's version + // calls `uv pip wheel`, which is not a real uv subcommand, so it fails in + // CI. Azure's version uses the working `uv build --wheel` flow. Re-include + // once the upstream script is fixed. "tests/conftest.py", - "tests/install_packages.py", "tests/tox.ini", // The pygen Python package. Mirrored from upstream because the tox envs diff --git a/packages/typespec-python/tests/install_packages.py b/packages/typespec-python/tests/install_packages.py new file mode 100644 index 0000000000..eea588ffb5 --- /dev/null +++ b/packages/typespec-python/tests/install_packages.py @@ -0,0 +1,145 @@ +#!/usr/bin/env python +"""Install generated packages for testing. + +Supports two modes: +1. Build wheels from source dirs into a wheel directory (build command) +2. Install from pre-built wheels via --find-links (instant, no compilation) + +The build step runs once before tox envs start. Each tox env then installs +from pre-built wheels, avoiding redundant source builds across environments. +""" + +import glob +import os +import subprocess +import sys + + +def _find_packages(generated_dir): + """Find all package directories that have pyproject.toml or setup.py.""" + all_dirs = glob.glob(os.path.join(generated_dir, "*")) + return sorted([ + p for p in all_dirs + if os.path.isdir(p) and ( + os.path.exists(os.path.join(p, "pyproject.toml")) or + os.path.exists(os.path.join(p, "setup.py")) + ) + ]) + + +def build_wheels(flavor, tests_dir): + """Build wheels for all packages into a shared directory.""" + generated_dir = os.path.join(tests_dir, "generated", flavor) + wheel_dir = os.path.join(tests_dir, ".wheels", flavor) + os.makedirs(wheel_dir, exist_ok=True) + + packages = _find_packages(generated_dir) + if not packages: + print(f"Warning: No packages found in {generated_dir}") + return + + print(f"Building {len(packages)} wheels for {flavor}...") + + failed = [] + for pkg in packages: + try: + subprocess.run( + ["uv", "build", "--wheel", "--no-build-logs", "--out-dir", wheel_dir, pkg], + check=True, + capture_output=True, + ) + except subprocess.CalledProcessError: + pkg_name = os.path.basename(pkg) + print(f"Warning: Failed to build wheel for {pkg_name}, will install from source") + failed.append(pkg) + + wheel_count = len(glob.glob(os.path.join(wheel_dir, "*.whl"))) + print(f"Built {wheel_count}/{len(packages)} wheels for {flavor}") + if failed: + print(f" Skipped {len(failed)}: {', '.join(os.path.basename(p) for p in failed)}") + + +def install_packages(flavor, tests_dir): + """Install generated packages for the given flavor.""" + generated_dir = os.path.join(tests_dir, "generated", flavor) + wheel_dir = os.path.join(tests_dir, ".wheels", flavor) + + if not os.path.exists(generated_dir): + print(f"Warning: Generated directory does not exist: {generated_dir}") + return + + packages = _find_packages(generated_dir) + if not packages: + print(f"Warning: No packages found in {generated_dir}") + return + + print(f"Installing {len(packages)} packages from {generated_dir}") + + use_wheels = os.path.isdir(wheel_dir) and bool(glob.glob(os.path.join(wheel_dir, "*.whl"))) + use_uv = True + + if use_wheels: + wheel_files = glob.glob(os.path.join(wheel_dir, "*.whl")) + print(f" Using {len(wheel_files)} pre-built wheels from .wheels/{flavor}/") + try: + cmd = ["uv", "pip", "install", "--no-deps", "--no-index", + "--find-links", wheel_dir, "--python", sys.executable] + wheel_files + subprocess.run(cmd, check=True) + print(f"Successfully installed {len(wheel_files)} packages") + return + except FileNotFoundError: + use_uv = False + try: + cmd = [sys.executable, "-m", "pip", "install", "--no-deps", + "--no-index", "--find-links", wheel_dir] + wheel_files + subprocess.run(cmd, check=True) + print(f"Successfully installed {len(wheel_files)} packages") + return + except subprocess.CalledProcessError: + print(" Wheel install failed, falling back to source install") + except subprocess.CalledProcessError: + print(" Wheel install failed, falling back to source install") + + # Fall back to source install + if use_uv: + cmd = ["uv", "pip", "install", "--no-deps", "--python", sys.executable] + packages + else: + cmd = [sys.executable, "-m", "pip", "install", "--no-deps"] + packages + + try: + subprocess.run(cmd, check=True) + print(f"Successfully installed {len(packages)} packages") + except subprocess.CalledProcessError as e: + print(f"Error installing packages: {e}") + sys.exit(1) + except FileNotFoundError: + if use_uv: + print("uv not found, falling back to pip") + cmd = [sys.executable, "-m", "pip", "install", "--no-deps"] + packages + subprocess.run(cmd, check=True) + + +def main(): + if len(sys.argv) < 2: + print("Usage: install_packages.py [tests_dir]") + print(" install_packages.py build [tests_dir]") + sys.exit(1) + + if sys.argv[1] == "build": + if len(sys.argv) < 3: + print("Usage: install_packages.py build [tests_dir]") + sys.exit(1) + flavor = sys.argv[2] + tests_dir = sys.argv[3] if len(sys.argv) > 3 else os.path.dirname(os.path.abspath(__file__)) + build_wheels(flavor, tests_dir) + elif sys.argv[1] in ("azure", "unbranded"): + flavor = sys.argv[1] + tests_dir = sys.argv[2] if len(sys.argv) > 2 else os.path.dirname(os.path.abspath(__file__)) + install_packages(flavor, tests_dir) + else: + print(f"Error: Unknown command or flavor '{sys.argv[1]}'") + sys.exit(1) + + +if __name__ == "__main__": + main() From fa2d16ff6891d82f2e9899a1f8a713da5e40f869 Mon Sep 17 00:00:00 2001 From: Yuchao Yan Date: Sat, 9 May 2026 11:52:21 +0800 Subject: [PATCH 25/36] update --- packages/typespec-python/package.json | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/typespec-python/package.json b/packages/typespec-python/package.json index a8a9eb82bd..6e2b174d39 100644 --- a/packages/typespec-python/package.json +++ b/packages/typespec-python/package.json @@ -47,7 +47,6 @@ "dist/**", "!dist/tests/**", "eng/scripts/setup/**", - "generator/**" ], "peerDependencies": { "@azure-tools/typespec-autorest": "workspace:^", From ea5755e943b9e1cab69e9250d28daf7a9a3e2c38 Mon Sep 17 00:00:00 2001 From: Yuchao Yan Date: Sat, 9 May 2026 11:55:30 +0800 Subject: [PATCH 26/36] fix package.json --- packages/typespec-python/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/typespec-python/package.json b/packages/typespec-python/package.json index 6e2b174d39..92fa363bb6 100644 --- a/packages/typespec-python/package.json +++ b/packages/typespec-python/package.json @@ -46,7 +46,7 @@ "files": [ "dist/**", "!dist/tests/**", - "eng/scripts/setup/**", + "eng/scripts/setup/**" ], "peerDependencies": { "@azure-tools/typespec-autorest": "workspace:^", From 54a1ff6ac467fe75d7149851f3af4bf957a6d3f3 Mon Sep 17 00:00:00 2001 From: Yuchao Yan Date: Sat, 9 May 2026 05:00:42 +0000 Subject: [PATCH 27/36] fix ci --- packages/typespec-python/.gitignore | 3 - packages/typespec-python/tests/conftest.py | 160 ++++++++++++++ .../tests/requirements/azure.txt | 5 + .../tests/requirements/base.txt | 12 ++ .../tests/requirements/docs.txt | 9 + .../tests/requirements/lint.txt | 4 + .../tests/requirements/typecheck.txt | 5 + .../tests/requirements/unbranded.txt | 5 + packages/typespec-python/tests/tox.ini | 201 ++++++++++++++++++ 9 files changed, 401 insertions(+), 3 deletions(-) create mode 100644 packages/typespec-python/tests/conftest.py create mode 100644 packages/typespec-python/tests/requirements/azure.txt create mode 100644 packages/typespec-python/tests/requirements/base.txt create mode 100644 packages/typespec-python/tests/requirements/docs.txt create mode 100644 packages/typespec-python/tests/requirements/lint.txt create mode 100644 packages/typespec-python/tests/requirements/typecheck.txt create mode 100644 packages/typespec-python/tests/requirements/unbranded.txt create mode 100644 packages/typespec-python/tests/tox.ini diff --git a/packages/typespec-python/.gitignore b/packages/typespec-python/.gitignore index 4b8e9ff276..75145c8ee0 100644 --- a/packages/typespec-python/.gitignore +++ b/packages/typespec-python/.gitignore @@ -4,7 +4,4 @@ # the Python test suites. tests/data/ tests/mock_api/ -tests/requirements/ -tests/conftest.py -tests/tox.ini generator/ diff --git a/packages/typespec-python/tests/conftest.py b/packages/typespec-python/tests/conftest.py new file mode 100644 index 0000000000..a0badda9ef --- /dev/null +++ b/packages/typespec-python/tests/conftest.py @@ -0,0 +1,160 @@ +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- +import os +import subprocess +import signal +import time +import urllib.request +import urllib.error +import tempfile +import pytest +import importlib +from pathlib import Path +from filelock import FileLock + +# Root of the http-client-python package +ROOT = Path(__file__).parent.parent +DATA_FOLDER = Path(__file__).parent / "mock_api" / "shared" + +# Server configuration +SERVER_HOST = "localhost" +SERVER_PORT = 3000 +SERVER_URL = f"http://{SERVER_HOST}:{SERVER_PORT}" + +# Lock file for coordinating server startup across xdist workers +LOCK_FILE = Path(tempfile.gettempdir()) / "http_client_python_test_server.lock" +PID_FILE = Path(tempfile.gettempdir()) / "http_client_python_test_server.pid" + + +def wait_for_server(url: str, timeout: int = 60, interval: float = 0.5) -> bool: + """Wait for the server to be ready by polling the URL.""" + start_time = time.time() + while time.time() - start_time < timeout: + try: + urllib.request.urlopen(url, timeout=1) + return True + except urllib.error.HTTPError: + # Server is up but returned an error (e.g., 404) - that's fine + return True + except (urllib.error.URLError, OSError): + # Server not reachable yet + time.sleep(interval) + return False + + +def start_server_process(): + """Start the tsp-spector mock API server. + + Always serves both azure-http-specs and http-specs regardless of flavor. + This allows azure and unbranded tests to run in parallel using the same server. + """ + azure_http_path = ROOT / "node_modules/@azure-tools/azure-http-specs" + http_path = ROOT / "node_modules/@typespec/http-specs" + + # Always serve both spec sets so azure and unbranded tests can run in parallel + # Use absolute paths with forward slashes (works on all platforms including Windows) + cwd = azure_http_path.resolve() + azure_specs = str(cwd / "specs").replace("\\", "/") + http_specs = str((http_path / "specs").resolve()).replace("\\", "/") + cmd = f"npx tsp-spector serve {azure_specs} {http_specs}" + + # Add node_modules/.bin to PATH + env = os.environ.copy() + node_bin = str(ROOT / "node_modules" / ".bin") + env["PATH"] = f"{node_bin}{os.pathsep}{env.get('PATH', '')}" + + if os.name == "nt": + return subprocess.Popen(cmd, shell=True, cwd=str(cwd), env=env) + return subprocess.Popen(cmd, shell=True, cwd=str(cwd), env=env, preexec_fn=os.setsid) + + +def terminate_server_process(process): + """Terminate the mock API server process.""" + if process is None: + return + try: + if os.name == "nt": + # On Windows, use taskkill to kill the entire process tree + # process.kill() only kills the shell, not the child node process + subprocess.run( + ["taskkill", "/F", "/T", "/PID", str(process.pid)], + capture_output=True, + check=False, + ) + else: + os.killpg(os.getpgid(process.pid), signal.SIGTERM) + except ProcessLookupError: + pass # Process already terminated + except Exception: + # Fallback: try basic kill + try: + process.kill() + except Exception: + pass + + +@pytest.fixture(scope="session", autouse=True) +def testserver(): + """Start the mock API server, coordinated across xdist workers via file lock. + + The first process to acquire the lock starts the server; others wait for it. + The server is intentionally NOT killed in teardown — with xdist, the owning + worker may finish before others, killing the server prematurely. The server + is cleaned up when the tox/parent process exits. + """ + # Check if server is already running + if not wait_for_server(SERVER_URL, timeout=1, interval=0.1): + lock = FileLock(str(LOCK_FILE), timeout=120) + try: + with lock: + # Double-check after acquiring lock + if not wait_for_server(SERVER_URL, timeout=1, interval=0.1): + server = start_server_process() + PID_FILE.write_text(str(server.pid)) + if not wait_for_server(SERVER_URL, timeout=60): + terminate_server_process(server) + pytest.fail(f"Mock API server failed to start at {SERVER_URL}") + except TimeoutError: + if not wait_for_server(SERVER_URL, timeout=5): + pytest.fail("Timeout waiting for server lock") + + # Final check that server is reachable + if not wait_for_server(SERVER_URL, timeout=30): + pytest.fail(f"Mock API server not available at {SERVER_URL}") + + yield + + +@pytest.fixture +def core_library(): + """Import the appropriate core library (azure.core or corehttp).""" + try: + return importlib.import_module("azure.core") + except ModuleNotFoundError: + return importlib.import_module("corehttp") + + +@pytest.fixture +def key_credential(core_library): + """Get the appropriate credential class.""" + try: + return core_library.credentials.AzureKeyCredential + except AttributeError: + return core_library.credentials.ServiceKeyCredential + + +@pytest.fixture +def png_data() -> bytes: + """Load PNG test data.""" + with open(str(DATA_FOLDER / "data/image.png"), "rb") as file_in: + return file_in.read() + + +@pytest.fixture +def jpg_data() -> bytes: + """Load JPG test data.""" + with open(str(DATA_FOLDER / "data/image.jpg"), "rb") as file_in: + return file_in.read() diff --git a/packages/typespec-python/tests/requirements/azure.txt b/packages/typespec-python/tests/requirements/azure.txt new file mode 100644 index 0000000000..ca59fac7d9 --- /dev/null +++ b/packages/typespec-python/tests/requirements/azure.txt @@ -0,0 +1,5 @@ +# Azure SDK dependencies +-r base.txt +azure-core>=1.37.0 +azure-mgmt-core==1.6.0 +geojson>=3.0.0 diff --git a/packages/typespec-python/tests/requirements/base.txt b/packages/typespec-python/tests/requirements/base.txt new file mode 100644 index 0000000000..9331a4a1d8 --- /dev/null +++ b/packages/typespec-python/tests/requirements/base.txt @@ -0,0 +1,12 @@ +# Base test dependencies +pytest==8.3.2 +pytest-xdist>=3.5.0 +pytest-asyncio>=0.14.0 +aiohttp +coverage==7.6.1 +colorama==0.4.6 +isodate>=0.6.1 +typing-extensions>=4.6.0 +tox>=4.16.0 +tox-uv>=1.0.0 +filelock>=3.12.0 diff --git a/packages/typespec-python/tests/requirements/docs.txt b/packages/typespec-python/tests/requirements/docs.txt new file mode 100644 index 0000000000..5b80499ba3 --- /dev/null +++ b/packages/typespec-python/tests/requirements/docs.txt @@ -0,0 +1,9 @@ +# Documentation dependencies +-r base.txt +pip +pylint +pkginfo +sphinx>=7.0.0 +sphinx_rtd_theme>=2.0.0 +myst_parser>=2.0.0 +sphinxcontrib-jquery>=4.1 diff --git a/packages/typespec-python/tests/requirements/lint.txt b/packages/typespec-python/tests/requirements/lint.txt new file mode 100644 index 0000000000..736a780654 --- /dev/null +++ b/packages/typespec-python/tests/requirements/lint.txt @@ -0,0 +1,4 @@ +# Linting dependencies +-r base.txt +pylint==4.0.4 +black==26.3.1 diff --git a/packages/typespec-python/tests/requirements/typecheck.txt b/packages/typespec-python/tests/requirements/typecheck.txt new file mode 100644 index 0000000000..6e09ee898c --- /dev/null +++ b/packages/typespec-python/tests/requirements/typecheck.txt @@ -0,0 +1,5 @@ +# Type checking dependencies +-r base.txt +pyright==1.1.407 +mypy==1.19.1 +types-PyYAML==6.0.12.8 diff --git a/packages/typespec-python/tests/requirements/unbranded.txt b/packages/typespec-python/tests/requirements/unbranded.txt new file mode 100644 index 0000000000..724244f16e --- /dev/null +++ b/packages/typespec-python/tests/requirements/unbranded.txt @@ -0,0 +1,5 @@ +# === common unbranded dependencies across repos === +# Unbranded SDK dependencies +-r base.txt +corehttp[requests] +# === end common unbranded dependencies across repos === diff --git a/packages/typespec-python/tests/tox.ini b/packages/typespec-python/tests/tox.ini new file mode 100644 index 0000000000..a94a60603e --- /dev/null +++ b/packages/typespec-python/tests/tox.ini @@ -0,0 +1,201 @@ +[tox] +envlist = test-{azure,unbranded}, check-{azure,unbranded}, docs-{azure,unbranded}, unittest +skipsdist = True +isolated_build = True +requires = tox-uv + +[testenv] +deps = + -r {tox_root}/requirements/base.txt +setenv = + PYTHONPATH = {tox_root}/../generator + FLAVOR = {envname} +passenv = + FOLDER + +# ============================================================================= +# Test environments +# ============================================================================= + +[testenv:test-azure] +description = Run tests for Azure flavor +setenv = + {[testenv]setenv} + FLAVOR = azure +deps = + {[testenv]deps} + -r {tox_root}/requirements/azure.txt + -e {tox_root}/../generator +commands = + python {tox_root}/install_packages.py azure {tox_root} + pytest mock_api/azure mock_api/shared -v -n auto {posargs} + +[testenv:test-unbranded] +description = Run tests for unbranded flavor +setenv = + {[testenv]setenv} + FLAVOR = unbranded +deps = + {[testenv]deps} + -r {tox_root}/requirements/unbranded.txt + -e {tox_root}/../generator +commands = + python {tox_root}/install_packages.py unbranded {tox_root} + pytest mock_api/unbranded mock_api/shared -v -n auto {posargs} + +[testenv:unittest] +description = Run unit tests for pygen internals +deps = + {[testenv]deps} + -r {tox_root}/requirements/unbranded.txt + -e {tox_root}/../generator +commands = + python {tox_root}/install_packages.py unbranded {tox_root} + pytest unit/ -v -n auto {posargs} + +# ============================================================================= +# Lint, type checking, and static analysis environments +# Split into separate envs for maximum parallelism. Pre-built wheels make +# per-env package installs cheap (~5s instead of ~2min). +# ============================================================================= + +[testenv:lint-azure] +description = Run pylint for Azure flavor +setenv = + {[testenv]setenv} + FLAVOR = azure +deps = + -r {tox_root}/requirements/lint.txt + -r {tox_root}/requirements/azure.txt + -e {tox_root}/../generator +commands = + uv pip install azure-pylint-guidelines-checker==0.5.2 --index-url="https://pkgs.dev.azure.com/azure-sdk/public/_packaging/azure-sdk-for-python/pypi/simple/" + python {tox_root}/install_packages.py azure {tox_root} + python {tox_root}/../eng/scripts/ci/run_pylint.py -t azure -s generated {posargs} + +[testenv:lint-unbranded] +description = Run pylint for unbranded flavor +setenv = + {[testenv]setenv} + FLAVOR = unbranded +deps = + -r {tox_root}/requirements/lint.txt + -r {tox_root}/requirements/unbranded.txt + -e {tox_root}/../generator +commands = + python {tox_root}/install_packages.py unbranded {tox_root} + python {tox_root}/../eng/scripts/ci/run_pylint.py -t unbranded -s generated {posargs} + +[testenv:mypy-azure] +description = Run mypy type checking for Azure flavor +setenv = + {[testenv]setenv} + FLAVOR = azure +deps = + -r {tox_root}/requirements/typecheck.txt + -r {tox_root}/requirements/azure.txt + -e {tox_root}/../generator +commands = + python {tox_root}/install_packages.py azure {tox_root} + python {tox_root}/../eng/scripts/ci/run_mypy.py -t azure -s generated {posargs} + +[testenv:mypy-unbranded] +description = Run mypy type checking for unbranded flavor +setenv = + {[testenv]setenv} + FLAVOR = unbranded +deps = + -r {tox_root}/requirements/typecheck.txt + -r {tox_root}/requirements/unbranded.txt + -e {tox_root}/../generator +commands = + python {tox_root}/install_packages.py unbranded {tox_root} + python {tox_root}/../eng/scripts/ci/run_mypy.py -t unbranded -s generated {posargs} + +[testenv:pyright-azure] +description = Run pyright type checking for Azure flavor +setenv = + {[testenv]setenv} + FLAVOR = azure +deps = + -r {tox_root}/requirements/typecheck.txt + -r {tox_root}/requirements/azure.txt + -e {tox_root}/../generator +commands = + python {tox_root}/install_packages.py azure {tox_root} + python {tox_root}/../eng/scripts/ci/run_pyright.py -t azure -s generated {posargs} + +[testenv:pyright-unbranded] +description = Run pyright type checking for unbranded flavor +setenv = + {[testenv]setenv} + FLAVOR = unbranded +deps = + -r {tox_root}/requirements/typecheck.txt + -r {tox_root}/requirements/unbranded.txt + -e {tox_root}/../generator +commands = + python {tox_root}/install_packages.py unbranded {tox_root} + python {tox_root}/../eng/scripts/ci/run_pyright.py -t unbranded -s generated {posargs} + +# ============================================================================= +# Documentation environments (apiview and sphinx split for parallelism) +# ============================================================================= + +[testenv:apiview-azure] +description = Run apiview validation for Azure flavor +basepython = python3.10 +setenv = + {[testenv]setenv} + FLAVOR = azure +deps = + -r {tox_root}/requirements/docs.txt + -e {tox_root}/../generator +commands = + uv pip install apiview-stub-generator>=0.3.19 pylint-guidelines-checker --no-deps --index-url="https://pkgs.dev.azure.com/azure-sdk/public/_packaging/azure-sdk-for-python/pypi/simple/" + uv pip install astroid charset-normalizer pylint pkginfo + python {tox_root}/install_packages.py azure {tox_root} + python {tox_root}/../eng/scripts/ci/run_apiview.py -t azure -s generated {posargs} + +[testenv:apiview-unbranded] +description = Run apiview validation for unbranded flavor +basepython = python3.10 +setenv = + {[testenv]setenv} + FLAVOR = unbranded +deps = + -r {tox_root}/requirements/docs.txt + -e {tox_root}/../generator +commands = + uv pip install apiview-stub-generator>=0.3.19 pylint-guidelines-checker --no-deps --index-url="https://pkgs.dev.azure.com/azure-sdk/public/_packaging/azure-sdk-for-python/pypi/simple/" + uv pip install astroid charset-normalizer pylint pkginfo + python {tox_root}/install_packages.py unbranded {tox_root} + python {tox_root}/../eng/scripts/ci/run_apiview.py -t unbranded -s generated {posargs} + +[testenv:sphinx-azure] +description = Run sphinx docstring validation for Azure flavor +basepython = python3.10 +setenv = + {[testenv]setenv} + FLAVOR = azure +deps = + -r {tox_root}/requirements/docs.txt + -r {tox_root}/requirements/azure.txt + -e {tox_root}/../generator +commands = + python {tox_root}/install_packages.py azure {tox_root} + python {tox_root}/../eng/scripts/ci/run_sphinx_build.py -t azure -s generated {posargs} + +[testenv:sphinx-unbranded] +description = Run sphinx docstring validation for unbranded flavor +basepython = python3.10 +setenv = + {[testenv]setenv} + FLAVOR = unbranded +deps = + -r {tox_root}/requirements/docs.txt + -r {tox_root}/requirements/unbranded.txt + -e {tox_root}/../generator +commands = + python {tox_root}/install_packages.py unbranded {tox_root} + python {tox_root}/../eng/scripts/ci/run_sphinx_build.py -t unbranded -s generated {posargs} From 59ad193a18d213be7a136d63b06fdd51ddc18201 Mon Sep 17 00:00:00 2001 From: Yuchao Yan Date: Sat, 9 May 2026 05:36:19 +0000 Subject: [PATCH 28/36] update --- packages/typespec-python/.gitignore | 1 - packages/typespec-python/eng/scripts/sync.ts | 6 -- packages/typespec-python/tests/tox.ini | 99 ++++++++++++-------- 3 files changed, 62 insertions(+), 44 deletions(-) diff --git a/packages/typespec-python/.gitignore b/packages/typespec-python/.gitignore index 75145c8ee0..831a453e46 100644 --- a/packages/typespec-python/.gitignore +++ b/packages/typespec-python/.gitignore @@ -4,4 +4,3 @@ # the Python test suites. tests/data/ tests/mock_api/ -generator/ diff --git a/packages/typespec-python/eng/scripts/sync.ts b/packages/typespec-python/eng/scripts/sync.ts index a3b285d761..3e9e8c2114 100644 --- a/packages/typespec-python/eng/scripts/sync.ts +++ b/packages/typespec-python/eng/scripts/sync.ts @@ -92,12 +92,6 @@ const INCLUDES: readonly string[] = [ // CI. Azure's version uses the working `uv build --wheel` flow. Re-include // once the upstream script is fixed. "tests/conftest.py", - "tests/tox.ini", - - // The pygen Python package. Mirrored from upstream because the tox envs - // (`-e {tox_root}/../generator`) and PYTHONPATH expect this directory to - // exist. Gitignored locally; `pnpm sync` populates it before tests/builds. - "generator/", ]; /** diff --git a/packages/typespec-python/tests/tox.ini b/packages/typespec-python/tests/tox.ini index a94a60603e..3007a8069c 100644 --- a/packages/typespec-python/tests/tox.ini +++ b/packages/typespec-python/tests/tox.ini @@ -1,5 +1,5 @@ [tox] -envlist = test-{azure,unbranded}, check-{azure,unbranded}, docs-{azure,unbranded}, unittest +envlist = test-{azure,unbranded}, lint-{azure,unbranded}, mypy-{azure,unbranded}, pyright-{azure,unbranded}, apiview-{azure,unbranded}, sphinx-{azure,unbranded} skipsdist = True isolated_build = True requires = tox-uv @@ -8,10 +8,12 @@ requires = tox-uv deps = -r {tox_root}/requirements/base.txt setenv = - PYTHONPATH = {tox_root}/../generator FLAVOR = {envname} passenv = FOLDER +allowlist_externals = + pytest + uv # ============================================================================= # Test environments @@ -25,7 +27,6 @@ setenv = deps = {[testenv]deps} -r {tox_root}/requirements/azure.txt - -e {tox_root}/../generator commands = python {tox_root}/install_packages.py azure {tox_root} pytest mock_api/azure mock_api/shared -v -n auto {posargs} @@ -38,54 +39,46 @@ setenv = deps = {[testenv]deps} -r {tox_root}/requirements/unbranded.txt - -e {tox_root}/../generator commands = python {tox_root}/install_packages.py unbranded {tox_root} pytest mock_api/unbranded mock_api/shared -v -n auto {posargs} -[testenv:unittest] -description = Run unit tests for pygen internals -deps = - {[testenv]deps} - -r {tox_root}/requirements/unbranded.txt - -e {tox_root}/../generator -commands = - python {tox_root}/install_packages.py unbranded {tox_root} - pytest unit/ -v -n auto {posargs} - # ============================================================================= -# Lint, type checking, and static analysis environments -# Split into separate envs for maximum parallelism. Pre-built wheels make -# per-env package installs cheap (~5s instead of ~2min). +# Lint environments # ============================================================================= [testenv:lint-azure] -description = Run pylint for Azure flavor +description = Run linting for Azure flavor +basepython = python3.12 setenv = {[testenv]setenv} FLAVOR = azure deps = -r {tox_root}/requirements/lint.txt -r {tox_root}/requirements/azure.txt - -e {tox_root}/../generator commands = uv pip install azure-pylint-guidelines-checker==0.5.2 --index-url="https://pkgs.dev.azure.com/azure-sdk/public/_packaging/azure-sdk-for-python/pypi/simple/" python {tox_root}/install_packages.py azure {tox_root} python {tox_root}/../eng/scripts/ci/run_pylint.py -t azure -s generated {posargs} [testenv:lint-unbranded] -description = Run pylint for unbranded flavor +description = Run linting for unbranded flavor +basepython = python3.12 setenv = {[testenv]setenv} FLAVOR = unbranded deps = -r {tox_root}/requirements/lint.txt -r {tox_root}/requirements/unbranded.txt - -e {tox_root}/../generator commands = + uv pip install azure-pylint-guidelines-checker==0.5.2 --index-url="https://pkgs.dev.azure.com/azure-sdk/public/_packaging/azure-sdk-for-python/pypi/simple/" python {tox_root}/install_packages.py unbranded {tox_root} python {tox_root}/../eng/scripts/ci/run_pylint.py -t unbranded -s generated {posargs} +# ============================================================================= +# Type checking environments +# ============================================================================= + [testenv:mypy-azure] description = Run mypy type checking for Azure flavor setenv = @@ -94,7 +87,6 @@ setenv = deps = -r {tox_root}/requirements/typecheck.txt -r {tox_root}/requirements/azure.txt - -e {tox_root}/../generator commands = python {tox_root}/install_packages.py azure {tox_root} python {tox_root}/../eng/scripts/ci/run_mypy.py -t azure -s generated {posargs} @@ -107,7 +99,6 @@ setenv = deps = -r {tox_root}/requirements/typecheck.txt -r {tox_root}/requirements/unbranded.txt - -e {tox_root}/../generator commands = python {tox_root}/install_packages.py unbranded {tox_root} python {tox_root}/../eng/scripts/ci/run_mypy.py -t unbranded -s generated {posargs} @@ -120,7 +111,6 @@ setenv = deps = -r {tox_root}/requirements/typecheck.txt -r {tox_root}/requirements/azure.txt - -e {tox_root}/../generator commands = python {tox_root}/install_packages.py azure {tox_root} python {tox_root}/../eng/scripts/ci/run_pyright.py -t azure -s generated {posargs} @@ -133,7 +123,6 @@ setenv = deps = -r {tox_root}/requirements/typecheck.txt -r {tox_root}/requirements/unbranded.txt - -e {tox_root}/../generator commands = python {tox_root}/install_packages.py unbranded {tox_root} python {tox_root}/../eng/scripts/ci/run_pyright.py -t unbranded -s generated {posargs} @@ -144,58 +133,94 @@ commands = [testenv:apiview-azure] description = Run apiview validation for Azure flavor -basepython = python3.10 +basepython = python3.12 setenv = {[testenv]setenv} FLAVOR = azure deps = -r {tox_root}/requirements/docs.txt - -e {tox_root}/../generator commands = - uv pip install apiview-stub-generator>=0.3.19 pylint-guidelines-checker --no-deps --index-url="https://pkgs.dev.azure.com/azure-sdk/public/_packaging/azure-sdk-for-python/pypi/simple/" - uv pip install astroid charset-normalizer pylint pkginfo + pip install apiview-stub-generator>=0.3.19 pylint-guidelines-checker --no-deps --index-url="https://pkgs.dev.azure.com/azure-sdk/public/_packaging/azure-sdk-for-python/pypi/simple/" + pip install astroid charset-normalizer pylint pkginfo python {tox_root}/install_packages.py azure {tox_root} python {tox_root}/../eng/scripts/ci/run_apiview.py -t azure -s generated {posargs} [testenv:apiview-unbranded] description = Run apiview validation for unbranded flavor -basepython = python3.10 +basepython = python3.12 setenv = {[testenv]setenv} FLAVOR = unbranded deps = -r {tox_root}/requirements/docs.txt - -e {tox_root}/../generator commands = - uv pip install apiview-stub-generator>=0.3.19 pylint-guidelines-checker --no-deps --index-url="https://pkgs.dev.azure.com/azure-sdk/public/_packaging/azure-sdk-for-python/pypi/simple/" - uv pip install astroid charset-normalizer pylint pkginfo + pip install apiview-stub-generator>=0.3.19 pylint-guidelines-checker --no-deps --index-url="https://pkgs.dev.azure.com/azure-sdk/public/_packaging/azure-sdk-for-python/pypi/simple/" + pip install astroid charset-normalizer pylint pkginfo python {tox_root}/install_packages.py unbranded {tox_root} python {tox_root}/../eng/scripts/ci/run_apiview.py -t unbranded -s generated {posargs} [testenv:sphinx-azure] description = Run sphinx docstring validation for Azure flavor -basepython = python3.10 +basepython = python3.12 setenv = {[testenv]setenv} FLAVOR = azure deps = -r {tox_root}/requirements/docs.txt -r {tox_root}/requirements/azure.txt - -e {tox_root}/../generator commands = python {tox_root}/install_packages.py azure {tox_root} python {tox_root}/../eng/scripts/ci/run_sphinx_build.py -t azure -s generated {posargs} [testenv:sphinx-unbranded] description = Run sphinx docstring validation for unbranded flavor -basepython = python3.10 +basepython = python3.12 setenv = {[testenv]setenv} FLAVOR = unbranded deps = -r {tox_root}/requirements/docs.txt -r {tox_root}/requirements/unbranded.txt - -e {tox_root}/../generator commands = python {tox_root}/install_packages.py unbranded {tox_root} python {tox_root}/../eng/scripts/ci/run_sphinx_build.py -t unbranded -s generated {posargs} + +# ============================================================================= +# CI environments (combines all checks) +# ============================================================================= + +[testenv:ci-azure] +description = Run full CI for Azure flavor +basepython = python3.12 +setenv = + {[testenv]setenv} + FLAVOR = azure +deps = + -r {tox_root}/requirements/lint.txt + -r {tox_root}/requirements/typecheck.txt + -r {tox_root}/requirements/azure.txt +commands = + uv pip install azure-pylint-guidelines-checker==0.5.2 --index-url="https://pkgs.dev.azure.com/azure-sdk/public/_packaging/azure-sdk-for-python/pypi/simple/" + python {tox_root}/install_packages.py azure {tox_root} + pytest mock_api/azure mock_api/shared -v -n auto + python {tox_root}/../eng/scripts/ci/run_pylint.py -t azure -s generated + python {tox_root}/../eng/scripts/ci/run_mypy.py -t azure -s generated + python {tox_root}/../eng/scripts/ci/run_pyright.py -t azure -s generated + +[testenv:ci-unbranded] +description = Run full CI for unbranded flavor +basepython = python3.12 +setenv = + {[testenv]setenv} + FLAVOR = unbranded +deps = + -r {tox_root}/requirements/lint.txt + -r {tox_root}/requirements/typecheck.txt + -r {tox_root}/requirements/unbranded.txt +commands = + uv pip install azure-pylint-guidelines-checker==0.5.2 --index-url="https://pkgs.dev.azure.com/azure-sdk/public/_packaging/azure-sdk-for-python/pypi/simple/" + python {tox_root}/install_packages.py unbranded {tox_root} + pytest mock_api/unbranded mock_api/shared -v -n auto + python {tox_root}/../eng/scripts/ci/run_pylint.py -t unbranded -s generated + python {tox_root}/../eng/scripts/ci/run_mypy.py -t unbranded -s generated + python {tox_root}/../eng/scripts/ci/run_pyright.py -t unbranded -s generated From 90e08a85ca44a618505918973037991e8018ab09 Mon Sep 17 00:00:00 2001 From: Yuchao Yan Date: Sat, 9 May 2026 13:40:46 +0800 Subject: [PATCH 29/36] Update sync.ts/gitignore comments to reflect tox.ini and generator/ being wrapper-owned MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Following the recent commits that: - removed ests/tox.ini and generator/ from sync.ts INCLUDES (now wrapper-owned, committed) - removed generator/ from .gitignore (now tracked) - committed tests/requirements/* and tests/conftest.py as synced snapshots …the prose comments around the INCLUDES list and the gitignore header no longer matched what's actually being synced. Refresh them so a new reader can tell at a glance: * which files are upstream-truth (kept aligned via pnpm sync) * which files are wrapper-owned (and *why* — including the upstream install_packages.py bug tracked in microsoft/typespec#10636) * which synced paths are gitignored vs committed snapshots No behavior change. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- packages/typespec-python/.gitignore | 6 ++-- packages/typespec-python/eng/scripts/sync.ts | 38 +++++++++++++------- 2 files changed, 29 insertions(+), 15 deletions(-) diff --git a/packages/typespec-python/.gitignore b/packages/typespec-python/.gitignore index 831a453e46..67b9b754ac 100644 --- a/packages/typespec-python/.gitignore +++ b/packages/typespec-python/.gitignore @@ -1,6 +1,8 @@ # Test asset directories that are populated at runtime by `pnpm sync` from the # upstream http-client-python checkout (see eng/scripts/sync.ts INCLUDES). -# These are intentionally not committed; CI runs `pnpm sync` before running -# the Python test suites. +# These are too large or churn too much to commit; CI runs `pnpm sync` before +# running the Python test suites. Other synced files (tests/conftest.py, +# tests/requirements/*) are committed snapshots that `pnpm sync` refreshes in +# place. tests/data/ tests/mock_api/ diff --git a/packages/typespec-python/eng/scripts/sync.ts b/packages/typespec-python/eng/scripts/sync.ts index 3e9e8c2114..9c6f5eec43 100644 --- a/packages/typespec-python/eng/scripts/sync.ts +++ b/packages/typespec-python/eng/scripts/sync.ts @@ -71,26 +71,38 @@ const INCLUDES: readonly string[] = [ // (install.py, prepare.py, venvtools.py, etc.) diverged from upstream's // http-client-python build/test pipeline; the typespec-python wrapper // owns its own copies. + // + // Likewise NOT synced (committed and owned by this wrapper): + // - generator/ : pygen lives upstream as the source of + // truth, but the wrapper checks in a + // pinned snapshot rather than re-fetching + // on every CI run. + // - tests/tox.ini : tox envs differ from upstream (paths, + // emitter name, extra envs). + // - tests/install_packages.py : upstream's version calls `uv pip wheel`, + // which is not a real uv subcommand, so + // it fails in CI. The wrapper keeps the + // working `uv build --wheel` flow. Once + // the upstream script is fixed (see + // microsoft/typespec#10636) it can be + // re-added to this list. // Shared test assets. Directory entries (trailing `/`) are recursive and // **mirror** the upstream layout: files matching upstream are overwritten, - // and local-only files are deleted. The matching directories are - // .gitignored in this package so a fresh CI checkout starts empty and is - // fully populated by `pnpm sync`. Upstream tests are treated as the source - // of truth; any wrapper-specific test must live OUTSIDE these directories - // (e.g. tests/wrapper/) so it isn't pruned by the sync. + // and local-only files are deleted. `tests/data/` and `tests/mock_api/` + // are gitignored so a fresh CI checkout starts empty and is populated by + // `pnpm sync`; `tests/requirements/` is small and stable enough to commit + // as a snapshot that `pnpm sync` refreshes in place. Upstream tests are + // treated as the source of truth; any wrapper-specific test must live + // OUTSIDE these directories (e.g. tests/wrapper/) so it isn't pruned by + // the sync. "tests/data/", "tests/mock_api/", "tests/requirements/", - // Test driver/helper files at the tests/ root. Each is treated as the - // upstream source of truth — DATA_FOLDER, server-launch logic, lint/test - // tox envs etc. stay aligned with http-client-python. - // - // tests/install_packages.py is intentionally NOT synced: upstream's version - // calls `uv pip wheel`, which is not a real uv subcommand, so it fails in - // CI. Azure's version uses the working `uv build --wheel` flow. Re-include - // once the upstream script is fixed. + // Shared test driver/helper file. Treated as the upstream source of truth + // (DATA_FOLDER, server-launch logic, etc.) and kept aligned with + // http-client-python. "tests/conftest.py", ]; From ab178223295945120543071245ba2d7ffa45a2f2 Mon Sep 17 00:00:00 2001 From: Yuchao Yan Date: Sat, 9 May 2026 13:43:22 +0800 Subject: [PATCH 30/36] Exclude tests/mock_api/unbranded/test_unbranded.py from sync This upstream test is unbranded-only and doesn't apply to the Azure wrapper. Add an EXCLUDED_FILES allow-list to sync.ts that: - skips the file during the copy phase, and - prunes it from the destination if a previous sync (or a manual edit) left it behind. In --check mode the file is reported as drift so CI catches accidental re-introduction. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- packages/typespec-python/eng/scripts/sync.ts | 26 +++++++++++++++++--- 1 file changed, 22 insertions(+), 4 deletions(-) diff --git a/packages/typespec-python/eng/scripts/sync.ts b/packages/typespec-python/eng/scripts/sync.ts index 9c6f5eec43..64ab1c66c6 100644 --- a/packages/typespec-python/eng/scripts/sync.ts +++ b/packages/typespec-python/eng/scripts/sync.ts @@ -124,6 +124,21 @@ const EXCLUDED_SEGMENTS: ReadonlySet = new Set([ ".wheels", ]); +/** + * Specific file paths (POSIX, relative to the package root) that must NOT be + * present in the destination after a sync, even if upstream has them. They are + * skipped during the copy phase and actively deleted from the destination if + * they exist. In --check mode their presence is reported as drift. + * + * Use this for individual upstream files that don't apply to the wrapper but + * live inside an otherwise-mirrored directory. Whole directories should be + * handled via EXCLUDED_SEGMENTS instead. + */ +const EXCLUDED_FILES: ReadonlySet = new Set([ + // Unbranded-only mock test that doesn't apply to the Azure wrapper. + "tests/mock_api/unbranded/test_unbranded.py", +]); + const argv = parseArgs({ args: process.argv.slice(2), options: { @@ -327,22 +342,25 @@ function main(): void { const sourceFiles = listFilesRecursive(srcAbs); const sourceRelSet = new Set(sourceFiles.map((f) => toPosix(relative(srcAbs, f)))); - // Step 1: copy source -> dest + // Step 1: copy source -> dest (skipping excluded files) for (const srcFile of sourceFiles) { const relFromDir = toPosix(relative(srcAbs, srcFile)); const destAbs = join(destDirAbs, ...relFromDir.split("/")); const relFromPkg = toPosix(relative(packageRoot, destAbs)); + if (EXCLUDED_FILES.has(relFromPkg)) continue; syncFile(srcFile, destAbs, relFromPkg, stats); } - // Step 2: prune local-only files + // Step 2: prune local-only files (and any explicitly excluded files + // that may still be sitting in the destination from a previous sync). const destFiles = listFilesRecursive(destDirAbs); for (const destFile of destFiles) { const relFromDir = toPosix(relative(destDirAbs, destFile)); - if (sourceRelSet.has(relFromDir)) continue; const relFromPkg = toPosix(relative(packageRoot, destFile)); + const isExcluded = EXCLUDED_FILES.has(relFromPkg); + if (sourceRelSet.has(relFromDir) && !isExcluded) continue; if (check) { - stats.drifted.push(relFromPkg + " (local-only)"); + stats.drifted.push(relFromPkg + (isExcluded ? " (excluded)" : " (local-only)")); } else { fs.unlinkSync(destFile); removeEmptyDirsUpTo(dirname(destFile), destDirAbs); From 72425b4f19e4de45a444cb0d126786c09a0f1a7a Mon Sep 17 00:00:00 2001 From: Yuchao Yan Date: Sat, 9 May 2026 07:20:14 +0000 Subject: [PATCH 31/36] add debug configuration for typespec-python --- .vscode/launch.json | 15 +++++++++++++++ packages/typespec-python/.gitignore | 3 +++ 2 files changed, 18 insertions(+) diff --git a/.vscode/launch.json b/.vscode/launch.json index 306dd0c704..331a42d0e0 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -219,6 +219,21 @@ "request": "launch", "args": ["--extensionDevelopmentPath=${workspaceFolder}/packages/typespec-azure-vscode"], "sourceMaps": true + }, + { + "name": "typespec-python", + "request": "launch", + "args": [ + "compile", + "${workspaceFolder}/packages/typespec-python/alpha/client.tsp", + "--emit=${workspaceFolder}/packages/typespec-python", + "--option=@azure-tools/typespec-python.flavor=azure" + ], + "program": "${workspaceRoot}/core/packages/compiler/entrypoints/cli.js", + "skipFiles": ["/**"], + "type": "node", + "smartStep": true, + "sourceMaps": true } ], "compounds": [ diff --git a/packages/typespec-python/.gitignore b/packages/typespec-python/.gitignore index 67b9b754ac..b4233db6d8 100644 --- a/packages/typespec-python/.gitignore +++ b/packages/typespec-python/.gitignore @@ -6,3 +6,6 @@ # place. tests/data/ tests/mock_api/ + +# folder for debug +alpha From ec6808440bea91bd114d837b9331f8da1d2f1b55 Mon Sep 17 00:00:00 2001 From: Chenjie Shi Date: Mon, 25 May 2026 16:05:11 +0800 Subject: [PATCH 32/36] Backmerge release/may-2026 (tcgc@0.68.2 hotfix) (#4489) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Backmerge of hotfix release tcgc@0.69.0 from `release/may-2026` into `main`. This ensures the version bump and fixes are reflected in main. ⚠️ **Rebase merge** this PR (do not squash). --------- Co-authored-by: Copilot <198982749+Copilot@users.noreply.github.com> Co-authored-by: tadelesh <1726438+tadelesh@users.noreply.github.com> Co-authored-by: tadelesh Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../CHANGELOG.md | 13 ++ .../package.json | 2 +- .../src/clients.ts | 10 +- .../src/example.ts | 3 +- .../src/functions.ts | 4 + .../src/interfaces.ts | 8 +- .../src/methods.ts | 2 + .../src/types.ts | 32 +++++ .../examples/example-types/getDecimal.json | 10 ++ .../examples/example-types/getDecimal128.json | 10 ++ .../getModelDiscriminatorFromChild.json | 20 +++ .../test/examples/types.test.ts | 117 ++++++++++++++++++ .../test/functions/exact.test.ts | 59 +++++++++ .../test/functions/reorder-parameters.test.ts | 37 ++++++ 14 files changed, 318 insertions(+), 9 deletions(-) create mode 100644 packages/typespec-client-generator-core/test/examples/example-types/getDecimal.json create mode 100644 packages/typespec-client-generator-core/test/examples/example-types/getDecimal128.json create mode 100644 packages/typespec-client-generator-core/test/examples/example-types/getModelDiscriminatorFromChild.json diff --git a/packages/typespec-client-generator-core/CHANGELOG.md b/packages/typespec-client-generator-core/CHANGELOG.md index 4d29dfa34d..6d2fcae61a 100644 --- a/packages/typespec-client-generator-core/CHANGELOG.md +++ b/packages/typespec-client-generator-core/CHANGELOG.md @@ -1,5 +1,18 @@ # Change Log - @azure-tools/typespec-client-generator-core +## 0.68.2 + +### Features + +- [#4480](https://github.com/Azure/typespec-azure/pull/4480) Extend `isExactName` to additional SDK types whose names can be changed by `@clientName`: `SdkClientType`, `SdkServiceMethodBase` (and its derived method kinds), and `SdkEnumValueType`. Also fixed `SdkClientType.name` to strip the internal `exact()` marker. + +### Bug Fixes + +- [#4477](https://github.com/Azure/typespec-azure/pull/4477) Fix `reorderParameters`, `addParameter`, `removeParameter`, and `replaceParameter` so that decorators copied to cloned model properties and cloned operations are applied (by calling `finishType` after cloning). This fixes scenarios such as parameters with `@typeChangedFrom` under a `@versioned` service. +- [#4487](https://github.com/Azure/typespec-azure/pull/4487) Fix example value matching for `decimal` and `decimal128` typed properties. JSON `number` values in example files are now correctly recognized as matching `decimal` / `decimal128` typed properties. +- [#4484](https://github.com/Azure/typespec-azure/pull/4484) Fix example values being dropped on subtypes added via `@hierarchyBuilding` by propagating serialization options from the nearest ancestor to the newly added subtype + + ## 0.68.1 ### Bug Fixes diff --git a/packages/typespec-client-generator-core/package.json b/packages/typespec-client-generator-core/package.json index 52551e3690..5301aef4a7 100644 --- a/packages/typespec-client-generator-core/package.json +++ b/packages/typespec-client-generator-core/package.json @@ -1,6 +1,6 @@ { "name": "@azure-tools/typespec-client-generator-core", - "version": "0.68.1", + "version": "0.68.2", "author": "Microsoft Corporation", "description": "TypeSpec Data Plane Generation library", "homepage": "https://azure.github.io/typespec-azure", diff --git a/packages/typespec-client-generator-core/src/clients.ts b/packages/typespec-client-generator-core/src/clients.ts index 9e72456d6e..03ec54d252 100644 --- a/packages/typespec-client-generator-core/src/clients.ts +++ b/packages/typespec-client-generator-core/src/clients.ts @@ -33,7 +33,7 @@ import { } from "./internal-utils.js"; import { createDiagnostic } from "./lib.js"; import { createSdkMethods, getSdkMethodParameter } from "./methods.js"; -import { getCrossLanguageDefinitionId } from "./public-utils.js"; +import { getCrossLanguageDefinitionId, getLibraryName, isExactClientName } from "./public-utils.js"; import { getSdkBuiltInType, getSdkCredentialParameter, getTypeSpecBuiltInType } from "./types.js"; function getEndpointTypeFromSingleServer< @@ -190,17 +190,15 @@ export function createSdkClientType, readonly Diagnostic[]] { const diagnostics = createDiagnosticCollector(); let name = client.name; - if (client.type) { - const override = getClientNameOverride(context, client.type); - if (override) { - name = override; - } + if (client.type && getClientNameOverride(context, client.type)) { + name = getLibraryName(context, client.type); } const clientType = getActualClientType(client); const sdkClientType: SdkClientType = { __raw: client, kind: "client", name, + isExactName: client.type ? isExactClientName(context, client.type) : false, doc: client.type ? getClientDoc(context, client.type) : undefined, summary: client.type ? getSummary(context.program, client.type) : undefined, methods: [], diff --git a/packages/typespec-client-generator-core/src/example.ts b/packages/typespec-client-generator-core/src/example.ts index 715c797a47..deabda4b28 100644 --- a/packages/typespec-client-generator-core/src/example.ts +++ b/packages/typespec-client-generator-core/src/example.ts @@ -31,6 +31,7 @@ import { SdkServiceOperation, SdkType, TCGCContext, + isSdkFixedPointKind, isSdkFloatKind, isSdkIntKind, } from "./interfaces.js"; @@ -446,7 +447,7 @@ function getSdkTypeExample( return diagnostics.wrap(undefined); } - if (isSdkIntKind(type.kind) || isSdkFloatKind(type.kind)) { + if (isSdkIntKind(type.kind) || isSdkFloatKind(type.kind) || isSdkFixedPointKind(type.kind)) { return getSdkBaseTypeExample("number", type as SdkType, example, relativePath); } else { switch (type.kind) { diff --git a/packages/typespec-client-generator-core/src/functions.ts b/packages/typespec-client-generator-core/src/functions.ts index 992968143b..9a8a2e5b23 100644 --- a/packages/typespec-client-generator-core/src/functions.ts +++ b/packages/typespec-client-generator-core/src/functions.ts @@ -20,6 +20,8 @@ function cloneOperation( // Copy decorators from the original operation if (operation.decorators) { newOp.decorators = [...operation.decorators]; + // Re-finish the type so the copied decorators are applied + tk.type.finishType(newOp); } // Set the source operation for tracing @@ -40,6 +42,8 @@ function cloneModelProperty(tk: ReturnType, prop: ModelProperty): Mode if (prop.decorators) { clonedProp.decorators = [...prop.decorators]; } + // Finish the type so decorators are applied + tk.type.finishType(clonedProp); return clonedProp; } diff --git a/packages/typespec-client-generator-core/src/interfaces.ts b/packages/typespec-client-generator-core/src/interfaces.ts index 5cf8047dd9..11d57a45b2 100644 --- a/packages/typespec-client-generator-core/src/interfaces.ts +++ b/packages/typespec-client-generator-core/src/interfaces.ts @@ -208,6 +208,8 @@ export interface SdkClientType< kind: "client"; /** Name of the client. */ name: string; + /** Whether name should be used exactly as-is, without casing transformations. */ + isExactName: boolean; /** Full qualified namespace. */ namespace: string; /** Document for the type. */ @@ -373,7 +375,7 @@ export function isSdkFloatKind(kind: string): kind is keyof typeof SdkFloatingPo return kind in SdkFloatingPointKindsEnum; } -function isSdkFixedPointKind(kind: string): kind is keyof typeof SdkFixedPointKindsEnum { +export function isSdkFixedPointKind(kind: string): kind is keyof typeof SdkFixedPointKindsEnum { return kind in SdkFixedPointKindsEnum; } @@ -480,6 +482,8 @@ export interface SdkEnumValueType< > extends SdkTypeBase { kind: "enumvalue"; name: string; + /** Whether name should be used exactly as-is, without casing transformations. */ + isExactName: boolean; value: string | number; enumType: SdkEnumType; valueType: TValueType; @@ -1000,6 +1004,8 @@ interface SdkServiceMethodBase< > extends DecoratedType { __raw?: Operation; name: string; + /** Whether name should be used exactly as-is, without casing transformations. */ + isExactName: boolean; /** Whether the type has public or private accessibility */ access: AccessFlags; /** API versions supported for current type. */ diff --git a/packages/typespec-client-generator-core/src/methods.ts b/packages/typespec-client-generator-core/src/methods.ts index 8de5ce6ad3..03588f8eca 100644 --- a/packages/typespec-client-generator-core/src/methods.ts +++ b/packages/typespec-client-generator-core/src/methods.ts @@ -80,6 +80,7 @@ import { getCrossLanguageDefinitionId, getHttpOperationWithCache, getLibraryName, + isExactClientName, } from "./public-utils.js"; import { getClientTypeWithDiagnostics, @@ -736,6 +737,7 @@ export function getSdkBasicServiceMethod { return ( @@ -2121,6 +2128,31 @@ function handleLegacyHierarchyBuilding(context: TCGCContext): [void, readonly Di return diagnostics.wrap(undefined); } +/** + * Propagate serialization options from a parent model to a newly added subtype. + * This handles the case where updateSerializationOptions already ran on the parent + * before the subtype was added via @hierarchyBuilding. + */ +function propagateSerializationToSubtype(context: TCGCContext, sdkType: SdkModelType): void { + // Find the nearest ancestor with serialization options to determine content types + let ancestor: SdkModelType | undefined = sdkType.baseModel; + const contentTypes: string[] = []; + while (ancestor) { + if (ancestor.serializationOptions.json) { + contentTypes.push("application/json"); + } + if (ancestor.serializationOptions.xml) { + contentTypes.push("application/xml"); + } + if (contentTypes.length > 0) break; + ancestor = ancestor.baseModel; + } + + if (contentTypes.length > 0) { + updateSerializationOptions(context, sdkType, contentTypes); + } +} + /** * Reconcile properties on a rebased model after `@hierarchyBuilding(oldBase, newBase)`. * diff --git a/packages/typespec-client-generator-core/test/examples/example-types/getDecimal.json b/packages/typespec-client-generator-core/test/examples/example-types/getDecimal.json new file mode 100644 index 0000000000..7f367eb99f --- /dev/null +++ b/packages/typespec-client-generator-core/test/examples/example-types/getDecimal.json @@ -0,0 +1,10 @@ +{ + "operationId": "getDecimal", + "title": "getDecimal", + "parameters": {}, + "responses": { + "200": { + "body": 123.45 + } + } +} diff --git a/packages/typespec-client-generator-core/test/examples/example-types/getDecimal128.json b/packages/typespec-client-generator-core/test/examples/example-types/getDecimal128.json new file mode 100644 index 0000000000..7ebcf910fa --- /dev/null +++ b/packages/typespec-client-generator-core/test/examples/example-types/getDecimal128.json @@ -0,0 +1,10 @@ +{ + "operationId": "getDecimal128", + "title": "getDecimal128", + "parameters": {}, + "responses": { + "200": { + "body": 80 + } + } +} diff --git a/packages/typespec-client-generator-core/test/examples/example-types/getModelDiscriminatorFromChild.json b/packages/typespec-client-generator-core/test/examples/example-types/getModelDiscriminatorFromChild.json new file mode 100644 index 0000000000..073d46e871 --- /dev/null +++ b/packages/typespec-client-generator-core/test/examples/example-types/getModelDiscriminatorFromChild.json @@ -0,0 +1,20 @@ +{ + "operationId": "updatePet", + "title": "updatePet", + "parameters": { + "pet": { + "kind": "dog", + "isTrained": true, + "breed": "labrador" + } + }, + "responses": { + "200": { + "body": { + "kind": "dog", + "isTrained": true, + "breed": "labrador" + } + } + } +} diff --git a/packages/typespec-client-generator-core/test/examples/types.test.ts b/packages/typespec-client-generator-core/test/examples/types.test.ts index e26d1a70c5..19b182b310 100644 --- a/packages/typespec-client-generator-core/test/examples/types.test.ts +++ b/packages/typespec-client-generator-core/test/examples/types.test.ts @@ -345,6 +345,62 @@ it("SdkNumberExample", async () => { expectDiagnostics(context.diagnostics, []); }); +it("SdkNumberExample for decimal", async () => { + const instance = await SimpleTester.createInstance(); + await instance.fs.addRealTypeSpecFile( + "./examples/getDecimal.json", + `${__dirname}/example-types/getDecimal.json`, + ); + const { program } = await instance.compile(` + @service + namespace TestClient { + #suppress "@azure-tools/typespec-azure-core/no-generic-numeric" "for test" + op getDecimal(): decimal; + } + `); + const context = await createSdkContextForTester(program); + + const operation = (context.sdkPackage.clients[0].methods[0] as SdkServiceMethod) + .operation; + ok(operation); + strictEqual(operation.examples?.length, 1); + const response = operation.examples[0].responses.find((x) => x.statusCode === 200); + ok(response); + strictEqual(response.bodyValue?.kind, "number"); + strictEqual(response.bodyValue?.value, 123.45); + strictEqual(response.bodyValue?.type.kind, "decimal"); + + expectDiagnostics(context.diagnostics, []); +}); + +it("SdkNumberExample for decimal128", async () => { + const instance = await SimpleTester.createInstance(); + await instance.fs.addRealTypeSpecFile( + "./examples/getDecimal128.json", + `${__dirname}/example-types/getDecimal128.json`, + ); + const { program } = await instance.compile(` + @service + namespace TestClient { + #suppress "@azure-tools/typespec-azure-core/no-generic-numeric" "for test" + op getDecimal128(): decimal128; + } + `); + const context = await createSdkContextForTester(program); + + const operation = (context.sdkPackage.clients[0].methods[0] as SdkServiceMethod) + .operation; + ok(operation); + strictEqual(operation.examples?.length, 1); + const response = operation.examples[0].responses.find((x) => x.statusCode === 200); + ok(response); + strictEqual(response.bodyValue?.kind, "number"); + strictEqual(response.bodyValue?.value, 80); + strictEqual(response.bodyValue?.type.kind, "decimal128"); + + expectDiagnostics(context.diagnostics, []); +}); + it("SdkNumberExample diagnostic", async () => { const instance = await SimpleTester.createInstance(); await instance.fs.addRealTypeSpecFile( @@ -1277,6 +1333,67 @@ it("SdkModelExample from discriminated types with union kind fallback", async () expectDiagnostics(context.diagnostics, []); }); +it("SdkModelExample from discriminated types with child value via intermediate model", async () => { + const instance = await SimpleTester.createInstance(); + await instance.fs.addRealTypeSpecFile( + "./examples/updatePet.json", + `${__dirname}/example-types/getModelDiscriminatorFromChild.json`, + ); + const { program } = await instance.compile(` + @service + namespace TestClient { + @discriminator("kind") + model Animal { + kind: string; + @doc("Whether the pet is trained") + isTrained: boolean; + } + + model Pet extends Animal { + kind: "pet"; + } + + model Dog extends Animal { + kind: "dog"; + breed: string; + } + + model Cat extends Animal { + kind: "cat"; + } + + @@Azure.ClientGenerator.Core.Legacy.hierarchyBuilding(Dog, Pet); + @@usage(Animal, Usage.input | Usage.output); + + op updatePet(@body pet: Pet): void; + } + `); + const context = await createSdkContextForTester(program); + + const operation = (context.sdkPackage.clients[0].methods[0] as SdkServiceMethod) + .operation; + ok(operation); + strictEqual(operation.examples?.length, 1); + const example = operation.examples[0]; + const bodyParam = example.parameters.find((x) => x.parameter.name === "pet"); + ok(bodyParam); + strictEqual(bodyParam.value.kind, "model"); + strictEqual(bodyParam.value.type.name, "Dog"); + // The discriminator value "dog" from the child model should be preserved + strictEqual(bodyParam.value.value["kind"].value, "dog"); + strictEqual(bodyParam.value.value["kind"].kind, "string"); + strictEqual(bodyParam.value.value["kind"].type.kind, "constant"); + strictEqual(bodyParam.value.value["isTrained"].value, true); + strictEqual(bodyParam.value.value["breed"].value, "labrador"); + strictEqual(bodyParam.value.value["breed"].kind, "string"); + + // Only diagnostic expected is for the response body + // (operation returns void but example has a response body) + expectDiagnostics(context.diagnostics, [ + { code: "@azure-tools/typespec-client-generator-core/example-value-no-mapping" }, + ]); +}); + it("SdkModelExample with additional properties", async () => { const instance = await SimpleTester.createInstance(); await instance.fs.addRealTypeSpecFile( diff --git a/packages/typespec-client-generator-core/test/functions/exact.test.ts b/packages/typespec-client-generator-core/test/functions/exact.test.ts index 42018063a5..e51b5042a7 100644 --- a/packages/typespec-client-generator-core/test/functions/exact.test.ts +++ b/packages/typespec-client-generator-core/test/functions/exact.test.ts @@ -213,6 +213,65 @@ describe("exact", () => { const client = sdkPackage.clients[0]; const method = client.methods[0]; strictEqual(method.name, "my_exact_op"); + strictEqual(method.isExactName, true); + }); + }); + + describe("exact naming on enum values", () => { + it("marks enum value name as exact via exact()", async () => { + const { program } = await SimpleBaseTester.compile( + createClientCustomizationInput( + ` + @service + namespace MyService; + + enum Status { + Active, + Inactive, + } + + op get(@query status: Status): void; + `, + ` + #suppress "experimental-feature" "testing exact" + @@clientName(MyService.Status.Active, exact("my_active_value")); + `, + ), + ); + + const context = await createSdkContextForTester(program); + const sdkPackage = context.sdkPackage; + const enumType = sdkPackage.enums[0]; + const activeValue = enumType.values.find((v) => v.name === "my_active_value"); + strictEqual(activeValue?.isExactName, true); + const inactiveValue = enumType.values.find((v) => v.name === "Inactive"); + strictEqual(inactiveValue?.isExactName, false); + }); + }); + + describe("exact naming on clients", () => { + it("marks client name as exact via exact()", async () => { + const { program } = await SimpleBaseTester.compile( + createClientCustomizationInput( + ` + @service + namespace MyService; + + @route("/test") + op testOp(): void; + `, + ` + #suppress "experimental-feature" "testing exact" + @@clientName(MyService, exact("my_exact_client")); + `, + ), + ); + + const context = await createSdkContextForTester(program); + const sdkPackage = context.sdkPackage; + const client = sdkPackage.clients[0]; + strictEqual(client.name, "my_exact_client"); + strictEqual(client.isExactName, true); }); }); }); diff --git a/packages/typespec-client-generator-core/test/functions/reorder-parameters.test.ts b/packages/typespec-client-generator-core/test/functions/reorder-parameters.test.ts index 42ddac90e8..1dd36cdd05 100644 --- a/packages/typespec-client-generator-core/test/functions/reorder-parameters.test.ts +++ b/packages/typespec-client-generator-core/test/functions/reorder-parameters.test.ts @@ -118,6 +118,43 @@ describe("reorderParameters", () => { }); }); + describe("with versioning decorators", () => { + it("does not report error when parameter has @typeChangedFrom decorator", async () => { + const { program } = await SimpleBaseTester.compile( + createClientCustomizationInput( + ` + @service + @versioned(Versions) + namespace MyService; + + enum Versions { + v1, + v2, + } + + op myOp( + @typeChangedFrom(Versions.v2, int32) @query a: string, + @query b: string, + ): void; + `, + ` + #suppress "experimental-feature" "testing reorderParameters" + @@override(MyService.myOp, reorderParameters(MyService.myOp, #["b", "a"])); + `, + ), + ); + + const context = await createSdkContextForTester(program, { + "api-version": "v1", + }); + const method = context.sdkPackage.clients[0].methods[0]; + + const userParams = method.parameters.filter((p) => p.name !== "contentType"); + strictEqual(userParams[0].name, "b"); + strictEqual(userParams[1].name, "a"); + }); + }); + describe("scoped usage", () => { it("applies reorder only for specified language scope", async () => { const mainCode = ` From 5c22b43cc204502822d8409f93a61b7962c154a7 Mon Sep 17 00:00:00 2001 From: Yuchao Yan Date: Tue, 26 May 2026 03:25:46 +0000 Subject: [PATCH 33/36] update ignore --- packages/typespec-python/.gitignore | 9 --------- packages/typespec-python/package.json | 2 +- 2 files changed, 1 insertion(+), 10 deletions(-) diff --git a/packages/typespec-python/.gitignore b/packages/typespec-python/.gitignore index b4233db6d8..de61c5b4cd 100644 --- a/packages/typespec-python/.gitignore +++ b/packages/typespec-python/.gitignore @@ -1,11 +1,2 @@ -# Test asset directories that are populated at runtime by `pnpm sync` from the -# upstream http-client-python checkout (see eng/scripts/sync.ts INCLUDES). -# These are too large or churn too much to commit; CI runs `pnpm sync` before -# running the Python test suites. Other synced files (tests/conftest.py, -# tests/requirements/*) are committed snapshots that `pnpm sync` refreshes in -# place. -tests/data/ -tests/mock_api/ - # folder for debug alpha diff --git a/packages/typespec-python/package.json b/packages/typespec-python/package.json index f1d49fb7f0..1ffe5480bb 100644 --- a/packages/typespec-python/package.json +++ b/packages/typespec-python/package.json @@ -37,7 +37,7 @@ "lint:extra": "tsx ./eng/scripts/ci/lint.ts", "format:extra": "tsx ./eng/scripts/ci/format.ts --python", "format:extra:check": "tsx ./eng/scripts/ci/format.ts --python --check", - "regenerate": "pnpm run sync && tsx ./eng/scripts/ci/regenerate.ts", + "regenerate": "tsx ./eng/scripts/ci/regenerate.ts", "sync": "tsx ./eng/scripts/sync.ts", "sync:check": "tsx ./eng/scripts/sync.ts --check", "test:python:e2e": "tsx ./eng/scripts/ci/run-tests.ts", From 6594dcd29e5c27400bac994422f8882f4cb58731 Mon Sep 17 00:00:00 2001 From: Yuchao Yan Date: Tue, 26 May 2026 03:27:47 +0000 Subject: [PATCH 34/36] new test cases --- .../eng/scripts/ci/regenerate-common.ts | 34 +- packages/typespec-python/tests/data/image.jpg | Bin 0 -> 4069 bytes .../test_azure_arm_commonproperties_async.py | 95 ++++ .../test_azure_arm_largeheader_async.py | 31 ++ .../test_azure_arm_nonresource_async.py | 37 ++ ...test_azure_arm_operationtemplates_async.py | 206 ++++++++ .../test_azure_arm_resource_async.py | 479 ++++++++++++++++++ ...zure_client_generator_core_access_async.py | 102 ++++ ...generator_core_api_version_header_async.py | 19 + ...t_generator_core_api_version_path_async.py | 19 + ..._generator_core_api_version_query_async.py | 19 + ...nerator_core_client_default_value_async.py | 47 ++ ...erator_core_client_initialization_async.py | 58 +++ ...nt_generator_core_client_location_async.py | 83 +++ ..._deserialize_empty_string_as_null_async.py | 21 + ...ure_client_generator_core_flatten_async.py | 116 +++++ ...enerator_core_hierrarchy_building_async.py | 54 ++ ...ent_generator_core_next_link_verb_async.py | 29 ++ ...re_client_generator_core_override_async.py | 107 ++++ ...azure_client_generator_core_usage_async.py | 39 ++ .../asynctests/test_azure_core_basic_async.py | 77 +++ .../test_azure_core_lro_rpc_async.py | 23 + .../test_azure_core_lro_standard_async.py | 40 ++ .../asynctests/test_azure_core_model_async.py | 34 ++ .../asynctests/test_azure_core_page_async.py | 81 +++ .../test_azure_core_scalar_async.py | 42 ++ .../test_azure_core_traits_async.py | 88 ++++ .../test_azure_encode_duration_async.py | 20 + .../test_azure_example_basic_async.py | 31 ++ .../test_azure_payload_pageable_async.py | 20 + ...ce_manager_method_subscription_id_async.py | 249 +++++++++ ...re_resource_manager_multi_service_async.py | 111 ++++ ...nager_multi_service_shared_models_async.py | 133 +++++ ...special_headers_client_request_id_async.py | 31 ++ ...t_azure_versioning_previewversion_async.py | 54 ++ .../asynctests/test_client_namespace_async.py | 35 ++ .../asynctests/test_client_naming_async.py | 70 +++ .../test_client_naming_enum_conflict_async.py | 38 ++ .../asynctests/test_client_overload_async.py | 27 + .../asynctests/test_client_structure_async.py | 62 +++ ...nt_structure_clientoperationgroup_async.py | 29 ++ .../asynctests/test_encode_duration_async.py | 64 +++ .../asynctests/test_encode_numeric_async.py | 36 ++ .../asynctests/test_parameters_basic_async.py | 25 + .../test_parameters_spread_async.py | 77 +++ .../test_payload_content_negotiation_async.py | 38 ++ .../test_payload_multipart_async.py | 217 ++++++++ .../test_resiliency_srv_driven_async.py | 130 +++++ ...t_serialization_encoded_name_json_async.py | 25 + .../test_service_multi_service_async.py | 31 ++ .../asynctests/test_special_words_async.py | 72 +++ .../tests/mock_api/azure/conftest.py | 179 +++++++ .../tests/mock_api/azure/data/image.jpg | Bin 0 -> 4069 bytes .../tests/mock_api/azure/data/image.png | Bin 0 -> 2992 bytes .../azure/test_azure_arm_commonproperties.py | 89 ++++ .../azure/test_azure_arm_largeheader.py | 27 + .../azure/test_azure_arm_nonresource.py | 34 ++ .../test_azure_arm_operationtemplates.py | 180 +++++++ .../mock_api/azure/test_azure_arm_resource.py | 436 ++++++++++++++++ ...test_azure_client_generator_core_access.py | 92 ++++ ...lient_generator_core_api_version_header.py | 17 + ..._client_generator_core_api_version_path.py | 17 + ...client_generator_core_api_version_query.py | 17 + ...ent_generator_core_client_default_value.py | 42 ++ ...nt_generator_core_client_initialization.py | 51 ++ ...e_client_generator_core_client_location.py | 70 +++ ...r_core_deserialize_empty_string_as_null.py | 19 + ...est_azure_client_generator_core_flatten.py | 104 ++++ ...ient_generator_core_hierrarchy_building.py | 45 ++ ...re_client_generator_core_next_link_verb.py | 27 + ...st_azure_client_generator_core_override.py | 102 ++++ .../test_azure_client_generator_core_usage.py | 32 ++ .../mock_api/azure/test_azure_core_basic.py | 70 +++ .../mock_api/azure/test_azure_core_lro_rpc.py | 20 + .../azure/test_azure_core_lro_standard.py | 32 ++ .../mock_api/azure/test_azure_core_model.py | 30 ++ .../mock_api/azure/test_azure_core_page.py | 71 +++ .../mock_api/azure/test_azure_core_scalar.py | 35 ++ .../mock_api/azure/test_azure_core_traits.py | 85 ++++ .../azure/test_azure_encode_duration.py | 18 + .../azure/test_azure_example_basic.py | 29 ++ .../azure/test_azure_payload_pageable.py | 18 + ...resource_manager_method_subscription_id.py | 235 +++++++++ ...st_azure_resource_manager_multi_service.py | 104 ++++ ...rce_manager_multi_service_shared_models.py | 128 +++++ ...azure_special_headers_client_request_id.py | 29 ++ .../test_azure_versioning_previewversion.py | 50 ++ .../azure/test_clear_output_folder.py | 22 + .../mock_api/azure/test_client_namespace.py | 32 ++ .../mock_api/azure/test_client_naming.py | 57 +++ .../azure/test_client_naming_enum_conflict.py | 35 ++ .../mock_api/azure/test_client_overload.py | 25 + .../mock_api/azure/test_client_structure.py | 57 +++ ...t_client_structure_clientoperationgroup.py | 26 + .../mock_api/azure/test_encode_duration.py | 60 +++ .../mock_api/azure/test_encode_numeric.py | 31 ++ .../test_model_base_flatten_compatibility.py | 251 +++++++++ .../mock_api/azure/test_parameters_basic.py | 22 + .../mock_api/azure/test_parameters_spread.py | 66 +++ .../azure/test_payload_content_negotiation.py | 33 ++ .../mock_api/azure/test_payload_multipart.py | 198 ++++++++ .../azure/test_resiliency_srv_driven.py | 124 +++++ .../test_serialization_encoded_name_json.py | 21 + .../azure/test_service_multi_service.py | 29 ++ .../mock_api/azure/test_special_words.py | 63 +++ .../asynctests/test_authentication_async.py | 141 ++++++ .../asynctests/test_encode_array_async.py | 140 +++++ .../asynctests/test_encode_bytes_async.py | 133 +++++ .../asynctests/test_encode_datetime_async.py | 128 +++++ ...ation_subdir2_for_customized_code_async.py | 37 ++ ...ration_subdir2_for_generated_code_async.py | 37 ++ ...ration_subdir_for_customized_code_async.py | 19 + ...eration_subdir_for_generated_code_async.py | 25 + .../asynctests/test_headasboolean_async.py | 36 ++ .../test_parameters_body_optionality_async.py | 31 ++ ...test_parameters_collection_format_async.py | 39 ++ .../asynctests/test_parameters_path_async.py | 25 + .../asynctests/test_parameters_query_async.py | 19 + .../test_payload_json_merge_patch_async.py | 99 ++++ .../test_payload_media_type_async.py | 28 + .../asynctests/test_payload_pageable_async.py | 135 +++++ .../asynctests/test_payload_xml_async.py | 261 ++++++++++ .../test_response_status_code_range_async.py | 39 ++ .../shared/asynctests/test_routes_async.py | 332 ++++++++++++ .../test_server_endpoint_not_defined_async.py | 19 + .../test_server_path_multiple_async.py | 26 + .../test_server_path_single_async.py | 19 + ...est_server_versions_not_versioned_async.py | 29 ++ .../test_server_versions_versioned_async.py | 35 ++ ...ecial_headers_conditional_request_async.py | 39 ++ ...est_special_headers_repeatability_async.py | 20 + .../test_specs_documentation_async.py | 60 +++ .../asynctests/test_streaming_jsonl_async.py | 28 + .../asynctests/test_typetest_array_async.py | 128 +++++ .../test_typetest_dictionary_async.py | 99 ++++ .../test_typetest_enum_extensible_async.py | 26 + .../test_typetest_enum_fixed_async.py | 28 + .../asynctests/test_typetest_file_async.py | 59 +++ .../test_typetest_model_empty_async.py | 33 ++ ...el_inheritance_enum_discriminator_async.py | 71 +++ ..._inheritance_nested_discriminator_async.py | 86 ++++ ...del_inheritance_not_discriminated_async.py | 35 ++ ...etest_model_inheritance_recursive_async.py | 35 ++ ..._inheritance_single_discriminator_async.py | 68 +++ .../test_typetest_model_usage_async.py | 33 ++ .../test_typetest_model_visibility_async.py | 48 ++ ...est_property_additionalproperties_async.py | 338 ++++++++++++ .../test_typetest_property_nullable_async.py | 111 ++++ .../test_typetest_property_optional_async.py | 198 ++++++++ ...test_typetest_property_valuetypes_async.py | 316 ++++++++++++ .../asynctests/test_typetest_scalar_async.py | 61 +++ .../asynctests/test_typetest_union_async.py | 91 ++++ .../asynctests/test_versioning_added_async.py | 37 ++ .../test_versioning_made_optional_async.py | 22 + .../test_versioning_removed_async.py | 40 ++ .../test_versioning_renamed_from_async.py | 30 ++ ...rsioning_return_type_changed_from_async.py | 19 + ...test_versioning_type_changed_from_async.py | 23 + .../tests/mock_api/shared/conftest.py | 43 ++ .../tests/mock_api/shared/data/image.jpg | Bin 0 -> 4069 bytes .../tests/mock_api/shared/data/image.png | Bin 0 -> 2992 bytes .../mock_api/shared/test_authentication.py | 130 +++++ .../mock_api/shared/test_encode_array.py | 126 +++++ .../mock_api/shared/test_encode_bytes.py | 128 +++++ .../mock_api/shared/test_encode_datetime.py | 123 +++++ ..._generation_subdir2_for_customized_code.py | 32 ++ ...t_generation_subdir2_for_generated_code.py | 33 ++ ...t_generation_subdir_for_customized_code.py | 16 + ...st_generation_subdir_for_generated_code.py | 17 + .../mock_api/shared/test_headasboolean.py | 33 ++ .../test_parameters_body_optionality.py | 27 + .../test_parameters_collection_format.py | 33 ++ .../mock_api/shared/test_parameters_path.py | 22 + .../mock_api/shared/test_parameters_query.py | 17 + .../tests/mock_api/shared/test_patch.py | 12 + .../shared/test_payload_json_merge_patch.py | 93 ++++ .../shared/test_payload_media_type.py | 25 + .../mock_api/shared/test_payload_pageable.py | 99 ++++ .../tests/mock_api/shared/test_payload_xml.py | 234 +++++++++ .../shared/test_response_status_code_range.py | 36 ++ .../tests/mock_api/shared/test_routes.py | 285 +++++++++++ .../test_server_endpoint_not_defined.py | 17 + .../shared/test_server_path_multiple.py | 21 + .../shared/test_server_path_single.py | 17 + .../test_server_versions_not_versioned.py | 25 + .../shared/test_server_versions_versioned.py | 30 ++ ...est_special_headers_conditional_request.py | 34 ++ .../test_special_headers_repeatability.py | 18 + .../shared/test_specs_documentation.py | 51 ++ .../mock_api/shared/test_streaming_jsonl.py | 25 + .../mock_api/shared/test_typetest_array.py | 111 ++++ .../shared/test_typetest_dictionary.py | 86 ++++ .../shared/test_typetest_enum_extensible.py | 23 + .../shared/test_typetest_enum_fixed.py | 25 + .../mock_api/shared/test_typetest_file.py | 52 ++ .../shared/test_typetest_model_empty.py | 29 ++ ...st_model_inheritance_enum_discriminator.py | 58 +++ ..._model_inheritance_nested_discriminator.py | 79 +++ ...est_model_inheritance_not_discriminated.py | 31 ++ ...st_typetest_model_inheritance_recursive.py | 32 ++ ..._model_inheritance_single_discriminator.py | 60 +++ .../shared/test_typetest_model_usage.py | 28 + .../shared/test_typetest_model_visibility.py | 40 ++ ..._typetest_property_additionalproperties.py | 299 +++++++++++ .../shared/test_typetest_property_nullable.py | 102 ++++ .../shared/test_typetest_property_optional.py | 174 +++++++ .../test_typetest_property_valuetypes.py | 286 +++++++++++ .../mock_api/shared/test_typetest_scalar.py | 53 ++ .../mock_api/shared/test_typetest_union.py | 80 +++ .../test_typetest_union_discriminated.py | 290 +++++++++++ .../mock_api/shared/test_versioning_added.py | 33 ++ .../shared/test_versioning_made_optional.py | 20 + .../shared/test_versioning_removed.py | 37 ++ .../shared/test_versioning_renamed_from.py | 27 + ...est_versioning_return_type_changed_from.py | 17 + .../test_versioning_type_changed_from.py | 21 + .../shared/unittests/test_parse_pyproject.py | 95 ++++ .../mock_api/shared/unittests/test_readme.py | 46 ++ .../asynctests/test_auth_flow_async.py | 19 + .../asynctests/test_encode_duration_async.py | 64 +++ .../asynctests/test_encode_numeric_async.py | 36 ++ .../asynctests/test_parameters_basic_async.py | 25 + .../test_parameters_spread_async.py | 77 +++ .../test_payload_content_negotiation_async.py | 38 ++ .../test_payload_multipart_async.py | 219 ++++++++ ...t_serialization_encoded_name_json_async.py | 25 + .../asynctests/test_special_words_async.py | 74 +++ .../asynctests/test_unbranded_async.py | 25 + .../tests/mock_api/unbranded/conftest.py | 63 +++ .../tests/mock_api/unbranded/data/image.jpg | Bin 0 -> 4069 bytes .../tests/mock_api/unbranded/data/image.png | Bin 0 -> 2992 bytes .../mock_api/unbranded/test_auth_flow.py | 17 + .../unbranded/test_encode_duration.py | 60 +++ .../mock_api/unbranded/test_encode_numeric.py | 32 ++ .../unbranded/test_parameters_basic.py | 22 + .../unbranded/test_parameters_spread.py | 66 +++ .../test_payload_content_negotiation.py | 33 ++ .../unbranded/test_payload_multipart.py | 200 ++++++++ .../test_serialization_encoded_name_json.py | 22 + .../mock_api/unbranded/test_special_words.py | 66 +++ 240 files changed, 16511 insertions(+), 13 deletions(-) create mode 100644 packages/typespec-python/tests/data/image.jpg create mode 100644 packages/typespec-python/tests/mock_api/azure/asynctests/test_azure_arm_commonproperties_async.py create mode 100644 packages/typespec-python/tests/mock_api/azure/asynctests/test_azure_arm_largeheader_async.py create mode 100644 packages/typespec-python/tests/mock_api/azure/asynctests/test_azure_arm_nonresource_async.py create mode 100644 packages/typespec-python/tests/mock_api/azure/asynctests/test_azure_arm_operationtemplates_async.py create mode 100644 packages/typespec-python/tests/mock_api/azure/asynctests/test_azure_arm_resource_async.py create mode 100644 packages/typespec-python/tests/mock_api/azure/asynctests/test_azure_client_generator_core_access_async.py create mode 100644 packages/typespec-python/tests/mock_api/azure/asynctests/test_azure_client_generator_core_api_version_header_async.py create mode 100644 packages/typespec-python/tests/mock_api/azure/asynctests/test_azure_client_generator_core_api_version_path_async.py create mode 100644 packages/typespec-python/tests/mock_api/azure/asynctests/test_azure_client_generator_core_api_version_query_async.py create mode 100644 packages/typespec-python/tests/mock_api/azure/asynctests/test_azure_client_generator_core_client_default_value_async.py create mode 100644 packages/typespec-python/tests/mock_api/azure/asynctests/test_azure_client_generator_core_client_initialization_async.py create mode 100644 packages/typespec-python/tests/mock_api/azure/asynctests/test_azure_client_generator_core_client_location_async.py create mode 100644 packages/typespec-python/tests/mock_api/azure/asynctests/test_azure_client_generator_core_deserialize_empty_string_as_null_async.py create mode 100644 packages/typespec-python/tests/mock_api/azure/asynctests/test_azure_client_generator_core_flatten_async.py create mode 100644 packages/typespec-python/tests/mock_api/azure/asynctests/test_azure_client_generator_core_hierrarchy_building_async.py create mode 100644 packages/typespec-python/tests/mock_api/azure/asynctests/test_azure_client_generator_core_next_link_verb_async.py create mode 100644 packages/typespec-python/tests/mock_api/azure/asynctests/test_azure_client_generator_core_override_async.py create mode 100644 packages/typespec-python/tests/mock_api/azure/asynctests/test_azure_client_generator_core_usage_async.py create mode 100644 packages/typespec-python/tests/mock_api/azure/asynctests/test_azure_core_basic_async.py create mode 100644 packages/typespec-python/tests/mock_api/azure/asynctests/test_azure_core_lro_rpc_async.py create mode 100644 packages/typespec-python/tests/mock_api/azure/asynctests/test_azure_core_lro_standard_async.py create mode 100644 packages/typespec-python/tests/mock_api/azure/asynctests/test_azure_core_model_async.py create mode 100644 packages/typespec-python/tests/mock_api/azure/asynctests/test_azure_core_page_async.py create mode 100644 packages/typespec-python/tests/mock_api/azure/asynctests/test_azure_core_scalar_async.py create mode 100644 packages/typespec-python/tests/mock_api/azure/asynctests/test_azure_core_traits_async.py create mode 100644 packages/typespec-python/tests/mock_api/azure/asynctests/test_azure_encode_duration_async.py create mode 100644 packages/typespec-python/tests/mock_api/azure/asynctests/test_azure_example_basic_async.py create mode 100644 packages/typespec-python/tests/mock_api/azure/asynctests/test_azure_payload_pageable_async.py create mode 100644 packages/typespec-python/tests/mock_api/azure/asynctests/test_azure_resource_manager_method_subscription_id_async.py create mode 100644 packages/typespec-python/tests/mock_api/azure/asynctests/test_azure_resource_manager_multi_service_async.py create mode 100644 packages/typespec-python/tests/mock_api/azure/asynctests/test_azure_resource_manager_multi_service_shared_models_async.py create mode 100644 packages/typespec-python/tests/mock_api/azure/asynctests/test_azure_special_headers_client_request_id_async.py create mode 100644 packages/typespec-python/tests/mock_api/azure/asynctests/test_azure_versioning_previewversion_async.py create mode 100644 packages/typespec-python/tests/mock_api/azure/asynctests/test_client_namespace_async.py create mode 100644 packages/typespec-python/tests/mock_api/azure/asynctests/test_client_naming_async.py create mode 100644 packages/typespec-python/tests/mock_api/azure/asynctests/test_client_naming_enum_conflict_async.py create mode 100644 packages/typespec-python/tests/mock_api/azure/asynctests/test_client_overload_async.py create mode 100644 packages/typespec-python/tests/mock_api/azure/asynctests/test_client_structure_async.py create mode 100644 packages/typespec-python/tests/mock_api/azure/asynctests/test_client_structure_clientoperationgroup_async.py create mode 100644 packages/typespec-python/tests/mock_api/azure/asynctests/test_encode_duration_async.py create mode 100644 packages/typespec-python/tests/mock_api/azure/asynctests/test_encode_numeric_async.py create mode 100644 packages/typespec-python/tests/mock_api/azure/asynctests/test_parameters_basic_async.py create mode 100644 packages/typespec-python/tests/mock_api/azure/asynctests/test_parameters_spread_async.py create mode 100644 packages/typespec-python/tests/mock_api/azure/asynctests/test_payload_content_negotiation_async.py create mode 100644 packages/typespec-python/tests/mock_api/azure/asynctests/test_payload_multipart_async.py create mode 100644 packages/typespec-python/tests/mock_api/azure/asynctests/test_resiliency_srv_driven_async.py create mode 100644 packages/typespec-python/tests/mock_api/azure/asynctests/test_serialization_encoded_name_json_async.py create mode 100644 packages/typespec-python/tests/mock_api/azure/asynctests/test_service_multi_service_async.py create mode 100644 packages/typespec-python/tests/mock_api/azure/asynctests/test_special_words_async.py create mode 100644 packages/typespec-python/tests/mock_api/azure/conftest.py create mode 100644 packages/typespec-python/tests/mock_api/azure/data/image.jpg create mode 100644 packages/typespec-python/tests/mock_api/azure/data/image.png create mode 100644 packages/typespec-python/tests/mock_api/azure/test_azure_arm_commonproperties.py create mode 100644 packages/typespec-python/tests/mock_api/azure/test_azure_arm_largeheader.py create mode 100644 packages/typespec-python/tests/mock_api/azure/test_azure_arm_nonresource.py create mode 100644 packages/typespec-python/tests/mock_api/azure/test_azure_arm_operationtemplates.py create mode 100644 packages/typespec-python/tests/mock_api/azure/test_azure_arm_resource.py create mode 100644 packages/typespec-python/tests/mock_api/azure/test_azure_client_generator_core_access.py create mode 100644 packages/typespec-python/tests/mock_api/azure/test_azure_client_generator_core_api_version_header.py create mode 100644 packages/typespec-python/tests/mock_api/azure/test_azure_client_generator_core_api_version_path.py create mode 100644 packages/typespec-python/tests/mock_api/azure/test_azure_client_generator_core_api_version_query.py create mode 100644 packages/typespec-python/tests/mock_api/azure/test_azure_client_generator_core_client_default_value.py create mode 100644 packages/typespec-python/tests/mock_api/azure/test_azure_client_generator_core_client_initialization.py create mode 100644 packages/typespec-python/tests/mock_api/azure/test_azure_client_generator_core_client_location.py create mode 100644 packages/typespec-python/tests/mock_api/azure/test_azure_client_generator_core_deserialize_empty_string_as_null.py create mode 100644 packages/typespec-python/tests/mock_api/azure/test_azure_client_generator_core_flatten.py create mode 100644 packages/typespec-python/tests/mock_api/azure/test_azure_client_generator_core_hierrarchy_building.py create mode 100644 packages/typespec-python/tests/mock_api/azure/test_azure_client_generator_core_next_link_verb.py create mode 100644 packages/typespec-python/tests/mock_api/azure/test_azure_client_generator_core_override.py create mode 100644 packages/typespec-python/tests/mock_api/azure/test_azure_client_generator_core_usage.py create mode 100644 packages/typespec-python/tests/mock_api/azure/test_azure_core_basic.py create mode 100644 packages/typespec-python/tests/mock_api/azure/test_azure_core_lro_rpc.py create mode 100644 packages/typespec-python/tests/mock_api/azure/test_azure_core_lro_standard.py create mode 100644 packages/typespec-python/tests/mock_api/azure/test_azure_core_model.py create mode 100644 packages/typespec-python/tests/mock_api/azure/test_azure_core_page.py create mode 100644 packages/typespec-python/tests/mock_api/azure/test_azure_core_scalar.py create mode 100644 packages/typespec-python/tests/mock_api/azure/test_azure_core_traits.py create mode 100644 packages/typespec-python/tests/mock_api/azure/test_azure_encode_duration.py create mode 100644 packages/typespec-python/tests/mock_api/azure/test_azure_example_basic.py create mode 100644 packages/typespec-python/tests/mock_api/azure/test_azure_payload_pageable.py create mode 100644 packages/typespec-python/tests/mock_api/azure/test_azure_resource_manager_method_subscription_id.py create mode 100644 packages/typespec-python/tests/mock_api/azure/test_azure_resource_manager_multi_service.py create mode 100644 packages/typespec-python/tests/mock_api/azure/test_azure_resource_manager_multi_service_shared_models.py create mode 100644 packages/typespec-python/tests/mock_api/azure/test_azure_special_headers_client_request_id.py create mode 100644 packages/typespec-python/tests/mock_api/azure/test_azure_versioning_previewversion.py create mode 100644 packages/typespec-python/tests/mock_api/azure/test_clear_output_folder.py create mode 100644 packages/typespec-python/tests/mock_api/azure/test_client_namespace.py create mode 100644 packages/typespec-python/tests/mock_api/azure/test_client_naming.py create mode 100644 packages/typespec-python/tests/mock_api/azure/test_client_naming_enum_conflict.py create mode 100644 packages/typespec-python/tests/mock_api/azure/test_client_overload.py create mode 100644 packages/typespec-python/tests/mock_api/azure/test_client_structure.py create mode 100644 packages/typespec-python/tests/mock_api/azure/test_client_structure_clientoperationgroup.py create mode 100644 packages/typespec-python/tests/mock_api/azure/test_encode_duration.py create mode 100644 packages/typespec-python/tests/mock_api/azure/test_encode_numeric.py create mode 100644 packages/typespec-python/tests/mock_api/azure/test_model_base_flatten_compatibility.py create mode 100644 packages/typespec-python/tests/mock_api/azure/test_parameters_basic.py create mode 100644 packages/typespec-python/tests/mock_api/azure/test_parameters_spread.py create mode 100644 packages/typespec-python/tests/mock_api/azure/test_payload_content_negotiation.py create mode 100644 packages/typespec-python/tests/mock_api/azure/test_payload_multipart.py create mode 100644 packages/typespec-python/tests/mock_api/azure/test_resiliency_srv_driven.py create mode 100644 packages/typespec-python/tests/mock_api/azure/test_serialization_encoded_name_json.py create mode 100644 packages/typespec-python/tests/mock_api/azure/test_service_multi_service.py create mode 100644 packages/typespec-python/tests/mock_api/azure/test_special_words.py create mode 100644 packages/typespec-python/tests/mock_api/shared/asynctests/test_authentication_async.py create mode 100644 packages/typespec-python/tests/mock_api/shared/asynctests/test_encode_array_async.py create mode 100644 packages/typespec-python/tests/mock_api/shared/asynctests/test_encode_bytes_async.py create mode 100644 packages/typespec-python/tests/mock_api/shared/asynctests/test_encode_datetime_async.py create mode 100644 packages/typespec-python/tests/mock_api/shared/asynctests/test_generation_subdir2_for_customized_code_async.py create mode 100644 packages/typespec-python/tests/mock_api/shared/asynctests/test_generation_subdir2_for_generated_code_async.py create mode 100644 packages/typespec-python/tests/mock_api/shared/asynctests/test_generation_subdir_for_customized_code_async.py create mode 100644 packages/typespec-python/tests/mock_api/shared/asynctests/test_generation_subdir_for_generated_code_async.py create mode 100644 packages/typespec-python/tests/mock_api/shared/asynctests/test_headasboolean_async.py create mode 100644 packages/typespec-python/tests/mock_api/shared/asynctests/test_parameters_body_optionality_async.py create mode 100644 packages/typespec-python/tests/mock_api/shared/asynctests/test_parameters_collection_format_async.py create mode 100644 packages/typespec-python/tests/mock_api/shared/asynctests/test_parameters_path_async.py create mode 100644 packages/typespec-python/tests/mock_api/shared/asynctests/test_parameters_query_async.py create mode 100644 packages/typespec-python/tests/mock_api/shared/asynctests/test_payload_json_merge_patch_async.py create mode 100644 packages/typespec-python/tests/mock_api/shared/asynctests/test_payload_media_type_async.py create mode 100644 packages/typespec-python/tests/mock_api/shared/asynctests/test_payload_pageable_async.py create mode 100644 packages/typespec-python/tests/mock_api/shared/asynctests/test_payload_xml_async.py create mode 100644 packages/typespec-python/tests/mock_api/shared/asynctests/test_response_status_code_range_async.py create mode 100644 packages/typespec-python/tests/mock_api/shared/asynctests/test_routes_async.py create mode 100644 packages/typespec-python/tests/mock_api/shared/asynctests/test_server_endpoint_not_defined_async.py create mode 100644 packages/typespec-python/tests/mock_api/shared/asynctests/test_server_path_multiple_async.py create mode 100644 packages/typespec-python/tests/mock_api/shared/asynctests/test_server_path_single_async.py create mode 100644 packages/typespec-python/tests/mock_api/shared/asynctests/test_server_versions_not_versioned_async.py create mode 100644 packages/typespec-python/tests/mock_api/shared/asynctests/test_server_versions_versioned_async.py create mode 100644 packages/typespec-python/tests/mock_api/shared/asynctests/test_special_headers_conditional_request_async.py create mode 100644 packages/typespec-python/tests/mock_api/shared/asynctests/test_special_headers_repeatability_async.py create mode 100644 packages/typespec-python/tests/mock_api/shared/asynctests/test_specs_documentation_async.py create mode 100644 packages/typespec-python/tests/mock_api/shared/asynctests/test_streaming_jsonl_async.py create mode 100644 packages/typespec-python/tests/mock_api/shared/asynctests/test_typetest_array_async.py create mode 100644 packages/typespec-python/tests/mock_api/shared/asynctests/test_typetest_dictionary_async.py create mode 100644 packages/typespec-python/tests/mock_api/shared/asynctests/test_typetest_enum_extensible_async.py create mode 100644 packages/typespec-python/tests/mock_api/shared/asynctests/test_typetest_enum_fixed_async.py create mode 100644 packages/typespec-python/tests/mock_api/shared/asynctests/test_typetest_file_async.py create mode 100644 packages/typespec-python/tests/mock_api/shared/asynctests/test_typetest_model_empty_async.py create mode 100644 packages/typespec-python/tests/mock_api/shared/asynctests/test_typetest_model_inheritance_enum_discriminator_async.py create mode 100644 packages/typespec-python/tests/mock_api/shared/asynctests/test_typetest_model_inheritance_nested_discriminator_async.py create mode 100644 packages/typespec-python/tests/mock_api/shared/asynctests/test_typetest_model_inheritance_not_discriminated_async.py create mode 100644 packages/typespec-python/tests/mock_api/shared/asynctests/test_typetest_model_inheritance_recursive_async.py create mode 100644 packages/typespec-python/tests/mock_api/shared/asynctests/test_typetest_model_inheritance_single_discriminator_async.py create mode 100644 packages/typespec-python/tests/mock_api/shared/asynctests/test_typetest_model_usage_async.py create mode 100644 packages/typespec-python/tests/mock_api/shared/asynctests/test_typetest_model_visibility_async.py create mode 100644 packages/typespec-python/tests/mock_api/shared/asynctests/test_typetest_property_additionalproperties_async.py create mode 100644 packages/typespec-python/tests/mock_api/shared/asynctests/test_typetest_property_nullable_async.py create mode 100644 packages/typespec-python/tests/mock_api/shared/asynctests/test_typetest_property_optional_async.py create mode 100644 packages/typespec-python/tests/mock_api/shared/asynctests/test_typetest_property_valuetypes_async.py create mode 100644 packages/typespec-python/tests/mock_api/shared/asynctests/test_typetest_scalar_async.py create mode 100644 packages/typespec-python/tests/mock_api/shared/asynctests/test_typetest_union_async.py create mode 100644 packages/typespec-python/tests/mock_api/shared/asynctests/test_versioning_added_async.py create mode 100644 packages/typespec-python/tests/mock_api/shared/asynctests/test_versioning_made_optional_async.py create mode 100644 packages/typespec-python/tests/mock_api/shared/asynctests/test_versioning_removed_async.py create mode 100644 packages/typespec-python/tests/mock_api/shared/asynctests/test_versioning_renamed_from_async.py create mode 100644 packages/typespec-python/tests/mock_api/shared/asynctests/test_versioning_return_type_changed_from_async.py create mode 100644 packages/typespec-python/tests/mock_api/shared/asynctests/test_versioning_type_changed_from_async.py create mode 100644 packages/typespec-python/tests/mock_api/shared/conftest.py create mode 100644 packages/typespec-python/tests/mock_api/shared/data/image.jpg create mode 100644 packages/typespec-python/tests/mock_api/shared/data/image.png create mode 100644 packages/typespec-python/tests/mock_api/shared/test_authentication.py create mode 100644 packages/typespec-python/tests/mock_api/shared/test_encode_array.py create mode 100644 packages/typespec-python/tests/mock_api/shared/test_encode_bytes.py create mode 100644 packages/typespec-python/tests/mock_api/shared/test_encode_datetime.py create mode 100644 packages/typespec-python/tests/mock_api/shared/test_generation_subdir2_for_customized_code.py create mode 100644 packages/typespec-python/tests/mock_api/shared/test_generation_subdir2_for_generated_code.py create mode 100644 packages/typespec-python/tests/mock_api/shared/test_generation_subdir_for_customized_code.py create mode 100644 packages/typespec-python/tests/mock_api/shared/test_generation_subdir_for_generated_code.py create mode 100644 packages/typespec-python/tests/mock_api/shared/test_headasboolean.py create mode 100644 packages/typespec-python/tests/mock_api/shared/test_parameters_body_optionality.py create mode 100644 packages/typespec-python/tests/mock_api/shared/test_parameters_collection_format.py create mode 100644 packages/typespec-python/tests/mock_api/shared/test_parameters_path.py create mode 100644 packages/typespec-python/tests/mock_api/shared/test_parameters_query.py create mode 100644 packages/typespec-python/tests/mock_api/shared/test_patch.py create mode 100644 packages/typespec-python/tests/mock_api/shared/test_payload_json_merge_patch.py create mode 100644 packages/typespec-python/tests/mock_api/shared/test_payload_media_type.py create mode 100644 packages/typespec-python/tests/mock_api/shared/test_payload_pageable.py create mode 100644 packages/typespec-python/tests/mock_api/shared/test_payload_xml.py create mode 100644 packages/typespec-python/tests/mock_api/shared/test_response_status_code_range.py create mode 100644 packages/typespec-python/tests/mock_api/shared/test_routes.py create mode 100644 packages/typespec-python/tests/mock_api/shared/test_server_endpoint_not_defined.py create mode 100644 packages/typespec-python/tests/mock_api/shared/test_server_path_multiple.py create mode 100644 packages/typespec-python/tests/mock_api/shared/test_server_path_single.py create mode 100644 packages/typespec-python/tests/mock_api/shared/test_server_versions_not_versioned.py create mode 100644 packages/typespec-python/tests/mock_api/shared/test_server_versions_versioned.py create mode 100644 packages/typespec-python/tests/mock_api/shared/test_special_headers_conditional_request.py create mode 100644 packages/typespec-python/tests/mock_api/shared/test_special_headers_repeatability.py create mode 100644 packages/typespec-python/tests/mock_api/shared/test_specs_documentation.py create mode 100644 packages/typespec-python/tests/mock_api/shared/test_streaming_jsonl.py create mode 100644 packages/typespec-python/tests/mock_api/shared/test_typetest_array.py create mode 100644 packages/typespec-python/tests/mock_api/shared/test_typetest_dictionary.py create mode 100644 packages/typespec-python/tests/mock_api/shared/test_typetest_enum_extensible.py create mode 100644 packages/typespec-python/tests/mock_api/shared/test_typetest_enum_fixed.py create mode 100644 packages/typespec-python/tests/mock_api/shared/test_typetest_file.py create mode 100644 packages/typespec-python/tests/mock_api/shared/test_typetest_model_empty.py create mode 100644 packages/typespec-python/tests/mock_api/shared/test_typetest_model_inheritance_enum_discriminator.py create mode 100644 packages/typespec-python/tests/mock_api/shared/test_typetest_model_inheritance_nested_discriminator.py create mode 100644 packages/typespec-python/tests/mock_api/shared/test_typetest_model_inheritance_not_discriminated.py create mode 100644 packages/typespec-python/tests/mock_api/shared/test_typetest_model_inheritance_recursive.py create mode 100644 packages/typespec-python/tests/mock_api/shared/test_typetest_model_inheritance_single_discriminator.py create mode 100644 packages/typespec-python/tests/mock_api/shared/test_typetest_model_usage.py create mode 100644 packages/typespec-python/tests/mock_api/shared/test_typetest_model_visibility.py create mode 100644 packages/typespec-python/tests/mock_api/shared/test_typetest_property_additionalproperties.py create mode 100644 packages/typespec-python/tests/mock_api/shared/test_typetest_property_nullable.py create mode 100644 packages/typespec-python/tests/mock_api/shared/test_typetest_property_optional.py create mode 100644 packages/typespec-python/tests/mock_api/shared/test_typetest_property_valuetypes.py create mode 100644 packages/typespec-python/tests/mock_api/shared/test_typetest_scalar.py create mode 100644 packages/typespec-python/tests/mock_api/shared/test_typetest_union.py create mode 100644 packages/typespec-python/tests/mock_api/shared/test_typetest_union_discriminated.py create mode 100644 packages/typespec-python/tests/mock_api/shared/test_versioning_added.py create mode 100644 packages/typespec-python/tests/mock_api/shared/test_versioning_made_optional.py create mode 100644 packages/typespec-python/tests/mock_api/shared/test_versioning_removed.py create mode 100644 packages/typespec-python/tests/mock_api/shared/test_versioning_renamed_from.py create mode 100644 packages/typespec-python/tests/mock_api/shared/test_versioning_return_type_changed_from.py create mode 100644 packages/typespec-python/tests/mock_api/shared/test_versioning_type_changed_from.py create mode 100644 packages/typespec-python/tests/mock_api/shared/unittests/test_parse_pyproject.py create mode 100644 packages/typespec-python/tests/mock_api/shared/unittests/test_readme.py create mode 100644 packages/typespec-python/tests/mock_api/unbranded/asynctests/test_auth_flow_async.py create mode 100644 packages/typespec-python/tests/mock_api/unbranded/asynctests/test_encode_duration_async.py create mode 100644 packages/typespec-python/tests/mock_api/unbranded/asynctests/test_encode_numeric_async.py create mode 100644 packages/typespec-python/tests/mock_api/unbranded/asynctests/test_parameters_basic_async.py create mode 100644 packages/typespec-python/tests/mock_api/unbranded/asynctests/test_parameters_spread_async.py create mode 100644 packages/typespec-python/tests/mock_api/unbranded/asynctests/test_payload_content_negotiation_async.py create mode 100644 packages/typespec-python/tests/mock_api/unbranded/asynctests/test_payload_multipart_async.py create mode 100644 packages/typespec-python/tests/mock_api/unbranded/asynctests/test_serialization_encoded_name_json_async.py create mode 100644 packages/typespec-python/tests/mock_api/unbranded/asynctests/test_special_words_async.py create mode 100644 packages/typespec-python/tests/mock_api/unbranded/asynctests/test_unbranded_async.py create mode 100644 packages/typespec-python/tests/mock_api/unbranded/conftest.py create mode 100644 packages/typespec-python/tests/mock_api/unbranded/data/image.jpg create mode 100644 packages/typespec-python/tests/mock_api/unbranded/data/image.png create mode 100644 packages/typespec-python/tests/mock_api/unbranded/test_auth_flow.py create mode 100644 packages/typespec-python/tests/mock_api/unbranded/test_encode_duration.py create mode 100644 packages/typespec-python/tests/mock_api/unbranded/test_encode_numeric.py create mode 100644 packages/typespec-python/tests/mock_api/unbranded/test_parameters_basic.py create mode 100644 packages/typespec-python/tests/mock_api/unbranded/test_parameters_spread.py create mode 100644 packages/typespec-python/tests/mock_api/unbranded/test_payload_content_negotiation.py create mode 100644 packages/typespec-python/tests/mock_api/unbranded/test_payload_multipart.py create mode 100644 packages/typespec-python/tests/mock_api/unbranded/test_serialization_encoded_name_json.py create mode 100644 packages/typespec-python/tests/mock_api/unbranded/test_special_words.py diff --git a/packages/typespec-python/eng/scripts/ci/regenerate-common.ts b/packages/typespec-python/eng/scripts/ci/regenerate-common.ts index f21c401361..5e6b2b9ed8 100644 --- a/packages/typespec-python/eng/scripts/ci/regenerate-common.ts +++ b/packages/typespec-python/eng/scripts/ci/regenerate-common.ts @@ -677,7 +677,7 @@ export async function preprocess(flavor: string, generatedFolder: string): Promi /** * Resets the `tests/generated/{azure,unbranded}` baseline by sparse-checking-out - * `eng/tools/emitter/gen` from the Azure/azure-sdk-for-python repo, then + * `eng/tools/azure-sdk-tools/emitter/generated` from the Azure/azure-sdk-for-python repo, then * deleting a couple of fully-generated package folders so regeneration has to * recreate them from scratch (smoke test of full-emit path). * @@ -686,8 +686,8 @@ export async function preprocess(flavor: string, generatedFolder: string): Promi */ export async function prepareBaselineOfGeneratedCode(generatedFolder: string): Promise { const repoUrl = "https://github.com/Azure/azure-sdk-for-python.git"; - const branch = "main"; - const sourceSubdir = "eng/tools/emitter/gen"; + const branch = "typespec-python-generated-tests"; + const sourceSubdir = "eng/tools/azure-sdk-tools/emitter/generated"; const testsGeneratedDir = resolve(generatedFolder, "../tests/generated"); console.log(pc.cyan(`\n${"=".repeat(60)}`)); @@ -708,6 +708,7 @@ export async function prepareBaselineOfGeneratedCode(generatedFolder: string): P execSync(cmd, { cwd: tempDir, stdio: ["ignore", "ignore", "inherit"] }); run(`git init`); + run(`git config core.longpaths true`); run(`git remote add origin ${repoUrl}`); run(`git config core.sparseCheckout true`); run(`git sparse-checkout init --cone`); @@ -732,16 +733,23 @@ export async function prepareBaselineOfGeneratedCode(generatedFolder: string): P rmSync(tempDir, { recursive: true, force: true }); } - // Delete a couple of fully-generated package folders so regeneration has to - // recreate them from scratch (smoke test of full-emit path). - const targetsToDelete = [ - join(testsGeneratedDir, "azure", "authentication-http-custom"), - join(testsGeneratedDir, "unbranded", "encode-array"), - ]; - for (const target of targetsToDelete) { - if (existsSync(target)) { - console.log(pc.dim(`Deleting ${target}`)); - rmSync(target, { recursive: true, force: true }); + // Smoke test the full-emit path: delete a couple of fully-generated package + // folders and every README.md so regeneration has to recreate them. + const deleteIfExists = (path: string) => { + if (!existsSync(path)) return; + console.log(pc.dim(`Deleting ${path}`)); + rmSync(path, { recursive: true, force: true }); + }; + + deleteIfExists(join(testsGeneratedDir, "azure", "authentication-http-custom")); + deleteIfExists(join(testsGeneratedDir, "unbranded", "encode-array")); + + if (existsSync(testsGeneratedDir)) { + const entries = await readdir(testsGeneratedDir, { recursive: true, withFileTypes: true }); + for (const entry of entries) { + if (entry.isFile() && entry.name === "README.md") { + deleteIfExists(join(entry.parentPath, entry.name)); + } } } } diff --git a/packages/typespec-python/tests/data/image.jpg b/packages/typespec-python/tests/data/image.jpg new file mode 100644 index 0000000000000000000000000000000000000000..b95b3e7b58286ad3e665d98d48b345977f862403 GIT binary patch literal 4069 zcmeHJX;@QN8a_8Gn*#{~QJ4uNv1G6$BrHN6AVrn}mbL^3a4V7!OhA&51QRm!5kx@+ zTNcGZ6cC$Q+;~`GASla}wUxz{#c@GKXr)k4Y@<*!Hx%*D{OB`(hxgoj&v(xGzVDv* zyZ1cLYZx{>23FxAVIcs504RVPFpPlD9#xbBu1V2)YXM|gXB#0R#?0;vho@Ai`n{4K2Z_tc-vVNE8}_H8C|ahaEIl00AM92ow^HM!{MR`W#*d zC>$E^#0bDxN5*4GscV^8g=bC3n`_%`I5%f0?p)~sQ!`sT!n*Yv-gBn@)y2cpYm>JR zD=;WH4t_4#kAFVxjHXs&7-n{@yDwxhGFyQlZNTet7ry*D&GGCKBT{NGO}CV%+x+1&FN z^Dlq-RsZU>kryl_f2RdM|0^#X%nN}+AyHT(F9@M9633y?P7Dk_AQBs&YE5EhnXKJh zc(%6PlpPs~<`z2kKs1OmhoPzVGH-Zu)3MZ>_F zVvR60H(i4HGS)1?$_V@l3~&{b9rK09ND}!zi#oLh#Ro!~r%~ ztf@M>v0>6|AHFNXRdW{F2PwyE*zd{a+%36uhi4yu9aJ^ zpE7`9t8Rioz2KlN=S`ybbp-7ElQg->VN&I!l@n$S;9H_)yZXl$&PTX9ZObWvjhcE$f>gQt?~wSk)wt*@QfJ9e zFelD#>m0AB_sUj(c%Hr(E_yV;phB&=i9g9-)lO~OzQ2==_`u&bT{~<52lxK#Ow_NO zH{&-1-x&aQ;LQ0M(Zy$<1nTsq)xvVR{*&=ztX;IOz6|@z-F$Uf=(W0nyex6{P>FpW z4;0_dipualIew@$bH3M?aaJh~zSVba_s(ZYwY`7uX0rQ=C{sn1g*}wrL&Zt0cwal& z|(+)A&#XhLRoSPH3mt4Ji?-$~1F~yma)AnXu zRaaV$2SjEq$b{PVCY+v+iL;w8BOWVxgqdDst2gCLzog0=vM#q5L^ScNF_ipEjeb6n z1J0h4Y=S>iPa2P#Wgqq@^xWzm>-n^78z*$sXAucKo}EO|0uu3 zLs)^AUypvJF<+QUj|p5L&+NFzk0eJN%fi)?Gy8fd4jBz;gBAkjn_MPYks`G3a33&nP_o zg=l|nT>VF<@}|PZtIypU-TXbb#NA#UwTKA877jAo-sRoA;|O7M!oq~_ndaKA)cm{QH_jPuzCA+J zs!aHNWSYHBYfaj3>w14Gdb?$=t7cDh+;r%rP@Vlr;qGatS1nE0#?Fk+V2@G6gWq0G nRDbTJ{wDPH&YhvRw~$ZQH=nuD@w!Nwq+ZJbRY$2v!^nRCgjEVM literal 0 HcmV?d00001 diff --git a/packages/typespec-python/tests/mock_api/azure/asynctests/test_azure_arm_commonproperties_async.py b/packages/typespec-python/tests/mock_api/azure/asynctests/test_azure_arm_commonproperties_async.py new file mode 100644 index 0000000000..15b8038fef --- /dev/null +++ b/packages/typespec-python/tests/mock_api/azure/asynctests/test_azure_arm_commonproperties_async.py @@ -0,0 +1,95 @@ +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- +import pytest +import pytest_asyncio +from azure.resourcemanager.commonproperties.aio import CommonPropertiesClient +from azure.resourcemanager.commonproperties import models +from azure.core import exceptions + +SUBSCRIPTION_ID = "00000000-0000-0000-0000-000000000000" +RESOURCE_GROUP_NAME = "test-rg" + + +@pytest_asyncio.fixture +async def client(credential, authentication_policy): + async with CommonPropertiesClient( + credential, SUBSCRIPTION_ID, "http://localhost:3000", authentication_policy=authentication_policy + ) as client: + yield client + + +@pytest.mark.asyncio +async def test_managed_identity_get(client): + result = await client.managed_identity.get( + resource_group_name=RESOURCE_GROUP_NAME, managed_identity_tracked_resource_name="identity" + ) + assert result.location == "eastus" + assert result.identity.type == "SystemAssigned" + assert result.properties.provisioning_state == "Succeeded" + + +@pytest.mark.asyncio +async def test_managed_identity_create_with_system_assigned(client): + result = await client.managed_identity.create_with_system_assigned( + resource_group_name=RESOURCE_GROUP_NAME, + managed_identity_tracked_resource_name="identity", + resource=models.ManagedIdentityTrackedResource( + location="eastus", identity=models.ManagedServiceIdentity(type="SystemAssigned") + ), + ) + assert result.location == "eastus" + assert result.identity.type == "SystemAssigned" + assert result.properties.provisioning_state == "Succeeded" + + +@pytest.mark.asyncio +async def test_managed_identity_update_with_user_assigned_and_system_assigned(client): + result = await client.managed_identity.update_with_user_assigned_and_system_assigned( + resource_group_name=RESOURCE_GROUP_NAME, + managed_identity_tracked_resource_name="identity", + properties=models.ManagedIdentityTrackedResource( + location="eastus", + identity=models.ManagedServiceIdentity( + type="SystemAssigned,UserAssigned", + user_assigned_identities={ + "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/test-rg/providers/Microsoft.ManagedIdentity/userAssignedIdentities/id1": models.UserAssignedIdentity() + }, + ), + ), + ) + assert result.location == "eastus" + assert result.identity.type == "SystemAssigned,UserAssigned" + assert result.properties.provisioning_state == "Succeeded" + + +@pytest.mark.asyncio +async def test_error_get_for_predefined_error(client): + try: + await client.error.get_for_predefined_error( + resource_group_name=RESOURCE_GROUP_NAME, + confidential_resource_name="confidential", + ) + except exceptions.ResourceNotFoundError as e: + assert e.status_code == 404 + assert ( + e.error.message + == "The Resource 'Azure.ResourceManager.CommonProperties/confidentialResources/confidential' under resource group 'test-rg' was not found." + ) + + +@pytest.mark.asyncio +async def test_error_create_for_user_defined_error(client): + try: + await client.error.create_for_user_defined_error( + resource_group_name=RESOURCE_GROUP_NAME, + confidential_resource_name="confidential", + resource=models.ConfidentialResource( + location="eastus", properties=models.ConfidentialResourceProperties(username="00") + ), + ) + except exceptions.HttpResponseError as e: + assert e.status_code == 400 + assert e.error.message == "Username should not contain only numbers." diff --git a/packages/typespec-python/tests/mock_api/azure/asynctests/test_azure_arm_largeheader_async.py b/packages/typespec-python/tests/mock_api/azure/asynctests/test_azure_arm_largeheader_async.py new file mode 100644 index 0000000000..e696553a2f --- /dev/null +++ b/packages/typespec-python/tests/mock_api/azure/asynctests/test_azure_arm_largeheader_async.py @@ -0,0 +1,31 @@ +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- +import pytest +import pytest_asyncio +from azure.resourcemanager.largeheader.aio import LargeHeaderClient +from azure.resourcemanager.largeheader import models + +SUBSCRIPTION_ID = "00000000-0000-0000-0000-000000000000" +RESOURCE_GROUP_NAME = "test-rg" + + +@pytest_asyncio.fixture +async def client(credential, authentication_policy): + async with LargeHeaderClient( + credential, SUBSCRIPTION_ID, "http://localhost:3000", authentication_policy=authentication_policy + ) as client: + yield client + + +@pytest.mark.asyncio +async def test_large_headers_begin_two6_k(client: LargeHeaderClient): + result = await ( + await client.large_headers.begin_two6_k( + resource_group_name=RESOURCE_GROUP_NAME, + large_header_name="header1", + ) + ).result() + assert result == models.CancelResult(succeeded=True) diff --git a/packages/typespec-python/tests/mock_api/azure/asynctests/test_azure_arm_nonresource_async.py b/packages/typespec-python/tests/mock_api/azure/asynctests/test_azure_arm_nonresource_async.py new file mode 100644 index 0000000000..926dcb129a --- /dev/null +++ b/packages/typespec-python/tests/mock_api/azure/asynctests/test_azure_arm_nonresource_async.py @@ -0,0 +1,37 @@ +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- +import pytest +import pytest_asyncio +from azure.resourcemanager.nonresource.aio import NonResourceClient +from azure.resourcemanager.nonresource import models + +SUBSCRIPTION_ID = "00000000-0000-0000-0000-000000000000" +RESOURCE_GROUP_NAME = "test-rg" + + +@pytest_asyncio.fixture +async def client(credential, authentication_policy): + async with NonResourceClient( + credential, SUBSCRIPTION_ID, "http://localhost:3000", authentication_policy=authentication_policy + ) as client: + yield client + + +@pytest.mark.asyncio +async def test_non_resource_create(client: NonResourceClient): + result = await client.non_resource_operations.create( + location="eastus", parameter="hello", body=models.NonResource(id="id", name="hello", type="nonResource") + ) + assert result == models.NonResource(id="id", name="hello", type="nonResource") + + +@pytest.mark.asyncio +async def test_non_resource_get(client: NonResourceClient): + result = await client.non_resource_operations.get( + location="eastus", + parameter="hello", + ) + assert result == models.NonResource(id="id", name="hello", type="nonResource") diff --git a/packages/typespec-python/tests/mock_api/azure/asynctests/test_azure_arm_operationtemplates_async.py b/packages/typespec-python/tests/mock_api/azure/asynctests/test_azure_arm_operationtemplates_async.py new file mode 100644 index 0000000000..d28064a1bc --- /dev/null +++ b/packages/typespec-python/tests/mock_api/azure/asynctests/test_azure_arm_operationtemplates_async.py @@ -0,0 +1,206 @@ +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- +import pytest +import pytest_asyncio +from azure.resourcemanager.operationtemplates.aio import OperationTemplatesClient +from azure.resourcemanager.operationtemplates import models + +SUBSCRIPTION_ID = "00000000-0000-0000-0000-000000000000" +RESOURCE_GROUP_NAME = "test-rg" + + +@pytest_asyncio.fixture +async def client(credential, authentication_policy): + async with OperationTemplatesClient( + credential, + SUBSCRIPTION_ID, + "http://localhost:3000", + authentication_policy=authentication_policy, + polling_interval=0, + ) as client: + yield client + + +@pytest.mark.asyncio +async def test_check_name_availability_check_global(client): + result = await client.check_name_availability.check_global( + body=models.CheckNameAvailabilityRequest(name="checkName", type="Microsoft.Web/site") + ) + assert result.name_available == False + assert result.reason == models.CheckNameAvailabilityReason.ALREADY_EXISTS + assert result.message == "Hostname 'checkName' already exists. Please select a different name." + + +@pytest.mark.asyncio +async def test_check_name_availability_check_local(client): + result = await client.check_name_availability.check_local( + location="westus", + body=models.CheckNameAvailabilityRequest(name="checkName", type="Microsoft.Web/site"), + ) + assert result.name_available == False + assert result.reason == models.CheckNameAvailabilityReason.ALREADY_EXISTS + assert result.message == "Hostname 'checkName' already exists. Please select a different name." + + +@pytest.mark.asyncio +async def test_operations_list(client): + result = client.operations.list() + async for operation in result: + assert operation.name == "Microsoft.Compute/virtualMachines/write" + assert operation.display.operation == "Create or Update Virtual Machine." + assert operation.origin == "user,system" + assert operation.action_type == "Internal" + + +@pytest.mark.asyncio +async def test_lro_begin_create_or_replace(client): + result = await ( + await client.lro.begin_create_or_replace( + resource_group_name=RESOURCE_GROUP_NAME, + order_name="order1", + resource=models.Order( + location="eastus", + properties=models.OrderProperties(product_id="product1", amount=1), + ), + ) + ).result() + assert result.name == "order1" + assert ( + result.id + == "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/test-rg/providers/Azure.ResourceManager.OperationTemplates/orders/order1" + ) + assert result.type == "Azure.ResourceManager.Resources/orders" + assert result.location == "eastus" + assert result.system_data.created_by == "AzureSDK" + + +@pytest.mark.asyncio +async def test_lro_begin_export(client): + await ( + await client.lro.begin_export( + resource_group_name=RESOURCE_GROUP_NAME, + order_name="order1", + body=models.ExportRequest(format="csv"), + ) + ).result() + + +@pytest.mark.asyncio +async def test_lro_begin_delete(client): + await ( + await client.lro.begin_delete( + resource_group_name=RESOURCE_GROUP_NAME, + order_name="order1", + ) + ).result() + + +@pytest.mark.asyncio +async def test_optional_body_get(client): + result = await client.optional_body.get( + resource_group_name=RESOURCE_GROUP_NAME, + widget_name="widget1", + ) + assert result.name == "widget1" + assert ( + result.id + == "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/test-rg/providers/Azure.ResourceManager.OperationTemplates/widgets/widget1" + ) + assert result.type == "Azure.ResourceManager.OperationTemplates/widgets" + assert result.location == "eastus" + assert result.properties.name == "widget1" + assert result.properties.description == "A test widget" + assert result.properties.provisioning_state == "Succeeded" + + +@pytest.mark.asyncio +async def test_optional_body_patch_without_body(client): + result = await client.optional_body.patch( + resource_group_name=RESOURCE_GROUP_NAME, + widget_name="widget1", + ) + assert result.name == "widget1" + assert result.properties.name == "widget1" + assert result.properties.description == "A test widget" + + +@pytest.mark.asyncio +async def test_optional_body_patch_with_body(client): + result = await client.optional_body.patch( + resource_group_name=RESOURCE_GROUP_NAME, + widget_name="widget1", + properties=models.Widget( + location="eastus", + properties=models.WidgetProperties(name="updated-widget", description="Updated description"), + ), + ) + assert result.name == "widget1" + assert result.properties.name == "updated-widget" + assert result.properties.description == "Updated description" + + +@pytest.mark.asyncio +async def test_optional_body_post_without_body(client): + result = await client.optional_body.post( + resource_group_name=RESOURCE_GROUP_NAME, + widget_name="widget1", + ) + assert result.result == "Action completed successfully" + + +@pytest.mark.asyncio +async def test_optional_body_post_with_body(client): + result = await client.optional_body.post( + resource_group_name=RESOURCE_GROUP_NAME, + widget_name="widget1", + body=models.ActionRequest(action_type="perform", parameters="test-parameters"), + ) + assert result.result == "Action completed successfully with parameters" + + +@pytest.mark.asyncio +async def test_optional_body_provider_post_without_body(client): + result = await client.optional_body.provider_post() + assert result.total_allowed == 50 + assert result.status == "Changed to default allowance" + + +@pytest.mark.asyncio +async def test_optional_body_provider_post_with_body(client): + result = await client.optional_body.provider_post( + body=models.ChangeAllowanceRequest(total_allowed=100, reason="Increased demand"), + ) + assert result.total_allowed == 100 + assert result.status == "Changed to requested allowance" + + +@pytest.mark.asyncio +async def test_lro_begin_export_array(client): + result = await ( + await client.lro.begin_export_array( + body=models.ExportRequest(format="csv"), + ) + ).result() + assert len(result) == 2 + assert result[0].content == "order1,product1,1" + assert result[1].content == "order2,product2,2" + + +@pytest.mark.asyncio +async def test_lro_paging_begin_post_paging_lro(client): + poller = await client.lro_paging.begin_post_paging_lro( + resource_group_name=RESOURCE_GROUP_NAME, + product_name="default", + ) + result = await poller.result() + items = [item async for item in result] + assert len(items) == 2 + assert items[0].name == "product1" + assert items[0].properties.product_id == "product1" + assert items[0].properties.provisioning_state == "Succeeded" + assert items[1].name == "product2" + assert items[1].properties.product_id == "product2" + assert items[1].properties.provisioning_state == "Succeeded" diff --git a/packages/typespec-python/tests/mock_api/azure/asynctests/test_azure_arm_resource_async.py b/packages/typespec-python/tests/mock_api/azure/asynctests/test_azure_arm_resource_async.py new file mode 100644 index 0000000000..eb20ed43ee --- /dev/null +++ b/packages/typespec-python/tests/mock_api/azure/asynctests/test_azure_arm_resource_async.py @@ -0,0 +1,479 @@ +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- +import pytest +import pytest_asyncio +from azure.resourcemanager.resources.aio import ResourcesClient +from azure.resourcemanager.resources import models + +SUBSCRIPTION_ID = "00000000-0000-0000-0000-000000000000" +RESOURCE_GROUP_NAME = "test-rg" + + +@pytest_asyncio.fixture +async def client(credential, authentication_policy): + async with ResourcesClient( + credential, + SUBSCRIPTION_ID, + "http://localhost:3000", + authentication_policy=authentication_policy, + ) as client: + yield client + + +@pytest.mark.asyncio +async def test_client_signature(credential, authentication_policy): + # make sure signautre order is correct + client1 = ResourcesClient( + credential, + SUBSCRIPTION_ID, + "http://localhost:3000", + authentication_policy=authentication_policy, + ) + # make sure signautre name is correct + client2 = ResourcesClient( + credential=credential, + subscription_id=SUBSCRIPTION_ID, + base_url="http://localhost:3000", + authentication_policy=authentication_policy, + ) + for client in [client1, client2]: + # make sure signautre order is correct + await client.top_level.get(RESOURCE_GROUP_NAME, "top") + # make sure signautre name is correct + await client.top_level.get( + resource_group_name=RESOURCE_GROUP_NAME, + top_level_tracked_resource_name="top", + ) + + +@pytest.mark.asyncio +async def test_top_level_begin_create_or_replace(client): + result = await ( + await client.top_level.begin_create_or_replace( + resource_group_name=RESOURCE_GROUP_NAME, + top_level_tracked_resource_name="top", + resource=models.TopLevelTrackedResource( + location="eastus", + properties=models.TopLevelTrackedResourceProperties( + models.TopLevelTrackedResourceProperties(description="valid") + ), + ), + polling_interval=0, # set polling_interval to 0 s to make the test faster since default is 30s + ) + ).result() + assert result.location == "eastus" + assert result.properties.description == "valid" + assert result.properties.provisioning_state == "Succeeded" + assert result.name == "top" + assert result.type == "Azure.ResourceManager.Resources/topLevelTrackedResources" + assert result.system_data.created_by == "AzureSDK" + + +@pytest.mark.asyncio +async def test_top_level_begin_update(client): + result = await ( + await client.top_level.begin_update( + resource_group_name=RESOURCE_GROUP_NAME, + top_level_tracked_resource_name="top", + properties=models.TopLevelTrackedResource( + location="eastus", + properties=models.TopLevelTrackedResourceProperties( + models.TopLevelTrackedResourceProperties(description="valid2") + ), + ), + polling_interval=0, # set polling_interval to 0 s to make the test faster since default is 30s + ) + ).result() + assert result.location == "eastus" + assert result.properties.description == "valid2" + assert result.properties.provisioning_state == "Succeeded" + assert result.name == "top" + assert result.type == "Azure.ResourceManager.Resources/topLevelTrackedResources" + assert result.system_data.created_by == "AzureSDK" + + +@pytest.mark.asyncio +async def test_top_level_begin_delete(client): + await ( + await client.top_level.begin_delete( + resource_group_name=RESOURCE_GROUP_NAME, + top_level_tracked_resource_name="top", + polling_interval=0, # set polling_interval to 0 s to make the test faster since default is 30s + ) + ).result() + + +@pytest.mark.asyncio +async def test_top_level_list_by_resource_group(client): + response = client.top_level.list_by_resource_group( + resource_group_name=RESOURCE_GROUP_NAME, + ) + result = [r async for r in response] + for result in result: + assert result.location == "eastus" + assert result.properties.description == "valid" + assert result.properties.provisioning_state == "Succeeded" + assert result.name == "top" + assert result.type == "Azure.ResourceManager.Resources/topLevelTrackedResources" + assert result.system_data.created_by == "AzureSDK" + + +@pytest.mark.asyncio +async def test_top_level_list_by_subscription(client): + response = client.top_level.list_by_subscription() + result = [r async for r in response] + for result in result: + assert result.location == "eastus" + assert result.properties.description == "valid" + assert result.properties.provisioning_state == "Succeeded" + assert result.name == "top" + assert result.type == "Azure.ResourceManager.Resources/topLevelTrackedResources" + assert result.system_data.created_by == "AzureSDK" + + +@pytest.mark.asyncio +async def test_nested_get(client): + result = await client.nested.get( + resource_group_name=RESOURCE_GROUP_NAME, + top_level_tracked_resource_name="top", + nexted_proxy_resource_name="nested", + ) + assert result.properties.description == "valid" + assert result.properties.provisioning_state == "Succeeded" + assert result.name == "nested" + assert result.type == "Azure.ResourceManager.Resources/topLevelTrackedResources/top/nestedProxyResources" + assert result.system_data.created_by == "AzureSDK" + + +@pytest.mark.asyncio +async def test_nested_begin_create_or_replace(client): + result = await ( + await client.nested.begin_create_or_replace( + resource_group_name=RESOURCE_GROUP_NAME, + top_level_tracked_resource_name="top", + nexted_proxy_resource_name="nested", + resource=models.TopLevelTrackedResource( + properties=models.TopLevelTrackedResourceProperties( + models.TopLevelTrackedResourceProperties(description="valid") + ), + ), + polling_interval=0, # set polling_interval to 0 s to make the test faster since default is 30s + ) + ).result() + assert result.properties.description == "valid" + assert result.properties.provisioning_state == "Succeeded" + assert result.name == "nested" + assert result.type == "Azure.ResourceManager.Resources/topLevelTrackedResources/top/nestedProxyResources" + assert result.system_data.created_by == "AzureSDK" + + +@pytest.mark.asyncio +async def test_nested_begin_update(client): + result = await ( + await client.nested.begin_update( + resource_group_name=RESOURCE_GROUP_NAME, + top_level_tracked_resource_name="top", + nexted_proxy_resource_name="nested", + properties=models.TopLevelTrackedResource( + properties=models.TopLevelTrackedResourceProperties( + models.TopLevelTrackedResourceProperties(description="valid2") + ), + ), + polling_interval=0, # set polling_interval to 0 s to make the test faster since default is 30s + ) + ).result() + assert result.properties.description == "valid2" + assert result.properties.provisioning_state == "Succeeded" + assert result.name == "nested" + assert result.type == "Azure.ResourceManager.Resources/topLevelTrackedResources/top/nestedProxyResources" + assert result.system_data.created_by == "AzureSDK" + + +@pytest.mark.asyncio +async def test_nested_begin_delete(client): + await ( + await client.nested.begin_delete( + resource_group_name=RESOURCE_GROUP_NAME, + top_level_tracked_resource_name="top", + nexted_proxy_resource_name="nested", + polling_interval=0, # set polling_interval to 0 s to make the test faster since default is 30s + ) + ).result() + + +@pytest.mark.asyncio +async def test_nested_list_by_top_level_tracked_resource(client): + response = client.nested.list_by_top_level_tracked_resource( + resource_group_name=RESOURCE_GROUP_NAME, + top_level_tracked_resource_name="top", + ) + result = [r async for r in response] + for result in result: + assert result.properties.description == "valid" + assert result.properties.provisioning_state == "Succeeded" + assert result.name == "nested" + assert result.type == "Azure.ResourceManager.Resources/topLevelTrackedResources/top/nestedProxyResources" + assert result.system_data.created_by == "AzureSDK" + + +@pytest.mark.asyncio +async def test_top_level_action_sync(client): + await client.top_level.action_sync( + resource_group_name=RESOURCE_GROUP_NAME, + top_level_tracked_resource_name="top", + body={"message": "Resource action at top level.", "urgent": True}, + ) + + +@pytest.mark.asyncio +async def test_singleton_get_by_resource_group(client): + result = await client.singleton.get_by_resource_group( + resource_group_name=RESOURCE_GROUP_NAME, + ) + assert result.properties.description == "valid" + assert result.properties.provisioning_state == "Succeeded" + assert result.name == "default" + assert result.type == "Azure.ResourceManager.Resources/singletonTrackedResources" + assert result.system_data.created_by == "AzureSDK" + + +@pytest.mark.asyncio +async def test_singleton_begin_create_or_replace(client): + result = await ( + await client.singleton.begin_create_or_update( + resource_group_name=RESOURCE_GROUP_NAME, + resource=models.SingletonTrackedResource( + location="eastus", + properties=models.SingletonTrackedResourceProperties( + models.SingletonTrackedResourceProperties(description="valid") + ), + ), + ) + ).result() + assert result.properties.description == "valid" + assert result.properties.provisioning_state == "Succeeded" + assert result.name == "default" + assert result.type == "Azure.ResourceManager.Resources/singletonTrackedResources" + assert result.system_data.created_by == "AzureSDK" + + +@pytest.mark.asyncio +async def test_singleton_update(client): + result = await client.singleton.update( + resource_group_name=RESOURCE_GROUP_NAME, + properties=models.SingletonTrackedResource( + location="eastus2", + properties=models.SingletonTrackedResourceProperties( + models.SingletonTrackedResourceProperties(description="valid2") + ), + ), + ) + assert result.properties.description == "valid2" + assert result.properties.provisioning_state == "Succeeded" + assert result.name == "default" + assert result.type == "Azure.ResourceManager.Resources/singletonTrackedResources" + assert result.system_data.created_by == "AzureSDK" + + +@pytest.mark.asyncio +async def test_singleton_list_by_resource_group(client): + response = client.singleton.list_by_resource_group( + resource_group_name=RESOURCE_GROUP_NAME, + ) + result = [r async for r in response] + for result in result: + assert result.properties.description == "valid" + assert result.properties.provisioning_state == "Succeeded" + assert result.name == "default" + assert result.type == "Azure.ResourceManager.Resources/singletonTrackedResources" + assert result.system_data.created_by == "AzureSDK" + + +@pytest.mark.asyncio +@pytest.mark.parametrize( + "scope", + [ + "", + "/subscriptions/00000000-0000-0000-0000-000000000000", + "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/test-rg", + "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/test-rg/providers/Azure.ResourceManager.Resources/topLevelTrackedResources/top", + ], +) +async def test_extensions_resources_begin_create_or_update(client, scope): + result = await ( + await client.extensions_resources.begin_create_or_update( + resource_uri=scope, + extensions_resource_name="extension", + resource=models.ExtensionsResource(properties=models.ExtensionsResourceProperties(description="valid")), + ) + ).result() + assert result.id == f"{scope}/providers/Azure.ResourceManager.Resources/extensionsResources/extension" + assert result.name == "extension" + assert result.type == "Azure.ResourceManager.Resources/extensionsResources" + assert result.properties.description == "valid" + assert result.properties.provisioning_state == "Succeeded" + assert result.system_data.created_by == "AzureSDK" + + +@pytest.mark.asyncio +@pytest.mark.parametrize( + "scope", + [ + "", + "/subscriptions/00000000-0000-0000-0000-000000000000", + "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/test-rg", + "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/test-rg/providers/Azure.ResourceManager.Resources/topLevelTrackedResources/top", + ], +) +async def test_extensions_resources_update(client, scope): + result = await client.extensions_resources.update( + resource_uri=scope, + extensions_resource_name="extension", + properties=models.ExtensionsResource(properties=models.ExtensionsResourceProperties(description="valid2")), + ) + assert result.id == f"{scope}/providers/Azure.ResourceManager.Resources/extensionsResources/extension" + assert result.name == "extension" + assert result.type == "Azure.ResourceManager.Resources/extensionsResources" + assert result.properties.description == "valid2" + assert result.properties.provisioning_state == "Succeeded" + assert result.system_data.created_by == "AzureSDK" + + +@pytest.mark.asyncio +@pytest.mark.parametrize( + "scope", + [ + "", + "/subscriptions/00000000-0000-0000-0000-000000000000", + "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/test-rg", + "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/test-rg/providers/Azure.ResourceManager.Resources/topLevelTrackedResources/top", + ], +) +async def test_extensions_resources_get(client, scope): + result = await client.extensions_resources.get(resource_uri=scope, extensions_resource_name="extension") + assert result.id == f"{scope}/providers/Azure.ResourceManager.Resources/extensionsResources/extension" + assert result.name == "extension" + assert result.type == "Azure.ResourceManager.Resources/extensionsResources" + assert result.properties.description == "valid" + assert result.properties.provisioning_state == "Succeeded" + assert result.system_data.created_by == "AzureSDK" + + +@pytest.mark.asyncio +@pytest.mark.parametrize( + "scope", + [ + "", + "/subscriptions/00000000-0000-0000-0000-000000000000", + "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/test-rg", + "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/test-rg/providers/Azure.ResourceManager.Resources/topLevelTrackedResources/top", + ], +) +async def test_extensions_resources_list_by_scope(client, scope): + response = client.extensions_resources.list_by_scope( + resource_uri=scope, + ) + result = [r async for r in response] + for result in result: + assert result.id == f"{scope}/providers/Azure.ResourceManager.Resources/extensionsResources/extension" + assert result.name == "extension" + assert result.type == "Azure.ResourceManager.Resources/extensionsResources" + assert result.properties.description == "valid" + assert result.properties.provisioning_state == "Succeeded" + assert result.system_data.created_by == "AzureSDK" + + +@pytest.mark.asyncio +@pytest.mark.parametrize( + "scope", + [ + "", + "/subscriptions/00000000-0000-0000-0000-000000000000", + "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/test-rg", + "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/test-rg/providers/Azure.ResourceManager.Resources/topLevelTrackedResources/top", + ], +) +async def test_extensions_resources_delete(client, scope): + await client.extensions_resources.delete(resource_uri=scope, extensions_resource_name="extension") + + +@pytest.mark.asyncio +async def test_location_resources_create_or_update(client): + result = await client.location_resources.create_or_update( + location="eastus", + location_resource_name="resource", + resource=models.LocationResource(properties=models.LocationResourceProperties(description="valid")), + ) + assert ( + result.id + == "/subscriptions/00000000-0000-0000-0000-000000000000/providers/Azure.ResourceManager.Resources/locations/eastus/locationResources/resource" + ) + assert result.name == "resource" + assert result.type == "Azure.ResourceManager.Resources/locationResources" + assert result.properties.description == "valid" + assert result.properties.provisioning_state == "Succeeded" + assert result.system_data.created_by == "AzureSDK" + + +@pytest.mark.asyncio +async def test_location_resources_update(client): + result = await client.location_resources.update( + location="eastus", + location_resource_name="resource", + properties=models.LocationResource(properties=models.LocationResourceProperties(description="valid2")), + ) + assert ( + result.id + == "/subscriptions/00000000-0000-0000-0000-000000000000/providers/Azure.ResourceManager.Resources/locations/eastus/locationResources/resource" + ) + assert result.name == "resource" + assert result.type == "Azure.ResourceManager.Resources/locationResources" + assert result.properties.description == "valid2" + assert result.properties.provisioning_state == "Succeeded" + assert result.system_data.created_by == "AzureSDK" + + +@pytest.mark.asyncio +async def test_location_resources_get(client): + result = await client.location_resources.get( + location="eastus", + location_resource_name="resource", + ) + assert ( + result.id + == "/subscriptions/00000000-0000-0000-0000-000000000000/providers/Azure.ResourceManager.Resources/locations/eastus/locationResources/resource" + ) + assert result.name == "resource" + assert result.type == "Azure.ResourceManager.Resources/locationResources" + assert result.properties.description == "valid" + assert result.properties.provisioning_state == "Succeeded" + assert result.system_data.created_by == "AzureSDK" + + +@pytest.mark.asyncio +async def test_location_resources_delete(client): + await client.location_resources.delete( + location="eastus", + location_resource_name="resource", + ) + + +@pytest.mark.asyncio +async def test_location_resources_list_by_location(client): + response = client.location_resources.list_by_location( + location="eastus", + ) + result = [r async for r in response] + for result in result: + assert ( + result.id + == "/subscriptions/00000000-0000-0000-0000-000000000000/providers/Azure.ResourceManager.Resources/locations/eastus/locationResources/resource" + ) + assert result.name == "resource" + assert result.type == "Azure.ResourceManager.Resources/locationResources" + assert result.properties.description == "valid" + assert result.properties.provisioning_state == "Succeeded" + assert result.system_data.created_by == "AzureSDK" diff --git a/packages/typespec-python/tests/mock_api/azure/asynctests/test_azure_client_generator_core_access_async.py b/packages/typespec-python/tests/mock_api/azure/asynctests/test_azure_client_generator_core_access_async.py new file mode 100644 index 0000000000..2091b74337 --- /dev/null +++ b/packages/typespec-python/tests/mock_api/azure/asynctests/test_azure_client_generator_core_access_async.py @@ -0,0 +1,102 @@ +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- +import pytest +import pytest_asyncio +from specs.azure.clientgenerator.core.access.aio import AccessClient +from specs.azure.clientgenerator.core.access import models + + +@pytest_asyncio.fixture +async def client(): + async with AccessClient() as client: + yield client + + +@pytest.mark.asyncio +async def test_no_decorator_in_public(client: AccessClient): + result = await client.public_operation.no_decorator_in_public(name="sample") + assert result == models.NoDecoratorModelInPublic(name="sample") + + +@pytest.mark.asyncio +async def test_public_decorator_in_public(client: AccessClient): + result = await client.public_operation.public_decorator_in_public(name="sample") + assert result == models.PublicDecoratorModelInPublic(name="sample") + + +@pytest.mark.asyncio +async def test_no_decorator_in_internal(client: AccessClient): + result = await client.internal_operation._no_decorator_in_internal(name="sample") + assert result == models._models.NoDecoratorModelInInternal(name="sample") + + with pytest.raises(ImportError): + from specs.azure.clientgenerator.core.access.models import NoDecoratorModelInInternal + + with pytest.raises(AttributeError): + await client.internal_operation.no_decorator_in_internal(name="sample") + + +@pytest.mark.asyncio +async def test_internal_decorator_in_internal(client: AccessClient): + result = await client.internal_operation._internal_decorator_in_internal(name="sample") + assert result == models._models.InternalDecoratorModelInInternal(name="sample") + + with pytest.raises(ImportError): + from specs.azure.clientgenerator.core.access.models import InternalDecoratorModelInInternal + + with pytest.raises(AttributeError): + await client.internal_operation.internal_decorator_in_internal(name="sample") + + +@pytest.mark.asyncio +async def test_public_decorator_in_internal(client: AccessClient): + result = await client.internal_operation._public_decorator_in_internal(name="sample") + assert result == models.PublicDecoratorModelInInternal(name="sample") + + with pytest.raises(AttributeError): + await client.internal_operation.public_decorator_in_internal(name="sample") + + +@pytest.mark.asyncio +async def test_public(client: AccessClient): + result = await client.shared_model_in_operation.public(name="sample") + assert result == models.SharedModel(name="sample") + + +@pytest.mark.asyncio +async def test_internal(client: AccessClient): + result = await client.shared_model_in_operation._internal(name="sample") + assert result == models.SharedModel(name="sample") + + with pytest.raises(AttributeError): + await client.shared_model_in_operation.internal(name="sample") + + +@pytest.mark.asyncio +async def test_operation(client: AccessClient): + result = await client.relative_model_in_operation._operation(name="Madge") + assert result == models._models.OuterModel(name="Madge", inner=models._models.InnerModel(name="Madge")) + + with pytest.raises(ImportError): + from specs.azure.clientgenerator.core.access.models import OuterModel + + with pytest.raises(ImportError): + from specs.azure.clientgenerator.core.access.models import InnerModel + + with pytest.raises(AttributeError): + await client.shared_model_in_operation.operation(name="Madge") + + +@pytest.mark.asyncio +async def test_discriminator(client: AccessClient): + result = await client.relative_model_in_operation._discriminator(kind="real") + assert result == models._models.RealModel(name="Madge") + + with pytest.raises(ImportError): + from specs.azure.clientgenerator.core.access.models import RealModel + + with pytest.raises(AttributeError): + await client.shared_model_in_operation.discriminator(kind="real") diff --git a/packages/typespec-python/tests/mock_api/azure/asynctests/test_azure_client_generator_core_api_version_header_async.py b/packages/typespec-python/tests/mock_api/azure/asynctests/test_azure_client_generator_core_api_version_header_async.py new file mode 100644 index 0000000000..7baa44a747 --- /dev/null +++ b/packages/typespec-python/tests/mock_api/azure/asynctests/test_azure_client_generator_core_api_version_header_async.py @@ -0,0 +1,19 @@ +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- +import pytest +import pytest_asyncio +from client.alternateapiversion.service.header.aio import HeaderClient + + +@pytest_asyncio.fixture +async def client(): + async with HeaderClient(endpoint="http://localhost:3000") as client: + yield client + + +@pytest.mark.asyncio +async def test_header_api_version(client: HeaderClient): + await client.header_api_version() diff --git a/packages/typespec-python/tests/mock_api/azure/asynctests/test_azure_client_generator_core_api_version_path_async.py b/packages/typespec-python/tests/mock_api/azure/asynctests/test_azure_client_generator_core_api_version_path_async.py new file mode 100644 index 0000000000..885f6f6007 --- /dev/null +++ b/packages/typespec-python/tests/mock_api/azure/asynctests/test_azure_client_generator_core_api_version_path_async.py @@ -0,0 +1,19 @@ +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- +import pytest +import pytest_asyncio +from client.alternateapiversion.service.path.aio import PathClient + + +@pytest_asyncio.fixture +async def client(): + async with PathClient(endpoint="http://localhost:3000") as client: + yield client + + +@pytest.mark.asyncio +async def test_path_api_version(client: PathClient): + await client.path_api_version() diff --git a/packages/typespec-python/tests/mock_api/azure/asynctests/test_azure_client_generator_core_api_version_query_async.py b/packages/typespec-python/tests/mock_api/azure/asynctests/test_azure_client_generator_core_api_version_query_async.py new file mode 100644 index 0000000000..62f2f9847c --- /dev/null +++ b/packages/typespec-python/tests/mock_api/azure/asynctests/test_azure_client_generator_core_api_version_query_async.py @@ -0,0 +1,19 @@ +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- +import pytest +import pytest_asyncio +from client.alternateapiversion.service.query.aio import QueryClient + + +@pytest_asyncio.fixture +async def client(): + async with QueryClient(endpoint="http://localhost:3000") as client: + yield client + + +@pytest.mark.asyncio +async def test_query_api_version(client: QueryClient): + await client.query_api_version() diff --git a/packages/typespec-python/tests/mock_api/azure/asynctests/test_azure_client_generator_core_client_default_value_async.py b/packages/typespec-python/tests/mock_api/azure/asynctests/test_azure_client_generator_core_client_default_value_async.py new file mode 100644 index 0000000000..f4bbaaae04 --- /dev/null +++ b/packages/typespec-python/tests/mock_api/azure/asynctests/test_azure_client_generator_core_client_default_value_async.py @@ -0,0 +1,47 @@ +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- +import pytest +import pytest_asyncio +from specs.azure.clientgenerator.core.clientdefaultvalue.aio import ClientDefaultValueClient +from specs.azure.clientgenerator.core.clientdefaultvalue.models import ModelWithDefaultValues + + +@pytest_asyncio.fixture +async def client(): + async with ClientDefaultValueClient() as client: + yield client + + +@pytest.mark.asyncio +async def test_put_model_property(client: ClientDefaultValueClient): + """Test case 1: @clientDefaultValue for model property.""" + body = ModelWithDefaultValues(name="test") + result = await client.put_model_property(body=body) + assert result.name == "test" + assert result.timeout == 30 + assert result.tier == "standard" + assert result.retry is True + + +@pytest.mark.asyncio +async def test_get_operation_parameter(client: ClientDefaultValueClient): + """Test case 2: @clientDefaultValue for operation parameter.""" + # Test with only required parameter (name), defaults should be applied + await client.get_operation_parameter(name="test") + + +@pytest.mark.asyncio +async def test_get_path_parameter(client: ClientDefaultValueClient): + """Test case 3: @clientDefaultValue for first path segment.""" + # Test with only required segment2, segment1 should use default + await client.get_path_parameter(segment2="segment2") + + +@pytest.mark.asyncio +async def test_get_header_parameter(client: ClientDefaultValueClient): + """Test case 4: @clientDefaultValue for header parameters.""" + # Test with default header values + await client.get_header_parameter() diff --git a/packages/typespec-python/tests/mock_api/azure/asynctests/test_azure_client_generator_core_client_initialization_async.py b/packages/typespec-python/tests/mock_api/azure/asynctests/test_azure_client_generator_core_client_initialization_async.py new file mode 100644 index 0000000000..156f87a9a0 --- /dev/null +++ b/packages/typespec-python/tests/mock_api/azure/asynctests/test_azure_client_generator_core_client_initialization_async.py @@ -0,0 +1,58 @@ +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- +import pytest +from specs.azure.clientgenerator.core.clientinitialization.default.aio import ( + HeaderParamClient, + MultipleParamsClient, + MixedParamsClient, + PathParamClient, + ParamAliasClient, +) +from specs.azure.clientgenerator.core.clientinitialization.default.models import Input + + +@pytest.mark.asyncio +async def test_header_param_client(): + async with HeaderParamClient("test-name-value") as client: + await client.with_query(id="test-id") + await client.with_body(Input(name="test-name")) + + +@pytest.mark.asyncio +async def test_multiple_params_client(): + async with MultipleParamsClient("test-name-value", "us-west") as client: + await client.with_query(id="test-id") + await client.with_body(Input(name="test-name")) + + +@pytest.mark.asyncio +async def test_mixed_params_client(): + async with MixedParamsClient("test-name-value") as client: + await client.with_query(region="us-west", id="test-id") + await client.with_body(Input(name="test-name"), region="us-west") + + +@pytest.mark.asyncio +async def test_path_param_client(): + async with PathParamClient("sample-blob") as client: + await client.with_query(format="text") + await client.get_standalone() + await client.delete_standalone() + + +@pytest.mark.asyncio +async def test_param_alias_client(): + async with ParamAliasClient("sample-blob") as client: + await client.with_aliased_name() + await client.with_original_name() + + +# @pytest.mark.asyncio +# async def test_parent_child_client(): +# async with ParentClient() as client: +# await client.child_client.with_query() +# await client.child_client.get_standalone() +# await client.child_client.delete_standalone() diff --git a/packages/typespec-python/tests/mock_api/azure/asynctests/test_azure_client_generator_core_client_location_async.py b/packages/typespec-python/tests/mock_api/azure/asynctests/test_azure_client_generator_core_client_location_async.py new file mode 100644 index 0000000000..d320f31ffb --- /dev/null +++ b/packages/typespec-python/tests/mock_api/azure/asynctests/test_azure_client_generator_core_client_location_async.py @@ -0,0 +1,83 @@ +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- +import pytest +import pytest_asyncio +from specs.azure.clientgenerator.core.clientlocation.parameter.aio import MoveMethodParameterToClient +from specs.azure.clientgenerator.core.clientlocation.subclient.aio import MoveToExistingSubClient +from specs.azure.clientgenerator.core.clientlocation.newsubclient.aio import MoveToNewSubClient +from specs.azure.clientgenerator.core.clientlocation.rootclient.aio import MoveToRootClient + + +@pytest_asyncio.fixture +async def move_method_parameter_to_client(): + async with MoveMethodParameterToClient(storage_account="testaccount") as client: + yield client + + +@pytest_asyncio.fixture +async def move_to_existing_sub_client(): + async with MoveToExistingSubClient() as client: + yield client + + +@pytest_asyncio.fixture +async def move_to_new_sub_client(): + async with MoveToNewSubClient() as client: + yield client + + +@pytest_asyncio.fixture +async def move_to_root_client(): + async with MoveToRootClient() as client: + yield client + + +@pytest.mark.asyncio +async def test_move_method_parameter_to_client_blob_operations_get_blob( + move_method_parameter_to_client: MoveMethodParameterToClient, +): + await move_method_parameter_to_client.blob_operations.get_blob(container="testcontainer", blob="testblob.txt") + + +@pytest.mark.asyncio +async def test_move_to_existing_sub_client_user_operations_get_user( + move_to_existing_sub_client: MoveToExistingSubClient, +): + await move_to_existing_sub_client.user_operations.get_user() + + +@pytest.mark.asyncio +async def test_move_to_existing_sub_client_admin_operations_delete_user( + move_to_existing_sub_client: MoveToExistingSubClient, +): + await move_to_existing_sub_client.admin_operations.delete_user() + + +@pytest.mark.asyncio +async def test_move_to_existing_sub_client_admin_operations_get_admin_info( + move_to_existing_sub_client: MoveToExistingSubClient, +): + await move_to_existing_sub_client.admin_operations.get_admin_info() + + +@pytest.mark.asyncio +async def test_move_to_new_sub_client_product_operations_list_products(move_to_new_sub_client: MoveToNewSubClient): + await move_to_new_sub_client.product_operations.list_products() + + +@pytest.mark.asyncio +async def test_move_to_new_sub_client_archive_operations_archive_product(move_to_new_sub_client: MoveToNewSubClient): + await move_to_new_sub_client.archive_operations.archive_product() + + +@pytest.mark.asyncio +async def test_move_to_root_client_resource_operations_get_resource(move_to_root_client: MoveToRootClient): + await move_to_root_client.resource_operations.get_resource() + + +@pytest.mark.asyncio +async def test_move_to_root_client_get_health_status(move_to_root_client: MoveToRootClient): + await move_to_root_client.get_health_status() diff --git a/packages/typespec-python/tests/mock_api/azure/asynctests/test_azure_client_generator_core_deserialize_empty_string_as_null_async.py b/packages/typespec-python/tests/mock_api/azure/asynctests/test_azure_client_generator_core_deserialize_empty_string_as_null_async.py new file mode 100644 index 0000000000..e926baf8da --- /dev/null +++ b/packages/typespec-python/tests/mock_api/azure/asynctests/test_azure_client_generator_core_deserialize_empty_string_as_null_async.py @@ -0,0 +1,21 @@ +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- +import pytest +import pytest_asyncio +from specs.azure.clientgenerator.core.emptystring.aio import DeserializeEmptyStringAsNullClient +from specs.azure.clientgenerator.core.emptystring import models + + +@pytest_asyncio.fixture +async def client(): + async with DeserializeEmptyStringAsNullClient() as client: + yield client + + +@pytest.mark.asyncio +async def test_get(client: DeserializeEmptyStringAsNullClient): + result = await client.get() + assert result == models.ResponseModel(sample_url="") diff --git a/packages/typespec-python/tests/mock_api/azure/asynctests/test_azure_client_generator_core_flatten_async.py b/packages/typespec-python/tests/mock_api/azure/asynctests/test_azure_client_generator_core_flatten_async.py new file mode 100644 index 0000000000..6ebe71ad86 --- /dev/null +++ b/packages/typespec-python/tests/mock_api/azure/asynctests/test_azure_client_generator_core_flatten_async.py @@ -0,0 +1,116 @@ +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- +import pytest +import pytest_asyncio +from specs.azure.clientgenerator.core.flattenproperty.aio import FlattenPropertyClient +from specs.azure.clientgenerator.core.flattenproperty.models import ( + ChildFlattenModel, + ChildModel, + FlattenModel, + FlattenUnknownModel, + NestedFlattenModel, + Solution, + SolutionProperties, +) + + +@pytest_asyncio.fixture +async def client(): + async with FlattenPropertyClient() as client: + yield client + + +# ========== test for spector ========== + + +@pytest.mark.asyncio +async def test_put_flatten_model(client: FlattenPropertyClient): + resp = FlattenModel(name="test", properties=ChildModel(age=1, description="test")) + assert ( + await client.put_flatten_model(FlattenModel(name="foo", properties=ChildModel(age=10, description="bar"))) + == resp + ) + assert await client.put_flatten_model(FlattenModel(name="foo", age=10, description="bar")) == resp + + +@pytest.mark.asyncio +async def test_put_nested_flatten_model(client: FlattenPropertyClient): + # python doesn't support nested flatten model + assert await client.put_nested_flatten_model( + NestedFlattenModel( + name="foo", + properties=ChildFlattenModel(summary="bar", properties=ChildModel(age=10, description="test")), + ) + ) == NestedFlattenModel( + name="test", + properties=ChildFlattenModel(summary="test", properties=ChildModel(age=1, description="foo")), + ) + + +@pytest.mark.asyncio +async def test_put_flatten_unknown_model(client: FlattenPropertyClient): + result = await client.put_flatten_unknown_model(FlattenUnknownModel(name="foo")) + assert result.name == "test" + assert result.properties == {"key1": "value1", "key2": "value2"} + + +@pytest.mark.asyncio +async def test_put_flatten_read_only_model(client: FlattenPropertyClient): + result = await client.put_flatten_read_only_model(Solution(name="foo")) + assert result == Solution( + name="foo", + properties=SolutionProperties(solution_id="solution1", title="Solution Title", content="Solution Content"), + ) + assert result.solution_id == "solution1" + assert result.title == "Solution Title" + assert result.content == "Solution Content" + + +@pytest.mark.asyncio # ============test for compatibility ============ +async def test_dpg_model_common(): + flatten_model = FlattenModel(name="hello", properties=ChildModel(age=0, description="test")) + assert flatten_model.name == "hello" + assert flatten_model.properties.age == 0 + assert flatten_model.properties.description == "test" + + +@pytest.mark.asyncio +async def test_dpg_model_none(): + flatten_model = FlattenModel() + assert flatten_model.name is None + assert flatten_model.properties is None + assert flatten_model.age is None + assert flatten_model.description is None + + +@pytest.mark.asyncio +async def test_dpg_model_compatibility(): + flatten_model = FlattenModel(description="test", age=0) + assert flatten_model.description == "test" + assert flatten_model.age == 0 + assert flatten_model.properties.description == "test" + assert flatten_model.properties.age == 0 + + +@pytest.mark.asyncio +async def test_dpg_model_setattr(): + flatten_model = FlattenModel() + + flatten_model.age = 0 + assert flatten_model.properties.age == 0 + flatten_model.description = "test" + assert flatten_model.properties.description == "test" + + flatten_model.properties.age = 1 + assert flatten_model.age == 1 + flatten_model.properties.description = "test2" + assert flatten_model.description == "test2" + + +@pytest.mark.asyncio +async def test_dpg_model_exception(): + with pytest.raises(AttributeError): + FlattenModel().no_prop diff --git a/packages/typespec-python/tests/mock_api/azure/asynctests/test_azure_client_generator_core_hierrarchy_building_async.py b/packages/typespec-python/tests/mock_api/azure/asynctests/test_azure_client_generator_core_hierrarchy_building_async.py new file mode 100644 index 0000000000..9cf9749e50 --- /dev/null +++ b/packages/typespec-python/tests/mock_api/azure/asynctests/test_azure_client_generator_core_hierrarchy_building_async.py @@ -0,0 +1,54 @@ +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- +import pytest +import pytest_asyncio +from specs.azure.clientgenerator.core.hierarchybuilding.aio import HierarchyBuildingClient +from specs.azure.clientgenerator.core.hierarchybuilding.models import ( + Pet, + Dog, +) + + +@pytest_asyncio.fixture +async def client(): + async with HierarchyBuildingClient() as client: + yield client + + +# ========== test for spector ========== + + +@pytest.mark.asyncio +async def test_update_pet_as_pet(client: HierarchyBuildingClient): + resp = Pet(name="Buddy", trained=True) + assert await client.pet_operations.update_pet_as_pet(Pet(name="Buddy", trained=True)) == resp + + +@pytest.mark.asyncio +async def test_update_dog_as_pet(client: HierarchyBuildingClient): + resp = Dog(name="Rex", trained=True, breed="German Shepherd") + assert await client.pet_operations.update_dog_as_pet(Dog(name="Rex", trained=True, breed="German Shepherd")) == resp + + +@pytest.mark.asyncio +async def test_update_pet_as_animal(client: HierarchyBuildingClient): + resp = Pet(name="Buddy", trained=True) + assert await client.animal_operations.update_pet_as_animal(Pet(name="Buddy", trained=True)) == resp + + +@pytest.mark.asyncio +async def test_update_dog_as_animal(client: HierarchyBuildingClient): + resp = Dog(name="Rex", trained=True, breed="German Shepherd") + assert ( + await client.animal_operations.update_dog_as_animal(Dog(name="Rex", trained=True, breed="German Shepherd")) + == resp + ) + + +@pytest.mark.asyncio +async def test_update_dog_as_dog(client: HierarchyBuildingClient): + resp = Dog(name="Rex", trained=True, breed="German Shepherd") + assert await client.dog_operations.update_dog_as_dog(Dog(name="Rex", trained=True, breed="German Shepherd")) == resp diff --git a/packages/typespec-python/tests/mock_api/azure/asynctests/test_azure_client_generator_core_next_link_verb_async.py b/packages/typespec-python/tests/mock_api/azure/asynctests/test_azure_client_generator_core_next_link_verb_async.py new file mode 100644 index 0000000000..c9061a3f8a --- /dev/null +++ b/packages/typespec-python/tests/mock_api/azure/asynctests/test_azure_client_generator_core_next_link_verb_async.py @@ -0,0 +1,29 @@ +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- +import pytest +import pytest_asyncio + +from specs.azure.clientgenerator.core.nextlinkverb.aio import NextLinkVerbClient + + +@pytest_asyncio.fixture +async def client(): + async with NextLinkVerbClient(endpoint="http://localhost:3000") as client: + yield client + + +def assert_items(items): + assert len(items) == 2 + assert items[0].id == "test1" + assert items[1].id == "test2" + + +@pytest.mark.asyncio +async def test_list_items_next_link_verb(client: NextLinkVerbClient): + # The operation uses POST for nextLink per @nextLinkVerb + pager = client.list_items() + items = [item async for item in pager] + assert_items(items) diff --git a/packages/typespec-python/tests/mock_api/azure/asynctests/test_azure_client_generator_core_override_async.py b/packages/typespec-python/tests/mock_api/azure/asynctests/test_azure_client_generator_core_override_async.py new file mode 100644 index 0000000000..aeae909856 --- /dev/null +++ b/packages/typespec-python/tests/mock_api/azure/asynctests/test_azure_client_generator_core_override_async.py @@ -0,0 +1,107 @@ +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- +import inspect +import pytest +import pytest_asyncio +from specs.azure.clientgenerator.core.override.aio import OverrideClient + + +@pytest_asyncio.fixture +async def client(): + async with OverrideClient() as client: + yield client + + +@pytest.mark.asyncio +async def test_reorder_parameters(client: OverrideClient): + await client.reorder_parameters.reorder("param1", "param2") + + +@pytest.mark.asyncio +async def test_group_parameters(client: OverrideClient): + await client.group_parameters.group(param1="param1", param2="param2") + + +@pytest.mark.asyncio +async def test_require_optional_parameter(client: OverrideClient): + await client.require_optional_parameter.require_optional("param1", "param2") + + +@pytest.mark.asyncio +async def test_remove_optional_parameter(client: OverrideClient): + # Test with optional param2 provided + await client.remove_optional_parameter.remove_optional("param1", param2="param2") + + +def test_reorder_parameters_unit_async(client: OverrideClient): + # make sure signature name of `reorder_parameters` are ["param1", "param2"] + # Get the reorder method from the reorder_parameters operation + reorder_method = client.reorder_parameters.reorder + + # Inspect the method signature + sig = inspect.signature(reorder_method) + + # Get parameter names excluding 'self' and '**kwargs' + param_names = [ + param_name + for param_name, param in sig.parameters.items() + if param_name not in ("self", "kwargs") and param.kind != param.VAR_KEYWORD + ] + + # Assert that the parameter names are exactly ["param1", "param2"] + assert param_names == ["param1", "param2"], f"Expected parameter names ['param1', 'param2'], but got {param_names}" + + +def test_require_optional_parameter_signature(client: OverrideClient): + # Get the require_optional method + require_optional_method = client.require_optional_parameter.require_optional + + # Inspect the method signature + sig = inspect.signature(require_optional_method) + + # Get parameter details + params = sig.parameters + + # Check that both param1 and param2 are required (no default values) + assert "param1" in params, "param1 should be present in signature" + assert "param2" in params, "param2 should be present in signature" + assert params["param1"].default == params["param1"].empty, "param1 should have no default value" + assert params["param2"].default == params["param2"].empty, "param2 should have no default value" + + +def test_remove_optional_parameter_signature(client: OverrideClient): + """Test that remove_optional_parameter.remove_optional method signature has correct parameters. + + The @override decorator should remove some optional parameters from the method signature. + Only param1 (required) and param2 (optional) should remain. + """ + # Get the remove_optional method + remove_optional_method = client.remove_optional_parameter.remove_optional + + # Inspect the method signature + sig = inspect.signature(remove_optional_method) + + # Get parameter names excluding 'self' and '**kwargs' + param_names = [ + param_name + for param_name, param in sig.parameters.items() + if param_name not in ("self", "kwargs") and param.kind != param.VAR_KEYWORD + ] + + # Should have param1 (required) and param2 (keyword-only optional) + assert "param1" in param_names, "param1 should be present in signature" + assert "param2" in sig.parameters, "param2 should be present in signature" + + # param1 should be required (positional) + assert sig.parameters["param1"].default == sig.parameters["param1"].empty, "param1 should have no default value" + + # param2 should be optional keyword-only with None default + assert sig.parameters["param2"].kind == sig.parameters["param2"].KEYWORD_ONLY, "param2 should be keyword-only" + assert sig.parameters["param2"].default is None, "param2 should have None as default value" + + # param3 and param4 should be removed + assert "param3" not in param_names, "param3 should not be present in signature" + assert "param4" not in param_names, "param4 should not be present in signature" diff --git a/packages/typespec-python/tests/mock_api/azure/asynctests/test_azure_client_generator_core_usage_async.py b/packages/typespec-python/tests/mock_api/azure/asynctests/test_azure_client_generator_core_usage_async.py new file mode 100644 index 0000000000..816279eeb9 --- /dev/null +++ b/packages/typespec-python/tests/mock_api/azure/asynctests/test_azure_client_generator_core_usage_async.py @@ -0,0 +1,39 @@ +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- +import pytest +import pytest_asyncio +from specs.azure.clientgenerator.core.usage.aio import UsageClient +from specs.azure.clientgenerator.core.usage import models + + +@pytest_asyncio.fixture +async def client(): + async with UsageClient() as client: + yield client + + +@pytest.mark.asyncio +async def test_input_to_input_output(client: UsageClient): + await client.model_in_operation.input_to_input_output(models.InputModel(name="Madge")) + + +@pytest.mark.asyncio +async def test_output_to_input_output(client: UsageClient): + assert models.OutputModel(name="Madge") == await client.model_in_operation.output_to_input_output() + + +@pytest.mark.asyncio +async def test_model_usage(client: UsageClient): + assert models.RoundTripModel( + result=models.ResultModel(name="Madge") + ) == await client.model_in_operation.model_in_read_only_property(body=models.RoundTripModel()) + + +@pytest.mark.asyncio +async def test_orphan_model_serializable(client: UsageClient): + await client.model_in_operation.orphan_model_serializable( + body=models.OrphanModel(model_name="name", description="desc") + ) diff --git a/packages/typespec-python/tests/mock_api/azure/asynctests/test_azure_core_basic_async.py b/packages/typespec-python/tests/mock_api/azure/asynctests/test_azure_core_basic_async.py new file mode 100644 index 0000000000..3ce2c52262 --- /dev/null +++ b/packages/typespec-python/tests/mock_api/azure/asynctests/test_azure_core_basic_async.py @@ -0,0 +1,77 @@ +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- +import pytest +import pytest_asyncio +from specs.azure.core.basic import models, aio + +VALID_USER = models.User(id=1, name="Madge", etag="11bdc430-65e8-45ad-81d9-8ffa60d55b59") + + +@pytest_asyncio.fixture +async def client(): + async with aio.BasicClient() as client: + yield client + + +@pytest.mark.asyncio +async def test_create_or_update(client: aio.BasicClient): + result = await client.create_or_update(id=1, resource={"name": "Madge"}) + assert result == VALID_USER + + +@pytest.mark.asyncio +async def test_create_or_replace(client: aio.BasicClient): + result = await client.create_or_replace(id=1, resource={"name": "Madge"}) + assert result == VALID_USER + + +@pytest.mark.asyncio +async def test_get(client: aio.BasicClient): + result = await client.get(id=1) + assert result == VALID_USER + + +@pytest.mark.asyncio +async def test_list(client: aio.BasicClient): + result = client.list( + top=5, + skip=10, + orderby=["id"], + filter="id lt 10", + select=["id", "orders", "etag"], + expand=["orders"], + ) + result = [item async for item in result] + assert len(result) == 2 + assert result[0].id == 1 + assert result[0].name == "Madge" + assert result[0].etag == "11bdc430-65e8-45ad-81d9-8ffa60d55b59" + assert result[0].orders[0].id == 1 + assert result[0].orders[0].user_id == 1 + assert result[0].orders[0].detail == "a recorder" + assert result[1].id == 2 + assert result[1].name == "John" + assert result[1].etag == "11bdc430-65e8-45ad-81d9-8ffa60d55b5a" + assert result[1].orders[0].id == 2 + assert result[1].orders[0].user_id == 2 + assert result[1].orders[0].detail == "a TV" + + +@pytest.mark.asyncio +async def test_delete(client: aio.BasicClient): + await client.delete(id=1) + + +@pytest.mark.asyncio +async def test_export(client: aio.BasicClient): + result = await client.export(id=1, format="json") + assert result == VALID_USER + + +@pytest.mark.asyncio +async def test_export_all_users(client: aio.BasicClient): + result = await client.export_all_users(format="json") + assert result.users[0] == VALID_USER diff --git a/packages/typespec-python/tests/mock_api/azure/asynctests/test_azure_core_lro_rpc_async.py b/packages/typespec-python/tests/mock_api/azure/asynctests/test_azure_core_lro_rpc_async.py new file mode 100644 index 0000000000..57c19c423b --- /dev/null +++ b/packages/typespec-python/tests/mock_api/azure/asynctests/test_azure_core_lro_rpc_async.py @@ -0,0 +1,23 @@ +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- +import pytest +import pytest_asyncio +from specs.azure.core.lro.rpc.aio import RpcClient +from specs.azure.core.lro.rpc import models + + +@pytest_asyncio.fixture +async def client(): + async with RpcClient() as client: + yield client + + +@pytest.mark.asyncio +async def test_long_running_rpc(client: RpcClient, async_polling_method): + result = await client.begin_long_running_rpc( + models.GenerationOptions(prompt="text"), polling_interval=0, polling=async_polling_method + ) + assert (await result.result()) == models.GenerationResult(data="text data") diff --git a/packages/typespec-python/tests/mock_api/azure/asynctests/test_azure_core_lro_standard_async.py b/packages/typespec-python/tests/mock_api/azure/asynctests/test_azure_core_lro_standard_async.py new file mode 100644 index 0000000000..05c4c09a2a --- /dev/null +++ b/packages/typespec-python/tests/mock_api/azure/asynctests/test_azure_core_lro_standard_async.py @@ -0,0 +1,40 @@ +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- +import pytest +import pytest_asyncio +from specs.azure.core.lro.standard.aio import StandardClient +from specs.azure.core.lro.standard.models import User, ExportedUser + + +@pytest_asyncio.fixture +async def client(): + async with StandardClient() as client: + yield client + + +@pytest.mark.asyncio +async def test_lro_core_put(client, async_polling_method): + user = User({"name": "madge", "role": "contributor"}) + result = await ( + await client.begin_create_or_replace( + name=user.name, resource=user, polling_interval=0, polling=async_polling_method + ) + ).result() + assert result == user + + +@pytest.mark.asyncio +async def test_lro_core_delete(client, async_polling_method): + await (await client.begin_delete(name="madge", polling_interval=0, polling=async_polling_method)).result() + + +@pytest.mark.asyncio +async def test_lro_core_export(client, async_polling_method): + export_user = ExportedUser({"name": "madge", "resourceUri": "/users/madge"}) + result = await ( + await client.begin_export(name="madge", format="json", polling_interval=0, polling=async_polling_method) + ).result() + assert result == export_user diff --git a/packages/typespec-python/tests/mock_api/azure/asynctests/test_azure_core_model_async.py b/packages/typespec-python/tests/mock_api/azure/asynctests/test_azure_core_model_async.py new file mode 100644 index 0000000000..333cfb5dcb --- /dev/null +++ b/packages/typespec-python/tests/mock_api/azure/asynctests/test_azure_core_model_async.py @@ -0,0 +1,34 @@ +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- +import pytest +import pytest_asyncio +from specs.azure.core.model.aio import ModelClient +from specs.azure.core.model.models import AzureEmbeddingModel + + +@pytest_asyncio.fixture +async def client(): + async with ModelClient() as client: + yield client + + +@pytest.mark.asyncio +async def test_azure_core_embedding_vector_post(client: ModelClient): + embedding_model = AzureEmbeddingModel(embedding=[0, 1, 2, 3, 4]) + result = await client.azure_core_embedding_vector.post( + body=embedding_model, + ) + assert result == AzureEmbeddingModel(embedding=[5, 6, 7, 8, 9]) + + +@pytest.mark.asyncio +async def test_azure_core_embedding_vector_put(client: ModelClient): + await client.azure_core_embedding_vector.put(body=[0, 1, 2, 3, 4]) + + +@pytest.mark.asyncio +async def test_azure_core_embedding_vector_get(client: ModelClient): + assert [0, 1, 2, 3, 4] == (await client.azure_core_embedding_vector.get()) diff --git a/packages/typespec-python/tests/mock_api/azure/asynctests/test_azure_core_page_async.py b/packages/typespec-python/tests/mock_api/azure/asynctests/test_azure_core_page_async.py new file mode 100644 index 0000000000..01a862620f --- /dev/null +++ b/packages/typespec-python/tests/mock_api/azure/asynctests/test_azure_core_page_async.py @@ -0,0 +1,81 @@ +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- +import pytest +import pytest_asyncio +from typing import AsyncIterable +from specs.azure.core.page import models, aio + +VALID_USER = models.User(id=1, name="Madge", etag="11bdc430-65e8-45ad-81d9-8ffa60d55b59") + + +@pytest_asyncio.fixture +async def client(): + async with aio.PageClient() as client: + yield client + + +async def _list_with_page_tests(pager: AsyncIterable[models.User]): + result = [p async for p in pager] + assert len(result) == 1 + assert result[0].id == 1 + assert result[0].name == "Madge" + assert result[0].etag == "11bdc430-65e8-45ad-81d9-8ffa60d55b59" + assert result[0].orders is None + + +@pytest.mark.asyncio +async def test_list_with_page(client: aio.PageClient): + await _list_with_page_tests(client.list_with_page()) + + +@pytest.mark.asyncio +async def test_list_with_custom_page_model(client: aio.PageClient): + await _list_with_page_tests(client.list_with_custom_page_model()) + with pytest.raises(AttributeError): + models.CustomPageModel + + +@pytest.mark.asyncio +async def test_list_with_parameters(client: aio.PageClient): + result = [ + item + async for item in client.list_with_parameters(models.ListItemInputBody(input_name="Madge"), another="Second") + ] + assert len(result) == 1 + assert result[0] == VALID_USER + + +@pytest.mark.asyncio +async def test_two_models_as_page_item(client: aio.PageClient): + result = [item async for item in client.two_models_as_page_item.list_first_item()] + assert len(result) == 1 + assert result[0].id == 1 + + result = [item async for item in client.two_models_as_page_item.list_second_item()] + assert len(result) == 1 + assert result[0].name == "Madge" + + +@pytest.mark.asyncio +async def test_list_with_parameterized_next_link(client: aio.PageClient): + result = [item async for item in client.with_parameterized_next_link(select="name", include_pending=True)] + assert len(result) == 2 + assert result[0].id == 1 + assert result[0].name == "User1" + assert result[1].id == 2 + assert result[1].name == "User2" + + +@pytest.mark.asyncio +async def test_list_with_relative_next_link(client: aio.PageClient): + result = [item async for item in client.with_relative_next_link()] + assert len(result) == 2 + assert result[0].id == 1 + assert result[0].name == "User1" + assert result[0].etag == "11bdc430-65e8-45ad-81d9-8ffa60d55b59" + assert result[1].id == 2 + assert result[1].name == "User2" + assert result[1].etag == "11bdc430-65e8-45ad-81d9-8ffa60d55b59" diff --git a/packages/typespec-python/tests/mock_api/azure/asynctests/test_azure_core_scalar_async.py b/packages/typespec-python/tests/mock_api/azure/asynctests/test_azure_core_scalar_async.py new file mode 100644 index 0000000000..321ebf9fc1 --- /dev/null +++ b/packages/typespec-python/tests/mock_api/azure/asynctests/test_azure_core_scalar_async.py @@ -0,0 +1,42 @@ +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- +import pytest +import pytest_asyncio +from specs.azure.core.scalar.aio import ScalarClient +from specs.azure.core.scalar import models + + +@pytest_asyncio.fixture +async def client(): + async with ScalarClient() as client: + yield client + + +@pytest.mark.asyncio +async def test_azure_location_scalar_get(client: ScalarClient): + result = await client.azure_location_scalar.get() + assert result == "eastus" + + +@pytest.mark.asyncio +async def test_azure_location_scalar_put(client: ScalarClient): + await client.azure_location_scalar.put("eastus") + + +@pytest.mark.asyncio +async def test_azure_location_scalar_post(client: ScalarClient): + result = await client.azure_location_scalar.post(models.AzureLocationModel(location="eastus")) + assert result == models.AzureLocationModel(location="eastus") + + +@pytest.mark.asyncio +async def test_azure_location_scalar_header(client: ScalarClient): + await client.azure_location_scalar.header(region="eastus") + + +@pytest.mark.asyncio +async def test_azure_location_scalar_query(client: ScalarClient): + await client.azure_location_scalar.query(region="eastus") diff --git a/packages/typespec-python/tests/mock_api/azure/asynctests/test_azure_core_traits_async.py b/packages/typespec-python/tests/mock_api/azure/asynctests/test_azure_core_traits_async.py new file mode 100644 index 0000000000..02060f56c2 --- /dev/null +++ b/packages/typespec-python/tests/mock_api/azure/asynctests/test_azure_core_traits_async.py @@ -0,0 +1,88 @@ +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- +import functools +from datetime import datetime + +import pytest +import pytest_asyncio +from azure.core.exceptions import HttpResponseError +from azure.core import MatchConditions +from specs.azure.core.traits.aio import TraitsClient +from specs.azure.core.traits.models import UserActionParam + + +@pytest_asyncio.fixture +async def client(): + async with TraitsClient() as client: + yield client + + +@pytest.mark.asyncio +async def test_get(client: TraitsClient, check_client_request_id_header): + async def assert_test_get(**kwargs): + checked = {} + result, header = await client.smoke_test( + id=1, + foo="123", + if_unmodified_since=datetime(year=2022, month=8, day=26, hour=14, minute=38, second=0), + if_modified_since=datetime(year=2021, month=8, day=26, hour=14, minute=38, second=0), + cls=lambda x, y, z: (y, z), + raw_request_hook=functools.partial( + check_client_request_id_header, header="x-ms-client-request-id", checked=checked + ), + **kwargs, + ) + assert result.id == 1 + assert result.name == "Madge" + assert header["ETag"] == "11bdc430-65e8-45ad-81d9-8ffa60d55b59" + assert header["bar"] == "456" + assert header["x-ms-client-request-id"] == checked["x-ms-client-request-id"] + + await assert_test_get(etag="valid", match_condition=MatchConditions.IfNotModified) + await assert_test_get(etag="invalid", match_condition=MatchConditions.IfModified) + with pytest.raises(HttpResponseError): + await assert_test_get() + + +@pytest.mark.asyncio +async def test_repeatable_action(client: TraitsClient, check_repeatability_header): + result, header = await client.repeatable_action( + id=1, + body=UserActionParam(user_action_value="test"), + cls=lambda x, y, z: (y, z), + raw_request_hook=check_repeatability_header, + ) + assert result.user_action_result == "test" + assert header["Repeatability-Result"] == "accepted" + + result, header = await client.repeatable_action( + id=1, + body=UserActionParam(user_action_value="test"), + cls=lambda x, y, z: (y, z), + headers={ + "Repeatability-Request-ID": "5942d803-e3fa-4f96-8f67-607d7bd607f5", + "Repeatability-First-Sent": "Sun, 06 Nov 1994 08:49:37 GMT", + }, + raw_request_hook=check_repeatability_header, + ) + assert result.user_action_result == "test" + assert header["Repeatability-Result"] == "accepted" + + with pytest.raises(HttpResponseError): + await client.repeatable_action( + id=1, + body=UserActionParam(user_action_value="test"), + cls=lambda x, y, z: (y, z), + headers={"Repeatability-Request-ID": "wrong-id"}, + ) + + with pytest.raises(HttpResponseError): + await client.repeatable_action( + id=1, + body=UserActionParam(user_action_value="test"), + cls=lambda x, y, z: (y, z), + headers={"Repeatability-First-Sent": "wrong-datetime"}, + ) diff --git a/packages/typespec-python/tests/mock_api/azure/asynctests/test_azure_encode_duration_async.py b/packages/typespec-python/tests/mock_api/azure/asynctests/test_azure_encode_duration_async.py new file mode 100644 index 0000000000..d1c4867b89 --- /dev/null +++ b/packages/typespec-python/tests/mock_api/azure/asynctests/test_azure_encode_duration_async.py @@ -0,0 +1,20 @@ +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- +import pytest +import pytest_asyncio +from specs.azure.encode.duration.aio import DurationClient +from specs.azure.encode.duration import models + + +@pytest_asyncio.fixture +async def client(): + async with DurationClient() as client: + yield client + + +@pytest.mark.asyncio +async def test_duration_constant(client: DurationClient): + await client.duration_constant(models.DurationModel(input="1.02:59:59.5000000")) diff --git a/packages/typespec-python/tests/mock_api/azure/asynctests/test_azure_example_basic_async.py b/packages/typespec-python/tests/mock_api/azure/asynctests/test_azure_example_basic_async.py new file mode 100644 index 0000000000..00ce65cfb4 --- /dev/null +++ b/packages/typespec-python/tests/mock_api/azure/asynctests/test_azure_example_basic_async.py @@ -0,0 +1,31 @@ +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- +import pytest +import pytest_asyncio +from specs.azure.example.basic.aio import AzureExampleClient +from specs.azure.example.basic.models import ActionRequest, Model + + +@pytest_asyncio.fixture +async def client(): + async with AzureExampleClient() as client: + yield client + + +@pytest.mark.asyncio +async def test_basic_action(client: AzureExampleClient): + body = ActionRequest( + string_property="text", + model_property=Model(int32_property=1, float32_property=1.5, enum_property="EnumValue1"), + array_property=["item"], + record_property={"record": "value"}, + ) + result = await client.basic_action( + body=body, + query_param="query", + header_param="header", + ) + assert result.string_property == body.string_property diff --git a/packages/typespec-python/tests/mock_api/azure/asynctests/test_azure_payload_pageable_async.py b/packages/typespec-python/tests/mock_api/azure/asynctests/test_azure_payload_pageable_async.py new file mode 100644 index 0000000000..1da9e66589 --- /dev/null +++ b/packages/typespec-python/tests/mock_api/azure/asynctests/test_azure_payload_pageable_async.py @@ -0,0 +1,20 @@ +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- +import pytest +import pytest_asyncio +from specs.azure.payload.pageable.aio import PageableClient + + +@pytest_asyncio.fixture +async def client(): + async with PageableClient(endpoint="http://localhost:3000") as client: + yield client + + +@pytest.mark.asyncio +async def test_list(client: PageableClient): + result = [p async for p in client.list(maxpagesize=3)] + assert len(result) == 4 diff --git a/packages/typespec-python/tests/mock_api/azure/asynctests/test_azure_resource_manager_method_subscription_id_async.py b/packages/typespec-python/tests/mock_api/azure/asynctests/test_azure_resource_manager_method_subscription_id_async.py new file mode 100644 index 0000000000..4cd896a347 --- /dev/null +++ b/packages/typespec-python/tests/mock_api/azure/asynctests/test_azure_resource_manager_method_subscription_id_async.py @@ -0,0 +1,249 @@ +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- +import pytest +import pytest_asyncio +from azure.resourcemanager.methodsubscriptionid.aio import MethodSubscriptionIdClient +from azure.resourcemanager.methodsubscriptionid import models + +SUBSCRIPTION_ID = "00000000-0000-0000-0000-000000000000" +RESOURCE_GROUP_NAME = "test-rg" + + +@pytest_asyncio.fixture +async def client(credential, authentication_policy): + async with MethodSubscriptionIdClient( + credential, + SUBSCRIPTION_ID, + "http://localhost:3000", + authentication_policy=authentication_policy, + ) as client: + yield client + + +@pytest.mark.asyncio +async def test_operations_list(client): + """Test Operations.list() endpoint.""" + operations = client.operations.list() + operations_list = [op async for op in operations] + assert len(operations_list) > 0 + + operation = operations_list[0] + assert operation.name == "Azure.ResourceManager.MethodSubscriptionId/services/read" + assert operation.is_data_action is False + assert operation.display.provider == "Azure.ResourceManager.MethodSubscriptionId" + assert operation.display.resource == "services" + assert operation.display.operation == "Lists services" + assert operation.display.description == "Lists registered services" + + +@pytest.mark.asyncio +async def test_two_subscription_resources_method_level_subscription_resource1_operations_get(client): + """Test get operation for SubscriptionResource1 with method-level subscription ID.""" + result = await client.two_subscription_resources_method_level.subscription_resource1_operations.get( + subscription_id=SUBSCRIPTION_ID, + subscription_resource1_name="sub-resource-1", + ) + + assert ( + result.id + == f"/subscriptions/{SUBSCRIPTION_ID}/providers/Azure.ResourceManager.MethodSubscriptionId/subscriptionResource1s/sub-resource-1" + ) + assert result.name == "sub-resource-1" + assert result.type == "Azure.ResourceManager.MethodSubscriptionId/subscriptionResource1s" + assert result.properties.description == "Valid subscription resource 1" + assert result.properties.provisioning_state == "Succeeded" + assert result.system_data.created_by == "AzureSDK" + + +@pytest.mark.asyncio +async def test_two_subscription_resources_method_level_subscription_resource1_operations_put(client): + """Test put operation for SubscriptionResource1 with method-level subscription ID.""" + resource = models.SubscriptionResource1( + properties=models.SubscriptionResource1Properties(description="Valid subscription resource 1") + ) + + result = await client.two_subscription_resources_method_level.subscription_resource1_operations.put( + subscription_id=SUBSCRIPTION_ID, + subscription_resource1_name="sub-resource-1", + resource=resource, + ) + + assert ( + result.id + == f"/subscriptions/{SUBSCRIPTION_ID}/providers/Azure.ResourceManager.MethodSubscriptionId/subscriptionResource1s/sub-resource-1" + ) + assert result.name == "sub-resource-1" + assert result.type == "Azure.ResourceManager.MethodSubscriptionId/subscriptionResource1s" + assert result.properties.description == "Valid subscription resource 1" + assert result.properties.provisioning_state == "Succeeded" + assert result.system_data.created_by == "AzureSDK" + + +@pytest.mark.asyncio +async def test_two_subscription_resources_method_level_subscription_resource1_operations_delete(client): + """Test delete operation for SubscriptionResource1 with method-level subscription ID.""" + await client.two_subscription_resources_method_level.subscription_resource1_operations.delete( + subscription_id=SUBSCRIPTION_ID, + subscription_resource1_name="sub-resource-1", + ) + + +@pytest.mark.asyncio +async def test_two_subscription_resources_method_level_subscription_resource2_operations_get(client): + """Test get operation for SubscriptionResource2 with method-level subscription ID.""" + result = await client.two_subscription_resources_method_level.subscription_resource2_operations.get( + subscription_id=SUBSCRIPTION_ID, + subscription_resource2_name="sub-resource-2", + ) + + assert ( + result.id + == f"/subscriptions/{SUBSCRIPTION_ID}/providers/Azure.ResourceManager.MethodSubscriptionId/subscriptionResource2s/sub-resource-2" + ) + assert result.name == "sub-resource-2" + assert result.type == "Azure.ResourceManager.MethodSubscriptionId/subscriptionResource2s" + assert result.properties.config_value == "test-config" + assert result.properties.provisioning_state == "Succeeded" + assert result.system_data.created_by == "AzureSDK" + + +@pytest.mark.asyncio +async def test_two_subscription_resources_method_level_subscription_resource2_operations_put(client): + """Test put operation for SubscriptionResource2 with method-level subscription ID.""" + resource = models.SubscriptionResource2( + properties=models.SubscriptionResource2Properties(config_value="test-config") + ) + + result = await client.two_subscription_resources_method_level.subscription_resource2_operations.put( + subscription_id=SUBSCRIPTION_ID, + subscription_resource2_name="sub-resource-2", + resource=resource, + ) + + assert ( + result.id + == f"/subscriptions/{SUBSCRIPTION_ID}/providers/Azure.ResourceManager.MethodSubscriptionId/subscriptionResource2s/sub-resource-2" + ) + assert result.name == "sub-resource-2" + assert result.type == "Azure.ResourceManager.MethodSubscriptionId/subscriptionResource2s" + assert result.properties.config_value == "test-config" + assert result.properties.provisioning_state == "Succeeded" + assert result.system_data.created_by == "AzureSDK" + + +@pytest.mark.asyncio +async def test_two_subscription_resources_method_level_subscription_resource2_operations_delete(client): + """Test delete operation for SubscriptionResource2 with method-level subscription ID.""" + await client.two_subscription_resources_method_level.subscription_resource2_operations.delete( + subscription_id=SUBSCRIPTION_ID, + subscription_resource2_name="sub-resource-2", + ) + + +@pytest.mark.asyncio +async def test_mixed_subscription_placement_subscription_resource_operations_get(client): + """Test get operation for SubscriptionResource in mixed placement scenario.""" + result = await client.mixed_subscription_placement.subscription_resource_operations.get( + subscription_id=SUBSCRIPTION_ID, + subscription_resource_name="sub-resource", + ) + + assert ( + result.id + == f"/subscriptions/{SUBSCRIPTION_ID}/providers/Azure.ResourceManager.MethodSubscriptionId/subscriptionResources/sub-resource" + ) + assert result.name == "sub-resource" + assert result.type == "Azure.ResourceManager.MethodSubscriptionId/subscriptionResources" + assert result.properties.subscription_setting == "test-sub-setting" + assert result.properties.provisioning_state == "Succeeded" + assert result.system_data.created_by == "AzureSDK" + + +@pytest.mark.asyncio +async def test_mixed_subscription_placement_subscription_resource_operations_put(client): + """Test put operation for SubscriptionResource in mixed placement scenario.""" + resource = models.SubscriptionResource( + properties=models.SubscriptionResourceProperties(subscription_setting="test-sub-setting") + ) + + result = await client.mixed_subscription_placement.subscription_resource_operations.put( + subscription_id=SUBSCRIPTION_ID, + subscription_resource_name="sub-resource", + resource=resource, + ) + + assert ( + result.id + == f"/subscriptions/{SUBSCRIPTION_ID}/providers/Azure.ResourceManager.MethodSubscriptionId/subscriptionResources/sub-resource" + ) + assert result.name == "sub-resource" + assert result.type == "Azure.ResourceManager.MethodSubscriptionId/subscriptionResources" + assert result.properties.subscription_setting == "test-sub-setting" + assert result.properties.provisioning_state == "Succeeded" + assert result.system_data.created_by == "AzureSDK" + + +@pytest.mark.asyncio +async def test_mixed_subscription_placement_subscription_resource_operations_delete(client): + """Test delete operation for SubscriptionResource in mixed placement scenario.""" + await client.mixed_subscription_placement.subscription_resource_operations.delete( + subscription_id=SUBSCRIPTION_ID, + subscription_resource_name="sub-resource", + ) + + +@pytest.mark.asyncio +async def test_mixed_subscription_placement_resource_group_resource_operations_get(client): + """Test get operation for ResourceGroupResource with client-level subscription ID.""" + result = await client.mixed_subscription_placement.resource_group_resource_operations.get( + resource_group_name=RESOURCE_GROUP_NAME, + resource_group_resource_name="rg-resource", + ) + + assert ( + result.id + == f"/subscriptions/{SUBSCRIPTION_ID}/resourceGroups/{RESOURCE_GROUP_NAME}/providers/Azure.ResourceManager.MethodSubscriptionId/resourceGroupResources/rg-resource" + ) + assert result.name == "rg-resource" + assert result.type == "Azure.ResourceManager.MethodSubscriptionId/resourceGroupResources" + assert result.location == "eastus" + assert result.properties.resource_group_setting == "test-setting" + assert result.properties.provisioning_state == "Succeeded" + assert result.system_data.created_by == "AzureSDK" + + +@pytest.mark.asyncio +async def test_mixed_subscription_placement_resource_group_resource_operations_put(client): + """Test put operation for ResourceGroupResource with client-level subscription ID.""" + resource = models.ResourceGroupResource( + location="eastus", properties=models.ResourceGroupResourceProperties(resource_group_setting="test-setting") + ) + + result = await client.mixed_subscription_placement.resource_group_resource_operations.put( + resource_group_name=RESOURCE_GROUP_NAME, + resource_group_resource_name="rg-resource", + resource=resource, + ) + + assert ( + result.id + == f"/subscriptions/{SUBSCRIPTION_ID}/resourceGroups/{RESOURCE_GROUP_NAME}/providers/Azure.ResourceManager.MethodSubscriptionId/resourceGroupResources/rg-resource" + ) + assert result.name == "rg-resource" + assert result.type == "Azure.ResourceManager.MethodSubscriptionId/resourceGroupResources" + assert result.location == "eastus" + assert result.properties.resource_group_setting == "test-setting" + assert result.properties.provisioning_state == "Succeeded" + assert result.system_data.created_by == "AzureSDK" + + +@pytest.mark.asyncio +async def test_mixed_subscription_placement_resource_group_resource_operations_delete(client): + """Test delete operation for ResourceGroupResource with client-level subscription ID.""" + await client.mixed_subscription_placement.resource_group_resource_operations.delete( + resource_group_name=RESOURCE_GROUP_NAME, + resource_group_resource_name="rg-resource", + ) diff --git a/packages/typespec-python/tests/mock_api/azure/asynctests/test_azure_resource_manager_multi_service_async.py b/packages/typespec-python/tests/mock_api/azure/asynctests/test_azure_resource_manager_multi_service_async.py new file mode 100644 index 0000000000..b80c58a227 --- /dev/null +++ b/packages/typespec-python/tests/mock_api/azure/asynctests/test_azure_resource_manager_multi_service_async.py @@ -0,0 +1,111 @@ +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- +import pytest +import pytest_asyncio +from azure.core.exceptions import HttpResponseError +from azure.resourcemanager.multiservice.combined.aio import CombinedClient +from azure.resourcemanager.multiservice.combined.models import VirtualMachine, Disk + + +@pytest_asyncio.fixture +async def client(credential, authentication_policy): + """Create a Combined async client for testing.""" + return CombinedClient( + credential=credential, + subscription_id="00000000-0000-0000-0000-000000000000", + base_url="http://localhost:3000", + authentication_policy=authentication_policy, + polling_interval=0.1, # Speed up tests by reducing polling interval + ) + + +@pytest.mark.asyncio +async def test_virtual_machines_get(client): + resource_group_name = "test-rg" + vm_name = "vm1" + + with pytest.raises(HttpResponseError): + await client.virtual_machines.get( + resource_group_name=resource_group_name, + vm_name=vm_name, + api_version="av1", # invalid api version shall raise error + ) + + result = await client.virtual_machines.get(resource_group_name=resource_group_name, vm_name=vm_name) + + assert result is not None + assert isinstance(result, VirtualMachine) + assert result.name == vm_name + + +@pytest.mark.asyncio +async def test_virtual_machines_create_or_update(client): + resource_group_name = "test-rg" + vm_name = "vm1" + + vm_resource = VirtualMachine(location="eastus", properties={}) + + with pytest.raises(HttpResponseError): + poller = await client.virtual_machines.begin_create_or_update( + resource_group_name=resource_group_name, + vm_name=vm_name, + resource=vm_resource, + api_version="av1", # invalid api version shall raise error + ) + await poller.result() + + poller = await client.virtual_machines.begin_create_or_update( + resource_group_name=resource_group_name, vm_name=vm_name, resource=vm_resource + ) + + result = await poller.result() + assert result is not None + assert isinstance(result, VirtualMachine) + assert result.location == "eastus" + + +@pytest.mark.asyncio +async def test_disks_get(client): + resource_group_name = "test-rg" + disk_name = "disk1" + with pytest.raises(HttpResponseError): + await client.disks.get( + resource_group_name=resource_group_name, + disk_name=disk_name, + api_version="av1", # invalid api version shall raise error + ) + + result = await client.disks.get(resource_group_name=resource_group_name, disk_name=disk_name) + + assert result is not None + assert isinstance(result, Disk) + assert result.name == disk_name + + +@pytest.mark.asyncio +async def test_disks_create_or_update(client): + resource_group_name = "test-rg" + disk_name = "disk1" + + disk_resource = Disk(location="eastus", properties={}) + + with pytest.raises(HttpResponseError): + poller = await client.disks.begin_create_or_update( + resource_group_name=resource_group_name, + disk_name=disk_name, + resource=disk_resource, + api_version="av1", # invalid api version shall raise error + ) + await poller.result() + + poller = await client.disks.begin_create_or_update( + resource_group_name=resource_group_name, disk_name=disk_name, resource=disk_resource + ) + + result = await poller.result() + assert result is not None + assert isinstance(result, Disk) + assert result.location == "eastus" diff --git a/packages/typespec-python/tests/mock_api/azure/asynctests/test_azure_resource_manager_multi_service_shared_models_async.py b/packages/typespec-python/tests/mock_api/azure/asynctests/test_azure_resource_manager_multi_service_shared_models_async.py new file mode 100644 index 0000000000..57bc4929d9 --- /dev/null +++ b/packages/typespec-python/tests/mock_api/azure/asynctests/test_azure_resource_manager_multi_service_shared_models_async.py @@ -0,0 +1,133 @@ +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- +import pytest +import pytest_asyncio +from azure.resourcemanager.multiservicesharedmodels.combined.aio import CombinedClient +from azure.resourcemanager.multiservicesharedmodels.combined.models import ( + VirtualMachine, + VirtualMachineProperties, + StorageAccount, + StorageAccountProperties, + SharedMetadata, +) + + +@pytest_asyncio.fixture +async def client(credential, authentication_policy): + """Create a Combined async client for testing.""" + return CombinedClient( + credential=credential, + subscription_id="00000000-0000-0000-0000-000000000000", + base_url="http://localhost:3000", + authentication_policy=authentication_policy, + polling_interval=0.1, + ) + + +@pytest.mark.asyncio +async def test_virtual_machines_get(client): + """Test getting a virtual machine with shared metadata.""" + resource_group_name = "test-rg" + vm_name = "vm-shared1" + + result = await client.virtual_machines.get(resource_group_name=resource_group_name, vm_name=vm_name) + + assert result is not None + assert isinstance(result, VirtualMachine) + assert result.name == vm_name + assert result.location == "eastus" + assert result.type == "Microsoft.Compute/virtualMachinesShared" + assert result.properties is not None + assert result.properties.provisioning_state == "Succeeded" + assert result.properties.metadata is not None + assert result.properties.metadata.created_by == "user@example.com" + assert result.properties.metadata.tags == {"environment": "production"} + + +@pytest.mark.asyncio +async def test_virtual_machines_create_or_update(client): + """Test creating or updating a virtual machine with shared metadata.""" + resource_group_name = "test-rg" + vm_name = "vm-shared1" + + vm_resource = VirtualMachine( + location="eastus", + properties=VirtualMachineProperties( + metadata=SharedMetadata( + created_by="user@example.com", + tags={"environment": "production"}, + ), + ), + ) + + poller = await client.virtual_machines.begin_create_or_update( + resource_group_name=resource_group_name, + vm_name=vm_name, + resource=vm_resource, + ) + + result = await poller.result() + assert result is not None + assert isinstance(result, VirtualMachine) + assert result.location == "eastus" + assert result.properties is not None + assert result.properties.provisioning_state == "Succeeded" + assert result.properties.metadata is not None + assert result.properties.metadata.created_by == "user@example.com" + assert result.properties.metadata.tags == {"environment": "production"} + + +@pytest.mark.asyncio +async def test_storage_accounts_get(client): + """Test getting a storage account with shared metadata.""" + resource_group_name = "test-rg" + account_name = "account1" + + result = await client.storage_accounts.get(resource_group_name=resource_group_name, account_name=account_name) + + assert result is not None + assert isinstance(result, StorageAccount) + assert result.name == account_name + assert result.location == "westus" + assert result.type == "Microsoft.Storage/storageAccounts" + assert result.properties is not None + assert result.properties.provisioning_state == "Succeeded" + assert result.properties.metadata is not None + assert result.properties.metadata.created_by == "admin@example.com" + assert result.properties.metadata.tags == {"department": "engineering"} + + +@pytest.mark.asyncio +async def test_storage_accounts_create_or_update(client): + """Test creating or updating a storage account with shared metadata.""" + resource_group_name = "test-rg" + account_name = "account1" + + storage_resource = StorageAccount( + location="westus", + properties=StorageAccountProperties( + metadata=SharedMetadata( + created_by="admin@example.com", + tags={"department": "engineering"}, + ), + ), + ) + + poller = await client.storage_accounts.begin_create_or_update( + resource_group_name=resource_group_name, + account_name=account_name, + resource=storage_resource, + ) + + result = await poller.result() + assert result is not None + assert isinstance(result, StorageAccount) + assert result.location == "westus" + assert result.properties is not None + assert result.properties.provisioning_state == "Succeeded" + assert result.properties.metadata is not None + assert result.properties.metadata.created_by == "admin@example.com" + assert result.properties.metadata.tags == {"department": "engineering"} diff --git a/packages/typespec-python/tests/mock_api/azure/asynctests/test_azure_special_headers_client_request_id_async.py b/packages/typespec-python/tests/mock_api/azure/asynctests/test_azure_special_headers_client_request_id_async.py new file mode 100644 index 0000000000..eb066f8427 --- /dev/null +++ b/packages/typespec-python/tests/mock_api/azure/asynctests/test_azure_special_headers_client_request_id_async.py @@ -0,0 +1,31 @@ +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- +import functools + +import pytest +import pytest_asyncio + +from azure.specialheaders.xmsclientrequestid.aio import XmsClientRequestIdClient + + +@pytest_asyncio.fixture +async def client(): + async with XmsClientRequestIdClient() as client: + yield client + + +@pytest.mark.asyncio +async def test_get(client: XmsClientRequestIdClient, check_client_request_id_header): + checked = {} + result, resp = await client.get( + cls=lambda x, y, z: (y, x), + raw_request_hook=functools.partial( + check_client_request_id_header, header="x-ms-client-request-id", checked=checked + ), + ) + assert result is None + assert resp.http_response.headers["x-ms-client-request-id"] == checked["x-ms-client-request-id"] + pass diff --git a/packages/typespec-python/tests/mock_api/azure/asynctests/test_azure_versioning_previewversion_async.py b/packages/typespec-python/tests/mock_api/azure/asynctests/test_azure_versioning_previewversion_async.py new file mode 100644 index 0000000000..a7d6d3d54c --- /dev/null +++ b/packages/typespec-python/tests/mock_api/azure/asynctests/test_azure_versioning_previewversion_async.py @@ -0,0 +1,54 @@ +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- +import pytest +import pytest_asyncio +from specs.azure.versioning.previewversion.aio import PreviewVersionClient +from specs.azure.versioning.previewversion.models import UpdateWidgetColorRequest + + +@pytest_asyncio.fixture +async def client(): + async with PreviewVersionClient() as client: + yield client + + +@pytest_asyncio.fixture +async def stable_client(): + async with PreviewVersionClient(api_version="2024-06-01") as client: + yield client + + +@pytest.mark.asyncio +async def test_get_widget(client: PreviewVersionClient): + result = await client.get_widget(id="widget-123") + assert result.id == "widget-123" + assert result.name == "Sample Widget" + assert result.color == "blue" + + +@pytest.mark.asyncio +async def test_update_widget_color(client: PreviewVersionClient): + color_update = UpdateWidgetColorRequest(color="red") + result = await client.update_widget_color(id="widget-123", color_update=color_update) + assert result.id == "widget-123" + assert result.name == "Sample Widget" + assert result.color == "red" + + with pytest.raises(ValueError): + async with PreviewVersionClient(api_version="2024-06-01") as stable_client: + await stable_client.update_widget_color(id="widget-123", color_update=color_update) + + +@pytest.mark.asyncio +async def test_list_widgets(stable_client: PreviewVersionClient): + result = await stable_client.list_widgets(name="test") + assert len(result.widgets) == 1 + assert result.widgets[0].id == "widget-1" + assert result.widgets[0].name == "test" + + with pytest.raises(ValueError): + async with PreviewVersionClient(api_version="2024-06-01") as client: + await client.list_widgets(name="test", color="test") diff --git a/packages/typespec-python/tests/mock_api/azure/asynctests/test_client_namespace_async.py b/packages/typespec-python/tests/mock_api/azure/asynctests/test_client_namespace_async.py new file mode 100644 index 0000000000..06812847e2 --- /dev/null +++ b/packages/typespec-python/tests/mock_api/azure/asynctests/test_client_namespace_async.py @@ -0,0 +1,35 @@ +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- +import pytest +import pytest_asyncio +from client.clientnamespace.aio import ClientNamespaceFirstClient +from client.clientnamespace.first.models import FirstClientResult + +from client.clientnamespace.second.aio import ClientNamespaceSecondClient +from client.clientnamespace.second.models import SecondClientResult +from client.clientnamespace.second.sub.models import SecondClientEnumType + + +@pytest_asyncio.fixture +async def first_client(): + async with ClientNamespaceFirstClient() as client: + yield client + + +@pytest_asyncio.fixture +async def second_client(): + async with ClientNamespaceSecondClient() as client: + yield client + + +@pytest.mark.asyncio +async def test_get_first(first_client: ClientNamespaceFirstClient): + assert await first_client.get_first() == FirstClientResult(name="first") + + +@pytest.mark.asyncio +async def test_get_second(second_client: ClientNamespaceSecondClient): + assert await second_client.get_second() == SecondClientResult(type=SecondClientEnumType.SECOND) diff --git a/packages/typespec-python/tests/mock_api/azure/asynctests/test_client_naming_async.py b/packages/typespec-python/tests/mock_api/azure/asynctests/test_client_naming_async.py new file mode 100644 index 0000000000..9a3f249740 --- /dev/null +++ b/packages/typespec-python/tests/mock_api/azure/asynctests/test_client_naming_async.py @@ -0,0 +1,70 @@ +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- +import pytest +import pytest_asyncio +from client.naming.main.aio import NamingClient +from client.naming.main import models + + +@pytest_asyncio.fixture +async def client(): + async with NamingClient() as client: + yield client + + +@pytest.mark.asyncio +async def test_client(client: NamingClient): + await client.property.client(models.ClientNameModel(client_name=True)) + + +@pytest.mark.asyncio +async def test_language(client: NamingClient): + await client.property.language(models.LanguageClientNameModel(python_name=True)) + + +@pytest.mark.asyncio +async def test_compatible_with_encoded_name(client: NamingClient): + await client.property.compatible_with_encoded_name(models.ClientNameAndJsonEncodedNameModel(client_name=True)) + + +@pytest.mark.asyncio +async def test_operation(client: NamingClient): + await client.client_name() + + +@pytest.mark.asyncio +async def test_parameter(client: NamingClient): + await client.parameter(client_name="true") + + +@pytest.mark.asyncio +async def test_header_request(client: NamingClient): + await client.header.request(client_name="true") + + +@pytest.mark.asyncio +async def test_header_response(client: NamingClient): + assert (await client.header.response(cls=lambda x, y, z: z))["default-name"] == "true" + + +@pytest.mark.asyncio +async def test_model_client(client: NamingClient): + await client.model_client.client(models.ClientModel(default_name=True)) + + +@pytest.mark.asyncio +async def test_model_language(client: NamingClient): + await client.model_client.language(models.PythonModel(default_name=True)) + + +@pytest.mark.asyncio +async def test_union_enum_member_name(client: NamingClient): + await client.union_enum.union_enum_member_name(models.ExtensibleEnum.CLIENT_ENUM_VALUE1) + + +@pytest.mark.asyncio +async def test_union_enum_name(client: NamingClient): + await client.union_enum.union_enum_name(models.ClientExtensibleEnum.ENUM_VALUE1) diff --git a/packages/typespec-python/tests/mock_api/azure/asynctests/test_client_naming_enum_conflict_async.py b/packages/typespec-python/tests/mock_api/azure/asynctests/test_client_naming_enum_conflict_async.py new file mode 100644 index 0000000000..edcf008684 --- /dev/null +++ b/packages/typespec-python/tests/mock_api/azure/asynctests/test_client_naming_enum_conflict_async.py @@ -0,0 +1,38 @@ +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- +import pytest +import pytest_asyncio +from client.naming.enumconflict.aio import EnumConflictClient +from client.naming.enumconflict.firstnamespace import models as first_models +from client.naming.enumconflict.secondnamespace import models as second_models + + +@pytest_asyncio.fixture +async def client(): + async with EnumConflictClient() as client: + yield client + + +@pytest.mark.asyncio +async def test_first_operations_first_async(client: EnumConflictClient): + """Test enum with same name in different namespace - first namespace (async).""" + body = first_models.FirstModel(status=first_models.Status.ACTIVE, name="test") + + response = await client.first_operations.first(body=body) + + assert response.status == "active" + assert response.name == "test" + + +@pytest.mark.asyncio +async def test_second_operations_second_async(client: EnumConflictClient): + """Test enum with same name in different namespace - second namespace (async).""" + body = second_models.SecondModel(status=second_models.SecondStatus.RUNNING, description="test description") + + response = await client.second_operations.second(body=body) + + assert response.status == "running" + assert response.description == "test description" diff --git a/packages/typespec-python/tests/mock_api/azure/asynctests/test_client_overload_async.py b/packages/typespec-python/tests/mock_api/azure/asynctests/test_client_overload_async.py new file mode 100644 index 0000000000..4d4e04cbe7 --- /dev/null +++ b/packages/typespec-python/tests/mock_api/azure/asynctests/test_client_overload_async.py @@ -0,0 +1,27 @@ +import pytest +from client.overload.aio import OverloadClient + + +class TestClientOverloadAsync: + @pytest.fixture + def client(self): + return OverloadClient(endpoint="http://localhost:3000") + + @pytest.mark.asyncio + async def test_list(self, client: OverloadClient): + result = await client.list() + assert len(result) == 2 + assert result[0]["id"] == "1" + assert result[0]["name"] == "foo" + assert result[0]["scope"] == "car" + assert result[1]["id"] == "2" + assert result[1]["name"] == "bar" + assert result[1]["scope"] == "bike" + + @pytest.mark.asyncio + async def test_list_by_scope(self, client: OverloadClient): + result = await client.list_by_scope("car") + assert len(result) == 1 + assert result[0]["id"] == "1" + assert result[0]["name"] == "foo" + assert result[0]["scope"] == "car" diff --git a/packages/typespec-python/tests/mock_api/azure/asynctests/test_client_structure_async.py b/packages/typespec-python/tests/mock_api/azure/asynctests/test_client_structure_async.py new file mode 100644 index 0000000000..8d17c7a069 --- /dev/null +++ b/packages/typespec-python/tests/mock_api/azure/asynctests/test_client_structure_async.py @@ -0,0 +1,62 @@ +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- +import pytest +from client.structure.service.models import ClientType +from client.structure.service.aio import ServiceClient +from client.structure.multiclient.aio import ClientAClient, ClientBClient +from client.structure.renamedoperation.aio import RenamedOperationClient +from client.structure.twooperationgroup.aio import TwoOperationGroupClient + + +@pytest.mark.asyncio +async def test_structure_default(): + client = ServiceClient(endpoint="http://localhost:3000", client=ClientType.DEFAULT) + await client.one() + await client.two() + await client.foo.three() + await client.foo.four() + await client.bar.five() + await client.bar.six() + await client.baz.foo.seven() + await client.qux.eight() + await client.qux.bar.nine() + + +@pytest.mark.asyncio +async def test_structure_multiclient(): + client_a = ClientAClient(endpoint="http://localhost:3000", client=ClientType.MULTI_CLIENT) + await client_a.renamed_one() + await client_a.renamed_three() + await client_a.renamed_five() + + client_b = ClientBClient(endpoint="http://localhost:3000", client=ClientType.MULTI_CLIENT) + await client_b.renamed_two() + await client_b.renamed_four() + await client_b.renamed_six() + + +@pytest.mark.asyncio +async def test_structure_renamed_operation(): + client = RenamedOperationClient(endpoint="http://localhost:3000", client=ClientType.RENAMED_OPERATION) + await client.renamed_one() + await client.renamed_three() + await client.renamed_five() + + await client.group.renamed_two() + await client.group.renamed_four() + await client.group.renamed_six() + + +@pytest.mark.asyncio +async def test_structure_two_operation_group(): + client = TwoOperationGroupClient(endpoint="http://localhost:3000", client=ClientType.TWO_OPERATION_GROUP) + await client.group1.one() + await client.group1.three() + await client.group1.four() + + await client.group2.two() + await client.group2.five() + await client.group2.six() diff --git a/packages/typespec-python/tests/mock_api/azure/asynctests/test_client_structure_clientoperationgroup_async.py b/packages/typespec-python/tests/mock_api/azure/asynctests/test_client_structure_clientoperationgroup_async.py new file mode 100644 index 0000000000..96f1157418 --- /dev/null +++ b/packages/typespec-python/tests/mock_api/azure/asynctests/test_client_structure_clientoperationgroup_async.py @@ -0,0 +1,29 @@ +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- +import pytest +from client.structure.clientoperationgroup.models import ClientType +from client.structure.clientoperationgroup.aio import FirstClient, SecondClient + + +@pytest.mark.asyncio +async def test_first_client_operations(): + client = FirstClient(endpoint="http://localhost:3000", client=ClientType.CLIENT_OPERATION_GROUP) + + await client.one() + + await client.group3.two() + await client.group3.three() + + await client.group4.four() + + +@pytest.mark.asyncio +async def test_second_client_operations(): + client = SecondClient(endpoint="http://localhost:3000", client=ClientType.CLIENT_OPERATION_GROUP) + + await client.five() + + await client.group5.six() diff --git a/packages/typespec-python/tests/mock_api/azure/asynctests/test_encode_duration_async.py b/packages/typespec-python/tests/mock_api/azure/asynctests/test_encode_duration_async.py new file mode 100644 index 0000000000..b79a501903 --- /dev/null +++ b/packages/typespec-python/tests/mock_api/azure/asynctests/test_encode_duration_async.py @@ -0,0 +1,64 @@ +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- +import datetime + +import pytest +import pytest_asyncio +from encode.duration.aio import DurationClient +from encode.duration.models import ( + Int32SecondsDurationProperty, + ISO8601DurationProperty, + FloatSecondsDurationProperty, + DefaultDurationProperty, + FloatSecondsDurationArrayProperty, +) + + +@pytest_asyncio.fixture +async def client(): + async with DurationClient() as client: + yield client + + +@pytest.mark.asyncio +async def test_query(client: DurationClient): + await client.query.default(input=datetime.timedelta(days=40)) + await client.query.iso8601(input=datetime.timedelta(days=40)) + await client.query.int32_seconds(input=36) + await client.query.int32_seconds_array(input=[36, 47]) + await client.query.float_seconds(input=35.625) + await client.query.float64_seconds(input=35.625) + + +@pytest.mark.asyncio +async def test_property(client: DurationClient): + result = await client.property.default(DefaultDurationProperty(value=datetime.timedelta(days=40))) + assert result.value == datetime.timedelta(days=40) + result = await client.property.default(DefaultDurationProperty(value="P40D")) + assert result.value == datetime.timedelta(days=40) + result = await client.property.iso8601(ISO8601DurationProperty(value=datetime.timedelta(days=40))) + assert result.value == datetime.timedelta(days=40) + result = await client.property.iso8601(ISO8601DurationProperty(value="P40D")) + assert result.value == datetime.timedelta(days=40) + result = await client.property.int32_seconds(Int32SecondsDurationProperty(value=36)) + assert result.value == 36 + result = await client.property.float_seconds(FloatSecondsDurationProperty(value=35.625)) + assert abs(result.value - 35.625) < 0.0001 + result = await client.property.float64_seconds(FloatSecondsDurationProperty(value=35.625)) + assert abs(result.value - 35.625) < 0.0001 + result = await client.property.float_seconds_array(FloatSecondsDurationArrayProperty(value=[35.625, 46.75])) + assert abs(result.value[0] - 35.625) < 0.0001 + assert abs(result.value[1] - 46.75) < 0.0001 + + +@pytest.mark.asyncio +async def test_header(client: DurationClient): + await client.header.default(duration=datetime.timedelta(days=40)) + await client.header.iso8601(duration=datetime.timedelta(days=40)) + await client.header.iso8601_array(duration=[datetime.timedelta(days=40), datetime.timedelta(days=50)]) + await client.header.int32_seconds(duration=36) + await client.header.float_seconds(duration=35.625) + await client.header.float64_seconds(duration=35.625) diff --git a/packages/typespec-python/tests/mock_api/azure/asynctests/test_encode_numeric_async.py b/packages/typespec-python/tests/mock_api/azure/asynctests/test_encode_numeric_async.py new file mode 100644 index 0000000000..a3a8a4d1fe --- /dev/null +++ b/packages/typespec-python/tests/mock_api/azure/asynctests/test_encode_numeric_async.py @@ -0,0 +1,36 @@ +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- +import pytest +import pytest_asyncio +from encode.numeric.aio import NumericClient +from encode.numeric import models + + +@pytest_asyncio.fixture +async def client(): + async with NumericClient() as client: + yield client + + +@pytest.mark.asyncio +async def test_safeint_as_string(client: NumericClient): + result = await client.property.safeint_as_string(models.SafeintAsStringProperty(value=10000000000)) + assert result.value == 10000000000 + assert result["value"] == "10000000000" + + +@pytest.mark.asyncio +async def test_uint32_as_string_optional(client: NumericClient): + result = await client.property.uint32_as_string_optional(models.Uint32AsStringProperty(value=1)) + assert result.value == 1 + assert result["value"] == "1" + + +@pytest.mark.asyncio +async def test_uint8_as_string_optional(client: NumericClient): + result = await client.property.uint8_as_string(models.Uint32AsStringProperty(value=255)) + assert result.value == 255 + assert result["value"] == "255" diff --git a/packages/typespec-python/tests/mock_api/azure/asynctests/test_parameters_basic_async.py b/packages/typespec-python/tests/mock_api/azure/asynctests/test_parameters_basic_async.py new file mode 100644 index 0000000000..2b53806b4c --- /dev/null +++ b/packages/typespec-python/tests/mock_api/azure/asynctests/test_parameters_basic_async.py @@ -0,0 +1,25 @@ +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- +import pytest +import pytest_asyncio +from parameters.basic.aio import BasicClient +from parameters.basic.models import User + + +@pytest_asyncio.fixture +async def client(): + async with BasicClient() as client: + yield client + + +@pytest.mark.asyncio +async def test_explicit_simple(client: BasicClient): + await client.explicit_body.simple(User(name="foo")) + + +@pytest.mark.asyncio +async def test_implicit_simple(client: BasicClient): + await client.implicit_body.simple(name="foo") diff --git a/packages/typespec-python/tests/mock_api/azure/asynctests/test_parameters_spread_async.py b/packages/typespec-python/tests/mock_api/azure/asynctests/test_parameters_spread_async.py new file mode 100644 index 0000000000..9fa0802863 --- /dev/null +++ b/packages/typespec-python/tests/mock_api/azure/asynctests/test_parameters_spread_async.py @@ -0,0 +1,77 @@ +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- +import pytest +import pytest_asyncio +from parameters.spread.aio import SpreadClient +from parameters.spread.models import BodyParameter + + +@pytest_asyncio.fixture +async def client(): + async with SpreadClient() as client: + yield client + + +@pytest.mark.asyncio +async def test_model_body(client: SpreadClient): + await client.model.spread_as_request_body(name="foo") + + +@pytest.mark.asyncio +async def test_model_composite_request_only_with_body(client: SpreadClient): + await client.model.spread_composite_request_only_with_body(BodyParameter(name="foo")) + + +@pytest.mark.asyncio +async def test_model_composite_request_without_body(client: SpreadClient): + await client.model.spread_composite_request_without_body(name="foo", test_header="bar") + + +@pytest.mark.asyncio +async def test_model_composite_request(client: SpreadClient): + await client.model.spread_composite_request(name="foo", body=BodyParameter(name="foo"), test_header="bar") + + +@pytest.mark.asyncio +async def test_model_composite_request_mix(client: SpreadClient): + await client.model.spread_composite_request_mix(name="foo", prop="foo", test_header="bar") + + +@pytest.mark.asyncio +async def test_alias_body(client: SpreadClient): + await client.alias.spread_as_request_body(name="foo") + + +@pytest.mark.asyncio +async def test_alias_parameter(client: SpreadClient): + await client.alias.spread_as_request_parameter("1", x_ms_test_header="bar", name="foo") + + +@pytest.mark.asyncio +async def test_alias_multiple_parameter(client: SpreadClient): + await client.alias.spread_with_multiple_parameters( + "1", + x_ms_test_header="bar", + required_string="foo", + required_int_list=[1, 2], + optional_string_list=["foo", "bar"], + optional_int=1, + ) + await client.alias.spread_with_multiple_parameters( + "1", + {"requiredString": "foo", "optionalInt": 1, "requiredIntList": [1, 2], "optionalStringList": ["foo", "bar"]}, + x_ms_test_header="bar", + ) + + +@pytest.mark.asyncio +async def test_inner_model(client: SpreadClient): + await client.alias.spread_parameter_with_inner_model(id="1", x_ms_test_header="bar", body={"name": "foo"}) + + +@pytest.mark.asyncio +async def test_inner_alias(client: SpreadClient): + await client.alias.spread_parameter_with_inner_alias(id="1", x_ms_test_header="bar", body={"name": "foo", "age": 1}) diff --git a/packages/typespec-python/tests/mock_api/azure/asynctests/test_payload_content_negotiation_async.py b/packages/typespec-python/tests/mock_api/azure/asynctests/test_payload_content_negotiation_async.py new file mode 100644 index 0000000000..84ec7ba708 --- /dev/null +++ b/packages/typespec-python/tests/mock_api/azure/asynctests/test_payload_content_negotiation_async.py @@ -0,0 +1,38 @@ +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- +import base64 +import pytest +import pytest_asyncio +from payload.contentnegotiation.aio import ContentNegotiationClient +from payload.contentnegotiation.models import PngImageAsJson + + +@pytest_asyncio.fixture +async def client(): + async with ContentNegotiationClient(endpoint="http://localhost:3000") as client: + yield client + + +@pytest.mark.asyncio +async def test_get_avatar_as_png(client: ContentNegotiationClient, png_data: bytes): + assert b"".join([d async for d in (await client.same_body.get_avatar_as_png())]) == png_data + + +@pytest.mark.asyncio +async def test_get_avatar_as_jpeg(client: ContentNegotiationClient, jpg_data: bytes): + assert b"".join([d async for d in (await client.same_body.get_avatar_as_jpeg())]) == jpg_data + + +@pytest.mark.asyncio +async def test_different_body_get_avatar_as_png(client: ContentNegotiationClient, png_data: bytes): + assert b"".join([d async for d in (await client.different_body.get_avatar_as_png())]) == png_data + + +@pytest.mark.asyncio +async def test_different_body_get_avatar_as_json(client: ContentNegotiationClient, png_data: bytes): + result = await client.different_body.get_avatar_as_json() + expected = PngImageAsJson(content=base64.b64encode(png_data).decode()) + assert result == expected diff --git a/packages/typespec-python/tests/mock_api/azure/asynctests/test_payload_multipart_async.py b/packages/typespec-python/tests/mock_api/azure/asynctests/test_payload_multipart_async.py new file mode 100644 index 0000000000..03668f5ddb --- /dev/null +++ b/packages/typespec-python/tests/mock_api/azure/asynctests/test_payload_multipart_async.py @@ -0,0 +1,217 @@ +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- +from pathlib import Path +import pytest +import pytest_asyncio +from payload.multipart import models +from payload.multipart.aio import MultiPartClient + +JPG = Path(__file__).parent.parent / "data/image.jpg" +PNG = Path(__file__).parent.parent / "data/image.png" + + +@pytest_asyncio.fixture +async def client(): + async with MultiPartClient(endpoint="http://localhost:3000") as client: + yield client + + +@pytest.mark.asyncio +async def test_anonymous_model(client: MultiPartClient): + await client.form_data.anonymous_model({"profileImage": open(str(JPG), "rb")}) + + +@pytest.mark.asyncio +async def test_basic(client: MultiPartClient): + await client.form_data.basic( + models.MultiPartRequest( + id="123", + profile_image=open(str(JPG), "rb"), + ) + ) + + +@pytest.mark.asyncio +async def test_binary_array_parts(client: MultiPartClient): + await client.form_data.binary_array_parts( + models.BinaryArrayPartsRequest( + id="123", + pictures=[ + open(str(PNG), "rb"), + open(str(PNG), "rb"), + ], + ) + ) + + +@pytest.mark.asyncio +async def test_check_file_name_and_content_type(client: MultiPartClient): + await client.form_data.check_file_name_and_content_type( + models.MultiPartRequest( + id="123", + profile_image=("hello.jpg", open(str(JPG), "rb"), "image/jpg"), + ) + ) + + +@pytest.mark.asyncio +async def test_complex(client: MultiPartClient): + await client.form_data.file_array_and_basic( + models.ComplexPartsRequest( + id="123", + address=models.Address(city="X"), + pictures=[ + open(str(PNG), "rb"), + open(str(PNG), "rb"), + ], + profile_image=open(str(JPG), "rb"), + ) + ) + + +@pytest.mark.asyncio +async def test_json_part(client: MultiPartClient): + await client.form_data.json_part( + models.JsonPartRequest( + address=models.Address(city="X"), + profile_image=open(str(JPG), "rb"), + ) + ) + + +@pytest.mark.asyncio +async def test_multi_binary_parts(client: MultiPartClient): + await client.form_data.multi_binary_parts( + models.MultiBinaryPartsRequest( + profile_image=open(str(JPG), "rb"), + picture=open(str(PNG), "rb"), + ) + ) + await client.form_data.multi_binary_parts( + models.MultiBinaryPartsRequest( + profile_image=open(str(JPG), "rb"), + ) + ) + + +@pytest.mark.asyncio +async def test_file_with_http_part_specific_content_type(client: MultiPartClient): + await client.form_data.http_parts.content_type.image_jpeg_content_type( + models.FileWithHttpPartSpecificContentTypeRequest( + profile_image=("hello.jpg", open(str(JPG), "rb"), "image/jpg"), + ) + ) + + +@pytest.mark.asyncio +async def test_file_with_http_part_required_content_type(client: MultiPartClient): + await client.form_data.http_parts.content_type.required_content_type( + models.FileWithHttpPartRequiredContentTypeRequest( + profile_image=open(str(JPG), "rb"), + ) + ) + + +@pytest.mark.asyncio +async def test_file_with_http_part_optional_content_type(client: MultiPartClient): + # call twice: one with content type, one without + await client.form_data.http_parts.content_type.optional_content_type( + models.FileWithHttpPartOptionalContentTypeRequest( + profile_image=("hello.jpg", open(str(JPG), "rb").read()), + ) + ) + await client.form_data.http_parts.content_type.optional_content_type( + models.FileWithHttpPartOptionalContentTypeRequest( + profile_image=("hello.jpg", open(str(JPG), "rb").read(), "application/octet-stream"), + ) + ) + + +@pytest.mark.asyncio +async def test_complex_with_http_part(client: MultiPartClient): + await client.form_data.http_parts.json_array_and_file_array( + models.ComplexHttpPartsModelRequest( + id="123", + previous_addresses=[ + models.Address(city="Y"), + models.Address(city="Z"), + ], + address=models.Address(city="X"), + pictures=[ + open(str(PNG), "rb"), + open(str(PNG), "rb"), + ], + profile_image=open(str(JPG), "rb"), + ) + ) + + +@pytest.mark.asyncio +async def test_http_parts_non_string_float(client: MultiPartClient): + await client.form_data.http_parts.non_string.float(models.FloatRequest(temperature=0.5)) + + +@pytest.mark.asyncio +async def test_with_wire_name(client: MultiPartClient): + await client.form_data.with_wire_name( + models.MultiPartRequestWithWireName( + identifier="123", + image=open(str(JPG), "rb"), + ) + ) + + +@pytest.mark.asyncio +async def test_optional_parts(client: MultiPartClient): + # First time with only id + await client.form_data.optional_parts( + models.MultiPartOptionalRequest( + id="123", + ) + ) + # Second time with only profileImage + await client.form_data.optional_parts( + models.MultiPartOptionalRequest( + profile_image=open(str(JPG), "rb"), + ) + ) + # Third time with both id and profileImage + await client.form_data.optional_parts( + models.MultiPartOptionalRequest( + id="123", + profile_image=open(str(JPG), "rb"), + ) + ) + + +@pytest.mark.asyncio +async def test_file_upload_file_specific_content_type(client: MultiPartClient): + await client.form_data.file.upload_file_specific_content_type( + models.UploadFileSpecificContentTypeRequest( + file=("image.png", open(str(PNG), "rb"), "image/png"), + ) + ) + + +@pytest.mark.asyncio +async def test_file_upload_file_required_filename(client: MultiPartClient): + await client.form_data.file.upload_file_required_filename( + models.UploadFileRequiredFilenameRequest( + file=("image.png", open(str(PNG), "rb"), "image/png"), + ) + ) + + +@pytest.mark.asyncio +async def test_file_upload_file_array(client: MultiPartClient): + await client.form_data.file.upload_file_array( + models.UploadFileArrayRequest( + files=[ + ("image.png", open(str(PNG), "rb"), "image/png"), + ("image.png", open(str(PNG), "rb"), "image/png"), + ], + ) + ) diff --git a/packages/typespec-python/tests/mock_api/azure/asynctests/test_resiliency_srv_driven_async.py b/packages/typespec-python/tests/mock_api/azure/asynctests/test_resiliency_srv_driven_async.py new file mode 100644 index 0000000000..290e3b68cb --- /dev/null +++ b/packages/typespec-python/tests/mock_api/azure/asynctests/test_resiliency_srv_driven_async.py @@ -0,0 +1,130 @@ +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- +import pytest +from resiliency.srv.driven1.aio import ResiliencyServiceDrivenClient as V1Client +from resiliency.srv.driven2.aio import ResiliencyServiceDrivenClient as V2Client + + +def get_v1_client(service_deployment_version: str, api_version: str = "v1") -> V1Client: + return V1Client( + endpoint="http://localhost:3000", + service_deployment_version=service_deployment_version, + api_version=api_version, + ) + + +def get_v2_client(service_deployment_version: str, api_version: str = "v2") -> V2Client: + return V2Client( + endpoint="http://localhost:3000", + service_deployment_version=service_deployment_version, + api_version=api_version, + ) + + +@pytest.mark.asyncio +async def test_add_optional_param_from_none(): + # old client to old service with api version v1 + async with V1Client(endpoint="http://localhost:3000", service_deployment_version="v1") as client: + await client.from_none() + + # old client to new service with api version v1 + async with V1Client(endpoint="http://localhost:3000", service_deployment_version="v2") as client: + await client.from_none() + + # new client to new service with api version v1 + async with V2Client( + endpoint="http://localhost:3000", + service_deployment_version="v2", + api_version="v1", + ) as client: + await client.from_none() + + # new client to new service with api version v2 + async with V2Client(endpoint="http://localhost:3000", service_deployment_version="v2") as client: + await client.from_none(new_parameter="new") + + +@pytest.mark.asyncio +async def test_add_optional_param_from_one_required(): + # old client to old service with api version v1 + async with V1Client(endpoint="http://localhost:3000", service_deployment_version="v1") as client: + await client.from_one_required(parameter="required") + + # old client to new service with api version v1 + async with V1Client(endpoint="http://localhost:3000", service_deployment_version="v2") as client: + await client.from_one_required(parameter="required") + + # new client to new service with api version v1 + async with V2Client( + endpoint="http://localhost:3000", + service_deployment_version="v2", + api_version="v1", + ) as client: + await client.from_one_required(parameter="required") + + # new client to new service with api version v2 + async with V2Client(endpoint="http://localhost:3000", service_deployment_version="v2") as client: + await client.from_one_required(parameter="required", new_parameter="new") + + +@pytest.mark.asyncio +async def test_add_optional_param_from_one_optional(): + # old client to old service with api version v1 + async with V1Client(endpoint="http://localhost:3000", service_deployment_version="v1") as client: + await client.from_one_optional(parameter="optional") + + # old client to new service with api version v1 + async with V1Client(endpoint="http://localhost:3000", service_deployment_version="v2") as client: + await client.from_one_optional(parameter="optional") + + # new client to new service with api version v1 + async with V2Client( + endpoint="http://localhost:3000", + service_deployment_version="v2", + api_version="v1", + ) as client: + await client.from_one_optional(parameter="optional") + + # new client to new service with api version v2 + async with V2Client(endpoint="http://localhost:3000", service_deployment_version="v2") as client: + await client.from_one_optional(parameter="optional", new_parameter="new") + + +@pytest.mark.asyncio +async def test_break_the_glass(): + from azure.core.rest import HttpRequest + + request = HttpRequest(method="DELETE", url="/add-operation") + async with V1Client( + endpoint="http://localhost:3000", + service_deployment_version="v2", + api_version="v2", + ) as client: + response = await client.send_request(request) + response.raise_for_status() + + +@pytest.mark.asyncio +async def test_add_operation(): + async with V2Client(endpoint="http://localhost:3000", service_deployment_version="v2") as client: + await client.add_operation() + + +@pytest.mark.parametrize( + "func_name, params", + [ + ("from_none", {"new_parameter": "new"}), + ("from_one_optional", {"parameter": "optional", "new_parameter": "new"}), + ("from_one_required", {"parameter": "required", "new_parameter": "new"}), + ("add_operation", {}), + ], +) +@pytest.mark.asyncio +async def test_new_client_with_old_apiversion_call_new_parameter(func_name, params): + client = get_v2_client(service_deployment_version="v2", api_version="v1") + with pytest.raises(ValueError) as ex: + await getattr(client, func_name)(**params) + assert "is not available in API version" in str(ex.value) diff --git a/packages/typespec-python/tests/mock_api/azure/asynctests/test_serialization_encoded_name_json_async.py b/packages/typespec-python/tests/mock_api/azure/asynctests/test_serialization_encoded_name_json_async.py new file mode 100644 index 0000000000..76594bbce5 --- /dev/null +++ b/packages/typespec-python/tests/mock_api/azure/asynctests/test_serialization_encoded_name_json_async.py @@ -0,0 +1,25 @@ +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- +import pytest +import pytest_asyncio +from serialization.encodedname.json.aio import JsonClient +from serialization.encodedname.json import models + + +@pytest_asyncio.fixture +async def client(): + async with JsonClient() as client: + yield client + + +@pytest.mark.asyncio +async def test_property_send(client: JsonClient): + await client.property.send(models.JsonEncodedNameModel(default_name=True)) + + +@pytest.mark.asyncio +async def test_property_get(client: JsonClient): + assert (await client.property.get()).default_name diff --git a/packages/typespec-python/tests/mock_api/azure/asynctests/test_service_multi_service_async.py b/packages/typespec-python/tests/mock_api/azure/asynctests/test_service_multi_service_async.py new file mode 100644 index 0000000000..07e04285c5 --- /dev/null +++ b/packages/typespec-python/tests/mock_api/azure/asynctests/test_service_multi_service_async.py @@ -0,0 +1,31 @@ +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- +import pytest +from azure.core.exceptions import HttpResponseError +from service.multiservice.aio import CombinedClient +from service.multiservice.models import VersionsA, VersionsB + + +@pytest.fixture +def client(): + """Fixture that creates a CombinedClient for testing.""" + return CombinedClient(endpoint="http://localhost:3000") + + +@pytest.mark.asyncio +async def test_service_multi_service_foo(client): + with pytest.raises(HttpResponseError): + await client.foo.test(api_version=VersionsA.AV1) + + await client.foo.test() + + +@pytest.mark.asyncio +async def test_service_multi_service_bar(client): + with pytest.raises(HttpResponseError): + await client.bar.test(api_version=VersionsB.BV1) + + await client.bar.test() diff --git a/packages/typespec-python/tests/mock_api/azure/asynctests/test_special_words_async.py b/packages/typespec-python/tests/mock_api/azure/asynctests/test_special_words_async.py new file mode 100644 index 0000000000..8c59ea0507 --- /dev/null +++ b/packages/typespec-python/tests/mock_api/azure/asynctests/test_special_words_async.py @@ -0,0 +1,72 @@ +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- +import pytest +import pytest_asyncio +from specialwords.aio import SpecialWordsClient +from specialwords import models + + +@pytest_asyncio.fixture +async def client(): + async with SpecialWordsClient() as client: + yield client + + +@pytest.mark.asyncio +async def test_operations(client: SpecialWordsClient, special_words): + for sw in special_words: + suffix = "" if sw == "constructor" else "_method" + await getattr(client.operations, sw + suffix)() + + +@pytest.mark.asyncio +async def test_parameter(client: SpecialWordsClient, special_words): + for sw in special_words: + suffix = "" if sw == "constructor" else "_parameter" + await getattr(client.parameters, "with_" + sw)(**{sw + suffix: "ok"}) + await client.parameters.with_cancellation_token(cancellation_token="ok") + + +@pytest.mark.asyncio +async def test_model(client: SpecialWordsClient, special_words): + for sw in special_words: + suffix = "" if sw == "constructor" else "Model" + model = getattr(models, sw.capitalize() + suffix) + await getattr(client.models, "with_" + sw)(model(name="ok")) + + +@pytest.mark.asyncio +async def test_model_properties(client: SpecialWordsClient): + await client.model_properties.same_as_model(models.SameAsModel(same_as_model="ok")) + + +@pytest.mark.asyncio +async def test_model_properties_dict_methods(client: SpecialWordsClient): + await client.model_properties.dict_methods( + body=models.DictMethods( + keys_property="ok", + items_property="ok", + values_property="ok", + popitem_property="ok", + clear_property="ok", + update_property="ok", + setdefault_property="ok", + pop_property="ok", + get_property="ok", + copy_property="ok", + ) + ) + + +@pytest.mark.asyncio +async def test_model_properties_with_list(client: SpecialWordsClient): + await client.model_properties.with_list(models.ModelWithList(list="ok")) + + +@pytest.mark.asyncio +async def test_extensible_strings(client: SpecialWordsClient): + for enum_value in models.ExtensibleString: + assert enum_value == await client.extensible_strings.put_extensible_string_value(body=enum_value) diff --git a/packages/typespec-python/tests/mock_api/azure/conftest.py b/packages/typespec-python/tests/mock_api/azure/conftest.py new file mode 100644 index 0000000000..20d7152e5d --- /dev/null +++ b/packages/typespec-python/tests/mock_api/azure/conftest.py @@ -0,0 +1,179 @@ +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- +import pytest +import re +from typing import Literal +from pathlib import Path + +FILE_FOLDER = Path(__file__).parent + + +_VALID_UUID = re.compile(r"^[0-9a-f]{8}-([0-9a-f]{4}-){3}[0-9a-f]{12}$") +_VALID_RFC7231 = re.compile( + r"^(Mon|Tue|Wed|Thu|Fri|Sat|Sun),\s\d{2}\s" + r"(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)\s\d{4}\s\d{2}:\d{2}:\d{2}\sGMT$" +) + + +def validate_format(value: str, format: Literal["uuid", "rfc7231"]): + if format == "uuid": + assert _VALID_UUID.match(value) + elif format == "rfc7231": + assert _VALID_RFC7231.match(value) + else: + raise ValueError("Unknown format") + + +@pytest.fixture +def check_repeatability_header(): + def func(request): + validate_format(request.http_request.headers["Repeatability-Request-ID"], "uuid") + validate_format(request.http_request.headers["Repeatability-First-Sent"], "rfc7231") + + return func + + +@pytest.fixture +def check_client_request_id_header(): + def func(request, header: str, checked: dict): + validate_format(request.http_request.headers[header], "uuid") + checked[header] = request.http_request.headers[header] + + return func + + +# ================== after azure-core fix, the following code can be removed (begin) ================== +import urllib.parse +from azure.core.rest import HttpRequest + + +def update_api_version_of_status_link(status_link: str): + request_params = {} + parsed_status_link = urllib.parse.urlparse(status_link) + request_params = { + key.lower(): [urllib.parse.quote(v) for v in value] + for key, value in urllib.parse.parse_qs(parsed_status_link.query).items() + } + request_params["api-version"] = "2022-12-01-preview" + status_link = urllib.parse.urljoin(status_link, parsed_status_link.path) + return status_link, request_params + + +@pytest.fixture +def polling_method(): + from azure.core.polling.base_polling import LROBasePolling + + class TempLroBasePolling(LROBasePolling): + + def request_status(self, status_link: str): + if self._path_format_arguments: + status_link = self._client.format_url(status_link, **self._path_format_arguments) + status_link, request_params = update_api_version_of_status_link(status_link) + if "request_id" not in self._operation_config: + self._operation_config["request_id"] = self._get_request_id() + + rest_request = HttpRequest("GET", status_link, params=request_params) + return self._client.send_request(rest_request, _return_pipeline_response=True, **self._operation_config) + + return TempLroBasePolling(0) + + +@pytest.fixture +def async_polling_method(): + from azure.core.polling.async_base_polling import AsyncLROBasePolling + + class AsyncTempLroBasePolling(AsyncLROBasePolling): + + async def request_status(self, status_link: str): + if self._path_format_arguments: + status_link = self._client.format_url(status_link, **self._path_format_arguments) + status_link, request_params = update_api_version_of_status_link(status_link) + # Re-inject 'x-ms-client-request-id' while polling + if "request_id" not in self._operation_config: + self._operation_config["request_id"] = self._get_request_id() + + rest_request = HttpRequest("GET", status_link, params=request_params) + return await self._client.send_request( + rest_request, _return_pipeline_response=True, **self._operation_config + ) + + return AsyncTempLroBasePolling(0) + + +# ================== after azure-core fix, the up code can be removed (end) ================== + + +@pytest.fixture() +def credential(): + """I actually don't need anything, since the authentication policy + will bypass it. + """ + + class FakeCredential: + pass + + return FakeCredential() + + +@pytest.fixture() +def authentication_policy(): + from azure.core.pipeline.policies import SansIOHTTPPolicy + + return SansIOHTTPPolicy() + + +SPECIAL_WORDS = [ + "and", + "as", + "assert", + "async", + "await", + "break", + "class", + "constructor", + "continue", + "def", + "del", + "elif", + "else", + "except", + "exec", + "finally", + "for", + "from", + "global", + "if", + "import", + "in", + "is", + "lambda", + "not", + "or", + "pass", + "raise", + "return", + "try", + "while", + "with", + "yield", +] + + +@pytest.fixture +def special_words() -> list[str]: + return SPECIAL_WORDS + + +@pytest.fixture +def png_data() -> bytes: + with open(str(FILE_FOLDER / "data/image.png"), "rb") as file_in: + return file_in.read() + + +@pytest.fixture +def jpg_data() -> bytes: + with open(str(FILE_FOLDER / "data/image.jpg"), "rb") as file_in: + return file_in.read() diff --git a/packages/typespec-python/tests/mock_api/azure/data/image.jpg b/packages/typespec-python/tests/mock_api/azure/data/image.jpg new file mode 100644 index 0000000000000000000000000000000000000000..b95b3e7b58286ad3e665d98d48b345977f862403 GIT binary patch literal 4069 zcmeHJX;@QN8a_8Gn*#{~QJ4uNv1G6$BrHN6AVrn}mbL^3a4V7!OhA&51QRm!5kx@+ zTNcGZ6cC$Q+;~`GASla}wUxz{#c@GKXr)k4Y@<*!Hx%*D{OB`(hxgoj&v(xGzVDv* zyZ1cLYZx{>23FxAVIcs504RVPFpPlD9#xbBu1V2)YXM|gXB#0R#?0;vho@Ai`n{4K2Z_tc-vVNE8}_H8C|ahaEIl00AM92ow^HM!{MR`W#*d zC>$E^#0bDxN5*4GscV^8g=bC3n`_%`I5%f0?p)~sQ!`sT!n*Yv-gBn@)y2cpYm>JR zD=;WH4t_4#kAFVxjHXs&7-n{@yDwxhGFyQlZNTet7ry*D&GGCKBT{NGO}CV%+x+1&FN z^Dlq-RsZU>kryl_f2RdM|0^#X%nN}+AyHT(F9@M9633y?P7Dk_AQBs&YE5EhnXKJh zc(%6PlpPs~<`z2kKs1OmhoPzVGH-Zu)3MZ>_F zVvR60H(i4HGS)1?$_V@l3~&{b9rK09ND}!zi#oLh#Ro!~r%~ ztf@M>v0>6|AHFNXRdW{F2PwyE*zd{a+%36uhi4yu9aJ^ zpE7`9t8Rioz2KlN=S`ybbp-7ElQg->VN&I!l@n$S;9H_)yZXl$&PTX9ZObWvjhcE$f>gQt?~wSk)wt*@QfJ9e zFelD#>m0AB_sUj(c%Hr(E_yV;phB&=i9g9-)lO~OzQ2==_`u&bT{~<52lxK#Ow_NO zH{&-1-x&aQ;LQ0M(Zy$<1nTsq)xvVR{*&=ztX;IOz6|@z-F$Uf=(W0nyex6{P>FpW z4;0_dipualIew@$bH3M?aaJh~zSVba_s(ZYwY`7uX0rQ=C{sn1g*}wrL&Zt0cwal& z|(+)A&#XhLRoSPH3mt4Ji?-$~1F~yma)AnXu zRaaV$2SjEq$b{PVCY+v+iL;w8BOWVxgqdDst2gCLzog0=vM#q5L^ScNF_ipEjeb6n z1J0h4Y=S>iPa2P#Wgqq@^xWzm>-n^78z*$sXAucKo}EO|0uu3 zLs)^AUypvJF<+QUj|p5L&+NFzk0eJN%fi)?Gy8fd4jBz;gBAkjn_MPYks`G3a33&nP_o zg=l|nT>VF<@}|PZtIypU-TXbb#NA#UwTKA877jAo-sRoA;|O7M!oq~_ndaKA)cm{QH_jPuzCA+J zs!aHNWSYHBYfaj3>w14Gdb?$=t7cDh+;r%rP@Vlr;qGatS1nE0#?Fk+V2@G6gWq0G nRDbTJ{wDPH&YhvRw~$ZQH=nuD@w!Nwq+ZJbRY$2v!^nRCgjEVM literal 0 HcmV?d00001 diff --git a/packages/typespec-python/tests/mock_api/azure/data/image.png b/packages/typespec-python/tests/mock_api/azure/data/image.png new file mode 100644 index 0000000000000000000000000000000000000000..42fe8dc14560b0046bf0f3f00b7a471fa0346e36 GIT binary patch literal 2992 zcmaJ>2UJtr5=}ynfPe^6#i)oP2~A3b_#j9P<c=;9z@urf$wEd&r0Smmc~ z4b}n)eX~PAprkO6@Q)ZL0M}MJAZwiOD16}zNDSD?0g_k*{=o$NMUbCNY?07U9S+2S zEZop`b^yBJDZ#-+YAA`O;C(9uFi4PXy{I6N!uB-*+qrI=1#0z#xnpTqM+_2ABESQJ zNP)p{I)S{F2V_P^0xBVx7N9{V941ncbaU9Z2qd7dnGrCJZy~e@a~RgqMFUNu1Zx<< zb>X@&6jVb)!;BJi2rs64KWLg-BsIiteAdnPEGl#*}3jJK)-!qsV_Nx++`r}x@ z0TF8+gdSWM@iR9-HCwYHUBc+WhrO)A2tdz(8Yn{}vv1-5tZHzM{I(Zu9;;%|=s zCVEhVDQFS_C`d#7x~w1M-<>~*W{9LqLSH=UG`#0SvISvT&z^Cv#7@xJSx2aa-|9tm}-z6Hc>u#KDm+I4F>M3G9RmW+_?M2)1;gWo3xcVR@W8PHPH4h8*{++h z8}Y5F9`(=WPeZXH<+|Y0gJnwP5YL?0zo!3|^aN{T{s{OKE?O45QM0I0;1yDN`SND{ zyOg5mp)N5c(u0Esp-E=kfllR0C&k1s@i0GrZRfs5<7!+x0s^%ugM8%*ef;#PiEVR~ zk~180fRXw!|2qMhFy2QQNA)X#rKKLKFql@YS0DB+8Y~M0L6l6MBxAd5adGjcF9c8t zo3^yHG!i%{(t~?+_KjG%t?wg9W@hGn@>d^2zlX4eDsq69+{GOYhow*ZZ9YFY+;qgj z#AWZ^z2xho`YaYJ$mptuez>fhT&9eIf;49^mEC)&XN9ajcTsqPhD7C%d`TOUID=@6 zW~%vaGf31w{D~F5LO*H9Ul5b;M$_L~@5Rf{$YXmij@GSqZ($ztNsv;Z`i@;wgI)yL z`tVD3-D4YatT^h!2`{f7xgFBk(KVv6D=iyOe>q)Zxtu3f1vhZeoRRfQZ3s>DQ~|{c zhLZ7j^pqm{@Kbe|+)KiSAs)dZlW4Rb|0>x!mf7eaT?yRGZFm;h)5lP}0s z)MR+lRu=;7XofSxFZS5kB(Io?U<4$)=j+Ujv-f1z7}jT(U8oBF@c2?YjHZlX3}y?2 zB}I!j)%5LcxOt457x{YKwWQLqjkl*P!m*TD-H`cTuN{_G`e(Occ-dLa=;vA%@*AOg(a(z}6t_crT&EO-&+m4gF>N0h;BXG0?{Bi7 z`CMs0?IQEIN_yrvkTId}4tcQlLFDsm2){A5T)eb!$m;U*9bpNnS{u9Nur=c6{IY zKC28T*@~?E=+fvG1A<0jF;cm0Q(bSl;8d`tTUme#<>4g zLGy3~(+z4auzTu_$wj7=5_bmr4M3i>XprZ8-8A{ z^S%T(i(@^t7G<(wYTc~P^uFuDm}iOCg0RJbylL{6l)E9&xd*ipG|e`)b?b`n)|`3$ z>k`idS@_lp+*>nk7_W2qvLHrYsnN9VjcdkaYxRqWdf5!mZ8vsD^2e%lG>7`oaP1~( z91eF(@?7&4^jE^(0w>-(Xig#TL8J;KX+2YL&fdmGjCA1!I<+uYch0=ri`kM?G=Uz= zYe(%m$g6gpfYRA}M3Wh=PjV`BA|f`Ajz1QY-KfS$+mLC&=*M@CqU0@-843#@s!tp+ z`hXG_$T+w$%ZRc;oA!hozBo{U_AgR)cc2=ist%Tf1!goyZ`H}XSr9&UY zJ^9hCDY9E_U|L$j^3{t+O$rDP^WqxkQ)&F;Eh@Hsx^<};S#~>%t}R_YRkG7OjOT7s&BTd5F;H{&a{d!BS5Vz@RgwkT{dwhcQ zPGno6OlTdu0KU{d<)>5lyi9d5Rz$1ros^mpW_coXd{r;;5w~?!YUHbE$=hL2`F`si x55d?S>E1-idha0G3zgVNNXgr$|KG8qZJn`L2pQ~%2Sy6WZoiY&ZA<_7e*r@k8!Z3; literal 0 HcmV?d00001 diff --git a/packages/typespec-python/tests/mock_api/azure/test_azure_arm_commonproperties.py b/packages/typespec-python/tests/mock_api/azure/test_azure_arm_commonproperties.py new file mode 100644 index 0000000000..fab853d096 --- /dev/null +++ b/packages/typespec-python/tests/mock_api/azure/test_azure_arm_commonproperties.py @@ -0,0 +1,89 @@ +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- +import pytest +from azure.resourcemanager.commonproperties import CommonPropertiesClient +from azure.resourcemanager.commonproperties import models +from azure.core import exceptions + +SUBSCRIPTION_ID = "00000000-0000-0000-0000-000000000000" +RESOURCE_GROUP_NAME = "test-rg" + + +@pytest.fixture +def client(credential, authentication_policy): + with CommonPropertiesClient( + credential, SUBSCRIPTION_ID, "http://localhost:3000", authentication_policy=authentication_policy + ) as client: + yield client + + +def test_managed_identity_get(client): + result = client.managed_identity.get( + resource_group_name=RESOURCE_GROUP_NAME, managed_identity_tracked_resource_name="identity" + ) + assert result.location == "eastus" + assert result.identity.type == "SystemAssigned" + assert result.properties.provisioning_state == "Succeeded" + + +def test_managed_identity_create_with_system_assigned(client): + result = client.managed_identity.create_with_system_assigned( + resource_group_name=RESOURCE_GROUP_NAME, + managed_identity_tracked_resource_name="identity", + resource=models.ManagedIdentityTrackedResource( + location="eastus", identity=models.ManagedServiceIdentity(type="SystemAssigned") + ), + ) + assert result.location == "eastus" + assert result.identity.type == "SystemAssigned" + assert result.properties.provisioning_state == "Succeeded" + + +def test_managed_identity_update_with_user_assigned_and_system_assigned(client): + result = client.managed_identity.update_with_user_assigned_and_system_assigned( + resource_group_name=RESOURCE_GROUP_NAME, + managed_identity_tracked_resource_name="identity", + properties=models.ManagedIdentityTrackedResource( + location="eastus", + identity=models.ManagedServiceIdentity( + type="SystemAssigned,UserAssigned", + user_assigned_identities={ + "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/test-rg/providers/Microsoft.ManagedIdentity/userAssignedIdentities/id1": models.UserAssignedIdentity() + }, + ), + ), + ) + assert result.location == "eastus" + assert result.identity.type == "SystemAssigned,UserAssigned" + assert result.properties.provisioning_state == "Succeeded" + + +def test_error_get_for_predefined_error(client): + try: + client.error.get_for_predefined_error( + resource_group_name=RESOURCE_GROUP_NAME, + confidential_resource_name="confidential", + ) + except exceptions.ResourceNotFoundError as e: + assert e.status_code == 404 + assert ( + e.error.message + == "The Resource 'Azure.ResourceManager.CommonProperties/confidentialResources/confidential' under resource group 'test-rg' was not found." + ) + + +def test_error_create_for_user_defined_error(client): + try: + client.error.create_for_user_defined_error( + resource_group_name=RESOURCE_GROUP_NAME, + confidential_resource_name="confidential", + resource=models.ConfidentialResource( + location="eastus", properties=models.ConfidentialResourceProperties(username="00") + ), + ) + except exceptions.HttpResponseError as e: + assert e.status_code == 400 + assert e.error.message == "Username should not contain only numbers." diff --git a/packages/typespec-python/tests/mock_api/azure/test_azure_arm_largeheader.py b/packages/typespec-python/tests/mock_api/azure/test_azure_arm_largeheader.py new file mode 100644 index 0000000000..9ad6d567e8 --- /dev/null +++ b/packages/typespec-python/tests/mock_api/azure/test_azure_arm_largeheader.py @@ -0,0 +1,27 @@ +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- +import pytest +from azure.resourcemanager.largeheader import LargeHeaderClient +from azure.resourcemanager.largeheader import models + +SUBSCRIPTION_ID = "00000000-0000-0000-0000-000000000000" +RESOURCE_GROUP_NAME = "test-rg" + + +@pytest.fixture +def client(credential, authentication_policy): + with LargeHeaderClient( + credential, SUBSCRIPTION_ID, "http://localhost:3000", authentication_policy=authentication_policy + ) as client: + yield client + + +def test_large_headers_begin_two6_k(client: LargeHeaderClient): + result = client.large_headers.begin_two6_k( + resource_group_name=RESOURCE_GROUP_NAME, + large_header_name="header1", + ).result() + assert result == models.CancelResult(succeeded=True) diff --git a/packages/typespec-python/tests/mock_api/azure/test_azure_arm_nonresource.py b/packages/typespec-python/tests/mock_api/azure/test_azure_arm_nonresource.py new file mode 100644 index 0000000000..6fd180f8b2 --- /dev/null +++ b/packages/typespec-python/tests/mock_api/azure/test_azure_arm_nonresource.py @@ -0,0 +1,34 @@ +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- +import pytest +from azure.resourcemanager.nonresource import NonResourceClient +from azure.resourcemanager.nonresource import models + +SUBSCRIPTION_ID = "00000000-0000-0000-0000-000000000000" +RESOURCE_GROUP_NAME = "test-rg" + + +@pytest.fixture +def client(credential, authentication_policy): + with NonResourceClient( + credential, SUBSCRIPTION_ID, "http://localhost:3000", authentication_policy=authentication_policy + ) as client: + yield client + + +def test_non_resource_create(client: NonResourceClient): + result = client.non_resource_operations.create( + location="eastus", parameter="hello", body=models.NonResource(id="id", name="hello", type="nonResource") + ) + assert result == models.NonResource(id="id", name="hello", type="nonResource") + + +def test_non_resource_get(client: NonResourceClient): + result = client.non_resource_operations.get( + location="eastus", + parameter="hello", + ) + assert result == models.NonResource(id="id", name="hello", type="nonResource") diff --git a/packages/typespec-python/tests/mock_api/azure/test_azure_arm_operationtemplates.py b/packages/typespec-python/tests/mock_api/azure/test_azure_arm_operationtemplates.py new file mode 100644 index 0000000000..c86c95ef4a --- /dev/null +++ b/packages/typespec-python/tests/mock_api/azure/test_azure_arm_operationtemplates.py @@ -0,0 +1,180 @@ +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- +import pytest +from azure.resourcemanager.operationtemplates import OperationTemplatesClient +from azure.resourcemanager.operationtemplates import models + +SUBSCRIPTION_ID = "00000000-0000-0000-0000-000000000000" +RESOURCE_GROUP_NAME = "test-rg" + + +@pytest.fixture +def client(credential, authentication_policy): + with OperationTemplatesClient( + credential, + SUBSCRIPTION_ID, + "http://localhost:3000", + authentication_policy=authentication_policy, + polling_interval=0, + ) as client: + yield client + + +def test_check_name_availability_check_global(client): + result = client.check_name_availability.check_global( + body=models.CheckNameAvailabilityRequest(name="checkName", type="Microsoft.Web/site") + ) + assert result.name_available == False + assert result.reason == models.CheckNameAvailabilityReason.ALREADY_EXISTS + assert result.message == "Hostname 'checkName' already exists. Please select a different name." + + +def test_check_name_availability_check_local(client): + result = client.check_name_availability.check_local( + location="westus", + body=models.CheckNameAvailabilityRequest(name="checkName", type="Microsoft.Web/site"), + ) + assert result.name_available == False + assert result.reason == models.CheckNameAvailabilityReason.ALREADY_EXISTS + assert result.message == "Hostname 'checkName' already exists. Please select a different name." + + +def test_operations_list(client): + result = client.operations.list().next() + assert result.name == "Microsoft.Compute/virtualMachines/write" + assert result.display.operation == "Create or Update Virtual Machine." + assert result.origin == "user,system" + assert result.action_type == "Internal" + + +def test_lro_begin_create_or_replace(client): + result = client.lro.begin_create_or_replace( + resource_group_name=RESOURCE_GROUP_NAME, + order_name="order1", + resource=models.Order( + location="eastus", + properties=models.OrderProperties(product_id="product1", amount=1), + ), + ).result() + assert result.name == "order1" + assert ( + result.id + == "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/test-rg/providers/Azure.ResourceManager.OperationTemplates/orders/order1" + ) + assert result.type == "Azure.ResourceManager.Resources/orders" + assert result.location == "eastus" + assert result.system_data.created_by == "AzureSDK" + + +def test_lro_begin_export(client): + client.lro.begin_export( + resource_group_name=RESOURCE_GROUP_NAME, + order_name="order1", + body=models.ExportRequest(format="csv"), + ).result() + + +def test_lro_begin_delete(client): + client.lro.begin_delete( + resource_group_name=RESOURCE_GROUP_NAME, + order_name="order1", + ).result() + + +def test_optional_body_get(client): + result = client.optional_body.get( + resource_group_name=RESOURCE_GROUP_NAME, + widget_name="widget1", + ) + assert result.name == "widget1" + assert ( + result.id + == "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/test-rg/providers/Azure.ResourceManager.OperationTemplates/widgets/widget1" + ) + assert result.type == "Azure.ResourceManager.OperationTemplates/widgets" + assert result.location == "eastus" + assert result.properties.name == "widget1" + assert result.properties.description == "A test widget" + assert result.properties.provisioning_state == "Succeeded" + + +def test_optional_body_patch_without_body(client): + result = client.optional_body.patch( + resource_group_name=RESOURCE_GROUP_NAME, + widget_name="widget1", + ) + assert result.name == "widget1" + assert result.properties.name == "widget1" + assert result.properties.description == "A test widget" + + +def test_optional_body_patch_with_body(client): + result = client.optional_body.patch( + resource_group_name=RESOURCE_GROUP_NAME, + widget_name="widget1", + properties=models.Widget( + location="eastus", + properties=models.WidgetProperties(name="updated-widget", description="Updated description"), + ), + ) + assert result.name == "widget1" + assert result.properties.name == "updated-widget" + assert result.properties.description == "Updated description" + + +def test_optional_body_post_without_body(client): + result = client.optional_body.post( + resource_group_name=RESOURCE_GROUP_NAME, + widget_name="widget1", + ) + assert result.result == "Action completed successfully" + + +def test_optional_body_post_with_body(client): + result = client.optional_body.post( + resource_group_name=RESOURCE_GROUP_NAME, + widget_name="widget1", + body=models.ActionRequest(action_type="perform", parameters="test-parameters"), + ) + assert result.result == "Action completed successfully with parameters" + + +def test_optional_body_provider_post_without_body(client): + result = client.optional_body.provider_post() + assert result.total_allowed == 50 + assert result.status == "Changed to default allowance" + + +def test_optional_body_provider_post_with_body(client): + result = client.optional_body.provider_post( + body=models.ChangeAllowanceRequest(total_allowed=100, reason="Increased demand"), + ) + assert result.total_allowed == 100 + assert result.status == "Changed to requested allowance" + + +def test_lro_begin_export_array(client): + result = client.lro.begin_export_array( + body=models.ExportRequest(format="csv"), + ).result() + assert len(result) == 2 + assert result[0].content == "order1,product1,1" + assert result[1].content == "order2,product2,2" + + +def test_lro_paging_begin_post_paging_lro(client): + result = client.lro_paging.begin_post_paging_lro( + resource_group_name=RESOURCE_GROUP_NAME, + product_name="default", + ).result() + items = list(result) + assert len(items) == 2 + assert items[0].name == "product1" + assert items[0].properties.product_id == "product1" + assert items[0].properties.provisioning_state == "Succeeded" + assert items[1].name == "product2" + assert items[1].properties.product_id == "product2" + assert items[1].properties.provisioning_state == "Succeeded" diff --git a/packages/typespec-python/tests/mock_api/azure/test_azure_arm_resource.py b/packages/typespec-python/tests/mock_api/azure/test_azure_arm_resource.py new file mode 100644 index 0000000000..c34d9a85ae --- /dev/null +++ b/packages/typespec-python/tests/mock_api/azure/test_azure_arm_resource.py @@ -0,0 +1,436 @@ +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- +import pytest +from azure.resourcemanager.resources import ResourcesClient +from azure.resourcemanager.resources import models + +SUBSCRIPTION_ID = "00000000-0000-0000-0000-000000000000" +RESOURCE_GROUP_NAME = "test-rg" + + +@pytest.fixture +def client(credential, authentication_policy): + with ResourcesClient( + credential, + SUBSCRIPTION_ID, + "http://localhost:3000", + authentication_policy=authentication_policy, + ) as client: + yield client + + +def test_client_signature(credential, authentication_policy): + # make sure signautre order is correct + client1 = ResourcesClient( + credential, + SUBSCRIPTION_ID, + "http://localhost:3000", + authentication_policy=authentication_policy, + ) + # make sure signautre name is correct + client2 = ResourcesClient( + credential=credential, + subscription_id=SUBSCRIPTION_ID, + base_url="http://localhost:3000", + authentication_policy=authentication_policy, + ) + for client in [client1, client2]: + # make sure signautre order is correct + client.top_level.get(RESOURCE_GROUP_NAME, "top") + # make sure signautre name is correct + client.top_level.get( + resource_group_name=RESOURCE_GROUP_NAME, + top_level_tracked_resource_name="top", + ) + + +def test_top_level_begin_create_or_replace(client): + result = client.top_level.begin_create_or_replace( + resource_group_name=RESOURCE_GROUP_NAME, + top_level_tracked_resource_name="top", + resource=models.TopLevelTrackedResource( + location="eastus", + properties=models.TopLevelTrackedResourceProperties( + models.TopLevelTrackedResourceProperties(description="valid") + ), + ), + polling_interval=0, # set polling_interval to 0 s to make the test faster since default is 30s + ).result() + assert result.location == "eastus" + assert result.properties.description == "valid" + assert result.properties.provisioning_state == "Succeeded" + assert result.name == "top" + assert result.type == "Azure.ResourceManager.Resources/topLevelTrackedResources" + assert result.system_data.created_by == "AzureSDK" + + +def test_top_level_begin_update(client): + result = client.top_level.begin_update( + resource_group_name=RESOURCE_GROUP_NAME, + top_level_tracked_resource_name="top", + properties=models.TopLevelTrackedResource( + location="eastus", + properties=models.TopLevelTrackedResourceProperties( + models.TopLevelTrackedResourceProperties(description="valid2") + ), + ), + polling_interval=0, # set polling_interval to 0 s to make the test faster since default is 30s + ).result() + assert result.location == "eastus" + assert result.properties.description == "valid2" + assert result.properties.provisioning_state == "Succeeded" + assert result.name == "top" + assert result.type == "Azure.ResourceManager.Resources/topLevelTrackedResources" + assert result.system_data.created_by == "AzureSDK" + + +def test_top_level_begin_delete(client): + client.top_level.begin_delete( + resource_group_name=RESOURCE_GROUP_NAME, + top_level_tracked_resource_name="top", + polling_interval=0, # set polling_interval to 0 s to make the test faster since default is 30s + ).result() + + +def test_top_level_list_by_resource_group(client): + response = client.top_level.list_by_resource_group( + resource_group_name=RESOURCE_GROUP_NAME, + ) + result = [r for r in response] + for result in result: + assert result.location == "eastus" + assert result.properties.description == "valid" + assert result.properties.provisioning_state == "Succeeded" + assert result.name == "top" + assert result.type == "Azure.ResourceManager.Resources/topLevelTrackedResources" + assert result.system_data.created_by == "AzureSDK" + + +def test_top_level_list_by_subscription(client): + response = client.top_level.list_by_subscription() + result = [r for r in response] + for result in result: + assert result.location == "eastus" + assert result.properties.description == "valid" + assert result.properties.provisioning_state == "Succeeded" + assert result.name == "top" + assert result.type == "Azure.ResourceManager.Resources/topLevelTrackedResources" + assert result.system_data.created_by == "AzureSDK" + + +def test_nested_get(client): + result = client.nested.get( + resource_group_name=RESOURCE_GROUP_NAME, + top_level_tracked_resource_name="top", + nexted_proxy_resource_name="nested", + ) + assert result.properties.description == "valid" + assert result.properties.provisioning_state == "Succeeded" + assert result.name == "nested" + assert result.type == "Azure.ResourceManager.Resources/topLevelTrackedResources/top/nestedProxyResources" + assert result.system_data.created_by == "AzureSDK" + + +def test_nested_begin_create_or_replace(client): + result = client.nested.begin_create_or_replace( + resource_group_name=RESOURCE_GROUP_NAME, + top_level_tracked_resource_name="top", + nexted_proxy_resource_name="nested", + resource=models.TopLevelTrackedResource( + properties=models.TopLevelTrackedResourceProperties( + models.TopLevelTrackedResourceProperties(description="valid") + ), + ), + polling_interval=0, # set polling_interval to 0 s to make the test faster since default is 30s + ).result() + assert result.properties.description == "valid" + assert result.properties.provisioning_state == "Succeeded" + assert result.name == "nested" + assert result.type == "Azure.ResourceManager.Resources/topLevelTrackedResources/top/nestedProxyResources" + assert result.system_data.created_by == "AzureSDK" + + +def test_nested_begin_update(client): + result = client.nested.begin_update( + resource_group_name=RESOURCE_GROUP_NAME, + top_level_tracked_resource_name="top", + nexted_proxy_resource_name="nested", + properties=models.TopLevelTrackedResource( + properties=models.TopLevelTrackedResourceProperties( + models.TopLevelTrackedResourceProperties(description="valid2") + ), + ), + polling_interval=0, # set polling_interval to 0 s to make the test faster since default is 30s + ).result() + assert result.properties.description == "valid2" + assert result.properties.provisioning_state == "Succeeded" + assert result.name == "nested" + assert result.type == "Azure.ResourceManager.Resources/topLevelTrackedResources/top/nestedProxyResources" + assert result.system_data.created_by == "AzureSDK" + + +def test_nested_begin_delete(client): + client.nested.begin_delete( + resource_group_name=RESOURCE_GROUP_NAME, + top_level_tracked_resource_name="top", + nexted_proxy_resource_name="nested", + polling_interval=0, # set polling_interval to 0 s to make the test faster since default is 30s + ).result() + + +def test_nested_list_by_top_level_tracked_resource(client): + response = client.nested.list_by_top_level_tracked_resource( + resource_group_name=RESOURCE_GROUP_NAME, + top_level_tracked_resource_name="top", + ) + result = [r for r in response] + for result in result: + assert result.properties.description == "valid" + assert result.properties.provisioning_state == "Succeeded" + assert result.name == "nested" + assert result.type == "Azure.ResourceManager.Resources/topLevelTrackedResources/top/nestedProxyResources" + assert result.system_data.created_by == "AzureSDK" + + +def test_top_level_action_sync(client): + client.top_level.action_sync( + resource_group_name=RESOURCE_GROUP_NAME, + top_level_tracked_resource_name="top", + body={"message": "Resource action at top level.", "urgent": True}, + ) + + +def test_singleton_get_by_resource_group(client): + result = client.singleton.get_by_resource_group( + resource_group_name=RESOURCE_GROUP_NAME, + ) + assert result.properties.description == "valid" + assert result.properties.provisioning_state == "Succeeded" + assert result.name == "default" + assert result.type == "Azure.ResourceManager.Resources/singletonTrackedResources" + assert result.system_data.created_by == "AzureSDK" + + +def test_singleton_begin_create_or_replace(client): + result = client.singleton.begin_create_or_update( + resource_group_name=RESOURCE_GROUP_NAME, + resource=models.SingletonTrackedResource( + location="eastus", + properties=models.SingletonTrackedResourceProperties( + models.SingletonTrackedResourceProperties(description="valid") + ), + ), + ).result() + assert result.properties.description == "valid" + assert result.properties.provisioning_state == "Succeeded" + assert result.name == "default" + assert result.type == "Azure.ResourceManager.Resources/singletonTrackedResources" + assert result.system_data.created_by == "AzureSDK" + + +def test_singleton_update(client): + result = client.singleton.update( + resource_group_name=RESOURCE_GROUP_NAME, + properties=models.SingletonTrackedResource( + location="eastus2", + properties=models.SingletonTrackedResourceProperties( + models.SingletonTrackedResourceProperties(description="valid2") + ), + ), + ) + assert result.properties.description == "valid2" + assert result.properties.provisioning_state == "Succeeded" + assert result.name == "default" + assert result.type == "Azure.ResourceManager.Resources/singletonTrackedResources" + assert result.system_data.created_by == "AzureSDK" + + +def test_singleton_list_by_resource_group(client): + response = client.singleton.list_by_resource_group( + resource_group_name=RESOURCE_GROUP_NAME, + ) + result = [r for r in response] + for result in result: + assert result.properties.description == "valid" + assert result.properties.provisioning_state == "Succeeded" + assert result.name == "default" + assert result.type == "Azure.ResourceManager.Resources/singletonTrackedResources" + assert result.system_data.created_by == "AzureSDK" + + +@pytest.mark.parametrize( + "scope", + [ + "", + "/subscriptions/00000000-0000-0000-0000-000000000000", + "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/test-rg", + "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/test-rg/providers/Azure.ResourceManager.Resources/topLevelTrackedResources/top", + ], +) +def test_extensions_resources_begin_create_or_update(client, scope): + result = client.extensions_resources.begin_create_or_update( + resource_uri=scope, + extensions_resource_name="extension", + resource=models.ExtensionsResource(properties=models.ExtensionsResourceProperties(description="valid")), + ).result() + assert result.id == f"{scope}/providers/Azure.ResourceManager.Resources/extensionsResources/extension" + assert result.name == "extension" + assert result.type == "Azure.ResourceManager.Resources/extensionsResources" + assert result.properties.description == "valid" + assert result.properties.provisioning_state == "Succeeded" + assert result.system_data.created_by == "AzureSDK" + + +@pytest.mark.parametrize( + "scope", + [ + "", + "/subscriptions/00000000-0000-0000-0000-000000000000", + "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/test-rg", + "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/test-rg/providers/Azure.ResourceManager.Resources/topLevelTrackedResources/top", + ], +) +def test_extensions_resources_update(client, scope): + result = client.extensions_resources.update( + resource_uri=scope, + extensions_resource_name="extension", + properties=models.ExtensionsResource(properties=models.ExtensionsResourceProperties(description="valid2")), + ) + assert result.id == f"{scope}/providers/Azure.ResourceManager.Resources/extensionsResources/extension" + assert result.name == "extension" + assert result.type == "Azure.ResourceManager.Resources/extensionsResources" + assert result.properties.description == "valid2" + assert result.properties.provisioning_state == "Succeeded" + assert result.system_data.created_by == "AzureSDK" + + +@pytest.mark.parametrize( + "scope", + [ + "", + "/subscriptions/00000000-0000-0000-0000-000000000000", + "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/test-rg", + "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/test-rg/providers/Azure.ResourceManager.Resources/topLevelTrackedResources/top", + ], +) +def test_extensions_resources_get(client, scope): + result = client.extensions_resources.get(resource_uri=scope, extensions_resource_name="extension") + assert result.id == f"{scope}/providers/Azure.ResourceManager.Resources/extensionsResources/extension" + assert result.name == "extension" + assert result.type == "Azure.ResourceManager.Resources/extensionsResources" + assert result.properties.description == "valid" + assert result.properties.provisioning_state == "Succeeded" + assert result.system_data.created_by == "AzureSDK" + + +@pytest.mark.parametrize( + "scope", + [ + "", + "/subscriptions/00000000-0000-0000-0000-000000000000", + "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/test-rg", + "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/test-rg/providers/Azure.ResourceManager.Resources/topLevelTrackedResources/top", + ], +) +def test_extensions_resources_list(client, scope): + response = client.extensions_resources.list_by_scope( + resource_uri=scope, + ) + result = [r for r in response] + for result in result: + assert result.id == f"{scope}/providers/Azure.ResourceManager.Resources/extensionsResources/extension" + assert result.name == "extension" + assert result.type == "Azure.ResourceManager.Resources/extensionsResources" + assert result.properties.description == "valid" + assert result.properties.provisioning_state == "Succeeded" + assert result.system_data.created_by == "AzureSDK" + + +@pytest.mark.parametrize( + "scope", + [ + "", + "/subscriptions/00000000-0000-0000-0000-000000000000", + "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/test-rg", + "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/test-rg/providers/Azure.ResourceManager.Resources/topLevelTrackedResources/top", + ], +) +def test_extensions_resources_delete(client, scope): + client.extensions_resources.delete(resource_uri=scope, extensions_resource_name="extension") + + +def test_location_resources_create_or_update(client): + result = client.location_resources.create_or_update( + location="eastus", + location_resource_name="resource", + resource=models.LocationResource(properties=models.LocationResourceProperties(description="valid")), + ) + assert ( + result.id + == "/subscriptions/00000000-0000-0000-0000-000000000000/providers/Azure.ResourceManager.Resources/locations/eastus/locationResources/resource" + ) + assert result.name == "resource" + assert result.type == "Azure.ResourceManager.Resources/locationResources" + assert result.properties.description == "valid" + assert result.properties.provisioning_state == "Succeeded" + assert result.system_data.created_by == "AzureSDK" + + +def test_location_resources_update(client): + result = client.location_resources.update( + location="eastus", + location_resource_name="resource", + properties=models.LocationResource(properties=models.LocationResourceProperties(description="valid2")), + ) + assert ( + result.id + == "/subscriptions/00000000-0000-0000-0000-000000000000/providers/Azure.ResourceManager.Resources/locations/eastus/locationResources/resource" + ) + assert result.name == "resource" + assert result.type == "Azure.ResourceManager.Resources/locationResources" + assert result.properties.description == "valid2" + assert result.properties.provisioning_state == "Succeeded" + assert result.system_data.created_by == "AzureSDK" + + +def test_location_resources_get(client): + result = client.location_resources.get( + location="eastus", + location_resource_name="resource", + ) + assert ( + result.id + == "/subscriptions/00000000-0000-0000-0000-000000000000/providers/Azure.ResourceManager.Resources/locations/eastus/locationResources/resource" + ) + assert result.name == "resource" + assert result.type == "Azure.ResourceManager.Resources/locationResources" + assert result.properties.description == "valid" + assert result.properties.provisioning_state == "Succeeded" + assert result.system_data.created_by == "AzureSDK" + + +def test_location_resources_delete(client): + client.location_resources.delete( + location="eastus", + location_resource_name="resource", + ) + + +def test_location_resources_list_by_location(client): + response = client.location_resources.list_by_location( + location="eastus", + ) + result = [r for r in response] + for result in result: + assert ( + result.id + == "/subscriptions/00000000-0000-0000-0000-000000000000/providers/Azure.ResourceManager.Resources/locations/eastus/locationResources/resource" + ) + assert result.name == "resource" + assert result.type == "Azure.ResourceManager.Resources/locationResources" + assert result.properties.description == "valid" + assert result.properties.provisioning_state == "Succeeded" + assert result.system_data.created_by == "AzureSDK" diff --git a/packages/typespec-python/tests/mock_api/azure/test_azure_client_generator_core_access.py b/packages/typespec-python/tests/mock_api/azure/test_azure_client_generator_core_access.py new file mode 100644 index 0000000000..ba26314706 --- /dev/null +++ b/packages/typespec-python/tests/mock_api/azure/test_azure_client_generator_core_access.py @@ -0,0 +1,92 @@ +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- +import pytest +from specs.azure.clientgenerator.core.access import AccessClient +from specs.azure.clientgenerator.core.access import models + + +@pytest.fixture +def client(): + with AccessClient() as client: + yield client + + +def test_no_decorator_in_public(client: AccessClient): + result = client.public_operation.no_decorator_in_public(name="sample") + assert result == models.NoDecoratorModelInPublic(name="sample") + + +def test_public_decorator_in_public(client: AccessClient): + result = client.public_operation.public_decorator_in_public(name="sample") + assert result == models.PublicDecoratorModelInPublic(name="sample") + + +def test_no_decorator_in_internal(client: AccessClient): + result = client.internal_operation._no_decorator_in_internal(name="sample") + assert result == models._models.NoDecoratorModelInInternal(name="sample") + + with pytest.raises(ImportError): + from specs.azure.clientgenerator.core.access.models import NoDecoratorModelInInternal + + with pytest.raises(AttributeError): + client.internal_operation.no_decorator_in_internal(name="sample") + + +def test_internal_decorator_in_internal(client: AccessClient): + result = client.internal_operation._internal_decorator_in_internal(name="sample") + assert result == models._models.InternalDecoratorModelInInternal(name="sample") + + with pytest.raises(ImportError): + from specs.azure.clientgenerator.core.access.models import InternalDecoratorModelInInternal + + with pytest.raises(AttributeError): + client.internal_operation.internal_decorator_in_internal(name="sample") + + +def test_public_decorator_in_internal(client: AccessClient): + result = client.internal_operation._public_decorator_in_internal(name="sample") + assert result == models.PublicDecoratorModelInInternal(name="sample") + + with pytest.raises(AttributeError): + client.internal_operation.public_decorator_in_internal(name="sample") + + +def test_public(client: AccessClient): + result = client.shared_model_in_operation.public(name="sample") + assert result == models.SharedModel(name="sample") + + +def test_internal(client: AccessClient): + result = client.shared_model_in_operation._internal(name="sample") + assert result == models.SharedModel(name="sample") + + with pytest.raises(AttributeError): + client.shared_model_in_operation.internal(name="sample") + + +def test_operation(client: AccessClient): + result = client.relative_model_in_operation._operation(name="Madge") + assert result == models._models.OuterModel(name="Madge", inner=models._models.InnerModel(name="Madge")) + + with pytest.raises(ImportError): + from specs.azure.clientgenerator.core.access.models import OuterModel + + with pytest.raises(ImportError): + from specs.azure.clientgenerator.core.access.models import InnerModel + + with pytest.raises(AttributeError): + client.shared_model_in_operation.operation(name="sample") + + +def test_discriminator(client: AccessClient): + result = client.relative_model_in_operation._discriminator(kind="real") + assert result == models._models.RealModel(name="Madge") + + with pytest.raises(ImportError): + from specs.azure.clientgenerator.core.access.models import RealModel + + with pytest.raises(AttributeError): + client.shared_model_in_operation.discriminator(kind="real") diff --git a/packages/typespec-python/tests/mock_api/azure/test_azure_client_generator_core_api_version_header.py b/packages/typespec-python/tests/mock_api/azure/test_azure_client_generator_core_api_version_header.py new file mode 100644 index 0000000000..bd15dcbcd2 --- /dev/null +++ b/packages/typespec-python/tests/mock_api/azure/test_azure_client_generator_core_api_version_header.py @@ -0,0 +1,17 @@ +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- +import pytest +from client.alternateapiversion.service.header import HeaderClient + + +@pytest.fixture +def client(): + with HeaderClient(endpoint="http://localhost:3000") as client: + yield client + + +def test_header_api_version(client: HeaderClient): + client.header_api_version() diff --git a/packages/typespec-python/tests/mock_api/azure/test_azure_client_generator_core_api_version_path.py b/packages/typespec-python/tests/mock_api/azure/test_azure_client_generator_core_api_version_path.py new file mode 100644 index 0000000000..f805e16f9d --- /dev/null +++ b/packages/typespec-python/tests/mock_api/azure/test_azure_client_generator_core_api_version_path.py @@ -0,0 +1,17 @@ +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- +import pytest +from client.alternateapiversion.service.path import PathClient + + +@pytest.fixture +def client(): + with PathClient(endpoint="http://localhost:3000") as client: + yield client + + +def test_path_api_version(client: PathClient): + client.path_api_version() diff --git a/packages/typespec-python/tests/mock_api/azure/test_azure_client_generator_core_api_version_query.py b/packages/typespec-python/tests/mock_api/azure/test_azure_client_generator_core_api_version_query.py new file mode 100644 index 0000000000..fbdca33cb8 --- /dev/null +++ b/packages/typespec-python/tests/mock_api/azure/test_azure_client_generator_core_api_version_query.py @@ -0,0 +1,17 @@ +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- +import pytest +from client.alternateapiversion.service.query import QueryClient + + +@pytest.fixture +def client(): + with QueryClient(endpoint="http://localhost:3000") as client: + yield client + + +def test_query_api_version(client: QueryClient): + client.query_api_version() diff --git a/packages/typespec-python/tests/mock_api/azure/test_azure_client_generator_core_client_default_value.py b/packages/typespec-python/tests/mock_api/azure/test_azure_client_generator_core_client_default_value.py new file mode 100644 index 0000000000..730c6a74b3 --- /dev/null +++ b/packages/typespec-python/tests/mock_api/azure/test_azure_client_generator_core_client_default_value.py @@ -0,0 +1,42 @@ +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- +import pytest +from specs.azure.clientgenerator.core.clientdefaultvalue import ClientDefaultValueClient +from specs.azure.clientgenerator.core.clientdefaultvalue.models import ModelWithDefaultValues + + +@pytest.fixture +def client(): + with ClientDefaultValueClient() as client: + yield client + + +def test_put_model_property(client: ClientDefaultValueClient): + """Test case 1: @clientDefaultValue for model property.""" + body = ModelWithDefaultValues(name="test") + result = client.put_model_property(body=body) + assert result.name == "test" + assert result.timeout == 30 + assert result.tier == "standard" + assert result.retry is True + + +def test_get_operation_parameter(client: ClientDefaultValueClient): + """Test case 2: @clientDefaultValue for operation parameter.""" + # Test with only required parameter (name), defaults should be applied + client.get_operation_parameter(name="test") + + +def test_get_path_parameter(client: ClientDefaultValueClient): + """Test case 3: @clientDefaultValue for first path segment.""" + # Test with only required segment2, segment1 should use default + client.get_path_parameter(segment2="segment2") + + +def test_get_header_parameter(client: ClientDefaultValueClient): + """Test case 4: @clientDefaultValue for header parameters.""" + # Test with default header values + client.get_header_parameter() diff --git a/packages/typespec-python/tests/mock_api/azure/test_azure_client_generator_core_client_initialization.py b/packages/typespec-python/tests/mock_api/azure/test_azure_client_generator_core_client_initialization.py new file mode 100644 index 0000000000..602332210f --- /dev/null +++ b/packages/typespec-python/tests/mock_api/azure/test_azure_client_generator_core_client_initialization.py @@ -0,0 +1,51 @@ +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- +from specs.azure.clientgenerator.core.clientinitialization.default import ( + HeaderParamClient, + MultipleParamsClient, + MixedParamsClient, + PathParamClient, + ParamAliasClient, +) +from specs.azure.clientgenerator.core.clientinitialization.default.models import Input + + +def test_header_param_client(): + with HeaderParamClient("test-name-value") as client: + client.with_query(id="test-id") + client.with_body(Input(name="test-name")) + + +def test_multiple_params_client(): + with MultipleParamsClient("test-name-value", "us-west") as client: + client.with_query(id="test-id") + client.with_body(Input(name="test-name")) + + +def test_mixed_params_client(): + with MixedParamsClient("test-name-value") as client: + client.with_query(region="us-west", id="test-id") + client.with_body(Input(name="test-name"), region="us-west") + + +def test_path_param_client(): + with PathParamClient("sample-blob") as client: + client.with_query(format="text") + client.get_standalone() + client.delete_standalone() + + +def test_param_alias_client(): + with ParamAliasClient("sample-blob") as client: + client.with_aliased_name() + client.with_original_name() + + +# def test_parent_child_client(): +# with ParentClient() as client: +# client.child_client.with_query() +# client.child_client.get_standalone() +# client.child_client.delete_standalone() diff --git a/packages/typespec-python/tests/mock_api/azure/test_azure_client_generator_core_client_location.py b/packages/typespec-python/tests/mock_api/azure/test_azure_client_generator_core_client_location.py new file mode 100644 index 0000000000..954ef99a70 --- /dev/null +++ b/packages/typespec-python/tests/mock_api/azure/test_azure_client_generator_core_client_location.py @@ -0,0 +1,70 @@ +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- +import pytest +from specs.azure.clientgenerator.core.clientlocation.parameter import MoveMethodParameterToClient +from specs.azure.clientgenerator.core.clientlocation.subclient import MoveToExistingSubClient +from specs.azure.clientgenerator.core.clientlocation.newsubclient import MoveToNewSubClient +from specs.azure.clientgenerator.core.clientlocation.rootclient import MoveToRootClient + + +@pytest.fixture +def move_method_parameter_to_client(): + with MoveMethodParameterToClient(storage_account="testaccount") as client: + yield client + + +@pytest.fixture +def move_to_existing_sub_client(): + with MoveToExistingSubClient() as client: + yield client + + +@pytest.fixture +def move_to_new_sub_client(): + with MoveToNewSubClient() as client: + yield client + + +@pytest.fixture +def move_to_root_client(): + with MoveToRootClient() as client: + yield client + + +def test_move_method_parameter_to_client_blob_operations_get_blob( + move_method_parameter_to_client: MoveMethodParameterToClient, +): + move_method_parameter_to_client.blob_operations.get_blob(container="testcontainer", blob="testblob.txt") + + +def test_move_to_existing_sub_client_user_operations_get_user(move_to_existing_sub_client: MoveToExistingSubClient): + move_to_existing_sub_client.user_operations.get_user() + + +def test_move_to_existing_sub_client_admin_operations_delete_user(move_to_existing_sub_client: MoveToExistingSubClient): + move_to_existing_sub_client.admin_operations.delete_user() + + +def test_move_to_existing_sub_client_admin_operations_get_admin_info( + move_to_existing_sub_client: MoveToExistingSubClient, +): + move_to_existing_sub_client.admin_operations.get_admin_info() + + +def test_move_to_new_sub_client_product_operations_list_products(move_to_new_sub_client: MoveToNewSubClient): + move_to_new_sub_client.product_operations.list_products() + + +def test_move_to_new_sub_client_archive_operations_archive_product(move_to_new_sub_client: MoveToNewSubClient): + move_to_new_sub_client.archive_operations.archive_product() + + +def test_move_to_root_client_resource_operations_get_resource(move_to_root_client: MoveToRootClient): + move_to_root_client.resource_operations.get_resource() + + +def test_move_to_root_client_get_health_status(move_to_root_client: MoveToRootClient): + move_to_root_client.get_health_status() diff --git a/packages/typespec-python/tests/mock_api/azure/test_azure_client_generator_core_deserialize_empty_string_as_null.py b/packages/typespec-python/tests/mock_api/azure/test_azure_client_generator_core_deserialize_empty_string_as_null.py new file mode 100644 index 0000000000..a83be0cd02 --- /dev/null +++ b/packages/typespec-python/tests/mock_api/azure/test_azure_client_generator_core_deserialize_empty_string_as_null.py @@ -0,0 +1,19 @@ +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- +import pytest +from specs.azure.clientgenerator.core.emptystring import DeserializeEmptyStringAsNullClient +from specs.azure.clientgenerator.core.emptystring import models + + +@pytest.fixture +def client(): + with DeserializeEmptyStringAsNullClient() as client: + yield client + + +def test_get(client: DeserializeEmptyStringAsNullClient): + result = client.get() + assert result == models.ResponseModel(sample_url="") diff --git a/packages/typespec-python/tests/mock_api/azure/test_azure_client_generator_core_flatten.py b/packages/typespec-python/tests/mock_api/azure/test_azure_client_generator_core_flatten.py new file mode 100644 index 0000000000..30745aae25 --- /dev/null +++ b/packages/typespec-python/tests/mock_api/azure/test_azure_client_generator_core_flatten.py @@ -0,0 +1,104 @@ +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- +import pytest +from specs.azure.clientgenerator.core.flattenproperty import FlattenPropertyClient +from specs.azure.clientgenerator.core.flattenproperty.models import ( + ChildFlattenModel, + ChildModel, + FlattenModel, + FlattenUnknownModel, + NestedFlattenModel, + Solution, + SolutionProperties, +) + + +@pytest.fixture +def client(): + with FlattenPropertyClient() as client: + yield client + + +# ========== test for spector ========== + + +def test_put_flatten_model(client: FlattenPropertyClient): + resp = FlattenModel(name="test", properties=ChildModel(age=1, description="test")) + assert client.put_flatten_model(FlattenModel(name="foo", properties=ChildModel(age=10, description="bar"))) == resp + assert client.put_flatten_model(FlattenModel(name="foo", age=10, description="bar")) == resp + + +def test_put_nested_flatten_model(client: FlattenPropertyClient): + # python doesn't support nested flatten model + assert client.put_nested_flatten_model( + NestedFlattenModel( + name="foo", + properties=ChildFlattenModel(summary="bar", properties=ChildModel(age=10, description="test")), + ) + ) == NestedFlattenModel( + name="test", + properties=ChildFlattenModel(summary="test", properties=ChildModel(age=1, description="foo")), + ) + + +def test_put_flatten_unknown_model(client: FlattenPropertyClient): + result = client.put_flatten_unknown_model(FlattenUnknownModel(name="foo")) + assert result.name == "test" + assert result.properties == {"key1": "value1", "key2": "value2"} + + +def test_put_flatten_read_only_model(client: FlattenPropertyClient): + result = client.put_flatten_read_only_model(Solution(name="foo")) + assert result == Solution( + name="foo", + properties=SolutionProperties(solution_id="solution1", title="Solution Title", content="Solution Content"), + ) + assert result.solution_id == "solution1" + assert result.title == "Solution Title" + assert result.content == "Solution Content" + + +# ============test for compatibility ============ +def test_dpg_model_common(): + flatten_model = FlattenModel(name="hello", properties=ChildModel(age=0, description="test")) + assert flatten_model.name == "hello" + assert flatten_model.properties.age == 0 + assert flatten_model.properties.description == "test" + + +def test_dpg_model_none(): + flatten_model = FlattenModel() + assert flatten_model.name is None + assert flatten_model.properties is None + assert flatten_model.age is None + assert flatten_model.description is None + + +def test_dpg_model_compatibility(): + flatten_model = FlattenModel(description="test", age=0) + assert flatten_model.description == "test" + assert flatten_model.age == 0 + assert flatten_model.properties.description == "test" + assert flatten_model.properties.age == 0 + + +def test_dpg_model_setattr(): + flatten_model = FlattenModel() + + flatten_model.age = 0 + assert flatten_model.properties.age == 0 + flatten_model.description = "test" + assert flatten_model.properties.description == "test" + + flatten_model.properties.age = 1 + assert flatten_model.age == 1 + flatten_model.properties.description = "test2" + assert flatten_model.description == "test2" + + +def test_dpg_model_exception(): + with pytest.raises(AttributeError): + FlattenModel().no_prop diff --git a/packages/typespec-python/tests/mock_api/azure/test_azure_client_generator_core_hierrarchy_building.py b/packages/typespec-python/tests/mock_api/azure/test_azure_client_generator_core_hierrarchy_building.py new file mode 100644 index 0000000000..f11314f6e9 --- /dev/null +++ b/packages/typespec-python/tests/mock_api/azure/test_azure_client_generator_core_hierrarchy_building.py @@ -0,0 +1,45 @@ +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- +import pytest +from specs.azure.clientgenerator.core.hierarchybuilding import HierarchyBuildingClient +from specs.azure.clientgenerator.core.hierarchybuilding.models import ( + Pet, + Dog, +) + + +@pytest.fixture +def client(): + with HierarchyBuildingClient() as client: + yield client + + +# ========== test for spector ========== + + +def test_update_pet_as_pet(client: HierarchyBuildingClient): + resp = Pet(name="Buddy", trained=True) + assert client.pet_operations.update_pet_as_pet(Pet(name="Buddy", trained=True)) == resp + + +def test_update_dog_as_pet(client: HierarchyBuildingClient): + resp = Dog(name="Rex", trained=True, breed="German Shepherd") + assert client.pet_operations.update_dog_as_pet(Dog(name="Rex", trained=True, breed="German Shepherd")) == resp + + +def test_update_pet_as_animal(client: HierarchyBuildingClient): + resp = Pet(name="Buddy", trained=True) + assert client.animal_operations.update_pet_as_animal(Pet(name="Buddy", trained=True)) == resp + + +def test_update_dog_as_animal(client: HierarchyBuildingClient): + resp = Dog(name="Rex", trained=True, breed="German Shepherd") + assert client.animal_operations.update_dog_as_animal(Dog(name="Rex", trained=True, breed="German Shepherd")) == resp + + +def test_update_dog_as_dog(client: HierarchyBuildingClient): + resp = Dog(name="Rex", trained=True, breed="German Shepherd") + assert client.dog_operations.update_dog_as_dog(Dog(name="Rex", trained=True, breed="German Shepherd")) == resp diff --git a/packages/typespec-python/tests/mock_api/azure/test_azure_client_generator_core_next_link_verb.py b/packages/typespec-python/tests/mock_api/azure/test_azure_client_generator_core_next_link_verb.py new file mode 100644 index 0000000000..dd8c5a8bbf --- /dev/null +++ b/packages/typespec-python/tests/mock_api/azure/test_azure_client_generator_core_next_link_verb.py @@ -0,0 +1,27 @@ +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- +import pytest + +from specs.azure.clientgenerator.core.nextlinkverb import NextLinkVerbClient + + +@pytest.fixture +def client(): + with NextLinkVerbClient(endpoint="http://localhost:3000") as client: + yield client + + +def assert_items(items): + items = list(items) + assert len(items) == 2 + assert items[0].id == "test1" + assert items[1].id == "test2" + + +def test_list_items_next_link_verb(client: NextLinkVerbClient): + # The operation uses POST for nextLink per @nextLinkVerb + pager = client.list_items() + assert_items(pager) diff --git a/packages/typespec-python/tests/mock_api/azure/test_azure_client_generator_core_override.py b/packages/typespec-python/tests/mock_api/azure/test_azure_client_generator_core_override.py new file mode 100644 index 0000000000..07a83a129f --- /dev/null +++ b/packages/typespec-python/tests/mock_api/azure/test_azure_client_generator_core_override.py @@ -0,0 +1,102 @@ +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- +import inspect +import pytest +from specs.azure.clientgenerator.core.override import OverrideClient + + +@pytest.fixture +def client(): + with OverrideClient() as client: + yield client + + +def test_reorder_parameters(client: OverrideClient): + client.reorder_parameters.reorder("param1", "param2") + + +def test_group_parameters(client: OverrideClient): + client.group_parameters.group(param1="param1", param2="param2") + + +def test_require_optional_parameter(client: OverrideClient): + client.require_optional_parameter.require_optional("param1", "param2") + + +def test_remove_optional_parameter(client: OverrideClient): + # Test with optional param2 provided + client.remove_optional_parameter.remove_optional("param1", param2="param2") + + +# make sure signature name of `reorder_parameters` are ["param1", "param2"] +def test_reorder_parameters_unit(client: OverrideClient): + # Get the reorder method from the reorder_parameters operation + reorder_method = client.reorder_parameters.reorder + + # Inspect the method signature + sig = inspect.signature(reorder_method) + + # Get parameter names excluding 'self' and '**kwargs' + param_names = [ + param_name + for param_name, param in sig.parameters.items() + if param_name not in ("self", "kwargs") and param.kind != param.VAR_KEYWORD + ] + + # Assert that the parameter names are exactly ["param1", "param2"] + assert param_names == ["param1", "param2"], f"Expected parameter names ['param1', 'param2'], but got {param_names}" + + +def test_require_optional_parameter_signature(client: OverrideClient): + # Get the require_optional method + require_optional_method = client.require_optional_parameter.require_optional + + # Inspect the method signature + sig = inspect.signature(require_optional_method) + + # Get parameter details + params = sig.parameters + + # Check that both param1 and param2 are required (no default values) + assert "param1" in params, "param1 should be present in signature" + assert "param2" in params, "param2 should be present in signature" + assert params["param1"].default == params["param1"].empty, "param1 should have no default value" + assert params["param2"].default == params["param2"].empty, "param2 should have no default value" + + +def test_remove_optional_parameter_signature(client: OverrideClient): + """Test that remove_optional_parameter.remove_optional method signature has correct parameters. + + The @override decorator should remove some optional parameters from the method signature. + Only param1 (required) and param2 (optional) should remain. + """ + # Get the remove_optional method + remove_optional_method = client.remove_optional_parameter.remove_optional + + # Inspect the method signature + sig = inspect.signature(remove_optional_method) + + # Get parameter names excluding 'self' and '**kwargs' + param_names = [ + param_name + for param_name, param in sig.parameters.items() + if param_name not in ("self", "kwargs") and param.kind != param.VAR_KEYWORD + ] + + # Should have param1 (required) and param2 (keyword-only optional) + assert "param1" in param_names, "param1 should be present in signature" + assert "param2" in sig.parameters, "param2 should be present in signature" + + # param1 should be required (positional) + assert sig.parameters["param1"].default == sig.parameters["param1"].empty, "param1 should have no default value" + + # param2 should be optional keyword-only with None default + assert sig.parameters["param2"].kind == sig.parameters["param2"].KEYWORD_ONLY, "param2 should be keyword-only" + assert sig.parameters["param2"].default is None, "param2 should have None as default value" + + # param3 and param4 should be removed + assert "param3" not in param_names, "param3 should not be present in signature" + assert "param4" not in param_names, "param4 should not be present in signature" diff --git a/packages/typespec-python/tests/mock_api/azure/test_azure_client_generator_core_usage.py b/packages/typespec-python/tests/mock_api/azure/test_azure_client_generator_core_usage.py new file mode 100644 index 0000000000..0094bef89a --- /dev/null +++ b/packages/typespec-python/tests/mock_api/azure/test_azure_client_generator_core_usage.py @@ -0,0 +1,32 @@ +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- +import pytest +from specs.azure.clientgenerator.core.usage import UsageClient +from specs.azure.clientgenerator.core.usage import models + + +@pytest.fixture +def client(): + with UsageClient() as client: + yield client + + +def test_input_to_input_output(client: UsageClient): + client.model_in_operation.input_to_input_output(models.InputModel(name="Madge")) + + +def test_output_to_input_output(client: UsageClient): + assert models.OutputModel(name="Madge") == client.model_in_operation.output_to_input_output() + + +def test_model_usage(client: UsageClient): + assert models.RoundTripModel( + result=models.ResultModel(name="Madge") + ) == client.model_in_operation.model_in_read_only_property(body=models.RoundTripModel()) + + +def test_orphan_model_serializable(client: UsageClient): + client.model_in_operation.orphan_model_serializable(body=models.OrphanModel(model_name="name", description="desc")) diff --git a/packages/typespec-python/tests/mock_api/azure/test_azure_core_basic.py b/packages/typespec-python/tests/mock_api/azure/test_azure_core_basic.py new file mode 100644 index 0000000000..8ba50795a8 --- /dev/null +++ b/packages/typespec-python/tests/mock_api/azure/test_azure_core_basic.py @@ -0,0 +1,70 @@ +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- +import pytest +from specs.azure.core.basic import BasicClient, models + +VALID_USER = models.User(id=1, name="Madge", etag="11bdc430-65e8-45ad-81d9-8ffa60d55b59") + + +@pytest.fixture +def client(): + with BasicClient() as client: + yield client + + +def test_create_or_update(client: BasicClient): + result = client.create_or_update(id=1, resource={"name": "Madge"}) + assert result == VALID_USER + + +def test_create_or_replace(client: BasicClient): + result = client.create_or_replace(id=1, resource={"name": "Madge"}) + assert result == VALID_USER + + +def test_get(client: BasicClient): + result = client.get(id=1) + assert result == VALID_USER + + +def test_list(client: BasicClient): + result = list( + client.list( + top=5, + skip=10, + orderby=["id"], + filter="id lt 10", + select=["id", "orders", "etag"], + expand=["orders"], + ) + ) + assert len(result) == 2 + assert result[0].id == 1 + assert result[0].name == "Madge" + assert result[0].etag == "11bdc430-65e8-45ad-81d9-8ffa60d55b59" + assert result[0].orders[0].id == 1 + assert result[0].orders[0].user_id == 1 + assert result[0].orders[0].detail == "a recorder" + assert result[1].id == 2 + assert result[1].name == "John" + assert result[1].etag == "11bdc430-65e8-45ad-81d9-8ffa60d55b5a" + assert result[1].orders[0].id == 2 + assert result[1].orders[0].user_id == 2 + assert result[1].orders[0].detail == "a TV" + + +def test_delete(client: BasicClient): + client.delete(id=1) + + +def test_export(client: BasicClient): + result = client.export(id=1, format="json") + assert result == VALID_USER + + +def test_export_all_users(client: BasicClient): + result = client.export_all_users(format="json") + assert result.users[0] == VALID_USER diff --git a/packages/typespec-python/tests/mock_api/azure/test_azure_core_lro_rpc.py b/packages/typespec-python/tests/mock_api/azure/test_azure_core_lro_rpc.py new file mode 100644 index 0000000000..7710fd9eb6 --- /dev/null +++ b/packages/typespec-python/tests/mock_api/azure/test_azure_core_lro_rpc.py @@ -0,0 +1,20 @@ +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- +import pytest +from specs.azure.core.lro.rpc import RpcClient, models + + +@pytest.fixture +def client(): + with RpcClient() as client: + yield client + + +def test_long_running_rpc(client: RpcClient, polling_method): + result = client.begin_long_running_rpc( + models.GenerationOptions(prompt="text"), polling_interval=0, polling=polling_method + ).result() + assert result == models.GenerationResult(data="text data") diff --git a/packages/typespec-python/tests/mock_api/azure/test_azure_core_lro_standard.py b/packages/typespec-python/tests/mock_api/azure/test_azure_core_lro_standard.py new file mode 100644 index 0000000000..c9337e93fa --- /dev/null +++ b/packages/typespec-python/tests/mock_api/azure/test_azure_core_lro_standard.py @@ -0,0 +1,32 @@ +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- +import pytest +from specs.azure.core.lro.standard import StandardClient +from specs.azure.core.lro.standard.models import User, ExportedUser + + +@pytest.fixture +def client(): + with StandardClient() as client: + yield client + + +def test_lro_core_put(client, polling_method): + user = User({"name": "madge", "role": "contributor"}) + result = client.begin_create_or_replace( + name=user.name, resource=user, polling_interval=0, polling=polling_method + ).result() + assert result == user + + +def test_lro_core_delete(client, polling_method): + client.begin_delete(name="madge", polling_interval=0, polling=polling_method).result() + + +def test_lro_core_export(client, polling_method): + export_user = ExportedUser({"name": "madge", "resourceUri": "/users/madge"}) + result = client.begin_export(name="madge", format="json", polling_interval=0, polling=polling_method).result() + assert result == export_user diff --git a/packages/typespec-python/tests/mock_api/azure/test_azure_core_model.py b/packages/typespec-python/tests/mock_api/azure/test_azure_core_model.py new file mode 100644 index 0000000000..adca0211e5 --- /dev/null +++ b/packages/typespec-python/tests/mock_api/azure/test_azure_core_model.py @@ -0,0 +1,30 @@ +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- +import pytest +from specs.azure.core.model import ModelClient +from specs.azure.core.model.models import AzureEmbeddingModel + + +@pytest.fixture +def client(): + with ModelClient() as client: + yield client + + +def test_azure_core_embedding_vector_post(client: ModelClient): + embedding_model = AzureEmbeddingModel(embedding=[0, 1, 2, 3, 4]) + result = client.azure_core_embedding_vector.post( + body=embedding_model, + ) + assert result == AzureEmbeddingModel(embedding=[5, 6, 7, 8, 9]) + + +def test_azure_core_embedding_vector_put(client: ModelClient): + client.azure_core_embedding_vector.put(body=[0, 1, 2, 3, 4]) + + +def test_azure_core_embedding_vector_get(client: ModelClient): + assert [0, 1, 2, 3, 4] == client.azure_core_embedding_vector.get() diff --git a/packages/typespec-python/tests/mock_api/azure/test_azure_core_page.py b/packages/typespec-python/tests/mock_api/azure/test_azure_core_page.py new file mode 100644 index 0000000000..b5837623be --- /dev/null +++ b/packages/typespec-python/tests/mock_api/azure/test_azure_core_page.py @@ -0,0 +1,71 @@ +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- +import pytest +from typing import Iterable +from specs.azure.core.page import PageClient, models + +VALID_USER = models.User(id=1, name="Madge", etag="11bdc430-65e8-45ad-81d9-8ffa60d55b59") + + +@pytest.fixture +def client(): + with PageClient() as client: + yield client + + +def _list_with_page_tests(pager: Iterable[models.User]): + result = list(pager) + assert len(result) == 1 + assert result[0].id == 1 + assert result[0].name == "Madge" + assert result[0].etag == "11bdc430-65e8-45ad-81d9-8ffa60d55b59" + assert result[0].orders is None + + +def test_list_with_page(client: PageClient): + _list_with_page_tests(client.list_with_page()) + + +def test_list_with_custom_page_model(client: PageClient): + _list_with_page_tests(client.list_with_custom_page_model()) + with pytest.raises(AttributeError): + models.CustomPageModel + + +def test_list_with_parameters(client: PageClient): + result = list(client.list_with_parameters(models.ListItemInputBody(input_name="Madge"), another="Second")) + assert len(result) == 1 + assert result[0] == VALID_USER + + +def test_two_models_as_page_item(client: PageClient): + result = list(client.two_models_as_page_item.list_first_item()) + assert len(result) == 1 + assert result[0].id == 1 + + result = list(client.two_models_as_page_item.list_second_item()) + assert len(result) == 1 + assert result[0].name == "Madge" + + +def test_list_with_parameterized_next_link(client: PageClient): + result = list(client.with_parameterized_next_link(select="name", include_pending=True)) + assert len(result) == 2 + assert result[0].id == 1 + assert result[0].name == "User1" + assert result[1].id == 2 + assert result[1].name == "User2" + + +def test_list_with_relative_next_link(client: PageClient): + result = list(client.with_relative_next_link()) + assert len(result) == 2 + assert result[0].id == 1 + assert result[0].name == "User1" + assert result[0].etag == "11bdc430-65e8-45ad-81d9-8ffa60d55b59" + assert result[1].id == 2 + assert result[1].name == "User2" + assert result[1].etag == "11bdc430-65e8-45ad-81d9-8ffa60d55b59" diff --git a/packages/typespec-python/tests/mock_api/azure/test_azure_core_scalar.py b/packages/typespec-python/tests/mock_api/azure/test_azure_core_scalar.py new file mode 100644 index 0000000000..1bca122b36 --- /dev/null +++ b/packages/typespec-python/tests/mock_api/azure/test_azure_core_scalar.py @@ -0,0 +1,35 @@ +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- +import pytest +from specs.azure.core.scalar import ScalarClient, models + + +@pytest.fixture +def client(): + with ScalarClient() as client: + yield client + + +def test_azure_location_scalar_get(client: ScalarClient): + result = client.azure_location_scalar.get() + assert result == "eastus" + + +def test_azure_location_scalar_put(client: ScalarClient): + client.azure_location_scalar.put("eastus") + + +def test_azure_location_scalar_post(client: ScalarClient): + result = client.azure_location_scalar.post(models.AzureLocationModel(location="eastus")) + assert result == models.AzureLocationModel(location="eastus") + + +def test_azure_location_scalar_header(client: ScalarClient): + client.azure_location_scalar.header(region="eastus") + + +def test_azure_location_scalar_query(client: ScalarClient): + client.azure_location_scalar.query(region="eastus") diff --git a/packages/typespec-python/tests/mock_api/azure/test_azure_core_traits.py b/packages/typespec-python/tests/mock_api/azure/test_azure_core_traits.py new file mode 100644 index 0000000000..982931efb5 --- /dev/null +++ b/packages/typespec-python/tests/mock_api/azure/test_azure_core_traits.py @@ -0,0 +1,85 @@ +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- +import functools +from datetime import datetime + +import pytest +from azure.core.exceptions import HttpResponseError +from azure.core import MatchConditions +from specs.azure.core.traits import TraitsClient +from specs.azure.core.traits.models import UserActionParam + + +@pytest.fixture +def client(): + with TraitsClient() as client: + yield client + + +def test_get(client: TraitsClient, check_client_request_id_header): + def assert_test_get(**kwargs): + checked = {} + result, header = client.smoke_test( + id=1, + foo="123", + if_unmodified_since=datetime(year=2022, month=8, day=26, hour=14, minute=38, second=0), + if_modified_since=datetime(year=2021, month=8, day=26, hour=14, minute=38, second=0), + cls=lambda x, y, z: (y, z), + raw_request_hook=functools.partial( + check_client_request_id_header, header="x-ms-client-request-id", checked=checked + ), + **kwargs, + ) + assert result.id == 1 + assert result.name == "Madge" + assert header["ETag"] == "11bdc430-65e8-45ad-81d9-8ffa60d55b59" + assert header["bar"] == "456" + assert header["x-ms-client-request-id"] == checked["x-ms-client-request-id"] + + assert_test_get(etag="valid", match_condition=MatchConditions.IfNotModified) + assert_test_get(etag="invalid", match_condition=MatchConditions.IfModified) + with pytest.raises(HttpResponseError): + assert_test_get() + + +def test_repeatable_action(client: TraitsClient, check_repeatability_header): + result, header = client.repeatable_action( + id=1, + body=UserActionParam(user_action_value="test"), + cls=lambda x, y, z: (y, z), + raw_request_hook=check_repeatability_header, + ) + assert result.user_action_result == "test" + assert header["Repeatability-Result"] == "accepted" + + result, header = client.repeatable_action( + id=1, + body=UserActionParam(user_action_value="test"), + cls=lambda x, y, z: (y, z), + headers={ + "Repeatability-Request-ID": "5942d803-e3fa-4f96-8f67-607d7bd607f5", + "Repeatability-First-Sent": "Sun, 06 Nov 1994 08:49:37 GMT", + }, + raw_request_hook=check_repeatability_header, + ) + assert result.user_action_result == "test" + assert header["Repeatability-Result"] == "accepted" + + with pytest.raises(HttpResponseError): + client.repeatable_action( + id=1, + body=UserActionParam(user_action_value="test"), + cls=lambda x, y, z: (y, z), + headers={"Repeatability-Request-ID": "wrong-id"}, + ) + + with pytest.raises(HttpResponseError): + client.repeatable_action( + id=1, + body=UserActionParam(user_action_value="test"), + cls=lambda x, y, z: (y, z), + headers={"Repeatability-First-Sent": "wrong-datetime"}, + ) diff --git a/packages/typespec-python/tests/mock_api/azure/test_azure_encode_duration.py b/packages/typespec-python/tests/mock_api/azure/test_azure_encode_duration.py new file mode 100644 index 0000000000..5ee88a6262 --- /dev/null +++ b/packages/typespec-python/tests/mock_api/azure/test_azure_encode_duration.py @@ -0,0 +1,18 @@ +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- +import pytest +from specs.azure.encode.duration import DurationClient +from specs.azure.encode.duration import models + + +@pytest.fixture +def client(): + with DurationClient() as client: + yield client + + +def test_duration_constant(client: DurationClient): + client.duration_constant(models.DurationModel(input="1.02:59:59.5000000")) diff --git a/packages/typespec-python/tests/mock_api/azure/test_azure_example_basic.py b/packages/typespec-python/tests/mock_api/azure/test_azure_example_basic.py new file mode 100644 index 0000000000..a3b0ee01cd --- /dev/null +++ b/packages/typespec-python/tests/mock_api/azure/test_azure_example_basic.py @@ -0,0 +1,29 @@ +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- +import pytest +from specs.azure.example.basic import AzureExampleClient +from specs.azure.example.basic.models import ActionRequest, Model + + +@pytest.fixture +def client(): + with AzureExampleClient() as client: + yield client + + +def test_basic_action(client: AzureExampleClient): + body = ActionRequest( + string_property="text", + model_property=Model(int32_property=1, float32_property=1.5, enum_property="EnumValue1"), + array_property=["item"], + record_property={"record": "value"}, + ) + result = client.basic_action( + body=body, + query_param="query", + header_param="header", + ) + assert result.string_property == body.string_property diff --git a/packages/typespec-python/tests/mock_api/azure/test_azure_payload_pageable.py b/packages/typespec-python/tests/mock_api/azure/test_azure_payload_pageable.py new file mode 100644 index 0000000000..e846ae434c --- /dev/null +++ b/packages/typespec-python/tests/mock_api/azure/test_azure_payload_pageable.py @@ -0,0 +1,18 @@ +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- +import pytest +from specs.azure.payload.pageable import PageableClient + + +@pytest.fixture +def client(): + with PageableClient(endpoint="http://localhost:3000") as client: + yield client + + +def test_list(client: PageableClient): + result = list(client.list(maxpagesize=3)) + assert len(result) == 4 diff --git a/packages/typespec-python/tests/mock_api/azure/test_azure_resource_manager_method_subscription_id.py b/packages/typespec-python/tests/mock_api/azure/test_azure_resource_manager_method_subscription_id.py new file mode 100644 index 0000000000..5f3704a5a1 --- /dev/null +++ b/packages/typespec-python/tests/mock_api/azure/test_azure_resource_manager_method_subscription_id.py @@ -0,0 +1,235 @@ +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- +import pytest +from azure.resourcemanager.methodsubscriptionid import MethodSubscriptionIdClient +from azure.resourcemanager.methodsubscriptionid import models + +SUBSCRIPTION_ID = "00000000-0000-0000-0000-000000000000" +RESOURCE_GROUP_NAME = "test-rg" + + +@pytest.fixture +def client(credential, authentication_policy): + with MethodSubscriptionIdClient( + credential, + SUBSCRIPTION_ID, + "http://localhost:3000", + authentication_policy=authentication_policy, + ) as client: + yield client + + +def test_operations_list(client): + """Test Operations.list() endpoint.""" + operations = client.operations.list() + operations_list = [op for op in operations] + assert len(operations_list) > 0 + + operation = operations_list[0] + assert operation.name == "Azure.ResourceManager.MethodSubscriptionId/services/read" + assert operation.is_data_action is False + assert operation.display.provider == "Azure.ResourceManager.MethodSubscriptionId" + assert operation.display.resource == "services" + assert operation.display.operation == "Lists services" + assert operation.display.description == "Lists registered services" + + +def test_two_subscription_resources_method_level_subscription_resource1_operations_get(client): + """Test get operation for SubscriptionResource1 with method-level subscription ID.""" + result = client.two_subscription_resources_method_level.subscription_resource1_operations.get( + subscription_id=SUBSCRIPTION_ID, + subscription_resource1_name="sub-resource-1", + ) + + assert ( + result.id + == f"/subscriptions/{SUBSCRIPTION_ID}/providers/Azure.ResourceManager.MethodSubscriptionId/subscriptionResource1s/sub-resource-1" + ) + assert result.name == "sub-resource-1" + assert result.type == "Azure.ResourceManager.MethodSubscriptionId/subscriptionResource1s" + assert result.properties.description == "Valid subscription resource 1" + assert result.properties.provisioning_state == "Succeeded" + assert result.system_data.created_by == "AzureSDK" + + +def test_two_subscription_resources_method_level_subscription_resource1_operations_put(client): + """Test put operation for SubscriptionResource1 with method-level subscription ID.""" + resource = models.SubscriptionResource1( + properties=models.SubscriptionResource1Properties(description="Valid subscription resource 1") + ) + + result = client.two_subscription_resources_method_level.subscription_resource1_operations.put( + subscription_id=SUBSCRIPTION_ID, + subscription_resource1_name="sub-resource-1", + resource=resource, + ) + + assert ( + result.id + == f"/subscriptions/{SUBSCRIPTION_ID}/providers/Azure.ResourceManager.MethodSubscriptionId/subscriptionResource1s/sub-resource-1" + ) + assert result.name == "sub-resource-1" + assert result.type == "Azure.ResourceManager.MethodSubscriptionId/subscriptionResource1s" + assert result.properties.description == "Valid subscription resource 1" + assert result.properties.provisioning_state == "Succeeded" + assert result.system_data.created_by == "AzureSDK" + + +def test_two_subscription_resources_method_level_subscription_resource1_operations_delete(client): + """Test delete operation for SubscriptionResource1 with method-level subscription ID.""" + client.two_subscription_resources_method_level.subscription_resource1_operations.delete( + subscription_id=SUBSCRIPTION_ID, + subscription_resource1_name="sub-resource-1", + ) + + +def test_two_subscription_resources_method_level_subscription_resource2_operations_get(client): + """Test get operation for SubscriptionResource2 with method-level subscription ID.""" + result = client.two_subscription_resources_method_level.subscription_resource2_operations.get( + subscription_id=SUBSCRIPTION_ID, + subscription_resource2_name="sub-resource-2", + ) + + assert ( + result.id + == f"/subscriptions/{SUBSCRIPTION_ID}/providers/Azure.ResourceManager.MethodSubscriptionId/subscriptionResource2s/sub-resource-2" + ) + assert result.name == "sub-resource-2" + assert result.type == "Azure.ResourceManager.MethodSubscriptionId/subscriptionResource2s" + assert result.properties.config_value == "test-config" + assert result.properties.provisioning_state == "Succeeded" + assert result.system_data.created_by == "AzureSDK" + + +def test_two_subscription_resources_method_level_subscription_resource2_operations_put(client): + """Test put operation for SubscriptionResource2 with method-level subscription ID.""" + resource = models.SubscriptionResource2( + properties=models.SubscriptionResource2Properties(config_value="test-config") + ) + + result = client.two_subscription_resources_method_level.subscription_resource2_operations.put( + subscription_id=SUBSCRIPTION_ID, + subscription_resource2_name="sub-resource-2", + resource=resource, + ) + + assert ( + result.id + == f"/subscriptions/{SUBSCRIPTION_ID}/providers/Azure.ResourceManager.MethodSubscriptionId/subscriptionResource2s/sub-resource-2" + ) + assert result.name == "sub-resource-2" + assert result.type == "Azure.ResourceManager.MethodSubscriptionId/subscriptionResource2s" + assert result.properties.config_value == "test-config" + assert result.properties.provisioning_state == "Succeeded" + assert result.system_data.created_by == "AzureSDK" + + +def test_two_subscription_resources_method_level_subscription_resource2_operations_delete(client): + """Test delete operation for SubscriptionResource2 with method-level subscription ID.""" + client.two_subscription_resources_method_level.subscription_resource2_operations.delete( + subscription_id=SUBSCRIPTION_ID, + subscription_resource2_name="sub-resource-2", + ) + + +def test_mixed_subscription_placement_subscription_resource_operations_get(client): + """Test get operation for SubscriptionResource in mixed placement scenario.""" + result = client.mixed_subscription_placement.subscription_resource_operations.get( + subscription_id=SUBSCRIPTION_ID, + subscription_resource_name="sub-resource", + ) + + assert ( + result.id + == f"/subscriptions/{SUBSCRIPTION_ID}/providers/Azure.ResourceManager.MethodSubscriptionId/subscriptionResources/sub-resource" + ) + assert result.name == "sub-resource" + assert result.type == "Azure.ResourceManager.MethodSubscriptionId/subscriptionResources" + assert result.properties.subscription_setting == "test-sub-setting" + assert result.properties.provisioning_state == "Succeeded" + assert result.system_data.created_by == "AzureSDK" + + +def test_mixed_subscription_placement_subscription_resource_operations_put(client): + """Test put operation for SubscriptionResource in mixed placement scenario.""" + resource = models.SubscriptionResource( + properties=models.SubscriptionResourceProperties(subscription_setting="test-sub-setting") + ) + + result = client.mixed_subscription_placement.subscription_resource_operations.put( + subscription_id=SUBSCRIPTION_ID, + subscription_resource_name="sub-resource", + resource=resource, + ) + + assert ( + result.id + == f"/subscriptions/{SUBSCRIPTION_ID}/providers/Azure.ResourceManager.MethodSubscriptionId/subscriptionResources/sub-resource" + ) + assert result.name == "sub-resource" + assert result.type == "Azure.ResourceManager.MethodSubscriptionId/subscriptionResources" + assert result.properties.subscription_setting == "test-sub-setting" + assert result.properties.provisioning_state == "Succeeded" + assert result.system_data.created_by == "AzureSDK" + + +def test_mixed_subscription_placement_subscription_resource_operations_delete(client): + """Test delete operation for SubscriptionResource in mixed placement scenario.""" + client.mixed_subscription_placement.subscription_resource_operations.delete( + subscription_id=SUBSCRIPTION_ID, + subscription_resource_name="sub-resource", + ) + + +def test_mixed_subscription_placement_resource_group_resource_operations_get(client): + """Test get operation for ResourceGroupResource with client-level subscription ID.""" + result = client.mixed_subscription_placement.resource_group_resource_operations.get( + resource_group_name=RESOURCE_GROUP_NAME, + resource_group_resource_name="rg-resource", + ) + + assert ( + result.id + == f"/subscriptions/{SUBSCRIPTION_ID}/resourceGroups/{RESOURCE_GROUP_NAME}/providers/Azure.ResourceManager.MethodSubscriptionId/resourceGroupResources/rg-resource" + ) + assert result.name == "rg-resource" + assert result.type == "Azure.ResourceManager.MethodSubscriptionId/resourceGroupResources" + assert result.location == "eastus" + assert result.properties.resource_group_setting == "test-setting" + assert result.properties.provisioning_state == "Succeeded" + assert result.system_data.created_by == "AzureSDK" + + +def test_mixed_subscription_placement_resource_group_resource_operations_put(client): + """Test put operation for ResourceGroupResource with client-level subscription ID.""" + resource = models.ResourceGroupResource( + location="eastus", properties=models.ResourceGroupResourceProperties(resource_group_setting="test-setting") + ) + + result = client.mixed_subscription_placement.resource_group_resource_operations.put( + resource_group_name=RESOURCE_GROUP_NAME, + resource_group_resource_name="rg-resource", + resource=resource, + ) + + assert ( + result.id + == f"/subscriptions/{SUBSCRIPTION_ID}/resourceGroups/{RESOURCE_GROUP_NAME}/providers/Azure.ResourceManager.MethodSubscriptionId/resourceGroupResources/rg-resource" + ) + assert result.name == "rg-resource" + assert result.type == "Azure.ResourceManager.MethodSubscriptionId/resourceGroupResources" + assert result.location == "eastus" + assert result.properties.resource_group_setting == "test-setting" + assert result.properties.provisioning_state == "Succeeded" + assert result.system_data.created_by == "AzureSDK" + + +def test_mixed_subscription_placement_resource_group_resource_operations_delete(client): + """Test delete operation for ResourceGroupResource with client-level subscription ID.""" + client.mixed_subscription_placement.resource_group_resource_operations.delete( + resource_group_name=RESOURCE_GROUP_NAME, + resource_group_resource_name="rg-resource", + ) diff --git a/packages/typespec-python/tests/mock_api/azure/test_azure_resource_manager_multi_service.py b/packages/typespec-python/tests/mock_api/azure/test_azure_resource_manager_multi_service.py new file mode 100644 index 0000000000..b56d0e4bfd --- /dev/null +++ b/packages/typespec-python/tests/mock_api/azure/test_azure_resource_manager_multi_service.py @@ -0,0 +1,104 @@ +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- +import pytest +from azure.core.exceptions import HttpResponseError +from azure.resourcemanager.multiservice.combined import CombinedClient +from azure.resourcemanager.multiservice.combined.models import VirtualMachine, Disk + + +@pytest.fixture +def client(credential, authentication_policy): + """Create a Combined client for testing.""" + return CombinedClient( + credential=credential, # Will use mock server, no real auth needed + subscription_id="00000000-0000-0000-0000-000000000000", + base_url="http://localhost:3000", + authentication_policy=authentication_policy, + polling_interval=0.1, # Speed up tests by reducing polling interval + ) + + +def test_virtual_machines_get(client): + resource_group_name = "test-rg" + vm_name = "vm1" + + with pytest.raises(HttpResponseError): + client.virtual_machines.get( + resource_group_name=resource_group_name, + vm_name=vm_name, + api_version="av1", # invalid api version shall raise error + ) + + result = client.virtual_machines.get(resource_group_name=resource_group_name, vm_name=vm_name) + + assert result is not None + assert isinstance(result, VirtualMachine) + assert result.name == vm_name + + +def test_virtual_machines_create_or_update(client): + resource_group_name = "test-rg" + vm_name = "vm1" + + vm_resource = VirtualMachine(location="eastus", properties={}) + + with pytest.raises(HttpResponseError): + client.virtual_machines.begin_create_or_update( + resource_group_name=resource_group_name, + vm_name=vm_name, + resource=vm_resource, + api_version="av1", # invalid api version shall raise error + ).result() + + poller = client.virtual_machines.begin_create_or_update( + resource_group_name=resource_group_name, vm_name=vm_name, resource=vm_resource + ) + + result = poller.result() + assert result is not None + assert isinstance(result, VirtualMachine) + assert result.location == "eastus" + + +def test_disks_get(client): + resource_group_name = "test-rg" + disk_name = "disk1" + with pytest.raises(HttpResponseError): + client.disks.get( + resource_group_name=resource_group_name, + disk_name=disk_name, + api_version="av1", # invalid api version shall raise error + ) + + result = client.disks.get(resource_group_name=resource_group_name, disk_name=disk_name) + + assert result is not None + assert isinstance(result, Disk) + assert result.name == disk_name + + +def test_disks_create_or_update(client): + resource_group_name = "test-rg" + disk_name = "disk1" + + disk_resource = Disk(location="eastus", properties={}) + + with pytest.raises(HttpResponseError): + client.disks.begin_create_or_update( + resource_group_name=resource_group_name, + disk_name=disk_name, + resource=disk_resource, + api_version="av1", # invalid api version shall raise error + ).result() + + poller = client.disks.begin_create_or_update( + resource_group_name=resource_group_name, disk_name=disk_name, resource=disk_resource + ) + + result = poller.result() + assert result is not None + assert isinstance(result, Disk) + assert result.location == "eastus" diff --git a/packages/typespec-python/tests/mock_api/azure/test_azure_resource_manager_multi_service_shared_models.py b/packages/typespec-python/tests/mock_api/azure/test_azure_resource_manager_multi_service_shared_models.py new file mode 100644 index 0000000000..0e3f67ebc1 --- /dev/null +++ b/packages/typespec-python/tests/mock_api/azure/test_azure_resource_manager_multi_service_shared_models.py @@ -0,0 +1,128 @@ +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- +import pytest +from azure.resourcemanager.multiservicesharedmodels.combined import CombinedClient +from azure.resourcemanager.multiservicesharedmodels.combined.models import ( + VirtualMachine, + VirtualMachineProperties, + StorageAccount, + StorageAccountProperties, + SharedMetadata, +) + + +@pytest.fixture +def client(credential, authentication_policy): + """Create a Combined client for testing.""" + return CombinedClient( + credential=credential, + subscription_id="00000000-0000-0000-0000-000000000000", + base_url="http://localhost:3000", + authentication_policy=authentication_policy, + polling_interval=0.1, + ) + + +def test_virtual_machines_get(client): + """Test getting a virtual machine with shared metadata.""" + resource_group_name = "test-rg" + vm_name = "vm-shared1" + + result = client.virtual_machines.get(resource_group_name=resource_group_name, vm_name=vm_name) + + assert result is not None + assert isinstance(result, VirtualMachine) + assert result.name == vm_name + assert result.location == "eastus" + assert result.type == "Microsoft.Compute/virtualMachinesShared" + assert result.properties is not None + assert result.properties.provisioning_state == "Succeeded" + assert result.properties.metadata is not None + assert result.properties.metadata.created_by == "user@example.com" + assert result.properties.metadata.tags == {"environment": "production"} + + +def test_virtual_machines_create_or_update(client): + """Test creating or updating a virtual machine with shared metadata.""" + resource_group_name = "test-rg" + vm_name = "vm-shared1" + + vm_resource = VirtualMachine( + location="eastus", + properties=VirtualMachineProperties( + metadata=SharedMetadata( + created_by="user@example.com", + tags={"environment": "production"}, + ), + ), + ) + + poller = client.virtual_machines.begin_create_or_update( + resource_group_name=resource_group_name, + vm_name=vm_name, + resource=vm_resource, + ) + + result = poller.result() + assert result is not None + assert isinstance(result, VirtualMachine) + assert result.location == "eastus" + assert result.properties is not None + assert result.properties.provisioning_state == "Succeeded" + assert result.properties.metadata is not None + assert result.properties.metadata.created_by == "user@example.com" + assert result.properties.metadata.tags == {"environment": "production"} + + +def test_storage_accounts_get(client): + """Test getting a storage account with shared metadata.""" + resource_group_name = "test-rg" + account_name = "account1" + + result = client.storage_accounts.get(resource_group_name=resource_group_name, account_name=account_name) + + assert result is not None + assert isinstance(result, StorageAccount) + assert result.name == account_name + assert result.location == "westus" + assert result.type == "Microsoft.Storage/storageAccounts" + assert result.properties is not None + assert result.properties.provisioning_state == "Succeeded" + assert result.properties.metadata is not None + assert result.properties.metadata.created_by == "admin@example.com" + assert result.properties.metadata.tags == {"department": "engineering"} + + +def test_storage_accounts_create_or_update(client): + """Test creating or updating a storage account with shared metadata.""" + resource_group_name = "test-rg" + account_name = "account1" + + storage_resource = StorageAccount( + location="westus", + properties=StorageAccountProperties( + metadata=SharedMetadata( + created_by="admin@example.com", + tags={"department": "engineering"}, + ), + ), + ) + + poller = client.storage_accounts.begin_create_or_update( + resource_group_name=resource_group_name, + account_name=account_name, + resource=storage_resource, + ) + + result = poller.result() + assert result is not None + assert isinstance(result, StorageAccount) + assert result.location == "westus" + assert result.properties is not None + assert result.properties.provisioning_state == "Succeeded" + assert result.properties.metadata is not None + assert result.properties.metadata.created_by == "admin@example.com" + assert result.properties.metadata.tags == {"department": "engineering"} diff --git a/packages/typespec-python/tests/mock_api/azure/test_azure_special_headers_client_request_id.py b/packages/typespec-python/tests/mock_api/azure/test_azure_special_headers_client_request_id.py new file mode 100644 index 0000000000..5a67d578f1 --- /dev/null +++ b/packages/typespec-python/tests/mock_api/azure/test_azure_special_headers_client_request_id.py @@ -0,0 +1,29 @@ +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- +import functools + +import pytest + +from azure.specialheaders.xmsclientrequestid import XmsClientRequestIdClient + + +@pytest.fixture +def client(): + with XmsClientRequestIdClient() as client: + yield client + + +def test_get(client: XmsClientRequestIdClient, check_client_request_id_header): + checked = {} + result, resp = client.get( + cls=lambda x, y, z: (y, x), + raw_request_hook=functools.partial( + check_client_request_id_header, header="x-ms-client-request-id", checked=checked + ), + ) + assert result is None + assert resp.http_response.headers["x-ms-client-request-id"] == checked["x-ms-client-request-id"] + pass diff --git a/packages/typespec-python/tests/mock_api/azure/test_azure_versioning_previewversion.py b/packages/typespec-python/tests/mock_api/azure/test_azure_versioning_previewversion.py new file mode 100644 index 0000000000..2bb1cf7c7d --- /dev/null +++ b/packages/typespec-python/tests/mock_api/azure/test_azure_versioning_previewversion.py @@ -0,0 +1,50 @@ +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- +import pytest +from specs.azure.versioning.previewversion import PreviewVersionClient +from specs.azure.versioning.previewversion.models import UpdateWidgetColorRequest + + +@pytest.fixture +def client(): + with PreviewVersionClient() as client: + yield client + + +@pytest.fixture +def stable_client(): + with PreviewVersionClient(api_version="2024-06-01") as client: + yield client + + +def test_get_widget(client: PreviewVersionClient): + result = client.get_widget(id="widget-123") + assert result.id == "widget-123" + assert result.name == "Sample Widget" + assert result.color == "blue" + + +def test_update_widget_color(client: PreviewVersionClient): + color_update = UpdateWidgetColorRequest(color="red") + result = client.update_widget_color(id="widget-123", color_update=color_update) + assert result.id == "widget-123" + assert result.name == "Sample Widget" + assert result.color == "red" + + with pytest.raises(ValueError): + with PreviewVersionClient(api_version="2024-06-01") as stable_client: + stable_client.update_widget_color(id="widget-123", color_update=color_update) + + +def test_list_widgets(stable_client: PreviewVersionClient): + result = stable_client.list_widgets(name="test") + assert len(result.widgets) == 1 + assert result.widgets[0].id == "widget-1" + assert result.widgets[0].name == "test" + + with pytest.raises(ValueError): + with PreviewVersionClient(api_version="2024-06-01") as client: + client.list_widgets(name="test", color="test") diff --git a/packages/typespec-python/tests/mock_api/azure/test_clear_output_folder.py b/packages/typespec-python/tests/mock_api/azure/test_clear_output_folder.py new file mode 100644 index 0000000000..9ae9307c19 --- /dev/null +++ b/packages/typespec-python/tests/mock_api/azure/test_clear_output_folder.py @@ -0,0 +1,22 @@ +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- +from pathlib import Path + +GENERATED_PATH = Path(__file__).parent.parent.parent.resolve() / "generated" / "azure" + + +def test_clear_output_folder(): + folder = GENERATED_PATH / "authentication-api-key/authentication/apikey/_operations" + assert folder.exists(), "Operations folder should exist" + assert not (folder / "to_be_deleted.py").exists(), "File to_be_deleted.py should be deleted after regeneration" + + if (GENERATED_PATH / "generation-subdir").exists(): + assert not (GENERATED_PATH / "generation-subdir/generated_tests/to_be_deleted.py").exists() + + assert (GENERATED_PATH / "generation-subdir/generation/subdir/_generated").exists() + assert not (GENERATED_PATH / "generation-subdir/generation/subdir/_generated/to_be_deleted.py").exists() + + assert (GENERATED_PATH / "generation-subdir/generation/subdir/to_be_kept.py").exists() diff --git a/packages/typespec-python/tests/mock_api/azure/test_client_namespace.py b/packages/typespec-python/tests/mock_api/azure/test_client_namespace.py new file mode 100644 index 0000000000..da19dba405 --- /dev/null +++ b/packages/typespec-python/tests/mock_api/azure/test_client_namespace.py @@ -0,0 +1,32 @@ +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- +import pytest +from client.clientnamespace import ClientNamespaceFirstClient +from client.clientnamespace.first.models import FirstClientResult + +from client.clientnamespace.second import ClientNamespaceSecondClient +from client.clientnamespace.second.models import SecondClientResult +from client.clientnamespace.second.sub.models import SecondClientEnumType + + +@pytest.fixture +def first_client(): + with ClientNamespaceFirstClient() as client: + yield client + + +@pytest.fixture +def second_client(): + with ClientNamespaceSecondClient() as client: + yield client + + +def test_get_first(first_client: ClientNamespaceFirstClient): + assert first_client.get_first() == FirstClientResult(name="first") + + +def test_get_second(second_client: ClientNamespaceSecondClient): + assert second_client.get_second() == SecondClientResult(type=SecondClientEnumType.SECOND) diff --git a/packages/typespec-python/tests/mock_api/azure/test_client_naming.py b/packages/typespec-python/tests/mock_api/azure/test_client_naming.py new file mode 100644 index 0000000000..94ef8c2d3b --- /dev/null +++ b/packages/typespec-python/tests/mock_api/azure/test_client_naming.py @@ -0,0 +1,57 @@ +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- +import pytest +from client.naming.main import NamingClient, models + + +@pytest.fixture +def client(): + with NamingClient() as client: + yield client + + +def test_client(client: NamingClient): + client.property.client(models.ClientNameModel(client_name=True)) + + +def test_language(client: NamingClient): + client.property.language(models.LanguageClientNameModel(python_name=True)) + + +def test_compatible_with_encoded_name(client: NamingClient): + client.property.compatible_with_encoded_name(models.ClientNameAndJsonEncodedNameModel(client_name=True)) + + +def test_operation(client: NamingClient): + client.client_name() + + +def test_parameter(client: NamingClient): + client.parameter(client_name="true") + + +def test_header_request(client: NamingClient): + client.header.request(client_name="true") + + +def test_header_response(client: NamingClient): + assert client.header.response(cls=lambda x, y, z: z)["default-name"] == "true" + + +def test_model_client(client: NamingClient): + client.model_client.client(models.ClientModel(default_name=True)) + + +def test_model_language(client: NamingClient): + client.model_client.language(models.PythonModel(default_name=True)) + + +def test_union_enum_member_name(client: NamingClient): + client.union_enum.union_enum_member_name(models.ExtensibleEnum.CLIENT_ENUM_VALUE1) + + +def test_union_enum_name(client: NamingClient): + client.union_enum.union_enum_name(models.ClientExtensibleEnum.ENUM_VALUE1) diff --git a/packages/typespec-python/tests/mock_api/azure/test_client_naming_enum_conflict.py b/packages/typespec-python/tests/mock_api/azure/test_client_naming_enum_conflict.py new file mode 100644 index 0000000000..f32415a361 --- /dev/null +++ b/packages/typespec-python/tests/mock_api/azure/test_client_naming_enum_conflict.py @@ -0,0 +1,35 @@ +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- +import pytest +from client.naming.enumconflict import EnumConflictClient +from client.naming.enumconflict.firstnamespace import models as first_models +from client.naming.enumconflict.secondnamespace import models as second_models + + +@pytest.fixture +def client(): + with EnumConflictClient() as client: + yield client + + +def test_first_operations_first(client: EnumConflictClient): + """Test enum with same name in different namespace - first namespace.""" + body = first_models.FirstModel(status=first_models.Status.ACTIVE, name="test") + + response = client.first_operations.first(body=body) + + assert response.status == "active" + assert response.name == "test" + + +def test_second_operations_second(client: EnumConflictClient): + """Test enum with same name in different namespace - second namespace.""" + body = second_models.SecondModel(status=second_models.SecondStatus.RUNNING, description="test description") + + response = client.second_operations.second(body=body) + + assert response.status == "running" + assert response.description == "test description" diff --git a/packages/typespec-python/tests/mock_api/azure/test_client_overload.py b/packages/typespec-python/tests/mock_api/azure/test_client_overload.py new file mode 100644 index 0000000000..24d74549d7 --- /dev/null +++ b/packages/typespec-python/tests/mock_api/azure/test_client_overload.py @@ -0,0 +1,25 @@ +import pytest +from client.overload import OverloadClient + + +class TestClientOverload: + @pytest.fixture + def client(self): + return OverloadClient(endpoint="http://localhost:3000") + + def test_list(self, client: OverloadClient): + result = client.list() + assert len(result) == 2 + assert result[0]["id"] == "1" + assert result[0]["name"] == "foo" + assert result[0]["scope"] == "car" + assert result[1]["id"] == "2" + assert result[1]["name"] == "bar" + assert result[1]["scope"] == "bike" + + def test_list_by_scope(self, client: OverloadClient): + result = client.list_by_scope("car") + assert len(result) == 1 + assert result[0]["id"] == "1" + assert result[0]["name"] == "foo" + assert result[0]["scope"] == "car" diff --git a/packages/typespec-python/tests/mock_api/azure/test_client_structure.py b/packages/typespec-python/tests/mock_api/azure/test_client_structure.py new file mode 100644 index 0000000000..d28827376c --- /dev/null +++ b/packages/typespec-python/tests/mock_api/azure/test_client_structure.py @@ -0,0 +1,57 @@ +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- +from client.structure.service.models import ClientType +from client.structure.service import ServiceClient +from client.structure.multiclient import ClientAClient, ClientBClient +from client.structure.renamedoperation import RenamedOperationClient +from client.structure.twooperationgroup import TwoOperationGroupClient + + +def test_structure_default(): + client = ServiceClient(endpoint="http://localhost:3000", client=ClientType.DEFAULT) + client.one() + client.two() + client.foo.three() + client.foo.four() + client.bar.five() + client.bar.six() + client.baz.foo.seven() + client.qux.eight() + client.qux.bar.nine() + + +def test_structure_multiclient(): + client_a = ClientAClient(endpoint="http://localhost:3000", client=ClientType.MULTI_CLIENT) + client_a.renamed_one() + client_a.renamed_three() + client_a.renamed_five() + + client_b = ClientBClient(endpoint="http://localhost:3000", client=ClientType.MULTI_CLIENT) + client_b.renamed_two() + client_b.renamed_four() + client_b.renamed_six() + + +def test_structure_renamed_operation(): + client = RenamedOperationClient(endpoint="http://localhost:3000", client=ClientType.RENAMED_OPERATION) + client.renamed_one() + client.renamed_three() + client.renamed_five() + + client.group.renamed_two() + client.group.renamed_four() + client.group.renamed_six() + + +def test_structure_two_operation_group(): + client = TwoOperationGroupClient(endpoint="http://localhost:3000", client=ClientType.TWO_OPERATION_GROUP) + client.group1.one() + client.group1.three() + client.group1.four() + + client.group2.two() + client.group2.five() + client.group2.six() diff --git a/packages/typespec-python/tests/mock_api/azure/test_client_structure_clientoperationgroup.py b/packages/typespec-python/tests/mock_api/azure/test_client_structure_clientoperationgroup.py new file mode 100644 index 0000000000..3990830ebd --- /dev/null +++ b/packages/typespec-python/tests/mock_api/azure/test_client_structure_clientoperationgroup.py @@ -0,0 +1,26 @@ +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- +from client.structure.clientoperationgroup.models import ClientType +from client.structure.clientoperationgroup import FirstClient, SecondClient + + +def test_first_client_operations(): + client = FirstClient(endpoint="http://localhost:3000", client=ClientType.CLIENT_OPERATION_GROUP) + + client.one() + + client.group3.two() + client.group3.three() + + client.group4.four() + + +def test_second_client_operations(): + client = SecondClient(endpoint="http://localhost:3000", client=ClientType.CLIENT_OPERATION_GROUP) + + client.five() + + client.group5.six() diff --git a/packages/typespec-python/tests/mock_api/azure/test_encode_duration.py b/packages/typespec-python/tests/mock_api/azure/test_encode_duration.py new file mode 100644 index 0000000000..db0e29416f --- /dev/null +++ b/packages/typespec-python/tests/mock_api/azure/test_encode_duration.py @@ -0,0 +1,60 @@ +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- +import datetime + +import pytest +from encode.duration import DurationClient +from encode.duration.models import ( + Int32SecondsDurationProperty, + ISO8601DurationProperty, + FloatSecondsDurationProperty, + DefaultDurationProperty, + FloatSecondsDurationArrayProperty, +) + + +@pytest.fixture +def client(): + with DurationClient() as client: + yield client + + +def test_query(client: DurationClient): + client.query.default(input=datetime.timedelta(days=40)) + client.query.iso8601(input=datetime.timedelta(days=40)) + client.query.int32_seconds(input=36) + client.query.int32_seconds_array(input=[36, 47]) + client.query.float_seconds(input=35.625) + client.query.float64_seconds(input=35.625) + + +def test_property(client: DurationClient): + result = client.property.default(DefaultDurationProperty(value=datetime.timedelta(days=40))) + assert result.value == datetime.timedelta(days=40) + result = client.property.default(DefaultDurationProperty(value="P40D")) + assert result.value == datetime.timedelta(days=40) + result = client.property.iso8601(ISO8601DurationProperty(value=datetime.timedelta(days=40))) + assert result.value == datetime.timedelta(days=40) + result = client.property.iso8601(ISO8601DurationProperty(value="P40D")) + assert result.value == datetime.timedelta(days=40) + result = client.property.int32_seconds(Int32SecondsDurationProperty(value=36)) + assert result.value == 36 + result = client.property.float_seconds(FloatSecondsDurationProperty(value=35.625)) + assert abs(result.value - 35.625) < 0.0001 + result = client.property.float64_seconds(FloatSecondsDurationProperty(value=35.625)) + assert abs(result.value - 35.625) < 0.0001 + result = client.property.float_seconds_array(FloatSecondsDurationArrayProperty(value=[35.625, 46.75])) + assert abs(result.value[0] - 35.625) < 0.0001 + assert abs(result.value[1] - 46.75) < 0.0001 + + +def test_header(client: DurationClient): + client.header.default(duration=datetime.timedelta(days=40)) + client.header.iso8601(duration=datetime.timedelta(days=40)) + client.header.iso8601_array(duration=[datetime.timedelta(days=40), datetime.timedelta(days=50)]) + client.header.int32_seconds(duration=36) + client.header.float_seconds(duration=35.625) + client.header.float64_seconds(duration=35.625) diff --git a/packages/typespec-python/tests/mock_api/azure/test_encode_numeric.py b/packages/typespec-python/tests/mock_api/azure/test_encode_numeric.py new file mode 100644 index 0000000000..b0dff4af5c --- /dev/null +++ b/packages/typespec-python/tests/mock_api/azure/test_encode_numeric.py @@ -0,0 +1,31 @@ +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- +import pytest +from encode.numeric import NumericClient, models + + +@pytest.fixture +def client(): + with NumericClient() as client: + yield client + + +def test_safeint_as_string(client: NumericClient): + result = client.property.safeint_as_string(models.SafeintAsStringProperty(value=10000000000)) + assert result.value == 10000000000 + assert result["value"] == "10000000000" + + +def test_uint32_as_string_optional(client: NumericClient): + result = client.property.uint32_as_string_optional(models.Uint32AsStringProperty(value=1)) + assert result.value == 1 + assert result["value"] == "1" + + +def test_uint8_as_string_optional(client: NumericClient): + result = client.property.uint8_as_string(models.Uint32AsStringProperty(value=255)) + assert result.value == 255 + assert result["value"] == "255" diff --git a/packages/typespec-python/tests/mock_api/azure/test_model_base_flatten_compatibility.py b/packages/typespec-python/tests/mock_api/azure/test_model_base_flatten_compatibility.py new file mode 100644 index 0000000000..538b03a953 --- /dev/null +++ b/packages/typespec-python/tests/mock_api/azure/test_model_base_flatten_compatibility.py @@ -0,0 +1,251 @@ +# ------------------------------------ +# Copyright (c) Microsoft Corporation. +# Licensed under the MIT License. +# ------------------------------------ +import datetime +from typing import ( + Any, + Mapping, + Optional, + overload, +) + +from specs.azure.clientgenerator.core.flattenproperty._utils.model_base import ( + Model, + rest_field, +) +from azure.core.serialization import attribute_list + + +class ModelProperty(Model): + """This is a test model.""" + + value: str = rest_field() + """Required.""" + + @overload + def __init__( + self, + *, + value: str, + ) -> None: ... + + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: + """ + :param mapping: raw JSON to initialize the model. + :type mapping: Mapping[str, Any] + """ + + def __init__(self, *args: Any, **kwargs: Any) -> None: + super().__init__(*args, **kwargs) + + +class ChildModel(Model): + """This is the child model to be flattened. + + :ivar description: Required. + :vartype description: str + :ivar age: Required. + :vartype age: int + """ + + description: str = rest_field() + """Required.""" + age: int = rest_field() + """Required.""" + model_property: "ModelProperty" = rest_field(name="modelProperty") + """Required.""" + datetime_default: datetime.datetime = rest_field(name="datetimeDefault") + datetime_rfc3339: datetime.datetime = rest_field(name="datetimeRfc3339", format="rfc3339") + datetime_rfc7231: datetime.datetime = rest_field(name="datetimeRfc7231", format="rfc7231") + datetime_unix_timestamp: datetime.datetime = rest_field(name="datetimeUnixTimestamp", format="unix-timestamp") + + @overload + def __init__( + self, + *, + description: str, + age: int, + model_property: "ModelProperty", + datetime_default: datetime.datetime, + datetime_rfc3339: datetime.datetime, + datetime_rfc7231: datetime.datetime, + datetime_unix_timestamp: datetime.datetime, + ) -> None: ... + + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: + """ + :param mapping: raw JSON to initialize the model. + :type mapping: Mapping[str, Any] + """ + + def __init__(self, *args: Any, **kwargs: Any) -> None: + super().__init__(*args, **kwargs) + + +class FlattenModel(Model): + """This is the model with one level of flattening.""" + + name: str = rest_field() + """Required.""" + properties: "ChildModel" = rest_field() + """Required.""" + + __flattened_items = [ + "description", + "age", + "model_property", + "datetime_default", + "datetime_rfc3339", + "datetime_rfc7231", + "datetime_unix_timestamp", + ] + + @overload + def __init__( + self, + *, + name: str, + properties: "ChildModel", + ) -> None: ... + + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: + """ + :param mapping: raw JSON to initialize the model. + :type mapping: Mapping[str, Any] + """ + + def __init__(self, *args: Any, **kwargs: Any) -> None: + _flattened_input = {k: kwargs.pop(k) for k in kwargs.keys() & self.__flattened_items} + super().__init__(*args, **kwargs) + for k, v in _flattened_input.items(): + setattr(self, k, v) + + def __getattr__(self, name: str) -> Any: + if name in self.__flattened_items: + if self.properties is None: + return None + return getattr(self.properties, name) + raise AttributeError(f"'{self.__class__.__name__}' object has no attribute '{name}'") + + def __setattr__(self, key: str, value: Any) -> None: + if key in self.__flattened_items: + if self.properties is None: + self.properties = self._attr_to_rest_field["properties"]._class_type() + setattr(self.properties, key, value) + else: + super().__setattr__(key, value) + + +def test_model_initialization(): + model = FlattenModel( + name="test", + description="a description", + age=30, + model_property=ModelProperty(value="test value"), + datetime_default=datetime.datetime(2023, 1, 12, 0, 0, 0, tzinfo=datetime.timezone.utc), + datetime_rfc3339=datetime.datetime(2023, 1, 12, 0, 0, 0, tzinfo=datetime.timezone.utc), + datetime_rfc7231=datetime.datetime(2023, 1, 12, 0, 0, 0, tzinfo=datetime.timezone.utc), + datetime_unix_timestamp=datetime.datetime(2023, 1, 12, 0, 0, 0, tzinfo=datetime.timezone.utc), + ) + + assert model.name == "test" + + assert model.description == "a description" + assert model.properties.description == "a description" + + assert model.age == 30 + assert model.properties.age == 30 + + assert model.model_property.value == "test value" + assert model.properties.model_property == ModelProperty(value="test value") + assert model.properties.model_property.value == "test value" + + assert model.datetime_default == datetime.datetime(2023, 1, 12, 0, 0, 0, tzinfo=datetime.timezone.utc) + assert model.properties.datetime_default == datetime.datetime(2023, 1, 12, 0, 0, 0, tzinfo=datetime.timezone.utc) + assert model.properties["datetimeDefault"] == "2023-01-12T00:00:00Z" + + assert model.datetime_rfc3339 == datetime.datetime(2023, 1, 12, 0, 0, 0, tzinfo=datetime.timezone.utc) + assert model.properties.datetime_rfc3339 == datetime.datetime(2023, 1, 12, 0, 0, 0, tzinfo=datetime.timezone.utc) + assert model.properties["datetimeRfc3339"] == "2023-01-12T00:00:00Z" + + assert model.datetime_rfc7231 == datetime.datetime(2023, 1, 12, 0, 0, 0, tzinfo=datetime.timezone.utc) + assert model.properties.datetime_rfc7231 == datetime.datetime(2023, 1, 12, 0, 0, 0, tzinfo=datetime.timezone.utc) + assert model.properties["datetimeRfc7231"] == "Thu, 12 Jan 2023 00:00:00 GMT" + + assert model.datetime_unix_timestamp == datetime.datetime(2023, 1, 12, 0, 0, 0, tzinfo=datetime.timezone.utc) + assert model.properties.datetime_unix_timestamp == datetime.datetime( + 2023, 1, 12, 0, 0, 0, tzinfo=datetime.timezone.utc + ) + assert model.properties["datetimeUnixTimestamp"] == 1673481600 + + +class FlattenModelWithOptionalProperties(Model): + """This is the model with one level of flattening and optional properties.""" + + name: str = rest_field() + """Required.""" + properties: Optional["ModelProperty"] = rest_field() + """Optional.""" + + __flattened_items = ["value"] + + @overload + def __init__( + self, + *, + name: str, + properties: Optional["ModelProperty"], + ) -> None: ... + + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: + """ + :param mapping: raw JSON to initialize the model. + :type mapping: Mapping[str, Any] + """ + + def __init__(self, *args: Any, **kwargs: Any) -> None: + _flattened_input = {k: kwargs.pop(k) for k in kwargs.keys() & self.__flattened_items} + super().__init__(*args, **kwargs) + for k, v in _flattened_input.items(): + setattr(self, k, v) + + def __getattr__(self, name: str) -> Any: + if name in self.__flattened_items: + if self.properties is None: + return None + return getattr(self.properties, name) + raise AttributeError(f"'{self.__class__.__name__}' object has no attribute '{name}'") + + def __setattr__(self, key: str, value: Any) -> None: + if key in self.__flattened_items: + if self.properties is None: + self.properties = self._attr_to_rest_field["properties"]._class_type() + setattr(self.properties, key, value) + else: + super().__setattr__(key, value) + + +def test_model_with_optional_properties_initialization(): + model = FlattenModelWithOptionalProperties( + name="test", + value="test value", + ) + + assert model.name == "test" + + assert model.value == "test value" + assert model.properties.value == "test value" + + +def test_model_with_optional_properties_attribute_list(): + model = FlattenModelWithOptionalProperties( + name="test", + ) + + attrs = attribute_list(model) + assert sorted(attrs) == sorted(["name", "value"]) diff --git a/packages/typespec-python/tests/mock_api/azure/test_parameters_basic.py b/packages/typespec-python/tests/mock_api/azure/test_parameters_basic.py new file mode 100644 index 0000000000..922bc1d629 --- /dev/null +++ b/packages/typespec-python/tests/mock_api/azure/test_parameters_basic.py @@ -0,0 +1,22 @@ +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- +import pytest +from parameters.basic import BasicClient +from parameters.basic.models import User + + +@pytest.fixture +def client(): + with BasicClient() as client: + yield client + + +def test_explicit_simple(client: BasicClient): + client.explicit_body.simple(User(name="foo")) + + +def test_implicit_simple(client: BasicClient): + client.implicit_body.simple(name="foo") diff --git a/packages/typespec-python/tests/mock_api/azure/test_parameters_spread.py b/packages/typespec-python/tests/mock_api/azure/test_parameters_spread.py new file mode 100644 index 0000000000..c205034971 --- /dev/null +++ b/packages/typespec-python/tests/mock_api/azure/test_parameters_spread.py @@ -0,0 +1,66 @@ +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- +import pytest +from parameters.spread import SpreadClient +from parameters.spread.models import BodyParameter + + +@pytest.fixture +def client(): + with SpreadClient() as client: + yield client + + +def test_model_body(client: SpreadClient): + client.model.spread_as_request_body(name="foo") + + +def test_model_composite_request_only_with_body(client: SpreadClient): + client.model.spread_composite_request_only_with_body(BodyParameter(name="foo")) + + +def test_model_composite_request_without_body(client: SpreadClient): + client.model.spread_composite_request_without_body(name="foo", test_header="bar") + + +def test_model_composite_request(client: SpreadClient): + client.model.spread_composite_request(name="foo", body=BodyParameter(name="foo"), test_header="bar") + + +def test_model_composite_request_mix(client: SpreadClient): + client.model.spread_composite_request_mix(name="foo", prop="foo", test_header="bar") + + +def test_alias_body(client: SpreadClient): + client.alias.spread_as_request_body(name="foo") + + +def test_alias_parameter(client: SpreadClient): + client.alias.spread_as_request_parameter("1", x_ms_test_header="bar", name="foo") + + +def test_alias_multiple_parameter(client: SpreadClient): + client.alias.spread_with_multiple_parameters( + "1", + x_ms_test_header="bar", + required_string="foo", + required_int_list=[1, 2], + optional_string_list=["foo", "bar"], + optional_int=1, + ) + client.alias.spread_with_multiple_parameters( + "1", + {"requiredString": "foo", "optionalInt": 1, "requiredIntList": [1, 2], "optionalStringList": ["foo", "bar"]}, + x_ms_test_header="bar", + ) + + +def test_inner_model(client: SpreadClient): + client.alias.spread_parameter_with_inner_model(id="1", x_ms_test_header="bar", body={"name": "foo"}) + + +def test_inner_alias(client: SpreadClient): + client.alias.spread_parameter_with_inner_alias(id="1", x_ms_test_header="bar", body={"name": "foo", "age": 1}) diff --git a/packages/typespec-python/tests/mock_api/azure/test_payload_content_negotiation.py b/packages/typespec-python/tests/mock_api/azure/test_payload_content_negotiation.py new file mode 100644 index 0000000000..27fa1ba25f --- /dev/null +++ b/packages/typespec-python/tests/mock_api/azure/test_payload_content_negotiation.py @@ -0,0 +1,33 @@ +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- +import base64 +import pytest +from payload.contentnegotiation import ContentNegotiationClient +from payload.contentnegotiation.models import PngImageAsJson + + +@pytest.fixture +def client(): + with ContentNegotiationClient(endpoint="http://localhost:3000") as client: + yield client + + +def test_get_avatar_as_png(client: ContentNegotiationClient, png_data: bytes): + assert b"".join(client.same_body.get_avatar_as_png()) == png_data + + +def test_get_avatar_as_jpeg(client: ContentNegotiationClient, jpg_data: bytes): + assert b"".join(client.same_body.get_avatar_as_jpeg()) == jpg_data + + +def test_different_body_get_avatar_as_png(client: ContentNegotiationClient, png_data: bytes): + assert b"".join(client.different_body.get_avatar_as_png()) == png_data + + +def test_different_body_get_avatar_as_json(client: ContentNegotiationClient, png_data: bytes): + result = client.different_body.get_avatar_as_json() + expected = PngImageAsJson(content=base64.b64encode(png_data).decode()) + assert result == expected diff --git a/packages/typespec-python/tests/mock_api/azure/test_payload_multipart.py b/packages/typespec-python/tests/mock_api/azure/test_payload_multipart.py new file mode 100644 index 0000000000..d99780920f --- /dev/null +++ b/packages/typespec-python/tests/mock_api/azure/test_payload_multipart.py @@ -0,0 +1,198 @@ +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- +from pathlib import Path +import pytest +from payload.multipart import MultiPartClient, models + +JPG = Path(__file__).parent / "data/image.jpg" +PNG = Path(__file__).parent / "data/image.png" + + +@pytest.fixture +def client(): + with MultiPartClient(endpoint="http://localhost:3000") as client: + yield client + + +def test_anonymous_model(client: MultiPartClient): + client.form_data.anonymous_model({"profileImage": open(str(JPG), "rb")}) + + +def test_basic(client: MultiPartClient): + client.form_data.basic( + models.MultiPartRequest( + id="123", + profile_image=open(str(JPG), "rb"), + ) + ) + + +def test_binary_array_parts(client: MultiPartClient): + client.form_data.binary_array_parts( + models.BinaryArrayPartsRequest( + id="123", + pictures=[ + open(str(PNG), "rb"), + open(str(PNG), "rb"), + ], + ) + ) + + +def test_check_file_name_and_content_type(client: MultiPartClient): + client.form_data.check_file_name_and_content_type( + models.MultiPartRequest( + id="123", + profile_image=("hello.jpg", open(str(JPG), "rb"), "image/jpg"), + ) + ) + + +def test_complex(client: MultiPartClient): + client.form_data.file_array_and_basic( + models.ComplexPartsRequest( + id="123", + address=models.Address(city="X"), + pictures=[ + open(str(PNG), "rb"), + open(str(PNG), "rb"), + ], + profile_image=open(str(JPG), "rb"), + ) + ) + + +def test_json_part(client: MultiPartClient): + client.form_data.json_part( + models.JsonPartRequest( + address=models.Address(city="X"), + profile_image=open(str(JPG), "rb"), + ) + ) + + +def test_multi_binary_parts(client: MultiPartClient): + client.form_data.multi_binary_parts( + models.MultiBinaryPartsRequest( + profile_image=open(str(JPG), "rb"), + picture=open(str(PNG), "rb"), + ) + ) + client.form_data.multi_binary_parts( + models.MultiBinaryPartsRequest( + profile_image=open(str(JPG), "rb"), + ) + ) + + +def test_file_with_http_part_specific_content_type(client: MultiPartClient): + client.form_data.http_parts.content_type.image_jpeg_content_type( + models.FileWithHttpPartSpecificContentTypeRequest( + profile_image=("hello.jpg", open(str(JPG), "rb"), "image/jpg"), + ) + ) + + +def test_file_with_http_part_required_content_type(client: MultiPartClient): + client.form_data.http_parts.content_type.required_content_type( + models.FileWithHttpPartRequiredContentTypeRequest( + profile_image=open(str(JPG), "rb"), + ) + ) + + +def test_file_with_http_part_optional_content_type(client: MultiPartClient): + # call twice: one with content type, one without + client.form_data.http_parts.content_type.optional_content_type( + models.FileWithHttpPartOptionalContentTypeRequest( + profile_image=("hello.jpg", open(str(JPG), "rb").read()), + ) + ) + client.form_data.http_parts.content_type.optional_content_type( + models.FileWithHttpPartOptionalContentTypeRequest( + profile_image=("hello.jpg", open(str(JPG), "rb").read(), "application/octet-stream"), + ) + ) + + +def test_complex_with_http_part(client: MultiPartClient): + client.form_data.http_parts.json_array_and_file_array( + models.ComplexHttpPartsModelRequest( + id="123", + previous_addresses=[ + models.Address(city="Y"), + models.Address(city="Z"), + ], + address=models.Address(city="X"), + pictures=[ + open(str(PNG), "rb"), + open(str(PNG), "rb"), + ], + profile_image=open(str(JPG), "rb"), + ) + ) + + +def test_http_parts_non_string_float(client: MultiPartClient): + client.form_data.http_parts.non_string.float(models.FloatRequest(temperature=0.5)) + + +def test_with_wire_name(client: MultiPartClient): + client.form_data.with_wire_name( + models.MultiPartRequestWithWireName( + identifier="123", + image=open(str(JPG), "rb"), + ) + ) + + +def test_optional_parts(client: MultiPartClient): + # First time with only id + client.form_data.optional_parts( + models.MultiPartOptionalRequest( + id="123", + ) + ) + # Second time with only profileImage + client.form_data.optional_parts( + models.MultiPartOptionalRequest( + profile_image=open(str(JPG), "rb"), + ) + ) + # Third time with both id and profileImage + client.form_data.optional_parts( + models.MultiPartOptionalRequest( + id="123", + profile_image=open(str(JPG), "rb"), + ) + ) + + +def test_file_upload_file_specific_content_type(client: MultiPartClient): + client.form_data.file.upload_file_specific_content_type( + models.UploadFileSpecificContentTypeRequest( + file=("image.png", open(str(PNG), "rb"), "image/png"), + ) + ) + + +def test_file_upload_file_required_filename(client: MultiPartClient): + client.form_data.file.upload_file_required_filename( + models.UploadFileRequiredFilenameRequest( + file=("image.png", open(str(PNG), "rb"), "image/png"), + ) + ) + + +def test_file_upload_file_array(client: MultiPartClient): + client.form_data.file.upload_file_array( + models.UploadFileArrayRequest( + files=[ + ("image.png", open(str(PNG), "rb"), "image/png"), + ("image.png", open(str(PNG), "rb"), "image/png"), + ], + ) + ) diff --git a/packages/typespec-python/tests/mock_api/azure/test_resiliency_srv_driven.py b/packages/typespec-python/tests/mock_api/azure/test_resiliency_srv_driven.py new file mode 100644 index 0000000000..a7f3f9a1e5 --- /dev/null +++ b/packages/typespec-python/tests/mock_api/azure/test_resiliency_srv_driven.py @@ -0,0 +1,124 @@ +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- +import pytest +from resiliency.srv.driven1 import ResiliencyServiceDrivenClient as V1Client +from resiliency.srv.driven2 import ResiliencyServiceDrivenClient as V2Client + + +def get_v1_client(service_deployment_version: str, api_version: str = "v1") -> V1Client: + return V1Client( + endpoint="http://localhost:3000", + service_deployment_version=service_deployment_version, + api_version=api_version, + ) + + +def get_v2_client(service_deployment_version: str, api_version: str = "v2") -> V2Client: + return V2Client( + endpoint="http://localhost:3000", + service_deployment_version=service_deployment_version, + api_version=api_version, + ) + + +def test_add_optional_param_from_none(): + # old client to old service with api version v1 + with V1Client(endpoint="http://localhost:3000", service_deployment_version="v1") as client: + client.from_none() + + # old client to new service with api version v1 + with V1Client(endpoint="http://localhost:3000", service_deployment_version="v2") as client: + client.from_none() + + # new client to new service with api version v1 + with V2Client( + endpoint="http://localhost:3000", + service_deployment_version="v2", + api_version="v1", + ) as client: + client.from_none() + + # new client to new service with api version v2 + with V2Client(endpoint="http://localhost:3000", service_deployment_version="v2") as client: + client.from_none(new_parameter="new") + + +def test_add_optional_param_from_one_required(): + # old client to old service with api version v1 + with V1Client(endpoint="http://localhost:3000", service_deployment_version="v1") as client: + client.from_one_required(parameter="required") + + # old client to new service with api version v1 + with V1Client(endpoint="http://localhost:3000", service_deployment_version="v2") as client: + client.from_one_required(parameter="required") + + # new client to new service with api version v1 + with V2Client( + endpoint="http://localhost:3000", + service_deployment_version="v2", + api_version="v1", + ) as client: + client.from_one_required(parameter="required") + + # new client to new service with api version v2 + with V2Client(endpoint="http://localhost:3000", service_deployment_version="v2") as client: + client.from_one_required(parameter="required", new_parameter="new") + + +def test_add_optional_param_from_one_optional(): + # old client to old service with api version v1 + with V1Client(endpoint="http://localhost:3000", service_deployment_version="v1") as client: + client.from_one_optional(parameter="optional") + + # old client to new service with api version v1 + with V1Client(endpoint="http://localhost:3000", service_deployment_version="v2") as client: + client.from_one_optional(parameter="optional") + + # new client to new service with api version v1 + with V2Client( + endpoint="http://localhost:3000", + service_deployment_version="v2", + api_version="v1", + ) as client: + client.from_one_optional(parameter="optional") + + # new client to new service with api version v2 + with V2Client(endpoint="http://localhost:3000", service_deployment_version="v2") as client: + client.from_one_optional(parameter="optional", new_parameter="new") + + +def test_break_the_glass(): + from azure.core.rest import HttpRequest + + request = HttpRequest(method="DELETE", url="/add-operation") + with V1Client( + endpoint="http://localhost:3000", + service_deployment_version="v2", + api_version="v2", + ) as client: + response = client.send_request(request) + response.raise_for_status() + + +def test_add_operation(): + with V2Client(endpoint="http://localhost:3000", service_deployment_version="v2") as client: + client.add_operation() + + +@pytest.mark.parametrize( + "func_name, params", + [ + ("from_none", {"new_parameter": "new"}), + ("from_one_optional", {"parameter": "optional", "new_parameter": "new"}), + ("from_one_required", {"parameter": "required", "new_parameter": "new"}), + ("add_operation", {}), + ], +) +def test_new_client_with_old_apiversion_call_new_parameter(func_name, params): + client = get_v2_client(service_deployment_version="v2", api_version="v1") + with pytest.raises(ValueError) as ex: + getattr(client, func_name)(**params) + assert "is not available in API version" in str(ex.value) diff --git a/packages/typespec-python/tests/mock_api/azure/test_serialization_encoded_name_json.py b/packages/typespec-python/tests/mock_api/azure/test_serialization_encoded_name_json.py new file mode 100644 index 0000000000..0f61ce86f2 --- /dev/null +++ b/packages/typespec-python/tests/mock_api/azure/test_serialization_encoded_name_json.py @@ -0,0 +1,21 @@ +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- +import pytest +from serialization.encodedname.json import JsonClient, models + + +@pytest.fixture +def client(): + with JsonClient() as client: + yield client + + +def test_property_send(client: JsonClient): + client.property.send(models.JsonEncodedNameModel(default_name=True)) + + +def test_property_get(client: JsonClient): + assert client.property.get().default_name diff --git a/packages/typespec-python/tests/mock_api/azure/test_service_multi_service.py b/packages/typespec-python/tests/mock_api/azure/test_service_multi_service.py new file mode 100644 index 0000000000..4a1f9f7803 --- /dev/null +++ b/packages/typespec-python/tests/mock_api/azure/test_service_multi_service.py @@ -0,0 +1,29 @@ +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- +import pytest +from azure.core.exceptions import HttpResponseError +from service.multiservice import CombinedClient +from service.multiservice.models import VersionsA, VersionsB + + +@pytest.fixture +def client(): + """Fixture that creates a CombinedClient for testing.""" + return CombinedClient(endpoint="http://localhost:3000") + + +def test_service_multi_service_foo(client): + with pytest.raises(HttpResponseError): + client.foo.test(api_version=VersionsA.AV1) + + client.foo.test() + + +def test_service_multi_service_bar(client): + with pytest.raises(HttpResponseError): + client.bar.test(api_version=VersionsB.BV1) + + client.bar.test() diff --git a/packages/typespec-python/tests/mock_api/azure/test_special_words.py b/packages/typespec-python/tests/mock_api/azure/test_special_words.py new file mode 100644 index 0000000000..ab23b59409 --- /dev/null +++ b/packages/typespec-python/tests/mock_api/azure/test_special_words.py @@ -0,0 +1,63 @@ +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- +import pytest +from specialwords import SpecialWordsClient, models + + +@pytest.fixture +def client(): + with SpecialWordsClient() as client: + yield client + + +def test_operations(client: SpecialWordsClient, special_words): + for sw in special_words: + suffix = "" if sw == "constructor" else "_method" + getattr(client.operations, sw + suffix)() + + +def test_parameter(client: SpecialWordsClient, special_words): + for sw in special_words: + suffix = "" if sw == "constructor" else "_parameter" + getattr(client.parameters, "with_" + sw)(**{sw + suffix: "ok"}) + client.parameters.with_cancellation_token(cancellation_token="ok") + + +def test_model(client: SpecialWordsClient, special_words): + for sw in special_words: + suffix = "" if sw == "constructor" else "Model" + model = getattr(models, sw.capitalize() + suffix) + getattr(client.models, "with_" + sw)(model(name="ok")) + + +def test_model_properties(client: SpecialWordsClient): + client.model_properties.same_as_model(models.SameAsModel(same_as_model="ok")) + + +def test_model_properties_dict_methods(client: SpecialWordsClient): + client.model_properties.dict_methods( + body=models.DictMethods( + keys_property="ok", + items_property="ok", + values_property="ok", + popitem_property="ok", + clear_property="ok", + update_property="ok", + setdefault_property="ok", + pop_property="ok", + get_property="ok", + copy_property="ok", + ) + ) + + +def test_model_properties_with_list(client: SpecialWordsClient): + client.model_properties.with_list(models.ModelWithList(list="ok")) + + +def test_extensible_strings(client: SpecialWordsClient): + for enum_value in models.ExtensibleString: + assert enum_value == client.extensible_strings.put_extensible_string_value(body=enum_value) diff --git a/packages/typespec-python/tests/mock_api/shared/asynctests/test_authentication_async.py b/packages/typespec-python/tests/mock_api/shared/asynctests/test_authentication_async.py new file mode 100644 index 0000000000..4be9d3a731 --- /dev/null +++ b/packages/typespec-python/tests/mock_api/shared/asynctests/test_authentication_async.py @@ -0,0 +1,141 @@ +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- +import pytest +import pytest_asyncio +from authentication.apikey.aio import ApiKeyClient +from authentication.http.custom.aio import CustomClient +from authentication.oauth2.aio import OAuth2Client +from authentication.union.aio import UnionClient +from setuppy.authentication.union.aio import UnionClient as SetuppyUnionClient +from authentication.noauth.union.aio import UnionClient as NoauthUnionClient + +# Utilities functions + + +@pytest_asyncio.fixture +async def api_key_client(key_credential): + client = None + + def _build_client(client_type, key: str = "valid-key"): + client = client_type(key_credential(key)) + return client + + yield _build_client + if client: + await client.close() + + +@pytest.fixture() +def token_credential(core_library): + class FakeCredential: + @staticmethod + async def get_token(*scopes): + return core_library.credentials.AccessToken(token="".join(scopes), expires_on=1800) + + @staticmethod + async def get_token_info(*scopes, **kwargs): + return core_library.credentials.AccessTokenInfo(token="".join(scopes), expires_on=1800) + + return FakeCredential() + + +@pytest_asyncio.fixture +async def oauth2_client(token_credential): + client = None + + def _build_client(client_type): + client = client_type(token_credential) + return client + + yield _build_client + if client: + await client.close() + + +@pytest_asyncio.fixture +async def http_custom_client(key_credential): + client = None + + def _build_client(key: str = "valid-key"): + client = CustomClient(key_credential(key)) + return client + + yield _build_client + if client: + await client.close() + + +# Tests + + +@pytest.mark.asyncio +async def test_api_key_valid(api_key_client): + client = api_key_client(ApiKeyClient) + await client.valid() + + +@pytest.mark.asyncio +async def test_api_key_invalid(api_key_client, core_library): + client = api_key_client(ApiKeyClient, "invalid-key") + with pytest.raises(core_library.exceptions.HttpResponseError) as ex: + await client.invalid() + assert ex.value.status_code == 403 + assert ex.value.reason == "Forbidden" + + +@pytest.mark.asyncio +async def test_oauth2_valid(oauth2_client): + client = oauth2_client(OAuth2Client) + await client.valid(enforce_https=False) + + +@pytest.mark.asyncio +async def test_oauth2_invalid(oauth2_client, core_library): + client = oauth2_client(OAuth2Client) + with pytest.raises(core_library.exceptions.HttpResponseError) as ex: + await client.invalid(enforce_https=False) + assert ex.value.status_code == 403 + + +@pytest.mark.asyncio +@pytest.mark.parametrize("union_client_type", [UnionClient, SetuppyUnionClient]) +async def test_union_keyvalid(api_key_client, union_client_type): + client = api_key_client(union_client_type) + await client.valid_key() + + +@pytest.mark.asyncio +@pytest.mark.parametrize("union_client_type", [UnionClient, SetuppyUnionClient]) +async def test_union_tokenvalid(oauth2_client, union_client_type): + client = oauth2_client(union_client_type) + await client.valid_token(enforce_https=False) + + +@pytest.mark.asyncio +async def test_noauth_union_valid_no_auth(): + client = NoauthUnionClient() + await client.valid_no_auth() + + +@pytest.mark.asyncio +async def test_noauth_union_valid_token(oauth2_client): + client = oauth2_client(NoauthUnionClient) + await client.valid_token(enforce_https=False) + + +@pytest.mark.asyncio +async def test_http_custom_valid(http_custom_client): + client = http_custom_client() + await client.valid() + + +@pytest.mark.asyncio +async def test_http_custom_invalid(http_custom_client, core_library): + client = http_custom_client(key="invalid-key") + with pytest.raises(core_library.exceptions.HttpResponseError) as ex: + await client.invalid() + assert ex.value.status_code == 403 + assert ex.value.reason == "Forbidden" diff --git a/packages/typespec-python/tests/mock_api/shared/asynctests/test_encode_array_async.py b/packages/typespec-python/tests/mock_api/shared/asynctests/test_encode_array_async.py new file mode 100644 index 0000000000..3ec7a56529 --- /dev/null +++ b/packages/typespec-python/tests/mock_api/shared/asynctests/test_encode_array_async.py @@ -0,0 +1,140 @@ +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- + +import pytest +import pytest_asyncio +from encode.array.aio import ArrayClient +from encode.array import models + + +@pytest_asyncio.fixture +async def client(): + async with ArrayClient() as client: + yield client + + +@pytest.mark.asyncio +async def test_comma_delimited(client: ArrayClient): + body = models.CommaDelimitedArrayProperty(value=["blue", "red", "green"]) + result = await client.property.comma_delimited(body) + assert result.value == ["blue", "red", "green"] + + +@pytest.mark.asyncio +async def test_space_delimited(client: ArrayClient): + body = models.SpaceDelimitedArrayProperty(value=["blue", "red", "green"]) + result = await client.property.space_delimited(body) + assert result.value == ["blue", "red", "green"] + + +@pytest.mark.asyncio +async def test_pipe_delimited(client: ArrayClient): + body = models.PipeDelimitedArrayProperty(value=["blue", "red", "green"]) + result = await client.property.pipe_delimited(body) + assert result.value == ["blue", "red", "green"] + + +@pytest.mark.asyncio +async def test_newline_delimited(client: ArrayClient): + body = models.NewlineDelimitedArrayProperty(value=["blue", "red", "green"]) + result = await client.property.newline_delimited(body) + assert result.value == ["blue", "red", "green"] + + +@pytest.mark.asyncio +async def test_enum_comma_delimited(client: ArrayClient): + body = models.CommaDelimitedEnumArrayProperty(value=[models.Colors.BLUE, models.Colors.RED, models.Colors.GREEN]) + result = await client.property.enum_comma_delimited(body) + assert result.value == [models.Colors.BLUE, models.Colors.RED, models.Colors.GREEN] + + +@pytest.mark.asyncio +async def test_enum_space_delimited(client: ArrayClient): + body = models.SpaceDelimitedEnumArrayProperty(value=[models.Colors.BLUE, models.Colors.RED, models.Colors.GREEN]) + result = await client.property.enum_space_delimited(body) + assert result.value == [models.Colors.BLUE, models.Colors.RED, models.Colors.GREEN] + + +@pytest.mark.asyncio +async def test_enum_pipe_delimited(client: ArrayClient): + body = models.PipeDelimitedEnumArrayProperty(value=[models.Colors.BLUE, models.Colors.RED, models.Colors.GREEN]) + result = await client.property.enum_pipe_delimited(body) + assert result.value == [models.Colors.BLUE, models.Colors.RED, models.Colors.GREEN] + + +@pytest.mark.asyncio +async def test_enum_newline_delimited(client: ArrayClient): + body = models.NewlineDelimitedEnumArrayProperty(value=[models.Colors.BLUE, models.Colors.RED, models.Colors.GREEN]) + result = await client.property.enum_newline_delimited(body) + assert result.value == [models.Colors.BLUE, models.Colors.RED, models.Colors.GREEN] + + +@pytest.mark.asyncio +async def test_extensible_enum_comma_delimited(client: ArrayClient): + body = models.CommaDelimitedExtensibleEnumArrayProperty( + value=[ + models.ColorsExtensibleEnum.BLUE, + models.ColorsExtensibleEnum.RED, + models.ColorsExtensibleEnum.GREEN, + ] + ) + result = await client.property.extensible_enum_comma_delimited(body) + assert result.value == [ + models.ColorsExtensibleEnum.BLUE, + models.ColorsExtensibleEnum.RED, + models.ColorsExtensibleEnum.GREEN, + ] + + +@pytest.mark.asyncio +async def test_extensible_enum_space_delimited(client: ArrayClient): + body = models.SpaceDelimitedExtensibleEnumArrayProperty( + value=[ + models.ColorsExtensibleEnum.BLUE, + models.ColorsExtensibleEnum.RED, + models.ColorsExtensibleEnum.GREEN, + ] + ) + result = await client.property.extensible_enum_space_delimited(body) + assert result.value == [ + models.ColorsExtensibleEnum.BLUE, + models.ColorsExtensibleEnum.RED, + models.ColorsExtensibleEnum.GREEN, + ] + + +@pytest.mark.asyncio +async def test_extensible_enum_pipe_delimited(client: ArrayClient): + body = models.PipeDelimitedExtensibleEnumArrayProperty( + value=[ + models.ColorsExtensibleEnum.BLUE, + models.ColorsExtensibleEnum.RED, + models.ColorsExtensibleEnum.GREEN, + ] + ) + result = await client.property.extensible_enum_pipe_delimited(body) + assert result.value == [ + models.ColorsExtensibleEnum.BLUE, + models.ColorsExtensibleEnum.RED, + models.ColorsExtensibleEnum.GREEN, + ] + + +@pytest.mark.asyncio +async def test_extensible_enum_newline_delimited(client: ArrayClient): + body = models.NewlineDelimitedExtensibleEnumArrayProperty( + value=[ + models.ColorsExtensibleEnum.BLUE, + models.ColorsExtensibleEnum.RED, + models.ColorsExtensibleEnum.GREEN, + ] + ) + result = await client.property.extensible_enum_newline_delimited(body) + assert result.value == [ + models.ColorsExtensibleEnum.BLUE, + models.ColorsExtensibleEnum.RED, + models.ColorsExtensibleEnum.GREEN, + ] diff --git a/packages/typespec-python/tests/mock_api/shared/asynctests/test_encode_bytes_async.py b/packages/typespec-python/tests/mock_api/shared/asynctests/test_encode_bytes_async.py new file mode 100644 index 0000000000..5c57cb4281 --- /dev/null +++ b/packages/typespec-python/tests/mock_api/shared/asynctests/test_encode_bytes_async.py @@ -0,0 +1,133 @@ +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- +import pytest +import pytest_asyncio +from pathlib import Path +from encode.bytes.aio import BytesClient +from encode.bytes.models import ( + DefaultBytesProperty, + Base64urlBytesProperty, + Base64BytesProperty, + Base64urlArrayBytesProperty, +) + +FILE_FOLDER = Path(__file__).parent.parent + + +@pytest_asyncio.fixture +async def client(): + async with BytesClient() as client: + yield client + + +@pytest.mark.asyncio +async def test_query(client: BytesClient): + await client.query.default( + value=bytes("test", "utf-8"), + ) + await client.query.base64( + value=bytes("test", "utf-8"), + ) + await client.query.base64_url( + value=bytes("test", "utf-8"), + ) + await client.query.base64_url_array( + value=[ + bytes("test", "utf-8"), + bytes("test", "utf-8"), + ], + ) + + +@pytest.mark.asyncio +async def test_property(client: BytesClient): + result = await client.property.default( + DefaultBytesProperty( + value=bytes("test", "utf-8"), + ) + ) + assert result.value == bytes("test", "utf-8") + + result = await client.property.base64( + Base64BytesProperty( + value=bytes("test", "utf-8"), + ) + ) + assert result.value == bytes("test", "utf-8") + + result = await client.property.base64_url( + Base64urlBytesProperty( + value=bytes("test", "utf-8"), + ) + ) + assert result.value == bytes("test", "utf-8") + + result = await client.property.base64_url_array( + Base64urlArrayBytesProperty( + value=[ + bytes("test", "utf-8"), + bytes("test", "utf-8"), + ], + ) + ) + assert result.value == [ + bytes("test", "utf-8"), + bytes("test", "utf-8"), + ] + + +@pytest.mark.asyncio +async def test_header(client: BytesClient): + await client.header.default( + value=bytes("test", "utf-8"), + ) + await client.header.base64( + value=bytes("test", "utf-8"), + ) + await client.header.base64_url( + value=bytes("test", "utf-8"), + ) + await client.header.base64_url_array( + value=[ + bytes("test", "utf-8"), + bytes("test", "utf-8"), + ], + ) + + +@pytest.fixture +def png_data() -> bytes: + with open(str(FILE_FOLDER / "data/image.png"), "rb") as file_in: + return file_in.read() + + +@pytest.mark.asyncio +async def test_request_body(client: BytesClient, png_data: bytes): + await client.request_body.default( + value=png_data, + ) + await client.request_body.octet_stream( + value=png_data, + ) + await client.request_body.custom_content_type( + value=png_data, + ) + await client.request_body.base64( + value=bytes("test", "utf-8"), + ) + await client.request_body.base64_url( + value=bytes("test", "utf-8"), + ) + + +@pytest.mark.asyncio +async def test_response_body(client: BytesClient, png_data: bytes): + expected = b"test" + assert b"".join([d async for d in (await client.response_body.default())]) == png_data + assert expected == await client.response_body.base64() + assert b"".join([d async for d in (await client.response_body.octet_stream())]) == png_data + assert b"".join([d async for d in (await client.response_body.custom_content_type())]) == png_data + assert expected == await client.response_body.base64_url() diff --git a/packages/typespec-python/tests/mock_api/shared/asynctests/test_encode_datetime_async.py b/packages/typespec-python/tests/mock_api/shared/asynctests/test_encode_datetime_async.py new file mode 100644 index 0000000000..bd5b590a09 --- /dev/null +++ b/packages/typespec-python/tests/mock_api/shared/asynctests/test_encode_datetime_async.py @@ -0,0 +1,128 @@ +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- +import datetime + +import pytest +import pytest_asyncio +from encode.datetime.aio import DatetimeClient +from encode.datetime.models import ( + DefaultDatetimeProperty, + Rfc3339DatetimeProperty, + Rfc7231DatetimeProperty, + UnixTimestampDatetimeProperty, + UnixTimestampArrayDatetimeProperty, +) + + +@pytest_asyncio.fixture +async def client(): + async with DatetimeClient() as client: + yield client + + +@pytest.mark.asyncio +async def test_query(client: DatetimeClient): + await client.query.default( + value=datetime.datetime(2022, 8, 26, 18, 38, 0, tzinfo=datetime.timezone.utc), + ) + await client.query.rfc3339( + value=datetime.datetime(2022, 8, 26, 18, 38, 0, tzinfo=datetime.timezone.utc), + ) + await client.query.rfc7231( + value=datetime.datetime(2022, 8, 26, 14, 38, 0, tzinfo=datetime.timezone.utc), + ) + await client.query.unix_timestamp( + value=datetime.datetime(2023, 6, 12, 10, 47, 44, tzinfo=datetime.timezone.utc), + ) + await client.query.unix_timestamp_array( + value=[ + datetime.datetime(2023, 6, 12, 10, 47, 44, tzinfo=datetime.timezone.utc), + datetime.datetime(2023, 6, 14, 9, 17, 36, tzinfo=datetime.timezone.utc), + ], + ) + + +@pytest.mark.asyncio +async def test_property(client: DatetimeClient): + result = await client.property.default( + DefaultDatetimeProperty( + value=datetime.datetime(2022, 8, 26, 18, 38, 0, tzinfo=datetime.timezone.utc), + ) + ) + assert result.value == datetime.datetime(2022, 8, 26, 18, 38, 0, tzinfo=datetime.timezone.utc) + + result = await client.property.rfc3339( + Rfc3339DatetimeProperty( + value=datetime.datetime(2022, 8, 26, 18, 38, 0, tzinfo=datetime.timezone.utc), + ) + ) + assert result.value == datetime.datetime(2022, 8, 26, 18, 38, 0, tzinfo=datetime.timezone.utc) + + result = await client.property.rfc7231( + Rfc7231DatetimeProperty( + value=datetime.datetime(2022, 8, 26, 14, 38, 0, tzinfo=datetime.timezone.utc), + ) + ) + assert result.value == datetime.datetime(2022, 8, 26, 14, 38, 0, tzinfo=datetime.timezone.utc) + + result = await client.property.unix_timestamp( + UnixTimestampDatetimeProperty( + value=datetime.datetime(2023, 6, 12, 10, 47, 44, tzinfo=datetime.timezone.utc), + ) + ) + assert result.value == datetime.datetime(2023, 6, 12, 10, 47, 44, tzinfo=datetime.timezone.utc) + + result = await client.property.unix_timestamp_array( + UnixTimestampArrayDatetimeProperty( + value=[ + datetime.datetime(2023, 6, 12, 10, 47, 44, tzinfo=datetime.timezone.utc), + datetime.datetime(2023, 6, 14, 9, 17, 36, tzinfo=datetime.timezone.utc), + ], + ) + ) + assert result.value == [ + datetime.datetime(2023, 6, 12, 10, 47, 44, tzinfo=datetime.timezone.utc), + datetime.datetime(2023, 6, 14, 9, 17, 36, tzinfo=datetime.timezone.utc), + ] + + +@pytest.mark.asyncio +async def test_header(client: DatetimeClient): + await client.header.default( + value=datetime.datetime(2022, 8, 26, 14, 38, 0, tzinfo=datetime.timezone.utc), + ) + await client.header.rfc3339( + value=datetime.datetime(2022, 8, 26, 18, 38, 0, tzinfo=datetime.timezone.utc), + ) + await client.header.rfc7231( + value=datetime.datetime(2022, 8, 26, 14, 38, 0, tzinfo=datetime.timezone.utc), + ) + await client.header.unix_timestamp( + value=datetime.datetime(2023, 6, 12, 10, 47, 44, tzinfo=datetime.timezone.utc), + ) + await client.header.unix_timestamp_array( + value=[ + datetime.datetime(2023, 6, 12, 10, 47, 44, tzinfo=datetime.timezone.utc), + datetime.datetime(2023, 6, 14, 9, 17, 36, tzinfo=datetime.timezone.utc), + ] + ) + + +@pytest.mark.asyncio +async def test_response_header(client: DatetimeClient): + cls = lambda x, y, z: z + assert (await client.response_header.default(cls=cls))["value"] == datetime.datetime( + 2022, 8, 26, 14, 38, 0, tzinfo=datetime.timezone.utc + ) + assert (await client.response_header.rfc3339(cls=cls))["value"] == datetime.datetime( + 2022, 8, 26, 18, 38, 0, tzinfo=datetime.timezone.utc + ) + assert (await client.response_header.rfc7231(cls=cls))["value"] == datetime.datetime( + 2022, 8, 26, 14, 38, 0, tzinfo=datetime.timezone.utc + ) + assert (await client.response_header.unix_timestamp(cls=cls))["value"] == datetime.datetime( + 2023, 6, 12, 10, 47, 44, tzinfo=datetime.timezone.utc + ) diff --git a/packages/typespec-python/tests/mock_api/shared/asynctests/test_generation_subdir2_for_customized_code_async.py b/packages/typespec-python/tests/mock_api/shared/asynctests/test_generation_subdir2_for_customized_code_async.py new file mode 100644 index 0000000000..bbc02dba59 --- /dev/null +++ b/packages/typespec-python/tests/mock_api/shared/asynctests/test_generation_subdir2_for_customized_code_async.py @@ -0,0 +1,37 @@ +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- +import pytest +import pytest_asyncio +from generation.subdir2.aio import AddedClient +from generation.subdir2 import ModelV1, ModelV2, EnumV1, EnumV2 + + +@pytest_asyncio.fixture +async def client(): + async with AddedClient(endpoint="http://localhost:3000", version="v2") as client: + yield client + + +@pytest.mark.asyncio +async def test_v1(client: AddedClient): + assert await client.v1( + ModelV1(prop="foo", enum_prop=EnumV1.ENUM_MEMBER_V2, union_prop=10), + header_v2="bar", + ) == ModelV1(prop="foo", enum_prop=EnumV1.ENUM_MEMBER_V2, union_prop=10) + + +@pytest.mark.asyncio +async def test_v2(client: AddedClient): + assert await client.v2(ModelV2(prop="foo", enum_prop=EnumV2.ENUM_MEMBER, union_prop="bar")) == ModelV2( + prop="foo", enum_prop=EnumV2.ENUM_MEMBER, union_prop="bar" + ) + + +@pytest.mark.asyncio +async def test_interface_v2(client: AddedClient): + assert await client.interface_v2.v2_in_interface( + ModelV2(prop="foo", enum_prop=EnumV2.ENUM_MEMBER, union_prop="bar") + ) == ModelV2(prop="foo", enum_prop=EnumV2.ENUM_MEMBER, union_prop="bar") diff --git a/packages/typespec-python/tests/mock_api/shared/asynctests/test_generation_subdir2_for_generated_code_async.py b/packages/typespec-python/tests/mock_api/shared/asynctests/test_generation_subdir2_for_generated_code_async.py new file mode 100644 index 0000000000..f7fa5f9d08 --- /dev/null +++ b/packages/typespec-python/tests/mock_api/shared/asynctests/test_generation_subdir2_for_generated_code_async.py @@ -0,0 +1,37 @@ +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- +import pytest +import pytest_asyncio +from generation.subdir2._generated.aio import AddedClient +from generation.subdir2._generated.models import ModelV1, ModelV2, EnumV1, EnumV2 + + +@pytest_asyncio.fixture +async def client(): + async with AddedClient(endpoint="http://localhost:3000", version="v2") as client: + yield client + + +@pytest.mark.asyncio +async def test_v1(client: AddedClient): + assert await client.v1( + ModelV1(prop="foo", enum_prop=EnumV1.ENUM_MEMBER_V2, union_prop=10), + header_v2="bar", + ) == ModelV1(prop="foo", enum_prop=EnumV1.ENUM_MEMBER_V2, union_prop=10) + + +@pytest.mark.asyncio +async def test_v2(client: AddedClient): + assert await client.v2(ModelV2(prop="foo", enum_prop=EnumV2.ENUM_MEMBER, union_prop="bar")) == ModelV2( + prop="foo", enum_prop=EnumV2.ENUM_MEMBER, union_prop="bar" + ) + + +@pytest.mark.asyncio +async def test_interface_v2(client: AddedClient): + assert await client.interface_v2.v2_in_interface( + ModelV2(prop="foo", enum_prop=EnumV2.ENUM_MEMBER, union_prop="bar") + ) == ModelV2(prop="foo", enum_prop=EnumV2.ENUM_MEMBER, union_prop="bar") diff --git a/packages/typespec-python/tests/mock_api/shared/asynctests/test_generation_subdir_for_customized_code_async.py b/packages/typespec-python/tests/mock_api/shared/asynctests/test_generation_subdir_for_customized_code_async.py new file mode 100644 index 0000000000..f992bd973d --- /dev/null +++ b/packages/typespec-python/tests/mock_api/shared/asynctests/test_generation_subdir_for_customized_code_async.py @@ -0,0 +1,19 @@ +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- +import pytest +from generation.subdir import Extension +from generation.subdir.aio import CustomizedClient + + +@pytest.mark.asyncio +async def test_custom_method(): + client = CustomizedClient() + assert (await client.customized_get()) == Extension( + { + "level": 0, + "extension": [{"level": 1, "extension": [{"level": 2}]}, {"level": 1}], + } + ) diff --git a/packages/typespec-python/tests/mock_api/shared/asynctests/test_generation_subdir_for_generated_code_async.py b/packages/typespec-python/tests/mock_api/shared/asynctests/test_generation_subdir_for_generated_code_async.py new file mode 100644 index 0000000000..4fd9e7496e --- /dev/null +++ b/packages/typespec-python/tests/mock_api/shared/asynctests/test_generation_subdir_for_generated_code_async.py @@ -0,0 +1,25 @@ +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- +import pytest +import pytest_asyncio +from generation.subdir._generated.aio import RecursiveClient +from generation.subdir._generated.models import Extension + + +@pytest_asyncio.fixture +async def client(): + async with RecursiveClient() as client: + yield client + + +@pytest.mark.asyncio +async def test_custom_method(client: RecursiveClient): + assert await client.get() == Extension( + { + "level": 0, + "extension": [{"level": 1, "extension": [{"level": 2}]}, {"level": 1}], + } + ) diff --git a/packages/typespec-python/tests/mock_api/shared/asynctests/test_headasboolean_async.py b/packages/typespec-python/tests/mock_api/shared/asynctests/test_headasboolean_async.py new file mode 100644 index 0000000000..d2c2f10da0 --- /dev/null +++ b/packages/typespec-python/tests/mock_api/shared/asynctests/test_headasboolean_async.py @@ -0,0 +1,36 @@ +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- +import pytest +import pytest_asyncio +from headasbooleantrue.aio import VisibilityClient as HeadAsBooleanTrueClient +from headasbooleantrue import models as models_true + +from headasbooleanfalse.aio import VisibilityClient as HeadAsBooleanFalseClient +from headasbooleanfalse import models as models_false + + +@pytest_asyncio.fixture +async def client_true(): + async with HeadAsBooleanTrueClient() as client: + yield client + + +@pytest_asyncio.fixture +async def client_false(): + async with HeadAsBooleanFalseClient() as client: + yield client + + +@pytest.mark.asyncio +async def test_head_true(client_true): + body = models_true.VisibilityModel() + assert await client_true.head_model(body, query_prop=123) == True + + +@pytest.mark.asyncio +async def test_head_false(client_false): + body = models_false.VisibilityModel() + assert await client_false.head_model(body, query_prop=123) is None diff --git a/packages/typespec-python/tests/mock_api/shared/asynctests/test_parameters_body_optionality_async.py b/packages/typespec-python/tests/mock_api/shared/asynctests/test_parameters_body_optionality_async.py new file mode 100644 index 0000000000..47bc79fd47 --- /dev/null +++ b/packages/typespec-python/tests/mock_api/shared/asynctests/test_parameters_body_optionality_async.py @@ -0,0 +1,31 @@ +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- +import pytest +import pytest_asyncio +from parameters.bodyoptionality.aio import BodyOptionalityClient +from parameters.bodyoptionality.models import BodyModel + + +@pytest_asyncio.fixture +async def client(): + async with BodyOptionalityClient() as client: + yield client + + +@pytest.mark.asyncio +async def test_required_explicit(client: BodyOptionalityClient): + await client.required_explicit(BodyModel(name="foo")) + + +@pytest.mark.asyncio +async def test_required_implicit(client: BodyOptionalityClient): + await client.required_implicit(name="foo") + + +@pytest.mark.asyncio +async def test_optional_explicit(client: BodyOptionalityClient): + await client.optional_explicit.set(BodyModel(name="foo")) + await client.optional_explicit.omit() diff --git a/packages/typespec-python/tests/mock_api/shared/asynctests/test_parameters_collection_format_async.py b/packages/typespec-python/tests/mock_api/shared/asynctests/test_parameters_collection_format_async.py new file mode 100644 index 0000000000..6ed93c4651 --- /dev/null +++ b/packages/typespec-python/tests/mock_api/shared/asynctests/test_parameters_collection_format_async.py @@ -0,0 +1,39 @@ +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- +import pytest +import pytest_asyncio +from parameters.collectionformat.aio import CollectionFormatClient + + +@pytest_asyncio.fixture +async def client(): + async with CollectionFormatClient() as client: + yield client + + +@pytest.mark.asyncio +async def test_query_multi(client: CollectionFormatClient): + await client.query.multi(colors=["blue", "red", "green"]) + + +@pytest.mark.asyncio +async def test_query_csv(client: CollectionFormatClient): + await client.query.csv(colors=["blue", "red", "green"]) + + +@pytest.mark.asyncio +async def test_query_pipes(client: CollectionFormatClient): + await client.query.pipes(colors=["blue", "red", "green"]) + + +@pytest.mark.asyncio +async def test_query_ssv(client: CollectionFormatClient): + await client.query.ssv(colors=["blue", "red", "green"]) + + +@pytest.mark.asyncio +async def test_csv_header(client: CollectionFormatClient): + await client.header.csv(colors=["blue", "red", "green"]) diff --git a/packages/typespec-python/tests/mock_api/shared/asynctests/test_parameters_path_async.py b/packages/typespec-python/tests/mock_api/shared/asynctests/test_parameters_path_async.py new file mode 100644 index 0000000000..aee4b15005 --- /dev/null +++ b/packages/typespec-python/tests/mock_api/shared/asynctests/test_parameters_path_async.py @@ -0,0 +1,25 @@ +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- +import pytest +import pytest_asyncio +from parameters.path.aio import PathClient + + +@pytest_asyncio.fixture +async def client(): + async with PathClient() as client: + yield client + + +@pytest.mark.asyncio +async def test_normal(client: PathClient): + await client.normal("foo") + + +@pytest.mark.asyncio +async def test_optional(client: PathClient): + await client.optional() + await client.optional(name="foo") diff --git a/packages/typespec-python/tests/mock_api/shared/asynctests/test_parameters_query_async.py b/packages/typespec-python/tests/mock_api/shared/asynctests/test_parameters_query_async.py new file mode 100644 index 0000000000..70fb18603d --- /dev/null +++ b/packages/typespec-python/tests/mock_api/shared/asynctests/test_parameters_query_async.py @@ -0,0 +1,19 @@ +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- +import pytest +import pytest_asyncio +from parameters.query.aio import QueryClient + + +@pytest_asyncio.fixture +async def client(): + async with QueryClient() as client: + yield client + + +@pytest.mark.asyncio +async def test_constant(client: QueryClient): + await client.constant.post() diff --git a/packages/typespec-python/tests/mock_api/shared/asynctests/test_payload_json_merge_patch_async.py b/packages/typespec-python/tests/mock_api/shared/asynctests/test_payload_json_merge_patch_async.py new file mode 100644 index 0000000000..54709bed05 --- /dev/null +++ b/packages/typespec-python/tests/mock_api/shared/asynctests/test_payload_json_merge_patch_async.py @@ -0,0 +1,99 @@ +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- +import pytest +import pytest_asyncio +from payload.jsonmergepatch.aio import JsonMergePatchClient +from payload.jsonmergepatch.models import InnerModel, Resource, ResourcePatch + +try: + from azure.core.serialization import NULL +except ImportError: + from corehttp.serialization import NULL + + +@pytest_asyncio.fixture +async def client(): + async with JsonMergePatchClient(endpoint="http://localhost:3000") as client: + yield client + + +@pytest.mark.asyncio +async def test_create_resource(client: JsonMergePatchClient): + inner_madge = InnerModel(name="InnerMadge", description="innerDesc") + create_resource = Resource( + name="Madge", + description="desc", + map={"key": inner_madge}, + array=[inner_madge], + int_value=1, + float_value=1.25, + inner_model=inner_madge, + int_array=[1, 2, 3], + ) + response = await client.create_resource(create_resource) + assert response == create_resource + + +@pytest.mark.asyncio +async def test_update_resource_model_input(client: JsonMergePatchClient): + update_resource = ResourcePatch( + description=NULL, + map={"key": InnerModel(description=NULL), "key2": NULL}, + array=NULL, + int_value=NULL, + float_value=NULL, + inner_model=NULL, + int_array=NULL, + ) + response = await client.update_resource(update_resource) + assert response == Resource(name="Madge", map={"key": InnerModel(name="InnerMadge")}) + + +@pytest.mark.asyncio +async def test_update_resource_raw_input(client: JsonMergePatchClient): + response = await client.update_resource( + { + "description": None, + "map": {"key": {"description": None}, "key2": None}, + "array": None, + "intValue": None, + "floatValue": None, + "innerModel": None, + "intArray": None, + } + ) + assert response == Resource(name="Madge", map={"key": InnerModel(name="InnerMadge")}) + + +@pytest.mark.asyncio +async def test_update_optional_resource_model_input(client: JsonMergePatchClient): + update_resource = ResourcePatch( + description=NULL, + map={"key": InnerModel(description=NULL), "key2": NULL}, + array=NULL, + int_value=NULL, + float_value=NULL, + inner_model=NULL, + int_array=NULL, + ) + response = await client.update_optional_resource(update_resource) + assert response == Resource(name="Madge", map={"key": InnerModel(name="InnerMadge")}) + + +@pytest.mark.asyncio +async def test_update_optional_resource_raw_input(client: JsonMergePatchClient): + response = await client.update_optional_resource( + { + "description": None, + "map": {"key": {"description": None}, "key2": None}, + "array": None, + "intValue": None, + "floatValue": None, + "innerModel": None, + "intArray": None, + } + ) + assert response == Resource(name="Madge", map={"key": InnerModel(name="InnerMadge")}) diff --git a/packages/typespec-python/tests/mock_api/shared/asynctests/test_payload_media_type_async.py b/packages/typespec-python/tests/mock_api/shared/asynctests/test_payload_media_type_async.py new file mode 100644 index 0000000000..551d71bc42 --- /dev/null +++ b/packages/typespec-python/tests/mock_api/shared/asynctests/test_payload_media_type_async.py @@ -0,0 +1,28 @@ +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- +import pytest +import pytest_asyncio +from payload.mediatype.aio import MediaTypeClient + + +@pytest_asyncio.fixture +async def client(): + async with MediaTypeClient(endpoint="http://localhost:3000") as client: + yield client + + +@pytest.mark.asyncio +async def test_json(client: MediaTypeClient): + data = "foo" + await client.string_body.send_as_json(data) + assert await client.string_body.get_as_json() == data + + +@pytest.mark.asyncio +async def test_text(client: MediaTypeClient): + data = "{cat}" + await client.string_body.send_as_text(data) + assert await client.string_body.get_as_text() == data diff --git a/packages/typespec-python/tests/mock_api/shared/asynctests/test_payload_pageable_async.py b/packages/typespec-python/tests/mock_api/shared/asynctests/test_payload_pageable_async.py new file mode 100644 index 0000000000..900caa49ed --- /dev/null +++ b/packages/typespec-python/tests/mock_api/shared/asynctests/test_payload_pageable_async.py @@ -0,0 +1,135 @@ +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- +import pytest +import pytest_asyncio +from payload.pageable.aio import PageableClient +from payload.pageable.serverdrivenpagination.alternateinitialverb.models import Filter + + +@pytest_asyncio.fixture +async def client(): + async with PageableClient(endpoint="http://localhost:3000") as client: + yield client + + +def assert_result(result): + assert len(result) == 4 + assert result[0].id == "1" + assert result[1].id == "2" + assert result[2].id == "3" + assert result[3].id == "4" + assert result[0].name == "dog" + assert result[1].name == "cat" + assert result[2].name == "bird" + assert result[3].name == "fish" + + +@pytest.mark.asyncio +async def test_link(client: PageableClient): + result = [p async for p in client.server_driven_pagination.link()] + assert_result(result) + + +@pytest.mark.asyncio +async def test_link_string(client: PageableClient): + result = [p async for p in client.server_driven_pagination.link_string()] + assert_result(result) + + +@pytest.mark.asyncio +async def test_request_query_response_body(client: PageableClient): + result = [ + p + async for p in client.server_driven_pagination.continuation_token.request_query_response_body( + foo="foo", bar="bar" + ) + ] + assert_result(result) + + +@pytest.mark.asyncio +async def test_request_header_response_body(client: PageableClient): + result = [ + p + async for p in client.server_driven_pagination.continuation_token.request_header_response_body( + foo="foo", bar="bar" + ) + ] + assert_result(result) + + +@pytest.mark.asyncio +async def test_request_query_response_header(client: PageableClient): + result = [ + p + async for p in client.server_driven_pagination.continuation_token.request_query_response_header( + foo="foo", bar="bar" + ) + ] + assert_result(result) + + +@pytest.mark.asyncio +async def test_request_header_response_header(client: PageableClient): + result = [ + p + async for p in client.server_driven_pagination.continuation_token.request_query_response_header( + foo="foo", bar="bar" + ) + ] + assert_result(result) + + +@pytest.mark.asyncio +async def test_nested_link(client: PageableClient): + result = [p async for p in client.server_driven_pagination.nested_link()] + assert_result(result) + + +@pytest.mark.asyncio +async def test_request_query_nested_response_body(client: PageableClient): + result = [ + p + async for p in client.server_driven_pagination.continuation_token.request_query_nested_response_body( + foo="foo", bar="bar" + ) + ] + assert_result(result) + + +@pytest.mark.asyncio +async def test_request_header_nested_response_body(client: PageableClient): + result = [ + p + async for p in client.server_driven_pagination.continuation_token.request_header_nested_response_body( + foo="foo", bar="bar" + ) + ] + assert_result(result) + + +@pytest.mark.asyncio +async def test_list_without_continuation(client: PageableClient): + result = [p async for p in client.page_size.list_without_continuation()] + assert_result(result) + + +@pytest.mark.asyncio +async def test_xml_pagination_list_with_continuation(client: PageableClient): + result = [p async for p in client.xml_pagination.list_with_continuation()] + assert_result(result) + + +@pytest.mark.asyncio +async def test_xml_pagination_list_with_next_link(client: PageableClient): + result = [p async for p in client.xml_pagination.list_with_next_link()] + assert_result(result) + + +@pytest.mark.asyncio +async def test_alternate_initial_verb_post(client: PageableClient): + result = [p async for p in client.server_driven_pagination.alternate_initial_verb.post(Filter(filter="foo eq bar"))] + assert_result(result) diff --git a/packages/typespec-python/tests/mock_api/shared/asynctests/test_payload_xml_async.py b/packages/typespec-python/tests/mock_api/shared/asynctests/test_payload_xml_async.py new file mode 100644 index 0000000000..8ae1cc69ad --- /dev/null +++ b/packages/typespec-python/tests/mock_api/shared/asynctests/test_payload_xml_async.py @@ -0,0 +1,261 @@ +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- +import datetime +import pytest +import pytest_asyncio +from payload.xml.aio import XmlClient +from payload.xml.models import ( + Author, + Book, + SimpleModel, + ModelWithSimpleArrays, + ModelWithArrayOfModel, + ModelWithAttributes, + ModelWithUnwrappedArray, + ModelWithUnwrappedModelArray, + ModelWithRenamedArrays, + ModelWithRenamedProperty, + ModelWithRenamedAttribute, + ModelWithRenamedNestedModel, + ModelWithRenamedWrappedModelArray, + ModelWithRenamedUnwrappedModelArray, + ModelWithRenamedWrappedAndItemModelArray, + ModelWithOptionalField, + ModelWithRenamedFields, + ModelWithEmptyArray, + ModelWithText, + ModelWithDictionary, + ModelWithEncodedNames, + ModelWithEnum, + ModelWithDatetime, + ModelWithNamespace, + ModelWithNamespaceOnProperties, + ModelWithNestedModel, + ModelWithWrappedPrimitiveCustomItemNames, +) + + +@pytest_asyncio.fixture +async def client(): + async with XmlClient(endpoint="http://localhost:3000") as client: + yield client + + +@pytest.mark.asyncio +async def test_simple_model(client: XmlClient): + model = SimpleModel(name="foo", age=123) + assert await client.simple_model_value.get() == model + await client.simple_model_value.put(model) + + +@pytest.mark.asyncio +async def test_model_with_renamed_property(client: XmlClient): + model = ModelWithRenamedProperty(title="foo", author="bar") + assert await client.model_with_renamed_property_value.get() == model + await client.model_with_renamed_property_value.put(model) + + +@pytest.mark.asyncio +async def test_model_with_simple_arrays(client: XmlClient): + model = ModelWithSimpleArrays(colors=["red", "green", "blue"], counts=[1, 2]) + assert await client.model_with_simple_arrays_value.get() == model + await client.model_with_simple_arrays_value.put(model) + + +@pytest.mark.asyncio +async def test_model_with_wrapped_primitive_custom_item_names(client: XmlClient): + model = ModelWithWrappedPrimitiveCustomItemNames(tags=["fiction", "classic"]) + assert await client.model_with_wrapped_primitive_custom_item_names_value.get() == model + await client.model_with_wrapped_primitive_custom_item_names_value.put(model) + + +@pytest.mark.asyncio +async def test_model_with_array_of_model(client: XmlClient): + model = ModelWithArrayOfModel( + items_property=[ + SimpleModel(name="foo", age=123), + SimpleModel(name="bar", age=456), + ] + ) + assert await client.model_with_array_of_model_value.get() == model + await client.model_with_array_of_model_value.put(model) + + +@pytest.mark.asyncio +async def test_model_with_unwrapped_model_array(client: XmlClient): + model = ModelWithUnwrappedModelArray( + items_property=[ + SimpleModel(name="foo", age=123), + SimpleModel(name="bar", age=456), + ] + ) + assert await client.model_with_unwrapped_model_array_value.get() == model + await client.model_with_unwrapped_model_array_value.put(model) + + +@pytest.mark.asyncio +async def test_model_with_renamed_wrapped_model_array(client: XmlClient): + model = ModelWithRenamedWrappedModelArray( + items_property=[ + SimpleModel(name="foo", age=123), + SimpleModel(name="bar", age=456), + ] + ) + assert await client.model_with_renamed_wrapped_model_array_value.get() == model + await client.model_with_renamed_wrapped_model_array_value.put(model) + + +@pytest.mark.asyncio +async def test_model_with_renamed_unwrapped_model_array(client: XmlClient): + model = ModelWithRenamedUnwrappedModelArray( + items_property=[ + SimpleModel(name="foo", age=123), + SimpleModel(name="bar", age=456), + ] + ) + assert await client.model_with_renamed_unwrapped_model_array_value.get() == model + await client.model_with_renamed_unwrapped_model_array_value.put(model) + + +@pytest.mark.asyncio +async def test_model_with_renamed_wrapped_and_item_model_array(client: XmlClient): + model = ModelWithRenamedWrappedAndItemModelArray( + books=[ + Book(title="The Great Gatsby"), + Book(title="Les Miserables"), + ] + ) + assert await client.model_with_renamed_wrapped_and_item_model_array_value.get() == model + await client.model_with_renamed_wrapped_and_item_model_array_value.put(model) + + +@pytest.mark.asyncio +async def test_model_with_attributes(client: XmlClient): + model = ModelWithAttributes(id1=123, id2="foo", enabled=True) + assert await client.model_with_attributes_value.get() == model + await client.model_with_attributes_value.put(model) + + +@pytest.mark.asyncio +async def test_model_with_renamed_attribute(client: XmlClient): + model = ModelWithRenamedAttribute(id=123, title="The Great Gatsby", author="F. Scott Fitzgerald") + assert await client.model_with_renamed_attribute_value.get() == model + await client.model_with_renamed_attribute_value.put(model) + + +@pytest.mark.asyncio +async def test_model_with_unwrapped_array(client: XmlClient): + model = ModelWithUnwrappedArray(colors=["red", "green", "blue"], counts=[1, 2]) + assert await client.model_with_unwrapped_array_value.get() == model + await client.model_with_unwrapped_array_value.put(model) + + +@pytest.mark.asyncio +async def test_model_with_renamed_arrays(client: XmlClient): + model = ModelWithRenamedArrays(colors=["red", "green", "blue"], counts=[1, 2]) + assert await client.model_with_renamed_arrays_value.get() == model + await client.model_with_renamed_arrays_value.put(model) + + +@pytest.mark.asyncio +async def test_model_with_optional_field(client: XmlClient): + model = ModelWithOptionalField(item="widget") + assert await client.model_with_optional_field_value.get() == model + await client.model_with_optional_field_value.put(model) + + +@pytest.mark.asyncio +async def test_model_with_nested_model(client: XmlClient): + model = ModelWithNestedModel(nested=SimpleModel(name="foo", age=123)) + assert await client.model_with_nested_model_value.get() == model + await client.model_with_nested_model_value.put(model) + + +@pytest.mark.asyncio +async def test_model_with_renamed_nested_model(client: XmlClient): + model = ModelWithRenamedNestedModel(author=Author(name="foo")) + assert await client.model_with_renamed_nested_model_value.get() == model + await client.model_with_renamed_nested_model_value.put(model) + + +@pytest.mark.asyncio +async def test_model_with_renamed_fields(client: XmlClient): + model = ModelWithRenamedFields( + input_data=SimpleModel(name="foo", age=123), + output_data=SimpleModel(name="bar", age=456), + ) + assert await client.model_with_renamed_fields_value.get() == model + await client.model_with_renamed_fields_value.put(model) + + +@pytest.mark.asyncio +async def test_model_with_empty_array(client: XmlClient): + model = ModelWithEmptyArray(items_property=[]) + assert await client.model_with_empty_array_value.get() == model + await client.model_with_empty_array_value.put(model) + + +@pytest.mark.asyncio +async def test_model_with_text(client: XmlClient): + model = ModelWithText(language="foo", content="\n This is some text.\n") + assert await client.model_with_text_value.get() == model + await client.model_with_text_value.put(model) + + +@pytest.mark.asyncio +async def test_model_with_dictionary(client: XmlClient): + model = ModelWithDictionary(metadata={"Color": "blue", "Count": "123", "Enabled": "false"}) + assert await client.model_with_dictionary_value.get() == model + await client.model_with_dictionary_value.put(model) + + +@pytest.mark.asyncio +async def test_model_with_encoded_names(client: XmlClient): + model = ModelWithEncodedNames(model_data=SimpleModel(name="foo", age=123), colors=["red", "green", "blue"]) + assert await client.model_with_encoded_names_value.get() == model + await client.model_with_encoded_names_value.put(model) + + +@pytest.mark.asyncio +async def test_model_with_enum(client: XmlClient): + model = ModelWithEnum(status="success") + assert await client.model_with_enum_value.get() == model + await client.model_with_enum_value.put(model) + + +@pytest.mark.asyncio +async def test_model_with_datetime(client: XmlClient): + model = ModelWithDatetime( + rfc3339=datetime.datetime(2022, 8, 26, 18, 38, 0, tzinfo=datetime.timezone.utc), + rfc7231=datetime.datetime(2022, 8, 26, 14, 38, 0, tzinfo=datetime.timezone.utc), + ) + result = await client.model_with_datetime_value.get() + assert result.rfc3339 == model.rfc3339 + assert result.rfc7231 == model.rfc7231 + await client.model_with_datetime_value.put(model) + + +@pytest.mark.asyncio +async def test_model_with_namespace(client: XmlClient): + model = ModelWithNamespace(id=123, title="The Great Gatsby") + assert await client.model_with_namespace_value.get() == model + await client.model_with_namespace_value.put(model) + + +@pytest.mark.asyncio +async def test_model_with_namespace_on_properties(client: XmlClient): + model = ModelWithNamespaceOnProperties(id=123, title="The Great Gatsby", author="F. Scott Fitzgerald") + assert await client.model_with_namespace_on_properties_value.get() == model + await client.model_with_namespace_on_properties_value.put(model) + + +@pytest.mark.asyncio +async def test_xml_error_value(client: XmlClient, core_library): + with pytest.raises(core_library.exceptions.HttpResponseError) as ex: + await client.xml_error_value.get() + assert ex.value.status_code == 400 + assert ex.value.model.message == "Something went wrong" + assert ex.value.model.code == 400 diff --git a/packages/typespec-python/tests/mock_api/shared/asynctests/test_response_status_code_range_async.py b/packages/typespec-python/tests/mock_api/shared/asynctests/test_response_status_code_range_async.py new file mode 100644 index 0000000000..0dd34b667c --- /dev/null +++ b/packages/typespec-python/tests/mock_api/shared/asynctests/test_response_status_code_range_async.py @@ -0,0 +1,39 @@ +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- +import pytest +import pytest_asyncio +from response.statuscoderange.aio import StatusCodeRangeClient +from response.statuscoderange.models import ErrorInRange, NotFoundError + + +@pytest_asyncio.fixture +async def client(): + async with StatusCodeRangeClient(endpoint="http://localhost:3000") as client: + yield client + + +@pytest.mark.asyncio +async def test_error_response_status_code_in_range(client: StatusCodeRangeClient): + with pytest.raises(Exception) as exc_info: + await client.error_response_status_code_in_range() + + error = exc_info.value.model + assert isinstance(error, ErrorInRange) + assert error.code == "request-header-too-large" + assert error.message == "Request header too large" + assert exc_info.value.response.status_code == 494 + + +@pytest.mark.asyncio +async def test_error_response_status_code_404(client: StatusCodeRangeClient): + with pytest.raises(Exception) as exc_info: + await client.error_response_status_code404() + + error = exc_info.value.model + assert isinstance(error, NotFoundError) + assert error.code == "not-found" + assert error.resource_id == "resource1" + assert exc_info.value.response.status_code == 404 diff --git a/packages/typespec-python/tests/mock_api/shared/asynctests/test_routes_async.py b/packages/typespec-python/tests/mock_api/shared/asynctests/test_routes_async.py new file mode 100644 index 0000000000..d3e34bc1f9 --- /dev/null +++ b/packages/typespec-python/tests/mock_api/shared/asynctests/test_routes_async.py @@ -0,0 +1,332 @@ +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- +import pytest +import pytest_asyncio +from routes.aio import RoutesClient + + +@pytest_asyncio.fixture +async def client(): + async with RoutesClient() as client: + yield client + + +@pytest.mark.asyncio +async def test_fixed(client: RoutesClient): + await client.fixed() + + +@pytest.mark.asyncio +async def test_in_interface_fixed(client: RoutesClient): + await client.in_interface.fixed() + + +@pytest.mark.asyncio +async def test_path_parameters_template_only(client: RoutesClient): + await client.path_parameters.template_only( + param="a", + ) + + +@pytest.mark.asyncio +async def test_path_parameters_explicit(client: RoutesClient): + await client.path_parameters.explicit( + param="a", + ) + + +@pytest.mark.asyncio +async def test_path_parameters_annotation_only(client: RoutesClient): + await client.path_parameters.annotation_only( + param="a", + ) + + +@pytest.mark.asyncio +async def test_path_parameters_reserved_expansion_template(client: RoutesClient): + await client.path_parameters.reserved_expansion.template( + param="foo/bar baz", + ) + + +@pytest.mark.asyncio +async def test_path_parameters_reserved_expansion_annotation(client: RoutesClient): + await client.path_parameters.reserved_expansion.annotation( + param="foo/bar baz", + ) + + +# @pytest.mark.asyncio +# async def test_path_parameters_simple_expansion_standard_primitive(client: RoutesClient): +# await client.path_parameters.simple_expansion.standard.primitive( +# param="a", +# ) + + +# @pytest.mark.asyncio +# async def test_path_parameters_simple_expansion_standard_array(client: RoutesClient): +# await client.path_parameters.simple_expansion.standard.array( +# param=["a", "b"], +# ) + + +# @pytest.mark.asyncio +# async def test_path_parameters_simple_expansion_standard_record(client: RoutesClient): +# await client.path_parameters.simple_expansion.standard.record( +# param={"a": 1, "b": 2}, +# ) + + +# @pytest.mark.asyncio +# async def test_path_parameters_simple_expansion_explode_primitive(client: RoutesClient): +# await client.path_parameters.simple_expansion.explode.primitive( +# param="a", +# ) + + +# @pytest.mark.asyncio +# async def test_path_parameters_simple_expansion_explode_array(client: RoutesClient): +# await client.path_parameters.simple_expansion.explode.array( +# param=["a", "b"], +# ) + + +# @pytest.mark.asyncio +# async def test_path_parameters_simple_expansion_explode_record(client: RoutesClient): +# await client.path_parameters.simple_expansion.explode.record( +# param={"a": 1, "b": 2}, +# ) + + +# @pytest.mark.asyncio +# async def test_path_parameters_path_expansion_standard_primitive(client: RoutesClient): +# await client.path_parameters.path_expansion.standard.primitive( +# param="a", +# ) + + +# @pytest.mark.asyncio +# async def test_path_parameters_path_expansion_standard_array(client: RoutesClient): +# await client.path_parameters.path_expansion.standard.array( +# param=["a", "b"], +# ) + + +# @pytest.mark.asyncio +# async def test_path_parameters_path_expansion_standard_record(client: RoutesClient): +# await client.path_parameters.path_expansion.standard.record( +# param={"a": 1, "b": 2}, +# ) + + +# @pytest.mark.asyncio +# async def test_path_parameters_path_expansion_explode_primitive(client: RoutesClient): +# await client.path_parameters.path_expansion.explode.primitive( +# param="a", +# ) + + +# @pytest.mark.asyncio +# async def test_path_parameters_path_expansion_explode_array(client: RoutesClient): +# await client.path_parameters.path_expansion.explode.array( +# param=["a", "b"], +# ) + + +# @pytest.mark.asyncio +# async def test_path_parameters_path_expansion_explode_record(client: RoutesClient): +# await client.path_parameters.path_expansion.explode.record( +# param={"a": 1, "b": 2}, +# ) + + +# @pytest.mark.asyncio +# async def test_path_parameters_label_expansion_standard_primitive(client: RoutesClient): +# await client.path_parameters.label_expansion.standard.primitive( +# param="a", +# ) + + +# @pytest.mark.asyncio +# async def test_path_parameters_label_expansion_standard_array(client: RoutesClient): +# await client.path_parameters.label_expansion.standard.array( +# param=["a", "b"], +# ) + + +# @pytest.mark.asyncio +# async def test_path_parameters_label_expansion_standard_record(client: RoutesClient): +# await client.path_parameters.label_expansion.standard.record( +# param={"a": 1, "b": 2}, +# ) + + +# @pytest.mark.asyncio +# async def test_path_parameters_label_expansion_explode_primitive(client: RoutesClient): +# await client.path_parameters.label_expansion.explode.primitive( +# param="a", +# ) + + +# @pytest.mark.asyncio +# async def test_path_parameters_label_expansion_explode_array(client: RoutesClient): +# await client.path_parameters.label_expansion.explode.array( +# param=["a", "b"], +# ) + + +# @pytest.mark.asyncio +# async def test_path_parameters_label_expansion_explode_record(client: RoutesClient): +# await client.path_parameters.label_expansion.explode.record( +# param={"a": 1, "b": 2}, +# ) + + +# @pytest.mark.asyncio +# async def test_path_parameters_matrix_expansion_standard_primitive(client: RoutesClient): +# await client.path_parameters.matrix_expansion.standard.primitive( +# param="a", +# ) + + +# @pytest.mark.asyncio +# async def test_path_parameters_matrix_expansion_standard_array(client: RoutesClient): +# await client.path_parameters.matrix_expansion.standard.array( +# param=["a", "b"], +# ) + + +# @pytest.mark.asyncio +# async def test_path_parameters_matrix_expansion_standard_record(client: RoutesClient): +# await client.path_parameters.matrix_expansion.standard.record( +# param={"a": 1, "b": 2}, +# ) + + +# @pytest.mark.asyncio +# async def test_path_parameters_matrix_expansion_explode_primitive(client: RoutesClient): +# await client.path_parameters.matrix_expansion.explode.primitive( +# param="a", +# ) + + +# @pytest.mark.asyncio +# async def test_path_parameters_matrix_expansion_explode_array(client: RoutesClient): +# await client.path_parameters.matrix_expansion.explode.array( +# param=["a", "b"], +# ) + + +# @pytest.mark.asyncio +# async def test_path_parameters_matrix_expansion_explode_record(client: RoutesClient): +# await client.path_parameters.matrix_expansion.explode.record( +# param={"a": 1, "b": 2}, +# ) + + +@pytest.mark.asyncio +async def test_query_parameters_template_only(client: RoutesClient): + await client.query_parameters.template_only( + param="a", + ) + + +@pytest.mark.asyncio +async def test_query_parameters_explicit(client: RoutesClient): + await client.query_parameters.explicit( + param="a", + ) + + +@pytest.mark.asyncio +async def test_query_parameters_annotation_only(client: RoutesClient): + await client.query_parameters.annotation_only( + param="a", + ) + + +@pytest.mark.asyncio +async def test_query_parameters_query_expansion_standard_primitive(client: RoutesClient): + await client.query_parameters.query_expansion.standard.primitive( + param="a", + ) + + +# @pytest.mark.asyncio +# async def test_query_parameters_query_expansion_standard_array(client: RoutesClient): +# await client.query_parameters.query_expansion.standard.array( +# param=["a", "b"], +# ) + + +# @pytest.mark.asyncio +# async def test_query_parameters_query_expansion_standard_record(client: RoutesClient): +# await client.query_parameters.query_expansion.standard.record( +# param={"a": 1, "b": 2}, +# ) + + +@pytest.mark.asyncio +async def test_query_parameters_query_expansion_explode_primitive(client: RoutesClient): + await client.query_parameters.query_expansion.explode.primitive( + param="a", + ) + + +# @pytest.mark.asyncio +# async def test_query_parameters_query_expansion_explode_array(client: RoutesClient): +# await client.query_parameters.query_expansion.explode.array( +# param=["a", "b"], +# ) + + +# @pytest.mark.asyncio +# async def test_query_parameters_query_expansion_explode_record(client: RoutesClient): +# await client.query_parameters.query_expansion.explode.record( +# param={"a": 1, "b": 2}, +# ) + + +@pytest.mark.asyncio +async def test_query_parameters_query_continuation_standard_primitive(client: RoutesClient): + await client.query_parameters.query_continuation.standard.primitive( + param="a", + ) + + +# @pytest.mark.asyncio +# async def test_query_parameters_query_continuation_standard_array(client: RoutesClient): +# await client.query_parameters.query_continuation.standard.array( +# param=["a", "b"], +# ) + + +# @pytest.mark.asyncio +# async def test_query_parameters_query_continuation_standard_record(client: RoutesClient): +# await client.query_parameters.query_continuation.standard.record( +# param={"a": 1, "b": 2}, +# ) + + +@pytest.mark.asyncio +async def test_query_parameters_query_continuation_explode_primitive(client: RoutesClient): + await client.query_parameters.query_continuation.explode.primitive( + param="a", + ) + + +# @pytest.mark.asyncio +# async def test_query_parameters_query_continuation_explode_array(client: RoutesClient): +# await client.query_parameters.query_continuation.explode.array( +# param=["a", "b"], +# ) + + +# @pytest.mark.asyncio +# async def test_query_parameters_query_continuation_explode_record(client: RoutesClient): +# await client.query_parameters.query_continuation.explode.record( +# param={"a": 1, "b": 2}, +# ) diff --git a/packages/typespec-python/tests/mock_api/shared/asynctests/test_server_endpoint_not_defined_async.py b/packages/typespec-python/tests/mock_api/shared/asynctests/test_server_endpoint_not_defined_async.py new file mode 100644 index 0000000000..a14997b71c --- /dev/null +++ b/packages/typespec-python/tests/mock_api/shared/asynctests/test_server_endpoint_not_defined_async.py @@ -0,0 +1,19 @@ +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- +import pytest +import pytest_asyncio +from server.endpoint.notdefined.aio import NotDefinedClient + + +@pytest_asyncio.fixture +async def client(): + async with NotDefinedClient(endpoint="http://localhost:3000") as client: + yield client + + +@pytest.mark.asyncio +async def test_valid(client: NotDefinedClient): + assert await client.valid() is True diff --git a/packages/typespec-python/tests/mock_api/shared/asynctests/test_server_path_multiple_async.py b/packages/typespec-python/tests/mock_api/shared/asynctests/test_server_path_multiple_async.py new file mode 100644 index 0000000000..50bc53b5e3 --- /dev/null +++ b/packages/typespec-python/tests/mock_api/shared/asynctests/test_server_path_multiple_async.py @@ -0,0 +1,26 @@ +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- +import pytest +import pytest_asyncio +from server.path.multiple.aio import MultipleClient + + +@pytest_asyncio.fixture +async def client(): + async with MultipleClient(endpoint="http://localhost:3000") as client: + yield client + + +@pytest.mark.asyncio +async def test_no_operation_params(client: MultipleClient): + # await client.no_operation_params() + pass + + +@pytest.mark.asyncio +async def test_with_operation_path_param(client: MultipleClient): + # await client.with_operation_path_param(keyword="test") + pass diff --git a/packages/typespec-python/tests/mock_api/shared/asynctests/test_server_path_single_async.py b/packages/typespec-python/tests/mock_api/shared/asynctests/test_server_path_single_async.py new file mode 100644 index 0000000000..efcb703028 --- /dev/null +++ b/packages/typespec-python/tests/mock_api/shared/asynctests/test_server_path_single_async.py @@ -0,0 +1,19 @@ +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- +import pytest +import pytest_asyncio +from server.path.single.aio import SingleClient + + +@pytest_asyncio.fixture +async def client(): + async with SingleClient(endpoint="http://localhost:3000") as client: + yield client + + +@pytest.mark.asyncio +async def test_my_op(client): + assert await client.my_op() is True diff --git a/packages/typespec-python/tests/mock_api/shared/asynctests/test_server_versions_not_versioned_async.py b/packages/typespec-python/tests/mock_api/shared/asynctests/test_server_versions_not_versioned_async.py new file mode 100644 index 0000000000..14f7e4239d --- /dev/null +++ b/packages/typespec-python/tests/mock_api/shared/asynctests/test_server_versions_not_versioned_async.py @@ -0,0 +1,29 @@ +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- +import pytest +import pytest_asyncio +from server.versions.notversioned.aio import NotVersionedClient + + +@pytest_asyncio.fixture +async def client(): + async with NotVersionedClient(endpoint="http://localhost:3000") as client: + yield client + + +@pytest.mark.asyncio +async def test_without_api_version(client: NotVersionedClient): + await client.without_api_version() + + +@pytest.mark.asyncio +async def test_with_query_api_version(client: NotVersionedClient): + await client.with_query_api_version(api_version="v1.0") + + +@pytest.mark.asyncio +async def test_with_path_api_version(client: NotVersionedClient): + await client.with_path_api_version(api_version="v1.0") diff --git a/packages/typespec-python/tests/mock_api/shared/asynctests/test_server_versions_versioned_async.py b/packages/typespec-python/tests/mock_api/shared/asynctests/test_server_versions_versioned_async.py new file mode 100644 index 0000000000..8f96a2f550 --- /dev/null +++ b/packages/typespec-python/tests/mock_api/shared/asynctests/test_server_versions_versioned_async.py @@ -0,0 +1,35 @@ +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- +import pytest +import pytest_asyncio +from server.versions.versioned.aio import VersionedClient + + +@pytest_asyncio.fixture +async def client(): + async with VersionedClient(endpoint="http://localhost:3000") as client: + yield client + + +@pytest.mark.asyncio +async def test_without_api_version(client: VersionedClient): + await client.without_api_version() + + +@pytest.mark.asyncio +async def test_with_query_api_version(client: VersionedClient): + await client.with_query_api_version() + + +@pytest.mark.asyncio +async def test_with_path_api_version(client: VersionedClient): + await client.with_path_api_version() + + +@pytest.mark.asyncio +async def test_with_query_old_api_version(): + async with VersionedClient(endpoint="http://localhost:3000", api_version="2021-01-01-preview") as client: + await client.with_query_old_api_version() diff --git a/packages/typespec-python/tests/mock_api/shared/asynctests/test_special_headers_conditional_request_async.py b/packages/typespec-python/tests/mock_api/shared/asynctests/test_special_headers_conditional_request_async.py new file mode 100644 index 0000000000..dc86ac0635 --- /dev/null +++ b/packages/typespec-python/tests/mock_api/shared/asynctests/test_special_headers_conditional_request_async.py @@ -0,0 +1,39 @@ +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- +import pytest +import pytest_asyncio +import datetime +from specialheaders.conditionalrequest.aio import ConditionalRequestClient + + +@pytest_asyncio.fixture +async def client(): + async with ConditionalRequestClient() as client: + yield client + + +@pytest.mark.asyncio +async def test_post_if_match(core_library, client: ConditionalRequestClient): + await client.post_if_match(etag="valid", match_condition=core_library.MatchConditions.IfNotModified) + + +@pytest.mark.asyncio +async def test_post_if_none_match(core_library, client: ConditionalRequestClient): + await client.post_if_none_match(etag="invalid", match_condition=core_library.MatchConditions.IfModified) + + +@pytest.mark.asyncio +async def test_head_if_modified_since(client: ConditionalRequestClient): + await client.head_if_modified_since( + if_modified_since=datetime.datetime(2022, 8, 26, 14, 38, 0, tzinfo=datetime.timezone.utc) + ) + + +@pytest.mark.asyncio +async def test_post_if_unmodified_since(client: ConditionalRequestClient): + await client.post_if_unmodified_since( + if_unmodified_since=datetime.datetime(2022, 8, 26, 14, 38, 0, tzinfo=datetime.timezone.utc) + ) diff --git a/packages/typespec-python/tests/mock_api/shared/asynctests/test_special_headers_repeatability_async.py b/packages/typespec-python/tests/mock_api/shared/asynctests/test_special_headers_repeatability_async.py new file mode 100644 index 0000000000..941890ea23 --- /dev/null +++ b/packages/typespec-python/tests/mock_api/shared/asynctests/test_special_headers_repeatability_async.py @@ -0,0 +1,20 @@ +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- +import pytest +import pytest_asyncio +from specialheaders.repeatability.aio import RepeatabilityClient + + +@pytest_asyncio.fixture +async def client(): + async with RepeatabilityClient() as client: + yield client + + +@pytest.mark.asyncio +async def test_immediate_success(client: RepeatabilityClient): + cls = lambda x, y, z: z + assert (await client.immediate_success(cls=cls))["Repeatability-Result"] == "accepted" diff --git a/packages/typespec-python/tests/mock_api/shared/asynctests/test_specs_documentation_async.py b/packages/typespec-python/tests/mock_api/shared/asynctests/test_specs_documentation_async.py new file mode 100644 index 0000000000..dff527765c --- /dev/null +++ b/packages/typespec-python/tests/mock_api/shared/asynctests/test_specs_documentation_async.py @@ -0,0 +1,60 @@ +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- + +import pytest +import pytest_asyncio +from specs.documentation.aio import DocumentationClient +from specs.documentation import models + + +@pytest_asyncio.fixture +async def client(): + async with DocumentationClient(endpoint="http://localhost:3000") as client: + yield client + + +class TestLists: + @pytest.mark.asyncio + async def test_bullet_points_op(self, client: DocumentationClient): + # GET /documentation/lists/bullet-points/op + # Expected: 204 No Content + await client.lists.bullet_points_op() + + @pytest.mark.asyncio + async def test_bullet_points_model(self, client: DocumentationClient): + # POST /documentation/lists/bullet-points/model + # Expected request body: {"input": {"prop": "Simple"}} + # Expected: 200 OK + await client.lists.bullet_points_model(input=models.BulletPointsModel(prop="Simple")) + + # Also test with JSON + await client.lists.bullet_points_model(body={"input": {"prop": "Simple"}}) + + @pytest.mark.asyncio + async def test_numbered(self, client: DocumentationClient): + # GET /documentation/lists/numbered + # Expected: 204 No Content + await client.lists.numbered() + + +class TestTextFormatting: + @pytest.mark.asyncio + async def test_bold_text(self, client: DocumentationClient): + # GET /documentation/text-formatting/bold + # Expected: 204 No Content + await client.text_formatting.bold_text() + + @pytest.mark.asyncio + async def test_italic_text(self, client: DocumentationClient): + # GET /documentation/text-formatting/italic + # Expected: 204 No Content + await client.text_formatting.italic_text() + + @pytest.mark.asyncio + async def test_combined_formatting(self, client: DocumentationClient): + # GET /documentation/text-formatting/combined + # Expected: 204 No Content + await client.text_formatting.combined_formatting() diff --git a/packages/typespec-python/tests/mock_api/shared/asynctests/test_streaming_jsonl_async.py b/packages/typespec-python/tests/mock_api/shared/asynctests/test_streaming_jsonl_async.py new file mode 100644 index 0000000000..74e05cebd1 --- /dev/null +++ b/packages/typespec-python/tests/mock_api/shared/asynctests/test_streaming_jsonl_async.py @@ -0,0 +1,28 @@ +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- +import pytest +import pytest_asyncio + +from streaming.jsonl.aio import JsonlClient + + +@pytest_asyncio.fixture +async def client(): + async with JsonlClient(endpoint="http://localhost:3000") as client: + yield client + + +JSONL = b'{"desc": "one"}\n{"desc": "two"}\n{"desc": "three"}' + + +@pytest.mark.asyncio +async def test_basic_send(client: JsonlClient): + await client.basic.send(JSONL) + + +@pytest.mark.asyncio +async def test_basic_recv(client: JsonlClient): + assert b"".join([d async for d in (await client.basic.receive())]) == JSONL diff --git a/packages/typespec-python/tests/mock_api/shared/asynctests/test_typetest_array_async.py b/packages/typespec-python/tests/mock_api/shared/asynctests/test_typetest_array_async.py new file mode 100644 index 0000000000..66c3b24c1f --- /dev/null +++ b/packages/typespec-python/tests/mock_api/shared/asynctests/test_typetest_array_async.py @@ -0,0 +1,128 @@ +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- + +import pytest +import pytest_asyncio +import isodate +from typetest.array.aio import ArrayClient +from typetest.array import models + + +@pytest_asyncio.fixture +async def client(): + async with ArrayClient() as client: + yield client + + +@pytest.mark.asyncio +async def test_boolean_value(client: ArrayClient): + assert await client.boolean_value.get() == [True, False] + await client.boolean_value.put([True, False]) + + +@pytest.mark.asyncio +async def test_datetime_value(client: ArrayClient): + assert await client.datetime_value.get() == [isodate.parse_datetime("2022-08-26T18:38:00Z")] + await client.datetime_value.put([isodate.parse_datetime("2022-08-26T18:38:00Z")]) + + +@pytest.mark.asyncio +async def test_duration_value(client: ArrayClient): + assert await client.duration_value.get() == [isodate.parse_duration("P123DT22H14M12.011S")] + await client.duration_value.put([isodate.parse_duration("P123DT22H14M12.011S")]) + + +@pytest.mark.asyncio +async def test_float32_value(client: ArrayClient): + assert await client.float32_value.get() == [43.125] + await client.float32_value.put([43.125]) + + +@pytest.mark.asyncio +async def test_int32_value(client: ArrayClient): + assert await client.int32_value.get() == [1, 2] + await client.int32_value.put([1, 2]) + + +@pytest.mark.asyncio +async def test_int64_value(client: ArrayClient): + assert await client.int64_value.get() == [2**53 - 1, -(2**53 - 1)] + await client.int64_value.put([2**53 - 1, -(2**53 - 1)]) + + +@pytest.mark.asyncio +async def test_model_value(client: ArrayClient): + assert await client.model_value.get() == [ + models.InnerModel(property="hello"), + models.InnerModel(property="world"), + ] + # test list[model] + await client.model_value.put( + [ + models.InnerModel(property="hello"), + models.InnerModel(property="world"), + ] + ) + + # test list[JSON] + await client.model_value.put( + [ + {"property": "hello"}, + {"property": "world"}, + ] + ) + + +@pytest.mark.asyncio +async def test_nullable_boolean_value(client: ArrayClient): + assert await client.nullable_boolean_value.get() == [True, None, False] + await client.nullable_boolean_value.put([True, None, False]) + + +@pytest.mark.asyncio +async def test_nullable_float_value(client: ArrayClient): + assert await client.nullable_float_value.get() == [1.25, None, 3.0] + await client.nullable_float_value.put([1.25, None, 3.0]) + + +@pytest.mark.asyncio +async def test_nullable_int32_value(client: ArrayClient): + assert await client.nullable_int32_value.get() == [1, None, 3] + await client.nullable_int32_value.put([1, None, 3]) + + +@pytest.mark.asyncio +async def test_nullable_model_value(client: ArrayClient): + assert await client.nullable_model_value.get() == [ + models.InnerModel(property="hello"), + None, + models.InnerModel(property="world"), + ] + await client.nullable_model_value.put( + [ + models.InnerModel(property="hello"), + None, + models.InnerModel(property="world"), + ] + ) + + +@pytest.mark.asyncio +async def test_nullable_string_value(client: ArrayClient): + assert await client.nullable_string_value.get() == ["hello", None, "world"] + await client.nullable_string_value.put(["hello", None, "world"]) + + +@pytest.mark.asyncio +async def test_string_value(client: ArrayClient): + assert await client.string_value.get() == ["hello", ""] + await client.string_value.put(["hello", ""]) + + +@pytest.mark.asyncio +async def test_unknown_value(client: ArrayClient): + assert await client.unknown_value.get() == [1, "hello", None] + await client.unknown_value.put([1, "hello", None]) diff --git a/packages/typespec-python/tests/mock_api/shared/asynctests/test_typetest_dictionary_async.py b/packages/typespec-python/tests/mock_api/shared/asynctests/test_typetest_dictionary_async.py new file mode 100644 index 0000000000..76a57a1ba9 --- /dev/null +++ b/packages/typespec-python/tests/mock_api/shared/asynctests/test_typetest_dictionary_async.py @@ -0,0 +1,99 @@ +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- +import pytest +import pytest_asyncio +from typetest.dictionary import models +from typetest.dictionary.aio import DictionaryClient +import isodate + + +@pytest_asyncio.fixture +async def client(): + async with DictionaryClient() as client: + yield client + + +@pytest.mark.asyncio +async def test_boolean_value(client: DictionaryClient): + value = {"k1": True, "k2": False} + assert await client.boolean_value.get() == value + await client.boolean_value.put(value) + + +@pytest.mark.asyncio +async def test_datetime_value(client: DictionaryClient): + value = {"k1": isodate.parse_datetime("2022-08-26T18:38:00Z")} + assert await client.datetime_value.get() == value + await client.datetime_value.put(value) + + +@pytest.mark.asyncio +async def test_duration_value(client: DictionaryClient): + value = {"k1": isodate.parse_duration("P123DT22H14M12.011S")} + assert await client.duration_value.get() == value + await client.duration_value.put(value) + + +@pytest.mark.asyncio +async def test_float32_value(client: DictionaryClient): + value = {"k1": 43.125} + assert await client.float32_value.get() == value + await client.float32_value.put(value) + + +@pytest.mark.asyncio +async def test_int32_value(client: DictionaryClient): + value = {"k1": 1, "k2": 2} + assert await client.int32_value.get() == value + await client.int32_value.put(value) + + +@pytest.mark.asyncio +async def test_int64_value(client: DictionaryClient): + value = {"k1": 2**53 - 1, "k2": -(2**53 - 1)} + assert await client.int64_value.get() == value + await client.int64_value.put(value) + + +@pytest.mark.asyncio +async def test_model_value(client: DictionaryClient): + value = { + "k1": models.InnerModel(property="hello"), + "k2": models.InnerModel(property="world"), + } + assert await client.model_value.get() == value + await client.model_value.put(value) + + +@pytest.mark.asyncio +async def test_nullable_float_value(client: DictionaryClient): + value = {"k1": 1.25, "k2": 0.5, "k3": None} + assert await client.nullable_float_value.get() == value + await client.nullable_float_value.put(value) + + +@pytest.mark.asyncio +async def test_recursive_model_value(client: DictionaryClient): + value = { + "k1": models.InnerModel(property="hello", children={}), + "k2": models.InnerModel(property="world", children={"k2.1": models.InnerModel(property="inner world")}), + } + assert await client.recursive_model_value.get() == value + await client.recursive_model_value.put(value) + + +@pytest.mark.asyncio +async def test_string_value(client: DictionaryClient): + value = {"k1": "hello", "k2": ""} + assert await client.string_value.get() == value + await client.string_value.put(value) + + +@pytest.mark.asyncio +async def test_unknown_value(client: DictionaryClient): + value = {"k1": 1, "k2": "hello", "k3": None} + assert await client.unknown_value.get() == value + await client.unknown_value.put(value) diff --git a/packages/typespec-python/tests/mock_api/shared/asynctests/test_typetest_enum_extensible_async.py b/packages/typespec-python/tests/mock_api/shared/asynctests/test_typetest_enum_extensible_async.py new file mode 100644 index 0000000000..aedc6e6a92 --- /dev/null +++ b/packages/typespec-python/tests/mock_api/shared/asynctests/test_typetest_enum_extensible_async.py @@ -0,0 +1,26 @@ +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- +import pytest +import pytest_asyncio +from typetest.enum.extensible import models, aio + + +@pytest_asyncio.fixture +async def client(): + async with aio.ExtensibleClient() as client: + yield client + + +@pytest.mark.asyncio +async def test_known_value(client): + assert await client.string.get_known_value() == models.DaysOfWeekExtensibleEnum.MONDAY + await client.string.put_known_value(models.DaysOfWeekExtensibleEnum.MONDAY) + + +@pytest.mark.asyncio +async def test_unknown_value(client): + assert await client.string.get_unknown_value() == "Weekend" + await client.string.put_unknown_value("Weekend") diff --git a/packages/typespec-python/tests/mock_api/shared/asynctests/test_typetest_enum_fixed_async.py b/packages/typespec-python/tests/mock_api/shared/asynctests/test_typetest_enum_fixed_async.py new file mode 100644 index 0000000000..5b6822fcfd --- /dev/null +++ b/packages/typespec-python/tests/mock_api/shared/asynctests/test_typetest_enum_fixed_async.py @@ -0,0 +1,28 @@ +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- +import pytest +import pytest_asyncio +from typetest.enum.fixed import aio, models + + +@pytest_asyncio.fixture +async def client(): + async with aio.FixedClient() as client: + yield client + + +@pytest.mark.asyncio +async def test_known_value(client): + assert await client.string.get_known_value() == models.DaysOfWeekEnum.MONDAY + await client.string.put_known_value(models.DaysOfWeekEnum.MONDAY) + + +@pytest.mark.asyncio +async def test_unknown_value(client: aio.FixedClient, core_library): + try: + await client.string.put_unknown_value("Weekend") + except core_library.exceptions.HttpResponseError as err: + assert err.status_code == 500 diff --git a/packages/typespec-python/tests/mock_api/shared/asynctests/test_typetest_file_async.py b/packages/typespec-python/tests/mock_api/shared/asynctests/test_typetest_file_async.py new file mode 100644 index 0000000000..6fa9132a6b --- /dev/null +++ b/packages/typespec-python/tests/mock_api/shared/asynctests/test_typetest_file_async.py @@ -0,0 +1,59 @@ +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- +# after we support Http.File case, enable these tests again + + +# import json + +# import pytest +# from typetest.file.aio import FileClient + + +# @pytest.fixture +# async def client(): +# async with FileClient(endpoint="http://localhost:3000") as client: +# yield client + + +# @pytest.mark.asyncio +# async def test_upload_file_specific_content_type(client: FileClient, png_data: bytes): +# await client.body.upload_file_specific_content_type(png_data) + + +# # Do not support this case for now +# # @pytest.mark.asyncio +# # async def test_upload_file_json_content_type(client: FileClient): +# # await client.body.upload_file_json_content_type(json.dumps({"message": "test file content"}).encode()) + + +# # although result is expected but actually there is deserialization issue +# # @pytest.mark.asyncio +# # async def test_download_file_json_content_type(client: FileClient): +# # result = await client.body.download_file_json_content_type() +# # assert result == {"message": "test file content"} + + +# @pytest.mark.asyncio +# async def test_download_file_specific_content_type(client: FileClient, png_data: bytes): +# result = b"".join([d async for d in (await client.body.download_file_specific_content_type())]) +# assert result == png_data + + +# @pytest.mark.asyncio +# async def test_download_file_multiple_content_types(client: FileClient, png_data: bytes): +# result = b"".join([d async for d in (await client.body.download_file_multiple_content_types())]) +# assert result == png_data + + +# @pytest.mark.asyncio +# async def test_upload_file_default_content_type(client: FileClient, png_data: bytes): +# await client.body.upload_file_default_content_type(png_data, content_type="image/png") + + +# @pytest.mark.asyncio +# async def test_download_file_default_content_type(client: FileClient, png_data: bytes): +# result = b"".join([d async for d in (await client.body.download_file_default_content_type())]) +# assert result == png_data diff --git a/packages/typespec-python/tests/mock_api/shared/asynctests/test_typetest_model_empty_async.py b/packages/typespec-python/tests/mock_api/shared/asynctests/test_typetest_model_empty_async.py new file mode 100644 index 0000000000..030d3bd84f --- /dev/null +++ b/packages/typespec-python/tests/mock_api/shared/asynctests/test_typetest_model_empty_async.py @@ -0,0 +1,33 @@ +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- +import pytest +import pytest_asyncio +from typetest.model.empty.aio import EmptyClient +from typetest.model.empty.models import EmptyInput, EmptyOutput, EmptyInputOutput + + +@pytest_asyncio.fixture +async def client(): + async with EmptyClient() as client: + yield client + + +@pytest.mark.asyncio +async def test_put(client: EmptyClient): + await client.put_empty(EmptyInput()) + await client.put_empty({}) + + +@pytest.mark.asyncio +async def test_get(client: EmptyClient): + assert await client.get_empty() == EmptyOutput() + assert await client.get_empty() == {} + + +@pytest.mark.asyncio +async def test_post_round(client: EmptyClient): + assert await client.post_round_trip_empty(EmptyInputOutput()) == EmptyInputOutput() + assert await client.post_round_trip_empty({}) == {} diff --git a/packages/typespec-python/tests/mock_api/shared/asynctests/test_typetest_model_inheritance_enum_discriminator_async.py b/packages/typespec-python/tests/mock_api/shared/asynctests/test_typetest_model_inheritance_enum_discriminator_async.py new file mode 100644 index 0000000000..dc176b3fd9 --- /dev/null +++ b/packages/typespec-python/tests/mock_api/shared/asynctests/test_typetest_model_inheritance_enum_discriminator_async.py @@ -0,0 +1,71 @@ +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- +import pytest +import pytest_asyncio +from typetest.model.enumdiscriminator.aio import EnumDiscriminatorClient +from typetest.model.enumdiscriminator import models + + +@pytest_asyncio.fixture +async def client(): + async with EnumDiscriminatorClient() as client: + yield client + + +@pytest.fixture +def valid_body(): + return models.Golden(weight=10) + + +@pytest.fixture +def valid_fixed_body(): + return models.Cobra(length=10) + + +@pytest.mark.asyncio +async def test_get_extensible_model(client: EnumDiscriminatorClient, valid_body: models.Dog): + assert await client.get_extensible_model() == valid_body + assert isinstance(await client.get_extensible_model(), models.Golden) + + +@pytest.mark.asyncio +async def test_put_extensible_model(client: EnumDiscriminatorClient, valid_body: models.Dog): + await client.put_extensible_model(valid_body) + + +@pytest.mark.asyncio +async def test_get_extensible_model_missing_discriminator( + client: EnumDiscriminatorClient, +): + assert await client.get_extensible_model_missing_discriminator() == models.Dog(weight=10) + + +@pytest.mark.asyncio +async def test_get_extensible_model_wrong_discriminator( + client: EnumDiscriminatorClient, +): + assert await client.get_extensible_model_wrong_discriminator() == models.Dog(weight=8, kind="wrongKind") + + +@pytest.mark.asyncio +async def test_get_fixed_model(client: EnumDiscriminatorClient, valid_fixed_body: models.Snake): + assert await client.get_fixed_model() == valid_fixed_body + assert isinstance(await client.get_fixed_model(), models.Cobra) + + +@pytest.mark.asyncio +async def test_put_fixed_model(client: EnumDiscriminatorClient, valid_fixed_body: models.Snake): + await client.put_fixed_model(valid_fixed_body) + + +@pytest.mark.asyncio +async def test_get_fixed_model_missing_discriminator(client: EnumDiscriminatorClient): + assert await client.get_fixed_model_missing_discriminator() == models.Snake(length=10) + + +@pytest.mark.asyncio +async def test_get_fixed_model_wrong_discriminator(client: EnumDiscriminatorClient): + assert await client.get_fixed_model_wrong_discriminator() == models.Snake(length=8, kind="wrongKind") diff --git a/packages/typespec-python/tests/mock_api/shared/asynctests/test_typetest_model_inheritance_nested_discriminator_async.py b/packages/typespec-python/tests/mock_api/shared/asynctests/test_typetest_model_inheritance_nested_discriminator_async.py new file mode 100644 index 0000000000..f6e57f5aff --- /dev/null +++ b/packages/typespec-python/tests/mock_api/shared/asynctests/test_typetest_model_inheritance_nested_discriminator_async.py @@ -0,0 +1,86 @@ +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- +import pytest +import pytest_asyncio +from typetest.model.nesteddiscriminator.aio import NestedDiscriminatorClient +from typetest.model.nesteddiscriminator.models import GoblinShark, Salmon, Fish + + +@pytest_asyncio.fixture +async def client(): + async with NestedDiscriminatorClient() as client: + yield client + + +@pytest_asyncio.fixture +async def valid_body(): + return GoblinShark(age=1) + + +@pytest.mark.asyncio +async def test_get_model(client, valid_body): + assert await client.get_model() == valid_body + assert isinstance(await client.get_model(), GoblinShark) + + +@pytest.mark.asyncio +async def test_put_model(client, valid_body): + await client.put_model(valid_body) + + +@pytest_asyncio.fixture +async def valid_recursive_body(): + return Salmon( + { + "age": 1, + "kind": "salmon", + "partner": {"age": 2, "kind": "shark", "sharktype": "saw"}, + "friends": [ + { + "age": 2, + "kind": "salmon", + "partner": {"age": 3, "kind": "salmon"}, + "hate": { + "key1": {"age": 4, "kind": "salmon"}, + "key2": {"age": 2, "kind": "shark", "sharktype": "goblin"}, + }, + }, + {"age": 3, "kind": "shark", "sharktype": "goblin"}, + ], + "hate": { + "key3": {"age": 3, "kind": "shark", "sharktype": "saw"}, + "key4": { + "age": 2, + "kind": "salmon", + "friends": [ + {"age": 1, "kind": "salmon"}, + {"age": 4, "kind": "shark", "sharktype": "goblin"}, + ], + }, + }, + } + ) + + +@pytest.mark.asyncio +async def test_get_recursive_model(client, valid_recursive_body): + assert valid_recursive_body == await client.get_recursive_model() + assert isinstance(await client.get_recursive_model(), Salmon) + + +@pytest.mark.asyncio +async def test_put_recursive_model(client, valid_recursive_body): + await client.put_recursive_model(valid_recursive_body) + + +@pytest.mark.asyncio +async def test_get_missing_discriminator(client): + assert await client.get_missing_discriminator() == Fish(age=1) + + +@pytest.mark.asyncio +async def test_get_wrong_discriminator(client): + assert await client.get_wrong_discriminator() == Fish(age=1, kind="wrongKind") diff --git a/packages/typespec-python/tests/mock_api/shared/asynctests/test_typetest_model_inheritance_not_discriminated_async.py b/packages/typespec-python/tests/mock_api/shared/asynctests/test_typetest_model_inheritance_not_discriminated_async.py new file mode 100644 index 0000000000..5ed075e3d5 --- /dev/null +++ b/packages/typespec-python/tests/mock_api/shared/asynctests/test_typetest_model_inheritance_not_discriminated_async.py @@ -0,0 +1,35 @@ +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- +import pytest +import pytest_asyncio +from typetest.model.notdiscriminated.aio import NotDiscriminatedClient +from typetest.model.notdiscriminated.models import Siamese + + +@pytest_asyncio.fixture +async def client(): + async with NotDiscriminatedClient() as client: + yield client + + +@pytest_asyncio.fixture +async def valid_body(): + return Siamese(name="abc", age=32, smart=True) + + +@pytest.mark.asyncio +async def test_get_valid(client, valid_body): + assert await client.get_valid() == valid_body + + +@pytest.mark.asyncio +async def test_post_valid(client, valid_body): + await client.post_valid(valid_body) + + +@pytest.mark.asyncio +async def test_put_valid(client, valid_body): + assert valid_body == await client.put_valid(valid_body) diff --git a/packages/typespec-python/tests/mock_api/shared/asynctests/test_typetest_model_inheritance_recursive_async.py b/packages/typespec-python/tests/mock_api/shared/asynctests/test_typetest_model_inheritance_recursive_async.py new file mode 100644 index 0000000000..3056c2c40a --- /dev/null +++ b/packages/typespec-python/tests/mock_api/shared/asynctests/test_typetest_model_inheritance_recursive_async.py @@ -0,0 +1,35 @@ +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- +import pytest +import pytest_asyncio +from typetest.model.recursive.aio import RecursiveClient +from typetest.model.recursive.models import Extension + + +@pytest_asyncio.fixture +async def client(): + async with RecursiveClient() as client: + yield client + + +@pytest_asyncio.fixture +async def expected(): + return Extension( + { + "level": 0, + "extension": [{"level": 1, "extension": [{"level": 2}]}, {"level": 1}], + } + ) + + +@pytest.mark.asyncio +async def test_put(client: RecursiveClient, expected: Extension): + await client.put(expected) + + +@pytest.mark.asyncio +async def test_get(client: RecursiveClient, expected: Extension): + assert await client.get() == expected diff --git a/packages/typespec-python/tests/mock_api/shared/asynctests/test_typetest_model_inheritance_single_discriminator_async.py b/packages/typespec-python/tests/mock_api/shared/asynctests/test_typetest_model_inheritance_single_discriminator_async.py new file mode 100644 index 0000000000..e6ddd9c44f --- /dev/null +++ b/packages/typespec-python/tests/mock_api/shared/asynctests/test_typetest_model_inheritance_single_discriminator_async.py @@ -0,0 +1,68 @@ +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- +import pytest +import pytest_asyncio +from typetest.model.singlediscriminator.aio import SingleDiscriminatorClient +from typetest.model.singlediscriminator.models import Sparrow, Eagle, Bird, Dinosaur + + +@pytest_asyncio.fixture +async def client(): + async with SingleDiscriminatorClient() as client: + yield client + + +@pytest_asyncio.fixture +async def valid_body(): + return Sparrow(wingspan=1) + + +@pytest.mark.asyncio +async def test_get_model(client, valid_body): + assert await client.get_model() == valid_body + + +@pytest.mark.asyncio +async def test_put_model(client, valid_body): + await client.put_model(valid_body) + + +@pytest_asyncio.fixture +async def recursive_body(): + return Eagle( + { + "wingspan": 5, + "kind": "eagle", + "partner": {"wingspan": 2, "kind": "goose"}, + "friends": [{"wingspan": 2, "kind": "seagull"}], + "hate": {"key3": {"wingspan": 1, "kind": "sparrow"}}, + } + ) + + +@pytest.mark.asyncio +async def test_get_recursive_model(client, recursive_body): + assert await client.get_recursive_model() == recursive_body + + +@pytest.mark.asyncio +async def test_put_recursive_model(client, recursive_body): + await client.put_recursive_model(recursive_body) + + +@pytest.mark.asyncio +async def test_get_missing_discriminator(client): + assert await client.get_missing_discriminator() == Bird(wingspan=1) + + +@pytest.mark.asyncio +async def test_get_wrong_discriminator(client): + assert await client.get_wrong_discriminator() == Bird(wingspan=1, kind="wrongKind") + + +@pytest.mark.asyncio +async def test_get_legacy_model(client): + assert await client.get_legacy_model() == Dinosaur(size=20, kind="t-rex") diff --git a/packages/typespec-python/tests/mock_api/shared/asynctests/test_typetest_model_usage_async.py b/packages/typespec-python/tests/mock_api/shared/asynctests/test_typetest_model_usage_async.py new file mode 100644 index 0000000000..a7e0035403 --- /dev/null +++ b/packages/typespec-python/tests/mock_api/shared/asynctests/test_typetest_model_usage_async.py @@ -0,0 +1,33 @@ +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- +import pytest +import pytest_asyncio +from typetest.model.usage import models +from typetest.model.usage.aio import UsageClient + + +@pytest_asyncio.fixture +async def client(): + async with UsageClient() as client: + yield client + + +@pytest.mark.asyncio +async def test_input(client: UsageClient): + input = models.InputRecord(required_prop="example-value") + assert await client.input(input) is None + + +@pytest.mark.asyncio +async def test_output(client: UsageClient): + output = models.OutputRecord(required_prop="example-value") + assert output == await client.output() + + +@pytest.mark.asyncio +async def test_input_and_output(client: UsageClient): + input_output = models.InputOutputRecord(required_prop="example-value") + assert input_output == await client.input_and_output(input_output) diff --git a/packages/typespec-python/tests/mock_api/shared/asynctests/test_typetest_model_visibility_async.py b/packages/typespec-python/tests/mock_api/shared/asynctests/test_typetest_model_visibility_async.py new file mode 100644 index 0000000000..6282769581 --- /dev/null +++ b/packages/typespec-python/tests/mock_api/shared/asynctests/test_typetest_model_visibility_async.py @@ -0,0 +1,48 @@ +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- +import pytest +import pytest_asyncio +from typetest.model.visibility.aio import VisibilityClient +from typetest.model.visibility import models + + +@pytest_asyncio.fixture +async def client(): + async with VisibilityClient() as client: + yield client + + +@pytest.mark.asyncio +async def test_get_model(client): + result = await client.get_model(models.VisibilityModel(), query_prop=123) + assert result == models.VisibilityModel(read_prop="abc") + + +@pytest.mark.asyncio +async def test_put_model(client): + await client.put_model(models.VisibilityModel(create_prop=["foo", "bar"], update_prop=[1, 2])) + + +@pytest.mark.asyncio +async def test_patch_model(client): + await client.patch_model(models.VisibilityModel(update_prop=[1, 2])) + + +@pytest.mark.asyncio +async def test_post_model(client): + await client.post_model(models.VisibilityModel(create_prop=["foo", "bar"])) + + +@pytest.mark.asyncio +async def test_delete_model(client): + await client.delete_model(models.VisibilityModel(delete_prop=True)) + + +@pytest.mark.asyncio +async def test_put_read_only_model(client): + await client.put_read_only_model( + models.ReadOnlyModel(optional_nullable_int_list=[1, 2], optional_string_record={"foo", "bar"}) + ) diff --git a/packages/typespec-python/tests/mock_api/shared/asynctests/test_typetest_property_additionalproperties_async.py b/packages/typespec-python/tests/mock_api/shared/asynctests/test_typetest_property_additionalproperties_async.py new file mode 100644 index 0000000000..3bded493a0 --- /dev/null +++ b/packages/typespec-python/tests/mock_api/shared/asynctests/test_typetest_property_additionalproperties_async.py @@ -0,0 +1,338 @@ +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- +import pytest +import pytest_asyncio +from typetest.property.additionalproperties import models +from typetest.property.additionalproperties.aio import AdditionalPropertiesClient + + +@pytest_asyncio.fixture +async def client(): + async with AdditionalPropertiesClient() as client: + yield client + + +@pytest.mark.asyncio +async def test_extends_different_spread_float(client: AdditionalPropertiesClient): + body = models.DifferentSpreadFloatDerived({"name": "abc", "prop": 43.125, "derivedProp": 43.125}) + assert await client.extends_different_spread_float.get() == body + await client.extends_different_spread_float.put(body) + + +@pytest.mark.asyncio +async def test_extends_different_spread_model(client: AdditionalPropertiesClient): + body = models.DifferentSpreadModelDerived( + {"knownProp": "abc", "prop": {"state": "ok"}, "derivedProp": {"state": "ok"}} + ) + assert await client.extends_different_spread_model.get() == body + await client.extends_different_spread_model.put(body) + + +@pytest.mark.asyncio +async def test_extends_different_spread_model_array(client: AdditionalPropertiesClient): + body = models.DifferentSpreadModelArrayDerived( + { + "knownProp": "abc", + "prop": [{"state": "ok"}, {"state": "ok"}], + "derivedProp": [{"state": "ok"}, {"state": "ok"}], + } + ) + assert await client.extends_different_spread_model_array.get() == body + await client.extends_different_spread_model_array.put(body) + + +@pytest.mark.asyncio +async def test_extends_different_spread_string(client: AdditionalPropertiesClient): + body = models.DifferentSpreadStringDerived({"id": 43.125, "prop": "abc", "derivedProp": "abc"}) + assert await client.extends_different_spread_string.get() == body + await client.extends_different_spread_string.put(body) + + +@pytest.mark.asyncio +async def test_extends_float(client: AdditionalPropertiesClient): + body = models.ExtendsFloatAdditionalProperties({"id": 43.125, "prop": 43.125}) + assert await client.extends_float.get() == body + await client.extends_float.put(body) + + +@pytest.mark.asyncio +async def test_extends_model(client: AdditionalPropertiesClient): + body = models.ExtendsModelAdditionalProperties({"knownProp": {"state": "ok"}, "prop": {"state": "ok"}}) + assert await client.extends_model.get() == body + await client.extends_model.put(body) + + +@pytest.mark.asyncio +async def test_extends_model_array(client: AdditionalPropertiesClient): + body = models.ExtendsModelArrayAdditionalProperties( + { + "knownProp": [{"state": "ok"}, {"state": "ok"}], + "prop": [{"state": "ok"}, {"state": "ok"}], + } + ) + assert await client.extends_model_array.get() == body + await client.extends_model_array.put(body) + + +@pytest.mark.asyncio +async def test_extends_string(client: AdditionalPropertiesClient): + body = models.ExtendsStringAdditionalProperties({"name": "ExtendsStringAdditionalProperties", "prop": "abc"}) + assert await client.extends_string.get() == body + await client.extends_string.put(body) + + +@pytest.mark.asyncio +async def test_extends_unknown(client: AdditionalPropertiesClient): + body = models.ExtendsUnknownAdditionalProperties( + { + "name": "ExtendsUnknownAdditionalProperties", + "prop1": 32, + "prop2": True, + "prop3": "abc", + } + ) + assert await client.extends_unknown.get() == body + await client.extends_unknown.put(body) + + +@pytest.mark.asyncio +async def test_extends_unknown_derived(client: AdditionalPropertiesClient): + body = models.ExtendsUnknownAdditionalPropertiesDerived( + { + "name": "ExtendsUnknownAdditionalProperties", + "index": 314, + "age": 2.71875, + "prop1": 32, + "prop2": True, + "prop3": "abc", + } + ) + assert await client.extends_unknown_derived.get() == body + await client.extends_unknown_derived.put(body) + + +@pytest.mark.asyncio +async def test_extends_unknown_discriminated(client: AdditionalPropertiesClient): + body = models.ExtendsUnknownAdditionalPropertiesDiscriminatedDerived( + { + "kind": "derived", + "name": "Derived", + "index": 314, + "age": 2.71875, + "prop1": 32, + "prop2": True, + "prop3": "abc", + } + ) + assert await client.extends_unknown_discriminated.get() == body + await client.extends_unknown_discriminated.put(body) + + +@pytest.mark.asyncio +async def test_is_float(client: AdditionalPropertiesClient): + body = models.IsFloatAdditionalProperties({"id": 43.125, "prop": 43.125}) + assert await client.is_float.get() == body + await client.is_float.put(body) + + +@pytest.mark.asyncio +async def test_is_model(client: AdditionalPropertiesClient): + body = models.IsModelAdditionalProperties({"knownProp": {"state": "ok"}, "prop": {"state": "ok"}}) + assert await client.is_model.get() == body + await client.is_model.put(body) + + +@pytest.mark.asyncio +async def test_is_model_array(client: AdditionalPropertiesClient): + body = models.IsModelArrayAdditionalProperties( + { + "knownProp": [{"state": "ok"}, {"state": "ok"}], + "prop": [{"state": "ok"}, {"state": "ok"}], + } + ) + assert await client.is_model_array.get() == body + await client.is_model_array.put(body) + + +@pytest.mark.asyncio +async def test_is_string(client: AdditionalPropertiesClient): + body = models.IsStringAdditionalProperties({"name": "IsStringAdditionalProperties", "prop": "abc"}) + assert await client.is_string.get() == body + await client.is_string.put(body) + + +@pytest.mark.asyncio +async def test_is_unknown(client: AdditionalPropertiesClient): + body = models.IsUnknownAdditionalProperties( + { + "name": "IsUnknownAdditionalProperties", + "prop1": 32, + "prop2": True, + "prop3": "abc", + } + ) + assert await client.is_unknown.get() == body + await client.is_unknown.put(body) + + +@pytest.mark.asyncio +async def test_is_unknown_derived(client: AdditionalPropertiesClient): + body = models.IsUnknownAdditionalPropertiesDerived( + { + "name": "IsUnknownAdditionalProperties", + "index": 314, + "age": 2.71875, + "prop1": 32, + "prop2": True, + "prop3": "abc", + } + ) + assert await client.is_unknown_derived.get() == body + await client.is_unknown_derived.put(body) + + +@pytest.mark.asyncio +async def test_is_unknown_discriminated(client: AdditionalPropertiesClient): + body = models.IsUnknownAdditionalPropertiesDiscriminatedDerived( + { + "kind": "derived", + "name": "Derived", + "index": 314, + "age": 2.71875, + "prop1": 32, + "prop2": True, + "prop3": "abc", + } + ) + assert await client.is_unknown_discriminated.get() == body + await client.is_unknown_discriminated.put(body) + + +@pytest.mark.asyncio +async def test_multiple_spread(client: AdditionalPropertiesClient): + body = {"flag": True, "prop1": "abc", "prop2": 43.125} + assert await client.multiple_spread.get() == body + await client.multiple_spread.put(body) + + +@pytest.mark.asyncio +async def test_spread_different_float(client: AdditionalPropertiesClient): + body = {"name": "abc", "prop": 43.125} + assert await client.spread_different_float.get() == body + await client.spread_different_float.put(body) + + +@pytest.mark.asyncio +async def test_spread_different_model(client: AdditionalPropertiesClient): + body = {"knownProp": "abc", "prop": {"state": "ok"}} + assert await client.spread_different_model.get() == body + await client.spread_different_model.put(body) + + +@pytest.mark.asyncio +async def test_spread_different_model_array(client: AdditionalPropertiesClient): + body = {"knownProp": "abc", "prop": [{"state": "ok"}, {"state": "ok"}]} + assert await client.spread_different_model_array.get() == body + await client.spread_different_model_array.put(body) + + +@pytest.mark.asyncio +async def test_spread_different_string(client: AdditionalPropertiesClient): + body = {"id": 43.125, "prop": "abc"} + assert await client.spread_different_string.get() == body + await client.spread_different_string.put(body) + + +@pytest.mark.asyncio +async def test_spread_model(client: AdditionalPropertiesClient): + body = {"knownProp": {"state": "ok"}, "prop": {"state": "ok"}} + assert await client.spread_model.get() == body + await client.spread_model.put(body) + + +@pytest.mark.asyncio +async def test_spread_model_array(client: AdditionalPropertiesClient): + body = { + "knownProp": [{"state": "ok"}, {"state": "ok"}], + "prop": [{"state": "ok"}, {"state": "ok"}], + } + assert await client.spread_model_array.get() == body + await client.spread_model_array.put(body) + + +@pytest.mark.asyncio +async def test_spread_record_non_discriminated_union( + client: AdditionalPropertiesClient, +): + body = { + "name": "abc", + "prop1": {"kind": "kind0", "fooProp": "abc"}, + "prop2": { + "kind": "kind1", + "start": "2021-01-01T00:00:00Z", + "end": "2021-01-02T00:00:00Z", + }, + } + assert await client.spread_record_non_discriminated_union.get() == body + await client.spread_record_non_discriminated_union.put(body) + + +@pytest.mark.asyncio +async def test_spread_record_non_discriminated_union2( + client: AdditionalPropertiesClient, +): + body = { + "name": "abc", + "prop1": {"kind": "kind1", "start": "2021-01-01T00:00:00Z"}, + "prop2": { + "kind": "kind1", + "start": "2021-01-01T00:00:00Z", + "end": "2021-01-02T00:00:00Z", + }, + } + assert await client.spread_record_non_discriminated_union2.get() == body + await client.spread_record_non_discriminated_union2.put(body) + + +@pytest.mark.asyncio +async def test_spread_record_non_discriminated_union3( + client: AdditionalPropertiesClient, +): + body = { + "name": "abc", + "prop1": [ + {"kind": "kind1", "start": "2021-01-01T00:00:00Z"}, + {"kind": "kind1", "start": "2021-01-01T00:00:00Z"}, + ], + "prop2": { + "kind": "kind1", + "start": "2021-01-01T00:00:00Z", + "end": "2021-01-02T00:00:00Z", + }, + } + assert await client.spread_record_non_discriminated_union3.get() == body + await client.spread_record_non_discriminated_union3.put(body) + + +@pytest.mark.asyncio +async def test_spread_record_union(client: AdditionalPropertiesClient): + body = {"flag": True, "prop1": "abc", "prop2": 43.125} + assert await client.spread_record_union.get() == body + await client.spread_record_union.put(body) + + +@pytest.mark.asyncio +async def test_spread_string(client: AdditionalPropertiesClient): + body = {"name": "SpreadSpringRecord", "prop": "abc"} + assert await client.spread_string.get() == body + await client.spread_string.put(body) + + +@pytest.mark.asyncio +async def test_spread_float(client: AdditionalPropertiesClient): + body = {"id": 43.125, "prop": 43.125} + assert await client.spread_float.get() == body + await client.spread_float.put(body) diff --git a/packages/typespec-python/tests/mock_api/shared/asynctests/test_typetest_property_nullable_async.py b/packages/typespec-python/tests/mock_api/shared/asynctests/test_typetest_property_nullable_async.py new file mode 100644 index 0000000000..f54cafb464 --- /dev/null +++ b/packages/typespec-python/tests/mock_api/shared/asynctests/test_typetest_property_nullable_async.py @@ -0,0 +1,111 @@ +# cspell: ignore Hdvcmxk +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- +import json +import pytest +import pytest_asyncio +from typetest.property.nullable import models +from typetest.property.nullable.aio import NullableClient +from typetest.property.nullable._utils.model_base import ( # pylint: disable=protected-access + SdkJSONEncoder, +) + +try: + from corehttp.serialization import NULL +except ImportError: + from azure.core.serialization import NULL + + +@pytest_asyncio.fixture +async def client(): + async with NullableClient() as client: + yield client + + +@pytest.mark.asyncio +async def test_bytes(client: NullableClient): + non_null_model = models.BytesProperty(required_property="foo", nullable_property="aGVsbG8sIHdvcmxkIQ==") + non_model = models.BytesProperty(required_property="foo", nullable_property=NULL) + assert '{"requiredProperty": "foo", "nullableProperty": null}' == json.dumps(non_model, cls=SdkJSONEncoder) + assert await client.bytes.get_non_null() == non_null_model + assert (await client.bytes.get_null())["nullableProperty"] is None + await client.bytes.patch_non_null(body=non_null_model) + await client.bytes.patch_null(body=non_model) + + +@pytest.mark.asyncio +async def test_collections_byte(client: NullableClient): + non_null_model = models.CollectionsByteProperty( + required_property="foo", + nullable_property=["aGVsbG8sIHdvcmxkIQ==", "aGVsbG8sIHdvcmxkIQ=="], + ) + non_model = models.CollectionsByteProperty(required_property="foo", nullable_property=NULL) + assert '{"requiredProperty": "foo", "nullableProperty": null}' == json.dumps(non_model, cls=SdkJSONEncoder) + assert await client.collections_byte.get_non_null() == non_null_model + assert (await client.collections_byte.get_null())["nullableProperty"] is None + await client.collections_byte.patch_non_null(body=non_null_model) + await client.collections_byte.patch_null(body=non_model) + + +@pytest.mark.asyncio +async def test_collections_model(client: NullableClient): + non_null_model = models.CollectionsModelProperty( + required_property="foo", + nullable_property=[ + models.InnerModel(property="hello"), + models.InnerModel(property="world"), + ], + ) + non_model = models.CollectionsModelProperty(required_property="foo", nullable_property=NULL) + assert '{"requiredProperty": "foo", "nullableProperty": null}' == json.dumps(non_model, cls=SdkJSONEncoder) + assert await client.collections_model.get_non_null() == non_null_model + assert (await client.collections_model.get_null())["nullableProperty"] is None + await client.collections_model.patch_non_null(body=non_null_model) + await client.collections_model.patch_null(body=non_model) + + +@pytest.mark.asyncio +async def test_collections_string(client: NullableClient): + non_null_model = models.CollectionsStringProperty(required_property="foo", nullable_property=["hello", "world"]) + non_model = models.CollectionsStringProperty(required_property="foo", nullable_property=NULL) + assert '{"requiredProperty": "foo", "nullableProperty": null}' == json.dumps(non_model, cls=SdkJSONEncoder) + assert await client.collections_string.get_non_null() == non_null_model + assert (await client.collections_string.get_null())["nullableProperty"] is None + await client.collections_string.patch_non_null(body=non_null_model) + await client.collections_string.patch_null(body=non_model) + + +@pytest.mark.asyncio +async def test_datetime(client: NullableClient): + non_null_model = models.DatetimeProperty(required_property="foo", nullable_property="2022-08-26T18:38:00Z") + non_model = models.DatetimeProperty(required_property="foo", nullable_property=NULL) + assert '{"requiredProperty": "foo", "nullableProperty": null}' == json.dumps(non_model, cls=SdkJSONEncoder) + assert await client.datetime.get_non_null() == non_null_model + assert (await client.datetime.get_null())["nullableProperty"] is None + await client.datetime.patch_non_null(body=non_null_model) + await client.datetime.patch_null(body=non_model) + + +@pytest.mark.asyncio +async def test_duration(client: NullableClient): + non_null_model = models.DurationProperty(required_property="foo", nullable_property="P123DT22H14M12.011S") + non_model = models.DurationProperty(required_property="foo", nullable_property=NULL) + assert '{"requiredProperty": "foo", "nullableProperty": null}' == json.dumps(non_model, cls=SdkJSONEncoder) + assert await client.duration.get_non_null() == non_null_model + assert (await client.duration.get_null())["nullableProperty"] is None + await client.duration.patch_non_null(body=non_null_model) + await client.duration.patch_null(body=non_model) + + +@pytest.mark.asyncio +async def test_string(client: NullableClient): + non_null_model = models.StringProperty(required_property="foo", nullable_property="hello") + non_model = models.StringProperty(required_property="foo", nullable_property=NULL) + assert '{"requiredProperty": "foo", "nullableProperty": null}' == json.dumps(non_model, cls=SdkJSONEncoder) + assert await client.string.get_non_null() == non_null_model + assert (await client.string.get_null())["nullableProperty"] is None + await client.string.patch_non_null(body=non_null_model) + await client.string.patch_null(body=non_model) diff --git a/packages/typespec-python/tests/mock_api/shared/asynctests/test_typetest_property_optional_async.py b/packages/typespec-python/tests/mock_api/shared/asynctests/test_typetest_property_optional_async.py new file mode 100644 index 0000000000..51d8bd362e --- /dev/null +++ b/packages/typespec-python/tests/mock_api/shared/asynctests/test_typetest_property_optional_async.py @@ -0,0 +1,198 @@ +# cspell: ignore Hdvcmxk +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- +from typing import Any +import pytest +import pytest_asyncio +from typetest.property.optional import models +from typetest.property.optional.aio import OptionalClient + + +@pytest_asyncio.fixture +async def client(): + async with OptionalClient() as client: + yield client + + +@pytest.mark.asyncio +async def test_boolean_literal(client): + body = models.BooleanLiteralProperty(property=True) + assert await client.boolean_literal.get_all() == body + assert await client.boolean_literal.get_default() == models.BooleanLiteralProperty() + await client.boolean_literal.put_all(body) + await client.boolean_literal.put_default(models.BooleanLiteralProperty()) + + +@pytest.mark.asyncio +async def test_bytes(client): + body = models.BytesProperty(property="aGVsbG8sIHdvcmxkIQ==") + assert await client.bytes.get_all() == body + assert await client.bytes.get_default() == models.BytesProperty() + await client.bytes.put_all(body) + await client.bytes.put_default(models.BytesProperty()) + + +@pytest.mark.asyncio +async def test_collections_byte(client): + body = models.CollectionsByteProperty(property=["aGVsbG8sIHdvcmxkIQ==", "aGVsbG8sIHdvcmxkIQ=="]) + assert await client.collections_byte.get_all() == body + assert await client.collections_byte.get_default() == models.CollectionsByteProperty() + await client.collections_byte.put_all(body) + await client.collections_byte.put_default(models.CollectionsByteProperty()) + + +@pytest.mark.asyncio +async def test_collections_model(client): + body = models.CollectionsModelProperty( + property=[ + models.StringProperty(property="hello"), + models.StringProperty(property="world"), + ] + ) + assert await client.collections_model.get_all() == body + assert await client.collections_model.get_default() == models.CollectionsModelProperty() + await client.collections_model.put_all(body) + await client.collections_model.put_default(models.CollectionsModelProperty()) + + +@pytest.mark.asyncio +async def test_datetime(client): + body = models.DatetimeProperty(property="2022-08-26T18:38:00Z") + assert await client.datetime.get_all() == body + assert await client.datetime.get_default() == models.DatetimeProperty() + await client.datetime.put_all(body) + await client.datetime.put_default(models.DatetimeProperty()) + + +@pytest.mark.asyncio +async def test_duration(client): + body = models.DurationProperty(property="P123DT22H14M12.011S") + assert await client.duration.get_all() == body + assert await client.duration.get_default() == models.DurationProperty() + await client.duration.put_all(body) + await client.duration.put_default(models.DurationProperty()) + + +@pytest.mark.asyncio +async def test_float_literal(client): + body = models.FloatLiteralProperty(property=1.25) + assert await client.float_literal.get_all() == body + assert await client.float_literal.get_default() == models.FloatLiteralProperty() + await client.float_literal.put_all(body) + await client.float_literal.put_default(models.FloatLiteralProperty()) + + +@pytest.mark.asyncio +async def test_int_literal(client): + body = models.IntLiteralProperty(property=1) + assert await client.int_literal.get_all() == body + assert await client.int_literal.get_default() == models.IntLiteralProperty() + await client.int_literal.put_all(body) + await client.int_literal.put_default(models.IntLiteralProperty()) + + +@pytest.mark.asyncio +async def test_plaindate(client): + body = models.PlainDateProperty(property="2022-12-12") + assert await client.plain_date.get_all() == body + + +@pytest.mark.asyncio +async def test_plaindate(client): + assert await client.plain_date.get_default() == models.PlainDateProperty() + + +@pytest.mark.asyncio +async def test_plaindate(client): + body = models.PlainDateProperty(property="2022-12-12") + await client.plain_date.put_all(body) + + +@pytest.mark.asyncio +async def test_plaindate(client): + await client.plain_date.put_default(models.PlainDateProperty()) + + +@pytest.mark.asyncio +async def test_plaintime(client): + body = models.PlainTimeProperty(property="13:06:12") + assert await client.plain_time.get_all() == body + + +@pytest.mark.asyncio +async def test_plaintime(client): + assert await client.plain_time.get_default() == models.PlainTimeProperty() + + +@pytest.mark.asyncio +async def test_plaintime(client): + body = models.PlainTimeProperty(property="13:06:12") + await client.plain_time.put_all(body) + + +@pytest.mark.asyncio +async def test_plaintime(client): + await client.plain_time.put_default(models.PlainTimeProperty()) + + +@pytest.mark.asyncio +async def test_required_and_optional(client): + all_body = { + "optionalProperty": "hello", + "requiredProperty": 42, + } + required_only_body = { + "requiredProperty": 42, + } + assert await client.required_and_optional.get_all() == all_body + assert await client.required_and_optional.get_required_only() == required_only_body + await client.required_and_optional.put_all(all_body) + await client.required_and_optional.put_required_only(required_only_body) + + +@pytest.mark.asyncio +async def test_string(client): + body = models.StringProperty(property="hello") + assert await client.string.get_all() == body + assert await client.string.get_default() == models.StringProperty() + await client.string.put_all(body) + await client.string.put_default(models.StringProperty()) + + +@pytest.mark.asyncio +async def test_string_literal(client): + body = models.StringLiteralProperty(property="hello") + assert await client.string_literal.get_all() == body + assert await client.string_literal.get_default() == models.StringLiteralProperty() + await client.string_literal.put_all(body) + await client.string_literal.put_default(models.StringLiteralProperty()) + + +@pytest.mark.asyncio +async def test_union_float_literal(client): + body = models.UnionFloatLiteralProperty(property=2.375) + assert await client.union_float_literal.get_all() == body + assert await client.union_float_literal.get_default() == models.UnionFloatLiteralProperty() + await client.union_float_literal.put_all(body) + await client.union_float_literal.put_default(models.UnionFloatLiteralProperty()) + + +@pytest.mark.asyncio +async def test_union_int_literal(client): + body = models.UnionIntLiteralProperty(property=2) + assert await client.union_int_literal.get_all() == body + assert await client.union_int_literal.get_default() == models.UnionIntLiteralProperty() + await client.union_int_literal.put_all(body) + await client.union_int_literal.put_default(models.UnionIntLiteralProperty()) + + +@pytest.mark.asyncio +async def test_union_string_literal(client): + body = models.UnionStringLiteralProperty(property="world") + assert await client.union_string_literal.get_all() == body + assert await client.union_string_literal.get_default() == models.UnionStringLiteralProperty() + await client.union_string_literal.put_all(body) + await client.union_string_literal.put_default(models.UnionStringLiteralProperty()) diff --git a/packages/typespec-python/tests/mock_api/shared/asynctests/test_typetest_property_valuetypes_async.py b/packages/typespec-python/tests/mock_api/shared/asynctests/test_typetest_property_valuetypes_async.py new file mode 100644 index 0000000000..15a3e794e1 --- /dev/null +++ b/packages/typespec-python/tests/mock_api/shared/asynctests/test_typetest_property_valuetypes_async.py @@ -0,0 +1,316 @@ +# cspell: ignore Hdvcmxk +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- +import decimal + +import pytest +import pytest_asyncio +import datetime +from typetest.property.valuetypes import models +from typetest.property.valuetypes.aio import ValueTypesClient + + +@pytest_asyncio.fixture +async def client(): + async with ValueTypesClient() as client: + yield client + + +@pytest.mark.asyncio +async def test_boolean(client: ValueTypesClient): + body = models.BooleanProperty(property=True) + assert body.property == body["property"] + await client.boolean.put(body) + + resp = await client.boolean.get() + assert resp.property == resp["property"] == True + + +@pytest.mark.asyncio +async def test_boolean_literal(client: ValueTypesClient): + body = models.BooleanLiteralProperty(property=True) + assert body.property == body["property"] + await client.boolean_literal.put(body) + + resp = await client.boolean_literal.get() + assert resp.property == resp["property"] == True + + +@pytest.mark.asyncio +async def test_bytes(client: ValueTypesClient): + body = models.BytesProperty(property=b"hello, world!") + assert body.property == b"hello, world!" + assert body["property"] == "aGVsbG8sIHdvcmxkIQ==" + await client.bytes.put(body) + + resp = await client.bytes.get() + assert resp.property == b"hello, world!" + assert resp["property"] == "aGVsbG8sIHdvcmxkIQ==" + + +@pytest.mark.asyncio +async def test_collections_int(client: ValueTypesClient): + body = models.CollectionsIntProperty(property=[1, 2]) + assert body.property == body["property"] + await client.collections_int.put(body) + + resp = await client.collections_int.get() + assert resp.property == resp["property"] == [1, 2] + + +@pytest.mark.asyncio +async def test_collections_model(client: ValueTypesClient): + body = models.CollectionsModelProperty(property=[{"property": "hello"}, {"property": "world"}]) + assert body.property[0].property == body["property"][0]["property"] + await client.collections_model.put(body) + + resp = await client.collections_model.get() + assert resp.property[1].property == resp["property"][1]["property"] + + +@pytest.mark.asyncio +async def test_collections_string(client: ValueTypesClient): + body = models.CollectionsStringProperty(property=["hello", "world"]) + assert body.property == body["property"] + await client.collections_string.put(body) + + resp = await client.collections_string.get() + assert resp.property == resp["property"] == ["hello", "world"] + + +@pytest.mark.asyncio +async def test_datetime(client): + received_body = await client.datetime.get() + assert received_body == {"property": "2022-08-26T18:38:00Z"} + assert received_body.property.year == 2022 + assert received_body.property.month == 8 + assert received_body.property.day == 26 + assert received_body.property.hour == 18 + assert received_body.property.minute == 38 + + await client.datetime.put(models.DatetimeProperty(property=datetime.datetime(2022, 8, 26, hour=18, minute=38))) + + +@pytest.mark.asyncio +async def test_decimal(client: ValueTypesClient): + body = models.DecimalProperty(property=decimal.Decimal("0.33333")) + assert body.property == decimal.Decimal("0.33333") + assert body["property"] == 0.33333 + await client.decimal.put(body) + + resp = await client.decimal.get() + assert resp.property == decimal.Decimal("0.33333") + assert resp["property"] == 0.33333 + + +@pytest.mark.asyncio +async def test_decimal128(client: ValueTypesClient): + body = models.Decimal128Property(property=decimal.Decimal("0.33333")) + assert body.property == decimal.Decimal("0.33333") + assert body["property"] == 0.33333 + await client.decimal128.put(body) + + resp = await client.decimal128.get() + assert resp.property == decimal.Decimal("0.33333") + assert resp["property"] == 0.33333 + + +@pytest.mark.asyncio +async def test_dictionary_string(client: ValueTypesClient): + body = models.DictionaryStringProperty(property={"k1": "hello", "k2": "world"}) + assert body.property == body["property"] + await client.dictionary_string.put(body) + + resp = await client.dictionary_string.get() + assert resp.property == resp["property"] == {"k1": "hello", "k2": "world"} + + +@pytest.mark.asyncio +async def test_duration(client: ValueTypesClient): + body = models.DurationProperty(property="P123DT22H14M12.011S") + assert body.property == datetime.timedelta(days=123, seconds=80052, microseconds=11000) + assert body["property"] == "P123DT22H14M12.011S" + await client.duration.put(body) + + resp = await client.duration.get() + assert resp.property == datetime.timedelta(days=123, seconds=80052, microseconds=11000) + assert resp["property"] == "P123DT22H14M12.011S" + + +@pytest.mark.asyncio +async def test_enum(client: ValueTypesClient): + body = models.EnumProperty(property=models.InnerEnum.VALUE_ONE) + assert body.property == body["property"] + await client.enum.put(body) + + resp = await client.enum.get() + assert resp.property == resp["property"] == "ValueOne" + + +@pytest.mark.asyncio +async def test_extensible_enum(client: ValueTypesClient): + body = models.ExtensibleEnumProperty(property="UnknownValue") + assert body.property == body["property"] + await client.extensible_enum.put(body) + + resp = await client.extensible_enum.get() + assert resp.property == resp["property"] == "UnknownValue" + + +@pytest.mark.asyncio +async def test_float(client: ValueTypesClient): + body = models.FloatProperty(property=43.125) + assert body.property == body["property"] + await client.float.put(body) + + resp = await client.float.get() + assert resp.property == resp["property"] == 43.125 + + +@pytest.mark.asyncio +async def test_float_literal(client: ValueTypesClient): + body = models.FloatLiteralProperty(property=43.125) + assert body.property == body["property"] + await client.float_literal.put(body) + + resp = await client.float_literal.get() + assert resp.property == resp["property"] == 43.125 + + +@pytest.mark.asyncio +async def test_int(client: ValueTypesClient): + body = models.IntProperty(property=42) + assert body.property == body["property"] + await client.int_operations.put(body) + + resp = await client.int_operations.get() + assert resp.property == resp["property"] == 42 + + +@pytest.mark.asyncio +async def test_int_literal(client: ValueTypesClient): + body = models.IntLiteralProperty(property=42) + assert body.property == body["property"] + await client.int_literal.put(body) + + resp = await client.int_literal.get() + assert resp.property == resp["property"] == 42 + + +@pytest.mark.asyncio +async def test_model(client: ValueTypesClient): + body = models.ModelProperty(property={"property": "hello"}) + assert body.property.property == body["property"]["property"] + await client.model.put(body) + + resp = await client.model.get() + assert resp.property.property == resp["property"]["property"] + + +@pytest.mark.asyncio +async def test_never(client: ValueTypesClient): + assert await client.never.get() == models.NeverProperty() + await client.never.put(models.NeverProperty()) + + +@pytest.mark.asyncio +async def test_string(client: ValueTypesClient): + body = models.StringProperty(property="hello") + assert body.property == body["property"] + await client.string.put(body) + + resp = await client.string.get() + assert resp.property == resp["property"] == "hello" + + +@pytest.mark.asyncio +async def test_string_literal(client: ValueTypesClient): + body = models.StringLiteralProperty(property="hello") + assert body.property == body["property"] + await client.string_literal.put(body) + + resp = await client.string_literal.get() + assert resp.property == resp["property"] == "hello" + + +@pytest.mark.asyncio +async def test_union_enum_value(client: ValueTypesClient): + body = models.UnionEnumValueProperty(property=models.ExtendedEnum.ENUM_VALUE2) + assert body.property == body["property"] + await client.union_enum_value.put(body) + + resp = await client.union_enum_value.get() + assert resp.property == resp["property"] == "value2" + + +@pytest.mark.asyncio +async def test_union_float_literal(client: ValueTypesClient): + body = models.UnionFloatLiteralProperty(property=46.875) + assert body.property == body["property"] + await client.union_float_literal.put(body) + + resp = await client.union_float_literal.get() + assert resp.property == resp["property"] == 46.875 + + +@pytest.mark.asyncio +async def test_union_int_literal(client: ValueTypesClient): + body = models.UnionIntLiteralProperty(property=42) + assert body.property == body["property"] + await client.union_int_literal.put(body) + + resp = await client.union_int_literal.get() + assert resp.property == resp["property"] == 42 + + +@pytest.mark.asyncio +async def test_union_string_literal(client: ValueTypesClient): + body = models.UnionStringLiteralProperty(property="world") + assert body.property == body["property"] + await client.union_string_literal.put(body) + + resp = await client.union_string_literal.get() + assert resp.property == resp["property"] == "world" + + +@pytest.mark.asyncio +async def test_unknown_array(client: ValueTypesClient): + body = models.UnknownArrayProperty(property=["hello", "world"]) + assert body.property == body["property"] + await client.unknown_array.put(body) + + resp = await client.unknown_array.get() + assert resp.property == resp["property"] == ["hello", "world"] + + +@pytest.mark.asyncio +async def test_unknown_dict(client: ValueTypesClient): + body = models.UnknownDictProperty(property={"k1": "hello", "k2": 42}) + assert body.property == body["property"] + await client.unknown_dict.put(body) + + resp = await client.unknown_dict.get() + assert resp.property == resp["property"] == {"k1": "hello", "k2": 42} + + +@pytest.mark.asyncio +async def test_unknown_int(client: ValueTypesClient): + body = models.UnknownIntProperty(property=42) + assert body.property == body["property"] + await client.unknown_int.put(body) + + resp = await client.unknown_int.get() + assert resp.property == resp["property"] == 42 + + +@pytest.mark.asyncio +async def test_unknown_string(client: ValueTypesClient): + body = models.UnknownStringProperty(property="hello") + assert body.property == body["property"] + await client.unknown_string.put(body) + + resp = await client.unknown_string.get() + assert resp.property == resp["property"] == "hello" diff --git a/packages/typespec-python/tests/mock_api/shared/asynctests/test_typetest_scalar_async.py b/packages/typespec-python/tests/mock_api/shared/asynctests/test_typetest_scalar_async.py new file mode 100644 index 0000000000..674ee0e0d4 --- /dev/null +++ b/packages/typespec-python/tests/mock_api/shared/asynctests/test_typetest_scalar_async.py @@ -0,0 +1,61 @@ +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- +import decimal +from functools import reduce + +import pytest +import pytest_asyncio +from typetest.scalar.aio import ScalarClient + + +@pytest_asyncio.fixture +async def client(): + async with ScalarClient() as client: + yield client + + +@pytest.mark.asyncio +async def test_scalar_string(client: ScalarClient): + assert await client.string.get() == "test" + await client.string.put("test") + + +@pytest.mark.asyncio +async def test_scalar_boolean(client: ScalarClient): + assert await client.boolean.get() == True + await client.boolean.put(True) + + +@pytest.mark.asyncio +async def test_scalar_unknown(client: ScalarClient): + assert await client.unknown.get() == "test" + await client.unknown.put("test") + + +@pytest.mark.asyncio +async def test_decimal128_type(client: ScalarClient): + assert await client.decimal128_type.response_body() == decimal.Decimal("0.33333") + await client.decimal128_type.request_body(decimal.Decimal("0.33333")) + await client.decimal128_type.request_parameter(value=decimal.Decimal("0.33333")) + + +@pytest.mark.asyncio +async def test_decimal_type(client: ScalarClient): + assert await client.decimal_type.response_body() == decimal.Decimal("0.33333") + await client.decimal_type.request_body(decimal.Decimal("0.33333")) + await client.decimal_type.request_parameter(value=decimal.Decimal("0.33333")) + + +@pytest.mark.asyncio +async def test_decimal128_verify(client: ScalarClient): + prepare = await client.decimal128_verify.prepare_verify() + await client.decimal128_verify.verify(reduce(lambda x, y: x + y, prepare)) + + +@pytest.mark.asyncio +async def test_decimal_verify(client: ScalarClient): + prepare = await client.decimal_verify.prepare_verify() + await client.decimal_verify.verify(reduce(lambda x, y: x + y, prepare)) diff --git a/packages/typespec-python/tests/mock_api/shared/asynctests/test_typetest_union_async.py b/packages/typespec-python/tests/mock_api/shared/asynctests/test_typetest_union_async.py new file mode 100644 index 0000000000..18b5e1aba9 --- /dev/null +++ b/packages/typespec-python/tests/mock_api/shared/asynctests/test_typetest_union_async.py @@ -0,0 +1,91 @@ +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- +import pytest +import pytest_asyncio +from typetest.union.aio import UnionClient +from typetest.union import models + + +@pytest_asyncio.fixture +async def client(): + async with UnionClient() as client: + yield client + + +@pytest.mark.asyncio +async def test_enums_only(client: UnionClient): + value = models.EnumsOnlyCases(lr="right", ud="up") + assert (await client.enums_only.get()) == {"prop": value} + await client.enums_only.send(prop=value) + + +@pytest.mark.asyncio +async def test_floats_only(client: UnionClient): + value = 2.2 + assert (await client.floats_only.get()) == {"prop": value} + await client.floats_only.send(prop=value) + + +@pytest.mark.asyncio +async def test_ints_only(client: UnionClient): + value = 2 + assert (await client.ints_only.get()) == {"prop": value} + await client.ints_only.send(prop=value) + + +@pytest.mark.asyncio +async def test_mixed_literals(client: UnionClient): + value = models.MixedLiteralsCases(string_literal="a", int_literal=2, float_literal=3.3, boolean_literal=True) + assert (await client.mixed_literals.get()) == {"prop": value} + await client.mixed_literals.send(prop=value) + + +@pytest.mark.asyncio +async def test_mixed_types(client: UnionClient): + value = models.MixedTypesCases( + model=models.Cat(name="test"), + literal="a", + int_property=2, + boolean=True, + array=[models.Cat(name="test"), "a", 2, True], + ) + assert (await client.mixed_types.get()) == {"prop": value} + await client.mixed_types.send(prop=value) + + +@pytest.mark.asyncio +async def test_models_only(client: UnionClient): + value = models.Cat(name="test") + assert (await client.models_only.get()) == {"prop": value} + await client.models_only.send(prop=value) + + +@pytest.mark.asyncio +async def test_string_and_array(client: UnionClient): + value = models.StringAndArrayCases(string="test", array=["test1", "test2"]) + assert (await client.string_and_array.get()) == {"prop": value} + await client.string_and_array.send(prop=value) + + +@pytest.mark.asyncio +async def test_string_extensible(client: UnionClient): + value = "custom" + assert (await client.string_extensible.get()) == {"prop": value} + await client.string_extensible.send(prop=value) + + +@pytest.mark.asyncio +async def test_string_extensible_named(client: UnionClient): + value = "custom" + assert (await client.string_extensible_named.get()) == {"prop": value} + await client.string_extensible_named.send(prop=value) + + +@pytest.mark.asyncio +async def test_strings_only(client: UnionClient): + value = "b" + assert (await client.strings_only.get()) == {"prop": value} + await client.strings_only.send(prop=value) diff --git a/packages/typespec-python/tests/mock_api/shared/asynctests/test_versioning_added_async.py b/packages/typespec-python/tests/mock_api/shared/asynctests/test_versioning_added_async.py new file mode 100644 index 0000000000..8906113b96 --- /dev/null +++ b/packages/typespec-python/tests/mock_api/shared/asynctests/test_versioning_added_async.py @@ -0,0 +1,37 @@ +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- +import pytest +import pytest_asyncio +from versioning.added.aio import AddedClient +from versioning.added.models import ModelV1, ModelV2, EnumV1, EnumV2 + + +@pytest_asyncio.fixture +async def client(): + async with AddedClient(endpoint="http://localhost:3000", version="v2") as client: + yield client + + +@pytest.mark.asyncio +async def test_v1(client: AddedClient): + assert await client.v1( + ModelV1(prop="foo", enum_prop=EnumV1.ENUM_MEMBER_V2, union_prop=10), + header_v2="bar", + ) == ModelV1(prop="foo", enum_prop=EnumV1.ENUM_MEMBER_V2, union_prop=10) + + +@pytest.mark.asyncio +async def test_v2(client: AddedClient): + assert await client.v2(ModelV2(prop="foo", enum_prop=EnumV2.ENUM_MEMBER, union_prop="bar")) == ModelV2( + prop="foo", enum_prop=EnumV2.ENUM_MEMBER, union_prop="bar" + ) + + +@pytest.mark.asyncio +async def test_interface_v2(client: AddedClient): + assert await client.interface_v2.v2_in_interface( + ModelV2(prop="foo", enum_prop=EnumV2.ENUM_MEMBER, union_prop="bar") + ) == ModelV2(prop="foo", enum_prop=EnumV2.ENUM_MEMBER, union_prop="bar") diff --git a/packages/typespec-python/tests/mock_api/shared/asynctests/test_versioning_made_optional_async.py b/packages/typespec-python/tests/mock_api/shared/asynctests/test_versioning_made_optional_async.py new file mode 100644 index 0000000000..c126d40116 --- /dev/null +++ b/packages/typespec-python/tests/mock_api/shared/asynctests/test_versioning_made_optional_async.py @@ -0,0 +1,22 @@ +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- +import pytest +import pytest_asyncio +from versioning.madeoptional.aio import MadeOptionalClient +from versioning.madeoptional.models import TestModel + + +@pytest_asyncio.fixture +async def client(): + async with MadeOptionalClient(endpoint="http://localhost:3000", version="v2") as client: + yield client + + +@pytest.mark.asyncio +async def test(client: MadeOptionalClient): + assert await client.test( + TestModel(prop="foo"), + ) == TestModel(prop="foo") diff --git a/packages/typespec-python/tests/mock_api/shared/asynctests/test_versioning_removed_async.py b/packages/typespec-python/tests/mock_api/shared/asynctests/test_versioning_removed_async.py new file mode 100644 index 0000000000..22dab517fd --- /dev/null +++ b/packages/typespec-python/tests/mock_api/shared/asynctests/test_versioning_removed_async.py @@ -0,0 +1,40 @@ +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- +import pytest +import pytest_asyncio +from versioning.removed.aio import RemovedClient +from versioning.removed.models import ModelV2, EnumV2, ModelV3, EnumV3 + + +@pytest_asyncio.fixture +async def client(): + async with RemovedClient(endpoint="http://localhost:3000", version="v2") as client: + yield client + + +@pytest.mark.asyncio +async def test_v2(client: RemovedClient): + assert await client.v2(ModelV2(prop="foo", enum_prop=EnumV2.ENUM_MEMBER_V2, union_prop="bar")) == ModelV2( + prop="foo", enum_prop=EnumV2.ENUM_MEMBER_V2, union_prop="bar" + ) + + +@pytest.mark.asyncio +async def test_model_v3(): + async with RemovedClient(endpoint="http://localhost:3000", version="v1") as client1: + model1 = ModelV3(id="123", enum_prop=EnumV3.ENUM_MEMBER_V1) + result = await client1.model_v3(model1) + assert result == model1 + + async with RemovedClient(endpoint="http://localhost:3000", version="v2preview") as client2: + model2 = ModelV3(id="123") + result = await client2.model_v3(model2) + assert result == model2 + + async with RemovedClient(endpoint="http://localhost:3000", version="v2") as client3: + model3 = ModelV3(id="123", enum_prop=EnumV3.ENUM_MEMBER_V1) + result = await client3.model_v3(model3) + assert result == model3 diff --git a/packages/typespec-python/tests/mock_api/shared/asynctests/test_versioning_renamed_from_async.py b/packages/typespec-python/tests/mock_api/shared/asynctests/test_versioning_renamed_from_async.py new file mode 100644 index 0000000000..1e738c2132 --- /dev/null +++ b/packages/typespec-python/tests/mock_api/shared/asynctests/test_versioning_renamed_from_async.py @@ -0,0 +1,30 @@ +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- +import pytest +import pytest_asyncio +from versioning.renamedfrom.aio import RenamedFromClient +from versioning.renamedfrom.models import NewModel, NewEnum + + +@pytest_asyncio.fixture +async def client(): + async with RenamedFromClient(endpoint="http://localhost:3000", version="v2") as client: + yield client + + +@pytest.mark.asyncio +async def test_new_op(client: RenamedFromClient): + assert await client.new_op( + NewModel(new_prop="foo", enum_prop=NewEnum.NEW_ENUM_MEMBER, union_prop=10), + new_query="bar", + ) == NewModel(new_prop="foo", enum_prop=NewEnum.NEW_ENUM_MEMBER, union_prop=10) + + +@pytest.mark.asyncio +async def test_new_interface_test(client: RenamedFromClient): + assert await client.new_interface.new_op_in_new_interface( + NewModel(new_prop="foo", enum_prop=NewEnum.NEW_ENUM_MEMBER, union_prop=10) + ) == NewModel(new_prop="foo", enum_prop=NewEnum.NEW_ENUM_MEMBER, union_prop=10) diff --git a/packages/typespec-python/tests/mock_api/shared/asynctests/test_versioning_return_type_changed_from_async.py b/packages/typespec-python/tests/mock_api/shared/asynctests/test_versioning_return_type_changed_from_async.py new file mode 100644 index 0000000000..e6234f6960 --- /dev/null +++ b/packages/typespec-python/tests/mock_api/shared/asynctests/test_versioning_return_type_changed_from_async.py @@ -0,0 +1,19 @@ +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- +import pytest +import pytest_asyncio +from versioning.returntypechangedfrom.aio import ReturnTypeChangedFromClient + + +@pytest_asyncio.fixture +async def client(): + async with ReturnTypeChangedFromClient(endpoint="http://localhost:3000", version="v2") as client: + yield client + + +@pytest.mark.asyncio +async def test(client: ReturnTypeChangedFromClient): + assert await client.test("test") == "test" diff --git a/packages/typespec-python/tests/mock_api/shared/asynctests/test_versioning_type_changed_from_async.py b/packages/typespec-python/tests/mock_api/shared/asynctests/test_versioning_type_changed_from_async.py new file mode 100644 index 0000000000..6bf75a87be --- /dev/null +++ b/packages/typespec-python/tests/mock_api/shared/asynctests/test_versioning_type_changed_from_async.py @@ -0,0 +1,23 @@ +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- +import pytest +import pytest_asyncio +from versioning.typechangedfrom.aio import TypeChangedFromClient +from versioning.typechangedfrom.models import TestModel + + +@pytest_asyncio.fixture +async def client(): + async with TypeChangedFromClient(endpoint="http://localhost:3000", version="v2") as client: + yield client + + +@pytest.mark.asyncio +async def test(client: TypeChangedFromClient): + assert await client.test( + TestModel(prop="foo", changed_prop="bar"), + param="baz", + ) == TestModel(prop="foo", changed_prop="bar") diff --git a/packages/typespec-python/tests/mock_api/shared/conftest.py b/packages/typespec-python/tests/mock_api/shared/conftest.py new file mode 100644 index 0000000000..0f5685c338 --- /dev/null +++ b/packages/typespec-python/tests/mock_api/shared/conftest.py @@ -0,0 +1,43 @@ +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- +import pytest +import importlib +from pathlib import Path + +DATA_FOLDER = Path(__file__).parent.parent + + +""" +Use to disambiguate the core library we use +""" + + +@pytest.fixture +def core_library(): + try: + return importlib.import_module("azure.core") + except ModuleNotFoundError: + return importlib.import_module("corehttp") + + +@pytest.fixture +def key_credential(core_library): + try: + return core_library.credentials.AzureKeyCredential + except AttributeError: + return core_library.credentials.ServiceKeyCredential + + +@pytest.fixture +def png_data() -> bytes: + with open(str(DATA_FOLDER / "data/image.png"), "rb") as file_in: + return file_in.read() + + +@pytest.fixture +def jpg_data() -> bytes: + with open(str(DATA_FOLDER / "data/image.jpg"), "rb") as file_in: + return file_in.read() diff --git a/packages/typespec-python/tests/mock_api/shared/data/image.jpg b/packages/typespec-python/tests/mock_api/shared/data/image.jpg new file mode 100644 index 0000000000000000000000000000000000000000..b95b3e7b58286ad3e665d98d48b345977f862403 GIT binary patch literal 4069 zcmeHJX;@QN8a_8Gn*#{~QJ4uNv1G6$BrHN6AVrn}mbL^3a4V7!OhA&51QRm!5kx@+ zTNcGZ6cC$Q+;~`GASla}wUxz{#c@GKXr)k4Y@<*!Hx%*D{OB`(hxgoj&v(xGzVDv* zyZ1cLYZx{>23FxAVIcs504RVPFpPlD9#xbBu1V2)YXM|gXB#0R#?0;vho@Ai`n{4K2Z_tc-vVNE8}_H8C|ahaEIl00AM92ow^HM!{MR`W#*d zC>$E^#0bDxN5*4GscV^8g=bC3n`_%`I5%f0?p)~sQ!`sT!n*Yv-gBn@)y2cpYm>JR zD=;WH4t_4#kAFVxjHXs&7-n{@yDwxhGFyQlZNTet7ry*D&GGCKBT{NGO}CV%+x+1&FN z^Dlq-RsZU>kryl_f2RdM|0^#X%nN}+AyHT(F9@M9633y?P7Dk_AQBs&YE5EhnXKJh zc(%6PlpPs~<`z2kKs1OmhoPzVGH-Zu)3MZ>_F zVvR60H(i4HGS)1?$_V@l3~&{b9rK09ND}!zi#oLh#Ro!~r%~ ztf@M>v0>6|AHFNXRdW{F2PwyE*zd{a+%36uhi4yu9aJ^ zpE7`9t8Rioz2KlN=S`ybbp-7ElQg->VN&I!l@n$S;9H_)yZXl$&PTX9ZObWvjhcE$f>gQt?~wSk)wt*@QfJ9e zFelD#>m0AB_sUj(c%Hr(E_yV;phB&=i9g9-)lO~OzQ2==_`u&bT{~<52lxK#Ow_NO zH{&-1-x&aQ;LQ0M(Zy$<1nTsq)xvVR{*&=ztX;IOz6|@z-F$Uf=(W0nyex6{P>FpW z4;0_dipualIew@$bH3M?aaJh~zSVba_s(ZYwY`7uX0rQ=C{sn1g*}wrL&Zt0cwal& z|(+)A&#XhLRoSPH3mt4Ji?-$~1F~yma)AnXu zRaaV$2SjEq$b{PVCY+v+iL;w8BOWVxgqdDst2gCLzog0=vM#q5L^ScNF_ipEjeb6n z1J0h4Y=S>iPa2P#Wgqq@^xWzm>-n^78z*$sXAucKo}EO|0uu3 zLs)^AUypvJF<+QUj|p5L&+NFzk0eJN%fi)?Gy8fd4jBz;gBAkjn_MPYks`G3a33&nP_o zg=l|nT>VF<@}|PZtIypU-TXbb#NA#UwTKA877jAo-sRoA;|O7M!oq~_ndaKA)cm{QH_jPuzCA+J zs!aHNWSYHBYfaj3>w14Gdb?$=t7cDh+;r%rP@Vlr;qGatS1nE0#?Fk+V2@G6gWq0G nRDbTJ{wDPH&YhvRw~$ZQH=nuD@w!Nwq+ZJbRY$2v!^nRCgjEVM literal 0 HcmV?d00001 diff --git a/packages/typespec-python/tests/mock_api/shared/data/image.png b/packages/typespec-python/tests/mock_api/shared/data/image.png new file mode 100644 index 0000000000000000000000000000000000000000..42fe8dc14560b0046bf0f3f00b7a471fa0346e36 GIT binary patch literal 2992 zcmaJ>2UJtr5=}ynfPe^6#i)oP2~A3b_#j9P<c=;9z@urf$wEd&r0Smmc~ z4b}n)eX~PAprkO6@Q)ZL0M}MJAZwiOD16}zNDSD?0g_k*{=o$NMUbCNY?07U9S+2S zEZop`b^yBJDZ#-+YAA`O;C(9uFi4PXy{I6N!uB-*+qrI=1#0z#xnpTqM+_2ABESQJ zNP)p{I)S{F2V_P^0xBVx7N9{V941ncbaU9Z2qd7dnGrCJZy~e@a~RgqMFUNu1Zx<< zb>X@&6jVb)!;BJi2rs64KWLg-BsIiteAdnPEGl#*}3jJK)-!qsV_Nx++`r}x@ z0TF8+gdSWM@iR9-HCwYHUBc+WhrO)A2tdz(8Yn{}vv1-5tZHzM{I(Zu9;;%|=s zCVEhVDQFS_C`d#7x~w1M-<>~*W{9LqLSH=UG`#0SvISvT&z^Cv#7@xJSx2aa-|9tm}-z6Hc>u#KDm+I4F>M3G9RmW+_?M2)1;gWo3xcVR@W8PHPH4h8*{++h z8}Y5F9`(=WPeZXH<+|Y0gJnwP5YL?0zo!3|^aN{T{s{OKE?O45QM0I0;1yDN`SND{ zyOg5mp)N5c(u0Esp-E=kfllR0C&k1s@i0GrZRfs5<7!+x0s^%ugM8%*ef;#PiEVR~ zk~180fRXw!|2qMhFy2QQNA)X#rKKLKFql@YS0DB+8Y~M0L6l6MBxAd5adGjcF9c8t zo3^yHG!i%{(t~?+_KjG%t?wg9W@hGn@>d^2zlX4eDsq69+{GOYhow*ZZ9YFY+;qgj z#AWZ^z2xho`YaYJ$mptuez>fhT&9eIf;49^mEC)&XN9ajcTsqPhD7C%d`TOUID=@6 zW~%vaGf31w{D~F5LO*H9Ul5b;M$_L~@5Rf{$YXmij@GSqZ($ztNsv;Z`i@;wgI)yL z`tVD3-D4YatT^h!2`{f7xgFBk(KVv6D=iyOe>q)Zxtu3f1vhZeoRRfQZ3s>DQ~|{c zhLZ7j^pqm{@Kbe|+)KiSAs)dZlW4Rb|0>x!mf7eaT?yRGZFm;h)5lP}0s z)MR+lRu=;7XofSxFZS5kB(Io?U<4$)=j+Ujv-f1z7}jT(U8oBF@c2?YjHZlX3}y?2 zB}I!j)%5LcxOt457x{YKwWQLqjkl*P!m*TD-H`cTuN{_G`e(Occ-dLa=;vA%@*AOg(a(z}6t_crT&EO-&+m4gF>N0h;BXG0?{Bi7 z`CMs0?IQEIN_yrvkTId}4tcQlLFDsm2){A5T)eb!$m;U*9bpNnS{u9Nur=c6{IY zKC28T*@~?E=+fvG1A<0jF;cm0Q(bSl;8d`tTUme#<>4g zLGy3~(+z4auzTu_$wj7=5_bmr4M3i>XprZ8-8A{ z^S%T(i(@^t7G<(wYTc~P^uFuDm}iOCg0RJbylL{6l)E9&xd*ipG|e`)b?b`n)|`3$ z>k`idS@_lp+*>nk7_W2qvLHrYsnN9VjcdkaYxRqWdf5!mZ8vsD^2e%lG>7`oaP1~( z91eF(@?7&4^jE^(0w>-(Xig#TL8J;KX+2YL&fdmGjCA1!I<+uYch0=ri`kM?G=Uz= zYe(%m$g6gpfYRA}M3Wh=PjV`BA|f`Ajz1QY-KfS$+mLC&=*M@CqU0@-843#@s!tp+ z`hXG_$T+w$%ZRc;oA!hozBo{U_AgR)cc2=ist%Tf1!goyZ`H}XSr9&UY zJ^9hCDY9E_U|L$j^3{t+O$rDP^WqxkQ)&F;Eh@Hsx^<};S#~>%t}R_YRkG7OjOT7s&BTd5F;H{&a{d!BS5Vz@RgwkT{dwhcQ zPGno6OlTdu0KU{d<)>5lyi9d5Rz$1ros^mpW_coXd{r;;5w~?!YUHbE$=hL2`F`si x55d?S>E1-idha0G3zgVNNXgr$|KG8qZJn`L2pQ~%2Sy6WZoiY&ZA<_7e*r@k8!Z3; literal 0 HcmV?d00001 diff --git a/packages/typespec-python/tests/mock_api/shared/test_authentication.py b/packages/typespec-python/tests/mock_api/shared/test_authentication.py new file mode 100644 index 0000000000..aaa000a85c --- /dev/null +++ b/packages/typespec-python/tests/mock_api/shared/test_authentication.py @@ -0,0 +1,130 @@ +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- +import pytest +from authentication.apikey import ApiKeyClient +from authentication.oauth2 import OAuth2Client +from authentication.union import UnionClient +from setuppy.authentication.union import UnionClient as SetuppyUnionClient +from authentication.noauth.union import UnionClient as NoauthUnionClient +from authentication.http.custom import CustomClient + +# Utilities functions + + +@pytest.fixture +def api_key_client(key_credential): + client = None + + def _build_client(client_type, key: str = "valid-key"): + client = client_type(key_credential(key)) + return client + + yield _build_client + if client: + client.close() + + +@pytest.fixture +def token_credential(core_library): + class FakeCredential: + @staticmethod + def get_token(*scopes): + return core_library.credentials.AccessToken(token="".join(scopes), expires_on=1800) + + @staticmethod + def get_token_info(*scopes, **kwargs): + return core_library.credentials.AccessTokenInfo(token="".join(scopes), expires_on=1800) + + return FakeCredential() + + +@pytest.fixture +def oauth2_client(token_credential): + client = None + + def _build_client(client_type): + client = client_type(token_credential) + return client + + yield _build_client + if client: + client.close() + + +@pytest.fixture +def http_custom_client(key_credential): + client = None + + def _build_client(key: str = "valid-key"): + client = CustomClient(key_credential(key)) + return client + + yield _build_client + if client: + client.close() + + +# Tests + + +def test_api_key_valid(api_key_client): + client = api_key_client(ApiKeyClient) + client.valid() + + +def test_api_key_invalid(api_key_client, core_library): + client = api_key_client(ApiKeyClient, "invalid-key") + with pytest.raises(core_library.exceptions.HttpResponseError) as ex: + client.invalid() + assert ex.value.status_code == 403 + assert ex.value.reason == "Forbidden" + + +def test_oauth2_valid(oauth2_client): + client = oauth2_client(OAuth2Client) + client.valid(enforce_https=False) + + +def test_oauth2_invalid(oauth2_client, core_library): + client = oauth2_client(OAuth2Client) + with pytest.raises(core_library.exceptions.HttpResponseError) as ex: + client.invalid(enforce_https=False) + assert ex.value.status_code == 403 + + +@pytest.mark.parametrize("union_client_type", [UnionClient, SetuppyUnionClient]) +def test_union_keyvalid(api_key_client, union_client_type): + client = api_key_client(union_client_type) + client.valid_key() + + +@pytest.mark.parametrize("union_client_type", [UnionClient, SetuppyUnionClient]) +def test_union_tokenvalid(oauth2_client, union_client_type): + client = oauth2_client(union_client_type) + client.valid_token(enforce_https=False) + + +def test_noauth_union_valid_no_auth(): + client = NoauthUnionClient() + client.valid_no_auth() + + +def test_noauth_union_valid_token(oauth2_client): + client = oauth2_client(NoauthUnionClient) + client.valid_token(enforce_https=False) + + +def test_http_custom_valid(http_custom_client): + client = http_custom_client() + client.valid() + + +def test_http_custom_invalid(http_custom_client, core_library): + client = http_custom_client("invalid-key") + with pytest.raises(core_library.exceptions.HttpResponseError) as ex: + client.invalid() + assert ex.value.status_code == 403 + assert ex.value.reason == "Forbidden" diff --git a/packages/typespec-python/tests/mock_api/shared/test_encode_array.py b/packages/typespec-python/tests/mock_api/shared/test_encode_array.py new file mode 100644 index 0000000000..a09a05a793 --- /dev/null +++ b/packages/typespec-python/tests/mock_api/shared/test_encode_array.py @@ -0,0 +1,126 @@ +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- + +import pytest +from encode.array import ArrayClient, models + + +@pytest.fixture +def client(): + with ArrayClient() as client: + yield client + + +def test_comma_delimited(client: ArrayClient): + body = models.CommaDelimitedArrayProperty(value=["blue", "red", "green"]) + result = client.property.comma_delimited(body) + assert result.value == ["blue", "red", "green"] + + +def test_space_delimited(client: ArrayClient): + body = models.SpaceDelimitedArrayProperty(value=["blue", "red", "green"]) + result = client.property.space_delimited(body) + assert result.value == ["blue", "red", "green"] + + +def test_pipe_delimited(client: ArrayClient): + body = models.PipeDelimitedArrayProperty(value=["blue", "red", "green"]) + result = client.property.pipe_delimited(body) + assert result.value == ["blue", "red", "green"] + + +def test_newline_delimited(client: ArrayClient): + body = models.NewlineDelimitedArrayProperty(value=["blue", "red", "green"]) + result = client.property.newline_delimited(body) + assert result.value == ["blue", "red", "green"] + + +def test_enum_comma_delimited(client: ArrayClient): + body = models.CommaDelimitedEnumArrayProperty(value=[models.Colors.BLUE, models.Colors.RED, models.Colors.GREEN]) + result = client.property.enum_comma_delimited(body) + assert result.value == [models.Colors.BLUE, models.Colors.RED, models.Colors.GREEN] + + +def test_enum_space_delimited(client: ArrayClient): + body = models.SpaceDelimitedEnumArrayProperty(value=[models.Colors.BLUE, models.Colors.RED, models.Colors.GREEN]) + result = client.property.enum_space_delimited(body) + assert result.value == [models.Colors.BLUE, models.Colors.RED, models.Colors.GREEN] + + +def test_enum_pipe_delimited(client: ArrayClient): + body = models.PipeDelimitedEnumArrayProperty(value=[models.Colors.BLUE, models.Colors.RED, models.Colors.GREEN]) + result = client.property.enum_pipe_delimited(body) + assert result.value == [models.Colors.BLUE, models.Colors.RED, models.Colors.GREEN] + + +def test_enum_newline_delimited(client: ArrayClient): + body = models.NewlineDelimitedEnumArrayProperty(value=[models.Colors.BLUE, models.Colors.RED, models.Colors.GREEN]) + result = client.property.enum_newline_delimited(body) + assert result.value == [models.Colors.BLUE, models.Colors.RED, models.Colors.GREEN] + + +def test_extensible_enum_comma_delimited(client: ArrayClient): + body = models.CommaDelimitedExtensibleEnumArrayProperty( + value=[ + models.ColorsExtensibleEnum.BLUE, + models.ColorsExtensibleEnum.RED, + models.ColorsExtensibleEnum.GREEN, + ] + ) + result = client.property.extensible_enum_comma_delimited(body) + assert result.value == [ + models.ColorsExtensibleEnum.BLUE, + models.ColorsExtensibleEnum.RED, + models.ColorsExtensibleEnum.GREEN, + ] + + +def test_extensible_enum_space_delimited(client: ArrayClient): + body = models.SpaceDelimitedExtensibleEnumArrayProperty( + value=[ + models.ColorsExtensibleEnum.BLUE, + models.ColorsExtensibleEnum.RED, + models.ColorsExtensibleEnum.GREEN, + ] + ) + result = client.property.extensible_enum_space_delimited(body) + assert result.value == [ + models.ColorsExtensibleEnum.BLUE, + models.ColorsExtensibleEnum.RED, + models.ColorsExtensibleEnum.GREEN, + ] + + +def test_extensible_enum_pipe_delimited(client: ArrayClient): + body = models.PipeDelimitedExtensibleEnumArrayProperty( + value=[ + models.ColorsExtensibleEnum.BLUE, + models.ColorsExtensibleEnum.RED, + models.ColorsExtensibleEnum.GREEN, + ] + ) + result = client.property.extensible_enum_pipe_delimited(body) + assert result.value == [ + models.ColorsExtensibleEnum.BLUE, + models.ColorsExtensibleEnum.RED, + models.ColorsExtensibleEnum.GREEN, + ] + + +def test_extensible_enum_newline_delimited(client: ArrayClient): + body = models.NewlineDelimitedExtensibleEnumArrayProperty( + value=[ + models.ColorsExtensibleEnum.BLUE, + models.ColorsExtensibleEnum.RED, + models.ColorsExtensibleEnum.GREEN, + ] + ) + result = client.property.extensible_enum_newline_delimited(body) + assert result.value == [ + models.ColorsExtensibleEnum.BLUE, + models.ColorsExtensibleEnum.RED, + models.ColorsExtensibleEnum.GREEN, + ] diff --git a/packages/typespec-python/tests/mock_api/shared/test_encode_bytes.py b/packages/typespec-python/tests/mock_api/shared/test_encode_bytes.py new file mode 100644 index 0000000000..2ca75a22c3 --- /dev/null +++ b/packages/typespec-python/tests/mock_api/shared/test_encode_bytes.py @@ -0,0 +1,128 @@ +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- +from pathlib import Path + +import pytest +from encode.bytes import BytesClient +from encode.bytes.models import ( + DefaultBytesProperty, + Base64urlBytesProperty, + Base64BytesProperty, + Base64urlArrayBytesProperty, +) + +FILE_FOLDER = Path(__file__).parent + + +@pytest.fixture +def client(): + with BytesClient() as client: + yield client + + +def test_query(client: BytesClient): + client.query.default( + value=bytes("test", "utf-8"), + ) + client.query.base64( + value=bytes("test", "utf-8"), + ) + client.query.base64_url( + value=bytes("test", "utf-8"), + ) + client.query.base64_url_array( + value=[ + bytes("test", "utf-8"), + bytes("test", "utf-8"), + ], + ) + + +def test_property(client: BytesClient): + result = client.property.default( + DefaultBytesProperty( + value=bytes("test", "utf-8"), + ) + ) + assert result.value == bytes("test", "utf-8") + + result = client.property.base64( + Base64BytesProperty( + value=bytes("test", "utf-8"), + ) + ) + assert result.value == bytes("test", "utf-8") + + result = client.property.base64_url( + Base64urlBytesProperty( + value=bytes("test", "utf-8"), + ) + ) + assert result.value == bytes("test", "utf-8") + + result = client.property.base64_url_array( + Base64urlArrayBytesProperty( + value=[ + bytes("test", "utf-8"), + bytes("test", "utf-8"), + ], + ) + ) + assert result.value == [ + bytes("test", "utf-8"), + bytes("test", "utf-8"), + ] + + +def test_header(client: BytesClient): + client.header.default( + value=bytes("test", "utf-8"), + ) + client.header.base64( + value=bytes("test", "utf-8"), + ) + client.header.base64_url( + value=bytes("test", "utf-8"), + ) + client.header.base64_url_array( + value=[ + bytes("test", "utf-8"), + bytes("test", "utf-8"), + ], + ) + + +@pytest.fixture +def png_data() -> bytes: + with open(str(FILE_FOLDER / "data/image.png"), "rb") as file_in: + return file_in.read() + + +def test_request_body(client: BytesClient, png_data: bytes): + client.request_body.default( + value=png_data, + ) + client.request_body.octet_stream( + value=png_data, + ) + client.request_body.custom_content_type( + value=png_data, + ) + client.request_body.base64( + value=bytes("test", "utf-8"), + ) + client.request_body.base64_url( + value=bytes("test", "utf-8"), + ) + + +def test_response_body(client: BytesClient, png_data: bytes): + expected = b"test" + assert b"".join(client.response_body.default()) == png_data + assert expected == client.response_body.base64() + assert b"".join(client.response_body.octet_stream()) == png_data + assert b"".join(client.response_body.custom_content_type()) == png_data + assert expected == client.response_body.base64_url() diff --git a/packages/typespec-python/tests/mock_api/shared/test_encode_datetime.py b/packages/typespec-python/tests/mock_api/shared/test_encode_datetime.py new file mode 100644 index 0000000000..46b32f9734 --- /dev/null +++ b/packages/typespec-python/tests/mock_api/shared/test_encode_datetime.py @@ -0,0 +1,123 @@ +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- +import datetime + +import pytest +from encode.datetime import DatetimeClient +from encode.datetime.models import ( + DefaultDatetimeProperty, + Rfc3339DatetimeProperty, + Rfc7231DatetimeProperty, + UnixTimestampDatetimeProperty, + UnixTimestampArrayDatetimeProperty, +) + + +@pytest.fixture +def client(): + with DatetimeClient() as client: + yield client + + +def test_query(client: DatetimeClient): + client.query.default( + value=datetime.datetime(2022, 8, 26, 18, 38, 0, tzinfo=datetime.timezone.utc), + ) + client.query.rfc3339( + value=datetime.datetime(2022, 8, 26, 18, 38, 0, tzinfo=datetime.timezone.utc), + ) + client.query.rfc7231( + value=datetime.datetime(2022, 8, 26, 14, 38, 0, tzinfo=datetime.timezone.utc), + ) + client.query.unix_timestamp( + value=datetime.datetime(2023, 6, 12, 10, 47, 44, tzinfo=datetime.timezone.utc), + ) + client.query.unix_timestamp_array( + value=[ + datetime.datetime(2023, 6, 12, 10, 47, 44, tzinfo=datetime.timezone.utc), + datetime.datetime(2023, 6, 14, 9, 17, 36, tzinfo=datetime.timezone.utc), + ], + ) + + +def test_property(client: DatetimeClient): + result = client.property.default( + DefaultDatetimeProperty( + value=datetime.datetime(2022, 8, 26, 18, 38, 0, tzinfo=datetime.timezone.utc), + ) + ) + assert result.value == datetime.datetime(2022, 8, 26, 18, 38, 0, tzinfo=datetime.timezone.utc) + + result = client.property.rfc3339( + Rfc3339DatetimeProperty( + value=datetime.datetime(2022, 8, 26, 18, 38, 0, tzinfo=datetime.timezone.utc), + ) + ) + assert result.value == datetime.datetime(2022, 8, 26, 18, 38, 0, tzinfo=datetime.timezone.utc) + + result = client.property.rfc7231( + Rfc7231DatetimeProperty( + value=datetime.datetime(2022, 8, 26, 14, 38, 0, tzinfo=datetime.timezone.utc), + ) + ) + assert result.value == datetime.datetime(2022, 8, 26, 14, 38, 0, tzinfo=datetime.timezone.utc) + + result = client.property.unix_timestamp( + UnixTimestampDatetimeProperty( + value=datetime.datetime(2023, 6, 12, 10, 47, 44, tzinfo=datetime.timezone.utc), + ) + ) + assert result.value == datetime.datetime(2023, 6, 12, 10, 47, 44, tzinfo=datetime.timezone.utc) + + result = client.property.unix_timestamp_array( + UnixTimestampArrayDatetimeProperty( + value=[ + datetime.datetime(2023, 6, 12, 10, 47, 44, tzinfo=datetime.timezone.utc), + datetime.datetime(2023, 6, 14, 9, 17, 36, tzinfo=datetime.timezone.utc), + ], + ) + ) + assert result.value == [ + datetime.datetime(2023, 6, 12, 10, 47, 44, tzinfo=datetime.timezone.utc), + datetime.datetime(2023, 6, 14, 9, 17, 36, tzinfo=datetime.timezone.utc), + ] + + +def test_header(client: DatetimeClient): + client.header.default( + value=datetime.datetime(2022, 8, 26, 14, 38, 0, tzinfo=datetime.timezone.utc), + ) + client.header.rfc3339( + value=datetime.datetime(2022, 8, 26, 18, 38, 0, tzinfo=datetime.timezone.utc), + ) + client.header.rfc7231( + value=datetime.datetime(2022, 8, 26, 14, 38, 0, tzinfo=datetime.timezone.utc), + ) + client.header.unix_timestamp( + value=datetime.datetime(2023, 6, 12, 10, 47, 44, tzinfo=datetime.timezone.utc), + ) + client.header.unix_timestamp_array( + value=[ + datetime.datetime(2023, 6, 12, 10, 47, 44, tzinfo=datetime.timezone.utc), + datetime.datetime(2023, 6, 14, 9, 17, 36, tzinfo=datetime.timezone.utc), + ] + ) + + +def test_response_header(client: DatetimeClient): + cls = lambda x, y, z: z + assert client.response_header.default(cls=cls)["value"] == datetime.datetime( + 2022, 8, 26, 14, 38, 0, tzinfo=datetime.timezone.utc + ) + assert client.response_header.rfc3339(cls=cls)["value"] == datetime.datetime( + 2022, 8, 26, 18, 38, 0, tzinfo=datetime.timezone.utc + ) + assert client.response_header.rfc7231(cls=cls)["value"] == datetime.datetime( + 2022, 8, 26, 14, 38, 0, tzinfo=datetime.timezone.utc + ) + assert client.response_header.unix_timestamp(cls=cls)["value"] == datetime.datetime( + 2023, 6, 12, 10, 47, 44, tzinfo=datetime.timezone.utc + ) diff --git a/packages/typespec-python/tests/mock_api/shared/test_generation_subdir2_for_customized_code.py b/packages/typespec-python/tests/mock_api/shared/test_generation_subdir2_for_customized_code.py new file mode 100644 index 0000000000..9a90f290d3 --- /dev/null +++ b/packages/typespec-python/tests/mock_api/shared/test_generation_subdir2_for_customized_code.py @@ -0,0 +1,32 @@ +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- +import pytest +from generation.subdir2 import AddedClient, ModelV1, ModelV2, EnumV1, EnumV2 + + +@pytest.fixture +def client(): + with AddedClient(endpoint="http://localhost:3000", version="v2") as client: + yield client + + +def test_v1(client: AddedClient): + assert client.v1( + ModelV1(prop="foo", enum_prop=EnumV1.ENUM_MEMBER_V2, union_prop=10), + header_v2="bar", + ) == ModelV1(prop="foo", enum_prop=EnumV1.ENUM_MEMBER_V2, union_prop=10) + + +def test_v2(client: AddedClient): + assert client.v2(ModelV2(prop="foo", enum_prop=EnumV2.ENUM_MEMBER, union_prop="bar")) == ModelV2( + prop="foo", enum_prop=EnumV2.ENUM_MEMBER, union_prop="bar" + ) + + +def test_interface_v2(client: AddedClient): + assert client.interface_v2.v2_in_interface( + ModelV2(prop="foo", enum_prop=EnumV2.ENUM_MEMBER, union_prop="bar") + ) == ModelV2(prop="foo", enum_prop=EnumV2.ENUM_MEMBER, union_prop="bar") diff --git a/packages/typespec-python/tests/mock_api/shared/test_generation_subdir2_for_generated_code.py b/packages/typespec-python/tests/mock_api/shared/test_generation_subdir2_for_generated_code.py new file mode 100644 index 0000000000..32bbfc784d --- /dev/null +++ b/packages/typespec-python/tests/mock_api/shared/test_generation_subdir2_for_generated_code.py @@ -0,0 +1,33 @@ +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- +import pytest +from generation.subdir2._generated import AddedClient +from generation.subdir2._generated.models import ModelV1, ModelV2, EnumV1, EnumV2 + + +@pytest.fixture +def client(): + with AddedClient(endpoint="http://localhost:3000", version="v2") as client: + yield client + + +def test_v1(client: AddedClient): + assert client.v1( + ModelV1(prop="foo", enum_prop=EnumV1.ENUM_MEMBER_V2, union_prop=10), + header_v2="bar", + ) == ModelV1(prop="foo", enum_prop=EnumV1.ENUM_MEMBER_V2, union_prop=10) + + +def test_v2(client: AddedClient): + assert client.v2(ModelV2(prop="foo", enum_prop=EnumV2.ENUM_MEMBER, union_prop="bar")) == ModelV2( + prop="foo", enum_prop=EnumV2.ENUM_MEMBER, union_prop="bar" + ) + + +def test_interface_v2(client: AddedClient): + assert client.interface_v2.v2_in_interface( + ModelV2(prop="foo", enum_prop=EnumV2.ENUM_MEMBER, union_prop="bar") + ) == ModelV2(prop="foo", enum_prop=EnumV2.ENUM_MEMBER, union_prop="bar") \ No newline at end of file diff --git a/packages/typespec-python/tests/mock_api/shared/test_generation_subdir_for_customized_code.py b/packages/typespec-python/tests/mock_api/shared/test_generation_subdir_for_customized_code.py new file mode 100644 index 0000000000..d2b7460818 --- /dev/null +++ b/packages/typespec-python/tests/mock_api/shared/test_generation_subdir_for_customized_code.py @@ -0,0 +1,16 @@ +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- +from generation.subdir import CustomizedClient, Extension + + +def test_custom_method(): + client = CustomizedClient() + assert client.customized_get() == Extension( + { + "level": 0, + "extension": [{"level": 1, "extension": [{"level": 2}]}, {"level": 1}], + } + ) diff --git a/packages/typespec-python/tests/mock_api/shared/test_generation_subdir_for_generated_code.py b/packages/typespec-python/tests/mock_api/shared/test_generation_subdir_for_generated_code.py new file mode 100644 index 0000000000..3750a98f1a --- /dev/null +++ b/packages/typespec-python/tests/mock_api/shared/test_generation_subdir_for_generated_code.py @@ -0,0 +1,17 @@ +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- +from generation.subdir._generated import RecursiveClient +from generation.subdir._generated.models import Extension + + +def test_custom_method(): + client = RecursiveClient() + assert client.get() == Extension( + { + "level": 0, + "extension": [{"level": 1, "extension": [{"level": 2}]}, {"level": 1}], + } + ) \ No newline at end of file diff --git a/packages/typespec-python/tests/mock_api/shared/test_headasboolean.py b/packages/typespec-python/tests/mock_api/shared/test_headasboolean.py new file mode 100644 index 0000000000..c26d63d39f --- /dev/null +++ b/packages/typespec-python/tests/mock_api/shared/test_headasboolean.py @@ -0,0 +1,33 @@ +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- +import pytest +from headasbooleantrue import VisibilityClient as HeadAsBooleanTrueClient +from headasbooleantrue import models as models_true + +from headasbooleanfalse import VisibilityClient as HeadAsBooleanFalseClient +from headasbooleanfalse import models as models_false + + +@pytest.fixture +def client_true(): + with HeadAsBooleanTrueClient() as client: + yield client + + +@pytest.fixture +def client_false(): + with HeadAsBooleanFalseClient() as client: + yield client + + +def test_head_true(client_true): + body = models_true.VisibilityModel() + assert client_true.head_model(body, query_prop=123) == True + + +def test_head_false(client_false): + body = models_false.VisibilityModel() + assert client_false.head_model(body, query_prop=123) is None diff --git a/packages/typespec-python/tests/mock_api/shared/test_parameters_body_optionality.py b/packages/typespec-python/tests/mock_api/shared/test_parameters_body_optionality.py new file mode 100644 index 0000000000..66ea0a9fea --- /dev/null +++ b/packages/typespec-python/tests/mock_api/shared/test_parameters_body_optionality.py @@ -0,0 +1,27 @@ +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- +import pytest +from parameters.bodyoptionality import BodyOptionalityClient +from parameters.bodyoptionality.models import BodyModel + + +@pytest.fixture +def client(): + with BodyOptionalityClient() as client: + yield client + + +def test_required_explicit(client: BodyOptionalityClient): + client.required_explicit(BodyModel(name="foo")) + + +def test_required_implicit(client: BodyOptionalityClient): + client.required_implicit(name="foo") + + +def test_optional_explicit(client: BodyOptionalityClient): + client.optional_explicit.set(BodyModel(name="foo")) + client.optional_explicit.omit() diff --git a/packages/typespec-python/tests/mock_api/shared/test_parameters_collection_format.py b/packages/typespec-python/tests/mock_api/shared/test_parameters_collection_format.py new file mode 100644 index 0000000000..283a7080f7 --- /dev/null +++ b/packages/typespec-python/tests/mock_api/shared/test_parameters_collection_format.py @@ -0,0 +1,33 @@ +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- +import pytest +from parameters.collectionformat import CollectionFormatClient + + +@pytest.fixture +def client(): + with CollectionFormatClient() as client: + yield client + + +def test_query_multi(client: CollectionFormatClient): + client.query.multi(colors=["blue", "red", "green"]) + + +def test_query_csv(client: CollectionFormatClient): + client.query.csv(colors=["blue", "red", "green"]) + + +def test_query_pipes(client: CollectionFormatClient): + client.query.pipes(colors=["blue", "red", "green"]) + + +def test_query_ssv(client: CollectionFormatClient): + client.query.ssv(colors=["blue", "red", "green"]) + + +def test_csv_header(client: CollectionFormatClient): + client.header.csv(colors=["blue", "red", "green"]) diff --git a/packages/typespec-python/tests/mock_api/shared/test_parameters_path.py b/packages/typespec-python/tests/mock_api/shared/test_parameters_path.py new file mode 100644 index 0000000000..71c6257e67 --- /dev/null +++ b/packages/typespec-python/tests/mock_api/shared/test_parameters_path.py @@ -0,0 +1,22 @@ +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- +import pytest +from parameters.path import PathClient + + +@pytest.fixture +def client(): + with PathClient() as client: + yield client + + +def test_normal(client: PathClient): + client.normal("foo") + + +def test_optional(client: PathClient): + client.optional() + client.optional(name="foo") diff --git a/packages/typespec-python/tests/mock_api/shared/test_parameters_query.py b/packages/typespec-python/tests/mock_api/shared/test_parameters_query.py new file mode 100644 index 0000000000..64f0e62c57 --- /dev/null +++ b/packages/typespec-python/tests/mock_api/shared/test_parameters_query.py @@ -0,0 +1,17 @@ +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- +import pytest +from parameters.query import QueryClient + + +@pytest.fixture +def client(): + with QueryClient() as client: + yield client + + +def test_constant(client: QueryClient): + client.constant.post() diff --git a/packages/typespec-python/tests/mock_api/shared/test_patch.py b/packages/typespec-python/tests/mock_api/shared/test_patch.py new file mode 100644 index 0000000000..8410e4046b --- /dev/null +++ b/packages/typespec-python/tests/mock_api/shared/test_patch.py @@ -0,0 +1,12 @@ +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- + + +def test_patch_mixin_operation_group_in_operations_folder(key_credential): + from authentication.apikey import ApiKeyClient, aio + + assert hasattr(ApiKeyClient(key_credential), "patch_added_operation") + assert hasattr(aio.ApiKeyClient(key_credential), "patch_added_operation") \ No newline at end of file diff --git a/packages/typespec-python/tests/mock_api/shared/test_payload_json_merge_patch.py b/packages/typespec-python/tests/mock_api/shared/test_payload_json_merge_patch.py new file mode 100644 index 0000000000..d4dcbedc03 --- /dev/null +++ b/packages/typespec-python/tests/mock_api/shared/test_payload_json_merge_patch.py @@ -0,0 +1,93 @@ +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- +import pytest +from payload.jsonmergepatch import JsonMergePatchClient +from payload.jsonmergepatch.models import InnerModel, Resource, ResourcePatch + +try: + from azure.core.serialization import NULL +except ImportError: + from corehttp.serialization import NULL + + +@pytest.fixture +def client(): + with JsonMergePatchClient(endpoint="http://localhost:3000") as client: + yield client + + +def test_create_resource(client: JsonMergePatchClient): + inner_madge = InnerModel(name="InnerMadge", description="innerDesc") + create_resource = Resource( + name="Madge", + description="desc", + map={"key": inner_madge}, + array=[inner_madge], + int_value=1, + float_value=1.25, + inner_model=inner_madge, + int_array=[1, 2, 3], + ) + response = client.create_resource(create_resource) + assert response == create_resource + + +def test_update_resource_model_input(client: JsonMergePatchClient): + update_resource = ResourcePatch( + description=NULL, + map={"key": InnerModel(description=NULL), "key2": NULL}, + array=NULL, + int_value=NULL, + float_value=NULL, + inner_model=NULL, + int_array=NULL, + ) + response = client.update_resource(update_resource) + assert response == Resource(name="Madge", map={"key": InnerModel(name="InnerMadge")}) + + +def test_update_resource_raw_input(client: JsonMergePatchClient): + response = client.update_resource( + { + "description": None, + "map": {"key": {"description": None}, "key2": None}, + "array": None, + "intValue": None, + "floatValue": None, + "innerModel": None, + "intArray": None, + } + ) + assert response == Resource(name="Madge", map={"key": InnerModel(name="InnerMadge")}) + + +def test_update_optional_resource_model_input(client: JsonMergePatchClient): + update_resource = ResourcePatch( + description=NULL, + map={"key": InnerModel(description=NULL), "key2": NULL}, + array=NULL, + int_value=NULL, + float_value=NULL, + inner_model=NULL, + int_array=NULL, + ) + response = client.update_optional_resource(update_resource) + assert response == Resource(name="Madge", map={"key": InnerModel(name="InnerMadge")}) + + +def test_update_optional_resource_raw_input(client: JsonMergePatchClient): + response = client.update_optional_resource( + { + "description": None, + "map": {"key": {"description": None}, "key2": None}, + "array": None, + "intValue": None, + "floatValue": None, + "innerModel": None, + "intArray": None, + } + ) + assert response == Resource(name="Madge", map={"key": InnerModel(name="InnerMadge")}) diff --git a/packages/typespec-python/tests/mock_api/shared/test_payload_media_type.py b/packages/typespec-python/tests/mock_api/shared/test_payload_media_type.py new file mode 100644 index 0000000000..72bc9425fc --- /dev/null +++ b/packages/typespec-python/tests/mock_api/shared/test_payload_media_type.py @@ -0,0 +1,25 @@ +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- +import pytest +from payload.mediatype import MediaTypeClient + + +@pytest.fixture +def client(): + with MediaTypeClient(endpoint="http://localhost:3000") as client: + yield client + + +def test_json(client: MediaTypeClient): + data = "foo" + client.string_body.send_as_json(data) + assert client.string_body.get_as_json() == data + + +def test_text(client: MediaTypeClient): + data = "{cat}" + client.string_body.send_as_text(data) + assert client.string_body.get_as_text() == data diff --git a/packages/typespec-python/tests/mock_api/shared/test_payload_pageable.py b/packages/typespec-python/tests/mock_api/shared/test_payload_pageable.py new file mode 100644 index 0000000000..7aaf8e0ce3 --- /dev/null +++ b/packages/typespec-python/tests/mock_api/shared/test_payload_pageable.py @@ -0,0 +1,99 @@ +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- +import pytest +from payload.pageable import PageableClient +from payload.pageable.serverdrivenpagination.alternateinitialverb.models import Filter + + +@pytest.fixture +def client(): + with PageableClient(endpoint="http://localhost:3000") as client: + yield client + + +def assert_result(result): + assert len(result) == 4 + assert result[0].id == "1" + assert result[1].id == "2" + assert result[2].id == "3" + assert result[3].id == "4" + assert result[0].name == "dog" + assert result[1].name == "cat" + assert result[2].name == "bird" + assert result[3].name == "fish" + + +def test_link(client: PageableClient): + result = list(client.server_driven_pagination.link()) + assert_result(result) + + +def test_link_string(client: PageableClient): + result = list(client.server_driven_pagination.link_string()) + assert_result(result) + + +def test_request_query_response_body(client: PageableClient): + result = list(client.server_driven_pagination.continuation_token.request_query_response_body(foo="foo", bar="bar")) + assert_result(result) + + +def test_request_header_response_body(client: PageableClient): + result = list(client.server_driven_pagination.continuation_token.request_header_response_body(foo="foo", bar="bar")) + assert_result(result) + + +def test_request_query_response_header(client: PageableClient): + result = list( + client.server_driven_pagination.continuation_token.request_query_response_header(foo="foo", bar="bar") + ) + assert_result(result) + + +def test_request_header_response_header(client: PageableClient): + result = list( + client.server_driven_pagination.continuation_token.request_header_response_header(foo="foo", bar="bar") + ) + assert_result(result) + + +def test_nested_link(client: PageableClient): + result = list(client.server_driven_pagination.nested_link()) + assert_result(result) + + +def test_request_query_nested_response_body(client: PageableClient): + result = list( + client.server_driven_pagination.continuation_token.request_query_nested_response_body(foo="foo", bar="bar") + ) + assert_result(result) + + +def test_request_header_nested_response_body(client: PageableClient): + result = list( + client.server_driven_pagination.continuation_token.request_header_nested_response_body(foo="foo", bar="bar") + ) + assert_result(result) + + +def test_list_without_continuation(client: PageableClient): + result = list(client.page_size.list_without_continuation()) + assert_result(result) + + +def test_xml_pagination_list_with_continuation(client: PageableClient): + result = list(client.xml_pagination.list_with_continuation()) + assert_result(result) + + +def test_xml_pagination_list_with_next_link(client: PageableClient): + result = list(client.xml_pagination.list_with_next_link()) + assert_result(result) + + +def test_alternate_initial_verb_post(client: PageableClient): + result = list(client.server_driven_pagination.alternate_initial_verb.post(Filter(filter="foo eq bar"))) + assert_result(result) diff --git a/packages/typespec-python/tests/mock_api/shared/test_payload_xml.py b/packages/typespec-python/tests/mock_api/shared/test_payload_xml.py new file mode 100644 index 0000000000..e301ff0a1e --- /dev/null +++ b/packages/typespec-python/tests/mock_api/shared/test_payload_xml.py @@ -0,0 +1,234 @@ +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- +import datetime +import pytest +from payload.xml import XmlClient +from payload.xml.models import ( + Author, + Book, + SimpleModel, + ModelWithSimpleArrays, + ModelWithArrayOfModel, + ModelWithAttributes, + ModelWithUnwrappedArray, + ModelWithUnwrappedModelArray, + ModelWithRenamedArrays, + ModelWithRenamedProperty, + ModelWithRenamedAttribute, + ModelWithRenamedNestedModel, + ModelWithRenamedWrappedModelArray, + ModelWithRenamedUnwrappedModelArray, + ModelWithRenamedWrappedAndItemModelArray, + ModelWithOptionalField, + ModelWithRenamedFields, + ModelWithEmptyArray, + ModelWithText, + ModelWithDictionary, + ModelWithEncodedNames, + ModelWithEnum, + ModelWithDatetime, + ModelWithNamespace, + ModelWithNamespaceOnProperties, + ModelWithNestedModel, + ModelWithWrappedPrimitiveCustomItemNames, +) + + +@pytest.fixture +def client(): + with XmlClient(endpoint="http://localhost:3000") as client: + yield client + + +def test_simple_model(client: XmlClient): + model = SimpleModel(name="foo", age=123) + assert client.simple_model_value.get() == model + client.simple_model_value.put(model) + + +def test_model_with_renamed_property(client: XmlClient): + model = ModelWithRenamedProperty(title="foo", author="bar") + assert client.model_with_renamed_property_value.get() == model + client.model_with_renamed_property_value.put(model) + + +def test_model_with_simple_arrays(client: XmlClient): + model = ModelWithSimpleArrays(colors=["red", "green", "blue"], counts=[1, 2]) + assert client.model_with_simple_arrays_value.get() == model + client.model_with_simple_arrays_value.put(model) + + +def test_model_with_wrapped_primitive_custom_item_names(client: XmlClient): + model = ModelWithWrappedPrimitiveCustomItemNames(tags=["fiction", "classic"]) + assert client.model_with_wrapped_primitive_custom_item_names_value.get() == model + client.model_with_wrapped_primitive_custom_item_names_value.put(model) + + +def test_model_with_array_of_model(client: XmlClient): + model = ModelWithArrayOfModel( + items_property=[ + SimpleModel(name="foo", age=123), + SimpleModel(name="bar", age=456), + ] + ) + assert client.model_with_array_of_model_value.get() == model + client.model_with_array_of_model_value.put(model) + + +def test_model_with_unwrapped_model_array(client: XmlClient): + model = ModelWithUnwrappedModelArray( + items_property=[ + SimpleModel(name="foo", age=123), + SimpleModel(name="bar", age=456), + ] + ) + assert client.model_with_unwrapped_model_array_value.get() == model + client.model_with_unwrapped_model_array_value.put(model) + + +def test_model_with_renamed_wrapped_model_array(client: XmlClient): + model = ModelWithRenamedWrappedModelArray( + items_property=[ + SimpleModel(name="foo", age=123), + SimpleModel(name="bar", age=456), + ] + ) + assert client.model_with_renamed_wrapped_model_array_value.get() == model + client.model_with_renamed_wrapped_model_array_value.put(model) + + +def test_model_with_renamed_unwrapped_model_array(client: XmlClient): + model = ModelWithRenamedUnwrappedModelArray( + items_property=[ + SimpleModel(name="foo", age=123), + SimpleModel(name="bar", age=456), + ] + ) + assert client.model_with_renamed_unwrapped_model_array_value.get() == model + client.model_with_renamed_unwrapped_model_array_value.put(model) + + +def test_model_with_renamed_wrapped_and_item_model_array(client: XmlClient): + model = ModelWithRenamedWrappedAndItemModelArray( + books=[ + Book(title="The Great Gatsby"), + Book(title="Les Miserables"), + ] + ) + assert client.model_with_renamed_wrapped_and_item_model_array_value.get() == model + client.model_with_renamed_wrapped_and_item_model_array_value.put(model) + + +def test_model_with_attributes(client: XmlClient): + model = ModelWithAttributes(id1=123, id2="foo", enabled=True) + assert client.model_with_attributes_value.get() == model + client.model_with_attributes_value.put(model) + + +def test_model_with_renamed_attribute(client: XmlClient): + model = ModelWithRenamedAttribute(id=123, title="The Great Gatsby", author="F. Scott Fitzgerald") + assert client.model_with_renamed_attribute_value.get() == model + client.model_with_renamed_attribute_value.put(model) + + +def test_model_with_unwrapped_array(client: XmlClient): + model = ModelWithUnwrappedArray(colors=["red", "green", "blue"], counts=[1, 2]) + assert client.model_with_unwrapped_array_value.get() == model + client.model_with_unwrapped_array_value.put(model) + + +def test_model_with_renamed_arrays(client: XmlClient): + model = ModelWithRenamedArrays(colors=["red", "green", "blue"], counts=[1, 2]) + assert client.model_with_renamed_arrays_value.get() == model + client.model_with_renamed_arrays_value.put(model) + + +def test_model_with_optional_field(client: XmlClient): + model = ModelWithOptionalField(item="widget") + assert client.model_with_optional_field_value.get() == model + client.model_with_optional_field_value.put(model) + + +def test_model_with_nested_model(client: XmlClient): + model = ModelWithNestedModel(nested=SimpleModel(name="foo", age=123)) + assert client.model_with_nested_model_value.get() == model + client.model_with_nested_model_value.put(model) + + +def test_model_with_renamed_nested_model(client: XmlClient): + model = ModelWithRenamedNestedModel(author=Author(name="foo")) + assert client.model_with_renamed_nested_model_value.get() == model + client.model_with_renamed_nested_model_value.put(model) + + +def test_model_with_renamed_fields(client: XmlClient): + model = ModelWithRenamedFields( + input_data=SimpleModel(name="foo", age=123), + output_data=SimpleModel(name="bar", age=456), + ) + assert client.model_with_renamed_fields_value.get() == model + client.model_with_renamed_fields_value.put(model) + + +def test_model_with_empty_array(client: XmlClient): + model = ModelWithEmptyArray(items_property=[]) + assert client.model_with_empty_array_value.get() == model + client.model_with_empty_array_value.put(model) + + +def test_model_with_text(client: XmlClient): + model = ModelWithText(language="foo", content="\n This is some text.\n") + assert client.model_with_text_value.get() == model + client.model_with_text_value.put(model) + + +def test_model_with_dictionary(client: XmlClient): + model = ModelWithDictionary(metadata={"Color": "blue", "Count": "123", "Enabled": "false"}) + assert client.model_with_dictionary_value.get() == model + client.model_with_dictionary_value.put(model) + + +def test_model_with_encoded_names(client: XmlClient): + model = ModelWithEncodedNames(model_data=SimpleModel(name="foo", age=123), colors=["red", "green", "blue"]) + assert client.model_with_encoded_names_value.get() == model + client.model_with_encoded_names_value.put(model) + + +def test_model_with_enum(client: XmlClient): + model = ModelWithEnum(status="success") + assert client.model_with_enum_value.get() == model + client.model_with_enum_value.put(model) + + +def test_model_with_datetime(client: XmlClient): + model = ModelWithDatetime( + rfc3339=datetime.datetime(2022, 8, 26, 18, 38, 0, tzinfo=datetime.timezone.utc), + rfc7231=datetime.datetime(2022, 8, 26, 14, 38, 0, tzinfo=datetime.timezone.utc), + ) + result = client.model_with_datetime_value.get() + assert result.rfc3339 == model.rfc3339 + assert result.rfc7231 == model.rfc7231 + client.model_with_datetime_value.put(model) + + +def test_model_with_namespace(client: XmlClient): + model = ModelWithNamespace(id=123, title="The Great Gatsby") + assert client.model_with_namespace_value.get() == model + client.model_with_namespace_value.put(model) + + +def test_model_with_namespace_on_properties(client: XmlClient): + model = ModelWithNamespaceOnProperties(id=123, title="The Great Gatsby", author="F. Scott Fitzgerald") + assert client.model_with_namespace_on_properties_value.get() == model + client.model_with_namespace_on_properties_value.put(model) + + +def test_xml_error_value(client: XmlClient, core_library): + with pytest.raises(core_library.exceptions.HttpResponseError) as ex: + client.xml_error_value.get() + assert ex.value.status_code == 400 + assert ex.value.model.message == "Something went wrong" + assert ex.value.model.code == 400 diff --git a/packages/typespec-python/tests/mock_api/shared/test_response_status_code_range.py b/packages/typespec-python/tests/mock_api/shared/test_response_status_code_range.py new file mode 100644 index 0000000000..247e095472 --- /dev/null +++ b/packages/typespec-python/tests/mock_api/shared/test_response_status_code_range.py @@ -0,0 +1,36 @@ +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- +import pytest +from response.statuscoderange import StatusCodeRangeClient +from response.statuscoderange.models import ErrorInRange, NotFoundError + + +@pytest.fixture +def client(): + with StatusCodeRangeClient(endpoint="http://localhost:3000") as client: + yield client + + +def test_error_response_status_code_in_range(client: StatusCodeRangeClient): + with pytest.raises(Exception) as exc_info: + client.error_response_status_code_in_range() + + error = exc_info.value.model + assert isinstance(error, ErrorInRange) + assert error.code == "request-header-too-large" + assert error.message == "Request header too large" + assert exc_info.value.response.status_code == 494 + + +def test_error_response_status_code_404(client: StatusCodeRangeClient): + with pytest.raises(Exception) as exc_info: + client.error_response_status_code404() + + error = exc_info.value.model + assert isinstance(error, NotFoundError) + assert error.code == "not-found" + assert error.resource_id == "resource1" + assert exc_info.value.response.status_code == 404 diff --git a/packages/typespec-python/tests/mock_api/shared/test_routes.py b/packages/typespec-python/tests/mock_api/shared/test_routes.py new file mode 100644 index 0000000000..e1058d0665 --- /dev/null +++ b/packages/typespec-python/tests/mock_api/shared/test_routes.py @@ -0,0 +1,285 @@ +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- +import pytest +from routes import RoutesClient + + +@pytest.fixture +def client(): + with RoutesClient() as client: + yield client + + +def test_fixed(client: RoutesClient): + client.fixed() + + +def test_in_interface_fixed(client: RoutesClient): + client.in_interface.fixed() + + +def test_path_parameters_template_only(client: RoutesClient): + client.path_parameters.template_only( + param="a", + ) + + +def test_path_parameters_explicit(client: RoutesClient): + client.path_parameters.explicit( + param="a", + ) + + +def test_path_parameters_annotation_only(client: RoutesClient): + client.path_parameters.annotation_only( + param="a", + ) + + +def test_path_parameters_reserved_expansion_template(client: RoutesClient): + client.path_parameters.reserved_expansion.template( + param="foo/bar baz", + ) + + +def test_path_parameters_reserved_expansion_annotation(client: RoutesClient): + client.path_parameters.reserved_expansion.annotation( + param="foo/bar baz", + ) + + +# def test_path_parameters_simple_expansion_standard_primitive(client: RoutesClient): +# client.path_parameters.simple_expansion.standard.primitive( +# param="a", +# ) + + +# def test_path_parameters_simple_expansion_standard_array(client: RoutesClient): +# client.path_parameters.simple_expansion.standard.array( +# param=["a", "b"], +# ) + + +# def test_path_parameters_simple_expansion_standard_record(client: RoutesClient): +# client.path_parameters.simple_expansion.standard.record( +# param={"a": 1, "b": 2}, +# ) + + +# def test_path_parameters_simple_expansion_explode_primitive(client: RoutesClient): +# client.path_parameters.simple_expansion.explode.primitive( +# param="a", +# ) + + +# def test_path_parameters_simple_expansion_explode_array(client: RoutesClient): +# client.path_parameters.simple_expansion.explode.array( +# param=["a", "b"], +# ) + + +# def test_path_parameters_simple_expansion_explode_record(client: RoutesClient): +# client.path_parameters.simple_expansion.explode.record( +# param={"a": 1, "b": 2}, +# ) + + +# def test_path_parameters_path_expansion_standard_primitive(client: RoutesClient): +# client.path_parameters.path_expansion.standard.primitive( +# param="a", +# ) + + +# def test_path_parameters_path_expansion_standard_array(client: RoutesClient): +# client.path_parameters.path_expansion.standard.array( +# param=["a", "b"], +# ) + + +# def test_path_parameters_path_expansion_standard_record(client: RoutesClient): +# client.path_parameters.path_expansion.standard.record( +# param={"a": 1, "b": 2}, +# ) + + +# def test_path_parameters_path_expansion_explode_primitive(client: RoutesClient): +# client.path_parameters.path_expansion.explode.primitive( +# param="a", +# ) + + +# def test_path_parameters_path_expansion_explode_array(client: RoutesClient): +# client.path_parameters.path_expansion.explode.array( +# param=["a", "b"], +# ) + + +# def test_path_parameters_path_expansion_explode_record(client: RoutesClient): +# client.path_parameters.path_expansion.explode.record( +# param={"a": 1, "b": 2}, +# ) + + +# def test_path_parameters_label_expansion_standard_primitive(client: RoutesClient): +# client.path_parameters.label_expansion.standard.primitive( +# param="a", +# ) + + +# def test_path_parameters_label_expansion_standard_array(client: RoutesClient): +# client.path_parameters.label_expansion.standard.array( +# param=["a", "b"], +# ) + + +# def test_path_parameters_label_expansion_standard_record(client: RoutesClient): +# client.path_parameters.label_expansion.standard.record( +# param={"a": 1, "b": 2}, +# ) + + +# def test_path_parameters_label_expansion_explode_primitive(client: RoutesClient): +# client.path_parameters.label_expansion.explode.primitive( +# param="a", +# ) + + +# def test_path_parameters_label_expansion_explode_array(client: RoutesClient): +# client.path_parameters.label_expansion.explode.array( +# param=["a", "b"], +# ) + + +# def test_path_parameters_label_expansion_explode_record(client: RoutesClient): +# client.path_parameters.label_expansion.explode.record( +# param={"a": 1, "b": 2}, +# ) + + +# def test_path_parameters_matrix_expansion_standard_primitive(client: RoutesClient): +# client.path_parameters.matrix_expansion.standard.primitive( +# param="a", +# ) + + +# def test_path_parameters_matrix_expansion_standard_array(client: RoutesClient): +# client.path_parameters.matrix_expansion.standard.array( +# param=["a", "b"], +# ) + + +# def test_path_parameters_matrix_expansion_standard_record(client: RoutesClient): +# client.path_parameters.matrix_expansion.standard.record( +# param={"a": 1, "b": 2}, +# ) + + +# def test_path_parameters_matrix_expansion_explode_primitive(client: RoutesClient): +# client.path_parameters.matrix_expansion.explode.primitive( +# param="a", +# ) + + +# def test_path_parameters_matrix_expansion_explode_array(client: RoutesClient): +# client.path_parameters.matrix_expansion.explode.array( +# param=["a", "b"], +# ) + + +# def test_path_parameters_matrix_expansion_explode_record(client: RoutesClient): +# client.path_parameters.matrix_expansion.explode.record( +# param={"a": 1, "b": 2}, +# ) + + +def test_query_parameters_template_only(client: RoutesClient): + client.query_parameters.template_only( + param="a", + ) + + +def test_query_parameters_explicit(client: RoutesClient): + client.query_parameters.explicit( + param="a", + ) + + +def test_query_parameters_annotation_only(client: RoutesClient): + client.query_parameters.annotation_only( + param="a", + ) + + +def test_query_parameters_query_expansion_standard_primitive(client: RoutesClient): + client.query_parameters.query_expansion.standard.primitive( + param="a", + ) + + +# def test_query_parameters_query_expansion_standard_array(client: RoutesClient): +# client.query_parameters.query_expansion.standard.array( +# param=["a", "b"], +# ) + + +# def test_query_parameters_query_expansion_standard_record(client: RoutesClient): +# client.query_parameters.query_expansion.standard.record( +# param={"a": 1, "b": 2}, +# ) + + +def test_query_parameters_query_expansion_explode_primitive(client: RoutesClient): + client.query_parameters.query_expansion.explode.primitive( + param="a", + ) + + +# def test_query_parameters_query_expansion_explode_array(client: RoutesClient): +# client.query_parameters.query_expansion.explode.array( +# param=["a", "b"], +# ) + + +# def test_query_parameters_query_expansion_explode_record(client: RoutesClient): +# client.query_parameters.query_expansion.explode.record( +# param={"a": 1, "b": 2}, +# ) + + +def test_query_parameters_query_continuation_standard_primitive(client: RoutesClient): + client.query_parameters.query_continuation.standard.primitive( + param="a", + ) + + +# def test_query_parameters_query_continuation_standard_array(client: RoutesClient): +# client.query_parameters.query_continuation.standard.array( +# param=["a", "b"], +# ) + + +# def test_query_parameters_query_continuation_standard_record(client: RoutesClient): +# client.query_parameters.query_continuation.standard.record( +# param={"a": 1, "b": 2}, +# ) + + +def test_query_parameters_query_continuation_explode_primitive(client: RoutesClient): + client.query_parameters.query_continuation.explode.primitive( + param="a", + ) + + +# def test_query_parameters_query_continuation_explode_array(client: RoutesClient): +# client.query_parameters.query_continuation.explode.array( +# param=["a", "b"], +# ) + + +# def test_query_parameters_query_continuation_explode_record(client: RoutesClient): +# client.query_parameters.query_continuation.explode.record( +# param={"a": 1, "b": 2}, +# ) diff --git a/packages/typespec-python/tests/mock_api/shared/test_server_endpoint_not_defined.py b/packages/typespec-python/tests/mock_api/shared/test_server_endpoint_not_defined.py new file mode 100644 index 0000000000..432542dd95 --- /dev/null +++ b/packages/typespec-python/tests/mock_api/shared/test_server_endpoint_not_defined.py @@ -0,0 +1,17 @@ +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- +import pytest +from server.endpoint.notdefined import NotDefinedClient + + +@pytest.fixture +def client(): + with NotDefinedClient(endpoint="http://localhost:3000") as client: + yield client + + +def test_valid(client: NotDefinedClient): + assert client.valid() is True diff --git a/packages/typespec-python/tests/mock_api/shared/test_server_path_multiple.py b/packages/typespec-python/tests/mock_api/shared/test_server_path_multiple.py new file mode 100644 index 0000000000..2a697f142f --- /dev/null +++ b/packages/typespec-python/tests/mock_api/shared/test_server_path_multiple.py @@ -0,0 +1,21 @@ +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- +import pytest +from server.path.multiple import MultipleClient + + +@pytest.fixture +def client(): + with MultipleClient(endpoint="http://localhost:3000") as client: + yield client + + +def test_no_operation_params(client: MultipleClient): + client.no_operation_params() + + +def test_with_operation_path_param(client: MultipleClient): + client.with_operation_path_param(keyword="test") diff --git a/packages/typespec-python/tests/mock_api/shared/test_server_path_single.py b/packages/typespec-python/tests/mock_api/shared/test_server_path_single.py new file mode 100644 index 0000000000..0ef66c1d0b --- /dev/null +++ b/packages/typespec-python/tests/mock_api/shared/test_server_path_single.py @@ -0,0 +1,17 @@ +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- +import pytest +from server.path.single import SingleClient + + +@pytest.fixture +def client(): + with SingleClient(endpoint="http://localhost:3000") as client: + yield client + + +def test_my_op(client): + assert client.my_op() is True diff --git a/packages/typespec-python/tests/mock_api/shared/test_server_versions_not_versioned.py b/packages/typespec-python/tests/mock_api/shared/test_server_versions_not_versioned.py new file mode 100644 index 0000000000..9d68cd9d48 --- /dev/null +++ b/packages/typespec-python/tests/mock_api/shared/test_server_versions_not_versioned.py @@ -0,0 +1,25 @@ +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- +import pytest +from server.versions.notversioned import NotVersionedClient + + +@pytest.fixture +def client(): + with NotVersionedClient(endpoint="http://localhost:3000") as client: + yield client + + +def test_without_api_version(client: NotVersionedClient): + client.without_api_version() + + +def test_with_query_api_version(client: NotVersionedClient): + client.with_query_api_version(api_version="v1.0") + + +def test_with_path_api_version(client: NotVersionedClient): + client.with_path_api_version(api_version="v1.0") diff --git a/packages/typespec-python/tests/mock_api/shared/test_server_versions_versioned.py b/packages/typespec-python/tests/mock_api/shared/test_server_versions_versioned.py new file mode 100644 index 0000000000..00b7fcd192 --- /dev/null +++ b/packages/typespec-python/tests/mock_api/shared/test_server_versions_versioned.py @@ -0,0 +1,30 @@ +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- +import pytest +from server.versions.versioned import VersionedClient + + +@pytest.fixture +def client(): + with VersionedClient(endpoint="http://localhost:3000") as client: + yield client + + +def test_without_api_version(client: VersionedClient): + client.without_api_version() + + +def test_with_query_api_version(client: VersionedClient): + client.with_query_api_version() + + +def test_with_path_api_version(client: VersionedClient): + client.with_path_api_version() + + +def test_with_query_old_api_version(): + with VersionedClient(endpoint="http://localhost:3000", api_version="2021-01-01-preview") as client: + client.with_query_old_api_version() diff --git a/packages/typespec-python/tests/mock_api/shared/test_special_headers_conditional_request.py b/packages/typespec-python/tests/mock_api/shared/test_special_headers_conditional_request.py new file mode 100644 index 0000000000..f476a1db9d --- /dev/null +++ b/packages/typespec-python/tests/mock_api/shared/test_special_headers_conditional_request.py @@ -0,0 +1,34 @@ +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- +import pytest +import datetime +from specialheaders.conditionalrequest import ConditionalRequestClient + + +@pytest.fixture +def client(): + with ConditionalRequestClient() as client: + yield client + + +def test_post_if_match(core_library, client: ConditionalRequestClient): + client.post_if_match(etag="valid", match_condition=core_library.MatchConditions.IfNotModified) + + +def test_post_if_none_match(core_library, client: ConditionalRequestClient): + client.post_if_none_match(etag="invalid", match_condition=core_library.MatchConditions.IfModified) + + +def test_head_if_modified_since(client: ConditionalRequestClient): + client.head_if_modified_since( + if_modified_since=datetime.datetime(2022, 8, 26, 14, 38, 0, tzinfo=datetime.timezone.utc) + ) + + +def test_post_if_unmodified_since(client: ConditionalRequestClient): + client.post_if_unmodified_since( + if_unmodified_since=datetime.datetime(2022, 8, 26, 14, 38, 0, tzinfo=datetime.timezone.utc) + ) diff --git a/packages/typespec-python/tests/mock_api/shared/test_special_headers_repeatability.py b/packages/typespec-python/tests/mock_api/shared/test_special_headers_repeatability.py new file mode 100644 index 0000000000..b35c8a1f16 --- /dev/null +++ b/packages/typespec-python/tests/mock_api/shared/test_special_headers_repeatability.py @@ -0,0 +1,18 @@ +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- +import pytest +from specialheaders.repeatability import RepeatabilityClient + + +@pytest.fixture +def client(): + with RepeatabilityClient() as client: + yield client + + +def test_immediate_success(client: RepeatabilityClient): + cls = lambda x, y, z: z + assert client.immediate_success(cls=cls)["Repeatability-Result"] == "accepted" diff --git a/packages/typespec-python/tests/mock_api/shared/test_specs_documentation.py b/packages/typespec-python/tests/mock_api/shared/test_specs_documentation.py new file mode 100644 index 0000000000..2f956dd75f --- /dev/null +++ b/packages/typespec-python/tests/mock_api/shared/test_specs_documentation.py @@ -0,0 +1,51 @@ +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- + +import pytest +from specs.documentation import DocumentationClient, models + + +@pytest.fixture +def client(): + with DocumentationClient(endpoint="http://localhost:3000") as client: + yield client + + +class TestLists: + def test_bullet_points_op(self, client: DocumentationClient): + # GET /documentation/lists/bullet-points/op + # Expected: 204 No Content + client.lists.bullet_points_op() + + def test_bullet_points_model(self, client: DocumentationClient): + # POST /documentation/lists/bullet-points/model + # Expected: 200 OK + client.lists.bullet_points_model(input=models.BulletPointsModel(prop="Simple")) + + # Also test with JSON + client.lists.bullet_points_model(body={"input": {"prop": "Simple"}}) + + def test_numbered(self, client: DocumentationClient): + # GET /documentation/lists/numbered + # Expected: 204 No Content + client.lists.numbered() + + +class TestTextFormatting: + def test_bold_text(self, client: DocumentationClient): + # GET /documentation/text-formatting/bold + # Expected: 204 No Content + client.text_formatting.bold_text() + + def test_italic_text(self, client: DocumentationClient): + # GET /documentation/text-formatting/italic + # Expected: 204 No Content + client.text_formatting.italic_text() + + def test_combined_formatting(self, client: DocumentationClient): + # GET /documentation/text-formatting/combined + # Expected: 204 No Content + client.text_formatting.combined_formatting() diff --git a/packages/typespec-python/tests/mock_api/shared/test_streaming_jsonl.py b/packages/typespec-python/tests/mock_api/shared/test_streaming_jsonl.py new file mode 100644 index 0000000000..494c17a349 --- /dev/null +++ b/packages/typespec-python/tests/mock_api/shared/test_streaming_jsonl.py @@ -0,0 +1,25 @@ +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- +import pytest + +from streaming.jsonl import JsonlClient + + +@pytest.fixture +def client(): + with JsonlClient(endpoint="http://localhost:3000") as client: + yield client + + +JSONL = b'{"desc": "one"}\n{"desc": "two"}\n{"desc": "three"}' + + +def test_basic_send(client: JsonlClient): + client.basic.send(JSONL) + + +def test_basic_recv(client: JsonlClient): + assert b"".join(client.basic.receive()) == JSONL diff --git a/packages/typespec-python/tests/mock_api/shared/test_typetest_array.py b/packages/typespec-python/tests/mock_api/shared/test_typetest_array.py new file mode 100644 index 0000000000..0c3c0f3f06 --- /dev/null +++ b/packages/typespec-python/tests/mock_api/shared/test_typetest_array.py @@ -0,0 +1,111 @@ +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- + +import pytest +import isodate +from typetest.array import ArrayClient, models + + +@pytest.fixture +def client(): + with ArrayClient() as client: + yield client + + +def test_boolean_value(client: ArrayClient): + assert client.boolean_value.get() == [True, False] + client.boolean_value.put([True, False]) + + +def test_datetime_value(client: ArrayClient): + assert client.datetime_value.get() == [isodate.parse_datetime("2022-08-26T18:38:00Z")] + client.datetime_value.put([isodate.parse_datetime("2022-08-26T18:38:00Z")]) + + +def test_duration_value(client: ArrayClient): + assert client.duration_value.get() == [isodate.parse_duration("P123DT22H14M12.011S")] + client.duration_value.put([isodate.parse_duration("P123DT22H14M12.011S")]) + + +def test_float32_value(client: ArrayClient): + assert client.float32_value.get() == [43.125] + client.float32_value.put([43.125]) + + +def test_int32_value(client: ArrayClient): + assert client.int32_value.get() == [1, 2] + client.int32_value.put([1, 2]) + + +def test_int64_value(client: ArrayClient): + assert client.int64_value.get() == [2**53 - 1, -(2**53 - 1)] + client.int64_value.put([2**53 - 1, -(2**53 - 1)]) + + +def test_model_value(client: ArrayClient): + assert client.model_value.get() == [ + models.InnerModel(property="hello"), + models.InnerModel(property="world"), + ] + # test list[model] + client.model_value.put( + [ + models.InnerModel(property="hello"), + models.InnerModel(property="world"), + ] + ) + # test list[JSON] + client.model_value.put( + [ + {"property": "hello"}, + {"property": "world"}, + ] + ) + + +def test_nullable_boolean_value(client: ArrayClient): + assert client.nullable_boolean_value.get() == [True, None, False] + client.nullable_boolean_value.put([True, None, False]) + + +def test_nullable_float_value(client: ArrayClient): + assert client.nullable_float_value.get() == [1.25, None, 3.0] + client.nullable_float_value.put([1.25, None, 3.0]) + + +def test_nullable_int32_value(client: ArrayClient): + assert client.nullable_int32_value.get() == [1, None, 3] + client.nullable_int32_value.put([1, None, 3]) + + +def test_nullable_model_value(client: ArrayClient): + assert client.nullable_model_value.get() == [ + models.InnerModel(property="hello"), + None, + models.InnerModel(property="world"), + ] + client.nullable_model_value.put( + [ + models.InnerModel(property="hello"), + None, + models.InnerModel(property="world"), + ] + ) + + +def test_nullable_string_value(client: ArrayClient): + assert client.nullable_string_value.get() == ["hello", None, "world"] + client.nullable_string_value.put(["hello", None, "world"]) + + +def test_string_value(client: ArrayClient): + assert client.string_value.get() == ["hello", ""] + client.string_value.put(["hello", ""]) + + +def test_unknown_value(client: ArrayClient): + assert client.unknown_value.get() == [1, "hello", None] + client.unknown_value.put([1, "hello", None]) diff --git a/packages/typespec-python/tests/mock_api/shared/test_typetest_dictionary.py b/packages/typespec-python/tests/mock_api/shared/test_typetest_dictionary.py new file mode 100644 index 0000000000..98fb416547 --- /dev/null +++ b/packages/typespec-python/tests/mock_api/shared/test_typetest_dictionary.py @@ -0,0 +1,86 @@ +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- +import pytest +from typetest.dictionary import DictionaryClient, models +import isodate + + +@pytest.fixture +def client(): + with DictionaryClient() as client: + yield client + + +def test_boolean_value(client: DictionaryClient): + value = {"k1": True, "k2": False} + assert client.boolean_value.get() == value + client.boolean_value.put(value) + + +def test_datetime_value(client: DictionaryClient): + value = {"k1": isodate.parse_datetime("2022-08-26T18:38:00Z")} + assert client.datetime_value.get() == value + client.datetime_value.put(value) + + +def test_duration_value(client: DictionaryClient): + value = {"k1": isodate.parse_duration("P123DT22H14M12.011S")} + assert client.duration_value.get() == value + client.duration_value.put(value) + + +def test_float32_value(client: DictionaryClient): + value = {"k1": 43.125} + assert client.float32_value.get() == value + client.float32_value.put(value) + + +def test_int32_value(client: DictionaryClient): + value = {"k1": 1, "k2": 2} + assert client.int32_value.get() == value + client.int32_value.put(value) + + +def test_int64_value(client: DictionaryClient): + value = {"k1": 2**53 - 1, "k2": -(2**53 - 1)} + assert client.int64_value.get() == value + client.int64_value.put(value) + + +def test_model_value(client: DictionaryClient): + value = { + "k1": models.InnerModel(property="hello"), + "k2": models.InnerModel(property="world"), + } + assert client.model_value.get() == value + client.model_value.put(value) + + +def test_nullable_float_value(client: DictionaryClient): + value = {"k1": 1.25, "k2": 0.5, "k3": None} + assert client.nullable_float_value.get() == value + client.nullable_float_value.put(value) + + +def test_recursive_model_value(client: DictionaryClient): + value = { + "k1": models.InnerModel(property="hello", children={}), + "k2": models.InnerModel(property="world", children={"k2.1": models.InnerModel(property="inner world")}), + } + assert client.recursive_model_value.get() == value + client.recursive_model_value.put(value) + + +def test_string_value(client: DictionaryClient): + value = {"k1": "hello", "k2": ""} + assert client.string_value.get() == value + client.string_value.put(value) + + +def test_unknown_value(client: DictionaryClient): + value = {"k1": 1, "k2": "hello", "k3": None} + assert client.unknown_value.get() == value + client.unknown_value.put(value) diff --git a/packages/typespec-python/tests/mock_api/shared/test_typetest_enum_extensible.py b/packages/typespec-python/tests/mock_api/shared/test_typetest_enum_extensible.py new file mode 100644 index 0000000000..b6bcf593e6 --- /dev/null +++ b/packages/typespec-python/tests/mock_api/shared/test_typetest_enum_extensible.py @@ -0,0 +1,23 @@ +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- +import pytest +from typetest.enum.extensible import ExtensibleClient, models + + +@pytest.fixture +def client(): + with ExtensibleClient() as client: + yield client + + +def test_known_value(client): + assert client.string.get_known_value() == models.DaysOfWeekExtensibleEnum.MONDAY + client.string.put_known_value(models.DaysOfWeekExtensibleEnum.MONDAY) + + +def test_unknown_value(client): + assert client.string.get_unknown_value() == "Weekend" + client.string.put_unknown_value("Weekend") diff --git a/packages/typespec-python/tests/mock_api/shared/test_typetest_enum_fixed.py b/packages/typespec-python/tests/mock_api/shared/test_typetest_enum_fixed.py new file mode 100644 index 0000000000..0d085d0200 --- /dev/null +++ b/packages/typespec-python/tests/mock_api/shared/test_typetest_enum_fixed.py @@ -0,0 +1,25 @@ +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- +import pytest +from typetest.enum.fixed import FixedClient, models + + +@pytest.fixture +def client(): + with FixedClient() as client: + yield client + + +def test_known_value(client): + assert client.string.get_known_value() == models.DaysOfWeekEnum.MONDAY + client.string.put_known_value(models.DaysOfWeekEnum.MONDAY) + + +def test_unknown_value(client: FixedClient, core_library): + try: + client.string.put_unknown_value("Weekend") + except core_library.exceptions.HttpResponseError as err: + assert err.status_code == 500 diff --git a/packages/typespec-python/tests/mock_api/shared/test_typetest_file.py b/packages/typespec-python/tests/mock_api/shared/test_typetest_file.py new file mode 100644 index 0000000000..1503b0b580 --- /dev/null +++ b/packages/typespec-python/tests/mock_api/shared/test_typetest_file.py @@ -0,0 +1,52 @@ +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- + +# after we support Http.File case, enable these tests again + +# import json + +# import pytest +# from typetest.file import FileClient + + +# @pytest.fixture +# def client(): +# with FileClient(endpoint="http://localhost:3000") as client: +# yield client + + +# def test_upload_file_specific_content_type(client: FileClient, png_data: bytes): +# client.body.upload_file_specific_content_type(png_data) + + +# # Do not support this case for now +# # def test_upload_file_json_content_type(client: FileClient): +# # client.body.upload_file_json_content_type(json.dumps({"message": "test file content"}).encode()) + + +# # although result is expected but actually there is deserialization issue +# # def test_download_file_json_content_type(client: FileClient): +# # result = client.body.download_file_json_content_type() +# # assert result == {"message": "test file content"} + + +# def test_download_file_specific_content_type(client: FileClient, png_data: bytes): +# result = b"".join(client.body.download_file_specific_content_type()) +# assert result == png_data + + +# def test_download_file_multiple_content_types(client: FileClient, png_data: bytes): +# result = b"".join(client.body.download_file_multiple_content_types()) +# assert result == png_data + + +# def test_upload_file_default_content_type(client: FileClient, png_data: bytes): +# client.body.upload_file_default_content_type(png_data, content_type="image/png") + + +# def test_download_file_default_content_type(client: FileClient, png_data: bytes): +# result = b"".join(client.body.download_file_default_content_type()) +# assert result == png_data diff --git a/packages/typespec-python/tests/mock_api/shared/test_typetest_model_empty.py b/packages/typespec-python/tests/mock_api/shared/test_typetest_model_empty.py new file mode 100644 index 0000000000..1ef7fcb5e2 --- /dev/null +++ b/packages/typespec-python/tests/mock_api/shared/test_typetest_model_empty.py @@ -0,0 +1,29 @@ +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- +import pytest +from typetest.model.empty import EmptyClient +from typetest.model.empty.models import EmptyInput, EmptyOutput, EmptyInputOutput + + +@pytest.fixture +def client(): + with EmptyClient() as client: + yield client + + +def test_put(client: EmptyClient): + client.put_empty(EmptyInput()) + client.put_empty({}) + + +def test_get(client: EmptyClient): + assert client.get_empty() == EmptyOutput() + assert client.get_empty() == {} + + +def test_post_round(client: EmptyClient): + assert client.post_round_trip_empty(EmptyInputOutput()) == EmptyInputOutput() + assert client.post_round_trip_empty({}) == {} diff --git a/packages/typespec-python/tests/mock_api/shared/test_typetest_model_inheritance_enum_discriminator.py b/packages/typespec-python/tests/mock_api/shared/test_typetest_model_inheritance_enum_discriminator.py new file mode 100644 index 0000000000..6d752166b4 --- /dev/null +++ b/packages/typespec-python/tests/mock_api/shared/test_typetest_model_inheritance_enum_discriminator.py @@ -0,0 +1,58 @@ +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- +import pytest +from typetest.model.enumdiscriminator import EnumDiscriminatorClient +from typetest.model.enumdiscriminator import models + + +@pytest.fixture +def client(): + with EnumDiscriminatorClient() as client: + yield client + + +@pytest.fixture +def valid_body(): + return models.Golden(weight=10) + + +@pytest.fixture +def valid_fixed_body(): + return models.Cobra(length=10) + + +def test_get_extensible_model(client: EnumDiscriminatorClient, valid_body: models.Dog): + assert client.get_extensible_model() == valid_body + assert isinstance(client.get_extensible_model(), models.Golden) + + +def test_put_extensible_model(client: EnumDiscriminatorClient, valid_body: models.Dog): + client.put_extensible_model(valid_body) + + +def test_get_extensible_model_missing_discriminator(client: EnumDiscriminatorClient): + assert client.get_extensible_model_missing_discriminator() == models.Dog(weight=10) + + +def test_get_extensible_model_wrong_discriminator(client: EnumDiscriminatorClient): + assert client.get_extensible_model_wrong_discriminator() == models.Dog(weight=8, kind="wrongKind") + + +def test_get_fixed_model(client: EnumDiscriminatorClient, valid_fixed_body: models.Snake): + assert client.get_fixed_model() == valid_fixed_body + assert isinstance(client.get_fixed_model(), models.Cobra) + + +def test_put_fixed_model(client: EnumDiscriminatorClient, valid_fixed_body: models.Snake): + client.put_fixed_model(valid_fixed_body) + + +def test_get_fixed_model_missing_discriminator(client: EnumDiscriminatorClient): + assert client.get_fixed_model_missing_discriminator() == models.Snake(length=10) + + +def test_get_fixed_model_wrong_discriminator(client: EnumDiscriminatorClient): + assert client.get_fixed_model_wrong_discriminator() == models.Snake(length=8, kind="wrongKind") diff --git a/packages/typespec-python/tests/mock_api/shared/test_typetest_model_inheritance_nested_discriminator.py b/packages/typespec-python/tests/mock_api/shared/test_typetest_model_inheritance_nested_discriminator.py new file mode 100644 index 0000000000..8ea1366afa --- /dev/null +++ b/packages/typespec-python/tests/mock_api/shared/test_typetest_model_inheritance_nested_discriminator.py @@ -0,0 +1,79 @@ +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- +import pytest +from typetest.model.nesteddiscriminator import NestedDiscriminatorClient +from typetest.model.nesteddiscriminator.models import GoblinShark, Salmon, Fish + + +@pytest.fixture +def client(): + with NestedDiscriminatorClient() as client: + yield client + + +@pytest.fixture +def valid_body(): + return GoblinShark(age=1) + + +def test_get_model(client, valid_body): + assert client.get_model() == valid_body + assert isinstance(client.get_model(), GoblinShark) + + +def test_put_model(client, valid_body): + client.put_model(valid_body) + + +@pytest.fixture +def valid_recursive_body(): + return Salmon( + { + "age": 1, + "kind": "salmon", + "partner": {"age": 2, "kind": "shark", "sharktype": "saw"}, + "friends": [ + { + "age": 2, + "kind": "salmon", + "partner": {"age": 3, "kind": "salmon"}, + "hate": { + "key1": {"age": 4, "kind": "salmon"}, + "key2": {"age": 2, "kind": "shark", "sharktype": "goblin"}, + }, + }, + {"age": 3, "kind": "shark", "sharktype": "goblin"}, + ], + "hate": { + "key3": {"age": 3, "kind": "shark", "sharktype": "saw"}, + "key4": { + "age": 2, + "kind": "salmon", + "friends": [ + {"age": 1, "kind": "salmon"}, + {"age": 4, "kind": "shark", "sharktype": "goblin"}, + ], + }, + }, + } + ) + + +def test_get_recursive_model(client, valid_recursive_body): + assert valid_recursive_body == client.get_recursive_model() + assert isinstance(client.get_recursive_model(), Salmon) + + +def test_put_recursive_model(client, valid_recursive_body): + client.put_recursive_model(valid_recursive_body) + + +def test_get_missing_discriminator(client): + assert client.get_missing_discriminator() == Fish(age=1) + + +def test_get_wrong_discriminator(client): + assert client.get_wrong_discriminator() == Fish(age=1, kind="wrongKind") diff --git a/packages/typespec-python/tests/mock_api/shared/test_typetest_model_inheritance_not_discriminated.py b/packages/typespec-python/tests/mock_api/shared/test_typetest_model_inheritance_not_discriminated.py new file mode 100644 index 0000000000..e9a1fa4752 --- /dev/null +++ b/packages/typespec-python/tests/mock_api/shared/test_typetest_model_inheritance_not_discriminated.py @@ -0,0 +1,31 @@ +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- +import pytest +from typetest.model.notdiscriminated import NotDiscriminatedClient +from typetest.model.notdiscriminated.models import Siamese + + +@pytest.fixture +def client(): + with NotDiscriminatedClient() as client: + yield client + + +@pytest.fixture +def valid_body(): + return Siamese(name="abc", age=32, smart=True) + + +def test_get_valid(client, valid_body): + assert client.get_valid() == valid_body + + +def test_post_valid(client, valid_body): + client.post_valid(valid_body) + + +def test_put_valid(client, valid_body): + assert valid_body == client.put_valid(valid_body) diff --git a/packages/typespec-python/tests/mock_api/shared/test_typetest_model_inheritance_recursive.py b/packages/typespec-python/tests/mock_api/shared/test_typetest_model_inheritance_recursive.py new file mode 100644 index 0000000000..1aa0758e34 --- /dev/null +++ b/packages/typespec-python/tests/mock_api/shared/test_typetest_model_inheritance_recursive.py @@ -0,0 +1,32 @@ +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- +import pytest +from typetest.model.recursive import RecursiveClient +from typetest.model.recursive.models import Extension + + +@pytest.fixture +def client(): + with RecursiveClient() as client: + yield client + + +@pytest.fixture +def expected(): + return Extension( + { + "level": 0, + "extension": [{"level": 1, "extension": [{"level": 2}]}, {"level": 1}], + } + ) + + +def test_put(client: RecursiveClient, expected: Extension): + client.put(expected) + + +def test_get(client: RecursiveClient, expected: Extension): + assert client.get() == expected diff --git a/packages/typespec-python/tests/mock_api/shared/test_typetest_model_inheritance_single_discriminator.py b/packages/typespec-python/tests/mock_api/shared/test_typetest_model_inheritance_single_discriminator.py new file mode 100644 index 0000000000..86435d5486 --- /dev/null +++ b/packages/typespec-python/tests/mock_api/shared/test_typetest_model_inheritance_single_discriminator.py @@ -0,0 +1,60 @@ +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- +import pytest +from typetest.model.singlediscriminator import SingleDiscriminatorClient +from typetest.model.singlediscriminator.models import Sparrow, Eagle, Bird, Dinosaur + + +@pytest.fixture +def client(): + with SingleDiscriminatorClient() as client: + yield client + + +@pytest.fixture +def valid_body(): + return Sparrow(wingspan=1) + + +def test_get_model(client, valid_body): + assert client.get_model() == valid_body + + +def test_put_model(client, valid_body): + client.put_model(valid_body) + + +@pytest.fixture +def recursive_body(): + return Eagle( + { + "wingspan": 5, + "kind": "eagle", + "partner": {"wingspan": 2, "kind": "goose"}, + "friends": [{"wingspan": 2, "kind": "seagull"}], + "hate": {"key3": {"wingspan": 1, "kind": "sparrow"}}, + } + ) + + +def test_get_recursive_model(client, recursive_body): + assert client.get_recursive_model() == recursive_body + + +def test_put_recursive_model(client, recursive_body): + client.put_recursive_model(recursive_body) + + +def test_get_missing_discriminator(client): + assert client.get_missing_discriminator() == Bird(wingspan=1) + + +def test_get_wrong_discriminator(client): + assert client.get_wrong_discriminator() == Bird(wingspan=1, kind="wrongKind") + + +def test_get_legacy_model(client): + assert client.get_legacy_model() == Dinosaur(size=20, kind="t-rex") diff --git a/packages/typespec-python/tests/mock_api/shared/test_typetest_model_usage.py b/packages/typespec-python/tests/mock_api/shared/test_typetest_model_usage.py new file mode 100644 index 0000000000..c9ef0e63e7 --- /dev/null +++ b/packages/typespec-python/tests/mock_api/shared/test_typetest_model_usage.py @@ -0,0 +1,28 @@ +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- +import pytest +from typetest.model.usage import UsageClient, models + + +@pytest.fixture +def client(): + with UsageClient() as client: + yield client + + +def test_input(client: UsageClient): + input = models.InputRecord(required_prop="example-value") + assert client.input(input) is None + + +def test_output(client: UsageClient): + output = models.OutputRecord(required_prop="example-value") + assert output == client.output() + + +def test_input_and_output(client: UsageClient): + input_output = models.InputOutputRecord(required_prop="example-value") + assert input_output == client.input_and_output(input_output) diff --git a/packages/typespec-python/tests/mock_api/shared/test_typetest_model_visibility.py b/packages/typespec-python/tests/mock_api/shared/test_typetest_model_visibility.py new file mode 100644 index 0000000000..c6f4695f2f --- /dev/null +++ b/packages/typespec-python/tests/mock_api/shared/test_typetest_model_visibility.py @@ -0,0 +1,40 @@ +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- +import pytest +from typetest.model.visibility import VisibilityClient, models + + +@pytest.fixture +def client(): + with VisibilityClient() as client: + yield client + + +def test_get_model(client): + result = client.get_model(models.VisibilityModel(), query_prop=123) + assert result == models.VisibilityModel(read_prop="abc") + + +def test_put_model(client): + client.put_model(models.VisibilityModel(create_prop=["foo", "bar"], update_prop=[1, 2])) + + +def test_patch_model(client): + client.patch_model(models.VisibilityModel(update_prop=[1, 2])) + + +def test_post_model(client): + client.post_model(models.VisibilityModel(create_prop=["foo", "bar"])) + + +def test_delete_model(client): + client.delete_model(models.VisibilityModel(delete_prop=True)) + + +def test_put_read_only_model(client): + client.put_read_only_model( + models.ReadOnlyModel(optional_nullable_int_list=[1, 2], optional_string_record={"foo", "bar"}) + ) diff --git a/packages/typespec-python/tests/mock_api/shared/test_typetest_property_additionalproperties.py b/packages/typespec-python/tests/mock_api/shared/test_typetest_property_additionalproperties.py new file mode 100644 index 0000000000..c34c281f82 --- /dev/null +++ b/packages/typespec-python/tests/mock_api/shared/test_typetest_property_additionalproperties.py @@ -0,0 +1,299 @@ +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- +import pytest +from typetest.property.additionalproperties import AdditionalPropertiesClient, models + + +@pytest.fixture +def client(): + with AdditionalPropertiesClient() as client: + yield client + + +def test_extends_different_spread_float(client: AdditionalPropertiesClient): + body = models.DifferentSpreadFloatDerived({"name": "abc", "prop": 43.125, "derivedProp": 43.125}) + assert client.extends_different_spread_float.get() == body + client.extends_different_spread_float.put(body) + + +def test_extends_different_spread_model(client: AdditionalPropertiesClient): + body = models.DifferentSpreadModelDerived( + {"knownProp": "abc", "prop": {"state": "ok"}, "derivedProp": {"state": "ok"}} + ) + assert client.extends_different_spread_model.get() == body + client.extends_different_spread_model.put(body) + + +def test_extends_different_spread_model_array(client: AdditionalPropertiesClient): + body = models.DifferentSpreadModelArrayDerived( + { + "knownProp": "abc", + "prop": [{"state": "ok"}, {"state": "ok"}], + "derivedProp": [{"state": "ok"}, {"state": "ok"}], + } + ) + assert client.extends_different_spread_model_array.get() == body + client.extends_different_spread_model_array.put(body) + + +def test_extends_different_spread_string(client: AdditionalPropertiesClient): + body = models.DifferentSpreadStringDerived({"id": 43.125, "prop": "abc", "derivedProp": "abc"}) + assert client.extends_different_spread_string.get() == body + client.extends_different_spread_string.put(body) + + +def test_extends_float(client: AdditionalPropertiesClient): + body = models.ExtendsFloatAdditionalProperties({"id": 43.125, "prop": 43.125}) + assert client.extends_float.get() == body + client.extends_float.put(body) + + +def test_extends_model(client: AdditionalPropertiesClient): + body = models.ExtendsModelAdditionalProperties({"knownProp": {"state": "ok"}, "prop": {"state": "ok"}}) + assert client.extends_model.get() == body + client.extends_model.put(body) + + +def test_extends_model_array(client: AdditionalPropertiesClient): + body = models.ExtendsModelArrayAdditionalProperties( + { + "knownProp": [{"state": "ok"}, {"state": "ok"}], + "prop": [{"state": "ok"}, {"state": "ok"}], + } + ) + assert client.extends_model_array.get() == body + client.extends_model_array.put(body) + + +def test_extends_string(client: AdditionalPropertiesClient): + body = models.ExtendsStringAdditionalProperties({"name": "ExtendsStringAdditionalProperties", "prop": "abc"}) + assert client.extends_string.get() == body + client.extends_string.put(body) + + +def test_extends_unknown(client: AdditionalPropertiesClient): + body = models.ExtendsUnknownAdditionalProperties( + { + "name": "ExtendsUnknownAdditionalProperties", + "prop1": 32, + "prop2": True, + "prop3": "abc", + } + ) + assert client.extends_unknown.get() == body + client.extends_unknown.put(body) + + +def test_extends_unknown_derived(client: AdditionalPropertiesClient): + body = models.ExtendsUnknownAdditionalPropertiesDerived( + { + "name": "ExtendsUnknownAdditionalProperties", + "index": 314, + "age": 2.71875, + "prop1": 32, + "prop2": True, + "prop3": "abc", + } + ) + assert client.extends_unknown_derived.get() == body + client.extends_unknown_derived.put(body) + + +def test_extends_unknown_discriminated(client: AdditionalPropertiesClient): + body = models.ExtendsUnknownAdditionalPropertiesDiscriminatedDerived( + { + "kind": "derived", + "name": "Derived", + "index": 314, + "age": 2.71875, + "prop1": 32, + "prop2": True, + "prop3": "abc", + } + ) + assert client.extends_unknown_discriminated.get() == body + client.extends_unknown_discriminated.put(body) + + +def test_is_float(client: AdditionalPropertiesClient): + body = models.IsFloatAdditionalProperties({"id": 43.125, "prop": 43.125}) + assert client.is_float.get() == body + client.is_float.put(body) + + +def test_is_model(client: AdditionalPropertiesClient): + body = models.IsModelAdditionalProperties({"knownProp": {"state": "ok"}, "prop": {"state": "ok"}}) + assert client.is_model.get() == body + client.is_model.put(body) + + +def test_is_model_array(client: AdditionalPropertiesClient): + body = models.IsModelArrayAdditionalProperties( + { + "knownProp": [{"state": "ok"}, {"state": "ok"}], + "prop": [{"state": "ok"}, {"state": "ok"}], + } + ) + assert client.is_model_array.get() == body + client.is_model_array.put(body) + + +def test_is_string(client: AdditionalPropertiesClient): + body = models.IsStringAdditionalProperties({"name": "IsStringAdditionalProperties", "prop": "abc"}) + assert client.is_string.get() == body + client.is_string.put(body) + + +def test_is_unknown(client: AdditionalPropertiesClient): + body = models.IsUnknownAdditionalProperties( + { + "name": "IsUnknownAdditionalProperties", + "prop1": 32, + "prop2": True, + "prop3": "abc", + } + ) + assert client.is_unknown.get() == body + client.is_unknown.put(body) + + +def test_is_unknown_derived(client: AdditionalPropertiesClient): + body = models.IsUnknownAdditionalPropertiesDerived( + { + "name": "IsUnknownAdditionalProperties", + "index": 314, + "age": 2.71875, + "prop1": 32, + "prop2": True, + "prop3": "abc", + } + ) + assert client.is_unknown_derived.get() == body + client.is_unknown_derived.put(body) + + +def test_is_unknown_discriminated(client: AdditionalPropertiesClient): + body = models.IsUnknownAdditionalPropertiesDiscriminatedDerived( + { + "kind": "derived", + "name": "Derived", + "index": 314, + "age": 2.71875, + "prop1": 32, + "prop2": True, + "prop3": "abc", + } + ) + assert client.is_unknown_discriminated.get() == body + client.is_unknown_discriminated.put(body) + + +def test_multiple_spread(client: AdditionalPropertiesClient): + body = {"flag": True, "prop1": "abc", "prop2": 43.125} + assert client.multiple_spread.get() == body + client.multiple_spread.put(body) + + +def test_spread_different_float(client: AdditionalPropertiesClient): + body = {"name": "abc", "prop": 43.125} + assert client.spread_different_float.get() == body + client.spread_different_float.put(body) + + +def test_spread_different_model(client: AdditionalPropertiesClient): + body = {"knownProp": "abc", "prop": {"state": "ok"}} + assert client.spread_different_model.get() == body + client.spread_different_model.put(body) + + +def test_spread_different_model_array(client: AdditionalPropertiesClient): + body = {"knownProp": "abc", "prop": [{"state": "ok"}, {"state": "ok"}]} + assert client.spread_different_model_array.get() == body + client.spread_different_model_array.put(body) + + +def test_spread_different_string(client: AdditionalPropertiesClient): + body = {"id": 43.125, "prop": "abc"} + assert client.spread_different_string.get() == body + client.spread_different_string.put(body) + + +def test_spread_model(client: AdditionalPropertiesClient): + body = {"knownProp": {"state": "ok"}, "prop": {"state": "ok"}} + assert client.spread_model.get() == body + client.spread_model.put(body) + + +def test_spread_model_array(client: AdditionalPropertiesClient): + body = { + "knownProp": [{"state": "ok"}, {"state": "ok"}], + "prop": [{"state": "ok"}, {"state": "ok"}], + } + assert client.spread_model_array.get() == body + client.spread_model_array.put(body) + + +def test_spread_record_non_discriminated_union(client: AdditionalPropertiesClient): + body = { + "name": "abc", + "prop1": {"kind": "kind0", "fooProp": "abc"}, + "prop2": { + "kind": "kind1", + "start": "2021-01-01T00:00:00Z", + "end": "2021-01-02T00:00:00Z", + }, + } + assert client.spread_record_non_discriminated_union.get() == body + client.spread_record_non_discriminated_union.put(body) + + +def test_spread_record_non_discriminated_union2(client: AdditionalPropertiesClient): + body = { + "name": "abc", + "prop1": {"kind": "kind1", "start": "2021-01-01T00:00:00Z"}, + "prop2": { + "kind": "kind1", + "start": "2021-01-01T00:00:00Z", + "end": "2021-01-02T00:00:00Z", + }, + } + assert client.spread_record_non_discriminated_union2.get() == body + client.spread_record_non_discriminated_union2.put(body) + + +def test_spread_record_non_discriminated_union3(client: AdditionalPropertiesClient): + body = { + "name": "abc", + "prop1": [ + {"kind": "kind1", "start": "2021-01-01T00:00:00Z"}, + {"kind": "kind1", "start": "2021-01-01T00:00:00Z"}, + ], + "prop2": { + "kind": "kind1", + "start": "2021-01-01T00:00:00Z", + "end": "2021-01-02T00:00:00Z", + }, + } + assert client.spread_record_non_discriminated_union3.get() == body + client.spread_record_non_discriminated_union3.put(body) + + +def test_spread_record_union(client: AdditionalPropertiesClient): + body = {"flag": True, "prop1": "abc", "prop2": 43.125} + assert client.spread_record_union.get() == body + client.spread_record_union.put(body) + + +def test_spread_string(client: AdditionalPropertiesClient): + body = {"name": "SpreadSpringRecord", "prop": "abc"} + assert client.spread_string.get() == body + client.spread_string.put(body) + + +def test_spread_float(client: AdditionalPropertiesClient): + body = {"id": 43.125, "prop": 43.125} + assert client.spread_float.get() == body + client.spread_float.put(body) diff --git a/packages/typespec-python/tests/mock_api/shared/test_typetest_property_nullable.py b/packages/typespec-python/tests/mock_api/shared/test_typetest_property_nullable.py new file mode 100644 index 0000000000..dcf3a44954 --- /dev/null +++ b/packages/typespec-python/tests/mock_api/shared/test_typetest_property_nullable.py @@ -0,0 +1,102 @@ +# cspell: ignore Hdvcmxk +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- +import json +import pytest +from typetest.property.nullable import NullableClient, models +from typetest.property.nullable._utils.model_base import ( # pylint: disable=protected-access + SdkJSONEncoder, +) + +try: + from corehttp.serialization import NULL +except ImportError: + from azure.core.serialization import NULL + + +@pytest.fixture +def client(): + with NullableClient() as client: + yield client + + +def test_bytes(client: NullableClient): + non_null_model = models.BytesProperty(required_property="foo", nullable_property="aGVsbG8sIHdvcmxkIQ==") + non_model = models.BytesProperty(required_property="foo", nullable_property=NULL) + assert '{"requiredProperty": "foo", "nullableProperty": null}' == json.dumps(non_model, cls=SdkJSONEncoder) + assert client.bytes.get_non_null() == non_null_model + assert client.bytes.get_null()["nullableProperty"] is None + client.bytes.patch_non_null(body=non_null_model) + client.bytes.patch_null(body=non_model) + + +def test_collections_byte(client: NullableClient): + non_null_model = models.CollectionsByteProperty( + required_property="foo", + nullable_property=["aGVsbG8sIHdvcmxkIQ==", "aGVsbG8sIHdvcmxkIQ=="], + ) + non_model = models.CollectionsByteProperty(required_property="foo", nullable_property=NULL) + assert '{"requiredProperty": "foo", "nullableProperty": null}' == json.dumps(non_model, cls=SdkJSONEncoder) + assert client.collections_byte.get_non_null() == non_null_model + assert client.collections_byte.get_null()["nullableProperty"] is None + client.collections_byte.patch_non_null(body=non_null_model) + client.collections_byte.patch_null(body=non_model) + + +def test_collections_model(client: NullableClient): + non_null_model = models.CollectionsModelProperty( + required_property="foo", + nullable_property=[ + models.InnerModel(property="hello"), + models.InnerModel(property="world"), + ], + ) + non_model = models.CollectionsModelProperty(required_property="foo", nullable_property=NULL) + assert '{"requiredProperty": "foo", "nullableProperty": null}' == json.dumps(non_model, cls=SdkJSONEncoder) + assert client.collections_model.get_non_null() == non_null_model + assert client.collections_model.get_null()["nullableProperty"] is None + client.collections_model.patch_non_null(body=non_null_model) + client.collections_model.patch_null(body=non_model) + + +def test_collections_string(client: NullableClient): + non_null_model = models.CollectionsStringProperty(required_property="foo", nullable_property=["hello", "world"]) + non_model = models.CollectionsStringProperty(required_property="foo", nullable_property=NULL) + assert '{"requiredProperty": "foo", "nullableProperty": null}' == json.dumps(non_model, cls=SdkJSONEncoder) + assert client.collections_string.get_non_null() == non_null_model + assert client.collections_string.get_null()["nullableProperty"] is None + client.collections_string.patch_non_null(body=non_null_model) + client.collections_string.patch_null(body=non_model) + + +def test_datetime(client: NullableClient): + non_null_model = models.DatetimeProperty(required_property="foo", nullable_property="2022-08-26T18:38:00Z") + non_model = models.DatetimeProperty(required_property="foo", nullable_property=NULL) + assert '{"requiredProperty": "foo", "nullableProperty": null}' == json.dumps(non_model, cls=SdkJSONEncoder) + assert client.datetime.get_non_null() == non_null_model + assert client.datetime.get_null()["nullableProperty"] is None + client.datetime.patch_non_null(body=non_null_model) + client.datetime.patch_null(body=non_model) + + +def test_duration(client: NullableClient): + non_null_model = models.DurationProperty(required_property="foo", nullable_property="P123DT22H14M12.011S") + non_model = models.DurationProperty(required_property="foo", nullable_property=NULL) + assert '{"requiredProperty": "foo", "nullableProperty": null}' == json.dumps(non_model, cls=SdkJSONEncoder) + assert client.duration.get_non_null() == non_null_model + assert client.duration.get_null()["nullableProperty"] is None + client.duration.patch_non_null(body=non_null_model) + client.duration.patch_null(body=non_model) + + +def test_string(client: NullableClient): + non_null_model = models.StringProperty(required_property="foo", nullable_property="hello") + non_model = models.StringProperty(required_property="foo", nullable_property=NULL) + assert '{"requiredProperty": "foo", "nullableProperty": null}' == json.dumps(non_model, cls=SdkJSONEncoder) + assert client.string.get_non_null() == non_null_model + assert client.string.get_null()["nullableProperty"] is None + client.string.patch_non_null(body=non_null_model) + client.string.patch_null(body=non_model) diff --git a/packages/typespec-python/tests/mock_api/shared/test_typetest_property_optional.py b/packages/typespec-python/tests/mock_api/shared/test_typetest_property_optional.py new file mode 100644 index 0000000000..84836538d0 --- /dev/null +++ b/packages/typespec-python/tests/mock_api/shared/test_typetest_property_optional.py @@ -0,0 +1,174 @@ +# cspell: ignore Hdvcmxk +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- +from typing import Any +import pytest +from typetest.property.optional import OptionalClient, models + + +@pytest.fixture +def client(): + with OptionalClient() as client: + yield client + + +def test_boolean_literal(client): + body = models.BooleanLiteralProperty(property=True) + assert client.boolean_literal.get_all() == body + assert client.boolean_literal.get_default() == models.BooleanLiteralProperty() + client.boolean_literal.put_all(body) + client.boolean_literal.put_default(models.BooleanLiteralProperty()) + + +def test_bytes(client): + body = models.BytesProperty(property="aGVsbG8sIHdvcmxkIQ==") + assert client.bytes.get_all() == body + assert client.bytes.get_default() == models.BytesProperty() + client.bytes.put_all(body) + client.bytes.put_default(models.BytesProperty()) + + +def test_collections_byte(client): + body = models.CollectionsByteProperty(property=["aGVsbG8sIHdvcmxkIQ==", "aGVsbG8sIHdvcmxkIQ=="]) + assert client.collections_byte.get_all() == body + assert client.collections_byte.get_default() == models.CollectionsByteProperty() + client.collections_byte.put_all(body) + client.collections_byte.put_default(models.CollectionsByteProperty()) + + +def test_collections_model(client): + body = models.CollectionsModelProperty( + property=[ + models.StringProperty(property="hello"), + models.StringProperty(property="world"), + ] + ) + assert client.collections_model.get_all() == body + assert client.collections_model.get_default() == models.CollectionsModelProperty() + client.collections_model.put_all(body) + client.collections_model.put_default(models.CollectionsModelProperty()) + + +def test_datetime(client): + body = models.DatetimeProperty(property="2022-08-26T18:38:00Z") + assert client.datetime.get_all() == body + assert client.datetime.get_default() == models.DatetimeProperty() + client.datetime.put_all(body) + client.datetime.put_default(models.DatetimeProperty()) + + +def test_duration(client): + body = models.DurationProperty(property="P123DT22H14M12.011S") + assert client.duration.get_all() == body + assert client.duration.get_default() == models.DurationProperty() + client.duration.put_all(body) + client.duration.put_default(models.DurationProperty()) + + +def test_float_literal(client): + body = models.FloatLiteralProperty(property=1.25) + assert client.float_literal.get_all() == body + assert client.float_literal.get_default() == models.FloatLiteralProperty() + client.float_literal.put_all(body) + client.float_literal.put_default(models.FloatLiteralProperty()) + + +def test_int_literal(client): + body = models.IntLiteralProperty(property=1) + assert client.int_literal.get_all() == body + assert client.int_literal.get_default() == models.IntLiteralProperty() + client.int_literal.put_all(body) + client.int_literal.put_default(models.IntLiteralProperty()) + + +def test_plaindate_get_all(client): + body = models.PlainDateProperty(property="2022-12-12") + assert client.plain_date.get_all() == body + + +def test_plaindate_get_default(client): + assert client.plain_date.get_default() == models.PlainDateProperty() + + +def test_plaindate_put_all(client): + body = models.PlainDateProperty(property="2022-12-12") + client.plain_date.put_all(body) + + +def test_plaindate_put_default(client): + client.plain_date.put_default(models.PlainDateProperty()) + + +def test_plaintime_get_all(client): + body = models.PlainTimeProperty(property="13:06:12") + assert client.plain_time.get_all() == body + + +def test_plaintime_get_default(client): + assert client.plain_time.get_default() == models.PlainTimeProperty() + + +def test_plaintime_put_all(client): + body = models.PlainTimeProperty(property="13:06:12") + client.plain_time.put_all(body) + + +def test_plaintime_put_default(client): + client.plain_time.put_default(models.PlainTimeProperty()) + + +def test_required_and_optional(client): + all_body = { + "optionalProperty": "hello", + "requiredProperty": 42, + } + required_only_body = { + "requiredProperty": 42, + } + assert client.required_and_optional.get_all() == all_body + assert client.required_and_optional.get_required_only() == required_only_body + client.required_and_optional.put_all(all_body) + client.required_and_optional.put_required_only(required_only_body) + + +def test_string(client): + body = models.StringProperty(property="hello") + assert client.string.get_all() == body + assert client.string.get_default() == models.StringProperty() + client.string.put_all(body) + client.string.put_default(models.StringProperty()) + + +def test_string_literal(client): + body = models.StringLiteralProperty(property="hello") + assert client.string_literal.get_all() == body + assert client.string_literal.get_default() == models.StringLiteralProperty() + client.string_literal.put_all(body) + client.string_literal.put_default(models.StringLiteralProperty()) + + +def test_union_float_literal(client): + body = models.UnionFloatLiteralProperty(property=2.375) + assert client.union_float_literal.get_all() == body + assert client.union_float_literal.get_default() == models.UnionFloatLiteralProperty() + client.union_float_literal.put_all(body) + client.union_float_literal.put_default(models.UnionFloatLiteralProperty()) + + +def test_union_int_literal(client): + body = models.UnionIntLiteralProperty(property=2) + assert client.union_int_literal.get_all() == body + assert client.union_int_literal.get_default() == models.UnionIntLiteralProperty() + client.union_int_literal.put_all(body) + client.union_int_literal.put_default(models.UnionIntLiteralProperty()) + + +def test_union_string_literal(client): + body = models.UnionStringLiteralProperty(property="world") + assert client.union_string_literal.get_all() == body + assert client.union_string_literal.get_default() == models.UnionStringLiteralProperty() + client.union_string_literal.put_all(body) + client.union_string_literal.put_default(models.UnionStringLiteralProperty()) diff --git a/packages/typespec-python/tests/mock_api/shared/test_typetest_property_valuetypes.py b/packages/typespec-python/tests/mock_api/shared/test_typetest_property_valuetypes.py new file mode 100644 index 0000000000..faabc4c707 --- /dev/null +++ b/packages/typespec-python/tests/mock_api/shared/test_typetest_property_valuetypes.py @@ -0,0 +1,286 @@ +# cspell: ignore Hdvcmxk +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- +from calendar import c +import decimal + +import pytest +import datetime +from typetest.property.valuetypes import ValueTypesClient, models + + +@pytest.fixture +def client(): + with ValueTypesClient() as client: + yield client + + +def test_boolean(client: ValueTypesClient): + body = models.BooleanProperty(property=True) + assert body.property == body["property"] + client.boolean.put(body) + + resp = client.boolean.get() + assert resp.property == resp["property"] == True + + +def test_boolean_literal(client: ValueTypesClient): + body = models.BooleanLiteralProperty(property=True) + assert body.property == body["property"] + client.boolean_literal.put(body) + + resp = client.boolean_literal.get() + assert resp.property == resp["property"] == True + + +def test_bytes(client: ValueTypesClient): + body = models.BytesProperty(property=b"hello, world!") + assert body.property == b"hello, world!" + assert body["property"] == "aGVsbG8sIHdvcmxkIQ==" + client.bytes.put(body) + + resp = client.bytes.get() + assert resp.property == b"hello, world!" + assert resp["property"] == "aGVsbG8sIHdvcmxkIQ==" + + +def test_collections_int(client: ValueTypesClient): + body = models.CollectionsIntProperty(property=[1, 2]) + assert body.property == body["property"] + client.collections_int.put(body) + + resp = client.collections_int.get() + assert resp.property == resp["property"] == [1, 2] + + +def test_collections_model(client: ValueTypesClient): + body = models.CollectionsModelProperty(property=[{"property": "hello"}, {"property": "world"}]) + assert body.property[0].property == body["property"][0]["property"] + client.collections_model.put(body) + + resp = client.collections_model.get() + assert resp.property[1].property == resp["property"][1]["property"] + + +def test_collections_string(client: ValueTypesClient): + body = models.CollectionsStringProperty(property=["hello", "world"]) + assert body.property == body["property"] + client.collections_string.put(body) + + resp = client.collections_string.get() + assert resp.property == resp["property"] == ["hello", "world"] + + +def test_datetime(client): + received_body = client.datetime.get() + assert received_body == {"property": "2022-08-26T18:38:00Z"} + assert received_body.property.year == 2022 + assert received_body.property.month == 8 + assert received_body.property.day == 26 + assert received_body.property.hour == 18 + assert received_body.property.minute == 38 + + client.datetime.put(models.DatetimeProperty(property=datetime.datetime(2022, 8, 26, hour=18, minute=38))) + + +def test_decimal(client: ValueTypesClient): + body = models.DecimalProperty(property=decimal.Decimal("0.33333")) + assert body.property == decimal.Decimal("0.33333") + assert body["property"] == 0.33333 + client.decimal.put(body) + + resp = client.decimal.get() + assert resp.property == decimal.Decimal("0.33333") + assert resp["property"] == 0.33333 + + +def test_decimal128(client: ValueTypesClient): + body = models.Decimal128Property(property=decimal.Decimal("0.33333")) + assert body.property == decimal.Decimal("0.33333") + assert body["property"] == 0.33333 + client.decimal128.put(body) + + resp = client.decimal128.get() + assert resp.property == decimal.Decimal("0.33333") + assert resp["property"] == 0.33333 + + +def test_dictionary_string(client: ValueTypesClient): + body = models.DictionaryStringProperty(property={"k1": "hello", "k2": "world"}) + assert body.property == body["property"] + client.dictionary_string.put(body) + + resp = client.dictionary_string.get() + assert resp.property == resp["property"] == {"k1": "hello", "k2": "world"} + + +def test_duration(client: ValueTypesClient): + body = models.DurationProperty(property="P123DT22H14M12.011S") + assert body.property == datetime.timedelta(days=123, seconds=80052, microseconds=11000) + assert body["property"] == "P123DT22H14M12.011S" + client.duration.put(body) + + resp = client.duration.get() + assert resp.property == datetime.timedelta(days=123, seconds=80052, microseconds=11000) + assert resp["property"] == "P123DT22H14M12.011S" + + +def test_enum(client: ValueTypesClient): + body = models.EnumProperty(property=models.InnerEnum.VALUE_ONE) + assert body.property == body["property"] + client.enum.put(body) + + resp = client.enum.get() + assert resp.property == resp["property"] == "ValueOne" + + +def test_extensible_enum(client: ValueTypesClient): + body = models.ExtensibleEnumProperty(property="UnknownValue") + assert body.property == body["property"] + client.extensible_enum.put(body) + + resp = client.extensible_enum.get() + assert resp.property == resp["property"] == "UnknownValue" + + +def test_float(client: ValueTypesClient): + body = models.FloatProperty(property=43.125) + assert body.property == body["property"] + client.float.put(body) + + resp = client.float.get() + assert resp.property == resp["property"] == 43.125 + + +def test_float_literal(client: ValueTypesClient): + body = models.FloatLiteralProperty(property=43.125) + assert body.property == body["property"] + client.float_literal.put(body) + + resp = client.float_literal.get() + assert resp.property == resp["property"] == 43.125 + + +def test_int(client: ValueTypesClient): + body = models.IntProperty(property=42) + assert body.property == body["property"] + client.int_operations.put(body) + + resp = client.int_operations.get() + assert resp.property == resp["property"] == 42 + + +def test_int_literal(client: ValueTypesClient): + body = models.IntLiteralProperty(property=42) + assert body.property == body["property"] + client.int_literal.put(body) + + resp = client.int_literal.get() + assert resp.property == resp["property"] == 42 + + +def test_model(client: ValueTypesClient): + body = models.ModelProperty(property={"property": "hello"}) + assert body.property.property == body["property"]["property"] + client.model.put(body) + + resp = client.model.get() + assert resp.property.property == resp["property"]["property"] + + +def test_never(client: ValueTypesClient): + assert client.never.get() == models.NeverProperty() + client.never.put(models.NeverProperty()) + + +def test_string(client: ValueTypesClient): + body = models.StringProperty(property="hello") + assert body.property == body["property"] + client.string.put(body) + + resp = client.string.get() + assert resp.property == resp["property"] == "hello" + + +def test_string_literal(client: ValueTypesClient): + body = models.StringLiteralProperty(property="hello") + assert body.property == body["property"] + client.string_literal.put(body) + + resp = client.string_literal.get() + assert resp.property == resp["property"] == "hello" + + +def test_union_enum_value(client: ValueTypesClient): + body = models.UnionEnumValueProperty(property=models.ExtendedEnum.ENUM_VALUE2) + assert body.property == body["property"] + client.union_enum_value.put(body) + + resp = client.union_enum_value.get() + assert resp.property == resp["property"] == "value2" + + +def test_union_float_literal(client: ValueTypesClient): + body = models.UnionFloatLiteralProperty(property=46.875) + assert body.property == body["property"] + client.union_float_literal.put(body) + + resp = client.union_float_literal.get() + assert resp.property == resp["property"] == 46.875 + + +def test_union_int_literal(client: ValueTypesClient): + body = models.UnionIntLiteralProperty(property=42) + assert body.property == body["property"] + client.union_int_literal.put(body) + + resp = client.union_int_literal.get() + assert resp.property == resp["property"] == 42 + + +def test_union_string_literal(client: ValueTypesClient): + body = models.UnionStringLiteralProperty(property="world") + assert body.property == body["property"] + client.union_string_literal.put(body) + + resp = client.union_string_literal.get() + assert resp.property == resp["property"] == "world" + + +def test_unknown_array(client: ValueTypesClient): + body = models.UnknownArrayProperty(property=["hello", "world"]) + assert body.property == body["property"] + client.unknown_array.put(body) + + resp = client.unknown_array.get() + assert resp.property == resp["property"] == ["hello", "world"] + + +def test_unknown_dict(client: ValueTypesClient): + body = models.UnknownDictProperty(property={"k1": "hello", "k2": 42}) + assert body.property == body["property"] + client.unknown_dict.put(body) + + resp = client.unknown_dict.get() + assert resp.property == resp["property"] == {"k1": "hello", "k2": 42} + + +def test_unknown_int(client: ValueTypesClient): + body = models.UnknownIntProperty(property=42) + assert body.property == body["property"] + client.unknown_int.put(body) + + resp = client.unknown_int.get() + assert resp.property == resp["property"] == 42 + + +def test_unknown_string(client: ValueTypesClient): + body = models.UnknownStringProperty(property="hello") + assert body.property == body["property"] + client.unknown_string.put(body) + + resp = client.unknown_string.get() + assert resp.property == resp["property"] == "hello" diff --git a/packages/typespec-python/tests/mock_api/shared/test_typetest_scalar.py b/packages/typespec-python/tests/mock_api/shared/test_typetest_scalar.py new file mode 100644 index 0000000000..32a1583ac1 --- /dev/null +++ b/packages/typespec-python/tests/mock_api/shared/test_typetest_scalar.py @@ -0,0 +1,53 @@ +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- +import decimal +from functools import reduce + +import pytest +from typetest.scalar import ScalarClient + + +@pytest.fixture +def client(): + with ScalarClient() as client: + yield client + + +def test_scalar_string(client: ScalarClient): + assert client.string.get() == "test" + client.string.put("test") + + +def test_scalar_boolean(client: ScalarClient): + assert client.boolean.get() == True + client.boolean.put(True) + + +def test_scalar_unknown(client: ScalarClient): + assert client.unknown.get() == "test" + client.unknown.put("test") + + +def test_decimal128_type(client: ScalarClient): + assert client.decimal128_type.response_body() == decimal.Decimal("0.33333") + client.decimal128_type.request_body(decimal.Decimal("0.33333")) + client.decimal128_type.request_parameter(value=decimal.Decimal("0.33333")) + + +def test_decimal_type(client: ScalarClient): + assert client.decimal_type.response_body() == decimal.Decimal("0.33333") + client.decimal_type.request_body(decimal.Decimal("0.33333")) + client.decimal_type.request_parameter(value=decimal.Decimal("0.33333")) + + +def test_decimal128_verify(client: ScalarClient): + prepare = client.decimal128_verify.prepare_verify() + client.decimal128_verify.verify(reduce(lambda x, y: x + y, prepare)) + + +def test_decimal_verify(client: ScalarClient): + prepare = client.decimal_verify.prepare_verify() + client.decimal_verify.verify(reduce(lambda x, y: x + y, prepare)) diff --git a/packages/typespec-python/tests/mock_api/shared/test_typetest_union.py b/packages/typespec-python/tests/mock_api/shared/test_typetest_union.py new file mode 100644 index 0000000000..3ca676d10a --- /dev/null +++ b/packages/typespec-python/tests/mock_api/shared/test_typetest_union.py @@ -0,0 +1,80 @@ +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- +import pytest +from typetest.union import UnionClient +from typetest.union import models + + +@pytest.fixture +def client(): + with UnionClient() as client: + yield client + + +def test_enums_only(client: UnionClient): + value = models.EnumsOnlyCases(lr="right", ud="up") + assert client.enums_only.get() == {"prop": value} + client.enums_only.send(prop=value) + + +def test_floats_only(client: UnionClient): + value = 2.2 + assert client.floats_only.get() == {"prop": value} + client.floats_only.send(prop=value) + + +def test_ints_only(client: UnionClient): + value = 2 + assert client.ints_only.get() == {"prop": value} + client.ints_only.send(prop=value) + + +def test_mixed_literals(client: UnionClient): + value = models.MixedLiteralsCases(string_literal="a", int_literal=2, float_literal=3.3, boolean_literal=True) + assert client.mixed_literals.get() == {"prop": value} + client.mixed_literals.send(prop=value) + + +def test_mixed_types(client: UnionClient): + value = models.MixedTypesCases( + model=models.Cat(name="test"), + literal="a", + int_property=2, + boolean=True, + array=[models.Cat(name="test"), "a", 2, True], + ) + assert client.mixed_types.get() == {"prop": value} + client.mixed_types.send(prop=value) + + +def test_models_only(client: UnionClient): + value = models.Cat(name="test") + assert client.models_only.get() == {"prop": value} + client.models_only.send(prop=value) + + +def test_string_and_array(client: UnionClient): + value = models.StringAndArrayCases(string="test", array=["test1", "test2"]) + assert client.string_and_array.get() == {"prop": value} + client.string_and_array.send(prop=value) + + +def test_string_extensible(client: UnionClient): + value = "custom" + assert client.string_extensible.get() == {"prop": value} + client.string_extensible.send(prop=value) + + +def test_string_extensible_named(client: UnionClient): + value = "custom" + assert client.string_extensible_named.get() == {"prop": value} + client.string_extensible_named.send(prop=value) + + +def test_strings_only(client: UnionClient): + value = "b" + assert client.strings_only.get() == {"prop": value} + client.strings_only.send(prop=value) diff --git a/packages/typespec-python/tests/mock_api/shared/test_typetest_union_discriminated.py b/packages/typespec-python/tests/mock_api/shared/test_typetest_union_discriminated.py new file mode 100644 index 0000000000..2b031c9fef --- /dev/null +++ b/packages/typespec-python/tests/mock_api/shared/test_typetest_union_discriminated.py @@ -0,0 +1,290 @@ +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- +import pytest +from typetest.discriminatedunion import DiscriminatedClient +from typetest.discriminatedunion import models + + +@pytest.fixture +def client(): + with DiscriminatedClient() as client: + yield client + + +@pytest.fixture +def cat_body(): + """Cat model for testing.""" + return models.Cat(name="Whiskers", meow=True) + + +@pytest.fixture +def dog_body(): + """Dog model for testing.""" + return models.Dog(name="Rex", bark=False) + + +# Tests for No Envelope / Default (inline discriminator with "kind") +@pytest.mark.skip(reason="After completely support discriminated unions, enable these tests") +class TestNoEnvelopeDefault: + """Test discriminated union with inline discriminator (no envelope).""" + + def test_get_default_cat(self, client: DiscriminatedClient, cat_body: models.Cat): + """Test getting cat with default (no query param or kind=cat). + + Expected response: + { + "kind": "cat", + "name": "Whiskers", + "meow": true + } + """ + result = client.no_envelope.default.get() + assert result == cat_body + assert isinstance(result, models.Cat) + + def test_get_with_kind_cat(self, client: DiscriminatedClient, cat_body: models.Cat): + """Test getting cat with kind=cat query parameter. + + Expected response: + { + "kind": "cat", + "name": "Whiskers", + "meow": true + } + """ + result = client.no_envelope.default.get(kind="cat") + assert result == cat_body + assert isinstance(result, models.Cat) + + def test_get_with_kind_dog(self, client: DiscriminatedClient, dog_body: models.Dog): + """Test getting dog with kind=dog query parameter. + + Expected response: + { + "kind": "dog", + "name": "Rex", + "bark": false + } + """ + result = client.no_envelope.default.get(kind="dog") + assert result == dog_body + assert isinstance(result, models.Dog) + + def test_put_cat(self, client: DiscriminatedClient, cat_body: models.Cat): + """Test sending cat with inline discriminator. + + Expected request: + { + "kind": "cat", + "name": "Whiskers", + "meow": true + } + """ + result = client.no_envelope.default.put(cat_body) + assert result == cat_body + assert isinstance(result, models.Cat) + + +# Tests for No Envelope / Custom Discriminator (inline with custom "type" property) +@pytest.mark.skip(reason="After completely support discriminated unions, enable these tests") +class TestNoEnvelopeCustomDiscriminator: + """Test discriminated union with inline discriminator and custom discriminator property name.""" + + def test_get_default_cat(self, client: DiscriminatedClient, cat_body: models.Cat): + """Test getting cat with default (no query param or type=cat). + + Expected response: + { + "type": "cat", + "name": "Whiskers", + "meow": true + } + """ + result = client.no_envelope.custom_discriminator.get() + assert result == cat_body + assert isinstance(result, models.Cat) + + def test_get_with_type_cat(self, client: DiscriminatedClient, cat_body: models.Cat): + """Test getting cat with type=cat query parameter. + + Expected response: + { + "type": "cat", + "name": "Whiskers", + "meow": true + } + """ + result = client.no_envelope.custom_discriminator.get(type="cat") + assert result == cat_body + assert isinstance(result, models.Cat) + + def test_get_with_type_dog(self, client: DiscriminatedClient, dog_body: models.Dog): + """Test getting dog with type=dog query parameter. + + Expected response: + { + "type": "dog", + "name": "Rex", + "bark": false + } + """ + result = client.no_envelope.custom_discriminator.get(type="dog") + assert result == dog_body + assert isinstance(result, models.Dog) + + def test_put_cat(self, client: DiscriminatedClient, cat_body: models.Cat): + """Test sending cat with inline custom discriminator. + + Expected request: + { + "type": "cat", + "name": "Whiskers", + "meow": true + } + """ + result = client.no_envelope.custom_discriminator.put(cat_body) + assert result == cat_body + assert isinstance(result, models.Cat) + + +# Tests for Envelope / Object / Default (envelope with "kind" and "value") +@pytest.mark.skip(reason="After completely support discriminated unions, enable these tests") +class TestEnvelopeObjectDefault: + """Test discriminated union with default envelope serialization.""" + + def test_get_default_cat(self, client: DiscriminatedClient, cat_body: models.Cat): + """Test getting cat with default (no query param or kind=cat). + + Expected response: + { + "kind": "cat", + "value": { + "name": "Whiskers", + "meow": true + } + } + """ + result = client.envelope.object.default.get() + assert result == cat_body + assert isinstance(result, models.Cat) + + def test_get_with_kind_cat(self, client: DiscriminatedClient, cat_body: models.Cat): + """Test getting cat with kind=cat query parameter. + + Expected response: + { + "kind": "cat", + "value": { + "name": "Whiskers", + "meow": true + } + } + """ + result = client.envelope.object.default.get(kind="cat") + assert result == cat_body + assert isinstance(result, models.Cat) + + def test_get_with_kind_dog(self, client: DiscriminatedClient, dog_body: models.Dog): + """Test getting dog with kind=dog query parameter. + + Expected response: + { + "kind": "dog", + "value": { + "name": "Rex", + "bark": false + } + } + """ + result = client.envelope.object.default.get(kind="dog") + assert result == dog_body + assert isinstance(result, models.Dog) + + def test_put_cat(self, client: DiscriminatedClient, cat_body: models.Cat): + """Test sending cat with envelope serialization. + + Expected request: + { + "kind": "cat", + "value": { + "name": "Whiskers", + "meow": true + } + } + """ + result = client.envelope.object.default.put(cat_body) + assert result == cat_body + assert isinstance(result, models.Cat) + + +# Tests for Envelope / Object / Custom Properties (envelope with custom "petType" and "petData") +@pytest.mark.skip(reason="After completely support discriminated unions, enable these tests") +class TestEnvelopeObjectCustomProperties: + """Test discriminated union with custom property names in envelope.""" + + def test_get_default_cat(self, client: DiscriminatedClient, cat_body: models.Cat): + """Test getting cat with default (no query param or petType=cat). + + Expected response: + { + "petType": "cat", + "petData": { + "name": "Whiskers", + "meow": true + } + } + """ + result = client.envelope.object.custom_properties.get() + assert result == cat_body + assert isinstance(result, models.Cat) + + def test_get_with_pet_type_cat(self, client: DiscriminatedClient, cat_body: models.Cat): + """Test getting cat with petType=cat query parameter. + + Expected response: + { + "petType": "cat", + "petData": { + "name": "Whiskers", + "meow": true + } + } + """ + result = client.envelope.object.custom_properties.get(pet_type="cat") + assert result == cat_body + assert isinstance(result, models.Cat) + + def test_get_with_pet_type_dog(self, client: DiscriminatedClient, dog_body: models.Dog): + """Test getting dog with petType=dog query parameter. + + Expected response: + { + "petType": "dog", + "petData": { + "name": "Rex", + "bark": false + } + } + """ + result = client.envelope.object.custom_properties.get(pet_type="dog") + assert result == dog_body + assert isinstance(result, models.Dog) + + def test_put_cat(self, client: DiscriminatedClient, cat_body: models.Cat): + """Test sending cat with custom property names in envelope. + + Expected request: + { + "petType": "cat", + "petData": { + "name": "Whiskers", + "meow": true + } + } + """ + result = client.envelope.object.custom_properties.put(cat_body) + assert result == cat_body + assert isinstance(result, models.Cat) diff --git a/packages/typespec-python/tests/mock_api/shared/test_versioning_added.py b/packages/typespec-python/tests/mock_api/shared/test_versioning_added.py new file mode 100644 index 0000000000..c51b159cba --- /dev/null +++ b/packages/typespec-python/tests/mock_api/shared/test_versioning_added.py @@ -0,0 +1,33 @@ +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- +import pytest +from versioning.added import AddedClient +from versioning.added.models import ModelV1, ModelV2, EnumV1, EnumV2 + + +@pytest.fixture +def client(): + with AddedClient(endpoint="http://localhost:3000", version="v2") as client: + yield client + + +def test_v1(client: AddedClient): + assert client.v1( + ModelV1(prop="foo", enum_prop=EnumV1.ENUM_MEMBER_V2, union_prop=10), + header_v2="bar", + ) == ModelV1(prop="foo", enum_prop=EnumV1.ENUM_MEMBER_V2, union_prop=10) + + +def test_v2(client: AddedClient): + assert client.v2(ModelV2(prop="foo", enum_prop=EnumV2.ENUM_MEMBER, union_prop="bar")) == ModelV2( + prop="foo", enum_prop=EnumV2.ENUM_MEMBER, union_prop="bar" + ) + + +def test_interface_v2(client: AddedClient): + assert client.interface_v2.v2_in_interface( + ModelV2(prop="foo", enum_prop=EnumV2.ENUM_MEMBER, union_prop="bar") + ) == ModelV2(prop="foo", enum_prop=EnumV2.ENUM_MEMBER, union_prop="bar") diff --git a/packages/typespec-python/tests/mock_api/shared/test_versioning_made_optional.py b/packages/typespec-python/tests/mock_api/shared/test_versioning_made_optional.py new file mode 100644 index 0000000000..52099a04b7 --- /dev/null +++ b/packages/typespec-python/tests/mock_api/shared/test_versioning_made_optional.py @@ -0,0 +1,20 @@ +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- +import pytest +from versioning.madeoptional import MadeOptionalClient +from versioning.madeoptional.models import TestModel + + +@pytest.fixture +def client(): + with MadeOptionalClient(endpoint="http://localhost:3000", version="v2") as client: + yield client + + +def test(client: MadeOptionalClient): + assert client.test( + TestModel(prop="foo"), + ) == TestModel(prop="foo") diff --git a/packages/typespec-python/tests/mock_api/shared/test_versioning_removed.py b/packages/typespec-python/tests/mock_api/shared/test_versioning_removed.py new file mode 100644 index 0000000000..ad5fb01d1a --- /dev/null +++ b/packages/typespec-python/tests/mock_api/shared/test_versioning_removed.py @@ -0,0 +1,37 @@ +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- +import pytest +from versioning.removed import RemovedClient +from versioning.removed.models import ModelV2, EnumV2, ModelV3, EnumV3 + + +@pytest.fixture +def client(): + with RemovedClient(endpoint="http://localhost:3000", version="v2") as client: + yield client + + +def test_v2(client: RemovedClient): + assert client.v2(ModelV2(prop="foo", enum_prop=EnumV2.ENUM_MEMBER_V2, union_prop="bar")) == ModelV2( + prop="foo", enum_prop=EnumV2.ENUM_MEMBER_V2, union_prop="bar" + ) + + +def test_model_v3(): + client1 = RemovedClient(endpoint="http://localhost:3000", version="v1") + model1 = ModelV3(id="123", enum_prop=EnumV3.ENUM_MEMBER_V1) + result = client1.model_v3(model1) + assert result == model1 + + client2 = RemovedClient(endpoint="http://localhost:3000", version="v2preview") + model2 = ModelV3(id="123") + result = client2.model_v3(model2) + assert result == model2 + + client3 = RemovedClient(endpoint="http://localhost:3000", version="v2") + model3 = ModelV3(id="123", enum_prop=EnumV3.ENUM_MEMBER_V1) + result = client3.model_v3(model3) + assert result == model3 diff --git a/packages/typespec-python/tests/mock_api/shared/test_versioning_renamed_from.py b/packages/typespec-python/tests/mock_api/shared/test_versioning_renamed_from.py new file mode 100644 index 0000000000..d81f258713 --- /dev/null +++ b/packages/typespec-python/tests/mock_api/shared/test_versioning_renamed_from.py @@ -0,0 +1,27 @@ +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- +import pytest +from versioning.renamedfrom import RenamedFromClient +from versioning.renamedfrom.models import NewModel, NewEnum + + +@pytest.fixture +def client(): + with RenamedFromClient(endpoint="http://localhost:3000", version="v2") as client: + yield client + + +def test_new_op(client: RenamedFromClient): + assert client.new_op( + NewModel(new_prop="foo", enum_prop=NewEnum.NEW_ENUM_MEMBER, union_prop=10), + new_query="bar", + ) == NewModel(new_prop="foo", enum_prop=NewEnum.NEW_ENUM_MEMBER, union_prop=10) + + +def test_new_interface_test(client: RenamedFromClient): + assert client.new_interface.new_op_in_new_interface( + NewModel(new_prop="foo", enum_prop=NewEnum.NEW_ENUM_MEMBER, union_prop=10) + ) == NewModel(new_prop="foo", enum_prop=NewEnum.NEW_ENUM_MEMBER, union_prop=10) diff --git a/packages/typespec-python/tests/mock_api/shared/test_versioning_return_type_changed_from.py b/packages/typespec-python/tests/mock_api/shared/test_versioning_return_type_changed_from.py new file mode 100644 index 0000000000..92decc7204 --- /dev/null +++ b/packages/typespec-python/tests/mock_api/shared/test_versioning_return_type_changed_from.py @@ -0,0 +1,17 @@ +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- +import pytest +from versioning.returntypechangedfrom import ReturnTypeChangedFromClient + + +@pytest.fixture +def client(): + with ReturnTypeChangedFromClient(endpoint="http://localhost:3000", version="v2") as client: + yield client + + +def test(client: ReturnTypeChangedFromClient): + assert client.test("test") == "test" diff --git a/packages/typespec-python/tests/mock_api/shared/test_versioning_type_changed_from.py b/packages/typespec-python/tests/mock_api/shared/test_versioning_type_changed_from.py new file mode 100644 index 0000000000..e10742a815 --- /dev/null +++ b/packages/typespec-python/tests/mock_api/shared/test_versioning_type_changed_from.py @@ -0,0 +1,21 @@ +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- +import pytest +from versioning.typechangedfrom import TypeChangedFromClient +from versioning.typechangedfrom.models import TestModel + + +@pytest.fixture +def client(): + with TypeChangedFromClient(endpoint="http://localhost:3000", version="v2") as client: + yield client + + +def test(client: TypeChangedFromClient): + assert client.test( + TestModel(prop="foo", changed_prop="bar"), + param="baz", + ) == TestModel(prop="foo", changed_prop="bar") diff --git a/packages/typespec-python/tests/mock_api/shared/unittests/test_parse_pyproject.py b/packages/typespec-python/tests/mock_api/shared/unittests/test_parse_pyproject.py new file mode 100644 index 0000000000..8ebf108f29 --- /dev/null +++ b/packages/typespec-python/tests/mock_api/shared/unittests/test_parse_pyproject.py @@ -0,0 +1,95 @@ +from pathlib import Path +from typing import Dict, Any + +try: + import tomllib +except ImportError: + import tomli as tomllib + + +def check_no_setup_py(package_path: str) -> None: + """ + Check that setup.py does not exist in the package directory. + + Args: + package_path: Relative path to the package directory + + Raises: + AssertionError: If setup.py exists in the package directory + """ + package_dir = Path(__file__).parent / package_path + setup_py_path = package_dir / "setup.py" + + assert not setup_py_path.exists(), f"setup.py should not exist at {setup_py_path} when using pyproject.toml" + + +def get_pyproject_section(package_path: str, section_name: str) -> Dict[str, Any]: + """ + Get a specific section from a package's pyproject.toml file. + + Args: + package_path: Relative path to the package directory containing pyproject.toml + section_name: Dot-separated section name (e.g., "tool.azure-sdk-build") + + Returns: + Dictionary containing the section data + + Raises: + AssertionError: If pyproject.toml not found or section missing + """ + try: + # Convert to absolute path and find pyproject.toml + package_dir = Path(__file__).parent / package_path + pyproject_path = package_dir / "pyproject.toml" + + # Assert pyproject.toml exists + assert pyproject_path.exists(), f"pyproject.toml not found at {pyproject_path}" + + # Parse pyproject.toml + with open(pyproject_path, "rb") as f: + data = tomllib.load(f) + + # Check that the project name matches the folder name + if "project" in data and "name" in data["project"]: + expected_name = package_dir.name + actual_name = data["project"]["name"] + assert ( + actual_name == expected_name + ), f"Project name '{actual_name}' in pyproject.toml does not match folder name '{expected_name}'" + + # Navigate to the requested section + section_parts = section_name.split(".") + current_data = data + + for part in section_parts: + assert ( + part in current_data + ), f"pyproject.toml does not contain [{'.'.join(section_parts[:section_parts.index(part)+1])}] section" + current_data = current_data[part] + + return current_data + + except Exception as e: + raise AssertionError(f"Error checking pyproject.toml at '{package_path}': {e}") + + +def test_azure_sdk_build(): + """Test that authentication-union packages have pyproject.toml with [tool.azure-sdk-build] pyright = false.""" + + # Need to check the file directly, since installed distribution metadata won't include custom sections. + test_paths = ["../../../generated/azure/authentication-union"] + + for package_path in test_paths: + # First check that setup.py doesn't exist + check_no_setup_py(package_path) + + # Get the [tool.azure-sdk-build] section + azure_sdk_build = get_pyproject_section(package_path, "tool.azure-sdk-build") + + # Check for pyright = false + assert ( + "pyright" in azure_sdk_build + ), f"[tool.azure-sdk-build] section does not contain 'pyright' setting in {package_path}" + assert ( + azure_sdk_build["pyright"] is False + ), f"Expected pyright = false, but got pyright = {azure_sdk_build['pyright']} in {package_path}" \ No newline at end of file diff --git a/packages/typespec-python/tests/mock_api/shared/unittests/test_readme.py b/packages/typespec-python/tests/mock_api/shared/unittests/test_readme.py new file mode 100644 index 0000000000..133f680d9e --- /dev/null +++ b/packages/typespec-python/tests/mock_api/shared/unittests/test_readme.py @@ -0,0 +1,46 @@ +from pathlib import Path + +import pytest + +GENERATED_DIR = Path(__file__).parent / "../../../generated" +FLAVORS = ("azure", "unbranded") + +# Folders that exist in the azure-sdk-for-python baseline checkout but are not +# regenerated by the emitter, so their README.md is never (re)written. Skip +# them to keep this test focused on real generated packages. +# - "azure/service-multiple-services": listed in SKIP_SPECS in +# eng/scripts/ci/regenerate-common.ts (no emitter run for this spec). +# - "azure/azure-client-generator-core-client-initialization": orphan parent +# folder; only its sub-specs (.../default, .../individually, +# .../individuallyParent) are actually emitted as packages. +SKIP_PACKAGES = { + ("azure", "service-multiple-services"), + ("azure", "azure-client-generator-core-client-initialization"), +} + + +def _package_dirs(): + base = GENERATED_DIR.resolve() + dirs = [] + for flavor in FLAVORS: + flavor_dir = base / flavor + if not flavor_dir.is_dir(): + continue + for p in sorted(flavor_dir.iterdir()): + if not p.is_dir(): + continue + if (flavor, p.name) in SKIP_PACKAGES: + continue + dirs.append(p) + return dirs + + +@pytest.mark.parametrize( + "package_dir", + _package_dirs(), + ids=lambda p: f"{p.parent.name}/{p.name}", +) +def test_readme_exists(package_dir: Path): + """Each generated SDK package folder (azure & unbranded) must contain a README.md.""" + readme_path = package_dir / "README.md" + assert readme_path.is_file(), f"README.md not found at {readme_path}" diff --git a/packages/typespec-python/tests/mock_api/unbranded/asynctests/test_auth_flow_async.py b/packages/typespec-python/tests/mock_api/unbranded/asynctests/test_auth_flow_async.py new file mode 100644 index 0000000000..5ad8263c4b --- /dev/null +++ b/packages/typespec-python/tests/mock_api/unbranded/asynctests/test_auth_flow_async.py @@ -0,0 +1,19 @@ +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- +import pytest +from authentication.oauth2.aio import OAuth2Client + + +@pytest.mark.asyncio +async def test_oauth2_auth_flows(): + oauth2_client = OAuth2Client("fake_credential") + assert oauth2_client._config.authentication_policy._auth_flows == [ + { + "authorizationUrl": "https://login.microsoftonline.com/common/oauth2/authorize", + "scopes": [{"value": "https://security.microsoft.com/.default"}], + "type": "implicit", + } + ] diff --git a/packages/typespec-python/tests/mock_api/unbranded/asynctests/test_encode_duration_async.py b/packages/typespec-python/tests/mock_api/unbranded/asynctests/test_encode_duration_async.py new file mode 100644 index 0000000000..2b0716dc98 --- /dev/null +++ b/packages/typespec-python/tests/mock_api/unbranded/asynctests/test_encode_duration_async.py @@ -0,0 +1,64 @@ +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- +import datetime + +import pytest +import pytest_asyncio +from encode.duration.aio import DurationClient +from encode.duration.property.models import ( + Int32SecondsDurationProperty, + ISO8601DurationProperty, + FloatSecondsDurationProperty, + DefaultDurationProperty, + FloatSecondsDurationArrayProperty, +) + + +@pytest_asyncio.fixture +async def client(): + async with DurationClient() as client: + yield client + + +@pytest.mark.asyncio +async def test_query(client: DurationClient): + await client.query.default(input=datetime.timedelta(days=40)) + await client.query.iso8601(input=datetime.timedelta(days=40)) + await client.query.int32_seconds(input=36) + await client.query.int32_seconds_array(input=[36, 47]) + await client.query.float_seconds(input=35.625) + await client.query.float64_seconds(input=35.625) + + +@pytest.mark.asyncio +async def test_property(client: DurationClient): + result = await client.property.default(DefaultDurationProperty(value=datetime.timedelta(days=40))) + assert result.value == datetime.timedelta(days=40) + result = await client.property.default(DefaultDurationProperty(value="P40D")) + assert result.value == datetime.timedelta(days=40) + result = await client.property.iso8601(ISO8601DurationProperty(value=datetime.timedelta(days=40))) + assert result.value == datetime.timedelta(days=40) + result = await client.property.iso8601(ISO8601DurationProperty(value="P40D")) + assert result.value == datetime.timedelta(days=40) + result = await client.property.int32_seconds(Int32SecondsDurationProperty(value=36)) + assert result.value == 36 + result = await client.property.float_seconds(FloatSecondsDurationProperty(value=35.625)) + assert abs(result.value - 35.625) < 0.0001 + result = await client.property.float64_seconds(FloatSecondsDurationProperty(value=35.625)) + assert abs(result.value - 35.625) < 0.0001 + result = await client.property.float_seconds_array(FloatSecondsDurationArrayProperty(value=[35.625, 46.75])) + assert abs(result.value[0] - 35.625) < 0.0001 + assert abs(result.value[1] - 46.75) < 0.0001 + + +@pytest.mark.asyncio +async def test_header(client: DurationClient): + await client.header.default(duration=datetime.timedelta(days=40)) + await client.header.iso8601(duration=datetime.timedelta(days=40)) + await client.header.iso8601_array(duration=[datetime.timedelta(days=40), datetime.timedelta(days=50)]) + await client.header.int32_seconds(duration=36) + await client.header.float_seconds(duration=35.625) + await client.header.float64_seconds(duration=35.625) diff --git a/packages/typespec-python/tests/mock_api/unbranded/asynctests/test_encode_numeric_async.py b/packages/typespec-python/tests/mock_api/unbranded/asynctests/test_encode_numeric_async.py new file mode 100644 index 0000000000..244f2ee0e1 --- /dev/null +++ b/packages/typespec-python/tests/mock_api/unbranded/asynctests/test_encode_numeric_async.py @@ -0,0 +1,36 @@ +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- +import pytest +import pytest_asyncio +from encode.numeric.aio import NumericClient +from encode.numeric.property import models + + +@pytest_asyncio.fixture +async def client(): + async with NumericClient() as client: + yield client + + +@pytest.mark.asyncio +async def test_safeint_as_string(client: NumericClient): + result = await client.property.safeint_as_string(models.SafeintAsStringProperty(value=10000000000)) + assert result.value == 10000000000 + assert result["value"] == "10000000000" + + +@pytest.mark.asyncio +async def test_uint32_as_string_optional(client: NumericClient): + result = await client.property.uint32_as_string_optional(models.Uint32AsStringProperty(value=1)) + assert result.value == 1 + assert result["value"] == "1" + + +@pytest.mark.asyncio +async def test_uint8_as_string_optional(client: NumericClient): + result = await client.property.uint8_as_string(models.Uint32AsStringProperty(value=255)) + assert result.value == 255 + assert result["value"] == "255" diff --git a/packages/typespec-python/tests/mock_api/unbranded/asynctests/test_parameters_basic_async.py b/packages/typespec-python/tests/mock_api/unbranded/asynctests/test_parameters_basic_async.py new file mode 100644 index 0000000000..f6d8c58a93 --- /dev/null +++ b/packages/typespec-python/tests/mock_api/unbranded/asynctests/test_parameters_basic_async.py @@ -0,0 +1,25 @@ +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- +import pytest +import pytest_asyncio +from parameters.basic.aio import BasicClient +from parameters.basic.explicitbody.models import User + + +@pytest_asyncio.fixture +async def client(): + async with BasicClient() as client: + yield client + + +@pytest.mark.asyncio +async def test_explicit_simple(client: BasicClient): + await client.explicit_body.simple(User(name="foo")) + + +@pytest.mark.asyncio +async def test_implicit_simple(client: BasicClient): + await client.implicit_body.simple(name="foo") diff --git a/packages/typespec-python/tests/mock_api/unbranded/asynctests/test_parameters_spread_async.py b/packages/typespec-python/tests/mock_api/unbranded/asynctests/test_parameters_spread_async.py new file mode 100644 index 0000000000..57de584d84 --- /dev/null +++ b/packages/typespec-python/tests/mock_api/unbranded/asynctests/test_parameters_spread_async.py @@ -0,0 +1,77 @@ +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- +import pytest +import pytest_asyncio +from parameters.spread.aio import SpreadClient +from parameters.spread.model.models import BodyParameter + + +@pytest_asyncio.fixture +async def client(): + async with SpreadClient() as client: + yield client + + +@pytest.mark.asyncio +async def test_model_body(client: SpreadClient): + await client.model.spread_as_request_body(name="foo") + + +@pytest.mark.asyncio +async def test_model_composite_request_only_with_body(client: SpreadClient): + await client.model.spread_composite_request_only_with_body(BodyParameter(name="foo")) + + +@pytest.mark.asyncio +async def test_model_composite_request_without_body(client: SpreadClient): + await client.model.spread_composite_request_without_body(name="foo", test_header="bar") + + +@pytest.mark.asyncio +async def test_model_composite_request(client: SpreadClient): + await client.model.spread_composite_request(name="foo", body=BodyParameter(name="foo"), test_header="bar") + + +@pytest.mark.asyncio +async def test_model_composite_request_mix(client: SpreadClient): + await client.model.spread_composite_request_mix(name="foo", prop="foo", test_header="bar") + + +@pytest.mark.asyncio +async def test_alias_body(client: SpreadClient): + await client.alias.spread_as_request_body(name="foo") + + +@pytest.mark.asyncio +async def test_alias_parameter(client: SpreadClient): + await client.alias.spread_as_request_parameter("1", x_ms_test_header="bar", name="foo") + + +@pytest.mark.asyncio +async def test_alias_multiple_parameter(client: SpreadClient): + await client.alias.spread_with_multiple_parameters( + "1", + x_ms_test_header="bar", + required_string="foo", + required_int_list=[1, 2], + optional_string_list=["foo", "bar"], + optional_int=1, + ) + await client.alias.spread_with_multiple_parameters( + "1", + {"requiredString": "foo", "optionalInt": 1, "requiredIntList": [1, 2], "optionalStringList": ["foo", "bar"]}, + x_ms_test_header="bar", + ) + + +@pytest.mark.asyncio +async def test_inner_model(client: SpreadClient): + await client.alias.spread_parameter_with_inner_model(id="1", x_ms_test_header="bar", body={"name": "foo"}) + + +@pytest.mark.asyncio +async def test_inner_alias(client: SpreadClient): + await client.alias.spread_parameter_with_inner_alias(id="1", x_ms_test_header="bar", body={"name": "foo", "age": 1}) diff --git a/packages/typespec-python/tests/mock_api/unbranded/asynctests/test_payload_content_negotiation_async.py b/packages/typespec-python/tests/mock_api/unbranded/asynctests/test_payload_content_negotiation_async.py new file mode 100644 index 0000000000..3dd1cc324b --- /dev/null +++ b/packages/typespec-python/tests/mock_api/unbranded/asynctests/test_payload_content_negotiation_async.py @@ -0,0 +1,38 @@ +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- +import base64 +import pytest +import pytest_asyncio +from payload.contentnegotiation.aio import ContentNegotiationClient +from payload.contentnegotiation.differentbody.models import PngImageAsJson + + +@pytest_asyncio.fixture +async def client(): + async with ContentNegotiationClient(endpoint="http://localhost:3000") as client: + yield client + + +@pytest.mark.asyncio +async def test_get_avatar_as_png(client: ContentNegotiationClient, png_data: bytes): + assert b"".join([d async for d in (await client.same_body.get_avatar_as_png())]) == png_data + + +@pytest.mark.asyncio +async def test_get_avatar_as_jpeg(client: ContentNegotiationClient, jpg_data: bytes): + assert b"".join([d async for d in (await client.same_body.get_avatar_as_jpeg())]) == jpg_data + + +@pytest.mark.asyncio +async def test_different_body_get_avatar_as_png(client: ContentNegotiationClient, png_data: bytes): + assert b"".join([d async for d in (await client.different_body.get_avatar_as_png())]) == png_data + + +@pytest.mark.asyncio +async def test_different_body_get_avatar_as_json(client: ContentNegotiationClient, png_data: bytes): + result = await client.different_body.get_avatar_as_json() + expected = PngImageAsJson(content=base64.b64encode(png_data).decode()) + assert result == expected diff --git a/packages/typespec-python/tests/mock_api/unbranded/asynctests/test_payload_multipart_async.py b/packages/typespec-python/tests/mock_api/unbranded/asynctests/test_payload_multipart_async.py new file mode 100644 index 0000000000..b5197313bf --- /dev/null +++ b/packages/typespec-python/tests/mock_api/unbranded/asynctests/test_payload_multipart_async.py @@ -0,0 +1,219 @@ +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- +from pathlib import Path +import pytest +import pytest_asyncio +from payload.multipart import models +from payload.multipart.aio import MultiPartClient +from payload.multipart.formdata.httpparts.nonstring.models import FloatRequest +from payload.multipart.formdata.file import models as file_models + +JPG = Path(__file__).parent.parent / "data/image.jpg" +PNG = Path(__file__).parent.parent / "data/image.png" + + +@pytest_asyncio.fixture +async def client(): + async with MultiPartClient(endpoint="http://localhost:3000") as client: + yield client + + +@pytest.mark.asyncio +async def test_anonymous_model(client: MultiPartClient): + await client.form_data.anonymous_model({"profileImage": open(str(JPG), "rb")}) + + +@pytest.mark.asyncio +async def test_basic(client: MultiPartClient): + await client.form_data.basic( + models.MultiPartRequest( + id="123", + profile_image=open(str(JPG), "rb"), + ) + ) + + +@pytest.mark.asyncio +async def test_binary_array_parts(client: MultiPartClient): + await client.form_data.binary_array_parts( + models.BinaryArrayPartsRequest( + id="123", + pictures=[ + open(str(PNG), "rb"), + open(str(PNG), "rb"), + ], + ) + ) + + +@pytest.mark.asyncio +async def test_check_file_name_and_content_type(client: MultiPartClient): + await client.form_data.check_file_name_and_content_type( + models.MultiPartRequest( + id="123", + profile_image=("hello.jpg", open(str(JPG), "rb"), "image/jpg"), + ) + ) + + +@pytest.mark.asyncio +async def test_complex(client: MultiPartClient): + await client.form_data.file_array_and_basic( + models.ComplexPartsRequest( + id="123", + address=models.Address(city="X"), + pictures=[ + open(str(PNG), "rb"), + open(str(PNG), "rb"), + ], + profile_image=open(str(JPG), "rb"), + ) + ) + + +@pytest.mark.asyncio +async def test_json_part(client: MultiPartClient): + await client.form_data.json_part( + models.JsonPartRequest( + address=models.Address(city="X"), + profile_image=open(str(JPG), "rb"), + ) + ) + + +@pytest.mark.asyncio +async def test_multi_binary_parts(client: MultiPartClient): + await client.form_data.multi_binary_parts( + models.MultiBinaryPartsRequest( + profile_image=open(str(JPG), "rb"), + picture=open(str(PNG), "rb"), + ) + ) + await client.form_data.multi_binary_parts( + models.MultiBinaryPartsRequest( + profile_image=open(str(JPG), "rb"), + ) + ) + + +@pytest.mark.asyncio +async def test_file_with_http_part_specific_content_type(client: MultiPartClient): + await client.form_data.http_parts.content_type.image_jpeg_content_type( + models.FileWithHttpPartSpecificContentTypeRequest( + profile_image=("hello.jpg", open(str(JPG), "rb"), "image/jpg"), + ) + ) + + +@pytest.mark.asyncio +async def test_file_with_http_part_required_content_type(client: MultiPartClient): + await client.form_data.http_parts.content_type.required_content_type( + models.FileWithHttpPartRequiredContentTypeRequest( + profile_image=open(str(JPG), "rb"), + ) + ) + + +@pytest.mark.asyncio +async def test_file_with_http_part_optional_content_type(client: MultiPartClient): + # call twice: one with content type, one without + await client.form_data.http_parts.content_type.optional_content_type( + models.FileWithHttpPartOptionalContentTypeRequest( + profile_image=("hello.jpg", open(str(JPG), "rb").read()), + ) + ) + await client.form_data.http_parts.content_type.optional_content_type( + models.FileWithHttpPartOptionalContentTypeRequest( + profile_image=("hello.jpg", open(str(JPG), "rb").read(), "application/octet-stream"), + ) + ) + + +@pytest.mark.asyncio +async def test_complex_with_http_part(client: MultiPartClient): + await client.form_data.http_parts.json_array_and_file_array( + models.ComplexHttpPartsModelRequest( + id="123", + previous_addresses=[ + models.Address(city="Y"), + models.Address(city="Z"), + ], + address=models.Address(city="X"), + pictures=[ + open(str(PNG), "rb"), + open(str(PNG), "rb"), + ], + profile_image=open(str(JPG), "rb"), + ) + ) + + +@pytest.mark.asyncio +async def test_http_parts_non_string_float(client: MultiPartClient): + await client.form_data.http_parts.non_string.float(FloatRequest(temperature=0.5)) + + +@pytest.mark.asyncio +async def test_with_wire_name(client: MultiPartClient): + await client.form_data.with_wire_name( + models.MultiPartRequestWithWireName( + identifier="123", + image=open(str(JPG), "rb"), + ) + ) + + +@pytest.mark.asyncio +async def test_optional_parts(client: MultiPartClient): + # First time with only id + await client.form_data.optional_parts( + models.MultiPartOptionalRequest( + id="123", + ) + ) + # Second time with only profileImage + await client.form_data.optional_parts( + models.MultiPartOptionalRequest( + profile_image=open(str(JPG), "rb"), + ) + ) + # Third time with both id and profileImage + await client.form_data.optional_parts( + models.MultiPartOptionalRequest( + id="123", + profile_image=open(str(JPG), "rb"), + ) + ) + + +@pytest.mark.asyncio +async def test_file_upload_file_specific_content_type(client: MultiPartClient): + await client.form_data.file.upload_file_specific_content_type( + file_models.UploadFileSpecificContentTypeRequest( + file=("image.png", open(str(PNG), "rb"), "image/png"), + ) + ) + + +@pytest.mark.asyncio +async def test_file_upload_file_required_filename(client: MultiPartClient): + await client.form_data.file.upload_file_required_filename( + file_models.UploadFileRequiredFilenameRequest( + file=("image.png", open(str(PNG), "rb"), "image/png"), + ) + ) + + +@pytest.mark.asyncio +async def test_file_upload_file_array(client: MultiPartClient): + await client.form_data.file.upload_file_array( + file_models.UploadFileArrayRequest( + files=[ + ("image.png", open(str(PNG), "rb"), "image/png"), + ("image.png", open(str(PNG), "rb"), "image/png"), + ], + ) + ) diff --git a/packages/typespec-python/tests/mock_api/unbranded/asynctests/test_serialization_encoded_name_json_async.py b/packages/typespec-python/tests/mock_api/unbranded/asynctests/test_serialization_encoded_name_json_async.py new file mode 100644 index 0000000000..c03899fe7e --- /dev/null +++ b/packages/typespec-python/tests/mock_api/unbranded/asynctests/test_serialization_encoded_name_json_async.py @@ -0,0 +1,25 @@ +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- +import pytest +import pytest_asyncio +from serialization.encodedname.json.aio import JsonClient +from serialization.encodedname.json.property import models + + +@pytest_asyncio.fixture +async def client(): + async with JsonClient() as client: + yield client + + +@pytest.mark.asyncio +async def test_property_send(client: JsonClient): + await client.property.send(models.JsonEncodedNameModel(default_name=True)) + + +@pytest.mark.asyncio +async def test_property_get(client: JsonClient): + assert (await client.property.get()).default_name diff --git a/packages/typespec-python/tests/mock_api/unbranded/asynctests/test_special_words_async.py b/packages/typespec-python/tests/mock_api/unbranded/asynctests/test_special_words_async.py new file mode 100644 index 0000000000..c1e3bc0a8f --- /dev/null +++ b/packages/typespec-python/tests/mock_api/unbranded/asynctests/test_special_words_async.py @@ -0,0 +1,74 @@ +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- +import pytest +import pytest_asyncio +from specialwords.aio import SpecialWordsClient +from specialwords.models import models +from specialwords.modelproperties import models as model_properties_models +from specialwords.extensiblestrings import models as extensible_strings_models + + +@pytest_asyncio.fixture +async def client(): + async with SpecialWordsClient() as client: + yield client + + +@pytest.mark.asyncio +async def test_operations(client: SpecialWordsClient, special_words): + for sw in special_words: + suffix = "" if sw == "constructor" else "_method" + await getattr(client.operations, sw + suffix)() + + +@pytest.mark.asyncio +async def test_parameter(client: SpecialWordsClient, special_words): + for sw in special_words: + suffix = "" if sw == "constructor" else "_parameter" + await getattr(client.parameters, "with_" + sw)(**{sw + suffix: "ok"}) + await client.parameters.with_cancellation_token(cancellation_token="ok") + + +@pytest.mark.asyncio +async def test_model(client: SpecialWordsClient, special_words): + for sw in special_words: + suffix = "" if sw == "constructor" else "Model" + model = getattr(models, sw.capitalize() + suffix) + await getattr(client.models, "with_" + sw)(model(name="ok")) + + +@pytest.mark.asyncio +async def test_model_properties(client: SpecialWordsClient): + await client.model_properties.same_as_model(model_properties_models.SameAsModel(same_as_model="ok")) + + +@pytest.mark.asyncio +async def test_model_properties_dict_methods(client: SpecialWordsClient): + await client.model_properties.dict_methods( + body=model_properties_models.DictMethods( + keys_property="ok", + items_property="ok", + values_property="ok", + popitem_property="ok", + clear_property="ok", + update_property="ok", + setdefault_property="ok", + pop_property="ok", + get_property="ok", + copy_property="ok", + ) + ) + + +@pytest.mark.asyncio +async def test_model_properties_with_list(client: SpecialWordsClient): + await client.model_properties.with_list(model_properties_models.ModelWithList(list="ok")) + + +@pytest.mark.asyncio +async def test_extensible_strings(client: SpecialWordsClient): + for enum_value in extensible_strings_models.ExtensibleString: + assert enum_value == await client.extensible_strings.put_extensible_string_value(body=enum_value) diff --git a/packages/typespec-python/tests/mock_api/unbranded/asynctests/test_unbranded_async.py b/packages/typespec-python/tests/mock_api/unbranded/asynctests/test_unbranded_async.py new file mode 100644 index 0000000000..0218d8578e --- /dev/null +++ b/packages/typespec-python/tests/mock_api/unbranded/asynctests/test_unbranded_async.py @@ -0,0 +1,25 @@ +# ------------------------------------ +# Copyright (c) Microsoft Corporation. +# Licensed under the MIT License. +# ------------------------------------ +import traceback +import pytest +import pytest_asyncio +from typetest.scalar.aio import ScalarClient +from corehttp.exceptions import HttpResponseError + + +@pytest_asyncio.fixture +async def client(): + async with ScalarClient() as client: + yield client + + +@pytest.mark.asyncio +async def test_track_back(client: ScalarClient): + try: + await client.string.put("to raise exception") + except HttpResponseError: + track_back = traceback.format_exc().lower() + assert "azure" not in track_back + assert "microsoft" not in track_back diff --git a/packages/typespec-python/tests/mock_api/unbranded/conftest.py b/packages/typespec-python/tests/mock_api/unbranded/conftest.py new file mode 100644 index 0000000000..df7cb9efbe --- /dev/null +++ b/packages/typespec-python/tests/mock_api/unbranded/conftest.py @@ -0,0 +1,63 @@ +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- +import pytest +from pathlib import Path + +FILE_FOLDER = Path(__file__).parent + + +SPECIAL_WORDS = [ + "and", + "as", + "assert", + "async", + "await", + "break", + "class", + "constructor", + "continue", + "def", + "del", + "elif", + "else", + "except", + "exec", + "finally", + "for", + "from", + "global", + "if", + "import", + "in", + "is", + "lambda", + "not", + "or", + "pass", + "raise", + "return", + "try", + "while", + "with", + "yield", +] + + +@pytest.fixture +def special_words() -> list[str]: + return SPECIAL_WORDS + + +@pytest.fixture +def png_data() -> bytes: + with open(str(FILE_FOLDER / "data/image.png"), "rb") as file_in: + return file_in.read() + + +@pytest.fixture +def jpg_data() -> bytes: + with open(str(FILE_FOLDER / "data/image.jpg"), "rb") as file_in: + return file_in.read() diff --git a/packages/typespec-python/tests/mock_api/unbranded/data/image.jpg b/packages/typespec-python/tests/mock_api/unbranded/data/image.jpg new file mode 100644 index 0000000000000000000000000000000000000000..b95b3e7b58286ad3e665d98d48b345977f862403 GIT binary patch literal 4069 zcmeHJX;@QN8a_8Gn*#{~QJ4uNv1G6$BrHN6AVrn}mbL^3a4V7!OhA&51QRm!5kx@+ zTNcGZ6cC$Q+;~`GASla}wUxz{#c@GKXr)k4Y@<*!Hx%*D{OB`(hxgoj&v(xGzVDv* zyZ1cLYZx{>23FxAVIcs504RVPFpPlD9#xbBu1V2)YXM|gXB#0R#?0;vho@Ai`n{4K2Z_tc-vVNE8}_H8C|ahaEIl00AM92ow^HM!{MR`W#*d zC>$E^#0bDxN5*4GscV^8g=bC3n`_%`I5%f0?p)~sQ!`sT!n*Yv-gBn@)y2cpYm>JR zD=;WH4t_4#kAFVxjHXs&7-n{@yDwxhGFyQlZNTet7ry*D&GGCKBT{NGO}CV%+x+1&FN z^Dlq-RsZU>kryl_f2RdM|0^#X%nN}+AyHT(F9@M9633y?P7Dk_AQBs&YE5EhnXKJh zc(%6PlpPs~<`z2kKs1OmhoPzVGH-Zu)3MZ>_F zVvR60H(i4HGS)1?$_V@l3~&{b9rK09ND}!zi#oLh#Ro!~r%~ ztf@M>v0>6|AHFNXRdW{F2PwyE*zd{a+%36uhi4yu9aJ^ zpE7`9t8Rioz2KlN=S`ybbp-7ElQg->VN&I!l@n$S;9H_)yZXl$&PTX9ZObWvjhcE$f>gQt?~wSk)wt*@QfJ9e zFelD#>m0AB_sUj(c%Hr(E_yV;phB&=i9g9-)lO~OzQ2==_`u&bT{~<52lxK#Ow_NO zH{&-1-x&aQ;LQ0M(Zy$<1nTsq)xvVR{*&=ztX;IOz6|@z-F$Uf=(W0nyex6{P>FpW z4;0_dipualIew@$bH3M?aaJh~zSVba_s(ZYwY`7uX0rQ=C{sn1g*}wrL&Zt0cwal& z|(+)A&#XhLRoSPH3mt4Ji?-$~1F~yma)AnXu zRaaV$2SjEq$b{PVCY+v+iL;w8BOWVxgqdDst2gCLzog0=vM#q5L^ScNF_ipEjeb6n z1J0h4Y=S>iPa2P#Wgqq@^xWzm>-n^78z*$sXAucKo}EO|0uu3 zLs)^AUypvJF<+QUj|p5L&+NFzk0eJN%fi)?Gy8fd4jBz;gBAkjn_MPYks`G3a33&nP_o zg=l|nT>VF<@}|PZtIypU-TXbb#NA#UwTKA877jAo-sRoA;|O7M!oq~_ndaKA)cm{QH_jPuzCA+J zs!aHNWSYHBYfaj3>w14Gdb?$=t7cDh+;r%rP@Vlr;qGatS1nE0#?Fk+V2@G6gWq0G nRDbTJ{wDPH&YhvRw~$ZQH=nuD@w!Nwq+ZJbRY$2v!^nRCgjEVM literal 0 HcmV?d00001 diff --git a/packages/typespec-python/tests/mock_api/unbranded/data/image.png b/packages/typespec-python/tests/mock_api/unbranded/data/image.png new file mode 100644 index 0000000000000000000000000000000000000000..42fe8dc14560b0046bf0f3f00b7a471fa0346e36 GIT binary patch literal 2992 zcmaJ>2UJtr5=}ynfPe^6#i)oP2~A3b_#j9P<c=;9z@urf$wEd&r0Smmc~ z4b}n)eX~PAprkO6@Q)ZL0M}MJAZwiOD16}zNDSD?0g_k*{=o$NMUbCNY?07U9S+2S zEZop`b^yBJDZ#-+YAA`O;C(9uFi4PXy{I6N!uB-*+qrI=1#0z#xnpTqM+_2ABESQJ zNP)p{I)S{F2V_P^0xBVx7N9{V941ncbaU9Z2qd7dnGrCJZy~e@a~RgqMFUNu1Zx<< zb>X@&6jVb)!;BJi2rs64KWLg-BsIiteAdnPEGl#*}3jJK)-!qsV_Nx++`r}x@ z0TF8+gdSWM@iR9-HCwYHUBc+WhrO)A2tdz(8Yn{}vv1-5tZHzM{I(Zu9;;%|=s zCVEhVDQFS_C`d#7x~w1M-<>~*W{9LqLSH=UG`#0SvISvT&z^Cv#7@xJSx2aa-|9tm}-z6Hc>u#KDm+I4F>M3G9RmW+_?M2)1;gWo3xcVR@W8PHPH4h8*{++h z8}Y5F9`(=WPeZXH<+|Y0gJnwP5YL?0zo!3|^aN{T{s{OKE?O45QM0I0;1yDN`SND{ zyOg5mp)N5c(u0Esp-E=kfllR0C&k1s@i0GrZRfs5<7!+x0s^%ugM8%*ef;#PiEVR~ zk~180fRXw!|2qMhFy2QQNA)X#rKKLKFql@YS0DB+8Y~M0L6l6MBxAd5adGjcF9c8t zo3^yHG!i%{(t~?+_KjG%t?wg9W@hGn@>d^2zlX4eDsq69+{GOYhow*ZZ9YFY+;qgj z#AWZ^z2xho`YaYJ$mptuez>fhT&9eIf;49^mEC)&XN9ajcTsqPhD7C%d`TOUID=@6 zW~%vaGf31w{D~F5LO*H9Ul5b;M$_L~@5Rf{$YXmij@GSqZ($ztNsv;Z`i@;wgI)yL z`tVD3-D4YatT^h!2`{f7xgFBk(KVv6D=iyOe>q)Zxtu3f1vhZeoRRfQZ3s>DQ~|{c zhLZ7j^pqm{@Kbe|+)KiSAs)dZlW4Rb|0>x!mf7eaT?yRGZFm;h)5lP}0s z)MR+lRu=;7XofSxFZS5kB(Io?U<4$)=j+Ujv-f1z7}jT(U8oBF@c2?YjHZlX3}y?2 zB}I!j)%5LcxOt457x{YKwWQLqjkl*P!m*TD-H`cTuN{_G`e(Occ-dLa=;vA%@*AOg(a(z}6t_crT&EO-&+m4gF>N0h;BXG0?{Bi7 z`CMs0?IQEIN_yrvkTId}4tcQlLFDsm2){A5T)eb!$m;U*9bpNnS{u9Nur=c6{IY zKC28T*@~?E=+fvG1A<0jF;cm0Q(bSl;8d`tTUme#<>4g zLGy3~(+z4auzTu_$wj7=5_bmr4M3i>XprZ8-8A{ z^S%T(i(@^t7G<(wYTc~P^uFuDm}iOCg0RJbylL{6l)E9&xd*ipG|e`)b?b`n)|`3$ z>k`idS@_lp+*>nk7_W2qvLHrYsnN9VjcdkaYxRqWdf5!mZ8vsD^2e%lG>7`oaP1~( z91eF(@?7&4^jE^(0w>-(Xig#TL8J;KX+2YL&fdmGjCA1!I<+uYch0=ri`kM?G=Uz= zYe(%m$g6gpfYRA}M3Wh=PjV`BA|f`Ajz1QY-KfS$+mLC&=*M@CqU0@-843#@s!tp+ z`hXG_$T+w$%ZRc;oA!hozBo{U_AgR)cc2=ist%Tf1!goyZ`H}XSr9&UY zJ^9hCDY9E_U|L$j^3{t+O$rDP^WqxkQ)&F;Eh@Hsx^<};S#~>%t}R_YRkG7OjOT7s&BTd5F;H{&a{d!BS5Vz@RgwkT{dwhcQ zPGno6OlTdu0KU{d<)>5lyi9d5Rz$1ros^mpW_coXd{r;;5w~?!YUHbE$=hL2`F`si x55d?S>E1-idha0G3zgVNNXgr$|KG8qZJn`L2pQ~%2Sy6WZoiY&ZA<_7e*r@k8!Z3; literal 0 HcmV?d00001 diff --git a/packages/typespec-python/tests/mock_api/unbranded/test_auth_flow.py b/packages/typespec-python/tests/mock_api/unbranded/test_auth_flow.py new file mode 100644 index 0000000000..4aa857b020 --- /dev/null +++ b/packages/typespec-python/tests/mock_api/unbranded/test_auth_flow.py @@ -0,0 +1,17 @@ +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- +from authentication.oauth2 import OAuth2Client + + +def test_oauth2_auth_flows(): + oauth2_client = OAuth2Client("fake_credential") + assert oauth2_client._config.authentication_policy._auth_flows == [ + { + "authorizationUrl": "https://login.microsoftonline.com/common/oauth2/authorize", + "scopes": [{"value": "https://security.microsoft.com/.default"}], + "type": "implicit", + } + ] diff --git a/packages/typespec-python/tests/mock_api/unbranded/test_encode_duration.py b/packages/typespec-python/tests/mock_api/unbranded/test_encode_duration.py new file mode 100644 index 0000000000..6025a3670d --- /dev/null +++ b/packages/typespec-python/tests/mock_api/unbranded/test_encode_duration.py @@ -0,0 +1,60 @@ +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- +import datetime + +import pytest +from encode.duration import DurationClient +from encode.duration.property.models import ( + Int32SecondsDurationProperty, + ISO8601DurationProperty, + FloatSecondsDurationProperty, + DefaultDurationProperty, + FloatSecondsDurationArrayProperty, +) + + +@pytest.fixture +def client(): + with DurationClient() as client: + yield client + + +def test_query(client: DurationClient): + client.query.default(input=datetime.timedelta(days=40)) + client.query.iso8601(input=datetime.timedelta(days=40)) + client.query.int32_seconds(input=36) + client.query.int32_seconds_array(input=[36, 47]) + client.query.float_seconds(input=35.625) + client.query.float64_seconds(input=35.625) + + +def test_property(client: DurationClient): + result = client.property.default(DefaultDurationProperty(value=datetime.timedelta(days=40))) + assert result.value == datetime.timedelta(days=40) + result = client.property.default(DefaultDurationProperty(value="P40D")) + assert result.value == datetime.timedelta(days=40) + result = client.property.iso8601(ISO8601DurationProperty(value=datetime.timedelta(days=40))) + assert result.value == datetime.timedelta(days=40) + result = client.property.iso8601(ISO8601DurationProperty(value="P40D")) + assert result.value == datetime.timedelta(days=40) + result = client.property.int32_seconds(Int32SecondsDurationProperty(value=36)) + assert result.value == 36 + result = client.property.float_seconds(FloatSecondsDurationProperty(value=35.625)) + assert abs(result.value - 35.625) < 0.0001 + result = client.property.float64_seconds(FloatSecondsDurationProperty(value=35.625)) + assert abs(result.value - 35.625) < 0.0001 + result = client.property.float_seconds_array(FloatSecondsDurationArrayProperty(value=[35.625, 46.75])) + assert abs(result.value[0] - 35.625) < 0.0001 + assert abs(result.value[1] - 46.75) < 0.0001 + + +def test_header(client: DurationClient): + client.header.default(duration=datetime.timedelta(days=40)) + client.header.iso8601(duration=datetime.timedelta(days=40)) + client.header.iso8601_array(duration=[datetime.timedelta(days=40), datetime.timedelta(days=50)]) + client.header.int32_seconds(duration=36) + client.header.float_seconds(duration=35.625) + client.header.float64_seconds(duration=35.625) diff --git a/packages/typespec-python/tests/mock_api/unbranded/test_encode_numeric.py b/packages/typespec-python/tests/mock_api/unbranded/test_encode_numeric.py new file mode 100644 index 0000000000..cf5468ef89 --- /dev/null +++ b/packages/typespec-python/tests/mock_api/unbranded/test_encode_numeric.py @@ -0,0 +1,32 @@ +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- +import pytest +from encode.numeric import NumericClient +from encode.numeric.property import models + + +@pytest.fixture +def client(): + with NumericClient() as client: + yield client + + +def test_safeint_as_string(client: NumericClient): + result = client.property.safeint_as_string(models.SafeintAsStringProperty(value=10000000000)) + assert result.value == 10000000000 + assert result["value"] == "10000000000" + + +def test_uint32_as_string_optional(client: NumericClient): + result = client.property.uint32_as_string_optional(models.Uint32AsStringProperty(value=1)) + assert result.value == 1 + assert result["value"] == "1" + + +def test_uint8_as_string_optional(client: NumericClient): + result = client.property.uint8_as_string(models.Uint32AsStringProperty(value=255)) + assert result.value == 255 + assert result["value"] == "255" diff --git a/packages/typespec-python/tests/mock_api/unbranded/test_parameters_basic.py b/packages/typespec-python/tests/mock_api/unbranded/test_parameters_basic.py new file mode 100644 index 0000000000..c6e82422e0 --- /dev/null +++ b/packages/typespec-python/tests/mock_api/unbranded/test_parameters_basic.py @@ -0,0 +1,22 @@ +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- +import pytest +from parameters.basic import BasicClient +from parameters.basic.explicitbody.models import User + + +@pytest.fixture +def client(): + with BasicClient() as client: + yield client + + +def test_explicit_simple(client: BasicClient): + client.explicit_body.simple(User(name="foo")) + + +def test_implicit_simple(client: BasicClient): + client.implicit_body.simple(name="foo") diff --git a/packages/typespec-python/tests/mock_api/unbranded/test_parameters_spread.py b/packages/typespec-python/tests/mock_api/unbranded/test_parameters_spread.py new file mode 100644 index 0000000000..ff649a40ed --- /dev/null +++ b/packages/typespec-python/tests/mock_api/unbranded/test_parameters_spread.py @@ -0,0 +1,66 @@ +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- +import pytest +from parameters.spread import SpreadClient +from parameters.spread.model.models import BodyParameter + + +@pytest.fixture +def client(): + with SpreadClient() as client: + yield client + + +def test_model_body(client: SpreadClient): + client.model.spread_as_request_body(name="foo") + + +def test_model_composite_request_only_with_body(client: SpreadClient): + client.model.spread_composite_request_only_with_body(BodyParameter(name="foo")) + + +def test_model_composite_request_without_body(client: SpreadClient): + client.model.spread_composite_request_without_body(name="foo", test_header="bar") + + +def test_model_composite_request(client: SpreadClient): + client.model.spread_composite_request(name="foo", body=BodyParameter(name="foo"), test_header="bar") + + +def test_model_composite_request_mix(client: SpreadClient): + client.model.spread_composite_request_mix(name="foo", prop="foo", test_header="bar") + + +def test_alias_body(client: SpreadClient): + client.alias.spread_as_request_body(name="foo") + + +def test_alias_parameter(client: SpreadClient): + client.alias.spread_as_request_parameter("1", x_ms_test_header="bar", name="foo") + + +def test_alias_multiple_parameter(client: SpreadClient): + client.alias.spread_with_multiple_parameters( + "1", + x_ms_test_header="bar", + required_string="foo", + required_int_list=[1, 2], + optional_string_list=["foo", "bar"], + optional_int=1, + ) + client.alias.spread_with_multiple_parameters( + "1", + {"requiredString": "foo", "optionalInt": 1, "requiredIntList": [1, 2], "optionalStringList": ["foo", "bar"]}, + x_ms_test_header="bar", + ) + + +def test_inner_model(client: SpreadClient): + client.alias.spread_parameter_with_inner_model(id="1", x_ms_test_header="bar", body={"name": "foo"}) + + +def test_inner_alias(client: SpreadClient): + client.alias.spread_parameter_with_inner_alias(id="1", x_ms_test_header="bar", body={"name": "foo", "age": 1}) diff --git a/packages/typespec-python/tests/mock_api/unbranded/test_payload_content_negotiation.py b/packages/typespec-python/tests/mock_api/unbranded/test_payload_content_negotiation.py new file mode 100644 index 0000000000..e683de73a0 --- /dev/null +++ b/packages/typespec-python/tests/mock_api/unbranded/test_payload_content_negotiation.py @@ -0,0 +1,33 @@ +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- +import base64 +import pytest +from payload.contentnegotiation import ContentNegotiationClient +from payload.contentnegotiation.differentbody.models import PngImageAsJson + + +@pytest.fixture +def client(): + with ContentNegotiationClient(endpoint="http://localhost:3000") as client: + yield client + + +def test_get_avatar_as_png(client: ContentNegotiationClient, png_data: bytes): + assert b"".join(client.same_body.get_avatar_as_png()) == png_data + + +def test_get_avatar_as_jpeg(client: ContentNegotiationClient, jpg_data: bytes): + assert b"".join(client.same_body.get_avatar_as_jpeg()) == jpg_data + + +def test_different_body_get_avatar_as_png(client: ContentNegotiationClient, png_data: bytes): + assert b"".join(client.different_body.get_avatar_as_png()) == png_data + + +def test_different_body_get_avatar_as_json(client: ContentNegotiationClient, png_data: bytes): + result = client.different_body.get_avatar_as_json() + expected = PngImageAsJson(content=base64.b64encode(png_data).decode()) + assert result == expected diff --git a/packages/typespec-python/tests/mock_api/unbranded/test_payload_multipart.py b/packages/typespec-python/tests/mock_api/unbranded/test_payload_multipart.py new file mode 100644 index 0000000000..f4cba4ec27 --- /dev/null +++ b/packages/typespec-python/tests/mock_api/unbranded/test_payload_multipart.py @@ -0,0 +1,200 @@ +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- +from pathlib import Path +import pytest +from payload.multipart import MultiPartClient, models +from payload.multipart.formdata.httpparts.nonstring.models import FloatRequest +from payload.multipart.formdata.file import models as file_models + +JPG = Path(__file__).parent / "data/image.jpg" +PNG = Path(__file__).parent / "data/image.png" + + +@pytest.fixture +def client(): + with MultiPartClient(endpoint="http://localhost:3000") as client: + yield client + + +def test_anonymous_model(client: MultiPartClient): + client.form_data.anonymous_model({"profileImage": open(str(JPG), "rb")}) + + +def test_basic(client: MultiPartClient): + client.form_data.basic( + models.MultiPartRequest( + id="123", + profile_image=open(str(JPG), "rb"), + ) + ) + + +def test_binary_array_parts(client: MultiPartClient): + client.form_data.binary_array_parts( + models.BinaryArrayPartsRequest( + id="123", + pictures=[ + open(str(PNG), "rb"), + open(str(PNG), "rb"), + ], + ) + ) + + +def test_check_file_name_and_content_type(client: MultiPartClient): + client.form_data.check_file_name_and_content_type( + models.MultiPartRequest( + id="123", + profile_image=("hello.jpg", open(str(JPG), "rb"), "image/jpg"), + ) + ) + + +def test_complex(client: MultiPartClient): + client.form_data.file_array_and_basic( + models.ComplexPartsRequest( + id="123", + address=models.Address(city="X"), + pictures=[ + open(str(PNG), "rb"), + open(str(PNG), "rb"), + ], + profile_image=open(str(JPG), "rb"), + ) + ) + + +def test_json_part(client: MultiPartClient): + client.form_data.json_part( + models.JsonPartRequest( + address=models.Address(city="X"), + profile_image=open(str(JPG), "rb"), + ) + ) + + +def test_multi_binary_parts(client: MultiPartClient): + client.form_data.multi_binary_parts( + models.MultiBinaryPartsRequest( + profile_image=open(str(JPG), "rb"), + picture=open(str(PNG), "rb"), + ) + ) + client.form_data.multi_binary_parts( + models.MultiBinaryPartsRequest( + profile_image=open(str(JPG), "rb"), + ) + ) + + +def test_file_with_http_part_specific_content_type(client: MultiPartClient): + client.form_data.http_parts.content_type.image_jpeg_content_type( + models.FileWithHttpPartSpecificContentTypeRequest( + profile_image=("hello.jpg", open(str(JPG), "rb"), "image/jpg"), + ) + ) + + +def test_file_with_http_part_required_content_type(client: MultiPartClient): + client.form_data.http_parts.content_type.required_content_type( + models.FileWithHttpPartRequiredContentTypeRequest( + profile_image=open(str(JPG), "rb"), + ) + ) + + +def test_file_with_http_part_optional_content_type(client: MultiPartClient): + # call twice: one with content type, one without + client.form_data.http_parts.content_type.optional_content_type( + models.FileWithHttpPartOptionalContentTypeRequest( + profile_image=("hello.jpg", open(str(JPG), "rb").read()), + ) + ) + client.form_data.http_parts.content_type.optional_content_type( + models.FileWithHttpPartOptionalContentTypeRequest( + profile_image=("hello.jpg", open(str(JPG), "rb").read(), "application/octet-stream"), + ) + ) + + +def test_complex_with_http_part(client: MultiPartClient): + client.form_data.http_parts.json_array_and_file_array( + models.ComplexHttpPartsModelRequest( + id="123", + previous_addresses=[ + models.Address(city="Y"), + models.Address(city="Z"), + ], + address=models.Address(city="X"), + pictures=[ + open(str(PNG), "rb"), + open(str(PNG), "rb"), + ], + profile_image=open(str(JPG), "rb"), + ) + ) + + +def test_http_parts_non_string_float(client: MultiPartClient): + client.form_data.http_parts.non_string.float(FloatRequest(temperature=0.5)) + + +def test_with_wire_name(client: MultiPartClient): + client.form_data.with_wire_name( + models.MultiPartRequestWithWireName( + identifier="123", + image=open(str(JPG), "rb"), + ) + ) + + +def test_optional_parts(client: MultiPartClient): + # First time with only id + client.form_data.optional_parts( + models.MultiPartOptionalRequest( + id="123", + ) + ) + # Second time with only profileImage + client.form_data.optional_parts( + models.MultiPartOptionalRequest( + profile_image=open(str(JPG), "rb"), + ) + ) + # Third time with both id and profileImage + client.form_data.optional_parts( + models.MultiPartOptionalRequest( + id="123", + profile_image=open(str(JPG), "rb"), + ) + ) + + +def test_file_upload_file_specific_content_type(client: MultiPartClient): + client.form_data.file.upload_file_specific_content_type( + file_models.UploadFileSpecificContentTypeRequest( + file=("image.png", open(str(PNG), "rb"), "image/png"), + ) + ) + + +def test_file_upload_file_required_filename(client: MultiPartClient): + client.form_data.file.upload_file_required_filename( + file_models.UploadFileRequiredFilenameRequest( + file=("image.png", open(str(PNG), "rb"), "image/png"), + ) + ) + + +def test_file_upload_file_array(client: MultiPartClient): + client.form_data.file.upload_file_array( + file_models.UploadFileArrayRequest( + files=[ + ("image.png", open(str(PNG), "rb"), "image/png"), + ("image.png", open(str(PNG), "rb"), "image/png"), + ], + ) + ) diff --git a/packages/typespec-python/tests/mock_api/unbranded/test_serialization_encoded_name_json.py b/packages/typespec-python/tests/mock_api/unbranded/test_serialization_encoded_name_json.py new file mode 100644 index 0000000000..8642e94b14 --- /dev/null +++ b/packages/typespec-python/tests/mock_api/unbranded/test_serialization_encoded_name_json.py @@ -0,0 +1,22 @@ +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- +import pytest +from serialization.encodedname.json import JsonClient +from serialization.encodedname.json.property import models + + +@pytest.fixture +def client(): + with JsonClient() as client: + yield client + + +def test_property_send(client: JsonClient): + client.property.send(models.JsonEncodedNameModel(default_name=True)) + + +def test_property_get(client: JsonClient): + assert client.property.get().default_name diff --git a/packages/typespec-python/tests/mock_api/unbranded/test_special_words.py b/packages/typespec-python/tests/mock_api/unbranded/test_special_words.py new file mode 100644 index 0000000000..83269cc1e4 --- /dev/null +++ b/packages/typespec-python/tests/mock_api/unbranded/test_special_words.py @@ -0,0 +1,66 @@ +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- +import pytest +from specialwords import SpecialWordsClient +from specialwords.models import models +from specialwords.modelproperties import models as model_properties_models +from specialwords.extensiblestrings import models as extensible_strings_models + + +@pytest.fixture +def client(): + with SpecialWordsClient() as client: + yield client + + +def test_operations(client: SpecialWordsClient, special_words): + for sw in special_words: + suffix = "" if sw == "constructor" else "_method" + getattr(client.operations, sw + suffix)() + + +def test_parameter(client: SpecialWordsClient, special_words): + for sw in special_words: + suffix = "" if sw == "constructor" else "_parameter" + getattr(client.parameters, "with_" + sw)(**{sw + suffix: "ok"}) + client.parameters.with_cancellation_token(cancellation_token="ok") + + +def test_model(client: SpecialWordsClient, special_words): + for sw in special_words: + suffix = "" if sw == "constructor" else "Model" + model = getattr(models, sw.capitalize() + suffix) + getattr(client.models, "with_" + sw)(model(name="ok")) + + +def test_model_properties(client: SpecialWordsClient): + client.model_properties.same_as_model(model_properties_models.SameAsModel(same_as_model="ok")) + + +def test_model_properties_dict_methods(client: SpecialWordsClient): + client.model_properties.dict_methods( + body=model_properties_models.DictMethods( + keys_property="ok", + items_property="ok", + values_property="ok", + popitem_property="ok", + clear_property="ok", + update_property="ok", + setdefault_property="ok", + pop_property="ok", + get_property="ok", + copy_property="ok", + ) + ) + + +def test_model_properties_with_list(client: SpecialWordsClient): + client.model_properties.with_list(model_properties_models.ModelWithList(list="ok")) + + +def test_extensible_strings(client: SpecialWordsClient): + for enum_value in extensible_strings_models.ExtensibleString: + assert enum_value == client.extensible_strings.put_extensible_string_value(body=enum_value) From 0ccba1c5b67b9934431927bade8cf1a68f2e4ced Mon Sep 17 00:00:00 2001 From: Yuchao Yan Date: Tue, 26 May 2026 03:37:23 +0000 Subject: [PATCH 35/36] update gitignore --- .gitignore | 1 + packages/typespec-python/.gitignore | 2 -- 2 files changed, 1 insertion(+), 2 deletions(-) delete mode 100644 packages/typespec-python/.gitignore diff --git a/.gitignore b/.gitignore index bb5e091993..c08fc96280 100644 --- a/.gitignore +++ b/.gitignore @@ -224,3 +224,4 @@ packages/samples/test/output/azure/templates-contoso/setup.* # python emitter packages/typespec-python/tests/generated/** +packages/typespec-python/alpha diff --git a/packages/typespec-python/.gitignore b/packages/typespec-python/.gitignore deleted file mode 100644 index de61c5b4cd..0000000000 --- a/packages/typespec-python/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -# folder for debug -alpha From a01cf7adb6699a559e0c67dbef335fcfe604e2d3 Mon Sep 17 00:00:00 2001 From: Yuchao Yan Date: Tue, 26 May 2026 05:13:43 +0000 Subject: [PATCH 36/36] update --- packages/typespec-python/eng/scripts/sync.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/typespec-python/eng/scripts/sync.ts b/packages/typespec-python/eng/scripts/sync.ts index 64ab1c66c6..ee9bbfba4a 100644 --- a/packages/typespec-python/eng/scripts/sync.ts +++ b/packages/typespec-python/eng/scripts/sync.ts @@ -137,6 +137,7 @@ const EXCLUDED_SEGMENTS: ReadonlySet = new Set([ const EXCLUDED_FILES: ReadonlySet = new Set([ // Unbranded-only mock test that doesn't apply to the Azure wrapper. "tests/mock_api/unbranded/test_unbranded.py", + "tests/mock_api/unbranded/asynctests/test_unbranded_async.py", ]); const argv = parseArgs({