/*
* 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.Threading;
using Nini.Config;
using NUnit.Framework;
using OpenMetaverse;
using OpenSim.Framework;
using OpenSim.Region.CoreModules.Framework.EntityTransfer;
using OpenSim.Region.CoreModules.ServiceConnectorsOut.Simulation;
using OpenSim.Region.Framework.Scenes;
using OpenSim.Region.ScriptEngine.Shared;
using OpenSim.Tests.Common;
namespace OpenSim.Region.ScriptEngine.XEngine.Tests
{
///
/// XEngine tests connected with crossing scripts between regions.
///
[TestFixture]
public class XEngineCrossingTests : OpenSimTestCase
{
[TestFixtureSetUp]
public void FixtureInit()
{
// Don't allow tests to be bamboozled by asynchronous events. Execute everything on the same thread.
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;
}
///
/// Test script state preservation when a script crosses between regions on the same simulator.
///
[Test]
public void TestScriptCrossOnSameSimulator()
{
TestHelpers.InMethod();
// TestHelpers.EnableLogging();
UUID userId = TestHelpers.ParseTail(0x1);
int sceneObjectIdTail = 0x2;
EntityTransferModule etmA = new EntityTransferModule();
EntityTransferModule etmB = new EntityTransferModule();
LocalSimulationConnectorModule lscm = new LocalSimulationConnectorModule();
XEngine xEngineA = new XEngine();
XEngine xEngineB = new XEngine();
xEngineA.DebugLevel = 1;
xEngineB.DebugLevel = 1;
IConfigSource configSource = new IniConfigSource();
IConfig startupConfig = configSource.AddConfig("Startup");
startupConfig.Set("DefaultScriptEngine", "XEngine");
startupConfig.Set("TrustBinaries", "true");
IConfig xEngineConfig = configSource.AddConfig("XEngine");
xEngineConfig.Set("Enabled", "true");
xEngineConfig.Set("StartDelay", "0");
// These tests will not run with AppDomainLoading = true, at least on mono. For unknown reasons, the call
// to AssemblyResolver.OnAssemblyResolve fails.
xEngineConfig.Set("AppDomainLoading", "false");
IConfig modulesConfig = configSource.AddConfig("Modules");
modulesConfig.Set("EntityTransferModule", etmA.Name);
modulesConfig.Set("SimulationServices", lscm.Name);
SceneHelpers sh = new SceneHelpers();
TestScene sceneA = sh.SetupScene("sceneA", TestHelpers.ParseTail(0x100), 1000, 1000, configSource);
TestScene sceneB = sh.SetupScene("sceneB", TestHelpers.ParseTail(0x200), 1000, 999, configSource);
SceneHelpers.SetupSceneModules(new Scene[] { sceneA, sceneB }, configSource, lscm);
SceneHelpers.SetupSceneModules(sceneA, configSource, etmA, xEngineA);
SceneHelpers.SetupSceneModules(sceneB, configSource, etmB, xEngineB);
sceneA.StartScripts();
sceneB.StartScripts();
SceneObjectGroup soSceneA = SceneHelpers.AddSceneObject(sceneA, 1, userId, "so1-", sceneObjectIdTail);
soSceneA.AbsolutePosition = new Vector3(128, 10, 20);
string soSceneAName = soSceneA.Name;
string scriptItemSceneAName = "script1";
// CREATE SCRIPT TODO
InventoryItemBase scriptItemSceneA = new InventoryItemBase();
// itemTemplate.ID = itemId;
scriptItemSceneA.Name = scriptItemSceneAName;
scriptItemSceneA.Folder = soSceneA.UUID;
scriptItemSceneA.InvType = (int)InventoryType.LSL;
AutoResetEvent chatEvent = new AutoResetEvent(false);
OSChatMessage messageReceived = null;
sceneA.EventManager.OnChatFromWorld += (s, m) => { messageReceived = m; chatEvent.Set(); };
sceneA.RezNewScript(userId, scriptItemSceneA,
@"integer c = 0;
default
{
state_entry()
{
llSay(0, ""Script running"");
}
changed(integer change)
{
llSay(0, ""Changed"");
}
touch_start(integer n)
{
c = c + 1;
llSay(0, (string)c);
}
}");
chatEvent.WaitOne(60000);
Assert.That(messageReceived, Is.Not.Null, "No chat message received.");
Assert.That(messageReceived.Message, Is.EqualTo("Script running"));
{
// XXX: Should not be doing this so directly. Should call some variant of EventManager.touch() instead.
DetectParams[] det = new DetectParams[1];
det[0] = new DetectParams();
det[0].Key = userId;
det[0].Populate(sceneA);
EventParams ep = new EventParams("touch_start", new Object[] { new LSL_Types.LSLInteger(1) }, det);
messageReceived = null;
chatEvent.Reset();
xEngineA.PostObjectEvent(soSceneA.LocalId, ep);
chatEvent.WaitOne(60000);
Assert.That(messageReceived.Message, Is.EqualTo("1"));
}
AutoResetEvent chatEventB = new AutoResetEvent(false);
sceneB.EventManager.OnChatFromWorld += (s, m) => { messageReceived = m; chatEventB.Set(); };
messageReceived = null;
chatEventB.Reset();
// Cross with a negative value
soSceneA.AbsolutePosition = new Vector3(128, -10, 20);
chatEventB.WaitOne(60000);
Assert.That(messageReceived, Is.Not.Null, "No Changed message received.");
Assert.That(messageReceived.Message, Is.Not.Null, "Changed message without content");
Assert.That(messageReceived.Message, Is.EqualTo("Changed"));
// TEST sending event to moved prim and output
{
SceneObjectGroup soSceneB = sceneB.GetSceneObjectGroup(soSceneAName);
TaskInventoryItem scriptItemSceneB = soSceneB.RootPart.Inventory.GetInventoryItem(scriptItemSceneAName);
// XXX: Should not be doing this so directly. Should call some variant of EventManager.touch() instead.
DetectParams[] det = new DetectParams[1];
det[0] = new DetectParams();
det[0].Key = userId;
det[0].Populate(sceneB);
EventParams ep = new EventParams("touch_start", new Object[] { new LSL_Types.LSLInteger(1) }, det);
Thread.Sleep(250); // wait for other change messages to pass
messageReceived = null;
chatEventB.Reset();
xEngineB.PostObjectEvent(soSceneB.LocalId, ep);
chatEventB.WaitOne(60000);
Assert.That(messageReceived.Message, Is.EqualTo("2"));
}
}
}
}