using System; using System.Text; using System.Collections.Generic; using System.Linq; using System.Threading; using System.Diagnostics; using Microsoft.VisualStudio.TestTools.UnitTesting; using Perforce.P4; namespace p4api.net.unit.test { [TestClass] public class P4ServerMultiThreadingTest { String TestDir = "c:\\MyTestDir"; P4Command cmd1 = null; P4Command cmd2 = null; P4Command cmd3 = null; P4Command cmd4 = null; P4Command cmd5 = null; P4Command cmd6 = null; int cmdCnt1 = 0; int cmdCnt2 = 0; int cmdCnt3 = 0; int cmdCnt4 = 0; int cmdCnt5 = 0; int cmdCnt6 = 0; bool run = true; TimeSpan delay = TimeSpan.FromMilliseconds(5); private void cmdThreadProc1() { try { while (run) { cmdCnt1++; cmd1 = new P4Command(server, "fstat", false, "//depot/..."); DateTime StartedAt = DateTime.Now; WriteLine(string.Format("Thread 1 starting command: {0:X8}, at {1}", cmd1.CommandId, StartedAt.ToLongTimeString())); P4CommandResult result = cmd1.Run(); WriteLine(string.Format("Thread 1 Finished command: {0:X8}, at {1}, run time {2} Milliseconds", cmd1.CommandId, StartedAt.ToLongTimeString(), (DateTime.Now - StartedAt).TotalMilliseconds)); P4CommandResult lastResult = server.LastResults; Assert.AreEqual(result.Success, lastResult.Success); if (result.InfoOutput != null) { Assert.AreEqual(result.InfoOutput.Count, lastResult.InfoOutput.Count); } else { Assert.IsNull(lastResult.InfoOutput); } if (result.ErrorList != null) { Assert.AreEqual(result.ErrorList.Count, lastResult.ErrorList.Count); } else { Assert.IsNull(result.ErrorList); } if (result.TextOutput != null) { Assert.AreEqual(result.TextOutput, lastResult.TextOutput); } else { Assert.IsNull(lastResult.TextOutput); } if (result.TaggedOutput != null) { Assert.AreEqual(result.TaggedOutput.Count, lastResult.TaggedOutput.Count); } else { Assert.IsNull(lastResult.TaggedOutput); } Assert.AreEqual(result.Cmd, lastResult.Cmd); if (result.CmdArgs != null) { Assert.AreEqual(result.CmdArgs.Length, lastResult.CmdArgs.Length); } else { Assert.IsNull(lastResult.CmdArgs); } if (!result.Success) { WriteLine(string.Format("Thread 1, fstat failed:{0}", (result.ErrorList != null && result.ErrorList.Count > 0) ? result.ErrorList[0].ErrorMessage : "")); } else { WriteLine(string.Format("Thread 1, fstat Success:{0}", (result.InfoOutput != null && result.InfoOutput.Count > 0) ? result.InfoOutput[0].Message : "")); } //Assert.IsTrue(result.Success); if (delay != TimeSpan.Zero) { Thread.Sleep(delay); } } WriteLine(string.Format("Thread 1 cleanly exited after running {0} commands", cmdCnt1)); return; } catch (ThreadAbortException) { Thread.ResetAbort(); return; } catch (Exception ex) { Assert.Fail(ex.Message); } } private void cmdThreadProc2() { try { while (run) { cmdCnt2++; cmd2 = new P4Command(server, "dirs", false, "//depot/*"); DateTime StartedAt = DateTime.Now; WriteLine(string.Format("Thread 2 starting command: {0:X8}, at {1}", cmd2.CommandId, StartedAt.ToLongTimeString())); P4CommandResult result = cmd2.Run(); WriteLine(string.Format("Thread 2 Finished command: {0:X8}, at {1}, run time {2} Milliseconds", cmd2.CommandId, StartedAt.ToLongTimeString(), (DateTime.Now - StartedAt).TotalMilliseconds)); P4CommandResult lastResult = server.LastResults; Assert.AreEqual(result.Success, lastResult.Success); if (result.InfoOutput != null) { Assert.AreEqual(result.InfoOutput.Count, lastResult.InfoOutput.Count); } else { Assert.IsNull(lastResult.InfoOutput); } if (result.ErrorList != null) { Assert.AreEqual(result.ErrorList.Count, lastResult.ErrorList.Count); } else { Assert.IsNull(result.ErrorList); } if (result.TextOutput != null) { Assert.AreEqual(result.TextOutput, lastResult.TextOutput); } else { Assert.IsNull(lastResult.TextOutput); } if (result.TaggedOutput != null) { Assert.AreEqual(result.TaggedOutput.Count, lastResult.TaggedOutput.Count); } else { Assert.IsNull(lastResult.TaggedOutput); } Assert.AreEqual(result.Cmd, lastResult.Cmd); if (result.CmdArgs != null) { Assert.AreEqual(result.CmdArgs.Length, lastResult.CmdArgs.Length); } else { Assert.IsNull(lastResult.CmdArgs); } if (!result.Success) { WriteLine(string.Format("Thread 2, dirs failed:{0}", (result.ErrorList != null && result.ErrorList.Count > 0) ? result.ErrorList[0].ErrorMessage : "")); } else { WriteLine(string.Format("Thread 2, dirs Success:{0}", (result.InfoOutput != null && result.InfoOutput.Count > 0) ? result.InfoOutput[0].Message : "")); } //Assert.IsTrue(result.Success); if (delay != TimeSpan.Zero) { Thread.Sleep(delay); } } WriteLine(string.Format("Thread 2 cleanly exited after running {0} commands", cmdCnt2)); } catch (ThreadAbortException) { Thread.ResetAbort(); return; } catch (Exception ex) { Assert.Fail(ex.Message); } } private void cmdThreadProc3() { try { while (run) { cmdCnt3++; cmd3 = new P4Command(server, "edit", false, "-n", "C:\\MyTestDir\\admin_space\\..."); DateTime StartedAt = DateTime.Now; WriteLine(string.Format("Thread 3 starting command: {0:X8}, at {1}", cmd3.CommandId, StartedAt.ToLongTimeString())); P4CommandResult result = cmd3.Run(); WriteLine(string.Format("Thread 3 Finished command: {0:X8}, at {1}, run time {2} Milliseconds", cmd3.CommandId, StartedAt.ToLongTimeString(), (DateTime.Now - StartedAt).TotalMilliseconds)); P4CommandResult lastResult = server.LastResults; Assert.AreEqual(result.Success, lastResult.Success); if (result.InfoOutput != null) { Assert.AreEqual(result.InfoOutput.Count, lastResult.InfoOutput.Count); } else { Assert.IsNull(lastResult.InfoOutput); } if (result.ErrorList != null) { Assert.AreEqual(result.ErrorList.Count, lastResult.ErrorList.Count); } else { Assert.IsNull(result.ErrorList); } if (result.TextOutput != null) { Assert.AreEqual(result.TextOutput, lastResult.TextOutput); } else { Assert.IsNull(lastResult.TextOutput); } if (result.TaggedOutput != null) { Assert.AreEqual(result.TaggedOutput.Count, lastResult.TaggedOutput.Count); } else { Assert.IsNull(lastResult.TaggedOutput); } Assert.AreEqual(result.Cmd, lastResult.Cmd); if (result.CmdArgs != null) { Assert.AreEqual(result.CmdArgs.Length, lastResult.CmdArgs.Length); } else { Assert.IsNull(lastResult.CmdArgs); } if (!result.Success) { WriteLine(string.Format("Thread 3, edit failed:{0}", (result.ErrorList != null && result.ErrorList.Count > 0) ? result.ErrorList[0].ErrorMessage : "")); } else { WriteLine(string.Format("Thread 3, edit Success:{0}", (result.InfoOutput != null && result.InfoOutput.Count > 0) ? result.InfoOutput[0].Message : "")); } //Assert.IsTrue(result.Success); if (delay != TimeSpan.Zero) { Thread.Sleep(delay); } } WriteLine(string.Format("Thread 3 cleanly exited after running {0} commands", cmdCnt3)); } catch (ThreadAbortException) { Thread.ResetAbort(); return; } catch (Exception ex) { Assert.Fail(ex.Message); } } private void cmdThreadProc4() { try { while (run) { cmdCnt4++; string val = P4Server.Get("P4IGNORE"); bool _p4IgnoreSet = !string.IsNullOrEmpty(val); if (_p4IgnoreSet) { WriteLine(string.Format("P4Ignore is set, {0}", val)); } else { WriteLine("P4Ignore is not set"); } cmd4 = new P4Command(server, "fstat", false, "//depot/..."); DateTime StartedAt = DateTime.Now; WriteLine(string.Format("Thread 4 starting command: {0:X8}, at {1}", cmd4.CommandId, StartedAt.ToLongTimeString())); P4CommandResult result = cmd4.Run(); WriteLine(string.Format("Thread 4 Finished command: {0:X8}, at {1}, run time {2} Milliseconds", cmd4.CommandId, StartedAt.ToLongTimeString(), (DateTime.Now - StartedAt).TotalMilliseconds)); P4CommandResult lastResult = server.LastResults; Assert.AreEqual(result.Success, lastResult.Success); if (result.InfoOutput != null) { Assert.AreEqual(result.InfoOutput.Count, lastResult.InfoOutput.Count); } else { Assert.IsNull(lastResult.InfoOutput); } if (result.ErrorList != null) { Assert.AreEqual(result.ErrorList.Count, lastResult.ErrorList.Count); } else { Assert.IsNull(result.ErrorList); } if (result.TextOutput != null) { Assert.AreEqual(result.TextOutput, lastResult.TextOutput); } else { Assert.IsNull(lastResult.TextOutput); } if (result.TaggedOutput != null) { Assert.AreEqual(result.TaggedOutput.Count, lastResult.TaggedOutput.Count); } else { Assert.IsNull(lastResult.TaggedOutput); } Assert.AreEqual(result.Cmd, lastResult.Cmd); if (result.CmdArgs != null) { Assert.AreEqual(result.CmdArgs.Length, lastResult.CmdArgs.Length); } else { Assert.IsNull(lastResult.CmdArgs); } if (!result.Success) { WriteLine(string.Format("Thread 4, fstat failed:{0}", (result.ErrorList != null && result.ErrorList.Count > 0) ? result.ErrorList[0].ErrorMessage : "")); } else { WriteLine(string.Format("Thread 4, fstat Success:{0}", (result.InfoOutput != null && result.InfoOutput.Count > 0) ? result.InfoOutput[0].Message : "")); } //Assert.IsTrue(result.Success); if (delay != TimeSpan.Zero) { Thread.Sleep(delay); } } WriteLine(string.Format("Thread 4 cleanly exited after running {0} commands", cmdCnt4)); } catch (ThreadAbortException) { Thread.ResetAbort(); return; } catch (Exception ex) { Assert.Fail(ex.Message); } } private void cmdThreadProc5() { try { while (run) { cmdCnt5++; cmd5 = new P4Command(server, "dirs", false, "//depot/*"); DateTime StartedAt = DateTime.Now; WriteLine(string.Format("Thread 5 starting command: {0:X8}, at {1}", cmd5.CommandId, StartedAt.ToLongTimeString())); P4CommandResult result = cmd5.Run(); WriteLine(string.Format("Thread 5 Finished command: {0:X8}, at {1}, run time {2} Milliseconds", cmd5.CommandId, StartedAt.ToLongTimeString(), (DateTime.Now - StartedAt).TotalMilliseconds)); P4CommandResult lastResult = server.LastResults; Assert.AreEqual(result.Success, lastResult.Success); if (result.InfoOutput != null) { Assert.AreEqual(result.InfoOutput.Count, lastResult.InfoOutput.Count); } else { Assert.IsNull(lastResult.InfoOutput); } if (result.ErrorList != null) { Assert.AreEqual(result.ErrorList.Count, lastResult.ErrorList.Count); } else { Assert.IsNull(result.ErrorList); } if (result.TextOutput != null) { Assert.AreEqual(result.TextOutput, lastResult.TextOutput); } else { Assert.IsNull(lastResult.TextOutput); } if (result.TaggedOutput != null) { Assert.AreEqual(result.TaggedOutput.Count, lastResult.TaggedOutput.Count); } else { Assert.IsNull(lastResult.TaggedOutput); } Assert.AreEqual(result.Cmd, lastResult.Cmd); if (result.CmdArgs != null) { Assert.AreEqual(result.CmdArgs.Length, lastResult.CmdArgs.Length); } else { Assert.IsNull(lastResult.CmdArgs); } if (!result.Success) { WriteLine(string.Format("Thread 5, dirs failed:{0}", (result.ErrorList != null && result.ErrorList.Count > 0) ? result.ErrorList[0].ErrorMessage : "")); } else { WriteLine(string.Format("Thread 5, dirs Success:{0}", (result.InfoOutput != null && result.InfoOutput.Count > 0) ? result.InfoOutput[0].Message : "")); } //Assert.IsTrue(result.Success); if (delay != TimeSpan.Zero) { Thread.Sleep(delay); } } WriteLine(string.Format("Thread 5 cleanly exited after running {0} commands", cmdCnt5)); } catch (ThreadAbortException) { Thread.ResetAbort(); return; } catch (Exception ex) { Assert.Fail(ex.Message); } } private void cmdThreadProc6() { try { while (run) { cmdCnt6++; cmd6 = new P4Command(server, "edit", false, "-n", "C:\\MyTestDir\\admin_space\\..."); DateTime StartedAt = DateTime.Now; WriteLine(string.Format("Thread 6 starting command: {0:X8}, at {1}", cmd6.CommandId, StartedAt.ToLongTimeString())); P4CommandResult result = cmd6.Run(); WriteLine(string.Format("Thread 6 Finished command: {0:X8}, at {1}, run time {2} Milliseconds", cmd6.CommandId, StartedAt.ToLongTimeString(), (DateTime.Now - StartedAt).TotalMilliseconds)); P4CommandResult lastResult = server.LastResults; Assert.AreEqual(result.Success, lastResult.Success); if (result.InfoOutput != null) { Assert.AreEqual(result.InfoOutput.Count, lastResult.InfoOutput.Count); } else { Assert.IsNull(lastResult.InfoOutput); } if (result.ErrorList != null) { Assert.AreEqual(result.ErrorList.Count, lastResult.ErrorList.Count); } else { Assert.IsNull(result.ErrorList); } if (result.TextOutput != null) { Assert.AreEqual(result.TextOutput, lastResult.TextOutput); } else { Assert.IsNull(lastResult.TextOutput); } if (result.TaggedOutput != null) { Assert.AreEqual(result.TaggedOutput.Count, lastResult.TaggedOutput.Count); } else { Assert.IsNull(lastResult.TaggedOutput); } Assert.AreEqual(result.Cmd, lastResult.Cmd); if (result.CmdArgs != null) { Assert.AreEqual(result.CmdArgs.Length, lastResult.CmdArgs.Length); } else { Assert.IsNull(lastResult.CmdArgs); } if (!result.Success) { WriteLine(string.Format("Thread 6, edit failed:{0}", (result.ErrorList != null && result.ErrorList.Count > 0) ? result.ErrorList[0].ErrorMessage : "")); } else { WriteLine(string.Format("Thread 6, edit Success:{0}", (result.InfoOutput != null && result.InfoOutput.Count > 0) ? result.InfoOutput[0].Message : "")); } //Assert.IsTrue(result.Success); if (delay != TimeSpan.Zero) { Thread.Sleep(delay); } } WriteLine(string.Format("Thread 6 cleanly exited after running {0} commands", cmdCnt6)); } catch (ThreadAbortException) { Thread.ResetAbort(); return; } catch (Exception ex) { Assert.Fail(ex.Message); } } P4Server server = null; #if _LOG_TO_FILE static System.IO.StreamWriter sw = null; public static void WriteLine(string msg) { lock (sw) { sw.WriteLine(msg); sw.Flush(); } } public static void LogBridgeMessage( int log_level,String source,String message ) { WriteLine(string.Format("[{0}] {1}:{2}", source, log_level, message)); } private static LogFile.LogMessageDelgate LogFn = new LogFile.LogMessageDelgate(LogBridgeMessage); #else public void WriteLine(string msg) { Trace.WriteLine(msg); } #endif /// ///A test for Running multiple command concurrently /// [TestMethod()] public void RunAsyncTest() { #if _LOG_TO_FILE using (sw = new System.IO.StreamWriter("C:\\Logs\\RunAsyncTestLog.Txt", true)) { LogFile.SetLoggingFunction(LogFn); #endif bool unicode = false; string serverAddr = "localhost:6666"; string user = "admin"; string pass = string.Empty; string ws_client = "admin_space"; // turn off exceptions for this test ErrorSeverity oldExceptionLevel = P4Exception.MinThrowLevel; P4Exception.MinThrowLevel = ErrorSeverity.E_NOEXC; for (int i = 0; i < 1; i++) // run once for ascii, once for unicode { Process p4d = Utilities.DeployP4TestServer(TestDir, unicode); try { using (server = new P4Server(serverAddr, user, pass, ws_client)) { if (unicode) Assert.IsTrue(server.UseUnicode, "Unicode server detected as not supporting Unicode"); else Assert.IsFalse(server.UseUnicode, "Non Unicode server detected as supporting Unicode"); cmdCnt1 = 0; cmdCnt2 = 0; cmdCnt3 = 0; cmdCnt4 = 0; cmdCnt5 = 0; cmdCnt6 = 0; run = true; Thread t1 = new Thread(new ThreadStart(cmdThreadProc1)); t1.Name = "RunAsyncTest Thread t1"; Thread t2 = new Thread(new ThreadStart(cmdThreadProc2)); t2.Name = "RunAsyncTest Thread t2"; Thread t3 = new Thread(new ThreadStart(cmdThreadProc3)); t3.Name = "RunAsyncTest Thread t3"; Thread t4 = new Thread(new ThreadStart(cmdThreadProc4)); t4.Name = "RunAsyncTest Thread t4"; Thread t5 = new Thread(new ThreadStart(cmdThreadProc5)); t5.Name = "RunAsyncTest Thread t5"; Thread t6 = new Thread(new ThreadStart(cmdThreadProc6)); t6.Name = "RunAsyncTest Thread t6"; t1.Start(); Thread.Sleep(TimeSpan.FromSeconds(5)); // wait to start a 4th thread t2.Start(); t3.Start(); Thread.Sleep(TimeSpan.FromSeconds(5)); // wait to start a 4th thread run = false; if (t1.Join(1000) == false) { WriteLine("Thread 1 did not cleanly exit"); t1.Abort(); } if (t2.Join(1000) == false) { WriteLine("Thread 2 did not cleanly exit"); t2.Abort(); } if (t3.Join(1000) == false) { WriteLine("Thread 3 did not cleanly exit"); t3.Abort(); } Thread.Sleep(TimeSpan.FromSeconds(15)); // wait 15 seconds so will disconnect run = true; ; t1 = new Thread(new ThreadStart(cmdThreadProc1)); t1.Name = "RunAsyncTest Thread t1b"; t2 = new Thread(new ThreadStart(cmdThreadProc2)); t2.Name = "RunAsyncTest Thread t2b"; t3 = new Thread(new ThreadStart(cmdThreadProc3)); t3.Name = "RunAsyncTest Thread t3b"; t1.Start(); t2.Start(); t3.Start(); Thread.Sleep(TimeSpan.FromSeconds(1)); // wait to start a 4th thread t4.Start(); Thread.Sleep(TimeSpan.FromSeconds(2)); // wait to start a 5th thread t5.Start(); Thread.Sleep(TimeSpan.FromSeconds(3)); // wait to start a 6th thread t6.Start(); //Thread.Sleep(TimeSpan.FromMinutes(15)); // run all threads for 15 sseconds Thread.Sleep(TimeSpan.FromSeconds(15)); // run all threads for 15 sseconds run = false; if (t1.Join(1000) == false) { WriteLine("Thread 1 did not cleanly exit"); t1.Abort(); } if (t2.Join(1000) == false) { WriteLine("Thread 2 did not cleanly exit"); t2.Abort(); } if (t3.Join(1000) == false) { WriteLine("Thread 3 did not cleanly exit"); t3.Abort(); } if (t4.Join(1000) == false) { WriteLine("Thread 4 did not cleanly exit"); t4.Abort(); } if (t5.Join(1000) == false) { WriteLine("Thread 5 did not cleanly exit"); t5.Abort(); } if (t6.Join(1000) == false) { WriteLine("Thread 6 did not cleanly exit"); t6.Abort(); } } } catch (Exception ex) { Assert.Fail("Test threw an exception: {0}\r\n{1}", ex.Message, ex.StackTrace); } finally { Utilities.RemoveTestServer(p4d, TestDir); } unicode = !unicode; } // reset the exception level P4Exception.MinThrowLevel = oldExceptionLevel; #if _LOG_TO_FILE } #endif } } }