Skip to content

Commit

Permalink
Fix TCGC broken with latest compiler and add e2e tests (#818)
Browse files Browse the repository at this point in the history
fix #817

---------

Co-authored-by: iscai-msft <[email protected]>
Co-authored-by: Timothee Guerin <[email protected]>
Co-authored-by: Timothee Guerin <[email protected]>
  • Loading branch information
4 people authored May 10, 2024
1 parent e7ff7d8 commit 4af68a2
Show file tree
Hide file tree
Showing 10 changed files with 132 additions and 6 deletions.
7 changes: 7 additions & 0 deletions .chronus/changes/add_e2e_test-2024-4-10-13-19-5.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
changeKind: fix
packages:
- "@azure-tools/typespec-client-generator-core"
---

Fix: Crash due to using api from next version of the compiler
2 changes: 1 addition & 1 deletion eng/pipelines/jobs/e2e-job.yml
Original file line number Diff line number Diff line change
Expand Up @@ -24,4 +24,4 @@ jobs:
displayName: Cadl Ranch e2e tests

- script: pnpm test:e2e
displayName: UI Tests
displayName: E2E Tests
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
import "@typespec/rest";
import "@azure-tools/typespec-client-generator-core";

op ping(): void;
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
{
"name": "@azure-tools/tcgc-test-basic-latest",
"dependencies": {
"@typespec/compiler": "latest",
"@typespec/rest": "latest",
"@typespec/http": "latest",
"@typespec/versioning": "latest",
"@typespec/openapi": "latest",
"@typespec/openapi3": "latest",
"@azure-tools/typespec-azure-core": "latest",
"@azure-tools/typespec-autorest": "latest",
"@azure-tools/typespec-azure-resource-manager": "latest"
},
"private": true
}
84 changes: 84 additions & 0 deletions packages/typespec-client-generator-core/e2e/check-latest.e2e.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
import { findTestPackageRoot } from "@typespec/compiler/testing";
import { SpawnOptions, spawn } from "child_process";
import { cp, readdir, rm } from "fs/promises";
import { join, resolve } from "path";
import { beforeAll, it } from "vitest";

const packageRoot = await findTestPackageRoot(import.meta.url);
const tempDir = join(packageRoot, "temp/e2e");

let tgzFile: string;
beforeAll(async () => {
await rm(tempDir, { recursive: true, force: true });

await execSuccessAsync("pnpm", ["pack", "--pack-destination", tempDir]);
const files = await readdir(tempDir);

const filename = files.find((x) => x.startsWith("azure-tools-typespec-client-generator-core-"));
if (filename === undefined) {
throw new Error(
`Cannot resolve package starting with "azure-tools-typespec-client-generator-core-"`
);
}
tgzFile = join(tempDir, filename);
});

// Make sure it works with the latest version of dependencies and not just the local build.
it("works with latest version of packages", async () => {
const dir = await setupScenario("basic-latest");
await execSuccessAsync("npm", ["install", tgzFile], { cwd: dir });
await execSuccessAsync("npx", ["tsp", "compile", "."], { cwd: dir });
});

async function setupScenario(name: string): Promise<string> {
const target = resolve(tempDir, name);
await cp(resolve(packageRoot, "e2e", name), target, {
recursive: true,
});
return target;
}

async function execSuccessAsync(command: string, args: string[] = [], options: SpawnOptions = {}) {
const result = await execAsync(command, args, options);
if (result.exitCode !== 0) {
throw new Error(
`Command '${command} ${args.join(" ")}' failed with exit code ${result.exitCode}\n` +
result.stdio
);
}
return result;
}
async function execAsync(
command: string,
args: string[] = [],
options: SpawnOptions = {}
): Promise<{ exitCode: number; stdio: string; stdout: string; stderr: string; proc: any }> {
const child = spawn(command, args, options);

return new Promise((resolve, reject) => {
child.on("error", (error) => {
reject(error);
});
const stdio: Buffer[] = [];
const stdout: Buffer[] = [];
const stderr: Buffer[] = [];
child.stdout?.on("data", (data) => {
stdout.push(data);
stdio.push(data);
});
child.stderr?.on("data", (data) => {
stderr.push(data);
stdio.push(data);
});

child.on("exit", (exitCode) => {
resolve({
exitCode: exitCode ?? -1,
stdio: Buffer.concat(stdio).toString(),
stdout: Buffer.concat(stdout).toString(),
stderr: Buffer.concat(stderr).toString(),
proc: child,
});
});
});
}
1 change: 1 addition & 0 deletions packages/typespec-client-generator-core/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@
"test:watch": "vitest -w",
"test:ui": "vitest --ui",
"test:ci": "vitest run --coverage --reporter=junit --reporter=default",
"test:e2e": "vitest run --config ./vitest.config.e2e.ts",
"lint": "eslint . --max-warnings=0",
"lint:fix": "eslint . --fix ",
"regen-docs": "tspd doc . --enable-experimental --output-dir ../../docs/libraries/typespec-client-generator-core/reference"
Expand Down
3 changes: 1 addition & 2 deletions packages/typespec-client-generator-core/src/public-utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@ import {
getProjectedName,
ignoreDiagnostics,
isErrorModel,
isType,
listServices,
resolveEncodedName,
} from "@typespec/compiler";
Expand Down Expand Up @@ -196,7 +195,7 @@ export function getLibraryName(
type.templateMapper.args
.filter(
(arg): arg is Model | Enum =>
isType(arg) && (arg.kind === "Model" || arg.kind === "Enum") && arg.name.length > 0
"kind" in arg && (arg.kind === "Model" || arg.kind === "Enum") && arg.name.length > 0
)
.map((arg) => pascalCase(arg.name))
.join("")
Expand Down
3 changes: 1 addition & 2 deletions packages/typespec-client-generator-core/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,6 @@ import {
ignoreDiagnostics,
isErrorModel,
isNeverType,
isType,
} from "@typespec/compiler";
import {
Authentication,
Expand Down Expand Up @@ -1147,7 +1146,7 @@ function checkAndGetClientType(
if (context.filterOutCoreModels && isAzureCoreModel(effectivePayloadType)) {
if (effectivePayloadType.templateMapper && effectivePayloadType.name) {
effectivePayloadType.templateMapper.args
.filter(isType)
.filter((arg): arg is Type => "kind" in arg)
.filter((arg) => arg.kind === "Model" && arg.name)
.forEach((arg) => {
retval.push(...diagnostics.pipe(checkAndGetClientType(context, arg, operation)));
Expand Down
2 changes: 1 addition & 1 deletion packages/typespec-client-generator-core/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,5 +10,5 @@
"rootDir": ".",
"tsBuildInfoFile": "temp/tsconfig.tsbuildinfo"
},
"include": ["src/**/*.ts", "test/**/*.ts"]
"include": ["src/**/*.ts", "test/**/*.ts", "e2e/**/*.ts"]
}
17 changes: 17 additions & 0 deletions packages/typespec-client-generator-core/vitest.config.e2e.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { defineConfig } from "vitest/config";

export default defineConfig({
test: {
environment: "node",
testTimeout: 60_000,
isolate: false,
coverage: {
reporter: ["cobertura", "json", "text"],
},
outputFile: {
junit: "./test-results.xml",
},

include: ["e2e/**/*.e2e.ts"],
},
});

0 comments on commit 4af68a2

Please sign in to comment.