blob: 5d5d8e243b0454df315230c098384e06df43f453 [file] [log] [blame]
Lukacs Berkidc174c42016-06-30 15:46:10 +00001// Copyright 2016 The Bazel Authors. All rights reserved.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15package com.google.devtools.build.lib.windows;
16
17import java.io.PrintStream;
18import java.nio.charset.Charset;
Lukacs Berki0451cf02016-07-01 14:32:53 +000019import java.nio.file.Paths;
Lukacs Berkidc174c42016-06-30 15:46:10 +000020import java.util.HashMap;
21import java.util.Map;
22
23/**
24 * Mock subprocess to be used for testing Windows process management. Command line usage:
25 *
26 * <ul>
27 * <li><code>I&lt;register&gt;&lt;count&gt;</code>: Read count bytes to the specified register
28 * <li><code>O-&lt;string&gt;</code>: Write a string to stdout</li>
29 * <li><code>E-&lt;string&gt;</code>: Write a string to stderr</li>
30 * <li><code>O$&lt;variable&gt;</code>: Write an environment variable to stdout</li>
31 * <li><code>E$&lt;variable&gt;</code>: Write an environment variable to stderr</li>
Lukacs Berki0451cf02016-07-01 14:32:53 +000032 * <li><code>O.</code>: Write the cwd stdout</li>
33 * <li><code>E.</code>: Write the cwd stderr</li>
Lukacs Berkidc174c42016-06-30 15:46:10 +000034 * <li><code>O&lt;register&gt;</code>: Write the contents of a register to stdout</li>
35 * <li><code>E&lt;register&gt;</code>: Write the contents of a register to stderr</li>
36 * <li><code>X&lt;exit code%gt;</code>: Exit with the specified exit code</li>
Lukacs Berki3d97e222016-08-19 14:40:20 +000037 * <li><code>S&lt;seconds&gt;</code>: Wait the specified number of seconds</li>
Lukacs Berkidc174c42016-06-30 15:46:10 +000038 * </ul>
39 *
40 * <p>Registers are single characters. Each command line argument is interpreted as a single
41 * operation. Example:
42 *
43 * <code>
44 * Ia10 Oa Oa Ea E-OVER X42
45 * </code>
46 *
47 * Means: read 10 bytes from stdin, write them back twice to stdout and once to stderr, write
48 * the string "OVER" to stderr then exit with exit code 42.
49 */
50public class MockSubprocess {
51 private static Map<Character, byte[]> registers = new HashMap<>();
Lukacs Berki0451cf02016-07-01 14:32:53 +000052 private static final Charset UTF8 = Charset.forName("UTF-8");
Lukacs Berkidc174c42016-06-30 15:46:10 +000053
54 private static void writeBytes(PrintStream stream, String arg) throws Exception {
Lukacs Berki0451cf02016-07-01 14:32:53 +000055
Lukacs Berkidc174c42016-06-30 15:46:10 +000056 byte[] buf;
57 switch (arg.charAt(1)) {
58 case '-':
59 // Immediate string
Lukacs Berki0451cf02016-07-01 14:32:53 +000060 buf = arg.substring(2).getBytes(UTF8);
Lukacs Berkidc174c42016-06-30 15:46:10 +000061 break;
62
63 case '$':
64 // Environment variable
Lukacs Berki0451cf02016-07-01 14:32:53 +000065 buf = System.getenv(arg.substring(2)).getBytes(UTF8);
66 break;
67
68 case '.':
69 buf = Paths.get(".").toAbsolutePath().normalize().toString().getBytes(UTF8);
Lukacs Berkidc174c42016-06-30 15:46:10 +000070 break;
71
72 default:
73 buf = registers.get(arg.charAt(1));
74 break;
75 }
76
77 stream.write(buf, 0, buf.length);
78}
79
80 public static void main(String[] args) throws Exception {
81 for (String arg : args) {
82 switch (arg.charAt(0)) {
83 case 'I':
84 char register = arg.charAt(1);
85 int length = Integer.parseInt(arg.substring(2));
86 byte[] buf = new byte[length];
87 registers.put(register, buf);
88 System.in.read(buf, 0, length);
89 break;
90
91 case 'E':
92 writeBytes(System.err, arg);
93 break;
94
95 case 'O':
96 writeBytes(System.out, arg);
97 break;
98
Lukacs Berki3d97e222016-08-19 14:40:20 +000099 case 'W':
100 try {
101 Thread.sleep(Integer.parseInt(arg.substring(1)) * 1000);
102 } catch (InterruptedException e) {
103 // This is good enough for a mock process
104 throw new IllegalStateException(e);
105 }
106 break;
107
Lukacs Berkidc174c42016-06-30 15:46:10 +0000108 case 'X':
109 System.exit(Integer.parseInt(arg.substring(1)));
Googler6394c3f2022-06-10 16:39:34 -0700110 default: // fall out
Lukacs Berkidc174c42016-06-30 15:46:10 +0000111 }
112 }
113 }
114}