private string GetMessage(Stream stdout, int timeout, Process debugAdapter, DebugAdapterRunner runner) { // Read header of message byte[] header = ReadBlockFromStream(stdout, debugAdapter, DAPConstants.ContentLength.Length, timeout); VerifyValueOfBuffer(header, DAPConstants.ContentLength); // Read the length (in bytes) of the json message int messageLengthBytes = 0; int nextByte = -1; while (true) { nextByte = stdout.ReadByte(); if (nextByte >= '0' && nextByte <= '9') { messageLengthBytes = messageLengthBytes * 10 + nextByte - '0'; } else { break; } } // Read and verify TWO_CRLF byte[] twoCRLF = new byte[DAPConstants.TwoCrLf.Length]; twoCRLF[0] = (byte)nextByte; // Read one less byte because we have the first byte and copy into twoCRLF byte array byte[] oneMinustwoCRLF = ReadBlockFromStream(stdout, debugAdapter, DAPConstants.TwoCrLf.Length - 1, timeout); Array.Copy(oneMinustwoCRLF, 0, twoCRLF, 1, oneMinustwoCRLF.Length); VerifyValueOfBuffer(twoCRLF, DAPConstants.TwoCrLf); // Read the message contents byte[] messageBuffer = ReadBlockFromStream(stdout, debugAdapter, messageLengthBytes, timeout); return(Encoding.UTF8.GetString(messageBuffer, 0, messageLengthBytes)); }
public virtual void Run(DebugAdapterRunner runner) { }
/// <summary> /// Runs a command against the debugger. /// </summary> /// <param name="command">The command to run.</param> /// <param name="expectedEvents">[OPTIONAL] If the command causes an event to occur, pass the expected event(s)</param> private void Run(DarRunner darRunner, ILoggingComponent log, params IEvent[] expectedEvents) { Parameter.ThrowIfNull(darRunner, nameof(darRunner)); log?.WriteLine("Running command {0}", this.ToString()); log?.WriteLine("Command '{0}' expecting response: {1}", this.Name, this.ExpectedResponse.ToString()); DebugAdapterResponse darCommandResponse = GetDarResponse(this.ExpectedResponse); DebugAdapterCommand darCommand = new DebugAdapterCommand( this.Name, this.Args, new[] { darCommandResponse }); List <Tuple <DebugAdapterResponse, IEvent> > darEventMap = new List <Tuple <DebugAdapterResponse, IEvent> >(expectedEvents.Length); // Add additional expected events to match if requested if (expectedEvents != null && expectedEvents.Length > 0) { if (expectedEvents.Length > 1) { log?.WriteLine("Command '{0}' expecting {1} events:", this.Name, expectedEvents.Length); } foreach (var expectedEvent in expectedEvents) { DebugAdapterResponse darEventResponse = GetDarResponse(expectedEvent); darCommand.ExpectedResponses.Add(darEventResponse); darEventMap.Add(Tuple.Create(darEventResponse, expectedEvent)); // Debug info for expected response string eventMessage = expectedEvents.Length > 1 ? " - {1}" : "Command '{0}' expecting event: {1}"; log?.WriteLine(eventMessage, this.Name, expectedEvent.ToString()); } } // Allow the command to override the timeout int overrideTimeout = Convert.ToInt32(this.Timeout.TotalMilliseconds); int savedTimeout = darRunner.ResponseTimeout; try { if (overrideTimeout > 0) { darRunner.ResponseTimeout = overrideTimeout; log?.WriteLine("Command '{0}' timeout set to {1:n0} seconds.", this.Name, this.Timeout.TotalSeconds); } darCommand.Run(darRunner); // Allow the command to retrieve properties from the actual matched response. string responseJson = JsonConvert.SerializeObject(darCommandResponse.Match); if (!string.IsNullOrWhiteSpace(responseJson)) { this.ProcessActualResponse(new ActualResponse(responseJson)); } // Allow the events to retrieve properties from the actual event. foreach (var darEvent in darEventMap) { string eventJson = JsonConvert.SerializeObject(darEvent.Item1.Match); darEvent.Item2.ProcessActualResponse(new ActualResponse(eventJson)); } } catch (Exception ex) { // Add information to the log when the exception occurs log?.WriteLine("ERROR: Running command '{0}'. Exception thrown.", this.Name); log?.WriteLine(UDebug.ExceptionToString(ex)); // The DARException is not serializable, create a new exception if (ex is DARException) { throw new RunnerException(ex.Message); } else { throw; } } finally { if (overrideTimeout > 0) { darRunner.ResponseTimeout = savedTimeout; } } }
public override void Run(DarRunner darRunner) { this.Run(darRunner, null); }
private string CreateDispatcherRequest(DebugAdapterRunner runner) { DispatcherRequest request = new DispatcherRequest(runner.GetNextSequenceNumber(), this.Name, this.args); return(runner.SerializeMessage(request)); }
public override void Run(DebugAdapterRunner runner) { // Send the request string request = CreateDispatcherRequest(runner); // VSCode doesn't send /n at the end. If this is writeline, then concord hangs runner.DebugAdapter.StandardInput.Write(request); // Process + validate responses List <object> responseList = new List <object>(); int currentExpectedResponseIndex = 0; // Loop until we have received as many expected responses as expected while (currentExpectedResponseIndex < this.ExpectedResponses.Count) { string receivedMessage = null; Exception getMessageExeception = null; try { receivedMessage = this.GetMessage( runner.DebugAdapter.StandardOutput.BaseStream, runner.ResponseTimeout, runner.DebugAdapter, runner); } catch (Exception e) { getMessageExeception = e; } if (getMessageExeception != null) { if (!runner.DebugAdapter.HasExited) { // If it hasn't exited yet, wait a little bit longer to make sure it isn't just about to exit try { runner.DebugAdapter.WaitForExit(500); } catch { } } string messageStart; if (runner.DebugAdapter.HasExited) { if (runner.HasAsserted()) { messageStart = string.Format(CultureInfo.CurrentCulture, "The debugger process has asserted and exited with code '{0}' without sending all expected responses. See test log for assert details.", runner.DebugAdapter.ExitCode); } else { messageStart = string.Format(CultureInfo.CurrentCulture, "The debugger process has exited with code '{0}' without sending all expected responses.", runner.DebugAdapter.ExitCode); } } else if (getMessageExeception is TimeoutException) { if (runner.HasAsserted()) { messageStart = "The debugger process has asserted. See test log for assert details."; } else { messageStart = "Expected response not found before timeout."; } } else { messageStart = "Exception while reading message from debug adpter. " + getMessageExeception.Message; } string expectedResponseText = JsonConvert.SerializeObject(this.ExpectedResponses[currentExpectedResponseIndex].Response); string actualResponseText = string.Empty; for (int i = 0; i < responseList.Count; i++) { actualResponseText += string.Format(CultureInfo.CurrentCulture, "{0}. {1}\n", (i + 1), JsonConvert.SerializeObject(responseList[i])); } string errorMessage = string.Format(CultureInfo.CurrentCulture, "{0}\nExpected = {1}\nActual Responses =\n{2}", messageStart, expectedResponseText, actualResponseText); throw new DARException(errorMessage); } try { DispatcherMessage dispatcherMessage = JsonConvert.DeserializeObject <DispatcherMessage>(receivedMessage); if (dispatcherMessage.type == "event") { DispatcherEvent dispatcherEvent = JsonConvert.DeserializeObject <DispatcherEvent>(receivedMessage); responseList.Add(dispatcherEvent); if (dispatcherEvent.eventType == "stopped") { runner.CurrentThreadId = dispatcherEvent.body.threadId; } var expected = this.ExpectedResponses[currentExpectedResponseIndex]; if (Utils.CompareObjects(expected.Response, dispatcherEvent, expected.IgnoreOrder)) { expected.Match = dispatcherEvent; currentExpectedResponseIndex++; } } else if (dispatcherMessage.type == "response") { DispatcherResponse dispatcherResponse = JsonConvert.DeserializeObject <DispatcherResponse>(receivedMessage); responseList.Add(dispatcherResponse); var expected = this.ExpectedResponses[currentExpectedResponseIndex]; if (Utils.CompareObjects(expected.Response, dispatcherResponse, expected.IgnoreOrder)) { expected.Match = dispatcherResponse; currentExpectedResponseIndex++; } } else if (dispatcherMessage.type == "request") { runner.HandleCallbackRequest(receivedMessage); } else { throw new DARException(String.Format(CultureInfo.CurrentCulture, "Unknown Dispatcher Message type: '{0}'", dispatcherMessage.type)); } } catch (JsonReaderException) { runner.AppendLineToDebugAdapterOutput("Response could not be parsed as json. This was the response:"); runner.AppendLineToDebugAdapterOutput(receivedMessage); throw; } } }