public Task <object> StartSession(string sessionId, MethodInfo testMethod, int schedulingSeed) { #if DEBUG Console.WriteLine(">> Session Id : {0}", sessionId); Console.WriteLine("============================================\n"); #endif // Initialize a new AsyncLocal session data this.testingApi.InitializeNewSession(sessionId); Console.WriteLine("\tSession {0}, Run {1}", this.testingApi.CurrentSession.Id, this.testingApi.CurrentSession.RunNumber); var testDefinition = GetTestDefinition(testMethod); // Create a main task so that we have control over // any exception thrown by arbitrary user code. // // The user code could be async or sync. // In either case, there could be multiple Tasks throwing exceptions. // This is challenging to deal with elegantly, so we simply silence exceptions // thrown by child Tasks, and only handle the exception thrown by the top-level Task. // See also: https://devblogs.microsoft.com/premier-developer/dissecting-the-async-methods-in-c/ var mainTask = new Promise((resolve, reject) => { /*Console.WriteLine("User Method\n Is Async: {0}\n Returns Task-like: {1}\n Returns NekaraTask: {2}", * testDefinition.Kind.HasFlag(TestDefinition.MethodKind.IsAsync), * testDefinition.Kind.HasFlag(TestDefinition.MethodKind.ReturnsTaskLike), * testDefinition.Kind.HasFlag(TestDefinition.MethodKind.ReturnsNekaraTask));*/ Nekara.Models.Task task; try { if (testDefinition.Kind.HasFlag(TestDefinition.MethodKind.ReturnsNekaraTask)) { task = (Nekara.Models.Task)testMethod.Invoke(null, null); } /*else if (testDefinition.Kind.HasFlag(TestDefinition.MethodKind.ReturnsTaskLike)) * { * task = Nekara.Models.Task.Run(() => testMethod.Invoke(null, null)); * }*/ else { task = Nekara.Models.Task.Run(() => testMethod.Invoke(null, null)); } task.Wait(); } catch (Exception ex) { Console.WriteLine(" [NekaraClient.StartSession] Main Task threw {0}!\n{1}", ex.GetType().Name, ex.Message); } try { var record = this.testingApi.WaitForMainTask(); resolve(record); } catch (Exception ex) { reject(ex); } }).Then(data => { SessionRecord record = SessionRecord.Deserialize((string)data); // if result exists, this is a replayed session lock (this.records) { if (!this.records.ContainsKey(sessionId)) { this.records.Add(sessionId, record); } else { this.records[sessionId] = record; } } #if DEBUG Console.WriteLine("\n--------------------------------------------\n"); Console.WriteLine(" Total Requests:\t{0}", this.testingApi.CurrentSession.numRequests); Console.WriteLine(" Average RTT:\t{0} ms", this.testingApi.CurrentSession.avgRtt); Console.WriteLine("\n\n==========[ Test {0} {1} ]==========\n", sessionId, record.reason == "" ? "PASSED" : "FAILED"); if (record.reason != "") { Console.WriteLine(" " + record.reason); Console.WriteLine("\n==================================== END ===[ {0} ms ]===", record.elapsedMs); } #endif return(record); }).Catch(ex => { Console.WriteLine(ex); throw ex; }); return(mainTask.Task); }