Skip to content

Commit

Permalink
feat(repo): spin up .ts daemon when running tests that use daemon
Browse files Browse the repository at this point in the history
  • Loading branch information
AgentEnder committed May 31, 2024
1 parent 1605f10 commit 88fa1c4
Show file tree
Hide file tree
Showing 33 changed files with 149 additions and 89 deletions.
1 change: 1 addition & 0 deletions jest.preset.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,5 @@ module.exports = {
coverageReporters: ['html'],
maxWorkers: 1,
testEnvironment: 'node',
setupFiles: ['../../scripts/unit-test-setup.js'],
};
5 changes: 5 additions & 0 deletions packages/cypress/src/executors/cypress/cypress.impl.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,11 @@ describe('Cypress builder', () => {
configuration,
};
};
(devkit as any).logger = {
warn: jest.fn(),
log: jest.fn(),
info: jest.fn(),
};
cypressRun = jest
.spyOn(Cypress, 'run')
.mockReturnValue(Promise.resolve({}));
Expand Down
1 change: 1 addition & 0 deletions packages/cypress/src/plugins/plugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -210,6 +210,7 @@ async function buildCypressTargets(
? cypressConfig.e2e.excludeSpecPattern.map((p) => join(projectRoot, p))
: [join(projectRoot, cypressConfig.e2e.excludeSpecPattern)];
const specFiles = await globWithWorkspaceContext(
context.workspaceRoot,
specPatterns,
excludeSpecPatterns
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ import { createTreeWithEmptyWorkspace } from 'nx/src/devkit-testing-exports';
import { WORKSPACE_PLUGIN_DIR } from '../../constants';
import update from './rename-workspace-rules';

import 'nx/src/internal-testing-utils/mock-project-graph';

const rule1Name = 'test-rule';
const rule2Name = 'my-rule';

Expand Down
2 changes: 2 additions & 0 deletions packages/eslint/src/generators/init/init.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,15 @@ import 'nx/src/internal-testing-utils/mock-project-graph';
import { NxJsonConfiguration, readJson, Tree, updateJson } from '@nx/devkit';
import { createTreeWithEmptyWorkspace } from '@nx/devkit/testing';
import { LinterInitOptions, lintInitGenerator } from './init';
import { setWorkspaceRoot } from 'nx/src/utils/workspace-root';

describe('@nx/eslint:init', () => {
let tree: Tree;
let options: LinterInitOptions;

beforeEach(() => {
tree = createTreeWithEmptyWorkspace({ layout: 'apps-libs' });
setWorkspaceRoot(tree.root);
options = {
addPlugin: true,
};
Expand Down
18 changes: 0 additions & 18 deletions packages/eslint/src/plugins/plugin.spec.ts
Original file line number Diff line number Diff line change
@@ -1,21 +1,3 @@
import 'nx/src/internal-testing-utils/mock-fs';

let fsRoot: string = '';

jest.mock(
'nx/src/utils/workspace-context',
(): Partial<typeof import('nx/src/utils/workspace-context')> => {
const glob: typeof import('fast-glob') = require('fast-glob');
return {
...jest.requireActual('nx/src/utils/globs'),
globWithWorkspaceContext(root: string, patterns: string[]) {
// This glob will operate on memfs thanks to 'nx/src/internal-testing-utils/mock-fs'
return glob(patterns, { cwd: fsRoot });
},
};
}
);

import { CreateNodesContext } from '@nx/devkit';
import { minimatch } from 'minimatch';
import { TempFs } from 'nx/src/internal-testing-utils/temp-fs';
Expand Down
2 changes: 1 addition & 1 deletion packages/eslint/src/plugins/plugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import {
import { existsSync } from 'node:fs';
import { dirname, join, normalize, sep } from 'node:path';
import { combineGlobPatterns } from 'nx/src/utils/globs';
import { globWithWorkspaceContext } from 'nx/src/utils/workspace-context';
import {
ESLINT_CONFIG_FILENAMES,
baseEsLintConfigFile,
Expand All @@ -15,7 +16,6 @@ import {
} from '../utils/config-file';
import { resolveESLintClass } from '../utils/resolve-eslint-class';
import { gte } from 'semver';
import { globWithWorkspaceContext } from 'nx/src/utils/workspace-context';

export interface EslintPluginOptions {
targetName?: string;
Expand Down
4 changes: 2 additions & 2 deletions packages/gradle/src/plugin/nodes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ export const createNodesV2: CreateNodesV2<GradlePluginOptions> = [
);
const targetsCache = readTargetsCache(cachePath);

populateGradleReport(context.workspaceRoot);
await populateGradleReport(context.workspaceRoot);
const gradleReport = getCurrentGradleReport();

try {
Expand Down Expand Up @@ -131,7 +131,7 @@ export const createNodes: CreateNodes<GradlePluginOptions> = [
logger.warn(
'`createNodes` is deprecated. Update your plugin to utilize createNodesV2 instead. In Nx 20, this will error.'
);
populateGradleReport(context.workspaceRoot);
await populateGradleReport(context.workspaceRoot);
const gradleReport = getCurrentGradleReport();
const internalCreateNodes = makeCreateNodes(gradleReport, {});
return await internalCreateNodes(configFile, options, context);
Expand Down
6 changes: 4 additions & 2 deletions packages/gradle/src/utils/get-gradle-report.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,10 @@ export function getCurrentGradleReport() {
return gradleReportCache;
}

export function populateGradleReport(workspaceRoot: string): void {
const gradleConfigHash = hashWithWorkspaceContext(workspaceRoot, [
export async function populateGradleReport(
workspaceRoot: string
): Promise<void> {
const gradleConfigHash = await hashWithWorkspaceContext(workspaceRoot, [
gradleConfigGlob,
]);
if (gradleReportCache && gradleConfigHash === gradleCurrentConfigHash) {
Expand Down
3 changes: 3 additions & 0 deletions packages/jest/src/plugins/plugin.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { join } from 'path';

import { createNodes } from './plugin';
import { TempFs } from 'nx/src/internal-testing-utils/temp-fs';
import { setWorkspaceRoot } from 'nx/src/utils/workspace-root';

describe('@nx/jest/plugin', () => {
let createNodesFunction = createNodes[1];
Expand All @@ -25,6 +26,8 @@ describe('@nx/jest/plugin', () => {
configFiles: [],
};

setWorkspaceRoot(tempFs.tempDir);

await tempFs.createFiles({
'proj/jest.config.js': `module.exports = {}`,
'proj/src/unit.spec.ts': '',
Expand Down
1 change: 1 addition & 0 deletions packages/nest/jest.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,5 @@ export default {
globals: {},
displayName: 'nest',
preset: '../../jest.preset.js',
setupFilesAfterEnv: ['<rootDir>/test-setup.ts'],
};
4 changes: 2 additions & 2 deletions packages/nest/src/generators/filter/filter.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,10 @@ describe('filter generator', () => {

beforeEach(() => {
tree = createTreeWithNestApplication(project);
jest.clearAllMocks();
});

it('should run successfully', async () => {
await expect(filterGenerator(tree, options)).resolves.not.toThrowError();
await filterGenerator(tree, options);
expect(true).toBe(true);
});
});
12 changes: 12 additions & 0 deletions packages/nest/test-setup.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
// If a test uses a util from devkit, but that util
// lives in the Nx package and creates the project graph,
// we need to mock the resolved value inside the Nx package
jest
.spyOn(
require('nx/src/project-graph/project-graph'),
'createProjectGraphAsync'
)
.mockResolvedValue({
nodes: {},
dependencies: {},
});
3 changes: 2 additions & 1 deletion packages/nest/tsconfig.lib.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@
"**/*.test.ts",
"**/*_spec.ts",
"**/*_test.ts",
"jest.config.ts"
"jest.config.ts",
"test-setup.ts"
],
"include": ["**/*.ts"]
}
3 changes: 2 additions & 1 deletion packages/nest/tsconfig.spec.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
"**/*.spec.jsx",
"**/*.test.jsx",
"**/*.d.ts",
"jest.config.ts"
"jest.config.ts",
"test-setup.ts"
]
}
8 changes: 8 additions & 0 deletions packages/nx/src/adapter/ngcli-adapter.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,14 @@ import {
import { createTreeWithEmptyWorkspace } from '../generators/testing-utils/create-tree-with-empty-workspace';
import { addProjectConfiguration } from '../generators/utils/project-configuration';

jest.mock('../project-graph/project-graph', () => ({
...jest.requireActual('../project-graph/project-graph'),
createProjectGraphAsync: () => ({
nodes: {},
externalNodes: {},
}),
}));

describe('ngcli-adapter', () => {
it('arrayBufferToString should support large buffers', () => {
const largeString = 'a'.repeat(1000000);
Expand Down
19 changes: 7 additions & 12 deletions packages/nx/src/daemon/client/client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { readFileSync, statSync } from 'fs';
import { FileHandle, open } from 'fs/promises';
import { ensureDirSync, ensureFileSync } from 'fs-extra';
import { connect } from 'net';
import { join } from 'path';
import { extname, join } from 'path';
import { performance } from 'perf_hooks';
import { output } from '../../utils/output';
import { getFullOsSocketPath, killSocketOrPath } from '../socket-utils';
Expand Down Expand Up @@ -49,9 +49,6 @@ import { NxWorkspaceFiles } from '../../native';
const DAEMON_ENV_SETTINGS = {
NX_PROJECT_GLOB_CACHE: 'false',
NX_CACHE_PROJECTS_CONFIG: 'false',

// Used to identify that the code is running in the daemon process.
NX_ON_DAEMON_PROCESS: 'true',
};

export type UnregisterCallback = () => void;
Expand Down Expand Up @@ -283,14 +280,9 @@ export class DaemonClient {
return this.sendToDaemonViaQueue(message);
}

getWorkspaceContextFileData(
globs: string[],
exclude?: string[]
): Promise<FileData[]> {
getWorkspaceContextFileData(): Promise<FileData[]> {
const message: HandleContextFileDataMessage = {
type: GET_CONTEXT_FILE_DATA,
globs,
exclude,
};
return this.sendToDaemonViaQueue(message);
}
Expand Down Expand Up @@ -480,14 +472,17 @@ export class DaemonClient {

const backgroundProcess = spawn(
process.execPath,
[join(__dirname, '../server/start.js')],
[join(__dirname, `../server/start.js`)],
{
cwd: workspaceRoot,
stdio: ['ignore', this._out.fd, this._err.fd],
detached: true,
windowsHide: true,
shell: false,
env: { ...process.env, ...DAEMON_ENV_SETTINGS },
env: {
...process.env,
...DAEMON_ENV_SETTINGS,
},
}
);
backgroundProcess.unref();
Expand Down
2 changes: 0 additions & 2 deletions packages/nx/src/daemon/message-types/get-context-file-data.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,6 @@ export const GET_CONTEXT_FILE_DATA = 'GET_CONTEXT_FILE_DATA' as const;

export type HandleContextFileDataMessage = {
type: typeof GET_CONTEXT_FILE_DATA;
globs: string[];
exclude?: string[];
};

export function isHandleContextFileDataMessage(
Expand Down
2 changes: 1 addition & 1 deletion packages/nx/src/daemon/server/handle-context-file-data.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { workspaceRoot } from '../../utils/workspace-root';
import { HandlerResult } from './server';

export async function handleContextFileData(): Promise<HandlerResult> {
const files = getAllFileDataInContext(workspaceRoot);
const files = await getAllFileDataInContext(workspaceRoot);
return {
response: JSON.stringify(files),
description: 'handleContextFileData',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { HandlerResult } from './server';
export async function handleGetFilesInDirectory(
dir: string
): Promise<HandlerResult> {
const files = getFilesInDirectoryUsingContext(workspaceRoot, dir);
const files = await getFilesInDirectoryUsingContext(workspaceRoot, dir);
return {
response: JSON.stringify(files),
description: 'handleNxWorkspaceFiles',
Expand Down
10 changes: 0 additions & 10 deletions packages/nx/src/daemon/server/handle-request-file-data.ts

This file was deleted.

26 changes: 14 additions & 12 deletions packages/nx/src/daemon/server/server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,6 @@ import {
handleRecordOutputsHash,
} from './handle-outputs-tracking';
import { handleProcessInBackground } from './handle-process-in-background';
import { handleRequestFileData } from './handle-request-file-data';
import { handleRequestProjectGraph } from './handle-request-project-graph';
import { handleRequestShutdown } from './handle-request-shutdown';
import { serverLogger } from './logger';
Expand Down Expand Up @@ -132,11 +131,12 @@ async function handleMessage(socket, data: string) {
);
}

if (daemonIsOutdated()) {
const outdated = daemonIsOutdated();
if (outdated) {
await respondWithErrorAndExit(
socket,
`Lock files changed`,
new Error('LOCK-FILES-CHANGED')
`Daemon outdated`,
new Error(outdated)
);
}

Expand Down Expand Up @@ -164,10 +164,6 @@ async function handleMessage(socket, data: string) {
);
} else if (payload.type === 'HASH_TASKS') {
await handleResult(socket, 'HASH_TASKS', () => handleHashTasks(payload));
} else if (payload.type === 'REQUEST_FILE_DATA') {
await handleResult(socket, 'REQUEST_FILE_DATA', () =>
handleRequestFileData()
);
} else if (payload.type === 'PROCESS_IN_BACKGROUND') {
await handleResult(socket, 'PROCESS_IN_BACKGROUND', () =>
handleProcessInBackground(payload)
Expand Down Expand Up @@ -274,8 +270,13 @@ function registerProcessTerminationListeners() {

let existingLockHash: string | undefined;

function daemonIsOutdated(): boolean {
return nxVersionChanged() || lockFileHashChanged();
function daemonIsOutdated(): string | null {
if (nxVersionChanged()) {
return 'NX_VERSION_CHANGED';
} else if (lockFileHashChanged()) {
return 'LOCK_FILES_CHANGED';
}
return null;
}

function nxVersionChanged(): boolean {
Expand Down Expand Up @@ -332,10 +333,11 @@ const handleWorkspaceChanges: FileWatcherCallback = async (
try {
resetInactivityTimeout(handleInactivityTimeout);

if (daemonIsOutdated()) {
const outdatedReason = daemonIsOutdated();
if (outdatedReason) {
await handleServerProcessTermination({
server,
reason: 'Lock file changed',
reason: outdatedReason,
});
return;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ describe('explicit package json dependencies', () => {

const fileMap = createFileMap(
projectsConfigurations as any,
getAllFileDataInContext(tempFs.tempDir)
await getAllFileDataInContext(tempFs.tempDir)
).fileMap;

const builder = new ProjectGraphBuilder(undefined, fileMap.projectFileMap);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,13 +34,14 @@ export function loadRemoteNxPlugin(
...(isWorkerTypescript
? {
// Ensures that the worker uses the same tsconfig as the main process
TS_NODE_PROJECT: path.join(__dirname, '../../../tsconfig.lib.json'),
TS_NODE_PROJECT: path.join(
__dirname,
'../../../../tsconfig.lib.json'
),
}
: {}),
};

delete env.NX_ON_DAEMON_PROCESS;

const worker = fork(workerPath, [], {
stdio: ['ignore', 'inherit', 'inherit', 'ipc'],
env,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ describe('retrieveProjectConfigurationPaths', () => {
})
);

const configPaths = retrieveProjectConfigurationPaths(fs.tempDir, [
const configPaths = await retrieveProjectConfigurationPaths(fs.tempDir, [
{
createNodes: [
'{project.json,**/project.json}',
Expand Down
Loading

0 comments on commit 88fa1c4

Please sign in to comment.