diff options
author | Justin Clark-Casey (justincc) | 2011-12-08 20:52:34 +0000 |
---|---|---|
committer | Justin Clark-Casey (justincc) | 2011-12-08 20:52:34 +0000 |
commit | bc13855e6475ce2df051ad20acdd76756fb22555 (patch) | |
tree | 5fbc8945dd3939e08b74e4e8163490938eb63e7a /OpenSim | |
parent | Remove unnecessary AgentCircuitData null check from Scene.AddNewClient(). (diff) | |
download | opensim-SC-bc13855e6475ce2df051ad20acdd76756fb22555.zip opensim-SC-bc13855e6475ce2df051ad20acdd76756fb22555.tar.gz opensim-SC-bc13855e6475ce2df051ad20acdd76756fb22555.tar.bz2 opensim-SC-bc13855e6475ce2df051ad20acdd76756fb22555.tar.xz |
Reactivate BasicCircuitTests.TestAddClient()
This checks that the initial UseCircuitCode packet is handled correctly for a normal client login.
Diffstat (limited to 'OpenSim')
-rw-r--r-- | OpenSim/Framework/Util.cs | 45 | ||||
-rw-r--r-- | OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs | 20 | ||||
-rw-r--r-- | OpenSim/Region/ClientStack/Linden/UDP/OpenSimUDPBase.cs | 2 | ||||
-rw-r--r-- | OpenSim/Region/ClientStack/Linden/UDP/Tests/BasicCircuitTests.cs | 225 |
4 files changed, 167 insertions, 125 deletions
diff --git a/OpenSim/Framework/Util.cs b/OpenSim/Framework/Util.cs index 21cfc09..ed92b2d 100644 --- a/OpenSim/Framework/Util.cs +++ b/OpenSim/Framework/Util.cs | |||
@@ -58,10 +58,12 @@ namespace OpenSim.Framework | |||
58 | /// <remarks> | 58 | /// <remarks> |
59 | /// None is used to execute the method in the same thread that made the call. It should only be used by regression | 59 | /// None is used to execute the method in the same thread that made the call. It should only be used by regression |
60 | /// test code that relies on predictable event ordering. | 60 | /// test code that relies on predictable event ordering. |
61 | /// RegressionTest is used by regression tests. It fires the call synchronously and does not catch any exceptions. | ||
61 | /// </remarks> | 62 | /// </remarks> |
62 | public enum FireAndForgetMethod | 63 | public enum FireAndForgetMethod |
63 | { | 64 | { |
64 | None, | 65 | None, |
66 | RegressionTest, | ||
65 | UnsafeQueueUserWorkItem, | 67 | UnsafeQueueUserWorkItem, |
66 | QueueUserWorkItem, | 68 | QueueUserWorkItem, |
67 | BeginInvoke, | 69 | BeginInvoke, |
@@ -1544,27 +1546,38 @@ namespace OpenSim.Framework | |||
1544 | 1546 | ||
1545 | public static void FireAndForget(System.Threading.WaitCallback callback, object obj) | 1547 | public static void FireAndForget(System.Threading.WaitCallback callback, object obj) |
1546 | { | 1548 | { |
1547 | // When OpenSim interacts with a database or sends data over the wire, it must send this in en_US culture | 1549 | WaitCallback realCallback; |
1548 | // so that we don't encounter problems where, for instance, data is saved with a culture that uses commas | ||
1549 | // for decimals places but is read by a culture that treats commas as number seperators. | ||
1550 | WaitCallback realCallback = delegate(object o) | ||
1551 | { | ||
1552 | Culture.SetCurrentCulture(); | ||
1553 | 1550 | ||
1554 | try | 1551 | if (FireAndForgetMethod == FireAndForgetMethod.RegressionTest) |
1555 | { | 1552 | { |
1556 | callback(o); | 1553 | // If we're running regression tests, then we want any exceptions to rise up to the test code. |
1557 | } | 1554 | realCallback = o => { Culture.SetCurrentCulture(); callback(o); }; |
1558 | catch (Exception e) | 1555 | } |
1556 | else | ||
1557 | { | ||
1558 | // When OpenSim interacts with a database or sends data over the wire, it must send this in en_US culture | ||
1559 | // so that we don't encounter problems where, for instance, data is saved with a culture that uses commas | ||
1560 | // for decimals places but is read by a culture that treats commas as number seperators. | ||
1561 | realCallback = o => | ||
1559 | { | 1562 | { |
1560 | m_log.ErrorFormat( | 1563 | Culture.SetCurrentCulture(); |
1561 | "[UTIL]: Continuing after async_call_method thread terminated with exception {0}{1}", | 1564 | |
1562 | e.Message, e.StackTrace); | 1565 | try |
1563 | } | 1566 | { |
1564 | }; | 1567 | callback(o); |
1568 | } | ||
1569 | catch (Exception e) | ||
1570 | { | ||
1571 | m_log.ErrorFormat( | ||
1572 | "[UTIL]: Continuing after async_call_method thread terminated with exception {0}{1}", | ||
1573 | e.Message, e.StackTrace); | ||
1574 | } | ||
1575 | }; | ||
1576 | } | ||
1565 | 1577 | ||
1566 | switch (FireAndForgetMethod) | 1578 | switch (FireAndForgetMethod) |
1567 | { | 1579 | { |
1580 | case FireAndForgetMethod.RegressionTest: | ||
1568 | case FireAndForgetMethod.None: | 1581 | case FireAndForgetMethod.None: |
1569 | realCallback.Invoke(obj); | 1582 | realCallback.Invoke(obj); |
1570 | break; | 1583 | break; |
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs index 4ab8fd0..ac21805 100644 --- a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs +++ b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs | |||
@@ -611,11 +611,13 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
611 | outgoingPacket.TickCount = Environment.TickCount & Int32.MaxValue; | 611 | outgoingPacket.TickCount = Environment.TickCount & Int32.MaxValue; |
612 | } | 612 | } |
613 | 613 | ||
614 | protected override void PacketReceived(UDPPacketBuffer buffer) | 614 | public override void PacketReceived(UDPPacketBuffer buffer) |
615 | { | 615 | { |
616 | // Debugging/Profiling | 616 | // Debugging/Profiling |
617 | //try { Thread.CurrentThread.Name = "PacketReceived (" + m_scene.RegionInfo.RegionName + ")"; } | 617 | //try { Thread.CurrentThread.Name = "PacketReceived (" + m_scene.RegionInfo.RegionName + ")"; } |
618 | //catch (Exception) { } | 618 | //catch (Exception) { } |
619 | // m_log.DebugFormat( | ||
620 | // "[LLUDPSERVER]: Packet received from {0} in {1}", buffer.RemoteEndPoint, m_scene.RegionInfo.RegionName); | ||
619 | 621 | ||
620 | LLUDPClient udpClient = null; | 622 | LLUDPClient udpClient = null; |
621 | Packet packet = null; | 623 | Packet packet = null; |
@@ -625,7 +627,13 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
625 | #region Decoding | 627 | #region Decoding |
626 | 628 | ||
627 | if (buffer.DataLength < 7) | 629 | if (buffer.DataLength < 7) |
630 | { | ||
631 | // m_log.WarnFormat( | ||
632 | // "[LLUDPSERVER]: Dropping undersized packet with {0} bytes received from {1} in {2}", | ||
633 | // buffer.DataLength, buffer.RemoteEndPoint, m_scene.RegionInfo.RegionName); | ||
634 | |||
628 | return; // Drop undersizd packet | 635 | return; // Drop undersizd packet |
636 | } | ||
629 | 637 | ||
630 | int headerLen = 7; | 638 | int headerLen = 7; |
631 | if (buffer.Data[6] == 0xFF) | 639 | if (buffer.Data[6] == 0xFF) |
@@ -637,7 +645,13 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
637 | } | 645 | } |
638 | 646 | ||
639 | if (buffer.DataLength < headerLen) | 647 | if (buffer.DataLength < headerLen) |
648 | { | ||
649 | // m_log.WarnFormat( | ||
650 | // "[LLUDPSERVER]: Dropping packet with malformed header received from {0} in {1}", | ||
651 | // buffer.RemoteEndPoint, m_scene.RegionInfo.RegionName); | ||
652 | |||
640 | return; // Malformed header | 653 | return; // Malformed header |
654 | } | ||
641 | 655 | ||
642 | try | 656 | try |
643 | { | 657 | { |
@@ -650,6 +664,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
650 | } | 664 | } |
651 | catch (IndexOutOfRangeException) | 665 | catch (IndexOutOfRangeException) |
652 | { | 666 | { |
667 | // m_log.WarnFormat( | ||
668 | // "[LLUDPSERVER]: Dropping short packet received from {0} in {1}", | ||
669 | // buffer.RemoteEndPoint, m_scene.RegionInfo.RegionName); | ||
670 | |||
653 | return; // Drop short packet | 671 | return; // Drop short packet |
654 | } | 672 | } |
655 | catch(Exception e) | 673 | catch(Exception e) |
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/OpenSimUDPBase.cs b/OpenSim/Region/ClientStack/Linden/UDP/OpenSimUDPBase.cs index 6eebd9d..039379d 100644 --- a/OpenSim/Region/ClientStack/Linden/UDP/OpenSimUDPBase.cs +++ b/OpenSim/Region/ClientStack/Linden/UDP/OpenSimUDPBase.cs | |||
@@ -44,7 +44,7 @@ namespace OpenMetaverse | |||
44 | /// This method is called when an incoming packet is received | 44 | /// This method is called when an incoming packet is received |
45 | /// </summary> | 45 | /// </summary> |
46 | /// <param name="buffer">Incoming packet buffer</param> | 46 | /// <param name="buffer">Incoming packet buffer</param> |
47 | protected abstract void PacketReceived(UDPPacketBuffer buffer); | 47 | public abstract void PacketReceived(UDPPacketBuffer buffer); |
48 | 48 | ||
49 | /// <summary>UDP port to bind to in server mode</summary> | 49 | /// <summary>UDP port to bind to in server mode</summary> |
50 | protected int m_udpPort; | 50 | protected int m_udpPort; |
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/Tests/BasicCircuitTests.cs b/OpenSim/Region/ClientStack/Linden/UDP/Tests/BasicCircuitTests.cs index 9d37cdf..e3b0eab 100644 --- a/OpenSim/Region/ClientStack/Linden/UDP/Tests/BasicCircuitTests.cs +++ b/OpenSim/Region/ClientStack/Linden/UDP/Tests/BasicCircuitTests.cs | |||
@@ -25,6 +25,7 @@ | |||
25 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | 25 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
26 | */ | 26 | */ |
27 | 27 | ||
28 | using System; | ||
28 | using System.Net; | 29 | using System.Net; |
29 | using log4net.Config; | 30 | using log4net.Config; |
30 | using Nini.Config; | 31 | using Nini.Config; |
@@ -32,10 +33,11 @@ using NUnit.Framework; | |||
32 | using OpenMetaverse; | 33 | using OpenMetaverse; |
33 | using OpenMetaverse.Packets; | 34 | using OpenMetaverse.Packets; |
34 | using OpenSim.Framework; | 35 | using OpenSim.Framework; |
36 | using OpenSim.Region.Framework.Scenes; | ||
35 | using OpenSim.Tests.Common; | 37 | using OpenSim.Tests.Common; |
36 | using OpenSim.Tests.Common.Mock; | 38 | using OpenSim.Tests.Common.Mock; |
37 | 39 | ||
38 | namespace OpenSim.Region.ClientStack.LindenUDP.Tests | 40 | namespace OpenSim.Region.ClientStack.LindenUDP |
39 | { | 41 | { |
40 | /// <summary> | 42 | /// <summary> |
41 | /// This will contain basic tests for the LindenUDP client stack | 43 | /// This will contain basic tests for the LindenUDP client stack |
@@ -43,19 +45,22 @@ namespace OpenSim.Region.ClientStack.LindenUDP.Tests | |||
43 | [TestFixture] | 45 | [TestFixture] |
44 | public class BasicCircuitTests | 46 | public class BasicCircuitTests |
45 | { | 47 | { |
46 | [SetUp] | 48 | [TestFixtureSetUp] |
47 | public void Init() | 49 | public void FixtureInit() |
48 | { | 50 | { |
49 | try | 51 | // Don't allow tests to be bamboozled by asynchronous events. Execute everything on the same thread. |
50 | { | 52 | Util.FireAndForgetMethod = FireAndForgetMethod.RegressionTest; |
51 | XmlConfigurator.Configure(); | ||
52 | } | ||
53 | catch | ||
54 | { | ||
55 | // I don't care, just leave log4net off | ||
56 | } | ||
57 | } | 53 | } |
58 | 54 | ||
55 | [TestFixtureTearDown] | ||
56 | public void TearDown() | ||
57 | { | ||
58 | // We must set this back afterwards, otherwise later tests will fail since they're expecting multiple | ||
59 | // threads. Possibly, later tests should be rewritten so none of them require async stuff (which regression | ||
60 | // tests really shouldn't). | ||
61 | Util.FireAndForgetMethod = Util.DefaultFireAndForgetMethod; | ||
62 | } | ||
63 | |||
59 | // /// <summary> | 64 | // /// <summary> |
60 | // /// Add a client for testing | 65 | // /// Add a client for testing |
61 | // /// </summary> | 66 | // /// </summary> |
@@ -78,54 +83,54 @@ namespace OpenSim.Region.ClientStack.LindenUDP.Tests | |||
78 | // testLLUDPServer.LocalScene = scene; | 83 | // testLLUDPServer.LocalScene = scene; |
79 | // } | 84 | // } |
80 | 85 | ||
81 | /// <summary> | 86 | // /// <summary> |
82 | /// Set up a client for tests which aren't concerned with this process itself and where only one client is being | 87 | // /// Set up a client for tests which aren't concerned with this process itself and where only one client is being |
83 | /// tested | 88 | // /// tested |
84 | /// </summary> | 89 | // /// </summary> |
85 | /// <param name="circuitCode"></param> | 90 | // /// <param name="circuitCode"></param> |
86 | /// <param name="epSender"></param> | 91 | // /// <param name="epSender"></param> |
87 | /// <param name="testLLUDPServer"></param> | 92 | // /// <param name="testLLUDPServer"></param> |
88 | /// <param name="acm"></param> | 93 | // /// <param name="acm"></param> |
89 | protected void AddClient( | 94 | // protected void AddClient( |
90 | uint circuitCode, EndPoint epSender, TestLLUDPServer testLLUDPServer, AgentCircuitManager acm) | 95 | // uint circuitCode, EndPoint epSender, TestLLUDPServer testLLUDPServer, AgentCircuitManager acm) |
91 | { | 96 | // { |
92 | UUID myAgentUuid = UUID.Parse("00000000-0000-0000-0000-000000000001"); | 97 | // UUID myAgentUuid = UUID.Parse("00000000-0000-0000-0000-000000000001"); |
93 | UUID mySessionUuid = UUID.Parse("00000000-0000-0000-0000-000000000002"); | 98 | // UUID mySessionUuid = UUID.Parse("00000000-0000-0000-0000-000000000002"); |
94 | 99 | // | |
95 | AddClient(circuitCode, epSender, myAgentUuid, mySessionUuid, testLLUDPServer, acm); | 100 | // AddClient(circuitCode, epSender, myAgentUuid, mySessionUuid, testLLUDPServer, acm); |
96 | } | 101 | // } |
97 | 102 | ||
98 | /// <summary> | 103 | // /// <summary> |
99 | /// Set up a client for tests which aren't concerned with this process itself | 104 | // /// Set up a client for tests which aren't concerned with this process itself |
100 | /// </summary> | 105 | // /// </summary> |
101 | /// <param name="circuitCode"></param> | 106 | // /// <param name="circuitCode"></param> |
102 | /// <param name="epSender"></param> | 107 | // /// <param name="epSender"></param> |
103 | /// <param name="agentId"></param> | 108 | // /// <param name="agentId"></param> |
104 | /// <param name="sessionId"></param> | 109 | // /// <param name="sessionId"></param> |
105 | /// <param name="testLLUDPServer"></param> | 110 | // /// <param name="testLLUDPServer"></param> |
106 | /// <param name="acm"></param> | 111 | // /// <param name="acm"></param> |
107 | protected void AddClient( | 112 | // protected void AddClient( |
108 | uint circuitCode, EndPoint epSender, UUID agentId, UUID sessionId, | 113 | // uint circuitCode, EndPoint epSender, UUID agentId, UUID sessionId, |
109 | TestLLUDPServer testLLUDPServer, AgentCircuitManager acm) | 114 | // TestLLUDPServer testLLUDPServer, AgentCircuitManager acm) |
110 | { | 115 | // { |
111 | AgentCircuitData acd = new AgentCircuitData(); | 116 | // AgentCircuitData acd = new AgentCircuitData(); |
112 | acd.AgentID = agentId; | 117 | // acd.AgentID = agentId; |
113 | acd.SessionID = sessionId; | 118 | // acd.SessionID = sessionId; |
114 | 119 | // | |
115 | UseCircuitCodePacket uccp = new UseCircuitCodePacket(); | 120 | // UseCircuitCodePacket uccp = new UseCircuitCodePacket(); |
116 | 121 | // | |
117 | UseCircuitCodePacket.CircuitCodeBlock uccpCcBlock | 122 | // UseCircuitCodePacket.CircuitCodeBlock uccpCcBlock |
118 | = new UseCircuitCodePacket.CircuitCodeBlock(); | 123 | // = new UseCircuitCodePacket.CircuitCodeBlock(); |
119 | uccpCcBlock.Code = circuitCode; | 124 | // uccpCcBlock.Code = circuitCode; |
120 | uccpCcBlock.ID = agentId; | 125 | // uccpCcBlock.ID = agentId; |
121 | uccpCcBlock.SessionID = sessionId; | 126 | // uccpCcBlock.SessionID = sessionId; |
122 | uccp.CircuitCode = uccpCcBlock; | 127 | // uccp.CircuitCode = uccpCcBlock; |
123 | 128 | // | |
124 | acm.AddNewCircuit(circuitCode, acd); | 129 | // acm.AddNewCircuit(circuitCode, acd); |
125 | 130 | // | |
126 | testLLUDPServer.LoadReceive(uccp, epSender); | 131 | // testLLUDPServer.LoadReceive(uccp, epSender); |
127 | testLLUDPServer.ReceiveData(null); | 132 | // testLLUDPServer.ReceiveData(null); |
128 | } | 133 | // } |
129 | 134 | ||
130 | /// <summary> | 135 | /// <summary> |
131 | /// Build an object name packet for test purposes | 136 | /// Build an object name packet for test purposes |
@@ -144,54 +149,60 @@ namespace OpenSim.Region.ClientStack.LindenUDP.Tests | |||
144 | return onp; | 149 | return onp; |
145 | } | 150 | } |
146 | 151 | ||
147 | // /// <summary> | 152 | /// <summary> |
148 | // /// Test adding a client to the stack | 153 | /// Test adding a client to the stack |
149 | // /// </summary> | 154 | /// </summary> |
150 | // [Test] | 155 | [Test] |
151 | // public void TestAddClient() | 156 | public void TestAddClient() |
152 | // { | 157 | { |
153 | // TestHelper.InMethod(); | 158 | TestHelpers.InMethod(); |
154 | // | 159 | XmlConfigurator.Configure(); |
155 | // uint myCircuitCode = 123456; | 160 | |
156 | // UUID myAgentUuid = UUID.Parse("00000000-0000-0000-0000-000000000001"); | 161 | TestScene scene = SceneHelpers.SetupScene(); |
157 | // UUID mySessionUuid = UUID.Parse("00000000-0000-0000-0000-000000000002"); | 162 | uint myCircuitCode = 123456; |
158 | // | 163 | UUID myAgentUuid = TestHelpers.ParseTail(0x1); |
159 | // TestLLUDPServer testLLUDPServer; | 164 | UUID mySessionUuid = TestHelpers.ParseTail(0x2); |
160 | // TestLLPacketServer testLLPacketServer; | 165 | IPEndPoint testEp = new IPEndPoint(IPAddress.Loopback, 999); |
161 | // AgentCircuitManager acm; | 166 | |
162 | // SetupStack(new MockScene(), out testLLUDPServer, out testLLPacketServer, out acm); | 167 | uint port = 0; |
163 | // | 168 | AgentCircuitManager acm = scene.AuthenticateHandler; |
164 | // AgentCircuitData acd = new AgentCircuitData(); | 169 | |
165 | // acd.AgentID = myAgentUuid; | 170 | LLUDPServer llUdpServer |
166 | // acd.SessionID = mySessionUuid; | 171 | = new LLUDPServer(IPAddress.Any, ref port, 0, false, new IniConfigSource(), acm); |
167 | // | 172 | llUdpServer.AddScene(scene); |
168 | // UseCircuitCodePacket uccp = new UseCircuitCodePacket(); | 173 | |
169 | // | 174 | UseCircuitCodePacket uccp = new UseCircuitCodePacket(); |
170 | // UseCircuitCodePacket.CircuitCodeBlock uccpCcBlock | 175 | |
171 | // = new UseCircuitCodePacket.CircuitCodeBlock(); | 176 | UseCircuitCodePacket.CircuitCodeBlock uccpCcBlock |
172 | // uccpCcBlock.Code = myCircuitCode; | 177 | = new UseCircuitCodePacket.CircuitCodeBlock(); |
173 | // uccpCcBlock.ID = myAgentUuid; | 178 | uccpCcBlock.Code = myCircuitCode; |
174 | // uccpCcBlock.SessionID = mySessionUuid; | 179 | uccpCcBlock.ID = myAgentUuid; |
175 | // uccp.CircuitCode = uccpCcBlock; | 180 | uccpCcBlock.SessionID = mySessionUuid; |
176 | // | 181 | uccp.CircuitCode = uccpCcBlock; |
177 | // EndPoint testEp = new IPEndPoint(IPAddress.Loopback, 999); | 182 | |
178 | // | 183 | byte[] uccpBytes = uccp.ToBytes(); |
179 | // testLLUDPServer.LoadReceive(uccp, testEp); | 184 | UDPPacketBuffer upb = new UDPPacketBuffer(testEp, uccpBytes.Length); |
180 | // testLLUDPServer.ReceiveData(null); | 185 | upb.DataLength = uccpBytes.Length; // God knows why this isn't set by the constructor. |
181 | // | 186 | Buffer.BlockCopy(uccpBytes, 0, upb.Data, 0, uccpBytes.Length); |
182 | // // Circuit shouildn't exist since the circuit manager doesn't know about this circuit for authentication yet | 187 | |
183 | // Assert.IsFalse(testLLUDPServer.HasCircuit(myCircuitCode)); | 188 | llUdpServer.PacketReceived(upb); |
184 | // | 189 | |
185 | // acm.AddNewCircuit(myCircuitCode, acd); | 190 | // Presence shouldn't exist since the circuit manager doesn't know about this circuit for authentication yet |
186 | // | 191 | Assert.That(scene.GetScenePresence(myAgentUuid), Is.Null); |
187 | // testLLUDPServer.LoadReceive(uccp, testEp); | 192 | |
188 | // testLLUDPServer.ReceiveData(null); | 193 | AgentCircuitData acd = new AgentCircuitData(); |
189 | // | 194 | acd.AgentID = myAgentUuid; |
190 | // // Should succeed now | 195 | acd.SessionID = mySessionUuid; |
191 | // Assert.IsTrue(testLLUDPServer.HasCircuit(myCircuitCode)); | 196 | |
192 | // Assert.IsFalse(testLLUDPServer.HasCircuit(101)); | 197 | acm.AddNewCircuit(myCircuitCode, acd); |
193 | // } | 198 | |
194 | // | 199 | llUdpServer.PacketReceived(upb); |
200 | |||
201 | // Should succeed now | ||
202 | ScenePresence sp = scene.GetScenePresence(myAgentUuid); | ||
203 | Assert.That(sp.UUID, Is.EqualTo(myAgentUuid)); | ||
204 | } | ||
205 | |||
195 | // /// <summary> | 206 | // /// <summary> |
196 | // /// Test removing a client from the stack | 207 | // /// Test removing a client from the stack |
197 | // /// </summary> | 208 | // /// </summary> |