|
8 | 8 | import com.azure.core.http.HttpResponse;
|
9 | 9 | import com.azure.core.util.Configuration;
|
10 | 10 | import com.azure.core.util.Context;
|
| 11 | +import com.azure.core.util.CoreUtils; |
11 | 12 | import com.azure.core.util.logging.ClientLogger;
|
12 | 13 |
|
| 14 | +import java.io.ByteArrayOutputStream; |
13 | 15 | import java.io.IOException;
|
14 | 16 | import java.io.UncheckedIOException;
|
| 17 | +import java.nio.charset.StandardCharsets; |
| 18 | +import java.nio.file.Files; |
15 | 19 | import java.nio.file.Path;
|
16 | 20 | import java.nio.file.Paths;
|
17 | 21 | import java.time.Duration;
|
@@ -46,40 +50,70 @@ public TestProxyManager(Path testClassPath) {
|
46 | 50 | public void startProxy() {
|
47 | 51 | try {
|
48 | 52 | // if we're not running in CI we will check to see if someone has started the proxy, and start one if not.
|
49 |
| - if (runningLocally() && !checkAlive(1, Duration.ofSeconds(1))) { |
| 53 | + if (runningLocally() && !checkAlive(1, Duration.ofSeconds(1), null)) { |
50 | 54 | String commandLine = Paths.get(TestProxyDownloader.getProxyDirectory().toString(),
|
51 | 55 | TestProxyUtils.getProxyProcessName()).toString();
|
52 | 56 |
|
53 |
| - ProcessBuilder builder = new ProcessBuilder(commandLine, |
54 |
| - "--storage-location", |
55 |
| - TestUtils.getRepoRootResolveUntil(testClassPath, "eng").toString()); |
| 57 | + Path repoRoot = TestUtils.getRepoRootResolveUntil(testClassPath, "eng"); |
| 58 | + |
| 59 | + // Resolve the path to the repo root 'target' folder and create the folder if it doesn't exist. |
| 60 | + // This folder will be used to store the 'test-proxy.log' file to enable simpler debugging of Test Proxy |
| 61 | + // locally. This is similar to what CI does, but CI uses a PowerShell process to run the Test Proxy |
| 62 | + // where running locally uses a Java ProcessBuilder. |
| 63 | + Path repoRootTarget = repoRoot.resolve("target"); |
| 64 | + if (!Files.exists(repoRootTarget)) { |
| 65 | + Files.createDirectory(repoRootTarget); |
| 66 | + } |
| 67 | + |
| 68 | + ProcessBuilder builder = new ProcessBuilder(commandLine, "--storage-location", repoRoot.toString()) |
| 69 | + .redirectOutput(repoRootTarget.resolve("test-proxy.log").toFile()); |
56 | 70 | Map<String, String> environment = builder.environment();
|
57 |
| - environment.put("LOGGING__LOGLEVEL", "Information"); |
58 |
| - environment.put("LOGGING__LOGLEVEL__MICROSOFT", "Warning"); |
59 |
| - environment.put("LOGGING__LOGLEVEL__DEFAULT", "Information"); |
| 71 | + environment.put("LOGGING__LOGLEVEL", "Debug"); |
| 72 | + environment.put("LOGGING__LOGLEVEL__MICROSOFT", "Debug"); |
| 73 | + environment.put("LOGGING__LOGLEVEL__DEFAULT", "Debug"); |
60 | 74 | proxy = builder.start();
|
61 | 75 | }
|
62 | 76 | // in either case the proxy should now be started, so let's wait to make sure.
|
63 |
| - if (checkAlive(10, Duration.ofSeconds(6))) { |
| 77 | + if (checkAlive(10, Duration.ofSeconds(6), proxy)) { |
64 | 78 | return;
|
65 | 79 | }
|
66 |
| - throw new RuntimeException("Test proxy did not initialize."); |
67 | 80 |
|
| 81 | + // If the Test Proxy process doesn't start within the timeout period read the error stream of the Process |
| 82 | + // for any additional details that could help determine why the Test Proxy process didn't start. |
| 83 | + // Include this additional information in the exception message. |
| 84 | + ByteArrayOutputStream errorLog = new ByteArrayOutputStream(); |
| 85 | + byte[] buffer = new byte[4096]; |
| 86 | + int read; |
| 87 | + while ((read = proxy.getErrorStream().read(buffer)) != -1) { |
| 88 | + errorLog.write(buffer, 0, read); |
| 89 | + } |
| 90 | + |
| 91 | + String errorLogString = new String(errorLog.toByteArray(), StandardCharsets.UTF_8); |
| 92 | + if (CoreUtils.isNullOrEmpty(errorLogString)) { |
| 93 | + throw new RuntimeException("Test proxy did not initialize."); |
| 94 | + } else { |
| 95 | + throw new RuntimeException("Test proxy did not initialize. Error log: " + errorLogString); |
| 96 | + } |
68 | 97 | } catch (IOException e) {
|
69 | 98 | throw LOGGER.logExceptionAsError(new UncheckedIOException(e));
|
70 | 99 | } catch (InterruptedException e) {
|
71 | 100 | throw new RuntimeException(e);
|
72 | 101 | }
|
73 | 102 | }
|
74 | 103 |
|
75 |
| - private boolean checkAlive(int loops, Duration waitTime) throws InterruptedException { |
| 104 | + private static boolean checkAlive(int loops, Duration waitTime, Process proxy) throws InterruptedException { |
76 | 105 | HttpURLConnectionHttpClient client = new HttpURLConnectionHttpClient();
|
77 | 106 | HttpRequest request = new HttpRequest(HttpMethod.GET,
|
78 | 107 | String.format("%s/admin/isalive", TestProxyUtils.getProxyUrl()));
|
79 | 108 | for (int i = 0; i < loops; i++) {
|
80 |
| - HttpResponse response = null; |
| 109 | + // If the proxy isn't alive and the exit value isn't 0, then the proxy process has exited with an error |
| 110 | + // and stop waiting. |
| 111 | + if (proxy != null && !proxy.isAlive() && proxy.exitValue() != 0) { |
| 112 | + return false; |
| 113 | + } |
| 114 | + |
81 | 115 | try {
|
82 |
| - response = client.sendSync(request, Context.NONE); |
| 116 | + HttpResponse response = client.sendSync(request, Context.NONE); |
83 | 117 | if (response != null && response.getStatusCode() == 200) {
|
84 | 118 | return true;
|
85 | 119 | }
|
|
0 commit comments