Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix TCGC broken with latest compiler and add e2e tests #818

Merged
merged 14 commits into from
May 10, 2024
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
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"],
},
});
Loading