microsoft/vscode-react-native

Public

mirrored from https://github.com/microsoft/vscode-react-nativeAvailable

CodeCommitsIssuesPull requestsActionsInsightsSecurity
0.5.7

Branches

Tags

  • No tags available.
0Branches0Tags
Go to file
Add file
Code

Clone

HTTPS

Download ZIP

test/resources/processExecution/recorder.ts

127lines · modeblame

efebb488digeff10 years ago1// Copyright (c) Microsoft Corporation. All rights reserved.
2// Licensed under the MIT license. See LICENSE file in the project root for details.
3
4import * as events from "events";
5import * as fs from "fs";
6import * as os from "os";
7import * as path from "path";
6d5c8798Nikita Matrosov9 years ago8import child_process = require("child_process");
efebb488digeff10 years ago9
10import {ITimedEvent,
11IEventArguments,
12Recording,
13IAndroidDevice,
14IIOSDevice,
15ISpawnArguments,
ea32ecf9digeff10 years ago16ISpawnOptions,
efebb488digeff10 years ago17} from "./recording";
18
19/* We use this class to capture the behavior of a ChildProces running inside of node, so we can store all the
20visible events and side-effects of that process, and then we can perfectly reproduce them in a test by using
21the Simulator class.
22
23Call Recorder.installGlobalRecorder() when your program starts to record the events of all the spawned processes.
24The recordings will be stored at the OS temporary directory e.g.:
25Windows: %TEMP%\processExecutionRecording.txt
26OS X: $TMPDIR/processExecutionRecording.txt
27*/
28export class Recorder {
29private static originalSpawn: (command: string, args: string[], options: ISpawnOptions) => child_process.ChildProcess;
30
31private recording: Recording;
32private previousEventTimestamp: number;
33
34public static installGlobalRecorder(): void {
35if (!this.originalSpawn) {
36this.originalSpawn = child_process.spawn;
37child_process.spawn = this.recordAndSpawn.bind(this);
38}
39}
40
5c8365a6Artem Egorov8 years ago41public static recordAndSpawn(command: string, args: string[] = [], options: ISpawnOptions = {}): child_process.ChildProcess {
efebb488digeff10 years ago42const spawnedProcess = this.originalSpawn(command, args, options);
43new Recorder(spawnedProcess, { command, args, options }).record();
44return spawnedProcess;
45}
46
47constructor(private execution: child_process.ChildProcess, spawnArguments: ISpawnArguments,
48private filePath = Recorder.defaultFilePath()) {
49this.initializeRecording(spawnArguments);
50}
51
52public record(): void {
53this.addListenerForRecordingEvent(this.execution.stdout, "stdout", "data", "data", data =>
54data.toString());
55this.addListenerForRecordingEvent(this.execution.stderr, "stderr", "data", "data", data =>
56data.toString());
57this.addListenerForRecordingEvent(this.execution, "error", "error", "error");
58this.addListenerForRecordingEvent(this.execution, "exit", "exit", "code");
59this.execution.on("error", () =>
60this.store());
61this.execution.on("exit", () =>
62this.store());
63this.previousEventTimestamp = this.now();
64}
65
66private initializeRecording(spawnArguments: ISpawnArguments): void {
67/* The TBD values needs to be filled manually by the recorder, so we know the full context
68where this recording was made */
69this.recording = {
70title: "TBD",
71arguments: spawnArguments,
72date: new Date(),
73configuration: {
74os: { platform: os.platform(), release: os.release() },
75android: {
76sdk: { tools: "TBD", platformTools: "TBD", buildTools: "TBD", repositoryForSupportLibraries: "TBD" },
77intelHAXMEmulator: "TBD",
78visualStudioEmulator: "TBD",
79},
80reactNative: "TBD",
81node: "TBD",
82npm: "TBD",
83},
84state: {
85reactNative: { packager: "TBD" },
86devices: { android: <IAndroidDevice[]>[], ios: <IIOSDevice[]>[] },
87},
88events: <IEventArguments[]>[],
89};
90}
91
92private static defaultFilePath(): string {
93return path.join(os.tmpdir(), "processExecutionRecording.txt");
94}
95
96private now(): number {
97return new Date().getTime();
98}
99
100private addListenerForRecordingEvent(emitter: events.EventEmitter, storedEventName: string, eventToListenName: string,
101argumentName: string, argumentsConverter: (value: any) => any = value => value): void {
102emitter.on(eventToListenName, (argument: any) => {
103const now = this.now();
104const relativeTimestamp = now - this.previousEventTimestamp;
105this.previousEventTimestamp = now;
106this.recording.events.push(this.generateEvent(relativeTimestamp, storedEventName, argumentName, argumentsConverter(argument)));
107});
108}
109
110/* Generate an event based on the parameters e.g.: { "after": 0, "stdout": { "data": ":app:assembleDebug" } } */
111private generateEvent(relativeTimestamp: number, eventName: string, argumentName: string, argument: any): IEventArguments {
112const event: ITimedEvent = { after: relativeTimestamp };
113(<any>event)[eventName] = this.generateEventArguments(argumentName, argument);
114return <IEventArguments>event;
115}
116
117/* Generate the event arguments based on the parameters e.g.: { "data": ":app:assembleDebug" } */
118private generateEventArguments(argumentName: string, argument: any): IEventArguments {
119const eventArguments: IEventArguments = <IEventArguments>{};
120(<any>eventArguments)[argumentName] = argument;
121return eventArguments;
122}
123
124private store(): void {
125fs.appendFileSync(this.filePath, JSON.stringify(this.recording) + "\n\n\n", "utf8");
126}
127}