/* * Copyright (c) Contributors, http://opensimulator.org/ * See CONTRIBUTORS.TXT for a full list of copyright holders. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the OpenSimulator Project nor the * names of its contributors may be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ using System; using System.Collections.Generic; using log4net.Config; using Nini.Config; using NUnit.Framework; using OpenMetaverse; using OpenSim.Framework; using OpenSim.Framework.Servers; using OpenSim.Framework.Servers.HttpServer; using OpenSim.Region.CoreModules.Avatar.Chat; using OpenSim.Region.CoreModules.Framework; using OpenSim.Region.CoreModules.Framework.EntityTransfer; using OpenSim.Region.CoreModules.ServiceConnectorsOut.Simulation; using OpenSim.Region.Framework.Scenes; using OpenSim.Services.Interfaces; using OpenSim.Tests.Common; using System.Threading; namespace OpenSim.Region.CoreModules.Avatar.Chat.Tests { [TestFixture] public class ChatModuleTests : OpenSimTestCase { [TestFixtureSetUp] public void FixtureInit() { // Don't allow tests to be bamboozled by asynchronous events. Execute everything on the same thread. // We must do this here so that child agent positions are updated in a predictable manner. Util.FireAndForgetMethod = FireAndForgetMethod.RegressionTest; } [TestFixtureTearDown] public void TearDown() { // We must set this back afterwards, otherwise later tests will fail since they're expecting multiple // threads. Possibly, later tests should be rewritten so none of them require async stuff (which regression // tests really shouldn't). Util.FireAndForgetMethod = Util.DefaultFireAndForgetMethod; } private void SetupNeighbourRegions(TestScene sceneA, TestScene sceneB) { // XXX: HTTP server is not (and should not be) necessary for this test, though it's absence makes the // CapabilitiesModule complain when it can't set up HTTP endpoints. BaseHttpServer httpServer = new BaseHttpServer(99999); MainServer.AddHttpServer(httpServer); MainServer.Instance = httpServer; // We need entity transfer modules so that when sp2 logs into the east region, the region calls // EntityTransferModuleto set up a child agent on the west region. // XXX: However, this is not an entity transfer so is misleading. EntityTransferModule etmA = new EntityTransferModule(); EntityTransferModule etmB = new EntityTransferModule(); LocalSimulationConnectorModule lscm = new LocalSimulationConnectorModule(); IConfigSource config = new IniConfigSource(); config.AddConfig("Chat"); IConfig modulesConfig = config.AddConfig("Modules"); modulesConfig.Set("EntityTransferModule", etmA.Name); modulesConfig.Set("SimulationServices", lscm.Name); SceneHelpers.SetupSceneModules(new Scene[] { sceneA, sceneB }, config, lscm); SceneHelpers.SetupSceneModules(sceneA, config, new CapabilitiesModule(), etmA, new ChatModule()); SceneHelpers.SetupSceneModules(sceneB, config, new CapabilitiesModule(), etmB, new ChatModule()); } /// /// Tests chat between neighbour regions on the east-west axis /// /// /// Really, this is a combination of a child agent position update test and a chat range test. These need /// to be separated later on. /// [Test] public void TestInterRegionChatDistanceEastWest() { TestHelpers.InMethod(); // TestHelpers.EnableLogging(); UUID sp1Uuid = TestHelpers.ParseTail(0x11); UUID sp2Uuid = TestHelpers.ParseTail(0x12); Vector3 sp1Position = new Vector3(6, 128, 20); Vector3 sp2Position = new Vector3(250, 128, 20); SceneHelpers sh = new SceneHelpers(); TestScene sceneWest = sh.SetupScene("sceneWest", TestHelpers.ParseTail(0x1), 1000, 1000); TestScene sceneEast = sh.SetupScene("sceneEast", TestHelpers.ParseTail(0x2), 1001, 1000); SetupNeighbourRegions(sceneWest, sceneEast); ScenePresence sp1 = SceneHelpers.AddScenePresence(sceneEast, sp1Uuid); TestClient sp1Client = (TestClient)sp1.ControllingClient; // If we don't set agents to flying, test will go wrong as they instantly fall to z = 0. // TODO: May need to create special complete no-op test physics module rather than basic physics, since // physics is irrelevant to this test. sp1.Flying = true; // When sp1 logs in to sceneEast, it sets up a child agent in sceneWest and informs the sp2 client to // make the connection. For this test, will simplify this chain by making the connection directly. ScenePresence sp1Child = SceneHelpers.AddChildScenePresence(sceneWest, sp1Uuid); TestClient sp1ChildClient = (TestClient)sp1Child.ControllingClient; sp1.AbsolutePosition = sp1Position; ScenePresence sp2 = SceneHelpers.AddScenePresence(sceneWest, sp2Uuid); TestClient sp2Client = (TestClient)sp2.ControllingClient; sp2.Flying = true; ScenePresence sp2Child = SceneHelpers.AddChildScenePresence(sceneEast, sp2Uuid); TestClient sp2ChildClient = (TestClient)sp2Child.ControllingClient; sp2.AbsolutePosition = sp2Position; // We must update the scenes in order to make the root new root agents trigger position updates in their // children. for (int i = 0; i < 6; ++i) { sceneWest.Update(1); sceneEast.Update(1); } sp1.DrawDistance += 64; sp2.DrawDistance += 64; for (int i = 0; i < 6; ++i) { sceneWest.Update(1); sceneEast.Update(1); } // Check child positions are correct. Assert.AreEqual( new Vector3(sp1Position.X + sceneEast.RegionInfo.RegionSizeX, sp1Position.Y, sp1Position.Z), sp1ChildClient.SceneAgent.AbsolutePosition); Assert.AreEqual( new Vector3(sp2Position.X - sceneWest.RegionInfo.RegionSizeX, sp2Position.Y, sp2Position.Z), sp2ChildClient.SceneAgent.AbsolutePosition); string receivedSp1ChatMessage = ""; string receivedSp2ChatMessage = ""; sp1ChildClient.OnReceivedChatMessage += (message, type, fromPos, fromName, fromAgentID, ownerID, source, audible) => receivedSp1ChatMessage = message; sp2ChildClient.OnReceivedChatMessage += (message, type, fromPos, fromName, fromAgentID, ownerID, source, audible) => receivedSp2ChatMessage = message; TestUserInRange(sp1Client, "ello darling", ref receivedSp2ChatMessage); TestUserInRange(sp2Client, "fantastic cats", ref receivedSp1ChatMessage); sp1Position = new Vector3(30, 128, 20); sp1.AbsolutePosition = sp1Position; for (int i = 0; i < 2; ++i) { sceneWest.Update(1); sceneEast.Update(1); } Thread.Sleep(12000); // child updates are now time limited for (int i = 0; i < 6; ++i) { sceneWest.Update(1); sceneEast.Update(1); } // Check child position is correct. Assert.AreEqual( new Vector3(sp1Position.X + sceneEast.RegionInfo.RegionSizeX, sp1Position.Y, sp1Position.Z), sp1ChildClient.SceneAgent.AbsolutePosition); TestUserOutOfRange(sp1Client, "beef", ref receivedSp2ChatMessage); TestUserOutOfRange(sp2Client, "lentils", ref receivedSp1ChatMessage); } /// /// Tests chat between neighbour regions on the north-south axis /// /// /// Really, this is a combination of a child agent position update test and a chat range test. These need /// to be separated later on. /// [Test] public void TestInterRegionChatDistanceNorthSouth() { TestHelpers.InMethod(); // TestHelpers.EnableLogging(); UUID sp1Uuid = TestHelpers.ParseTail(0x11); UUID sp2Uuid = TestHelpers.ParseTail(0x12); Vector3 sp1Position = new Vector3(128, 250, 20); Vector3 sp2Position = new Vector3(128, 6, 20); SceneHelpers sh = new SceneHelpers(); TestScene sceneNorth = sh.SetupScene("sceneNorth", TestHelpers.ParseTail(0x1), 1000, 1000); TestScene sceneSouth = sh.SetupScene("sceneSouth", TestHelpers.ParseTail(0x2), 1000, 1001); SetupNeighbourRegions(sceneNorth, sceneSouth); ScenePresence sp1 = SceneHelpers.AddScenePresence(sceneNorth, sp1Uuid); TestClient sp1Client = (TestClient)sp1.ControllingClient; // If we don't set agents to flying, test will go wrong as they instantly fall to z = 0. // TODO: May need to create special complete no-op test physics module rather than basic physics, since // physics is irrelevant to this test. sp1.Flying = true; // When sp1 logs in to sceneEast, it sets up a child agent in sceneNorth and informs the sp2 client to // make the connection. For this test, will simplify this chain by making the connection directly. ScenePresence sp1Child = SceneHelpers.AddChildScenePresence(sceneSouth, sp1Uuid); TestClient sp1ChildClient = (TestClient)sp1Child.ControllingClient; sp1.AbsolutePosition = sp1Position; ScenePresence sp2 = SceneHelpers.AddScenePresence(sceneSouth, sp2Uuid); TestClient sp2Client = (TestClient)sp2.ControllingClient; sp2.Flying = true; ScenePresence sp2Child = SceneHelpers.AddChildScenePresence(sceneNorth, sp2Uuid); TestClient sp2ChildClient = (TestClient)sp2Child.ControllingClient; sp2.AbsolutePosition = sp2Position; // We must update the scenes in order to make the root new root agents trigger position updates in their // children. for (int i = 0; i < 6; ++i) { sceneNorth.Update(1); sceneSouth.Update(1); } sp1.DrawDistance += 64; sp2.DrawDistance += 64; for (int i = 0; i < 6; ++i) { sceneNorth.Update(1); sceneSouth.Update(1); } // Check child positions are correct. Assert.AreEqual( new Vector3(sp1Position.X, sp1Position.Y - sceneNorth.RegionInfo.RegionSizeY, sp1Position.Z), sp1ChildClient.SceneAgent.AbsolutePosition); Assert.AreEqual( new Vector3(sp2Position.X, sp2Position.Y + sceneSouth.RegionInfo.RegionSizeY, sp2Position.Z), sp2ChildClient.SceneAgent.AbsolutePosition); string receivedSp1ChatMessage = ""; string receivedSp2ChatMessage = ""; sp1ChildClient.OnReceivedChatMessage += (message, type, fromPos, fromName, fromAgentID, ownerID, source, audible) => receivedSp1ChatMessage = message; sp2ChildClient.OnReceivedChatMessage += (message, type, fromPos, fromName, fromAgentID, ownerID, source, audible) => receivedSp2ChatMessage = message; TestUserInRange(sp1Client, "ello darling", ref receivedSp2ChatMessage); TestUserInRange(sp2Client, "fantastic cats", ref receivedSp1ChatMessage); sp1Position = new Vector3(30, 128, 20); sp1.AbsolutePosition = sp1Position; sceneNorth.Update(6); sceneSouth.Update(6); Thread.Sleep(12000); // child updates are now time limited sceneNorth.Update(6); sceneSouth.Update(6); // Check child position is correct. Assert.AreEqual( new Vector3(sp1Position.X, sp1Position.Y - sceneNorth.RegionInfo.RegionSizeY, sp1Position.Z), sp1ChildClient.SceneAgent.AbsolutePosition); TestUserOutOfRange(sp1Client, "beef", ref receivedSp2ChatMessage); TestUserOutOfRange(sp2Client, "lentils", ref receivedSp1ChatMessage); } private void TestUserInRange(TestClient speakClient, string testMessage, ref string receivedMessage) { receivedMessage = ""; speakClient.Chat(0, ChatTypeEnum.Say, testMessage); Assert.AreEqual(testMessage, receivedMessage); } private void TestUserOutOfRange(TestClient speakClient, string testMessage, ref string receivedMessage) { receivedMessage = ""; speakClient.Chat(0, ChatTypeEnum.Say, testMessage); Assert.AreNotEqual(testMessage, receivedMessage); } } }