diff --git a/Tests/OpenSim.Capabilities.Handlers.Tests/FetchInventory/Tests/FetchInventory2HandlerTests.cs b/Tests/OpenSim.Capabilities.Handlers.Tests/FetchInventory/Tests/FetchInventory2HandlerTests.cs new file mode 100644 index 00000000000..94c2c89f450 --- /dev/null +++ b/Tests/OpenSim.Capabilities.Handlers.Tests/FetchInventory/Tests/FetchInventory2HandlerTests.cs @@ -0,0 +1,170 @@ +/* + * 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 System.Linq; +using System.Net; +using System.Text.RegularExpressions; +using log4net; +using log4net.Config; +using NUnit.Framework; +using OpenMetaverse; +using OpenSim.Capabilities.Handlers; +using OpenSim.Framework; +using OpenSim.Framework.Servers.HttpServer; +using OpenSim.Region.Framework.Scenes; +using OpenSim.Services.Interfaces; +using OpenSim.Tests.Common; + +namespace OpenSim.Capabilities.Handlers.FetchInventory.Tests +{ + [TestFixture] + public class FetchInventory2HandlerTests : OpenSimTestCase + { + private UUID m_userID = UUID.Random(); + private Scene m_scene; + private UUID m_rootFolderID; + private UUID m_notecardsFolder; + private UUID m_objectsFolder; + + private void Init() + { + // Create an inventory that looks like this: + // + // /My Inventory + // + // /Objects + // Object 1 + // Object 2 + // Object 3 + // /Notecards + // Notecard 1 + // Notecard 2 + // Notecard 3 + // Notecard 4 + // Notecard 5 + + m_scene = new SceneHelpers().SetupScene(); + + m_scene.InventoryService.CreateUserInventory(m_userID); + + m_rootFolderID = m_scene.InventoryService.GetRootFolder(m_userID).ID; + + InventoryFolderBase of = m_scene.InventoryService.GetFolderForType(m_userID, FolderType.Object); + m_objectsFolder = of.ID; + + // Add 3 objects + InventoryItemBase item; + for (int i = 1; i <= 3; i++) + { + item = new InventoryItemBase(new UUID("b0000000-0000-0000-0000-0000000000b" + i), m_userID); + item.AssetID = UUID.Random(); + item.AssetType = (int)AssetType.Object; + item.Folder = m_objectsFolder; + item.Name = "Object " + i; + m_scene.InventoryService.AddItem(item); + } + + InventoryFolderBase ncf = m_scene.InventoryService.GetFolderForType(m_userID, FolderType.Notecard); + m_notecardsFolder = ncf.ID; + + // Add 5 notecards + for (int i = 1; i <= 5; i++) + { + item = new InventoryItemBase(new UUID("10000000-0000-0000-0000-00000000000" + i), m_userID); + item.AssetID = UUID.Random(); + item.AssetType = (int)AssetType.Notecard; + item.Folder = m_notecardsFolder; + item.Name = "Notecard " + i; + m_scene.InventoryService.AddItem(item); + } + + } + + [Test] + public void Test_001_RequestOne() + { + TestHelpers.InMethod(); + + Init(); + + FetchInventory2Handler handler = new FetchInventory2Handler(m_scene.InventoryService, m_userID); + TestOSHttpRequest req = new TestOSHttpRequest(); + TestOSHttpResponse resp = new TestOSHttpResponse(); + + string request = "itemsitem_id"; + request += "10000000-0000-0000-0000-000000000001"; // Notecard 1 + request += ""; + + string llsdresponse = handler.FetchInventoryRequest(request, "/FETCH", string.Empty, req, resp); + + Assert.That(llsdresponse != null, Is.True, "Incorrect null response"); + Assert.That(llsdresponse != string.Empty, Is.True, "Incorrect empty response"); + Assert.That(llsdresponse.Contains(m_userID.ToString()), Is.True, "Response should contain userID"); + + Assert.That(llsdresponse.Contains("10000000-0000-0000-0000-000000000001"), Is.True, "Response does not contain item uuid"); + Assert.That(llsdresponse.Contains("Notecard 1"), Is.True, "Response does not contain item Name"); + Console.WriteLine(llsdresponse); + } + + [Test] + public void Test_002_RequestMany() + { + TestHelpers.InMethod(); + + Init(); + + FetchInventory2Handler handler = new FetchInventory2Handler(m_scene.InventoryService, m_userID); + TestOSHttpRequest req = new TestOSHttpRequest(); + TestOSHttpResponse resp = new TestOSHttpResponse(); + + string request = "items"; + request += "item_id10000000-0000-0000-0000-000000000001"; // Notecard 1 + request += "item_id10000000-0000-0000-0000-000000000002"; // Notecard 2 + request += "item_id10000000-0000-0000-0000-000000000003"; // Notecard 3 + request += "item_id10000000-0000-0000-0000-000000000004"; // Notecard 4 + request += "item_id10000000-0000-0000-0000-000000000005"; // Notecard 5 + request += ""; + + string llsdresponse = handler.FetchInventoryRequest(request, "/FETCH", string.Empty, req, resp); + + Assert.That(llsdresponse != null, Is.True, "Incorrect null response"); + Assert.That(llsdresponse != string.Empty, Is.True, "Incorrect empty response"); + Assert.That(llsdresponse.Contains(m_userID.ToString()), Is.True, "Response should contain userID"); + + Console.WriteLine(llsdresponse); + Assert.That(llsdresponse.Contains("10000000-0000-0000-0000-000000000001"), Is.True, "Response does not contain notecard 1"); + Assert.That(llsdresponse.Contains("10000000-0000-0000-0000-000000000002"), Is.True, "Response does not contain notecard 2"); + Assert.That(llsdresponse.Contains("10000000-0000-0000-0000-000000000003"), Is.True, "Response does not contain notecard 3"); + Assert.That(llsdresponse.Contains("10000000-0000-0000-0000-000000000004"), Is.True, "Response does not contain notecard 4"); + Assert.That(llsdresponse.Contains("10000000-0000-0000-0000-000000000005"), Is.True, "Response does not contain notecard 5"); + } + + } + +} \ No newline at end of file diff --git a/Tests/OpenSim.Capabilities.Handlers.Tests/FetchInventory/Tests/FetchInventoryDescendents2HandlerTests.cs b/Tests/OpenSim.Capabilities.Handlers.Tests/FetchInventory/Tests/FetchInventoryDescendents2HandlerTests.cs new file mode 100644 index 00000000000..d8fe9732aa9 --- /dev/null +++ b/Tests/OpenSim.Capabilities.Handlers.Tests/FetchInventory/Tests/FetchInventoryDescendents2HandlerTests.cs @@ -0,0 +1,303 @@ +/* + * 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 System.Linq; +using System.IO; +using System.Text.RegularExpressions; +using log4net; +using log4net.Config; +using NUnit.Framework; +using OpenMetaverse; +using OpenSim.Capabilities.Handlers; +using OpenSim.Framework; +using OpenSim.Framework.Servers.HttpServer; +using OpenSim.Region.Framework.Scenes; +using OpenSim.Services.Interfaces; +using OpenSim.Tests.Common; + +namespace OpenSim.Capabilities.Handlers.FetchInventory.Tests +{ + [TestFixture] + public class FetchInventoryDescendents2HandlerTests : OpenSimTestCase + { + private UUID m_userID = new UUID("00000000-0000-0000-0000-000000000001"); + private Scene m_scene; + private UUID m_rootFolderID; + private int m_rootDescendents; + private UUID m_notecardsFolder; + private UUID m_objectsFolder; + + private void Init() + { + // Create an inventory that looks like this: + // + // /My Inventory + // + // /Objects + // Some Object + // /Notecards + // Notecard 1 + // Notecard 2 + // /Test Folder + // Link to notecard -> /Notecards/Notecard 2 + // Link to Objects folder -> /Objects + + m_scene = new SceneHelpers().SetupScene(); + + m_scene.InventoryService.CreateUserInventory(m_userID); + + m_rootFolderID = m_scene.InventoryService.GetRootFolder(m_userID).ID; + + InventoryFolderBase of = m_scene.InventoryService.GetFolderForType(m_userID, FolderType.Object); + m_objectsFolder = of.ID; + + // Add an object + InventoryItemBase item = new InventoryItemBase(new UUID("b0000000-0000-0000-0000-00000000000b"), m_userID); + item.AssetID = UUID.Random(); + item.AssetType = (int)AssetType.Object; + item.Folder = m_objectsFolder; + item.Name = "Some Object"; + m_scene.InventoryService.AddItem(item); + + InventoryFolderBase ncf = m_scene.InventoryService.GetFolderForType(m_userID, FolderType.Notecard); + m_notecardsFolder = ncf.ID; + + // Add a notecard + item = new InventoryItemBase(new UUID("10000000-0000-0000-0000-000000000001"), m_userID); + item.AssetID = UUID.Random(); + item.AssetType = (int)AssetType.Notecard; + item.Folder = m_notecardsFolder; + item.Name = "Test Notecard 1"; + m_scene.InventoryService.AddItem(item); + // Add another notecard + item.ID = new UUID("20000000-0000-0000-0000-000000000002"); + item.AssetID = new UUID("a0000000-0000-0000-0000-00000000000a"); + item.Name = "Test Notecard 2"; + m_scene.InventoryService.AddItem(item); + + // Add a folder + InventoryFolderBase folder = new InventoryFolderBase(new UUID("f0000000-0000-0000-0000-00000000000f"), "Test Folder", m_userID, m_rootFolderID); + folder.Type = (short)FolderType.None; + m_scene.InventoryService.AddFolder(folder); + + // Add a link to notecard 2 in Test Folder + item.AssetID = item.ID; // use item ID of notecard 2 + item.ID = new UUID("40000000-0000-0000-0000-000000000004"); + item.AssetType = (int)AssetType.Link; + item.Folder = folder.ID; + item.Name = "Link to notecard"; + m_scene.InventoryService.AddItem(item); + + // Add a link to the Objects folder in Test Folder + item.AssetID = m_scene.InventoryService.GetFolderForType(m_userID, FolderType.Object).ID; // use item ID of Objects folder + item.ID = new UUID("50000000-0000-0000-0000-000000000005"); + item.AssetType = (int)AssetType.LinkFolder; + item.Folder = folder.ID; + item.Name = "Link to Objects folder"; + m_scene.InventoryService.AddItem(item); + + InventoryCollection coll = m_scene.InventoryService.GetFolderContent(m_userID, m_rootFolderID); + m_rootDescendents = coll.Items.Count + coll.Folders.Count; + Console.WriteLine("Number of descendents: " + m_rootDescendents); + } + + private string dorequest(FetchInvDescHandler handler, string request) + { + TestOSHttpRequest req = new TestOSHttpRequest(); + TestOSHttpResponse resp = new TestOSHttpResponse(); + using(ExpiringKey bad = new ExpiringKey(5000)) // bad but this is test + using (MemoryStream ms = new MemoryStream(Utils.StringToBytes(request), false)) + { + req.InputStream = ms; + handler.FetchInventoryDescendentsRequest(req, resp, bad); + } + return Util.UTF8.GetString(resp.RawBuffer); + } + + [Test] + public void Test_001_SimpleFolder() + { + TestHelpers.InMethod(); + + Init(); + + FetchInvDescHandler handler = new FetchInvDescHandler(m_scene.InventoryService, null, m_scene); + + string request = "foldersfetch_folders1fetch_items1folder_id"; + request += m_rootFolderID; + request += "owner_id"; + request += m_userID.ToString(); + request += "sort_order1"; + + string llsdresponse = dorequest(handler, request); + + Assert.That(llsdresponse != null, Is.True, "Incorrect null response"); + Assert.That(llsdresponse != string.Empty, Is.True, "Incorrect empty response"); + Assert.That(llsdresponse.Contains(m_userID.ToString()), Is.True, "Response should contain userID"); + + string descendents = "descendents" + m_rootDescendents + ""; + Assert.That(llsdresponse.Contains(descendents), Is.True, "Incorrect number of descendents"); + Console.WriteLine(llsdresponse); + } + + [Test] + public void Test_002_MultipleFolders() + { + TestHelpers.InMethod(); + + FetchInvDescHandler handler = new FetchInvDescHandler(m_scene.InventoryService, null, m_scene); + + string request = "folders"; + request += "fetch_folders1fetch_items1folder_id"; + request += m_rootFolderID; + request += "owner_id00000000-0000-0000-0000-000000000001sort_order1"; + request += "fetch_folders1fetch_items1folder_id"; + request += m_notecardsFolder; + request += "owner_id00000000-0000-0000-0000-000000000001sort_order1"; + request += ""; + + string llsdresponse = dorequest(handler, request); + Console.WriteLine(llsdresponse); + + string descendents = "descendents" + m_rootDescendents + ""; + Assert.That(llsdresponse.Contains(descendents), Is.True, "Incorrect number of descendents for root folder"); + descendents = "descendents2"; + Assert.That(llsdresponse.Contains(descendents), Is.True, "Incorrect number of descendents for Notecard folder"); + + Assert.That(llsdresponse.Contains("10000000-0000-0000-0000-000000000001"), Is.True, "Notecard 1 is missing from response"); + Assert.That(llsdresponse.Contains("20000000-0000-0000-0000-000000000002"), Is.True, "Notecard 2 is missing from response"); + } + + [Test] + public void Test_003_Links() + { + TestHelpers.InMethod(); + + FetchInvDescHandler handler = new FetchInvDescHandler(m_scene.InventoryService, null, m_scene); + + string request = "foldersfetch_folders1fetch_items1folder_id"; + request += "f0000000-0000-0000-0000-00000000000f"; + request += "owner_id00000000-0000-0000-0000-000000000001sort_order1"; + + string llsdresponse = dorequest(handler, request); + Console.WriteLine(llsdresponse); + + string descendents = "descendents2"; + Assert.That(llsdresponse.Contains(descendents), Is.True, "Incorrect number of descendents for Test Folder"); + + // Make sure that the note card link is included + Assert.That(llsdresponse.Contains("Link to notecard"), Is.True, "Link to notecard is missing"); + + //Make sure the notecard item itself is included + Assert.That(llsdresponse.Contains("Test Notecard 2"), Is.True, "Notecard 2 item (the source) is missing"); + + // Make sure that the source item is before the link item + int pos1 = llsdresponse.IndexOf("Test Notecard 2"); + int pos2 = llsdresponse.IndexOf("Link to notecard"); + Assert.Less(pos1, pos2, "Source of link is after link"); + + // Make sure the folder link is included + Assert.That(llsdresponse.Contains("Link to Objects folder"), Is.True, "Link to Objects folder is missing"); + +/* contents of link folder are not supposed to be listed + // Make sure the objects inside the Objects folder are included + // Note: I'm not entirely sure this is needed, but that's what I found in the implementation + Assert.That(llsdresponse.Contains("Some Object"), Is.True, "Some Object item (contents of the source) is missing"); +*/ + // Make sure that the source item is before the link item + pos1 = llsdresponse.IndexOf("Some Object"); + pos2 = llsdresponse.IndexOf("Link to Objects folder"); + Assert.Less(pos1, pos2, "Contents of source of folder link is after folder link"); + } + + [Test] + public void Test_004_DuplicateFolders() + { + TestHelpers.InMethod(); + + FetchInvDescHandler handler = new FetchInvDescHandler(m_scene.InventoryService, null, m_scene); + + string request = "folders"; + request += "fetch_folders1fetch_items1folder_id"; + request += m_rootFolderID; + request += "owner_id00000000-0000-0000-0000-000000000000sort_order1"; + request += "fetch_folders1fetch_items1folder_id"; + request += m_notecardsFolder; + request += "owner_id00000000-0000-0000-0000-000000000000sort_order1"; + request += "fetch_folders1fetch_items1folder_id"; + request += m_rootFolderID; + request += "owner_id00000000-0000-0000-0000-000000000000sort_order1"; + request += "fetch_folders1fetch_items1folder_id"; + request += m_notecardsFolder; + request += "owner_id00000000-0000-0000-0000-000000000000sort_order1"; + request += ""; + + string llsdresponse = dorequest(handler, request); + Console.WriteLine(llsdresponse); + + string root_folder = "folder_id" + m_rootFolderID + ""; + string notecards_folder = "folder_id" + m_notecardsFolder + ""; + string notecards_category = "category_id" + m_notecardsFolder + ""; + + Assert.That(llsdresponse.Contains(root_folder), "Missing root folder"); + Assert.That(llsdresponse.Contains(notecards_folder), "Missing notecards folder"); + int count = Regex.Matches(llsdresponse, root_folder).Count; + Assert.AreEqual(1, count, "More than 1 root folder in response"); + count = Regex.Matches(llsdresponse, notecards_folder).Count; + Assert.AreEqual(1, count, "More than 1 notecards folder in response"); + count = Regex.Matches(llsdresponse, notecards_category).Count; + Assert.AreEqual(1, count, "More than 1 notecards folder in response"); // Notecards will also be a category on root + } + + [Test] + public void Test_005_FolderZero() + { + + TestHelpers.InMethod(); + + Init(); + + FetchInvDescHandler handler = new FetchInvDescHandler(m_scene.InventoryService, null, m_scene); + + string request = "foldersfetch_folders1fetch_items1folder_id"; + request += UUID.Zero; + request += "owner_id00000000-0000-0000-0000-000000000000sort_order1"; + + string llsdresponse = dorequest(handler, request); + + Assert.That(llsdresponse != null, Is.True, "Incorrect null response"); + Assert.That(llsdresponse != string.Empty, Is.True, "Incorrect empty response"); + // we do return a answer now + //Assert.That(llsdresponse.Contains("bad_folders00000000-0000-0000-0000-000000000000"), Is.True, "Folder Zero should be a bad folder"); + + Console.WriteLine(llsdresponse); + } + } + +} \ No newline at end of file diff --git a/Tests/OpenSim.Capabilities.Handlers.Tests/GetTexture/Tests/GetTextureHandlerTests.cs b/Tests/OpenSim.Capabilities.Handlers.Tests/GetTexture/Tests/GetTextureHandlerTests.cs new file mode 100644 index 00000000000..61aa689045e --- /dev/null +++ b/Tests/OpenSim.Capabilities.Handlers.Tests/GetTexture/Tests/GetTextureHandlerTests.cs @@ -0,0 +1,64 @@ +/* + * 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 System.Net; +using log4net; +using log4net.Config; +using NUnit.Framework; +using OpenMetaverse; +using OpenSim.Capabilities.Handlers; +using OpenSim.Framework; +using OpenSim.Framework.Servers.HttpServer; +using OpenSim.Region.Framework.Scenes; +using OpenSim.Tests.Common; + +/* +namespace OpenSim.Capabilities.Handlers.GetTexture.Tests +{ + [TestFixture] + public class GetTextureHandlerTests : OpenSimTestCase + { + [Test] + public void TestTextureNotFound() + { + TestHelpers.InMethod(); + + // Overkill - we only really need the asset service, not a whole scene. + Scene scene = new SceneHelpers().SetupScene(); + + GetTextureHandler handler = new GetTextureHandler("/gettexture", scene.AssetService, "TestGetTexture", null, null); + TestOSHttpRequest req = new TestOSHttpRequest(); + TestOSHttpResponse resp = new TestOSHttpResponse(); + req.Url = new Uri("http://localhost/?texture_id=00000000-0000-1111-9999-000000000012"); + handler.Handle(null, null, req, resp); + Assert.That(resp.StatusCode, Is.EqualTo((int)System.Net.HttpStatusCode.NotFound)); + } + } +} +*/ diff --git a/Tests/OpenSim.Capabilities.Handlers.Tests/OpenSim.Capabilities.Handlers.Tests.csproj b/Tests/OpenSim.Capabilities.Handlers.Tests/OpenSim.Capabilities.Handlers.Tests.csproj new file mode 100644 index 00000000000..c061ab1f438 --- /dev/null +++ b/Tests/OpenSim.Capabilities.Handlers.Tests/OpenSim.Capabilities.Handlers.Tests.csproj @@ -0,0 +1,65 @@ + + + net6.0 + + + + ..\..\..\bin\DotNetOpenId.dll + False + + + ..\..\..\bin\Nini.dll + False + + + ..\..\..\bin\OpenMetaverse.dll + False + + + ..\..\..\bin\OpenMetaverse.StructuredData.dll + False + + + ..\..\..\bin\OpenMetaverseTypes.dll + False + + + False + + + False + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Tests/OpenSim.Clients.Assets.Tests/AssetsClient.cs b/Tests/OpenSim.Clients.Assets.Tests/AssetsClient.cs new file mode 100644 index 00000000000..d6731ed81ab --- /dev/null +++ b/Tests/OpenSim.Clients.Assets.Tests/AssetsClient.cs @@ -0,0 +1,124 @@ +/* + * 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 System.Net; +using System.Text; +using System.Reflection; +using System.Threading; + +using OpenMetaverse; +using log4net; +using log4net.Appender; +using log4net.Layout; + +using OpenSim.Framework; +using OpenSim.Services.Interfaces; +using OpenSim.Services.Connectors; + +namespace OpenSim.Tests.Clients.AssetsClient +{ + public class AssetsClient + { + private static readonly ILog m_log = + LogManager.GetLogger( + MethodBase.GetCurrentMethod().DeclaringType); + + private static int m_MaxThreadID = 0; + private static readonly int NREQS = 150; + private static int m_NReceived = 0; + + public static void Main(string[] args) + { + ConsoleAppender consoleAppender = new ConsoleAppender(); + consoleAppender.Layout = + new PatternLayout("[%thread] - %message%newline"); + log4net.Config.BasicConfigurator.Configure(consoleAppender); + + string serverURI = "http://127.0.0.1:8003"; + if (args.Length > 1) + serverURI = args[1]; + int max1, max2; + ThreadPool.GetMaxThreads(out max1, out max2); + m_log.InfoFormat("[ASSET CLIENT]: Connecting to {0} max threads = {1} - {2}", serverURI, max1, max2); + ThreadPool.GetMinThreads(out max1, out max2); + m_log.InfoFormat("[ASSET CLIENT]: Connecting to {0} min threads = {1} - {2}", serverURI, max1, max2); + + if (!ThreadPool.SetMinThreads(1, 1)) + m_log.WarnFormat("[ASSET CLIENT]: Failed to set min threads"); + + if (!ThreadPool.SetMaxThreads(10, 3)) + m_log.WarnFormat("[ASSET CLIENT]: Failed to set max threads"); + + ThreadPool.GetMaxThreads(out max1, out max2); + m_log.InfoFormat("[ASSET CLIENT]: Post set max threads = {1} - {2}", serverURI, max1, max2); + ThreadPool.GetMinThreads(out max1, out max2); + m_log.InfoFormat("[ASSET CLIENT]: Post set min threads = {1} - {2}", serverURI, max1, max2); + + AssetServicesConnector m_Connector = new AssetServicesConnector(serverURI); + m_Connector.MaxAssetRequestConcurrency = 30; + + for (int i = 0; i < NREQS; i++) + { + UUID uuid = UUID.Random(); + m_Connector.Get(uuid.ToString(), null, ResponseReceived); + m_log.InfoFormat("[ASSET CLIENT]: [{0}] requested asset {1}", i, uuid); + } + + for (int i = 0; i < 500; i++) + { + var x = i; + ThreadPool.QueueUserWorkItem(delegate + { + Dummy(x); + }); + } + + Thread.Sleep(30 * 1000); + m_log.InfoFormat("[ASSET CLIENT]: Received responses {0}", m_NReceived); + } + + private static void ResponseReceived(string id, Object sender, AssetBase asset) + { + if (Thread.CurrentThread.ManagedThreadId > m_MaxThreadID) + m_MaxThreadID = Thread.CurrentThread.ManagedThreadId; + int max1, max2; + ThreadPool.GetAvailableThreads(out max1, out max2); + m_log.InfoFormat("[ASSET CLIENT]: Received asset {0} ({1}) ({2}-{3}) {4}", id, m_MaxThreadID, max1, max2, DateTime.Now.ToString("hh:mm:ss")); + m_NReceived++; + } + + private static void Dummy(int i) + { + int max1, max2; + ThreadPool.GetAvailableThreads(out max1, out max2); + m_log.InfoFormat("[ASSET CLIENT]: ({0}) Hello! {1} - {2} {3}", i, max1, max2, DateTime.Now.ToString("hh:mm:ss")); + Thread.Sleep(2000); + } + } +} diff --git a/Tests/OpenSim.Clients.Assets.Tests/OpenSim.Tests.Clients.AssetClient.csproj b/Tests/OpenSim.Clients.Assets.Tests/OpenSim.Tests.Clients.AssetClient.csproj new file mode 100644 index 00000000000..d05e87f5124 --- /dev/null +++ b/Tests/OpenSim.Clients.Assets.Tests/OpenSim.Tests.Clients.AssetClient.csproj @@ -0,0 +1,30 @@ + + + net6.0 + Exe + + + + + + + + + ..\..\..\..\bin\Nini.dll + False + + + ..\..\..\..\bin\OpenMetaverse.dll + False + + + ..\..\..\..\bin\OpenMetaverseTypes.dll + False + + + + + + + + \ No newline at end of file diff --git a/Tests/OpenSim.Common.Tests/ANumericalToleranceConstraint.cs b/Tests/OpenSim.Common.Tests/ANumericalToleranceConstraint.cs new file mode 100644 index 00000000000..15c88021fcf --- /dev/null +++ b/Tests/OpenSim.Common.Tests/ANumericalToleranceConstraint.cs @@ -0,0 +1,56 @@ +/* + * 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 NUnit.Framework.Constraints; + +namespace OpenSim.Tests.Common +{ + public abstract class ANumericalToleranceConstraint : Constraint + { + protected double _tolerance; + + public ANumericalToleranceConstraint(double tolerance) + { + if (tolerance < 0) + { + throw new ArgumentException("Tolerance cannot be negative."); + } + _tolerance = tolerance; + } + + protected bool IsWithinDoubleConstraint(double doubleValue, double baseValue) + { + if (doubleValue >= baseValue - _tolerance && doubleValue <= baseValue + _tolerance) + { + return true; + } + + return false; + } + } +} diff --git a/Tests/OpenSim.Common.Tests/DatabaseTestAttribute.cs b/Tests/OpenSim.Common.Tests/DatabaseTestAttribute.cs new file mode 100644 index 00000000000..d6a03cd6883 --- /dev/null +++ b/Tests/OpenSim.Common.Tests/DatabaseTestAttribute.cs @@ -0,0 +1,44 @@ +/* + * 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 System.Text; +using NUnit.Framework; + +namespace OpenSim.Tests.Common +{ + [AttributeUsage(AttributeTargets.All, + AllowMultiple=false, + Inherited=true)] + public class DatabaseTestAttribute : LongRunningAttribute + { + public DatabaseTestAttribute() : base("Database") + { + } + } +} \ No newline at end of file diff --git a/Tests/OpenSim.Common.Tests/DoubleToleranceConstraint.cs b/Tests/OpenSim.Common.Tests/DoubleToleranceConstraint.cs new file mode 100644 index 00000000000..b2f20571ae4 --- /dev/null +++ b/Tests/OpenSim.Common.Tests/DoubleToleranceConstraint.cs @@ -0,0 +1,77 @@ +/* + * 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 NUnit.Framework; +using NUnit.Framework.Constraints; + +namespace OpenSim.Tests.Common +{ + public class DoubleToleranceConstraint : ANumericalToleranceConstraint + { + private double _baseValue; + private double _valueToBeTested; + + public DoubleToleranceConstraint(double baseValue, double tolerance) : base(tolerance) + { + _baseValue = baseValue; + } + + /// + ///Test whether the constraint is satisfied by a given value + /// + ///The value to be tested + /// + ///True for success, false for failure + /// + public override bool Matches(object valueToBeTested) + { + if (valueToBeTested == null) + { + throw new ArgumentException("Constraint cannot be used upon null values."); + } + if (valueToBeTested.GetType() != typeof(double)) + { + throw new ArgumentException("Constraint cannot be used upon non double-values."); + } + + _valueToBeTested = (double)valueToBeTested; + + return IsWithinDoubleConstraint(_valueToBeTested, _baseValue); + } + + public override void WriteDescriptionTo(MessageWriter writer) + { + writer.WriteExpectedValue(string.Format("A value {0} within tolerance of plus or minus {1}",_baseValue,_tolerance)); + } + + public override void WriteActualValueTo(MessageWriter writer) + { + writer.WriteActualValue(_valueToBeTested); + } + } +} diff --git a/Tests/OpenSim.Common.Tests/Helpers/AssetHelpers.cs b/Tests/OpenSim.Common.Tests/Helpers/AssetHelpers.cs new file mode 100644 index 00000000000..974da4ca2bd --- /dev/null +++ b/Tests/OpenSim.Common.Tests/Helpers/AssetHelpers.cs @@ -0,0 +1,168 @@ +/* + * 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.Text; +using OpenMetaverse; +using OpenMetaverse.Assets; +using OpenSim.Framework; +using OpenSim.Region.Framework.Scenes; +using OpenSim.Region.Framework.Scenes.Serialization; +using OpenSim.Services.Interfaces; + +namespace OpenSim.Tests.Common +{ + public class AssetHelpers + { + /// + /// Create a notecard asset with a random uuids and dummy text. + /// + /// + public static AssetBase CreateNotecardAsset() + { + return CreateNotecardAsset(UUID.Random()); + } + + /// + /// Create a notecard asset with dummy text and a random owner. + /// + /// /param> + /// + public static AssetBase CreateNotecardAsset(UUID assetId) + { + return CreateNotecardAsset(assetId, "hello"); + } + + /// + /// Create a notecard asset with a random owner. + /// + /// /param> + /// + /// + public static AssetBase CreateNotecardAsset(UUID assetId, string text) + { + return CreateAsset(assetId, AssetType.Notecard, text, UUID.Random()); + } + +// /// +// /// Create and store a notecard asset with a random uuid and dummy text. +// /// +// /// /param> +// /// +// public static AssetBase CreateNotecardAsset(Scene scene, UUID creatorId) +// { +// AssetBase asset = CreateAsset(UUID.Random(), AssetType.Notecard, "hello", creatorId); +// scene.AssetService.Store(asset); +// return asset; +// } + + /// + /// Create an asset from the given object. + /// + /// + /// The hexadecimal last part of the UUID for the asset created. A UUID of the form "00000000-0000-0000-0000-{0:XD12}" + /// will be used. + /// + /// + /// + public static AssetBase CreateAsset(int assetUuidTail, SceneObjectGroup sog) + { + return CreateAsset(new UUID(string.Format("00000000-0000-0000-0000-{0:X12}", assetUuidTail)), sog); + } + + /// + /// Create an asset from the given object. + /// + /// + /// + /// + public static AssetBase CreateAsset(UUID assetUuid, SceneObjectGroup sog) + { + return CreateAsset( + assetUuid, + AssetType.Object, + Encoding.ASCII.GetBytes(SceneObjectSerializer.ToOriginalXmlFormat(sog)), + sog.OwnerID); + } + + /// + /// Create an asset from the given scene object. + /// + /// + /// The hexadecimal last part of the UUID for the asset created. A UUID of the form "00000000-0000-0000-0000-{0:XD12}" + /// will be used. + /// + /// + /// + public static AssetBase CreateAsset(int assetUuidTail, CoalescedSceneObjects coa) + { + return CreateAsset(new UUID(string.Format("00000000-0000-0000-0000-{0:X12}", assetUuidTail)), coa); + } + + /// + /// Create an asset from the given scene object. + /// + /// + /// + /// + public static AssetBase CreateAsset(UUID assetUuid, CoalescedSceneObjects coa) + { + return CreateAsset( + assetUuid, + AssetType.Object, + Encoding.ASCII.GetBytes(CoalescedSceneObjectsSerializer.ToXml(coa)), + coa.CreatorId); + } + + /// + /// Create an asset from the given data. + /// + public static AssetBase CreateAsset(UUID assetUuid, AssetType assetType, string text, UUID creatorID) + { + AssetNotecard anc = new AssetNotecard(); + anc.BodyText = text; + anc.Encode(); + + return CreateAsset(assetUuid, assetType, anc.AssetData, creatorID); + } + + /// + /// Create an asset from the given data. + /// + public static AssetBase CreateAsset(UUID assetUuid, AssetType assetType, byte[] data, UUID creatorID) + { + AssetBase asset = new AssetBase(assetUuid, assetUuid.ToString(), (sbyte)assetType, creatorID.ToString()); + asset.Data = data; + return asset; + } + + public static string ReadAssetAsString(IAssetService assetService, UUID uuid) + { + byte[] assetData = assetService.GetData(uuid.ToString()); + return Encoding.ASCII.GetString(assetData); + } + } +} diff --git a/Tests/OpenSim.Common.Tests/Helpers/BaseRequestHandlerHelpers.cs b/Tests/OpenSim.Common.Tests/Helpers/BaseRequestHandlerHelpers.cs new file mode 100644 index 00000000000..b27c7197801 --- /dev/null +++ b/Tests/OpenSim.Common.Tests/Helpers/BaseRequestHandlerHelpers.cs @@ -0,0 +1,75 @@ +/* + * 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 System.Text; +using NUnit.Framework; +using OpenSim.Framework; +using OpenSim.Framework.Servers; +using OpenSim.Framework.Servers.HttpServer; + +namespace OpenSim.Tests.Common +{ + public class BaseRequestHandlerHelpers + { + private static string[] m_emptyStringArray = new string[] { }; + + public static void BaseTestGetParams(BaseRequestHandler handler, string assetsPath) + { + Assert.AreEqual(String.Empty, handler.GetParam(null), "Failed on null path."); + Assert.AreEqual(String.Empty, handler.GetParam(""), "Failed on empty path."); + Assert.AreEqual(String.Empty, handler.GetParam("s"), "Failed on short url."); + Assert.AreEqual(String.Empty, handler.GetParam("corruptUrl"), "Failed on corruptUrl."); + + Assert.AreEqual(String.Empty, handler.GetParam(assetsPath)); + Assert.AreEqual("/", handler.GetParam(assetsPath + "/")); + Assert.AreEqual("/a", handler.GetParam(assetsPath + "/a")); + Assert.AreEqual("/b/", handler.GetParam(assetsPath + "/b/")); + Assert.AreEqual("/c/d", handler.GetParam(assetsPath + "/c/d")); + Assert.AreEqual("/e/f/", handler.GetParam(assetsPath + "/e/f/")); + } + + public static void BaseTestSplitParams(BaseRequestHandler handler, string assetsPath) + { + Assert.AreEqual(m_emptyStringArray, handler.SplitParams(null), "Failed on null."); + Assert.AreEqual(m_emptyStringArray, handler.SplitParams(""), "Failed on empty path."); + Assert.AreEqual(m_emptyStringArray, handler.SplitParams("corruptUrl"), "Failed on corrupt url."); + + Assert.AreEqual(m_emptyStringArray, handler.SplitParams(assetsPath), "Failed on empty params."); + Assert.AreEqual(m_emptyStringArray, handler.SplitParams(assetsPath + "/"), "Failed on single slash."); + + Assert.AreEqual(new string[] { "a" }, handler.SplitParams(assetsPath + "/a"), "Failed on first segment."); + Assert.AreEqual(new string[] { "b" }, handler.SplitParams(assetsPath + "/b/"), "Failed on second slash."); + Assert.AreEqual(new string[] { "c", "d" }, handler.SplitParams(assetsPath + "/c/d"), "Failed on second segment."); + Assert.AreEqual(new string[] { "e", "f" }, handler.SplitParams(assetsPath + "/e/f/"), "Failed on trailing slash."); + } + + public static byte[] EmptyByteArray = new byte[] {}; + + } +} diff --git a/Tests/OpenSim.Common.Tests/Helpers/ClientStackHelpers.cs b/Tests/OpenSim.Common.Tests/Helpers/ClientStackHelpers.cs new file mode 100644 index 00000000000..cfb776b2467 --- /dev/null +++ b/Tests/OpenSim.Common.Tests/Helpers/ClientStackHelpers.cs @@ -0,0 +1,95 @@ +/* + * 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.Net; +using Nini.Config; +using OpenMetaverse; +using OpenMetaverse.Packets; +using OpenSim.Framework; +using OpenSim.Region.ClientStack.LindenUDP; +using OpenSim.Region.Framework.Scenes; + +namespace OpenSim.Tests.Common +{ + /// + /// This class adds full UDP client classes and associated scene presence to scene. + /// + /// + /// This is used for testing client stack code. For testing other code, use SceneHelper methods instead since + /// they operate without the burden of setting up UDP structures which should be unnecessary for testing scene + /// code. + /// + public static class ClientStackHelpers + { + public static ScenePresence AddChildClient( + Scene scene, LLUDPServer udpServer, UUID agentId, UUID sessionId, uint circuitCode) + { + IPEndPoint testEp = new IPEndPoint(IPAddress.Loopback, 999); + + UseCircuitCodePacket uccp = new UseCircuitCodePacket(); + + UseCircuitCodePacket.CircuitCodeBlock uccpCcBlock + = new UseCircuitCodePacket.CircuitCodeBlock(); + uccpCcBlock.Code = circuitCode; + uccpCcBlock.ID = agentId; + uccpCcBlock.SessionID = sessionId; + uccp.CircuitCode = uccpCcBlock; + + byte[] uccpBytes = uccp.ToBytes(); + UDPPacketBuffer upb = new UDPPacketBuffer(testEp, uccpBytes.Length); + upb.DataLength = uccpBytes.Length; // God knows why this isn't set by the constructor. + Buffer.BlockCopy(uccpBytes, 0, upb.Data, 0, uccpBytes.Length); + + AgentCircuitData acd = new AgentCircuitData(); + acd.AgentID = agentId; + acd.SessionID = sessionId; + + scene.AuthenticateHandler.AddNewCircuit(circuitCode, acd); + + udpServer.PacketReceived(upb); + + return scene.GetScenePresence(agentId); + } + + public static TestLLUDPServer AddUdpServer(Scene scene) + { + return AddUdpServer(scene, new IniConfigSource()); + } + + public static TestLLUDPServer AddUdpServer(Scene scene, IniConfigSource configSource) + { + uint port = 0; + AgentCircuitManager acm = scene.AuthenticateHandler; + + TestLLUDPServer udpServer = new TestLLUDPServer(IPAddress.Any, port, 0, configSource, acm); + udpServer.AddScene(scene); + + return udpServer; + } + } +} diff --git a/Tests/OpenSim.Common.Tests/Helpers/EntityTransferHelpers.cs b/Tests/OpenSim.Common.Tests/Helpers/EntityTransferHelpers.cs new file mode 100644 index 00000000000..b0c9596665d --- /dev/null +++ b/Tests/OpenSim.Common.Tests/Helpers/EntityTransferHelpers.cs @@ -0,0 +1,123 @@ +/* + * 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 System.IO; +using System.Net; +using System.Reflection; +using System.Text; +using System.Threading; +using log4net; +using Nini.Config; +using NUnit.Framework; +using OpenMetaverse; +using OpenSim.Framework; + +using OpenSim.Framework.Servers; +using OpenSim.Region.Framework.Interfaces; +using OpenSim.Region.Framework.Scenes; +using OpenSim.Region.CoreModules.Framework; +using OpenSim.Tests.Common; + +namespace OpenSim.Tests.Common +{ + public static class EntityTransferHelpers + { + private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + + /// + /// Set up correct handling of the InformClientOfNeighbour call from the source region that triggers the + /// viewer to setup a connection with the destination region. + /// + /// + /// + /// A list that will be populated with any TestClients set up in response to + /// being informed about a destination region. + /// + public static void SetupInformClientOfNeighbourTriggersNeighbourClientCreate( + TestClient tc, List neighbourTcs) + { + // XXX: Confusingly, this is also used for non-neighbour notification (as in teleports that do not use the + // event queue). + + tc.OnTestClientInformClientOfNeighbour += (neighbourHandle, neighbourExternalEndPoint) => + { + uint x, y; + Util.RegionHandleToRegionLoc(neighbourHandle, out x, out y); + + m_log.DebugFormat( + "[TEST CLIENT]: Processing inform client of neighbour located at {0},{1} at {2}", + x, y, neighbourExternalEndPoint); + + AgentCircuitData newAgent = tc.RequestClientInfo(); + + Scene neighbourScene; + SceneManager.Instance.TryGetScene(x, y, out neighbourScene); + + TestClient neighbourTc = new TestClient(newAgent, neighbourScene); + neighbourTcs.Add(neighbourTc); + neighbourScene.AddNewAgent(neighbourTc, PresenceType.User); + }; + } + + /// + /// Set up correct handling of the InformClientOfNeighbour call from the source region that triggers the + /// viewer to setup a connection with the destination region. + /// + /// + /// + /// A list that will be populated with any TestClients set up in response to + /// being informed about a destination region. + /// + public static void SetupSendRegionTeleportTriggersDestinationClientCreateAndCompleteMovement( + TestClient client, List destinationClients) + { + client.OnTestClientSendRegionTeleport + += (regionHandle, simAccess, regionExternalEndPoint, locationID, flags, capsURL) => + { + uint x, y; + Util.RegionHandleToRegionLoc(regionHandle, out x, out y); + + m_log.DebugFormat( + "[TEST CLIENT]: Processing send region teleport for destination at {0},{1} at {2}", + x, y, regionExternalEndPoint); + + AgentCircuitData newAgent = client.RequestClientInfo(); + + Scene destinationScene; + SceneManager.Instance.TryGetScene(x, y, out destinationScene); + + TestClient destinationClient = new TestClient(newAgent, destinationScene); + destinationClients.Add(destinationClient); + destinationScene.AddNewAgent(destinationClient, PresenceType.User); + + ThreadPool.UnsafeQueueUserWorkItem(o => destinationClient.CompleteMovement(), null); + }; + } + } +} diff --git a/Tests/OpenSim.Common.Tests/Helpers/SceneHelpers.cs b/Tests/OpenSim.Common.Tests/Helpers/SceneHelpers.cs new file mode 100644 index 00000000000..60b9732ab8e --- /dev/null +++ b/Tests/OpenSim.Common.Tests/Helpers/SceneHelpers.cs @@ -0,0 +1,739 @@ +/* + * 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.Net; +using System.Collections.Generic; +using Nini.Config; +using OpenMetaverse; +using OpenSim.Data.Null; +using OpenSim.Framework; + +using OpenSim.Framework.Console; +using OpenSim.Region.PhysicsModules.SharedBase; +using OpenSim.Region.Framework.Interfaces; +using OpenSim.Region.Framework.Scenes; +using OpenSim.Region.CoreModules.Avatar.Gods; +using OpenSim.Region.CoreModules.ServiceConnectorsOut.Asset; +using OpenSim.Region.CoreModules.ServiceConnectorsOut.Authentication; +using OpenSim.Region.CoreModules.ServiceConnectorsOut.Inventory; +using OpenSim.Region.CoreModules.ServiceConnectorsOut.Grid; +using OpenSim.Region.CoreModules.ServiceConnectorsOut.UserAccounts; +using OpenSim.Region.CoreModules.ServiceConnectorsOut.Presence; +using OpenSim.Region.PhysicsModule.BasicPhysics; +using OpenSim.Services.Interfaces; +using OpenSim.Server.Base; + +using BaseServerUtils = OpenSim.Server.Base.ServerUtils; + +namespace OpenSim.Tests.Common +{ + /// + /// Helpers for setting up scenes. + /// + public class SceneHelpers + { + /// + /// We need a scene manager so that test clients can retrieve a scene when performing teleport tests. + /// + public SceneManager SceneManager { get; private set; } + + public ISimulationDataService SimDataService { get; private set; } + + private AgentCircuitManager m_acm = new AgentCircuitManager(); + private IEstateDataService m_estateDataService = null; + + private LocalAssetServicesConnector m_assetService; + private LocalAuthenticationServicesConnector m_authenticationService; + private LocalInventoryServicesConnector m_inventoryService; + private RegionGridServicesConnector m_gridService; + private LocalUserAccountServicesConnector m_userAccountService; + private LocalPresenceServicesConnector m_presenceService; + + private TestsAssetCache m_cache; + + private PhysicsScene m_physicsScene; + + public SceneHelpers() : this(null) {} + + public SceneHelpers(TestsAssetCache cache) + { + SceneManager = new SceneManager(); + + m_assetService = StartAssetService(cache); + m_authenticationService = StartAuthenticationService(); + m_inventoryService = StartInventoryService(); + m_gridService = StartGridService(); + m_userAccountService = StartUserAccountService(); + m_presenceService = StartPresenceService(); + + m_inventoryService.PostInitialise(); + m_assetService.PostInitialise(); + m_userAccountService.PostInitialise(); + m_presenceService.PostInitialise(); + + m_cache = cache; + + m_physicsScene = StartPhysicsScene(); + + SimDataService = BaseServerUtils.LoadPlugin("OpenSim.Tests.Common.dll", null); + } + + /// + /// Set up a test scene + /// + /// + /// Automatically starts services, as would the normal runtime. + /// + /// + public TestScene SetupScene() + { + return SetupScene("Unit test region", UUID.Random(), 1000, 1000); + } + + public TestScene SetupScene(string name, UUID id, uint x, uint y) + { + return SetupScene(name, id, x, y, new IniConfigSource()); + } + + public TestScene SetupScene(string name, UUID id, uint x, uint y, IConfigSource configSource) + { + return SetupScene(name, id, x, y, Constants.RegionSize, Constants.RegionSize, configSource); + } + + /// + /// Set up a scene. + /// + /// Name of the region + /// ID of the region + /// X co-ordinate of the region + /// Y co-ordinate of the region + /// X size of scene + /// Y size of scene + /// + /// + public TestScene SetupScene( + string name, UUID id, uint x, uint y, uint sizeX, uint sizeY, IConfigSource configSource) + { + Console.WriteLine("Setting up test scene {0}", name); + + // We must set up a console otherwise setup of some modules may fail + MainConsole.Instance = new MockConsole(); + + RegionInfo regInfo = new RegionInfo(x, y, new IPEndPoint(IPAddress.Loopback, 9000), "127.0.0.1"); + regInfo.RegionName = name; + regInfo.RegionID = id; + regInfo.RegionSizeX = sizeX; + regInfo.RegionSizeY = sizeY; + regInfo.ServerURI = "http://127.0.0.1:9000/"; + + + TestScene testScene = new TestScene( + regInfo, m_acm, SimDataService, m_estateDataService, configSource, null); + + testScene.RegionInfo.EstateSettings = new EstateSettings(); + testScene.RegionInfo.EstateSettings.EstateOwner = UUID.Random(); + + INonSharedRegionModule godsModule = new GodsModule(); + godsModule.Initialise(new IniConfigSource()); + godsModule.AddRegion(testScene); + + // Add scene to physics + ((INonSharedRegionModule)m_physicsScene).AddRegion(testScene); + ((INonSharedRegionModule)m_physicsScene).RegionLoaded(testScene); + + // Add scene to services + m_assetService.AddRegion(testScene); + + if (m_cache != null) + { + m_cache.AddRegion(testScene); + m_cache.RegionLoaded(testScene); + testScene.AddRegionModule(m_cache.Name, m_cache); + } + + m_assetService.RegionLoaded(testScene); + testScene.AddRegionModule(m_assetService.Name, m_assetService); + + m_authenticationService.AddRegion(testScene); + m_authenticationService.RegionLoaded(testScene); + testScene.AddRegionModule(m_authenticationService.Name, m_authenticationService); + + m_inventoryService.AddRegion(testScene); + m_inventoryService.RegionLoaded(testScene); + testScene.AddRegionModule(m_inventoryService.Name, m_inventoryService); + + m_gridService.AddRegion(testScene); + m_gridService.RegionLoaded(testScene); + testScene.AddRegionModule(m_gridService.Name, m_gridService); + + m_userAccountService.AddRegion(testScene); + m_userAccountService.RegionLoaded(testScene); + testScene.AddRegionModule(m_userAccountService.Name, m_userAccountService); + + m_presenceService.AddRegion(testScene); + m_presenceService.RegionLoaded(testScene); + testScene.AddRegionModule(m_presenceService.Name, m_presenceService); + + testScene.SetModuleInterfaces(); + + testScene.LandChannel = new TestLandChannel(testScene); + testScene.LoadWorldMap(); + + testScene.LoginsEnabled = true; + testScene.RegisterRegionWithGrid(); + + SceneManager.Add(testScene); + + return testScene; + } + + private static LocalAssetServicesConnector StartAssetService(TestsAssetCache cache) + { + IConfigSource config = new IniConfigSource(); + config.AddConfig("Modules"); + config.Configs["Modules"].Set("AssetServices", "LocalAssetServicesConnector"); + config.AddConfig("AssetService"); + config.Configs["AssetService"].Set("LocalServiceModule", "OpenSim.Services.AssetService.dll:AssetService"); + config.Configs["AssetService"].Set("StorageProvider", "OpenSim.Tests.Common.dll"); + + LocalAssetServicesConnector assetService = new LocalAssetServicesConnector(); + assetService.Initialise(config); + + if (cache != null) + { + IConfigSource cacheConfig = new IniConfigSource(); + cacheConfig.AddConfig("Modules"); + cacheConfig.Configs["Modules"].Set("AssetCaching", "TestsAssetCache"); + cacheConfig.AddConfig("AssetCache"); + + cache.Initialise(cacheConfig); + } + + return assetService; + } + + private static LocalAuthenticationServicesConnector StartAuthenticationService() + { + IConfigSource config = new IniConfigSource(); + config.AddConfig("Modules"); + config.AddConfig("AuthenticationService"); + config.Configs["Modules"].Set("AuthenticationServices", "LocalAuthenticationServicesConnector"); + config.Configs["AuthenticationService"].Set( + "LocalServiceModule", "OpenSim.Services.AuthenticationService.dll:PasswordAuthenticationService"); + config.Configs["AuthenticationService"].Set("StorageProvider", "OpenSim.Data.Null.dll"); + + LocalAuthenticationServicesConnector service = new LocalAuthenticationServicesConnector(); + service.Initialise(config); + + return service; + } + + private static LocalInventoryServicesConnector StartInventoryService() + { + IConfigSource config = new IniConfigSource(); + config.AddConfig("Modules"); + config.AddConfig("InventoryService"); + config.Configs["Modules"].Set("InventoryServices", "LocalInventoryServicesConnector"); + config.Configs["InventoryService"].Set("LocalServiceModule", "OpenSim.Services.InventoryService.dll:XInventoryService"); + config.Configs["InventoryService"].Set("StorageProvider", "OpenSim.Tests.Common.dll"); + + LocalInventoryServicesConnector inventoryService = new LocalInventoryServicesConnector(); + inventoryService.Initialise(config); + + return inventoryService; + } + + private static RegionGridServicesConnector StartGridService() + { + IConfigSource config = new IniConfigSource(); + config.AddConfig("Modules"); + config.AddConfig("GridService"); + config.Configs["Modules"].Set("GridServices", "RegionGridServicesConnector"); + config.Configs["GridService"].Set("StorageProvider", "OpenSim.Data.Null.dll:NullRegionData"); + config.Configs["GridService"].Set("LocalServiceModule", "OpenSim.Services.GridService.dll:GridService"); + config.Configs["GridService"].Set("ConnectionString", "!static"); + + RegionGridServicesConnector gridService = new RegionGridServicesConnector(); + gridService.Initialise(config); + + return gridService; + } + + /// + /// Start a user account service + /// + /// + /// + private static LocalUserAccountServicesConnector StartUserAccountService() + { + IConfigSource config = new IniConfigSource(); + config.AddConfig("Modules"); + config.AddConfig("UserAccountService"); + config.Configs["Modules"].Set("UserAccountServices", "LocalUserAccountServicesConnector"); + config.Configs["UserAccountService"].Set("StorageProvider", "OpenSim.Data.Null.dll"); + config.Configs["UserAccountService"].Set( + "LocalServiceModule", "OpenSim.Services.UserAccountService.dll:UserAccountService"); + + LocalUserAccountServicesConnector userAccountService = new LocalUserAccountServicesConnector(); + userAccountService.Initialise(config); + + return userAccountService; + } + + /// + /// Start a presence service + /// + /// + private static LocalPresenceServicesConnector StartPresenceService() + { + // Unfortunately, some services share data via statics, so we need to null every time to stop interference + // between tests. + // This is a massive non-obvious pita. + NullPresenceData.Instance = null; + + IConfigSource config = new IniConfigSource(); + config.AddConfig("Modules"); + config.AddConfig("PresenceService"); + config.Configs["Modules"].Set("PresenceServices", "LocalPresenceServicesConnector"); + config.Configs["PresenceService"].Set("StorageProvider", "OpenSim.Data.Null.dll"); + config.Configs["PresenceService"].Set( + "LocalServiceModule", "OpenSim.Services.PresenceService.dll:PresenceService"); + + LocalPresenceServicesConnector presenceService = new LocalPresenceServicesConnector(); + presenceService.Initialise(config); + + return presenceService; + } + + private static PhysicsScene StartPhysicsScene() + { + IConfigSource config = new IniConfigSource(); + config.AddConfig("Startup"); + config.Configs["Startup"].Set("physics", "basicphysics"); + + PhysicsScene pScene = new BasicScene(); + INonSharedRegionModule mod = pScene as INonSharedRegionModule; + mod.Initialise(config); + + return pScene; + } + + /// + /// Setup modules for a scene using their default settings. + /// + /// + /// + public static void SetupSceneModules(Scene scene, params object[] modules) + { + SetupSceneModules(scene, new IniConfigSource(), modules); + } + + /// + /// Setup modules for a scene. + /// + /// + /// If called directly, then all the modules must be shared modules. + /// + /// + /// + /// + public static void SetupSceneModules(Scene scene, IConfigSource config, params object[] modules) + { + SetupSceneModules(new Scene[] { scene }, config, modules); + } + + /// + /// Setup modules for a scene using their default settings. + /// + /// + /// + public static void SetupSceneModules(Scene[] scenes, params object[] modules) + { + SetupSceneModules(scenes, new IniConfigSource(), modules); + } + + /// + /// Setup modules for scenes. + /// + /// + /// If called directly, then all the modules must be shared modules. + /// + /// We are emulating here the normal calls made to setup region modules + /// (Initialise(), PostInitialise(), AddRegion, RegionLoaded()). + /// TODO: Need to reuse normal runtime module code. + /// + /// + /// + /// + public static void SetupSceneModules(Scene[] scenes, IConfigSource config, params object[] modules) + { + List newModules = new List(); + foreach (object module in modules) + { + IRegionModuleBase m = (IRegionModuleBase)module; +// Console.WriteLine("MODULE {0}", m.Name); + m.Initialise(config); + newModules.Add(m); + } + + foreach (IRegionModuleBase module in newModules) + { + if (module is ISharedRegionModule) ((ISharedRegionModule)module).PostInitialise(); + } + + foreach (IRegionModuleBase module in newModules) + { + foreach (Scene scene in scenes) + { + module.AddRegion(scene); + scene.AddRegionModule(module.Name, module); + } + } + + // RegionLoaded is fired after all modules have been appropriately added to all scenes + foreach (IRegionModuleBase module in newModules) + foreach (Scene scene in scenes) + module.RegionLoaded(scene); + + foreach (Scene scene in scenes) { scene.SetModuleInterfaces(); } + } + + /// + /// Generate some standard agent connection data. + /// + /// + /// + public static AgentCircuitData GenerateAgentData(UUID agentId) + { + AgentCircuitData acd = GenerateCommonAgentData(); + + acd.AgentID = agentId; + acd.firstname = "testfirstname"; + acd.lastname = "testlastname"; + acd.ServiceURLs = new Dictionary(); + + return acd; + } + + /// + /// Generate some standard agent connection data. + /// + /// + /// + public static AgentCircuitData GenerateAgentData(UserAccount ua) + { + AgentCircuitData acd = GenerateCommonAgentData(); + + acd.AgentID = ua.PrincipalID; + acd.firstname = ua.FirstName; + acd.lastname = ua.LastName; + acd.ServiceURLs = ua.ServiceURLs; + + return acd; + } + + private static AgentCircuitData GenerateCommonAgentData() + { + AgentCircuitData acd = new AgentCircuitData(); + + // XXX: Sessions must be unique, otherwise one presence can overwrite another in NullPresenceData. + acd.SessionID = UUID.Random(); + acd.SecureSessionID = UUID.Random(); + + acd.circuitcode = 123; + acd.BaseFolder = UUID.Zero; + acd.InventoryFolder = UUID.Zero; + acd.startpos = Vector3.Zero; + acd.CapsPath = "http://wibble.com"; + acd.Appearance = new AvatarAppearance(); + + return acd; + } + + /// + /// Add a root agent where the details of the agent connection (apart from the id) are unimportant for the test + /// + /// + /// XXX: Use the version of this method that takes the UserAccount structure wherever possible - this will + /// make the agent circuit data (e.g. first, lastname) consistent with the user account data. + /// + /// + /// + /// + public static ScenePresence AddScenePresence(Scene scene, UUID agentId) + { + return AddScenePresence(scene, GenerateAgentData(agentId)); + } + + /// + /// Add a root agent. + /// + /// + /// + /// + public static ScenePresence AddScenePresence(Scene scene, UserAccount ua) + { + return AddScenePresence(scene, GenerateAgentData(ua)); + } + + /// + /// Add a root agent. + /// + /// + /// This function + /// + /// 1) Tells the scene that an agent is coming. Normally, the login service (local if standalone, from the + /// userserver if grid) would give initial login data back to the client and separately tell the scene that the + /// agent was coming. + /// + /// 2) Connects the agent with the scene + /// + /// This function performs actions equivalent with notifying the scene that an agent is + /// coming and then actually connecting the agent to the scene. The one step missed out is the very first + /// + /// + /// + /// + public static ScenePresence AddScenePresence(Scene scene, AgentCircuitData agentData) + { + return AddScenePresence(scene, new TestClient(agentData, scene), agentData); + } + + /// + /// Add a root agent. + /// + /// + /// This function + /// + /// 1) Tells the scene that an agent is coming. Normally, the login service (local if standalone, from the + /// userserver if grid) would give initial login data back to the client and separately tell the scene that the + /// agent was coming. + /// + /// 2) Connects the agent with the scene + /// + /// This function performs actions equivalent with notifying the scene that an agent is + /// coming and then actually connecting the agent to the scene. The one step missed out is the very first + /// + /// + /// + /// + public static ScenePresence AddScenePresence( + Scene scene, IClientAPI client, AgentCircuitData agentData) + { + // We emulate the proper login sequence here by doing things in four stages + + // Stage 0: login + // We need to punch through to the underlying service because scene will not, correctly, let us call it + // through it's reference to the LPSC + LocalPresenceServicesConnector lpsc = (LocalPresenceServicesConnector)scene.PresenceService; + lpsc.m_PresenceService.LoginAgent(agentData.AgentID.ToString(), agentData.SessionID, agentData.SecureSessionID); + + // Stages 1 & 2 + ScenePresence sp = IntroduceClientToScene(scene, client, agentData, TeleportFlags.ViaLogin); + + // Stage 3: Complete the entrance into the region. This converts the child agent into a root agent. + sp.CompleteMovement(sp.ControllingClient, true); + + return sp; + } + + /// + /// Introduce an agent into the scene by adding a new client. + /// + /// The scene presence added + /// + /// + /// + /// + private static ScenePresence IntroduceClientToScene( + Scene scene, IClientAPI client, AgentCircuitData agentData, TeleportFlags tf) + { + string reason; + + // Stage 1: tell the scene to expect a new user connection + if (!scene.NewUserConnection(agentData, (uint)tf, null, out reason)) + Console.WriteLine("NewUserConnection failed: " + reason); + + // Stage 2: add the new client as a child agent to the scene + scene.AddNewAgent(client, PresenceType.User); + + return scene.GetScenePresence(client.AgentId); + } + + public static ScenePresence AddChildScenePresence(Scene scene, UUID agentId) + { + return AddChildScenePresence(scene, GenerateAgentData(agentId)); + } + + public static ScenePresence AddChildScenePresence(Scene scene, AgentCircuitData acd) + { + acd.child = true; + + // XXX: ViaLogin may not be correct for child agents + TestClient client = new TestClient(acd, scene); + return IntroduceClientToScene(scene, client, acd, TeleportFlags.ViaLogin); + } + + /// + /// Add a test object + /// + /// + /// + public static SceneObjectGroup AddSceneObject(Scene scene) + { + return AddSceneObject(scene, "Test Object", UUID.Random()); + } + + /// + /// Add a test object + /// + /// + /// + /// + /// + public static SceneObjectGroup AddSceneObject(Scene scene, string name, UUID ownerId) + { + SceneObjectGroup so = new SceneObjectGroup(CreateSceneObjectPart(name, UUID.Random(), ownerId)); + + //part.UpdatePrimFlags(false, false, true); + //part.ObjectFlags |= (uint)PrimFlags.Phantom; + + scene.AddNewSceneObject(so, true); + so.InvalidateDeepEffectivePerms(); + + return so; + } + + /// + /// Add a test object + /// + /// + /// + /// The number of parts that should be in the scene object + /// + /// + /// + /// The prefix to be given to part names. This will be suffixed with "Part" + /// (e.g. mynamePart1 for the root part) + /// + /// + /// The hexadecimal last part of the UUID for parts created. A UUID of the form "00000000-0000-0000-0000-{0:XD12}" + /// will be given to the root part, and incremented for each part thereafter. + /// + /// + public static SceneObjectGroup AddSceneObject(Scene scene, int parts, UUID ownerId, string partNamePrefix, int uuidTail) + { + SceneObjectGroup so = CreateSceneObject(parts, ownerId, partNamePrefix, uuidTail); + + scene.AddNewSceneObject(so, false); + so.InvalidateDeepEffectivePerms(); + + return so; + } + + /// + /// Create a scene object part. + /// + /// + /// + /// + /// + public static SceneObjectPart CreateSceneObjectPart(string name, UUID id, UUID ownerId) + { + return new SceneObjectPart( + ownerId, PrimitiveBaseShape.Default, Vector3.Zero, Quaternion.Identity, Vector3.Zero) + { Name = name, UUID = id, Scale = new Vector3(1, 1, 1) }; + } + + /// + /// Create a scene object but do not add it to the scene. + /// + /// + /// UUID always starts at 00000000-0000-0000-0000-000000000001. For some purposes, (e.g. serializing direct + /// to another object's inventory) we do not need a scene unique ID. So it would be better to add the + /// UUID when we actually add an object to a scene rather than on creation. + /// + /// The number of parts that should be in the scene object + /// + /// + public static SceneObjectGroup CreateSceneObject(int parts, UUID ownerId) + { + return CreateSceneObject(parts, ownerId, 0x1); + } + + /// + /// Create a scene object but do not add it to the scene. + /// + /// The number of parts that should be in the scene object + /// + /// + /// The hexadecimal last part of the UUID for parts created. A UUID of the form "00000000-0000-0000-0000-{0:XD12}" + /// will be given to the root part, and incremented for each part thereafter. + /// + /// + public static SceneObjectGroup CreateSceneObject(int parts, UUID ownerId, int uuidTail) + { + return CreateSceneObject(parts, ownerId, "", uuidTail); + } + + /// + /// Create a scene object but do not add it to the scene. + /// + /// + /// The number of parts that should be in the scene object + /// + /// + /// + /// The prefix to be given to part names. This will be suffixed with "Part" + /// (e.g. mynamePart1 for the root part) + /// + /// + /// The hexadecimal last part of the UUID for parts created. A UUID of the form "00000000-0000-0000-0000-{0:XD12}" + /// will be given to the root part, and incremented for each part thereafter. + /// + /// + public static SceneObjectGroup CreateSceneObject(int parts, UUID ownerId, string partNamePrefix, int uuidTail) + { + string rawSogId = string.Format("00000000-0000-0000-0000-{0:X12}", uuidTail); + + SceneObjectGroup sog + = new SceneObjectGroup( + CreateSceneObjectPart(string.Format("{0}Part1", partNamePrefix), new UUID(rawSogId), ownerId)); + + if (parts > 1) + for (int i = 2; i <= parts; i++) + sog.AddPart( + CreateSceneObjectPart( + string.Format("{0}Part{1}", partNamePrefix, i), + new UUID(string.Format("00000000-0000-0000-0000-{0:X12}", uuidTail + i - 1)), + ownerId)); + + return sog; + } + } +} diff --git a/Tests/OpenSim.Common.Tests/Helpers/TaskInventoryHelpers.cs b/Tests/OpenSim.Common.Tests/Helpers/TaskInventoryHelpers.cs new file mode 100644 index 00000000000..e3110f677c7 --- /dev/null +++ b/Tests/OpenSim.Common.Tests/Helpers/TaskInventoryHelpers.cs @@ -0,0 +1,210 @@ +/* + * 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 OpenMetaverse; +using OpenMetaverse.Assets; +using OpenSim.Framework; +using OpenSim.Region.Framework.Scenes; +using OpenSim.Services.Interfaces; + +namespace OpenSim.Tests.Common +{ + /// + /// Utility functions for carrying out task inventory tests. + /// + /// + public static class TaskInventoryHelpers + { + /// + /// Add a notecard item to the given part. + /// + /// + /// + /// + /// UUID or UUID stem + /// UUID or UUID stem + /// The tex to put in the notecard. + /// The item that was added + public static TaskInventoryItem AddNotecard( + IAssetService assetService, SceneObjectPart part, string itemName, string itemIDStem, string assetIDStem, string text) + { + return AddNotecard( + assetService, part, itemName, TestHelpers.ParseStem(itemIDStem), TestHelpers.ParseStem(assetIDStem), text); + } + + /// + /// Add a notecard item to the given part. + /// + /// + /// + /// + /// + /// + /// The tex to put in the notecard. + /// The item that was added + public static TaskInventoryItem AddNotecard( + IAssetService assetService, SceneObjectPart part, string itemName, UUID itemID, UUID assetID, string text) + { + AssetNotecard nc = new AssetNotecard(); + nc.BodyText = text; + nc.Encode(); + + AssetBase ncAsset + = AssetHelpers.CreateAsset(assetID, AssetType.Notecard, nc.AssetData, UUID.Zero); + assetService.Store(ncAsset); + + TaskInventoryItem ncItem + = new TaskInventoryItem + { Name = itemName, AssetID = assetID, ItemID = itemID, + Type = (int)AssetType.Notecard, InvType = (int)InventoryType.Notecard }; + part.Inventory.AddInventoryItem(ncItem, true); + + return ncItem; + } + + /// + /// Add a simple script to the given part. + /// + /// + /// TODO: Accept input for item and asset IDs to avoid mysterious script failures that try to use any of these + /// functions more than once in a test. + /// + /// + /// + /// The item that was added + public static TaskInventoryItem AddScript(IAssetService assetService, SceneObjectPart part) + { + return AddScript(assetService, part, "scriptItem", "default { state_entry() { llSay(0, \"Hello World\"); } }"); + } + + /// + /// Add a simple script to the given part. + /// + /// + /// TODO: Accept input for item and asset IDs so that we have completely replicatable regression tests rather + /// than a random component. + /// + /// + /// + /// Name of the script to add + /// LSL script source + /// The item that was added + public static TaskInventoryItem AddScript( + IAssetService assetService, SceneObjectPart part, string scriptName, string scriptSource) + { + return AddScript(assetService, part, UUID.Random(), UUID.Random(), scriptName, scriptSource); + } + + /// + /// Add a simple script to the given part. + /// + /// + /// TODO: Accept input for item and asset IDs so that we have completely replicatable regression tests rather + /// than a random component. + /// + /// + /// + /// Item UUID for the script + /// Asset UUID for the script + /// Name of the script to add + /// LSL script source + /// The item that was added + public static TaskInventoryItem AddScript( + IAssetService assetService, SceneObjectPart part, UUID itemId, UUID assetId, string scriptName, string scriptSource) + { + AssetScriptText ast = new AssetScriptText(); + ast.Source = scriptSource; + ast.Encode(); + + AssetBase asset + = AssetHelpers.CreateAsset(assetId, AssetType.LSLText, ast.AssetData, UUID.Zero); + assetService.Store(asset); + TaskInventoryItem item + = new TaskInventoryItem + { Name = scriptName, AssetID = assetId, ItemID = itemId, + Type = (int)AssetType.LSLText, InvType = (int)InventoryType.LSL }; + part.Inventory.AddInventoryItem(item, true); + + return item; + } + + /// + /// Add a scene object item to the given part. + /// + /// + /// TODO: Accept input for item and asset IDs to avoid mysterious script failures that try to use any of these + /// functions more than once in a test. + /// + /// + /// + /// + /// + /// + /// + /// + public static TaskInventoryItem AddSceneObject( + IAssetService assetService, SceneObjectPart sop, string itemName, UUID itemId, SceneObjectGroup soToAdd, UUID soAssetId) + { + AssetBase taskSceneObjectAsset = AssetHelpers.CreateAsset(soAssetId, soToAdd); + assetService.Store(taskSceneObjectAsset); + TaskInventoryItem taskSceneObjectItem + = new TaskInventoryItem + { Name = itemName, + AssetID = taskSceneObjectAsset.FullID, + ItemID = itemId, + OwnerID = soToAdd.OwnerID, + Type = (int)AssetType.Object, + InvType = (int)InventoryType.Object }; + sop.Inventory.AddInventoryItem(taskSceneObjectItem, true); + + return taskSceneObjectItem; + } + + /// + /// Add a scene object item to the given part. + /// + /// + /// TODO: Accept input for item and asset IDs to avoid mysterious script failures that try to use any of these + /// functions more than once in a test. + /// + /// + /// + /// + /// + /// + /// + public static TaskInventoryItem AddSceneObject( + IAssetService assetService, SceneObjectPart sop, string itemName, UUID itemId, UUID userId) + { + SceneObjectGroup taskSceneObject = SceneHelpers.CreateSceneObject(1, userId); + + return TaskInventoryHelpers.AddSceneObject( + assetService, sop, itemName, itemId, taskSceneObject, TestHelpers.ParseTail(0x10)); + } + } +} \ No newline at end of file diff --git a/Tests/OpenSim.Common.Tests/Helpers/UserAccountHelpers.cs b/Tests/OpenSim.Common.Tests/Helpers/UserAccountHelpers.cs new file mode 100644 index 00000000000..e6af34b879f --- /dev/null +++ b/Tests/OpenSim.Common.Tests/Helpers/UserAccountHelpers.cs @@ -0,0 +1,160 @@ +/* + * 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.Collections.Generic; +using OpenMetaverse; + +using OpenSim.Region.Framework.Scenes; +using OpenSim.Services.Interfaces; + +namespace OpenSim.Tests.Common +{ + /// + /// Utility functions for carrying out user profile related tests. + /// + public static class UserAccountHelpers + { +// /// +// /// Create a test user with a standard inventory +// /// +// /// +// /// +// /// Callback to invoke when inventory has been loaded. This is required because +// /// loading may be asynchronous, even on standalone +// /// +// /// +// public static CachedUserInfo CreateUserWithInventory( +// CommunicationsManager commsManager, OnInventoryReceivedDelegate callback) +// { +// UUID userId = UUID.Parse("00000000-0000-0000-0000-000000000099"); +// return CreateUserWithInventory(commsManager, userId, callback); +// } +// +// /// +// /// Create a test user with a standard inventory +// /// +// /// +// /// User ID +// /// +// /// Callback to invoke when inventory has been loaded. This is required because +// /// loading may be asynchronous, even on standalone +// /// +// /// +// public static CachedUserInfo CreateUserWithInventory( +// CommunicationsManager commsManager, UUID userId, OnInventoryReceivedDelegate callback) +// { +// return CreateUserWithInventory(commsManager, "Bill", "Bailey", userId, callback); +// } +// +// /// +// /// Create a test user with a standard inventory +// /// +// /// +// /// First name of user +// /// Last name of user +// /// User ID +// /// +// /// Callback to invoke when inventory has been loaded. This is required because +// /// loading may be asynchronous, even on standalone +// /// +// /// +// public static CachedUserInfo CreateUserWithInventory( +// CommunicationsManager commsManager, string firstName, string lastName, +// UUID userId, OnInventoryReceivedDelegate callback) +// { +// return CreateUserWithInventory(commsManager, firstName, lastName, "troll", userId, callback); +// } +// +// /// +// /// Create a test user with a standard inventory +// /// +// /// +// /// First name of user +// /// Last name of user +// /// Password +// /// User ID +// /// +// /// Callback to invoke when inventory has been loaded. This is required because +// /// loading may be asynchronous, even on standalone +// /// +// /// +// public static CachedUserInfo CreateUserWithInventory( +// CommunicationsManager commsManager, string firstName, string lastName, string password, +// UUID userId, OnInventoryReceivedDelegate callback) +// { +// LocalUserServices lus = (LocalUserServices)commsManager.UserService; +// lus.AddUser(firstName, lastName, password, "bill@bailey.com", 1000, 1000, userId); +// +// CachedUserInfo userInfo = commsManager.UserProfileCacheService.GetUserDetails(userId); +// userInfo.OnInventoryReceived += callback; +// userInfo.FetchInventory(); +// +// return userInfo; +// } + + public static UserAccount CreateUserWithInventory(Scene scene) + { + return CreateUserWithInventory(scene, TestHelpers.ParseTail(99)); + } + + public static UserAccount CreateUserWithInventory(Scene scene, UUID userId) + { + return CreateUserWithInventory(scene, "Bill", "Bailey", userId, "troll"); + } + + public static UserAccount CreateUserWithInventory(Scene scene, int userId) + { + return CreateUserWithInventory(scene, "Bill", "Bailey", TestHelpers.ParseTail(userId), "troll"); + } + + public static UserAccount CreateUserWithInventory( + Scene scene, string firstName, string lastName, UUID userId, string pw) + { + UserAccount ua = new UserAccount(userId) { FirstName = firstName, LastName = lastName }; + CreateUserWithInventory(scene, ua, pw); + return ua; + } + + public static UserAccount CreateUserWithInventory( + Scene scene, string firstName, string lastName, int userId, string pw) + { + UserAccount ua + = new UserAccount(TestHelpers.ParseTail(userId)) { FirstName = firstName, LastName = lastName }; + CreateUserWithInventory(scene, ua, pw); + return ua; + } + + public static void CreateUserWithInventory(Scene scene, UserAccount ua, string pw) + { + // FIXME: This should really be set up by UserAccount itself + ua.ServiceURLs = new Dictionary(); + scene.UserAccountService.StoreUserAccount(ua); + scene.InventoryService.CreateUserInventory(ua.PrincipalID); + scene.AuthenticationService.SetPassword(ua.PrincipalID, pw); + } + } +} \ No newline at end of file diff --git a/Tests/OpenSim.Common.Tests/Helpers/UserInventoryHelpers.cs b/Tests/OpenSim.Common.Tests/Helpers/UserInventoryHelpers.cs new file mode 100644 index 00000000000..e18866598c3 --- /dev/null +++ b/Tests/OpenSim.Common.Tests/Helpers/UserInventoryHelpers.cs @@ -0,0 +1,374 @@ +/* + * 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 OpenMetaverse; +using OpenSim.Framework; +using OpenSim.Region.CoreModules.Avatar.Inventory.Archiver; +using OpenSim.Region.Framework.Scenes; +using OpenSim.Services.Interfaces; + +namespace OpenSim.Tests.Common +{ + /// + /// Utility functions for carrying out user inventory tests. + /// + public static class UserInventoryHelpers + { + public static readonly string PATH_DELIMITER = "/"; + + /// + /// Add an existing scene object as an item in the user's inventory. + /// + /// + /// Will be added to the system Objects folder. + /// + /// + /// + /// + /// + /// The inventory item created. + public static InventoryItemBase AddInventoryItem( + Scene scene, SceneObjectGroup so, int inventoryIdTail, int assetIdTail) + { + return AddInventoryItem( + scene, + so.Name, + TestHelpers.ParseTail(inventoryIdTail), + InventoryType.Object, + AssetHelpers.CreateAsset(TestHelpers.ParseTail(assetIdTail), so), + so.OwnerID); + } + + /// + /// Add an existing scene object as an item in the user's inventory at the given path. + /// + /// + /// + /// + /// + /// The inventory item created. + public static InventoryItemBase AddInventoryItem( + Scene scene, SceneObjectGroup so, int inventoryIdTail, int assetIdTail, string path) + { + return AddInventoryItem( + scene, + so.Name, + TestHelpers.ParseTail(inventoryIdTail), + InventoryType.Object, + AssetHelpers.CreateAsset(TestHelpers.ParseTail(assetIdTail), so), + so.OwnerID, + path); + } + + /// + /// Adds the given item to the existing system folder for its type (e.g. an object will go in the "Objects" + /// folder). + /// + /// + /// + /// + /// + /// The serialized asset for this item + /// + /// + private static InventoryItemBase AddInventoryItem( + Scene scene, string itemName, UUID itemId, InventoryType itemType, AssetBase asset, UUID userId) + { + return AddInventoryItem( + scene, itemName, itemId, itemType, asset, userId, + scene.InventoryService.GetFolderForType(userId, (FolderType)asset.Type).Name); + } + + /// + /// Adds the given item to an inventory folder + /// + /// + /// + /// + /// + /// The serialized asset for this item + /// + /// Existing inventory path at which to add. + /// + private static InventoryItemBase AddInventoryItem( + Scene scene, string itemName, UUID itemId, InventoryType itemType, AssetBase asset, UUID userId, string path) + { + scene.AssetService.Store(asset); + + InventoryItemBase item = new InventoryItemBase(); + item.Name = itemName; + item.AssetID = asset.FullID; + item.ID = itemId; + item.Owner = userId; + item.AssetType = asset.Type; + item.InvType = (int)itemType; + item.BasePermissions = (uint)OpenMetaverse.PermissionMask.All | + (uint)(Framework.PermissionMask.FoldedMask | Framework.PermissionMask.FoldedCopy | Framework.PermissionMask.FoldedModify | Framework.PermissionMask.FoldedTransfer); + item.CurrentPermissions = (uint)OpenMetaverse.PermissionMask.All | + (uint)(Framework.PermissionMask.FoldedMask | Framework.PermissionMask.FoldedCopy | Framework.PermissionMask.FoldedModify | Framework.PermissionMask.FoldedTransfer); + + InventoryFolderBase folder = InventoryArchiveUtils.FindFoldersByPath(scene.InventoryService, userId, path)[0]; + + item.Folder = folder.ID; + scene.AddInventoryItem(item); + + return item; + } + + /// + /// Creates a notecard in the objects folder and specify an item id. + /// + /// + /// + /// + /// + /// + public static InventoryItemBase CreateInventoryItem(Scene scene, string itemName, UUID userId) + { + return CreateInventoryItem(scene, itemName, UUID.Random(), UUID.Random(), userId, InventoryType.Notecard); + } + + /// + /// Creates an item of the given type with an accompanying asset. + /// + /// + /// + /// + /// + /// Type of item to create + /// + public static InventoryItemBase CreateInventoryItem( + Scene scene, string itemName, UUID userId, InventoryType type) + { + return CreateInventoryItem(scene, itemName, UUID.Random(), UUID.Random(), userId, type); + } + + /// + /// Creates a notecard in the objects folder and specify an item id. + /// + /// + /// + /// + /// + /// + /// Type of item to create + /// + public static InventoryItemBase CreateInventoryItem( + Scene scene, string itemName, UUID itemId, UUID assetId, UUID userId, InventoryType itemType) + { + AssetBase asset = null; + + if (itemType == InventoryType.Notecard) + { + asset = AssetHelpers.CreateNotecardAsset(); + asset.CreatorID = userId.ToString(); + } + else if (itemType == InventoryType.Object) + { + asset = AssetHelpers.CreateAsset(assetId, SceneHelpers.CreateSceneObject(1, userId)); + } + else + { + throw new Exception(string.Format("Inventory type {0} not supported", itemType)); + } + + return AddInventoryItem(scene, itemName, itemId, itemType, asset, userId); + } + + /// + /// Create inventory folders starting from the user's root folder. + /// + /// + /// + /// + /// The folders to create. Multiple folders can be specified on a path delimited by the PATH_DELIMITER + /// + /// + /// If true, then folders in the path which already the same name are + /// used. This applies to the terminal folder as well. + /// If false, then all folders in the path are created, even if there is already a folder at a particular + /// level with the same name. + /// + /// + /// The folder created. If the path contains multiple folders then the last one created is returned. + /// Will return null if the root folder could not be found. + /// + public static InventoryFolderBase CreateInventoryFolder( + IInventoryService inventoryService, UUID userId, string path, bool useExistingFolders) + { + return CreateInventoryFolder(inventoryService, userId, UUID.Random(), path, useExistingFolders); + } + + /// + /// Create inventory folders starting from the user's root folder. + /// + /// + /// + /// + /// + /// The folders to create. Multiple folders can be specified on a path delimited by the PATH_DELIMITER + /// + /// + /// If true, then folders in the path which already the same name are + /// used. This applies to the terminal folder as well. + /// If false, then all folders in the path are created, even if there is already a folder at a particular + /// level with the same name. + /// + /// + /// The folder created. If the path contains multiple folders then the last one created is returned. + /// Will return null if the root folder could not be found. + /// + public static InventoryFolderBase CreateInventoryFolder( + IInventoryService inventoryService, UUID userId, UUID folderId, string path, bool useExistingFolders) + { + InventoryFolderBase rootFolder = inventoryService.GetRootFolder(userId); + + if (null == rootFolder) + return null; + + return CreateInventoryFolder(inventoryService, folderId, rootFolder, path, useExistingFolders); + } + + /// + /// Create inventory folders starting from a given parent folder + /// + /// + /// If any stem of the path names folders that already exist then these are not recreated. This includes the + /// final folder. + /// TODO: May need to make it an option to create duplicate folders. + /// + /// + /// ID of the folder to create + /// + /// + /// The folder to create. + /// + /// + /// If true, then folders in the path which already the same name are + /// used. This applies to the terminal folder as well. + /// If false, then all folders in the path are created, even if there is already a folder at a particular + /// level with the same name. + /// + /// + /// The folder created. If the path contains multiple folders then the last one created is returned. + /// + public static InventoryFolderBase CreateInventoryFolder( + IInventoryService inventoryService, UUID folderId, InventoryFolderBase parentFolder, string path, bool useExistingFolders) + { + string[] components = path.Split(new string[] { PATH_DELIMITER }, 2, StringSplitOptions.None); + + InventoryFolderBase folder = null; + + if (useExistingFolders) + folder = InventoryArchiveUtils.FindFolderByPath(inventoryService, parentFolder, components[0]); + + if (folder == null) + { +// Console.WriteLine("Creating folder {0} at {1}", components[0], parentFolder.Name); + + UUID folderIdForCreate; + + if (components.Length > 1) + folderIdForCreate = UUID.Random(); + else + folderIdForCreate = folderId; + + folder + = new InventoryFolderBase( + folderIdForCreate, components[0], parentFolder.Owner, (short)AssetType.Unknown, parentFolder.ID, 0); + + inventoryService.AddFolder(folder); + } +// else +// { +// Console.WriteLine("Found existing folder {0}", folder.Name); +// } + + if (components.Length > 1) + return CreateInventoryFolder(inventoryService, folderId, folder, components[1], useExistingFolders); + else + return folder; + } + + /// + /// Get the inventory folder that matches the path name. If there are multiple folders then only the first + /// is returned. + /// + /// + /// + /// + /// null if no folder matching the path was found + public static InventoryFolderBase GetInventoryFolder(IInventoryService inventoryService, UUID userId, string path) + { + List folders = GetInventoryFolders(inventoryService, userId, path); + + if (folders.Count != 0) + return folders[0]; + else + return null; + } + + /// + /// Get the inventory folders that match the path name. + /// + /// + /// + /// + /// An empty list if no matching folders were found + public static List GetInventoryFolders(IInventoryService inventoryService, UUID userId, string path) + { + return InventoryArchiveUtils.FindFoldersByPath(inventoryService, userId, path); + } + + /// + /// Get the inventory item that matches the path name. If there are multiple items then only the first + /// is returned. + /// + /// + /// + /// + /// null if no item matching the path was found + public static InventoryItemBase GetInventoryItem(IInventoryService inventoryService, UUID userId, string path) + { + return InventoryArchiveUtils.FindItemByPath(inventoryService, userId, path); + } + + /// + /// Get the inventory items that match the path name. + /// + /// + /// + /// + /// An empty list if no matching items were found. + public static List GetInventoryItems(IInventoryService inventoryService, UUID userId, string path) + { + return InventoryArchiveUtils.FindItemsByPath(inventoryService, userId, path); + } + } +} diff --git a/Tests/OpenSim.Common.Tests/LongRunningAttribute.cs b/Tests/OpenSim.Common.Tests/LongRunningAttribute.cs new file mode 100644 index 00000000000..6013fcb2186 --- /dev/null +++ b/Tests/OpenSim.Common.Tests/LongRunningAttribute.cs @@ -0,0 +1,49 @@ +/* + * 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 System.Text; +using NUnit.Framework; + +namespace OpenSim.Tests.Common +{ + [AttributeUsage(AttributeTargets.All, + AllowMultiple = false, + Inherited = true)] + public class LongRunningAttribute : CategoryAttribute + { + public LongRunningAttribute() : this("Long Running Test") + { + + } + + protected LongRunningAttribute(string category) : base(category) + { + } + } +} diff --git a/Tests/OpenSim.Common.Tests/Mock/BaseAssetRepository.cs b/Tests/OpenSim.Common.Tests/Mock/BaseAssetRepository.cs new file mode 100644 index 00000000000..d0430ff63a9 --- /dev/null +++ b/Tests/OpenSim.Common.Tests/Mock/BaseAssetRepository.cs @@ -0,0 +1,62 @@ +/* + * 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 OpenMetaverse; +using OpenSim.Framework; + +namespace OpenSim.Tests.Common +{ + public class BaseAssetRepository + { + protected Dictionary Assets = new Dictionary(); + + public AssetBase FetchAsset(UUID uuid) + { + if (AssetsExist(new[] { uuid })[0]) + return Assets[uuid]; + else + return null; + } + + public void CreateAsset(AssetBase asset) + { + Assets[asset.FullID] = asset; + } + + public void UpdateAsset(AssetBase asset) + { + CreateAsset(asset); + } + + public bool[] AssetsExist(UUID[] uuids) + { + return Array.ConvertAll(uuids, id => Assets.ContainsKey(id)); + } + } +} \ No newline at end of file diff --git a/Tests/OpenSim.Common.Tests/Mock/MockAssetDataPlugin.cs b/Tests/OpenSim.Common.Tests/Mock/MockAssetDataPlugin.cs new file mode 100644 index 00000000000..aaf61e7df21 --- /dev/null +++ b/Tests/OpenSim.Common.Tests/Mock/MockAssetDataPlugin.cs @@ -0,0 +1,70 @@ +/* + * 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 OpenMetaverse; +using OpenSim.Framework; +using OpenSim.Data; + +namespace OpenSim.Tests.Common +{ + /// + /// In memory asset data plugin for test purposes. Could be another dll when properly filled out and when the + /// mono addin plugin system starts co-operating with the unit test system. Currently no locking since unit + /// tests are single threaded. + /// + public class MockAssetDataPlugin : BaseAssetRepository, IAssetDataPlugin + { + public string Version { get { return "0"; } } + public string Name { get { return "MockAssetDataPlugin"; } } + + public void Initialise() {} + public void Initialise(string connect) {} + public void Dispose() {} + + private readonly List assets = new List(); + + public AssetBase GetAsset(UUID uuid) + { + return assets.Find(x=>x.FullID == uuid); + } + + public bool StoreAsset(AssetBase asset) + { + assets.Add(asset); + return true; + } + + public List FetchAssetMetadataSet(int start, int count) { return new List(count); } + + public bool Delete(string id) + { + return false; + } + } +} diff --git a/Tests/OpenSim.Common.Tests/Mock/MockGroupsServicesConnector.cs b/Tests/OpenSim.Common.Tests/Mock/MockGroupsServicesConnector.cs new file mode 100644 index 00000000000..e9deac768d6 --- /dev/null +++ b/Tests/OpenSim.Common.Tests/Mock/MockGroupsServicesConnector.cs @@ -0,0 +1,436 @@ +/* + * 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; +using System.Collections.Generic; +using System.Reflection; +using log4net; +using Mono.Addins; +using Nini.Config; +using OpenMetaverse; +using OpenSim.Data; +using OpenSim.Data.Null; +using OpenSim.Framework; +using OpenSim.Region.Framework.Interfaces; +using OpenSim.Region.Framework.Scenes; +using OpenSim.Region.OptionalModules.Avatar.XmlRpcGroups; + +namespace OpenSim.Tests.Common +{ + [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule")] + public class MockGroupsServicesConnector : ISharedRegionModule, IGroupsServicesConnector + { + private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + + IXGroupData m_data = new NullXGroupData(null, null); + + public string Name + { + get { return "MockGroupsServicesConnector"; } + } + + public Type ReplaceableInterface + { + get { return null; } + } + + public void Initialise(IConfigSource config) + { + } + + public void Close() + { + } + + public void AddRegion(Scene scene) + { + m_log.DebugFormat("[MOCK GROUPS SERVICES CONNECTOR]: Adding to region {0}", scene.RegionInfo.RegionName); + scene.RegisterModuleInterface(this); + } + + public void RemoveRegion(Scene scene) + { + } + + public void RegionLoaded(Scene scene) + { + } + + public void PostInitialise() + { + } + + public UUID CreateGroup(UUID requestingAgentID, string name, string charter, bool showInList, UUID insigniaID, + int membershipFee, bool openEnrollment, bool allowPublish, + bool maturePublish, UUID founderID) + { + XGroup group = new XGroup() + { + groupID = UUID.Random(), + ownerRoleID = UUID.Random(), + name = name, + charter = charter, + showInList = showInList, + insigniaID = insigniaID, + membershipFee = membershipFee, + openEnrollment = openEnrollment, + allowPublish = allowPublish, + maturePublish = maturePublish, + founderID = founderID, + everyonePowers = (ulong)XmlRpcGroupsServicesConnectorModule.DefaultEveryonePowers, + ownersPowers = (ulong)XmlRpcGroupsServicesConnectorModule.DefaultOwnerPowers + }; + + if (m_data.StoreGroup(group)) + { + m_log.DebugFormat("[MOCK GROUPS SERVICES CONNECTOR]: Created group {0} {1}", group.name, group.groupID); + return group.groupID; + } + else + { + m_log.ErrorFormat("[MOCK GROUPS SERVICES CONNECTOR]: Failed to create group {0}", name); + return UUID.Zero; + } + } + + public void UpdateGroup(UUID requestingAgentID, UUID groupID, string charter, bool showInList, + UUID insigniaID, int membershipFee, bool openEnrollment, + bool allowPublish, bool maturePublish) + { + } + + public void AddGroupRole(UUID requestingAgentID, UUID groupID, UUID roleID, string name, string description, + string title, ulong powers) + { + } + + public void RemoveGroupRole(UUID requestingAgentID, UUID groupID, UUID roleID) + { + } + + public void UpdateGroupRole(UUID requestingAgentID, UUID groupID, UUID roleID, string name, string description, + string title, ulong powers) + { + } + + private XGroup GetXGroup(UUID groupID, string name) + { + XGroup group = m_data.GetGroup(groupID); + + + if (group == null) + m_log.DebugFormat("[MOCK GROUPS SERVICES CONNECTOR]: No group found with ID {0}", groupID); + + return group; + } + + public GroupRecord GetGroupRecord(UUID requestingAgentID, UUID groupID, string groupName) + { + m_log.DebugFormat( + "[MOCK GROUPS SERVICES CONNECTOR]: Processing GetGroupRecord() for groupID {0}, name {1}", + groupID, groupName); + + XGroup xg = GetXGroup(groupID, groupName); + + if (xg == null) + return null; + + GroupRecord gr = new GroupRecord() + { + GroupID = xg.groupID, + GroupName = xg.name, + AllowPublish = xg.allowPublish, + MaturePublish = xg.maturePublish, + Charter = xg.charter, + FounderID = xg.founderID, + // FIXME: group picture storage location unknown + MembershipFee = xg.membershipFee, + OpenEnrollment = xg.openEnrollment, + OwnerRoleID = xg.ownerRoleID, + ShowInList = xg.showInList + }; + + return gr; + } + + public GroupProfileData GetMemberGroupProfile(UUID requestingAgentID, UUID GroupID, UUID AgentID) + { + return default(GroupProfileData); + } + + public void SetAgentActiveGroup(UUID requestingAgentID, UUID AgentID, UUID GroupID) + { + } + + public void SetAgentActiveGroupRole(UUID requestingAgentID, UUID AgentID, UUID GroupID, UUID RoleID) + { + } + + public void SetAgentGroupInfo(UUID requestingAgentID, UUID agentID, UUID groupID, bool acceptNotices, bool listInProfile) + { + m_log.DebugFormat( + "[MOCK GROUPS SERVICES CONNECTOR]: SetAgentGroupInfo, requestingAgentID {0}, agentID {1}, groupID {2}, acceptNotices {3}, listInProfile {4}", + requestingAgentID, agentID, groupID, acceptNotices, listInProfile); + + XGroup group = GetXGroup(groupID, null); + + if (group == null) + return; + + XGroupMember xgm = null; + if (!group.members.TryGetValue(agentID, out xgm)) + return; + + xgm.acceptNotices = acceptNotices; + xgm.listInProfile = listInProfile; + + m_data.StoreGroup(group); + } + + public void AddAgentToGroupInvite(UUID requestingAgentID, UUID inviteID, UUID groupID, UUID roleID, UUID agentID) + { + } + + public GroupInviteInfo GetAgentToGroupInvite(UUID requestingAgentID, UUID inviteID) + { + return null; + } + + public void RemoveAgentToGroupInvite(UUID requestingAgentID, UUID inviteID) + { + } + + public void AddAgentToGroup(UUID requestingAgentID, UUID agentID, UUID groupID, UUID roleID) + { + m_log.DebugFormat( + "[MOCK GROUPS SERVICES CONNECTOR]: AddAgentToGroup, requestingAgentID {0}, agentID {1}, groupID {2}, roleID {3}", + requestingAgentID, agentID, groupID, roleID); + + XGroup group = GetXGroup(groupID, null); + + if (group == null) + return; + + XGroupMember groupMember = new XGroupMember() + { + agentID = agentID, + groupID = groupID, + roleID = roleID + }; + + group.members[agentID] = groupMember; + + m_data.StoreGroup(group); + } + + public void RemoveAgentFromGroup(UUID requestingAgentID, UUID AgentID, UUID GroupID) + { + } + + public void AddAgentToGroupRole(UUID requestingAgentID, UUID AgentID, UUID GroupID, UUID RoleID) + { + } + + public void RemoveAgentFromGroupRole(UUID requestingAgentID, UUID AgentID, UUID GroupID, UUID RoleID) + { + } + + public List FindGroups(UUID requestingAgentID, string search) + { + return null; + } + + public GroupMembershipData GetAgentGroupMembership(UUID requestingAgentID, UUID AgentID, UUID GroupID) + { + return null; + } + + public GroupMembershipData GetAgentActiveMembership(UUID requestingAgentID, UUID AgentID) + { + return null; + } + + public List GetAgentGroupMemberships(UUID requestingAgentID, UUID AgentID) + { + return new List(); + } + + public List GetAgentGroupRoles(UUID requestingAgentID, UUID AgentID, UUID GroupID) + { + return null; + } + + public List GetGroupRoles(UUID requestingAgentID, UUID GroupID) + { + return null; + } + + public List GetGroupMembers(UUID requestingAgentID, UUID groupID) + { + m_log.DebugFormat( + "[MOCK GROUPS SERVICES CONNECTOR]: GetGroupMembers, requestingAgentID {0}, groupID {1}", + requestingAgentID, groupID); + + List groupMembers = new List(); + + XGroup group = GetXGroup(groupID, null); + + if (group == null) + return groupMembers; + + foreach (XGroupMember xgm in group.members.Values) + { + GroupMembersData gmd = new GroupMembersData(); + gmd.AgentID = xgm.agentID; + gmd.IsOwner = group.founderID == gmd.AgentID; + gmd.AcceptNotices = xgm.acceptNotices; + gmd.ListInProfile = xgm.listInProfile; + + groupMembers.Add(gmd); + } + + return groupMembers; + } + + public List GetGroupRoleMembers(UUID requestingAgentID, UUID GroupID) + { + return null; + } + + public List GetGroupNotices(UUID requestingAgentID, UUID groupID) + { + XGroup group = GetXGroup(groupID, null); + + if (group == null) + return null; + + List notices = new List(); + + foreach (XGroupNotice notice in group.notices.Values) + { + GroupNoticeData gnd = new GroupNoticeData() + { + NoticeID = notice.noticeID, + Timestamp = notice.timestamp, + FromName = notice.fromName, + Subject = notice.subject, + HasAttachment = notice.hasAttachment, + AssetType = (byte)notice.assetType + }; + + notices.Add(gnd); + } + + return notices; + } + + public GroupNoticeInfo GetGroupNotice(UUID requestingAgentID, UUID noticeID) + { + m_log.DebugFormat( + "[MOCK GROUPS SERVICES CONNECTOR]: GetGroupNotices, requestingAgentID {0}, noticeID {1}", + requestingAgentID, noticeID); + + // Yes, not an efficient way to do it. + Dictionary groups = m_data.GetGroups(); + + foreach (XGroup group in groups.Values) + { + if (group.notices.ContainsKey(noticeID)) + { + XGroupNotice n = group.notices[noticeID]; + + GroupNoticeInfo gni = new GroupNoticeInfo(); + gni.GroupID = n.groupID; + gni.Message = n.message; + gni.BinaryBucket = n.binaryBucket; + gni.noticeData.NoticeID = n.noticeID; + gni.noticeData.Timestamp = n.timestamp; + gni.noticeData.FromName = n.fromName; + gni.noticeData.Subject = n.subject; + gni.noticeData.HasAttachment = n.hasAttachment; + gni.noticeData.AssetType = (byte)n.assetType; + + return gni; + } + } + + return null; + } + + public void AddGroupNotice(UUID requestingAgentID, UUID groupID, UUID noticeID, string fromName, string subject, string message, byte[] binaryBucket) + { + m_log.DebugFormat( + "[MOCK GROUPS SERVICES CONNECTOR]: AddGroupNotice, requestingAgentID {0}, groupID {1}, noticeID {2}, fromName {3}, subject {4}, message {5}, binaryBucket.Length {6}", + requestingAgentID, groupID, noticeID, fromName, subject, message, binaryBucket.Length); + + XGroup group = GetXGroup(groupID, null); + + if (group == null) + return; + + XGroupNotice groupNotice = new XGroupNotice() + { + groupID = groupID, + noticeID = noticeID, + fromName = fromName, + subject = subject, + message = message, + timestamp = (uint)Util.UnixTimeSinceEpoch(), + hasAttachment = false, + assetType = 0, + binaryBucket = binaryBucket + }; + + group.notices[noticeID] = groupNotice; + + m_data.StoreGroup(group); + } + + public void ResetAgentGroupChatSessions(UUID agentID) + { + } + + public bool hasAgentBeenInvitedToGroupChatSession(UUID agentID, UUID groupID) + { + return false; + } + + public bool hasAgentDroppedGroupChatSession(UUID agentID, UUID groupID) + { + return false; + } + + public void AgentDroppedFromGroupChatSession(UUID agentID, UUID groupID) + { + } + + public void AgentInvitedToGroupChatSession(UUID agentID, UUID groupID) + { + } + } +} \ No newline at end of file diff --git a/Tests/OpenSim.Common.Tests/Mock/MockRegionDataPlugin.cs b/Tests/OpenSim.Common.Tests/Mock/MockRegionDataPlugin.cs new file mode 100644 index 00000000000..ab0e4f4454e --- /dev/null +++ b/Tests/OpenSim.Common.Tests/Mock/MockRegionDataPlugin.cs @@ -0,0 +1,375 @@ +/* + * 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.Reflection; +using System.Collections.Generic; +using log4net; +using OpenMetaverse; +using OpenSim.Framework; +using OpenSim.Region.Framework.Interfaces; +using OpenSim.Region.Framework.Scenes; + +namespace OpenSim.Data.Null +{ + public class NullDataService : ISimulationDataService + { + private NullDataStore m_store; + + public NullDataService() + { + m_store = new NullDataStore(); + } + + public void StoreObject(SceneObjectGroup obj, UUID regionUUID) + { + m_store.StoreObject(obj, regionUUID); + } + + public void RemoveObject(UUID uuid, UUID regionUUID) + { + m_store.RemoveObject(uuid, regionUUID); + } + + public void StorePrimInventory(UUID primID, ICollection items) + { + m_store.StorePrimInventory(primID, items); + } + + public List LoadObjects(UUID regionUUID) + { + return m_store.LoadObjects(regionUUID); + } + + public void StoreTerrain(double[,] terrain, UUID regionID) + { + m_store.StoreTerrain(terrain, regionID); + } + + public void StoreTerrain(TerrainData terrain, UUID regionID) + { + m_store.StoreTerrain(terrain, regionID); + } + + public void StoreBakedTerrain(TerrainData terrain, UUID regionID) + { + m_store.StoreBakedTerrain(terrain, regionID); + } + + public double[,] LoadTerrain(UUID regionID) + { + return m_store.LoadTerrain(regionID); + } + + public TerrainData LoadTerrain(UUID regionID, int pSizeX, int pSizeY, int pSizeZ) + { + return m_store.LoadTerrain(regionID, pSizeX, pSizeY, pSizeZ); + } + + public TerrainData LoadBakedTerrain(UUID regionID, int pSizeX, int pSizeY, int pSizeZ) + { + return m_store.LoadBakedTerrain(regionID, pSizeX, pSizeY, pSizeZ); + } + + public void StoreLandObject(ILandObject Parcel) + { + m_store.StoreLandObject(Parcel); + } + + public void RemoveLandObject(UUID globalID) + { + m_store.RemoveLandObject(globalID); + } + + public List LoadLandObjects(UUID regionUUID) + { + return m_store.LoadLandObjects(regionUUID); + } + + public void StoreRegionSettings(RegionSettings rs) + { + m_store.StoreRegionSettings(rs); + } + + public RegionSettings LoadRegionSettings(UUID regionUUID) + { + return m_store.LoadRegionSettings(regionUUID); + } + + public string LoadRegionEnvironmentSettings(UUID regionUUID) + { + return m_store.LoadRegionEnvironmentSettings(regionUUID); + } + + public void StoreRegionEnvironmentSettings(UUID regionUUID, string settings) + { + m_store.StoreRegionEnvironmentSettings(regionUUID, settings); + } + + public void RemoveRegionEnvironmentSettings(UUID regionUUID) + { + m_store.RemoveRegionEnvironmentSettings(regionUUID); + } + + public UUID[] GetObjectIDs(UUID regionID) + { + return new UUID[0]; + } + + public void SaveExtra(UUID regionID, string name, string value) + { + } + + public void RemoveExtra(UUID regionID, string name) + { + } + + public Dictionary GetExtra(UUID regionID) + { + return null; + } + } + + /// + /// Mock region data plugin. This obeys the api contract for persistence but stores everything in memory, so that + /// tests can check correct persistence. + /// + public class NullDataStore : ISimulationDataStore + { +// private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + + protected Dictionary m_regionSettings = new Dictionary(); + protected Dictionary m_sceneObjectParts = new Dictionary(); + protected Dictionary> m_primItems + = new Dictionary>(); + protected Dictionary m_terrains = new Dictionary(); + protected Dictionary m_bakedterrains = new Dictionary(); + protected Dictionary m_landData = new Dictionary(); + + public void Initialise(string dbfile) + { + return; + } + + public void Dispose() + { + } + + public void StoreRegionSettings(RegionSettings rs) + { + m_regionSettings[rs.RegionUUID] = rs; + } + + #region Environment Settings + public string LoadRegionEnvironmentSettings(UUID regionUUID) + { + //This connector doesn't support the Environment module yet + return string.Empty; + } + + public void StoreRegionEnvironmentSettings(UUID regionUUID, string settings) + { + //This connector doesn't support the Environment module yet + } + + public void RemoveRegionEnvironmentSettings(UUID regionUUID) + { + //This connector doesn't support the Environment module yet + } + #endregion + + public RegionSettings LoadRegionSettings(UUID regionUUID) + { + RegionSettings rs = null; + m_regionSettings.TryGetValue(regionUUID, out rs); + + if (rs == null) + rs = new RegionSettings(); + + return rs; + } + + public void StoreObject(SceneObjectGroup obj, UUID regionUUID) + { + // We can't simply store groups here because on delinking, OpenSim will not update the original group + // directly. Rather, the newly delinked parts will be updated to be in their own scene object group + // Therefore, we need to store parts rather than groups. + foreach (SceneObjectPart prim in obj.Parts) + { +// m_log.DebugFormat( +// "[MOCK REGION DATA PLUGIN]: Storing part {0} {1} in object {2} {3} in region {4}", +// prim.Name, prim.UUID, obj.Name, obj.UUID, regionUUID); + + m_sceneObjectParts[prim.UUID] = prim; + } + } + + public void RemoveObject(UUID obj, UUID regionUUID) + { + // All parts belonging to the object with the uuid are removed. + List parts = new List(m_sceneObjectParts.Values); + foreach (SceneObjectPart part in parts) + { + if (part.ParentGroup.UUID == obj) + { +// m_log.DebugFormat( +// "[MOCK REGION DATA PLUGIN]: Removing part {0} {1} as part of object {2} from {3}", +// part.Name, part.UUID, obj, regionUUID); + m_sceneObjectParts.Remove(part.UUID); + } + } + } + + public void StorePrimInventory(UUID primID, ICollection items) + { + m_primItems[primID] = items; + } + + public List LoadObjects(UUID regionUUID) + { + Dictionary objects = new Dictionary(); + + // Create all of the SOGs from the root prims first + foreach (SceneObjectPart prim in m_sceneObjectParts.Values) + { + if (prim.IsRoot) + { +// m_log.DebugFormat( +// "[MOCK REGION DATA PLUGIN]: Loading root part {0} {1} in {2}", prim.Name, prim.UUID, regionUUID); + objects[prim.UUID] = new SceneObjectGroup(prim); + } + } + + // Add all of the children objects to the SOGs + foreach (SceneObjectPart prim in m_sceneObjectParts.Values) + { + SceneObjectGroup sog; + if (prim.UUID != prim.ParentUUID) + { + if (objects.TryGetValue(prim.ParentUUID, out sog)) + { + int originalLinkNum = prim.LinkNum; + + sog.AddPart(prim); + + // SceneObjectGroup.AddPart() tries to be smart and automatically set the LinkNum. + // We override that here + if (originalLinkNum != 0) + prim.LinkNum = originalLinkNum; + } + else + { +// m_log.WarnFormat( +// "[MOCK REGION DATA PLUGIN]: Database contains an orphan child prim {0} {1} in region {2} pointing to missing parent {3}. This prim will not be loaded.", +// prim.Name, prim.UUID, regionUUID, prim.ParentUUID); + } + } + } + + // TODO: Load items. This is assymetric - we store items as a separate method but don't retrieve them that + // way! + + return new List(objects.Values); + } + + public void StoreTerrain(TerrainData ter, UUID regionID) + { + m_terrains[regionID] = ter; + } + + public void StoreBakedTerrain(TerrainData ter, UUID regionID) + { + m_bakedterrains[regionID] = ter; + } + + public void StoreTerrain(double[,] ter, UUID regionID) + { + m_terrains[regionID] = new TerrainData(ter); + } + + public TerrainData LoadTerrain(UUID regionID, int pSizeX, int pSizeY, int pSizeZ) + { + if (m_terrains.ContainsKey(regionID)) + return m_terrains[regionID]; + else + return null; + } + + public TerrainData LoadBakedTerrain(UUID regionID, int pSizeX, int pSizeY, int pSizeZ) + { + if (m_bakedterrains.ContainsKey(regionID)) + return m_bakedterrains[regionID]; + else + return null; + } + + public double[,] LoadTerrain(UUID regionID) + { + if (m_terrains.ContainsKey(regionID)) + return m_terrains[regionID].GetDoubles(); + else + return null; + } + + public void RemoveLandObject(UUID globalID) + { + if (m_landData.ContainsKey(globalID)) + m_landData.Remove(globalID); + } + + public void StoreLandObject(ILandObject land) + { + m_landData[land.LandData.GlobalID] = land.LandData; + } + + public List LoadLandObjects(UUID regionUUID) + { + return new List(m_landData.Values); + } + + public void Shutdown() + { + } + + public UUID[] GetObjectIDs(UUID regionID) + { + return new UUID[0]; + } + + public void SaveExtra(UUID regionID, string name, string value) + { + } + + public void RemoveExtra(UUID regionID, string name) + { + } + + public Dictionary GetExtra(UUID regionID) + { + return null; + } + } +} diff --git a/Tests/OpenSim.Common.Tests/Mock/MockScriptEngine.cs b/Tests/OpenSim.Common.Tests/Mock/MockScriptEngine.cs new file mode 100644 index 00000000000..e82456e5ac1 --- /dev/null +++ b/Tests/OpenSim.Common.Tests/Mock/MockScriptEngine.cs @@ -0,0 +1,289 @@ +/* + * 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; +using System.Collections.Generic; +using System.Reflection; +using Nini.Config; +using OpenMetaverse; +using OpenSim.Framework; +using OpenSim.Region.Framework.Interfaces; +using OpenSim.Region.Framework.Scenes; +using OpenSim.Region.ScriptEngine.Interfaces; +using OpenSim.Region.ScriptEngine.Shared; + +namespace OpenSim.Tests.Common +{ + public class MockScriptEngine : INonSharedRegionModule, IScriptModule, IScriptEngine + { + public IConfigSource ConfigSource { get; private set; } + + public IConfig Config { get; private set; } + + private Scene m_scene; + + /// + /// Expose posted events to tests. + /// + public Dictionary> PostedEvents { get; private set; } + + /// + /// A very primitive way of hooking text cose to a posed event. + /// + /// + /// May be replaced with something that uses more original code in the future. + /// + public event Action PostEventHook; + + public void Initialise(IConfigSource source) + { + ConfigSource = source; + + // Can set later on if required + Config = new IniConfig("MockScriptEngine", ConfigSource); + + PostedEvents = new Dictionary>(); + } + + public void Close() + { + } + + public void AddRegion(Scene scene) + { + m_scene = scene; + + m_scene.StackModuleInterface(this); + } + + public void RemoveRegion(Scene scene) + { + } + + public void RegionLoaded(Scene scene) + { + } + + public string Name { get { return "Mock Script Engine"; } } + public string ScriptEngineName { get { return Name; } } + + public Type ReplaceableInterface { get { return null; } } + +#pragma warning disable 0067 + public event ScriptRemoved OnScriptRemoved; + public event ObjectRemoved OnObjectRemoved; +#pragma warning restore 0067 + + public string GetXMLState (UUID itemID) + { + throw new System.NotImplementedException (); + } + + public bool SetXMLState(UUID itemID, string xml) + { + throw new System.NotImplementedException (); + } + + public void CancelScriptEvent(UUID itemID, string eventName) + { + + } + + public bool PostScriptEvent(UUID itemID, string name, object[] args) + { +// Console.WriteLine("Posting event {0} for {1}", name, itemID); + + return PostScriptEvent(itemID, new EventParams(name, args, null)); + } + + public bool PostScriptEvent(UUID itemID, EventParams evParams) + { + List eventsForItem; + + if (!PostedEvents.ContainsKey(itemID)) + { + eventsForItem = new List(); + PostedEvents.Add(itemID, eventsForItem); + } + else + { + eventsForItem = PostedEvents[itemID]; + } + + eventsForItem.Add(evParams); + + if (PostEventHook != null) + PostEventHook(itemID, evParams); + + return true; + } + + public bool PostObjectEvent(uint localID, EventParams evParams) + { + return PostObjectEvent(m_scene.GetSceneObjectPart(localID), evParams); + } + + public bool PostObjectEvent(UUID itemID, string name, object[] args) + { + return PostObjectEvent(m_scene.GetSceneObjectPart(itemID), new EventParams(name, args, null)); + } + + private bool PostObjectEvent(SceneObjectPart part, EventParams evParams) + { + foreach (TaskInventoryItem item in part.Inventory.GetInventoryItems(InventoryType.LSL)) + PostScriptEvent(item.ItemID, evParams); + + return true; + } + + public bool SuspendScript(UUID itemID) + { + throw new System.NotImplementedException (); + } + + public bool ResumeScript(UUID itemID) + { + throw new System.NotImplementedException (); + } + + public ArrayList GetScriptErrors(UUID itemID) + { + throw new System.NotImplementedException (); + } + + public bool HasScript(UUID itemID, out bool running) + { + throw new System.NotImplementedException (); + } + + public bool GetScriptState(UUID itemID) + { + throw new System.NotImplementedException (); + } + + public void SaveAllState() + { + throw new System.NotImplementedException (); + } + + public void StartProcessing() + { + throw new System.NotImplementedException (); + } + + public float GetScriptExecutionTime(List itemIDs) + { + return 0; + } + + public int GetScriptsMemory(List itemIDs) + { + return 0; + } + + public Dictionary GetObjectScriptsExecutionTimes() + { + throw new System.NotImplementedException (); + } + + public IScriptWorkItem QueueEventHandler(object parms) + { + throw new System.NotImplementedException (); + } + + public DetectParams GetDetectParams(UUID item, int number) + { + throw new System.NotImplementedException (); + } + + public void SetMinEventDelay(UUID itemID, double delay) + { + throw new System.NotImplementedException (); + } + + public int GetStartParameter(UUID itemID) + { + throw new System.NotImplementedException (); + } + + public void SetScriptState(UUID itemID, bool state, bool self) + { + throw new System.NotImplementedException (); + } + + public void SetState(UUID itemID, string newState) + { + throw new System.NotImplementedException (); + } + + public void ApiResetScript(UUID itemID) + { + throw new System.NotImplementedException (); + } + + public void ResetScript (UUID itemID) + { + throw new System.NotImplementedException (); + } + + public IScriptApi GetApi(UUID itemID, string name) + { + throw new System.NotImplementedException (); + } + + public Scene World { get { return m_scene; } } + + public IScriptModule ScriptModule { get { return this; } } + + public string ScriptEnginePath { get { throw new System.NotImplementedException (); }} + + public string ScriptClassName { get { throw new System.NotImplementedException (); } } + + public string ScriptBaseClassName { get { throw new System.NotImplementedException (); } } + + public string[] ScriptReferencedAssemblies { get { throw new System.NotImplementedException (); } } + + public ParameterInfo[] ScriptBaseClassParameters { get { throw new System.NotImplementedException (); } } + + public void ClearPostedEvents() + { + PostedEvents.Clear(); + } + + public void SleepScript(UUID itemID, int delay) + { + } + + public ICollection GetTopObjectStats(float mintime, int minmemory, out float totaltime, out float totalmemory) + { + totaltime = 0; + totalmemory = 0; + return null; + } + } +} diff --git a/Tests/OpenSim.Common.Tests/Mock/TestClient.cs b/Tests/OpenSim.Common.Tests/Mock/TestClient.cs new file mode 100644 index 00000000000..f4f828891e7 --- /dev/null +++ b/Tests/OpenSim.Common.Tests/Mock/TestClient.cs @@ -0,0 +1,1416 @@ +/* + * 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 System.Net; +using System.Reflection; +using System.Threading; +using log4net; +using OpenMetaverse; +using OpenMetaverse.Packets; +using OpenSim.Framework; +using OpenSim.Region.Framework.Interfaces; +using OpenSim.Region.Framework.Scenes; +using OpenSim.Framework.Client; + +namespace OpenSim.Tests.Common +{ + public class TestClient : IClientAPI, IClientCore + { + private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + + EventWaitHandle wh = new EventWaitHandle (false, EventResetMode.AutoReset, "Crossing"); + + private Scene m_scene; + + // Properties so that we can get at received data for test purposes + public List ReceivedKills { get; private set; } + public List ReceivedOfflineNotifications { get; private set; } + public List ReceivedOnlineNotifications { get; private set; } + public List ReceivedFriendshipTerminations { get; private set; } + + public List SentImageDataPackets { get; private set; } + public List SentImagePacketPackets { get; private set; } + public List SentImageNotInDatabasePackets { get; private set; } + + // Test client specific events - for use by tests to implement some IClientAPI behaviour. + public event Action OnReceivedMoveAgentIntoRegion; + public event Action OnTestClientInformClientOfNeighbour; + public event TestClientOnSendRegionTeleportDelegate OnTestClientSendRegionTeleport; + + public event Action OnReceivedEntityUpdate; + + public event OnReceivedChatMessageDelegate OnReceivedChatMessage; + public event Action OnReceivedInstantMessage; + + public event Action OnReceivedSendRebakeAvatarTextures; + + public delegate void TestClientOnSendRegionTeleportDelegate( + ulong regionHandle, byte simAccess, IPEndPoint regionExternalEndPoint, + uint locationID, uint flags, string capsURL); + + public delegate void OnReceivedChatMessageDelegate( + string message, byte type, Vector3 fromPos, string fromName, + UUID fromAgentID, UUID ownerID, byte source, byte audible); + + +// disable warning: public events, part of the public API +#pragma warning disable 67 + + public event Action OnLogout; + public event ObjectPermissions OnObjectPermissions; + + public event MoneyTransferRequest OnMoneyTransferRequest; + public event ParcelBuy OnParcelBuy; + public event Action OnConnectionClosed; + public event MoveItemsAndLeaveCopy OnMoveItemsAndLeaveCopy; + public event ImprovedInstantMessage OnInstantMessage; + public event ChatMessage OnChatFromClient; + public event TextureRequest OnRequestTexture; + public event RezObject OnRezObject; + public event ModifyTerrain OnModifyTerrain; + public event BakeTerrain OnBakeTerrain; + public event SetAppearance OnSetAppearance; + public event AvatarNowWearing OnAvatarNowWearing; + public event RezSingleAttachmentFromInv OnRezSingleAttachmentFromInv; + public event RezMultipleAttachmentsFromInv OnRezMultipleAttachmentsFromInv; + public event UUIDNameRequest OnDetachAttachmentIntoInv; + public event ObjectAttach OnObjectAttach; + public event ObjectDeselect OnObjectDetach; + public event ObjectDrop OnObjectDrop; + public event StartAnim OnStartAnim; + public event StopAnim OnStopAnim; + public event ChangeAnim OnChangeAnim; + public event LinkObjects OnLinkObjects; + public event DelinkObjects OnDelinkObjects; + public event RequestMapBlocks OnRequestMapBlocks; + public event RequestMapName OnMapNameRequest; + public event TeleportLocationRequest OnTeleportLocationRequest; + public event TeleportLandmarkRequest OnTeleportLandmarkRequest; + public event TeleportCancel OnTeleportCancel; + public event DisconnectUser OnDisconnectUser; + public event RequestAvatarProperties OnRequestAvatarProperties; + public event SetAlwaysRun OnSetAlwaysRun; + + public event DeRezObject OnDeRezObject; + public event RezRestoreToWorld OnRezRestoreToWorld; + public event Action OnRegionHandShakeReply; + public event GenericCall1 OnRequestWearables; + public event Action OnCompleteMovementToRegion; + public event UpdateAgent OnPreAgentUpdate; + public event UpdateAgent OnAgentUpdate; + public event UpdateAgent OnAgentCameraUpdate; + public event AgentRequestSit OnAgentRequestSit; + public event AgentSit OnAgentSit; + public event AvatarPickerRequest OnAvatarPickerRequest; + public event Action OnRequestAvatarsData; + public event AddNewPrim OnAddPrim; + public event RequestGodlikePowers OnRequestGodlikePowers; + public event GodKickUser OnGodKickUser; + public event ObjectDuplicate OnObjectDuplicate; + public event GrabObject OnGrabObject; + public event DeGrabObject OnDeGrabObject; + public event MoveObject OnGrabUpdate; + public event SpinStart OnSpinStart; + public event SpinObject OnSpinUpdate; + public event SpinStop OnSpinStop; + public event ViewerEffectEventHandler OnViewerEffect; + + public event AgentDataUpdate OnAgentDataUpdateRequest; + public event TeleportLocationRequest OnSetStartLocationRequest; + + public event UpdateShape OnUpdatePrimShape; + public event ObjectExtraParams OnUpdateExtraParams; + public event RequestObjectPropertiesFamily OnRequestObjectPropertiesFamily; + public event ObjectSelect OnObjectSelect; + public event ObjectRequest OnObjectRequest; + public event GenericCall7 OnObjectDescription; + public event GenericCall7 OnObjectName; + public event GenericCall7 OnObjectClickAction; + public event GenericCall7 OnObjectMaterial; + public event UpdatePrimFlags OnUpdatePrimFlags; + public event UpdatePrimTexture OnUpdatePrimTexture; + public event ClientChangeObject onClientChangeObject; + public event UpdateVector OnUpdatePrimGroupPosition; + public event UpdateVector OnUpdatePrimSinglePosition; + public event UpdatePrimRotation OnUpdatePrimGroupRotation; + public event UpdatePrimSingleRotation OnUpdatePrimSingleRotation; + public event UpdatePrimSingleRotationPosition OnUpdatePrimSingleRotationPosition; + public event UpdatePrimGroupRotation OnUpdatePrimGroupMouseRotation; + public event UpdateVector OnUpdatePrimScale; + public event UpdateVector OnUpdatePrimGroupScale; + public event StatusChange OnChildAgentStatus; + public event GenericCall2 OnStopMovement; + public event Action OnRemoveAvatar; + + public event CreateNewInventoryItem OnCreateNewInventoryItem; + public event LinkInventoryItem OnLinkInventoryItem; + public event CreateInventoryFolder OnCreateNewInventoryFolder; + public event UpdateInventoryFolder OnUpdateInventoryFolder; + public event MoveInventoryFolder OnMoveInventoryFolder; + public event RemoveInventoryFolder OnRemoveInventoryFolder; + public event RemoveInventoryItem OnRemoveInventoryItem; + public event FetchInventoryDescendents OnFetchInventoryDescendents; + public event PurgeInventoryDescendents OnPurgeInventoryDescendents; + public event FetchInventory OnFetchInventory; + public event RequestTaskInventory OnRequestTaskInventory; + public event UpdateInventoryItem OnUpdateInventoryItem; + public event CopyInventoryItem OnCopyInventoryItem; + public event MoveInventoryItem OnMoveInventoryItem; + public event UDPAssetUploadRequest OnAssetUploadRequest; + public event RequestTerrain OnRequestTerrain; + public event RequestTerrain OnUploadTerrain; + public event XferReceive OnXferReceive; + public event RequestXfer OnRequestXfer; + public event ConfirmXfer OnConfirmXfer; + public event AbortXfer OnAbortXfer; + public event RezScript OnRezScript; + public event UpdateTaskInventory OnUpdateTaskInventory; + public event MoveTaskInventory OnMoveTaskItem; + public event RemoveTaskInventory OnRemoveTaskItem; + public event RequestAsset OnRequestAsset; + public event GenericMessage OnGenericMessage; + public event UUIDNameRequest OnNameFromUUIDRequest; + public event UUIDNameRequest OnUUIDGroupNameRequest; + + public event ParcelPropertiesRequest OnParcelPropertiesRequest; + public event ParcelDivideRequest OnParcelDivideRequest; + public event ParcelJoinRequest OnParcelJoinRequest; + public event ParcelPropertiesUpdateRequest OnParcelPropertiesUpdateRequest; + public event ParcelAbandonRequest OnParcelAbandonRequest; + public event ParcelGodForceOwner OnParcelGodForceOwner; + public event ParcelReclaim OnParcelReclaim; + public event ParcelReturnObjectsRequest OnParcelReturnObjectsRequest; + public event ParcelAccessListRequest OnParcelAccessListRequest; + public event ParcelAccessListUpdateRequest OnParcelAccessListUpdateRequest; + public event ParcelSelectObjects OnParcelSelectObjects; + public event ParcelObjectOwnerRequest OnParcelObjectOwnerRequest; + public event ParcelDeedToGroup OnParcelDeedToGroup; + public event ObjectDeselect OnObjectDeselect; + public event RegionInfoRequest OnRegionInfoRequest; + public event EstateCovenantRequest OnEstateCovenantRequest; + public event EstateChangeInfo OnEstateChangeInfo; + public event EstateManageTelehub OnEstateManageTelehub; + public event CachedTextureRequest OnCachedTextureRequest; + + public event ObjectDuplicateOnRay OnObjectDuplicateOnRay; + + public event FriendActionDelegate OnApproveFriendRequest; + public event FriendActionDelegate OnDenyFriendRequest; + public event FriendshipTermination OnTerminateFriendship; + public event GrantUserFriendRights OnGrantUserRights; + + public event EconomyDataRequest OnEconomyDataRequest; + public event MoneyBalanceRequest OnMoneyBalanceRequest; + public event UpdateAvatarProperties OnUpdateAvatarProperties; + + public event ObjectIncludeInSearch OnObjectIncludeInSearch; + public event UUIDNameRequest OnTeleportHomeRequest; + + public event ScriptAnswer OnScriptAnswer; + public event RequestPayPrice OnRequestPayPrice; + public event ObjectSaleInfo OnObjectSaleInfo; + public event ObjectBuy OnObjectBuy; + public event BuyObjectInventory OnBuyObjectInventory; + public event AgentSit OnUndo; + public event AgentSit OnRedo; + public event LandUndo OnLandUndo; + + public event ForceReleaseControls OnForceReleaseControls; + + public event GodLandStatRequest OnLandStatRequest; + public event RequestObjectPropertiesFamily OnObjectGroupRequest; + + public event DetailedEstateDataRequest OnDetailedEstateDataRequest; + public event SetEstateFlagsRequest OnSetEstateFlagsRequest; + public event SetEstateTerrainBaseTexture OnSetEstateTerrainBaseTexture; + public event SetEstateTerrainDetailTexture OnSetEstateTerrainDetailTexture; + public event SetEstateTerrainTextureHeights OnSetEstateTerrainTextureHeights; + public event CommitEstateTerrainTextureRequest OnCommitEstateTerrainTextureRequest; + public event SetRegionTerrainSettings OnSetRegionTerrainSettings; + public event EstateRestartSimRequest OnEstateRestartSimRequest; + public event EstateChangeCovenantRequest OnEstateChangeCovenantRequest; + public event UpdateEstateAccessDeltaRequest OnUpdateEstateAccessDeltaRequest; + public event SimulatorBlueBoxMessageRequest OnSimulatorBlueBoxMessageRequest; + public event EstateBlueBoxMessageRequest OnEstateBlueBoxMessageRequest; + public event EstateDebugRegionRequest OnEstateDebugRegionRequest; + public event EstateTeleportOneUserHomeRequest OnEstateTeleportOneUserHomeRequest; + public event EstateTeleportAllUsersHomeRequest OnEstateTeleportAllUsersHomeRequest; + public event ScriptReset OnScriptReset; + public event GetScriptRunning OnGetScriptRunning; + public event SetScriptRunning OnSetScriptRunning; + public event Action OnAutoPilotGo; + + public event TerrainUnacked OnUnackedTerrain; + + public event RegionHandleRequest OnRegionHandleRequest; + public event ParcelInfoRequest OnParcelInfoRequest; + + public event ActivateGesture OnActivateGesture; + public event DeactivateGesture OnDeactivateGesture; + public event ObjectOwner OnObjectOwner; + + public event DirPlacesQuery OnDirPlacesQuery; + public event DirFindQuery OnDirFindQuery; + public event DirLandQuery OnDirLandQuery; + public event DirPopularQuery OnDirPopularQuery; + public event DirClassifiedQuery OnDirClassifiedQuery; + public event EventInfoRequest OnEventInfoRequest; + public event ParcelSetOtherCleanTime OnParcelSetOtherCleanTime; + + public event MapItemRequest OnMapItemRequest; + + public event OfferCallingCard OnOfferCallingCard; + public event AcceptCallingCard OnAcceptCallingCard; + public event DeclineCallingCard OnDeclineCallingCard; + + public event SoundTrigger OnSoundTrigger; + + public event StartLure OnStartLure; + public event TeleportLureRequest OnTeleportLureRequest; + public event NetworkStats OnNetworkStatsUpdate; + + public event ClassifiedInfoRequest OnClassifiedInfoRequest; + public event ClassifiedInfoUpdate OnClassifiedInfoUpdate; + public event ClassifiedDelete OnClassifiedDelete; + public event ClassifiedGodDelete OnClassifiedGodDelete; + + public event EventNotificationAddRequest OnEventNotificationAddRequest; + public event EventNotificationRemoveRequest OnEventNotificationRemoveRequest; + public event EventGodDelete OnEventGodDelete; + + public event ParcelDwellRequest OnParcelDwellRequest; + + public event UserInfoRequest OnUserInfoRequest; + public event UpdateUserInfo OnUpdateUserInfo; + + public event RetrieveInstantMessages OnRetrieveInstantMessages; + + public event PickDelete OnPickDelete; + public event PickGodDelete OnPickGodDelete; + public event PickInfoUpdate OnPickInfoUpdate; + public event AvatarNotesUpdate OnAvatarNotesUpdate; + + public event MuteListRequest OnMuteListRequest; + + public event AvatarInterestUpdate OnAvatarInterestUpdate; + + public event PlacesQuery OnPlacesQuery; + + public event FindAgentUpdate OnFindAgent; + public event TrackAgentUpdate OnTrackAgent; + public event NewUserReport OnUserReport; + public event SaveStateHandler OnSaveState; + public event GroupAccountSummaryRequest OnGroupAccountSummaryRequest; + public event GroupAccountDetailsRequest OnGroupAccountDetailsRequest; + public event GroupAccountTransactionsRequest OnGroupAccountTransactionsRequest; + public event FreezeUserUpdate OnParcelFreezeUser; + public event EjectUserUpdate OnParcelEjectUser; + public event ParcelBuyPass OnParcelBuyPass; + public event ParcelGodMark OnParcelGodMark; + public event GroupActiveProposalsRequest OnGroupActiveProposalsRequest; + public event GroupVoteHistoryRequest OnGroupVoteHistoryRequest; + public event SimWideDeletesDelegate OnSimWideDeletes; + public event SendPostcard OnSendPostcard; + public event ChangeInventoryItemFlags OnChangeInventoryItemFlags; + public event MuteListEntryUpdate OnUpdateMuteListEntry; + public event MuteListEntryRemove OnRemoveMuteListEntry; + public event GodlikeMessage onGodlikeMessage; + public event GodUpdateRegionInfoUpdate OnGodUpdateRegionInfoUpdate; + public event GenericCall2 OnUpdateThrottles; + public event AgentFOV OnAgentFOV; + +#pragma warning restore 67 + + /// + /// This agent's UUID + /// + private UUID m_agentId; + + public ISceneAgent SceneAgent { get; set; } + + public bool SupportObjectAnimations { get; set; } + + /// + /// The last caps seed url that this client was given. + /// + public string CapsSeedUrl; + + private Vector3 startPos = new Vector3(((int)Constants.RegionSize * 0.5f), ((int)Constants.RegionSize * 0.5f), 2); + + public virtual Vector3 StartPos + { + get { return startPos; } + set { } + } + + public float StartFar { get; set; } + + public virtual UUID AgentId + { + get { return m_agentId; } + } + + public UUID SessionId { get; set; } + + public UUID SecureSessionId { get; set; } + + public virtual string FirstName + { + get { return m_firstName; } + } + private string m_firstName; + + public virtual string LastName + { + get { return m_lastName; } + } + private string m_lastName; + + public virtual String Name + { + get { return FirstName + " " + LastName; } + } + + public int PingTimeMS { get { return 0; } } + + public bool IsActive + { + get { return true; } + set { } + } + + public bool IsLoggingOut { get; set; } + + public UUID ActiveGroupId + { + get { return UUID.Zero; } + set { } + } + + public string ActiveGroupName + { + get { return String.Empty; } + set { } + } + + public ulong ActiveGroupPowers + { + get { return 0; } + set { } + } + + public bool IsGroupMember(UUID groupID) + { + return false; + } + + public Dictionary GetGroupPowers() + { + return new Dictionary(); + } + + public void SetGroupPowers(Dictionary powers) { } + + public ulong GetGroupPowers(UUID groupID) + { + return 0; + } + + public virtual int NextAnimationSequenceNumber + { + get { return 1; } + set { } + } + + public IScene Scene + { + get { return m_scene; } + } + + public UUID ScopeId + { + get { return UUID.Zero; } + } + + public bool SendLogoutPacketWhenClosing + { + set { } + } + + private uint m_circuitCode; + + public uint CircuitCode + { + get { return m_circuitCode; } + set { m_circuitCode = value; } + } + + public IPEndPoint RemoteEndPoint + { + get { return new IPEndPoint(IPAddress.Loopback, (ushort)m_circuitCode); } + } + + public List SelectedObjects {get; private set;} + + /// + /// Constructor + /// + /// + /// + /// + public TestClient(AgentCircuitData agentData, Scene scene) + { + m_agentId = agentData.AgentID; + m_firstName = agentData.firstname; + m_lastName = agentData.lastname; + m_circuitCode = agentData.circuitcode; + m_scene = scene; + SessionId = agentData.SessionID; + SecureSessionId = agentData.SecureSessionID; + CapsSeedUrl = agentData.CapsPath; + + ReceivedKills = new List(); + ReceivedOfflineNotifications = new List(); + ReceivedOnlineNotifications = new List(); + ReceivedFriendshipTerminations = new List(); + + SentImageDataPackets = new List(); + SentImagePacketPackets = new List(); + SentImageNotInDatabasePackets = new List(); + } + + /// + /// Trigger chat coming from this connection. + /// + /// + /// + /// + public bool Chat(int channel, ChatTypeEnum type, string message) + { + ChatMessage handlerChatFromClient = OnChatFromClient; + + if (handlerChatFromClient != null) + { + OSChatMessage args = new OSChatMessage(); + args.Channel = channel; + args.From = Name; + args.Message = message; + args.Type = type; + + args.Scene = Scene; + args.Sender = this; + args.SenderUUID = AgentId; + + handlerChatFromClient(this, args); + } + + return true; + } + + /// + /// Attempt a teleport to the given region. + /// + /// + /// + /// + public void Teleport(ulong regionHandle, Vector3 position, Vector3 lookAt) + { + OnTeleportLocationRequest(this, regionHandle, position, lookAt, 16); + } + + public void CompleteMovement() + { + if (OnCompleteMovementToRegion != null) + OnCompleteMovementToRegion(this, true); + } + + /// + /// Emulate sending an IM from the viewer to the simulator. + /// + /// + public void HandleImprovedInstantMessage(GridInstantMessage im) + { + ImprovedInstantMessage handlerInstantMessage = OnInstantMessage; + + if (handlerInstantMessage != null) + handlerInstantMessage(this, im); + } + + public virtual void ActivateGesture(UUID assetId, UUID gestureId) + { + } + + public virtual void SendWearables(AvatarWearable[] wearables, int serial) + { + } + + public virtual void SendAppearance(UUID agentID, byte[] visualParams, byte[] textureEntry, float hover) + { + } + + public void SendCachedTextureResponse(ISceneEntity avatar, int serial, List cachedTextures) + { + + } + + public virtual void Kick(string message) + { + } + + public virtual void SendAvatarPickerReply(UUID QueryID, List users) + { + } + + public virtual void SendAgentDataUpdate(UUID agentid, UUID activegroupid, string firstname, string lastname, ulong grouppowers, string groupname, string grouptitle) + { + } + + public virtual void SendKillObject(List localID) + { + ReceivedKills.AddRange(localID); + } + + public void SendPartFullUpdate(ISceneEntity ent, uint? parentID) + { + } + + public virtual void SetChildAgentThrottle(byte[] throttle) + { + } + + public virtual void SetChildAgentThrottle(byte[] throttle, float factor) + { + } + + public void SetAgentThrottleSilent(int throttle, int setting) + { + } + + public int GetAgentThrottleSilent(int throttle) + { + return 0; + } + + public byte[] GetThrottlesPacked(float multiplier) + { + return Array.Empty(); + } + + public virtual void SendAnimations(UUID[] animations, int[] seqs, UUID sourceAgentId, UUID[] objectIDs) + { + } + + public virtual void SendChatMessage( + string message, byte type, Vector3 fromPos, string fromName, + UUID fromAgentID, UUID ownerID, byte source, byte audible) + { +// Console.WriteLine("mmm {0} {1} {2}", message, Name, AgentId); + if (OnReceivedChatMessage != null) + OnReceivedChatMessage(message, type, fromPos, fromName, fromAgentID, ownerID, source, audible); + } + + public void SendInstantMessage(GridInstantMessage im) + { + if (OnReceivedInstantMessage != null) + OnReceivedInstantMessage(im); + } + + public void SendGenericMessage(string method, UUID invoice, List message) + { + + } + + public void SendGenericMessage(string method, UUID invoice, List message) + { + + } + + public virtual bool CanSendLayerData() + { + return false; + } + + public virtual void SendLayerData() + { + } + + public void SendLayerData(int[] map) + { + } + + public virtual void SendWindData(int version, Vector2[] windSpeeds) { } + + public virtual void MoveAgentIntoRegion(RegionInfo regInfo, Vector3 pos, Vector3 look) + { + if (OnReceivedMoveAgentIntoRegion != null) + OnReceivedMoveAgentIntoRegion(regInfo, pos, look); + } + + public virtual AgentCircuitData RequestClientInfo() + { + AgentCircuitData agentData = new AgentCircuitData(); + agentData.AgentID = AgentId; + agentData.SessionID = SessionId; + agentData.SecureSessionID = UUID.Zero; + agentData.circuitcode = m_circuitCode; + agentData.child = false; + agentData.firstname = m_firstName; + agentData.lastname = m_lastName; + + ICapabilitiesModule capsModule = m_scene.RequestModuleInterface(); + if (capsModule != null) + { + agentData.CapsPath = capsModule.GetCapsPath(m_agentId); + agentData.ChildrenCapSeeds = new Dictionary(capsModule.GetChildrenSeeds(m_agentId)); + } + + return agentData; + } + + public virtual void InformClientOfNeighbour(ulong neighbourHandle, IPEndPoint neighbourExternalEndPoint) + { + if (OnTestClientInformClientOfNeighbour != null) + OnTestClientInformClientOfNeighbour(neighbourHandle, neighbourExternalEndPoint); + } + + public virtual void SendRegionTeleport( + ulong regionHandle, byte simAccess, IPEndPoint regionExternalEndPoint, + uint locationID, uint flags, string capsURL) + { + m_log.DebugFormat( + "[TEST CLIENT]: Received SendRegionTeleport for {0} {1} on {2}", m_firstName, m_lastName, m_scene.Name); + + CapsSeedUrl = capsURL; + + if (OnTestClientSendRegionTeleport != null) + OnTestClientSendRegionTeleport( + regionHandle, simAccess, regionExternalEndPoint, locationID, flags, capsURL); + } + + public virtual void SendTeleportFailed(string reason) + { + m_log.DebugFormat( + "[TEST CLIENT]: Teleport failed for {0} {1} on {2} with reason {3}", + m_firstName, m_lastName, m_scene.Name, reason); + } + + public virtual void CrossRegion(ulong newRegionHandle, Vector3 pos, Vector3 lookAt, + IPEndPoint newRegionExternalEndPoint, string capsURL) + { + // This is supposed to send a packet to the client telling it's ready to start region crossing. + // Instead I will just signal I'm ready, mimicking the communication behavior. + // It's ugly, but avoids needless communication setup. This is used in ScenePresenceTests.cs. + // Arthur V. + + wh.Set(); + } + + public virtual void SendMapBlock(List mapBlocks, uint flag) + { + } + + public virtual void SendLocalTeleport(Vector3 position, Vector3 lookAt, uint flags) + { + } + + public virtual void SendTeleportStart(uint flags) + { + } + + public void SendTeleportProgress(uint flags, string message) + { + } + + public virtual void SendMoneyBalance(UUID transaction, bool success, byte[] description, int balance, int transactionType, UUID sourceID, bool sourceIsGroup, UUID destID, bool destIsGroup, int amount, string item) + { + } + + public virtual void SendPayPrice(UUID objectID, int[] payPrice) + { + } + + public virtual void SendCoarseLocationUpdate(List users, List CoarseLocations) + { + } + + public virtual void SendDialog(string objectname, UUID objectID, UUID ownerID, string ownerFirstName, string ownerLastName, string msg, UUID textureID, int ch, string[] buttonlabels) + { + } + + public void SendEntityFullUpdateImmediate(ISceneEntity ent) + { + } + + public void SendEntityTerseUpdateImmediate(ISceneEntity ent) + { + } + + public void SendEntityUpdate(ISceneEntity entity, PrimUpdateFlags updateFlags) + { + if (OnReceivedEntityUpdate != null) + OnReceivedEntityUpdate(entity, updateFlags); + } + + public void ReprioritizeUpdates() + { + } + + public void FlushPrimUpdates() + { + } + + public void SendInventoryFolderDetails(UUID ownerID, UUID folderID, + List items, + List folders, + int version, + int descendents, + bool fetchFolders, + bool fetchItems) + { + } + + public void SendInventoryItemDetails(InventoryItemBase[] items) + { + } + + public void SendInventoryItemCreateUpdate(InventoryItemBase Item, uint callbackID) + { + } + + public void SendInventoryItemCreateUpdate(InventoryItemBase Item, UUID transactionID, uint callbackId) + { + } + + public void SendRemoveInventoryItem(UUID itemID) + { + } + + public void SendRemoveInventoryItems(UUID[] items) + { + } + + public void SendBulkUpdateInventory(InventoryNodeBase node, UUID? transactionID = null) + { + } + + public void SendBulkUpdateInventory(InventoryFolderBase[] folders, InventoryItemBase[] items) + { + } + + public void SendTakeControls(int controls, bool passToAgent, bool TakeControls) + { + } + + public virtual void SendTaskInventory(UUID taskID, short serial, byte[] fileName) + { + } + + public virtual void SendXferPacket(ulong xferID, uint packet, + byte[] XferData, int XferDataOffset, int XferDatapktLen, bool isTaskInventory) + { + } + + public virtual void SendAbortXferPacket(ulong xferID) + { + + } + + public virtual void SendEconomyData(float EnergyEfficiency, int ObjectCapacity, int ObjectCount, int PriceEnergyUnit, + int PriceGroupCreate, int PriceObjectClaim, float PriceObjectRent, float PriceObjectScaleFactor, + int PriceParcelClaim, float PriceParcelClaimFactor, int PriceParcelRent, int PricePublicObjectDecay, + int PricePublicObjectDelete, int PriceRentLight, int PriceUpload, int TeleportMinPrice, float TeleportPriceExponent) + { + } + + public virtual void SendNameReply(UUID profileId, string firstname, string lastname) + { + } + + public virtual void SendPreLoadSound(UUID objectID, UUID ownerID, UUID soundID) + { + } + + public virtual void SendPlayAttachedSound(UUID soundID, UUID objectID, UUID ownerID, float gain, + byte flags) + { + } + + public void SendTriggeredSound(UUID soundID, UUID ownerID, UUID objectID, UUID parentID, ulong handle, Vector3 position, float gain) + { + } + + public void SendAttachedSoundGainChange(UUID objectID, float gain) + { + + } + + public void SendAlertMessage(string message) + { + } + + public void SendAgentAlertMessage(string message, bool modal) + { + } + + public void SendAlertMessage(string message, string info) + { + } + + public void SendSystemAlertMessage(string message) + { + } + + public void SendLoadURL(string objectname, UUID objectID, UUID ownerID, bool groupOwned, string message, + string url) + { + } + + public virtual void SendRegionHandshake() + { + if (OnRegionHandShakeReply != null) + { + OnRegionHandShakeReply(this); + } + } + + public void SendAssetUploadCompleteMessage(sbyte AssetType, bool Success, UUID AssetFullID) + { + } + + public void SendConfirmXfer(ulong xferID, uint PacketID) + { + } + + public void SendXferRequest(ulong XferID, short AssetType, UUID vFileID, byte FilePath, byte[] FileName) + { + } + + public void SendInitiateDownload(string simFileName, string clientFileName) + { + } + + public void SendImageFirstPart(ushort numParts, UUID ImageUUID, uint ImageSize, byte[] ImageData, byte imageCodec) + { + ImageDataPacket im = new ImageDataPacket(); + im.Header.Reliable = false; + im.ImageID.Packets = numParts; + im.ImageID.ID = ImageUUID; + + if (ImageSize > 0) + im.ImageID.Size = ImageSize; + + im.ImageData.Data = ImageData; + im.ImageID.Codec = imageCodec; + im.Header.Zerocoded = true; + SentImageDataPackets.Add(im); + } + + public void SendImageNextPart(ushort partNumber, UUID imageUuid, byte[] imageData) + { + ImagePacketPacket im = new ImagePacketPacket(); + im.Header.Reliable = false; + im.ImageID.Packet = partNumber; + im.ImageID.ID = imageUuid; + im.ImageData.Data = imageData; + SentImagePacketPackets.Add(im); + } + + public void SendImageNotFound(UUID imageid) + { + ImageNotInDatabasePacket p = new ImageNotInDatabasePacket(); + p.ImageID.ID = imageid; + + SentImageNotInDatabasePackets.Add(p); + } + + public void SendShutdownConnectionNotice() + { + } + + public void SendSimStats(SimStats stats) + { + } + + public void SendObjectPropertiesFamilyData(ISceneEntity Entity, uint RequestFlags) + { + } + + public void SendObjectPropertiesReply(ISceneEntity entity) + { + } + + public void SendAgentOffline(UUID[] agentIDs) + { + ReceivedOfflineNotifications.AddRange(agentIDs); + } + + public void SendAgentOnline(UUID[] agentIDs) + { + ReceivedOnlineNotifications.AddRange(agentIDs); + } + + public void SendFindAgent(UUID HunterID, UUID PreyID, double GlobalX, double GlobalY) + { + } + + public void SendSitResponse(UUID TargetID, Vector3 OffsetPos, + Quaternion SitOrientation, bool autopilot, + Vector3 CameraAtOffset, Vector3 CameraEyeOffset, bool ForceMouseLook) + { + } + + public void SendAdminResponse(UUID Token, uint AdminLevel) + { + } + + public void SendGroupMembership(GroupMembershipData[] GroupMembership) + { + } + + public void SendViewerTime(Vector3 sunDir, float sunphase) + { + } + + public void SendViewerEffect(ViewerEffectPacket.EffectBlock[] effectBlocks) + { + } + + public void SendAvatarProperties(UUID avatarID, string aboutText, string bornOn, Byte[] membershipType, + string flAbout, uint flags, UUID flImageID, UUID imageID, string profileURL, + UUID partnerID) + { + } + + public int DebugPacketLevel { get; set; } + + public void InPacket(object NewPack) + { + } + + public void ProcessInPacket(Packet NewPack) + { + } + + /// + /// This is a TestClient only method to do shutdown tasks that are normally carried out by LLUDPServer.RemoveClient() + /// + public void Logout() + { + // We must set this here so that the presence is removed from the PresenceService by the PresenceDetector + IsLoggingOut = true; + + Close(); + } + + public void Close() + { + Close(true, false); + } + + public void Close(bool sendStop, bool force) + { + // Fire the callback for this connection closing + // This is necesary to get the presence detector to notice that a client has logged out. + if (OnConnectionClosed != null) + OnConnectionClosed(this); + + m_scene.RemoveClient(AgentId, true); + } + + public void Start() + { + throw new NotImplementedException(); + } + + public void Stop() + { + } + + public void SendBlueBoxMessage(UUID FromAvatarID, String FromAvatarName, String Message) + { + + } + public void SendLogoutPacket() + { + } + + public void Terminate() + { + } + + public ClientInfo GetClientInfo() + { + return null; + } + + public void SetClientInfo(ClientInfo info) + { + } + + public void SendScriptQuestion(UUID objectID, string taskName, string ownerName, UUID itemID, int question) + { + } + public void SendHealth(float health) + { + } + + public void SendTelehubInfo(UUID ObjectID, string ObjectName, Vector3 ObjectPos, Quaternion ObjectRot, List SpawnPoint) + { + } + + public void SendEstateList(UUID invoice, int code, UUID[] Data, uint estateID) + { + } + + public void SendBannedUserList(UUID invoice, EstateBan[] banlist, uint estateID) + { + } + + public void SendRegionInfoToEstateMenu(RegionInfoForEstateMenuArgs args) + { + } + + public void SendEstateCovenantInformation(UUID covenant) + { + } + + public void SendDetailedEstateData(UUID invoice, string estateName, uint estateID, uint parentEstate, uint estateFlags, uint sunPosition, UUID covenant, uint covenantChanged, string abuseEmail, UUID estateOwner) + { + } + + public void SendLandProperties(int sequence_id, bool snap_selection, int request_result, ILandObject lo, float simObjectBonusFactor, int parcelObjectCapacity, int simObjectCapacity, uint regionFlags) + { + } + + public void SendLandAccessListData(List accessList, uint accessFlag, int localLandID) + { + } + + public void SendForceClientSelectObjects(List objectIDs) + { + } + + public void SendCameraConstraint(Vector4 ConstraintPlane) + { + } + + public void SendLandObjectOwners(LandData land, List groups, Dictionary ownersAndCount) + { + } + + public void SendLandParcelOverlay(byte[] data, int sequence_id) + { + } + + public void SendParcelMediaCommand(uint flags, ParcelMediaCommandEnum command, float time) + { + } + + public void SendParcelMediaUpdate(string mediaUrl, UUID mediaTextureID, byte autoScale, string mediaType, + string mediaDesc, int mediaWidth, int mediaHeight, byte mediaLoop) + { + } + + public void SendGroupNameReply(UUID groupLLUID, string GroupName) + { + } + + public void SendLandStatReply(uint reportType, uint requestFlags, uint resultCount, LandStatReportItem[] lsrpia) + { + } + + public void SendScriptRunningReply(UUID objectID, UUID itemID, bool running) + { + } + + public void SendAsset(AssetRequestToClient req) + { + } + + public void SendTexture(AssetBase TextureAsset) + { + + } + + public void SendSetFollowCamProperties (UUID objectID, SortedDictionary parameters) + { + } + + public void SendClearFollowCamProperties (UUID objectID) + { + } + + public void SendRegionHandle (UUID regoinID, ulong handle) + { + } + + public void SendParcelInfo (RegionInfo info, LandData land, UUID parcelID, uint x, uint y) + { + } + + public void SetClientOption(string option, string value) + { + } + + public string GetClientOption(string option) + { + return string.Empty; + } + + public void SendScriptTeleportRequest(string objName, string simName, Vector3 pos, Vector3 lookAt) + { + } + + public void SendDirPlacesReply(UUID queryID, DirPlacesReplyData[] data) + { + } + + public void SendDirPeopleReply(UUID queryID, DirPeopleReplyData[] data) + { + } + + public void SendDirEventsReply(UUID queryID, DirEventsReplyData[] data) + { + } + + public void SendDirGroupsReply(UUID queryID, DirGroupsReplyData[] data) + { + } + + public void SendDirClassifiedReply(UUID queryID, DirClassifiedReplyData[] data) + { + } + + public void SendDirLandReply(UUID queryID, DirLandReplyData[] data) + { + } + + public void SendDirPopularReply(UUID queryID, DirPopularReplyData[] data) + { + } + + public void SendMapItemReply(mapItemReply[] replies, uint mapitemtype, uint flags) + { + } + + public void SendEventInfoReply (EventData info) + { + } + + public void SendOfferCallingCard (UUID destID, UUID transactionID) + { + } + + public void SendAcceptCallingCard (UUID transactionID) + { + } + + public void SendDeclineCallingCard (UUID transactionID) + { + } + + public void SendAvatarGroupsReply(UUID avatarID, GroupMembershipData[] data) + { + } + + public void SendAgentGroupDataUpdate(UUID avatarID, GroupMembershipData[] data) + { + } + + public void SendJoinGroupReply(UUID groupID, bool success) + { + } + + public void SendEjectGroupMemberReply(UUID agentID, UUID groupID, bool succss) + { + } + + public void SendLeaveGroupReply(UUID groupID, bool success) + { + } + + public void SendTerminateFriend(UUID exFriendID) + { + ReceivedFriendshipTerminations.Add(exFriendID); + } + + public bool AddGenericPacketHandler(string MethodName, GenericMessage handler) + { + //throw new NotImplementedException(); + return false; + } + + public void SendAvatarClassifiedReply(UUID targetID, UUID[] classifiedID, string[] name) + { + } + + public void SendClassifiedInfoReply(UUID classifiedID, UUID creatorID, uint creationDate, uint expirationDate, uint category, string name, string description, UUID parcelID, uint parentEstate, UUID snapshotID, string simName, Vector3 globalPos, string parcelName, byte classifiedFlags, int price) + { + } + + public void SendAgentDropGroup(UUID groupID) + { + } + + public void SendAvatarNotesReply(UUID targetID, string text) + { + } + + public void SendAvatarPicksReply(UUID targetID, Dictionary picks) + { + } + + public void SendAvatarClassifiedReply(UUID targetID, Dictionary classifieds) + { + } + + public void SendParcelDwellReply(int localID, UUID parcelID, float dwell) + { + } + + public void SendUserInfoReply(bool imViaEmail, bool visible, string email) + { + } + + public void SendCreateGroupReply(UUID groupID, bool success, string message) + { + } + + public void RefreshGroupMembership() + { + } + + public void UpdateGroupMembership(GroupMembershipData[] data) + { + } + + public void GroupMembershipRemove(UUID GroupID) + { + } + + public void GroupMembershipAddReplace(UUID GroupID,ulong GroupPowers) + { + } + + public void SendUseCachedMuteList() + { + } + + public void SendEmpytMuteList() + { + } + + public void SendMuteListUpdate(string filename) + { + } + + public void SendPickInfoReply(UUID pickID,UUID creatorID, bool topPick, UUID parcelID, string name, string desc, UUID snapshotID, string user, string originalName, string simName, Vector3 posGlobal, int sortOrder, bool enabled) + { + } + + public bool TryGet(out T iface) + { + iface = default(T); + return false; + } + + public T Get() + { + return default(T); + } + + public void Disconnect(string reason) + { + } + + public void Disconnect() + { + } + + public void SendRebakeAvatarTextures(UUID textureID) + { + if (OnReceivedSendRebakeAvatarTextures != null) + OnReceivedSendRebakeAvatarTextures(textureID); + } + + public void SendAvatarInterestsReply(UUID avatarID, uint wantMask, string wantText, uint skillsMask, string skillsText, string languages) + { + } + + public void SendGroupAccountingDetails(IClientAPI sender,UUID groupID, UUID transactionID, UUID sessionID, int amt) + { + } + + public void SendGroupAccountingSummary(IClientAPI sender,UUID groupID, uint moneyAmt, int totalTier, int usedTier) + { + } + + public void SendGroupTransactionsSummaryDetails(IClientAPI sender,UUID groupID, UUID transactionID, UUID sessionID,int amt) + { + } + + public void SendGroupVoteHistory(UUID groupID, UUID transactionID, GroupVoteHistory[] Votes) + { + } + + public void SendGroupActiveProposals(UUID groupID, UUID transactionID, GroupActiveProposals[] Proposals) + { + } + + public void SendChangeUserRights(UUID agentID, UUID friendID, int rights) + { + } + + public void SendTextBoxRequest(string message, int chatChannel, string objectname, UUID ownerID, string ownerFirstName, string ownerLastName, UUID objectId) + { + } + + public void SendAgentTerseUpdate(ISceneEntity presence) + { + } + + public void SendPlacesReply(UUID queryID, UUID transactionID, PlacesReplyData[] data) + { + } + + public void SendSelectedPartsProprieties(List parts) + { + } + + public void SendPartPhysicsProprieties(ISceneEntity entity) + { + } + + public uint GetViewerCaps() + { + return 0x1000; + } + + } +} diff --git a/Tests/OpenSim.Common.Tests/Mock/TestEventQueueGetModule.cs b/Tests/OpenSim.Common.Tests/Mock/TestEventQueueGetModule.cs new file mode 100644 index 00000000000..2cf8cf6b126 --- /dev/null +++ b/Tests/OpenSim.Common.Tests/Mock/TestEventQueueGetModule.cs @@ -0,0 +1,227 @@ +/* + * 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; +using System.Collections.Generic; +using System.Net; +using System.Reflection; +using System.Text; +using System.Threading; +using log4net; +using Nini.Config; +using Mono.Addins; +using OpenMetaverse; +using OpenMetaverse.StructuredData; +using OpenSim.Framework; +using OpenSim.Framework.Servers; +using OpenSim.Region.ClientStack.Linden; +using OpenSim.Region.Framework.Interfaces; +using OpenSim.Region.Framework.Scenes; + +namespace OpenSim.Tests.Common +{ + public class TestEventQueueGetModule : IEventQueue, INonSharedRegionModule + { + public class Event + { + public string Name { get; set; } + public object[] Args { get; set; } + + public Event(string name, object[] args) + { + name = Name; + args = Args; + } + } + + public Dictionary> Events { get; set; } + + public void Initialise(IConfigSource source) {} + + public void Close() {} + + public void AddRegion(Scene scene) + { + Events = new Dictionary>(); + scene.RegisterModuleInterface(this); + } + + public void RemoveRegion (Scene scene) {} + + public void RegionLoaded (Scene scene) {} + + public string Name { get { return "TestEventQueueGetModule"; } } + + public Type ReplaceableInterface { get { return null; } } + + private void AddEvent(UUID avatarID, string name, params object[] args) + { + Console.WriteLine("Adding event {0} for {1}", name, avatarID); + + List avEvents; + + if (!Events.ContainsKey(avatarID)) + { + avEvents = new List(); + Events[avatarID] = avEvents; + } + else + { + avEvents = Events[avatarID]; + } + + avEvents.Add(new Event(name, args)); + } + + public void ClearEvents() + { + if (Events != null) + Events.Clear(); + } + + public bool Enqueue(string o, UUID avatarID) + { + AddEvent(avatarID, "Enqueue", o); + return true; + } + public bool Enqueue(byte[] o, UUID avatarID) + { + return true; + } + public bool Enqueue(OSD o, UUID avatarID) + { + return true; + } + public bool Enqueue(osUTF8 o, UUID avatarID) + { + return true; + } + public void EnableSimulator (ulong handle, IPEndPoint endPoint, UUID avatarID, int regionSizeX, int regionSizeY) + { + AddEvent(avatarID, "EnableSimulator", handle); + } + + public void EstablishAgentCommunication (UUID avatarID, IPEndPoint endPoint, string capsPath, + ulong regionHandle, int regionSizeX, int regionSizeY) + { + AddEvent(avatarID, "EstablishAgentCommunication", endPoint, capsPath); + } + + public void TeleportFinishEvent (ulong regionHandle, byte simAccess, IPEndPoint regionExternalEndPoint, + uint locationID, uint flags, string capsURL, UUID agentID, int regionSizeX, int regionSizeY) + { + AddEvent(agentID, "TeleportFinishEvent", regionHandle, simAccess, regionExternalEndPoint, locationID, flags, capsURL); + } + + public void CrossRegion (ulong handle, Vector3 pos, Vector3 lookAt, IPEndPoint newRegionExternalEndPoint, + string capsURL, UUID avatarID, UUID sessionID, int regionSizeX, int regionSizeY) + { + AddEvent(avatarID, "CrossRegion", handle, pos, lookAt, newRegionExternalEndPoint, capsURL, sessionID); + } + + public void ChatterboxInvitation( + UUID sessionID, string sessionName, UUID fromAgent, string message, UUID toAgent, string fromName, + byte dialog, uint timeStamp, bool offline, int parentEstateID, Vector3 position, uint ttl, + UUID transactionID, bool fromGroup, byte[] binaryBucket) + { + AddEvent( + toAgent, "ChatterboxInvitation", sessionID, sessionName, fromAgent, message, toAgent, fromName, dialog, + timeStamp, offline, parentEstateID, position, ttl, transactionID, fromGroup, binaryBucket); + } + + public void ChatterBoxSessionStartReply(UUID sessionID, string sessionName, int type, + bool voiceEnabled, bool voiceModerated, UUID tmpSessionID, + bool sucess, string error, + UUID toAgent) + { + AddEvent(toAgent, "ChatterBoxSessionStartReply", sessionID, sessionName, type, + voiceEnabled, voiceModerated, tmpSessionID, + sucess, error); + } + + public void ChatterBoxSessionAgentListUpdates (UUID sessionID, UUID toAgent, List updates) + { + AddEvent(toAgent, "ChatterBoxSessionAgentListUpdates", sessionID, toAgent, updates); + } + + public void ChatterBoxForceClose (UUID toAgent, UUID sessionID, string reason) + { + AddEvent(toAgent, "ForceCloseChatterBoxSession", sessionID, reason); + } + + public void ParcelProperties (OpenMetaverse.Messages.Linden.ParcelPropertiesMessage parcelPropertiesMessage, UUID avatarID) + { + AddEvent(avatarID, "ParcelProperties", parcelPropertiesMessage); + } + + public void GroupMembershipData(UUID receiverAgent, GroupMembershipData[] data) + { + AddEvent(receiverAgent, "AgentGroupDataUpdate", data); + } + + public void ScriptRunningEvent (UUID objectID, UUID itemID, bool running, UUID avatarID) + { + Console.WriteLine("ONE"); + throw new System.NotImplementedException (); + } + + public byte[] BuildEvent(string eventName, OSD eventBody) + { + Console.WriteLine("TWOoo"); + throw new System.NotImplementedException(); + } + + public void partPhysicsProperties (uint localID, byte physhapetype, float density, float friction, float bounce, float gravmod, UUID avatarID) + { + AddEvent(avatarID, "partPhysicsProperties", localID, physhapetype, density, friction, bounce, gravmod); + } + + public void WindlightRefreshEvent(int interpolate, UUID avatarID) + { + } + + public void SendBulkUpdateInventoryItem(InventoryItemBase item, UUID avatarID, UUID? transationID = null) + { + } + + public osUTF8 StartEvent(string eventName) + { + return null; + } + + public osUTF8 StartEvent(string eventName, int cap) + { + return null; + } + + public byte[] EndEventToBytes(osUTF8 sb) + { + return Array.Empty(); + } + } +} \ No newline at end of file diff --git a/Tests/OpenSim.Common.Tests/Mock/TestGroupsDataPlugin.cs b/Tests/OpenSim.Common.Tests/Mock/TestGroupsDataPlugin.cs new file mode 100644 index 00000000000..8e2d8e6c989 --- /dev/null +++ b/Tests/OpenSim.Common.Tests/Mock/TestGroupsDataPlugin.cs @@ -0,0 +1,339 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +using OpenMetaverse; +using OpenSim.Data; + +namespace OpenSim.Tests.Common.Mock +{ + public class TestGroupsDataPlugin : IGroupsData + { + class CompositeKey + { + private readonly string _key; + public string Key + { + get { return _key; } + } + + public CompositeKey(UUID _k1, string _k2) + { + _key = _k1.ToString() + _k2; + } + + public CompositeKey(UUID _k1, string _k2, string _k3) + { + _key = _k1.ToString() + _k2 + _k3; + } + + public override bool Equals(object obj) + { + if (obj is CompositeKey) + { + return Key == ((CompositeKey)obj).Key; + } + return false; + } + + public override int GetHashCode() + { + return base.GetHashCode(); + } + + public override string ToString() + { + return Key; + } + } + + private Dictionary m_Groups; + private Dictionary m_Membership; + private Dictionary m_Roles; + private Dictionary m_RoleMembership; + private Dictionary m_Invites; + private Dictionary m_Notices; + private Dictionary m_Principals; + + public TestGroupsDataPlugin(string connectionString, string realm) + { + m_Groups = new Dictionary(); + m_Membership = new Dictionary(); + m_Roles = new Dictionary(); + m_RoleMembership = new Dictionary(); + m_Invites = new Dictionary(); + m_Notices = new Dictionary(); + m_Principals = new Dictionary(); + } + + #region groups table + public bool StoreGroup(GroupData data) + { + return false; + } + + public GroupData RetrieveGroup(UUID groupID) + { + if (m_Groups.ContainsKey(groupID)) + return m_Groups[groupID]; + + return null; + } + + public GroupData RetrieveGroup(string name) + { + return m_Groups.Values.First(g => g.Data.ContainsKey("Name") && g.Data["Name"] == name); + } + + public GroupData[] RetrieveGroups(string pattern) + { + if (string.IsNullOrEmpty(pattern)) + pattern = "1"; + + IEnumerable groups = m_Groups.Values.Where(g => g.Data.ContainsKey("Name") && (g.Data["Name"].StartsWith(pattern) || g.Data["Name"].EndsWith(pattern))); + + return (groups != null) ? groups.ToArray() : new GroupData[0]; + } + + public bool DeleteGroup(UUID groupID) + { + return m_Groups.Remove(groupID); + } + + public int GroupsCount() + { + return m_Groups.Count; + } + #endregion + + #region membership table + public MembershipData RetrieveMember(UUID groupID, string pricipalID) + { + CompositeKey dkey = new CompositeKey(groupID, pricipalID); + if (m_Membership.ContainsKey(dkey)) + return m_Membership[dkey]; + + return null; + } + + public MembershipData[] RetrieveMembers(UUID groupID) + { + IEnumerable keys = m_Membership.Keys.Where(k => k.Key.StartsWith(groupID.ToString())); + return keys.Where(m_Membership.ContainsKey).Select(x => m_Membership[x]).ToArray(); + } + + public MembershipData[] RetrieveMemberships(string principalID) + { + IEnumerable keys = m_Membership.Keys.Where(k => k.Key.EndsWith(principalID.ToString())); + return keys.Where(m_Membership.ContainsKey).Select(x => m_Membership[x]).ToArray(); + } + + public MembershipData[] RetrievePrincipalGroupMemberships(string principalID) + { + return RetrieveMemberships(principalID); + } + + public MembershipData RetrievePrincipalGroupMembership(string principalID, UUID groupID) + { + CompositeKey dkey = new CompositeKey(groupID, principalID); + if (m_Membership.ContainsKey(dkey)) + return m_Membership[dkey]; + return null; + } + + public bool StoreMember(MembershipData data) + { + CompositeKey dkey = new CompositeKey(data.GroupID, data.PrincipalID); + m_Membership[dkey] = data; + return true; + } + + public bool DeleteMember(UUID groupID, string principalID) + { + CompositeKey dkey = new CompositeKey(groupID, principalID); + if (m_Membership.ContainsKey(dkey)) + return m_Membership.Remove(dkey); + + return false; + } + + public int MemberCount(UUID groupID) + { + return m_Membership.Count; + } + #endregion + + #region roles table + public bool StoreRole(RoleData data) + { + CompositeKey dkey = new CompositeKey(data.GroupID, data.RoleID.ToString()); + m_Roles[dkey] = data; + return true; + } + + public RoleData RetrieveRole(UUID groupID, UUID roleID) + { + CompositeKey dkey = new CompositeKey(groupID, roleID.ToString()); + if (m_Roles.ContainsKey(dkey)) + return m_Roles[dkey]; + + return null; + } + + public RoleData[] RetrieveRoles(UUID groupID) + { + IEnumerable keys = m_Roles.Keys.Where(k => k.Key.StartsWith(groupID.ToString())); + return keys.Where(m_Roles.ContainsKey).Select(x => m_Roles[x]).ToArray(); + } + + public bool DeleteRole(UUID groupID, UUID roleID) + { + CompositeKey dkey = new CompositeKey(groupID, roleID.ToString()); + if (m_Roles.ContainsKey(dkey)) + return m_Roles.Remove(dkey); + + return false; + } + + public int RoleCount(UUID groupID) + { + return m_Roles.Count; + } + #endregion + + #region rolememberhip table + public RoleMembershipData[] RetrieveRolesMembers(UUID groupID) + { + IEnumerable keys = m_Roles.Keys.Where(k => k.Key.StartsWith(groupID.ToString())); + return keys.Where(m_RoleMembership.ContainsKey).Select(x => m_RoleMembership[x]).ToArray(); + } + + public RoleMembershipData[] RetrieveRoleMembers(UUID groupID, UUID roleID) + { + IEnumerable keys = m_Roles.Keys.Where(k => k.Key.StartsWith(groupID.ToString() + roleID.ToString())); + return keys.Where(m_RoleMembership.ContainsKey).Select(x => m_RoleMembership[x]).ToArray(); + } + + public RoleMembershipData[] RetrieveMemberRoles(UUID groupID, string principalID) + { + IEnumerable keys = m_Roles.Keys.Where(k => k.Key.StartsWith(groupID.ToString()) && k.Key.EndsWith(principalID)); + return keys.Where(m_RoleMembership.ContainsKey).Select(x => m_RoleMembership[x]).ToArray(); + } + + public RoleMembershipData RetrieveRoleMember(UUID groupID, UUID roleID, string principalID) + { + CompositeKey dkey = new CompositeKey(groupID, roleID.ToString(), principalID); + if (m_RoleMembership.ContainsKey(dkey)) + return m_RoleMembership[dkey]; + + return null; + } + + public int RoleMemberCount(UUID groupID, UUID roleID) + { + return m_RoleMembership.Count; + } + + public bool StoreRoleMember(RoleMembershipData data) + { + CompositeKey dkey = new CompositeKey(data.GroupID, data.RoleID.ToString(), data.PrincipalID); + m_RoleMembership[dkey] = data; + return true; + } + + public bool DeleteRoleMember(RoleMembershipData data) + { + CompositeKey dkey = new CompositeKey(data.GroupID, data.RoleID.ToString(), data.PrincipalID); + if (m_RoleMembership.ContainsKey(dkey)) + return m_RoleMembership.Remove(dkey); + + return false; + } + + public bool DeleteMemberAllRoles(UUID groupID, string principalID) + { + List keys = m_RoleMembership.Keys.Where(k => k.Key.StartsWith(groupID.ToString()) && k.Key.EndsWith(principalID)).ToList(); + foreach (CompositeKey k in keys) + m_RoleMembership.Remove(k); + return true; + } + #endregion + + #region principals table + public bool StorePrincipal(PrincipalData data) + { + m_Principals[data.PrincipalID] = data; + return true; + } + + public PrincipalData RetrievePrincipal(string principalID) + { + if (m_Principals.ContainsKey(principalID)) + return m_Principals[principalID]; + + return null; + } + + public bool DeletePrincipal(string principalID) + { + if (m_Principals.ContainsKey(principalID)) + return m_Principals.Remove(principalID); + return false; + } + #endregion + + #region invites table + public bool StoreInvitation(InvitationData data) + { + return false; + } + + public InvitationData RetrieveInvitation(UUID inviteID) + { + return null; + } + + public InvitationData RetrieveInvitation(UUID groupID, string principalID) + { + return null; + } + + public bool DeleteInvite(UUID inviteID) + { + return false; + } + + public void DeleteOldInvites() + { + } + #endregion + + #region notices table + public bool StoreNotice(NoticeData data) + { + return false; + } + + public NoticeData RetrieveNotice(UUID noticeID) + { + return null; + } + + public NoticeData[] RetrieveNotices(UUID groupID) + { + return new NoticeData[0]; + } + + public bool DeleteNotice(UUID noticeID) + { + return false; + } + + public void DeleteOldNotices() + { + } + #endregion + + } +} diff --git a/Tests/OpenSim.Common.Tests/Mock/TestHttpClientContext.cs b/Tests/OpenSim.Common.Tests/Mock/TestHttpClientContext.cs new file mode 100644 index 00000000000..72938304921 --- /dev/null +++ b/Tests/OpenSim.Common.Tests/Mock/TestHttpClientContext.cs @@ -0,0 +1,112 @@ +/* + * 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 System.IO; +using System.Net; +using System.Net.Sockets; +using System.Text; +using OSHttpServer; +using OpenSim.Framework; + +namespace OpenSim.Tests.Common +{ +/* + public class TestHttpClientContext: IHttpClientContext + { + /// + /// Bodies of responses from the server. + /// + public string ResponseBody + { + get { return Encoding.UTF8.GetString(m_responseStream.ToArray()); } + } + + public Byte[] ResponseBodyBytes + { + get{ return m_responseStream.ToArray(); } + } + + private MemoryStream m_responseStream = new MemoryStream(); + + public bool IsSecured { get; set; } + + public bool Secured + { + get { return IsSecured; } + set { IsSecured = value; } + } + + public TestHttpClientContext(bool secured) + { + Secured = secured; + } + + public void Disconnect(SocketError error) + { +// Console.WriteLine("TestHttpClientContext.Disconnect Received disconnect with status {0}", error); + } + + public void Respond(string httpVersion, HttpStatusCode statusCode, string reason, string body) {Console.WriteLine("x");} + public void Respond(string httpVersion, HttpStatusCode statusCode, string reason) {Console.WriteLine("xx");} + public void Respond(string body) { Console.WriteLine("xxx");} + + public void Send(byte[] buffer) + { + // Getting header data here +// Console.WriteLine("xxxx: Got {0}", Encoding.UTF8.GetString(buffer)); + } + + public void Send(byte[] buffer, int offset, int size) + { +// Util.PrintCallStack(); +// +// Console.WriteLine( +// "TestHttpClientContext.Send(byte[], int, int) got offset={0}, size={1}, buffer={2}", +// offset, size, Encoding.UTF8.GetString(buffer)); + + m_responseStream.Write(buffer, offset, size); + } + + public void Respond(string httpVersion, HttpStatusCode statusCode, string reason, string body, string contentType) {Console.WriteLine("xxxxxx");} + public void Close() { } + public bool EndWhenDone { get { return false;} set { return;}} + + public HTTPNetworkContext GiveMeTheNetworkStreamIKnowWhatImDoing() + { + return new HTTPNetworkContext(); + } + + public event EventHandler Disconnected = delegate { }; + /// + /// A request have been received in the context. + /// + public event EventHandler RequestReceived = delegate { }; + } +*/ +} \ No newline at end of file diff --git a/Tests/OpenSim.Common.Tests/Mock/TestHttpRequest.cs b/Tests/OpenSim.Common.Tests/Mock/TestHttpRequest.cs new file mode 100644 index 00000000000..b69c70db5cd --- /dev/null +++ b/Tests/OpenSim.Common.Tests/Mock/TestHttpRequest.cs @@ -0,0 +1,175 @@ +/* + * 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.Specialized; +using System.IO; +using OSHttpServer; + +namespace OpenSim.Tests.Common +{ +/* + public class TestHttpRequest: IHttpRequest + { + private string _uriPath; + public bool BodyIsComplete + { + get { return true; } + } + public string[] AcceptTypes + { + get {return _acceptTypes; } + } + private string[] _acceptTypes; + public Stream Body + { + get { return _body; } + set { _body = value;} + } + private Stream _body; + public ConnectionType Connection + { + get { return _connection; } + set { _connection = value; } + } + private ConnectionType _connection; + public int ContentLength + { + get { return _contentLength; } + set { _contentLength = value; } + } + private int _contentLength; + public NameValueCollection Headers + { + get { return _headers; } + } + private NameValueCollection _headers = new NameValueCollection(); + + public string HttpVersion { get; set; } + + public string Method + { + get { return _method; } + set { _method = value; } + } + private string _method = null; + public HttpInput QueryString + { + get { return _queryString; } + } + private HttpInput _queryString = null; + public Uri Uri + { + get { return _uri; } + set { _uri = value; } + } + private Uri _uri = null; + public string[] UriParts + { + get { return _uri.Segments; } + } + public HttpParam Param + { + get { return null; } + } + public HttpForm Form + { + get { return null; } + } + public bool IsAjax + { + get { return false; } + } + public RequestCookies Cookies + { + get { return null; } + } + + public TestHttpRequest() + { + HttpVersion = "HTTP/1.1"; + } + + public TestHttpRequest(string contentEncoding, string contentType, string userAgent, + string remoteAddr, string remotePort, string[] acceptTypes, + ConnectionType connectionType, int contentLength, Uri uri) : base() + { + _headers["content-encoding"] = contentEncoding; + _headers["content-type"] = contentType; + _headers["user-agent"] = userAgent; + _headers["remote_addr"] = remoteAddr; + _headers["remote_port"] = remotePort; + + _acceptTypes = acceptTypes; + _connection = connectionType; + _contentLength = contentLength; + _uri = uri; + } + + public void DecodeBody(FormDecoderProvider providers) {} + public void SetCookies(RequestCookies cookies) {} + public void AddHeader(string name, string value) + { + _headers.Add(name, value); + } + public int AddToBody(byte[] bytes, int offset, int length) + { + return 0; + } + public void Clear() {} + + public object Clone() + { + TestHttpRequest clone = new TestHttpRequest(); + clone._acceptTypes = _acceptTypes; + clone._connection = _connection; + clone._contentLength = _contentLength; + clone._uri = _uri; + clone._headers = new NameValueCollection(_headers); + + return clone; + } + public IHttpResponse CreateResponse(IHttpClientContext context) + { + return new HttpResponse(context, this); + } + /// + /// Path and query (will be merged with the host header) and put in Uri + /// + /// + public string UriPath + { + get { return _uriPath; } + set + { + _uriPath = value; + + } + } + } +*/ +} \ No newline at end of file diff --git a/Tests/OpenSim.Common.Tests/Mock/TestHttpResponse.cs b/Tests/OpenSim.Common.Tests/Mock/TestHttpResponse.cs new file mode 100644 index 00000000000..f6f789819c9 --- /dev/null +++ b/Tests/OpenSim.Common.Tests/Mock/TestHttpResponse.cs @@ -0,0 +1,173 @@ +/* + * 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.IO; +using System.Net; +using System.Text; +using OSHttpServer; + +namespace OpenSim.Tests.Common +{ +/* + public class TestHttpResponse: IHttpResponse + { + public Stream Body + { + get { return _body; } + + set { _body = value; } + } + private Stream _body; + + public string ProtocolVersion + { + get { return _protocolVersion; } + set { _protocolVersion = value; } + } + private string _protocolVersion; + + public bool Chunked + { + get { return _chunked; } + + set { _chunked = value; } + } + private bool _chunked; + + public ConnectionType Connection + { + get { return _connection; } + + set { _connection = value; } + } + private ConnectionType _connection; + + public Encoding Encoding + { + get { return _encoding; } + + set { _encoding = value; } + } + private Encoding _encoding; + + public int KeepAlive + { + get { return _keepAlive; } + + set { _keepAlive = value; } + } + private int _keepAlive; + + public HttpStatusCode Status + { + get { return _status; } + + set { _status = value; } + } + private HttpStatusCode _status; + + public string Reason + { + get { return _reason; } + + set { _reason = value; } + } + private string _reason; + + public long ContentLength + { + get { return _contentLength; } + + set { _contentLength = value; } + } + private long _contentLength; + + public string ContentType + { + get { return _contentType; } + + set { _contentType = value; } + } + private string _contentType; + + public bool HeadersSent + { + get { return _headersSent; } + } + private bool _headersSent; + + public bool Sent + { + get { return _sent; } + } + private bool _sent; + + public ResponseCookies Cookies + { + get { return _cookies; } + } + private ResponseCookies _cookies = null; + + public TestHttpResponse() + { + _headersSent = false; + _sent = false; + } + + public void AddHeader(string name, string value) {} + + public void Send() + { + if (!_headersSent) SendHeaders(); + if (_sent) throw new InvalidOperationException("stuff already sent"); + _sent = true; + } + + public void SendBody(byte[] buffer, int offset, int count) + { + if (!_headersSent) SendHeaders(); + _sent = true; + } + + public void SendBody(byte[] buffer) + { + if (!_headersSent) SendHeaders(); + _sent = true; + } + + public void SendHeaders() + { + if (_headersSent) throw new InvalidOperationException("headers already sent"); + _headersSent = true; + } + + public void Redirect(Uri uri) {} + public void Redirect(string url) {} + } +*/ +} \ No newline at end of file diff --git a/Tests/OpenSim.Common.Tests/Mock/TestInventoryDataPlugin.cs b/Tests/OpenSim.Common.Tests/Mock/TestInventoryDataPlugin.cs new file mode 100644 index 00000000000..04cda547bd1 --- /dev/null +++ b/Tests/OpenSim.Common.Tests/Mock/TestInventoryDataPlugin.cs @@ -0,0 +1,219 @@ +/* + * 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 System.Reflection; +using log4net; +using OpenMetaverse; +using OpenSim.Framework; +using OpenSim.Data; + +namespace OpenSim.Tests.Common +{ + /// + /// In memory inventory data plugin for test purposes. Could be another dll when properly filled out and when the + /// mono addin plugin system starts co-operating with the unit test system. Currently no locking since unit + /// tests are single threaded. + /// + public class TestInventoryDataPlugin : IInventoryDataPlugin + { +// private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + + /// + /// Inventory folders + /// + private Dictionary m_folders = new Dictionary(); + + //// + /// Inventory items + /// + private Dictionary m_items = new Dictionary(); + + /// + /// User root folders + /// + private Dictionary m_rootFolders = new Dictionary(); + + public string Version { get { return "0"; } } + public string Name { get { return "TestInventoryDataPlugin"; } } + + public void Initialise() {} + public void Initialise(string connect) {} + public void Dispose() {} + + public List getFolderHierarchy(UUID parentID) + { + List folders = new List(); + + foreach (InventoryFolderBase folder in m_folders.Values) + { + if (folder.ParentID == parentID) + { + folders.AddRange(getFolderHierarchy(folder.ID)); + folders.Add(folder); + } + } + + return folders; + } + + public List getInventoryInFolder(UUID folderID) + { +// InventoryFolderBase folder = m_folders[folderID]; + +// m_log.DebugFormat("[MOCK INV DB]: Getting items in folder {0} {1}", folder.Name, folder.ID); + + List items = new List(); + + foreach (InventoryItemBase item in m_items.Values) + { + if (item.Folder == folderID) + { +// m_log.DebugFormat("[MOCK INV DB]: getInventoryInFolder() adding item {0}", item.Name); + items.Add(item); + } + } + + return items; + } + + public List getUserRootFolders(UUID user) { return null; } + + public InventoryFolderBase getUserRootFolder(UUID user) + { +// m_log.DebugFormat("[MOCK INV DB]: Looking for root folder for {0}", user); + + InventoryFolderBase folder = null; + m_rootFolders.TryGetValue(user, out folder); + + return folder; + } + + public List getInventoryFolders(UUID parentID) + { +// InventoryFolderBase parentFolder = m_folders[parentID]; + +// m_log.DebugFormat("[MOCK INV DB]: Getting folders in folder {0} {1}", parentFolder.Name, parentFolder.ID); + + List folders = new List(); + + foreach (InventoryFolderBase folder in m_folders.Values) + { + if (folder.ParentID == parentID) + { +// m_log.DebugFormat( +// "[MOCK INV DB]: Found folder {0} {1} in {2} {3}", +// folder.Name, folder.ID, parentFolder.Name, parentFolder.ID); + + folders.Add(folder); + } + } + + return folders; + } + + public InventoryFolderBase getInventoryFolder(UUID folderId) + { + InventoryFolderBase folder = null; + m_folders.TryGetValue(folderId, out folder); + + return folder; + } + + public InventoryFolderBase queryInventoryFolder(UUID folderID) + { + return getInventoryFolder(folderID); + } + + public void addInventoryFolder(InventoryFolderBase folder) + { +// m_log.DebugFormat( +// "[MOCK INV DB]: Adding inventory folder {0} {1} type {2}", +// folder.Name, folder.ID, (AssetType)folder.Type); + + m_folders[folder.ID] = folder; + + if (folder.ParentID.IsZero()) + { +// m_log.DebugFormat( +// "[MOCK INV DB]: Adding root folder {0} {1} for {2}", folder.Name, folder.ID, folder.Owner); + m_rootFolders[folder.Owner] = folder; + } + } + + public void updateInventoryFolder(InventoryFolderBase folder) + { + m_folders[folder.ID] = folder; + } + + public void moveInventoryFolder(InventoryFolderBase folder) + { + // Simple replace + updateInventoryFolder(folder); + } + + public void deleteInventoryFolder(UUID folderId) + { + if (m_folders.ContainsKey(folderId)) + m_folders.Remove(folderId); + } + + public void addInventoryItem(InventoryItemBase item) + { + InventoryFolderBase folder = m_folders[item.Folder]; + +// m_log.DebugFormat( +// "[MOCK INV DB]: Adding inventory item {0} {1} in {2} {3}", item.Name, item.ID, folder.Name, folder.ID); + + m_items[item.ID] = item; + } + + public void updateInventoryItem(InventoryItemBase item) { addInventoryItem(item); } + + public void deleteInventoryItem(UUID itemId) + { + if (m_items.ContainsKey(itemId)) + m_items.Remove(itemId); + } + + public InventoryItemBase getInventoryItem(UUID itemId) + { + if (m_items.ContainsKey(itemId)) + return m_items[itemId]; + else + return null; + } + + public InventoryItemBase queryInventoryItem(UUID item) + { + return null; + } + + public List fetchActiveGestures(UUID avatarID) { return null; } + } +} diff --git a/Tests/OpenSim.Common.Tests/Mock/TestLLUDPServer.cs b/Tests/OpenSim.Common.Tests/Mock/TestLLUDPServer.cs new file mode 100644 index 00000000000..d32d1b5510c --- /dev/null +++ b/Tests/OpenSim.Common.Tests/Mock/TestLLUDPServer.cs @@ -0,0 +1,171 @@ +/* + * 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 System.Net; +using System.Net.Sockets; +using Nini.Config; +using OpenMetaverse.Packets; +using OpenSim.Framework; +using OpenSim.Region.ClientStack.LindenUDP; + +namespace OpenSim.Tests.Common +{ + /// + /// This class enables regression testing of the LLUDPServer by allowing us to intercept outgoing data. + /// + public class TestLLUDPServer : LLUDPServer + { + public List PacketsSent { get; private set; } + + public TestLLUDPServer(IPAddress listenIP, uint port, int proxyPortOffsetParm, IConfigSource configSource, AgentCircuitManager circuitManager) + : base(listenIP, port, proxyPortOffsetParm, configSource, circuitManager) + { + PacketsSent = new List(); + } + + public override void SendAckImmediate(IPEndPoint remoteEndpoint, PacketAckPacket ack) + { + PacketsSent.Add(ack); + } + + public override void SendPacket( + LLUDPClient udpClient, Packet packet, ThrottleOutPacketType category, bool allowSplitting, UnackedPacketMethod method) + { + PacketsSent.Add(packet); + } + + public void ClientOutgoingPacketHandler(IClientAPI client, bool resendUnacked, bool sendAcks, bool sendPing) + { + m_resendUnacked = resendUnacked; + m_sendAcks = sendAcks; + m_sendPing = sendPing; + + ClientOutgoingPacketHandler(client); + } + +//// /// +//// /// The chunks of data to pass to the LLUDPServer when it calls EndReceive +//// /// +//// protected Queue m_chunksToLoad = new Queue(); +// +//// protected override void BeginReceive() +//// { +//// if (m_chunksToLoad.Count > 0 && m_chunksToLoad.Peek().BeginReceiveException) +//// { +//// ChunkSenderTuple tuple = m_chunksToLoad.Dequeue(); +//// reusedEpSender = tuple.Sender; +//// throw new SocketException(); +//// } +//// } +// +//// protected override bool EndReceive(out int numBytes, IAsyncResult result, ref EndPoint epSender) +//// { +//// numBytes = 0; +//// +//// //m_log.Debug("Queue size " + m_chunksToLoad.Count); +//// +//// if (m_chunksToLoad.Count <= 0) +//// return false; +//// +//// ChunkSenderTuple tuple = m_chunksToLoad.Dequeue(); +//// RecvBuffer = tuple.Data; +//// numBytes = tuple.Data.Length; +//// epSender = tuple.Sender; +//// +//// return true; +//// } +// +//// public override void SendPacketTo(byte[] buffer, int size, SocketFlags flags, uint circuitcode) +//// { +//// // Don't do anything just yet +//// } +// +// /// +// /// Signal that this chunk should throw an exception on Socket.BeginReceive() +// /// +// /// +// public void LoadReceiveWithBeginException(EndPoint epSender) +// { +// ChunkSenderTuple tuple = new ChunkSenderTuple(epSender); +// tuple.BeginReceiveException = true; +// m_chunksToLoad.Enqueue(tuple); +// } +// +// /// +// /// Load some data to be received by the LLUDPServer on the next receive call +// /// +// /// +// /// +// public void LoadReceive(byte[] data, EndPoint epSender) +// { +// m_chunksToLoad.Enqueue(new ChunkSenderTuple(data, epSender)); +// } +// +// /// +// /// Load a packet to be received by the LLUDPServer on the next receive call +// /// +// /// +// public void LoadReceive(Packet packet, EndPoint epSender) +// { +// LoadReceive(packet.ToBytes(), epSender); +// } +// +// /// +// /// Calls the protected asynchronous result method. This fires out all data chunks currently queued for send +// /// +// /// +// public void ReceiveData(IAsyncResult result) +// { +// // Doesn't work the same way anymore +//// while (m_chunksToLoad.Count > 0) +//// OnReceivedData(result); +// } + } + + /// + /// Record the data and sender tuple + /// + public class ChunkSenderTuple + { + public byte[] Data; + public EndPoint Sender; + public bool BeginReceiveException; + + public ChunkSenderTuple(byte[] data, EndPoint sender) + { + Data = data; + Sender = sender; + } + + public ChunkSenderTuple(EndPoint sender) + { + Sender = sender; + } + } +} diff --git a/Tests/OpenSim.Common.Tests/Mock/TestLandChannel.cs b/Tests/OpenSim.Common.Tests/Mock/TestLandChannel.cs new file mode 100644 index 00000000000..38a4a2a476d --- /dev/null +++ b/Tests/OpenSim.Common.Tests/Mock/TestLandChannel.cs @@ -0,0 +1,130 @@ +/* + * 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.Collections.Generic; +using OpenMetaverse; +using OpenSim.Framework; +using OpenSim.Region.Framework.Interfaces; +using OpenSim.Region.Framework.Scenes; +using OpenSim.Region.CoreModules.World.Land; + +namespace OpenSim.Tests.Common +{ + /// + /// Land channel for test purposes + /// + public class TestLandChannel : ILandChannel + { + private Scene m_scene; + private List m_parcels; + + public float BanLineSafeHeight { get { return 100f; } } + + public TestLandChannel(Scene scene) + { + m_scene = scene; + m_parcels = new List(); + SetupDefaultParcel(); + } + + private void SetupDefaultParcel() + { + ILandObject obj = new LandObject(UUID.Zero, false, m_scene); + obj.LandData.Name = "Your Parcel"; + m_parcels.Add(obj); + } + + public List ParcelsNearPoint(Vector3 position) + { + return new List(); + } + + public List AllParcels() + { + return m_parcels; + } + + public void Clear(bool setupDefaultParcel) + { + m_parcels.Clear(); + + if (setupDefaultParcel) + SetupDefaultParcel(); + } + + protected ILandObject GetNoLand() + { + ILandObject obj = new LandObject(UUID.Zero, false, m_scene); + obj.LandData.Name = "NO LAND"; + return obj; + } + + public ILandObject GetLandObject(Vector3 position) + { + return GetLandObject(position.X, position.Y); + } + + public ILandObject GetLandObject(int x, int y) + { + return GetNoLand(); + } + + public ILandObject GetLandObjectClippedXY(float x, float y) + { + return GetNoLand(); + } + + public ILandObject GetLandObject(int localID) + { + return GetNoLand(); + } + + public ILandObject GetLandObject(UUID ID) + { + return GetNoLand(); + } + + public ILandObject GetLandObject(float x, float y) + { + return GetNoLand(); + } + + public bool IsLandPrimCountTainted() { return false; } + public bool IsForcefulBansAllowed() { return false; } + public void UpdateLandObject(int localID, LandData data) {} + public void SendParcelsOverlay(IClientAPI client) {} + public void ReturnObjectsInParcel(int localID, uint returnType, UUID[] agentIDs, UUID[] taskIDs, IClientAPI remoteClient) {} + public void setParcelObjectMaxOverride(overrideParcelMaxPrimCountDelegate overrideDel) {} + public void setSimulatorObjectMaxOverride(overrideSimulatorMaxPrimCountDelegate overrideDel) {} + public void SetParcelOtherCleanTime(IClientAPI remoteClient, int localID, int otherCleanTime) {} + + public void Join(int start_x, int start_y, int end_x, int end_y, UUID attempting_user_id) {} + public void Subdivide(int start_x, int start_y, int end_x, int end_y, UUID attempting_user_id) {} + public void sendClientInitialLandInfo(IClientAPI remoteClient, bool overlay) { } + public void ClearAllEnvironments(){ } + } +} \ No newline at end of file diff --git a/Tests/OpenSim.Common.Tests/Mock/TestOSHttpRequest.cs b/Tests/OpenSim.Common.Tests/Mock/TestOSHttpRequest.cs new file mode 100644 index 00000000000..722ab704787 --- /dev/null +++ b/Tests/OpenSim.Common.Tests/Mock/TestOSHttpRequest.cs @@ -0,0 +1,192 @@ +/* + * 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; +using System.Collections.Generic; +using System.Collections.Specialized; +using System.IO; +using System.Net; +using System.Text; +using System.Web; +using OpenSim.Framework.Servers.HttpServer; + +namespace OpenSim.Tests.Common +{ + public class TestOSHttpRequest : IOSHttpRequest + { + public string[] AcceptTypes + { + get + { + throw new NotImplementedException (); + } + } + + public Encoding ContentEncoding + { + get + { + throw new NotImplementedException (); + } + } + + public long ContentLength + { + get + { + throw new NotImplementedException (); + } + } + + public long ContentLength64 + { + get + { + throw new NotImplementedException (); + } + } + + public string ContentType + { + get + { + throw new NotImplementedException (); + } + } + + + public bool HasEntityBody + { + get + { + throw new NotImplementedException (); + } + } + + public NameValueCollection Headers { get; set; } + + public string HttpMethod + { + get + { + throw new NotImplementedException (); + } + } + + public Stream InputStream { get; set;} + + public bool IsSecured + { + get + { + throw new NotImplementedException (); + } + } + + public bool KeepAlive + { + get + { + throw new NotImplementedException (); + } + } + + public NameValueCollection QueryString + { + get + { + throw new NotImplementedException (); + } + } + + public Hashtable Query + { + get + { + throw new NotImplementedException(); + } + } + + public Dictionary QueryAsDictionary + { + get + { + throw new NotImplementedException(); + } + } + + public HashSet QueryFlags + { + get + { + throw new NotImplementedException(); + } + } + + public string RawUrl + { + get + { + throw new NotImplementedException (); + } + } + + public IPEndPoint RemoteIPEndPoint + { + get + { + throw new NotImplementedException(); + } + } + + public IPEndPoint LocalIPEndPoint + { + get + { + throw new NotImplementedException(); + } + } + + public Uri Url { get; set; } + public string UriPath { get;} + public double ArrivalTS { get; } + + public string UserAgent + { + get + { + throw new NotImplementedException (); + } + } + + public TestOSHttpRequest() + { + Headers = new NameValueCollection(); + } + } +} \ No newline at end of file diff --git a/Tests/OpenSim.Common.Tests/Mock/TestOSHttpResponse.cs b/Tests/OpenSim.Common.Tests/Mock/TestOSHttpResponse.cs new file mode 100644 index 00000000000..6afcb05d8ab --- /dev/null +++ b/Tests/OpenSim.Common.Tests/Mock/TestOSHttpResponse.cs @@ -0,0 +1,139 @@ +/* + * 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 System.IO; +using System.Net; +using System.Text; +using OpenSim.Framework.Servers.HttpServer; + +namespace OpenSim.Tests.Common +{ + public class TestOSHttpResponse : IOSHttpResponse + { + /// + /// Content type property. + /// + /// + /// Setting this property will also set IsContentTypeSet to + /// true. + /// + public string ContentType { get; set; } + + /// + /// Boolean property indicating whether the content type + /// property actively has been set. + /// + /// + /// IsContentTypeSet will go away together with .NET base. + /// + // public bool IsContentTypeSet + // { + // get { return _contentTypeSet; } + // } + // private bool _contentTypeSet; + + /// + /// Length of the body content; 0 if there is no body. + /// + public long ContentLength { get; set; } + + /// + /// Alias for ContentLength. + /// + public long ContentLength64 { get; set; } + + public int Priority { get; set; } + public byte[] RawBuffer { get; set; } + public int RawBufferStart { get; set; } + public int RawBufferLen { get; set; } + + /// + /// Encoding of the body content. + /// + public Encoding ContentEncoding { get; set; } + + public bool KeepAlive { get; set; } + + /// + /// Get or set the keep alive timeout property (default is + /// 20). Setting this to 0 also disables KeepAlive. Setting + /// this to something else but 0 also enable KeepAlive. + /// + public int KeepAliveTimeout { get; set; } + + /// + /// Return the output stream feeding the body. + /// + /// + /// On its way out... + /// + public Stream OutputStream { get; private set; } + + public string ProtocolVersion { get; set; } + + /// + /// Return the output stream feeding the body. + /// + public Stream Body { get; private set; } + + /// + /// Chunk transfers. + /// + public bool SendChunked { get; set; } + + /// + /// HTTP status code. + /// + public int StatusCode { get; set; } + + /// + /// HTTP status description. + /// + public string StatusDescription { get; set; } + + public double RequestTS { get; } + + /// + /// Set response as a http redirect + /// + /// redirection target url + /// the response Status, must be Redirect, Moved,MovedPermanently,RedirectKeepVerb, RedirectMethod, TemporaryRedirect. Defaults to Redirect + public void Redirect(string url, HttpStatusCode redirStatusCode = HttpStatusCode.Redirect) { throw new NotImplementedException(); } + /// + /// Add a header field and content to the response. + /// + /// string containing the header field + /// name + /// string containing the header field + /// value + public void AddHeader(string key, string value) { throw new NotImplementedException(); } + + public void Send() { } + } +} \ No newline at end of file diff --git a/Tests/OpenSim.Common.Tests/Mock/TestScene.cs b/Tests/OpenSim.Common.Tests/Mock/TestScene.cs new file mode 100644 index 00000000000..0b3d4465fc1 --- /dev/null +++ b/Tests/OpenSim.Common.Tests/Mock/TestScene.cs @@ -0,0 +1,77 @@ +/* + * 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 Nini.Config; +using OpenSim.Framework; + +using OpenSim.Framework.Servers; +using OpenSim.Region.Framework; +using OpenSim.Region.Framework.Interfaces; +using OpenSim.Region.Framework.Scenes; +using OpenSim.Region.PhysicsModules.SharedBase; +using OpenSim.Services.Interfaces; + +namespace OpenSim.Tests.Common +{ + public class TestScene : Scene + { + public TestScene( + RegionInfo regInfo, AgentCircuitManager authen, + ISimulationDataService simDataService, IEstateDataService estateDataService, + IConfigSource config, string simulatorVersion) + : base(regInfo, authen, simDataService, estateDataService, + config, simulatorVersion) + { + } + + ~TestScene() + { + //Console.WriteLine("TestScene destructor called for {0}", RegionInfo.RegionName); + Console.WriteLine("TestScene destructor called"); + } + + /// + /// Temporarily override session authentication for tests (namely teleport). + /// + /// + /// TODO: This needs to be mocked out properly. + /// + /// + /// + public override bool VerifyUserPresence(AgentCircuitData agent, out string reason) + { + reason = String.Empty; + return true; + } + + public AsyncSceneObjectGroupDeleter SceneObjectGroupDeleter + { + get { return m_asyncSceneObjectDeleter; } + } + } +} diff --git a/Tests/OpenSim.Common.Tests/Mock/TestXInventoryDataPlugin.cs b/Tests/OpenSim.Common.Tests/Mock/TestXInventoryDataPlugin.cs new file mode 100644 index 00000000000..c5d8d18d1df --- /dev/null +++ b/Tests/OpenSim.Common.Tests/Mock/TestXInventoryDataPlugin.cs @@ -0,0 +1,197 @@ +/* + * 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 System.Linq; +using System.Reflection; +using log4net; +using OpenMetaverse; +using OpenSim.Framework; +using OpenSim.Data; +using OpenSim.Data.Null; + +namespace OpenSim.Tests.Common +{ + public class TestXInventoryDataPlugin : NullGenericDataHandler, IXInventoryData + { + private Dictionary m_allFolders = new Dictionary(); + private Dictionary m_allItems = new Dictionary(); + + public TestXInventoryDataPlugin(string conn, string realm) {} + + public XInventoryItem[] GetItems(string field, string val) + { +// Console.WriteLine( +// "Requesting items, fields {0}, vals {1}", string.Join(", ", fields), string.Join(", ", vals)); + + List origItems = Get(field, val, m_allItems.Values.ToList()); + + XInventoryItem[] items = origItems.Select(i => i.Clone()).ToArray(); + +// Console.WriteLine("Found {0} items", items.Length); +// Array.ForEach(items, i => Console.WriteLine("Found item {0} {1}", i.inventoryName, i.inventoryID)); + + return items; + } + + public XInventoryItem[] GetItems(string field, string[] vals) + { +// Console.WriteLine( +// "Requesting items, fields {0}, vals {1}", string.Join(", ", fields), string.Join(", ", vals)); + + List origItems = Get(field, vals, m_allItems.Values.ToList()); + + XInventoryItem[] items = origItems.Select(i => i.Clone()).ToArray(); + +// Console.WriteLine("Found {0} items", items.Length); +// Array.ForEach(items, i => Console.WriteLine("Found item {0} {1}", i.inventoryName, i.inventoryID)); + + return items; + } + + public XInventoryItem[] GetItems(string[] fields, string[] vals) + { +// Console.WriteLine( +// "Requesting items, fields {0}, vals {1}", string.Join(", ", fields), string.Join(", ", vals)); + + List origItems = Get(fields, vals, m_allItems.Values.ToList()); + + XInventoryItem[] items = origItems.Select(i => i.Clone()).ToArray(); + +// Console.WriteLine("Found {0} items", items.Length); +// Array.ForEach(items, i => Console.WriteLine("Found item {0} {1}", i.inventoryName, i.inventoryID)); + + return items; + } + + public XInventoryFolder[] GetFolders(string[] fields, string[] vals) + { +// Console.WriteLine( +// "Requesting folders, fields {0}, vals {1}", string.Join(", ", fields), string.Join(", ", vals)); + + List origFolders + = Get(fields, vals, m_allFolders.Values.ToList()); + + XInventoryFolder[] folders = origFolders.Select(f => f.Clone()).ToArray(); + +// Console.WriteLine("Found {0} folders", folders.Length); +// Array.ForEach(folders, f => Console.WriteLine("Found folder {0} {1}", f.folderName, f.folderID)); + + return folders; + } + + public bool StoreFolder(XInventoryFolder folder) + { + m_allFolders[folder.folderID] = folder.Clone(); + +// Console.WriteLine("Added folder {0} {1}", folder.folderName, folder.folderID); + + return true; + } + + public bool StoreItem(XInventoryItem item) + { + m_allItems[item.inventoryID] = item.Clone(); + +// Console.WriteLine( +// "Added item {0} {1}, folder {2}, creator {3}, owner {4}", +// item.inventoryName, item.inventoryID, item.parentFolderID, item.creatorID, item.avatarID); + + return true; + } + + public bool DeleteFolders(string field, string val) + { + return DeleteFolders(new string[] { field }, new string[] { val }); + } + + public bool DeleteFolders(string[] fields, string[] vals) + { + XInventoryFolder[] foldersToDelete = GetFolders(fields, vals); + Array.ForEach(foldersToDelete, f => m_allFolders.Remove(f.folderID)); + + return true; + } + + public bool DeleteItems(string field, string val) + { + return DeleteItems(new string[] { field }, new string[] { val }); + } + + public bool DeleteItems(string[] fields, string[] vals) + { + XInventoryItem[] itemsToDelete = GetItems(fields, vals); + Array.ForEach(itemsToDelete, i => m_allItems.Remove(i.inventoryID)); + + return true; + } + + public bool MoveItem(string id, string newParent) + { + UUID uid = new UUID(id); + UUID upid = new UUID(newParent); + m_allItems[uid].parentFolderID = upid; + return true; + } + + public bool MoveItems(string[] ids, string[] newParents) + { + if(ids.Length != newParents.Length) + return false; + for(int i =0; i< ids.Length;++i) + MoveItem(ids[i], newParents[i]); + return true; + } + + public bool MoveFolder(string id, string newParent) + { + // Don't use GetFolders() here - it takes a clone! + XInventoryFolder folder = m_allFolders[new UUID(id)]; + + if (folder == null) + return false; + + folder.parentFolderID = new UUID(newParent); + +// XInventoryFolder[] newParentFolders +// = GetFolders(new string[] { "folderID" }, new string[] { folder.parentFolderID.ToString() }); + +// Console.WriteLine( +// "Moved folder {0} {1}, to {2} {3}", +// folder.folderName, folder.folderID, newParentFolders[0].folderName, folder.parentFolderID); + + // TODO: Really need to implement folder version incrementing, though this should be common code anyway, + // not reimplemented in each db plugin. + + return true; + } + + public XInventoryItem[] GetActiveGestures(UUID principalID) { throw new NotImplementedException(); } + public int GetAssetPermissions(UUID principalID, UUID assetID) { throw new NotImplementedException(); } + } +} \ No newline at end of file diff --git a/Tests/OpenSim.Common.Tests/OpenSim.Tests.Common.csproj b/Tests/OpenSim.Common.Tests/OpenSim.Tests.Common.csproj new file mode 100644 index 00000000000..1f699bfe62b --- /dev/null +++ b/Tests/OpenSim.Common.Tests/OpenSim.Tests.Common.csproj @@ -0,0 +1,55 @@ + + + net6.0 + + + + + + + + + + + + ..\..\..\bin\Nini.dll + False + + + ..\..\..\bin\OpenMetaverse.dll + False + + + ..\..\..\bin\OpenMetaverse.StructuredData.dll + False + + + ..\..\..\bin\OpenMetaverseTypes.dll + False + + + False + + + False + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Tests/OpenSim.Common.Tests/OpenSimTestCase.cs b/Tests/OpenSim.Common.Tests/OpenSimTestCase.cs new file mode 100644 index 00000000000..9fea34820c9 --- /dev/null +++ b/Tests/OpenSim.Common.Tests/OpenSimTestCase.cs @@ -0,0 +1,55 @@ +/* + * 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 NUnit.Framework; +using OpenSim.Framework; +using OpenSim.Framework.Servers; + +namespace OpenSim.Tests.Common +{ + [TestFixture] + public class OpenSimTestCase + { + [SetUp] + public virtual void SetUp() + { + //TestHelpers.InMethod(); + // Disable logging for each test so that one where logging is enabled doesn't cause all subsequent tests + // to have logging on if it failed with an exception. + TestHelpers.DisableLogging(); + + // This is an unfortunate bit of clean up we have to do because MainServer manages things through static + // variables and the VM is not restarted between tests. + if (MainServer.Instance != null) + { + MainServer.RemoveHttpServer(MainServer.Instance.Port); +// MainServer.Instance = null; + } + } + } +} \ No newline at end of file diff --git a/Tests/OpenSim.Common.Tests/QuaternionToleranceConstraint.cs b/Tests/OpenSim.Common.Tests/QuaternionToleranceConstraint.cs new file mode 100644 index 00000000000..b38c382f53b --- /dev/null +++ b/Tests/OpenSim.Common.Tests/QuaternionToleranceConstraint.cs @@ -0,0 +1,82 @@ +/* + * 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 OpenMetaverse; +using NUnit.Framework; +using NUnit.Framework.Constraints; + +namespace OpenSim.Tests.Common +{ + public class QuaternionToleranceConstraint : ANumericalToleranceConstraint + { + private Quaternion _baseValue; + private Quaternion _valueToBeTested; + + public QuaternionToleranceConstraint(Quaternion baseValue, double tolerance) : base(tolerance) + { + _baseValue = baseValue; + } + + /// + /// Test whether the constraint is satisfied by a given value + /// + /// The value to be tested + /// + /// True for success, false for failure + /// + public override bool Matches(object valueToBeTested) + { + if (valueToBeTested == null) + { + throw new ArgumentException("Constraint cannot be used upon null values."); + } + if (valueToBeTested.GetType() != typeof (Quaternion)) + { + throw new ArgumentException("Constraint cannot be used upon non quaternion values."); + } + + _valueToBeTested = (Quaternion)valueToBeTested; + + return (IsWithinDoubleConstraint(_valueToBeTested.X, _baseValue.X) && + IsWithinDoubleConstraint(_valueToBeTested.Y, _baseValue.Y) && + IsWithinDoubleConstraint(_valueToBeTested.Z, _baseValue.Z) && + IsWithinDoubleConstraint(_valueToBeTested.W, _baseValue.W)); + } + + public override void WriteDescriptionTo(MessageWriter writer) + { + writer.WriteExpectedValue( + string.Format("A value {0} within tolerance of plus or minus {1}", _baseValue, _tolerance)); + } + + public override void WriteActualValueTo(MessageWriter writer) + { + writer.WriteActualValue(_valueToBeTested); + } + } +} \ No newline at end of file diff --git a/Tests/OpenSim.Common.Tests/TestHelpers.cs b/Tests/OpenSim.Common.Tests/TestHelpers.cs new file mode 100644 index 00000000000..2b2af346705 --- /dev/null +++ b/Tests/OpenSim.Common.Tests/TestHelpers.cs @@ -0,0 +1,164 @@ +/* + * 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.Diagnostics; +using System.IO; +using System.Text; +using NUnit.Framework; +using OpenMetaverse; + +namespace OpenSim.Tests.Common +{ + public class TestHelpers + { + private static Stream EnableLoggingConfigStream + = new MemoryStream( + Encoding.UTF8.GetBytes( +@" + + + + + + + + + + + + + + + + +")); + + private static MemoryStream DisableLoggingConfigStream + = new MemoryStream( + Encoding.UTF8.GetBytes( +// "")); + //""))); +// "")); +// ""))); +// "")); + "")); + + public static bool AssertThisDelegateCausesArgumentException(TestDelegate d) + { + try + { + d(); + } + catch(ArgumentException) + { + return true; + } + + return false; + } + + /// + /// A debugging method that can be used to print out which test method you are in + /// + public static void InMethod() + { + StackTrace stackTrace = new StackTrace(); + Console.WriteLine(); + Console.WriteLine("===> In Test Method : {0} <===", stackTrace.GetFrame(1).GetMethod().Name); + } + + public static void EnableLogging() + { + log4net.Config.XmlConfigurator.Configure(EnableLoggingConfigStream); + EnableLoggingConfigStream.Position = 0; + } + + /// + /// Disable logging whilst running the tests. + /// + /// + /// Remember, if a regression test throws an exception before completing this will not be invoked if it's at + /// the end of the test. + /// TODO: Always invoke this after every test - probably need to make all test cases inherit from a common + /// TestCase class where this can be done. + /// + public static void DisableLogging() + { + log4net.Config.XmlConfigurator.Configure(DisableLoggingConfigStream); + DisableLoggingConfigStream.Position = 0; + } + + /// + /// Parse a UUID stem into a full UUID. + /// + /// + /// The fragment will come at the start of the UUID. The rest will be 0s + /// + /// + /// + /// A UUID fragment that will be parsed into a full UUID. Therefore, it can only contain + /// cahracters which are valid in a UUID, except for "-" which is currently only allowed if a full UUID is + /// given as the 'fragment'. + /// + public static UUID ParseStem(string stem) + { + string rawUuid = stem.PadRight(32, '0'); + + return UUID.Parse(rawUuid); + } + + /// + /// Parse tail section into full UUID. + /// + /// + /// + public static UUID ParseTail(int tail) + { + return new UUID(string.Format("00000000-0000-0000-0000-{0:X12}", tail)); + } + + /// + /// Parse a UUID tail section into a full UUID. + /// + /// + /// The fragment will come at the end of the UUID. The rest will be 0s + /// + /// + /// + /// A UUID fragment that will be parsed into a full UUID. Therefore, it can only contain + /// cahracters which are valid in a UUID, except for "-" which is currently only allowed if a full UUID is + /// given as the 'fragment'. + /// + public static UUID ParseTail(string stem) + { + string rawUuid = stem.PadLeft(32, '0'); + + return UUID.Parse(rawUuid); + } + } +} diff --git a/Tests/OpenSim.Common.Tests/TestLogging.cs b/Tests/OpenSim.Common.Tests/TestLogging.cs new file mode 100644 index 00000000000..4a08344321c --- /dev/null +++ b/Tests/OpenSim.Common.Tests/TestLogging.cs @@ -0,0 +1,46 @@ +/* + * 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 System.Text; +using log4net.Appender; +using log4net.Layout; + +namespace OpenSim.Tests.Common +{ + public static class TestLogging + { + public static void LogToConsole() + { + ConsoleAppender consoleAppender = new ConsoleAppender(); + consoleAppender.Layout = + new PatternLayout("%date [%thread] %-5level %logger [%property{NDC}] - %message%newline"); + log4net.Config.BasicConfigurator.Configure(consoleAppender); + } + } +} diff --git a/Tests/OpenSim.Common.Tests/TestsAssetCache.cs b/Tests/OpenSim.Common.Tests/TestsAssetCache.cs new file mode 100644 index 00000000000..63ef41ea548 --- /dev/null +++ b/Tests/OpenSim.Common.Tests/TestsAssetCache.cs @@ -0,0 +1,146 @@ +/* + * 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.Reflection; +using System.Runtime.Caching; +using Nini.Config; +using OpenSim.Framework; +using OpenSim.Region.Framework.Interfaces; +using OpenSim.Region.Framework.Scenes; +using log4net; + +namespace OpenSim.Tests.Common +{ + public class TestsAssetCache : ISharedRegionModule, IAssetCache + { + + private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + + private bool m_Enabled; + public MemoryCache m_Cache; + + public string Name + { + get { return "TestsAssetCache"; } + } + + public Type ReplaceableInterface + { + get { return null; } + } + + public void Initialise(IConfigSource source) + { + m_Cache = MemoryCache.Default; + m_Enabled = true; + } + + public void PostInitialise() + { + } + + public void Close() + { + } + + public void AddRegion(Scene scene) + { + if (m_Enabled) + scene.RegisterModuleInterface(this); + } + + public void RemoveRegion(Scene scene) + { + } + + public void RegionLoaded(Scene scene) + { + } + + //////////////////////////////////////////////////////////// + // IAssetCache + // + public bool Check(string id) + { + // XXX This is probably not an efficient implementation. + AssetBase asset; + if (!Get(id, out asset)) + return false; + return asset != null; + } + + public void Cache(AssetBase asset, bool replace = true) + { + if (asset != null) + { + //CacheItemPolicy policy = new CacheItemPolicy(); + //m_Cache.Set(asset.ID, asset, policy); + } + } + + public void CacheNegative(string id) + { + // We don't do negative caching + } + + public bool Get(string id, out AssetBase asset) + { + //asset = (AssetBase)m_Cache.Get(id); + asset = null; + return true; + } + + public bool GetFromMemory(string id, out AssetBase asset) + { + //asset = (AssetBase)m_Cache.Get(id); + asset = null; + return true; + } + + public AssetBase GetCached(string id) + { + //return (AssetBase)m_Cache.Get(id); + return null; + } + + public void Expire(string id) + { + //m_Cache.Remove(id); + } + + public void Clear() + { + } + /* + public bool UpdateContent(string id, byte[] data) + { + return false; + } + */ + } +} diff --git a/Tests/OpenSim.Common.Tests/VectorToleranceConstraint.cs b/Tests/OpenSim.Common.Tests/VectorToleranceConstraint.cs new file mode 100644 index 00000000000..2fa20edec92 --- /dev/null +++ b/Tests/OpenSim.Common.Tests/VectorToleranceConstraint.cs @@ -0,0 +1,81 @@ +/* + * 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 OpenMetaverse; +using NUnit.Framework; +using NUnit.Framework.Constraints; + +namespace OpenSim.Tests.Common +{ + public class VectorToleranceConstraint : ANumericalToleranceConstraint + { + private Vector3 _baseValue; + private Vector3 _valueToBeTested; + + public VectorToleranceConstraint(Vector3 baseValue, double tolerance) : base(tolerance) + { + _baseValue = baseValue; + } + + /// + ///Test whether the constraint is satisfied by a given value + /// + ///The value to be tested + /// + ///True for success, false for failure + /// + public override bool Matches(object valueToBeTested) + { + if (valueToBeTested == null) + { + throw new ArgumentException("Constraint cannot be used upon null values."); + } + if (valueToBeTested.GetType() != typeof (Vector3)) + { + throw new ArgumentException("Constraint cannot be used upon non vector values."); + } + + _valueToBeTested = (Vector3) valueToBeTested; + + return (IsWithinDoubleConstraint(_valueToBeTested.X, _baseValue.X) && + IsWithinDoubleConstraint(_valueToBeTested.Y, _baseValue.Y) && + IsWithinDoubleConstraint(_valueToBeTested.Z, _baseValue.Z)); + } + + public override void WriteDescriptionTo(MessageWriter writer) + { + writer.WriteExpectedValue( + string.Format("A value {0} within tolerance of plus or minus {1}", _baseValue, _tolerance)); + } + + public override void WriteActualValueTo(MessageWriter writer) + { + writer.WriteActualValue(_valueToBeTested); + } + } +} diff --git a/Tests/OpenSim.Data.Tests/AssetTests.cs b/Tests/OpenSim.Data.Tests/AssetTests.cs new file mode 100644 index 00000000000..cf1ef6ecffb --- /dev/null +++ b/Tests/OpenSim.Data.Tests/AssetTests.cs @@ -0,0 +1,220 @@ +/* + * 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.Collections.Generic; +using NUnit.Framework; +using OpenMetaverse; +using OpenSim.Framework; +using OpenSim.Tests.Common; +using System.Data.Common; + +// DBMS-specific: +using OpenSim.Data.MySQL; + +using System.Data.SQLite; +using OpenSim.Data.SQLite; +using MySqlConnector; + +namespace OpenSim.Data.Tests +{ + [TestFixture(Description = "Asset store tests (SQLite)")] + public class SQLiteAssetTests : AssetTests + { + } + + [TestFixture(Description = "Asset store tests (MySQL)")] + public class MySqlAssetTests : AssetTests + { + } + + public class AssetTests : BasicDataServiceTest + where TConn : DbConnection, new() + where TAssetData : AssetDataBase, new() + { + TAssetData m_db; + + public UUID uuid1 = UUID.Random(); + public UUID uuid2 = UUID.Random(); + public UUID uuid3 = UUID.Random(); + + public string critter1 = UUID.Random().ToString(); + public string critter2 = UUID.Random().ToString(); + public string critter3 = UUID.Random().ToString(); + + public byte[] data1 = new byte[100]; + + PropertyScrambler scrambler = new PropertyScrambler() + .DontScramble(x => x.ID) + .DontScramble(x => x.Type) + .DontScramble(x => x.FullID) + .DontScramble(x => x.Metadata.ID) + .DontScramble(x => x.Metadata.CreatorID) + .DontScramble(x => x.Metadata.ContentType) + .DontScramble(x => x.Metadata.FullID) + .DontScramble(x => x.Data); + + protected override void InitService(object service) + { + ClearDB(); + m_db = (TAssetData)service; + m_db.Initialise(m_connStr); + } + + private void ClearDB() + { + DropTables("assets"); + ResetMigrations("AssetStore"); + } + + + [Test] + public void T001_LoadEmpty() + { + TestHelpers.InMethod(); + + bool[] exist = m_db.AssetsExist(new[] { uuid1, uuid2, uuid3 }); + Assert.IsFalse(exist[0]); + Assert.IsFalse(exist[1]); + Assert.IsFalse(exist[2]); + } + + [Test] + public void T010_StoreReadVerifyAssets() + { + TestHelpers.InMethod(); + + AssetBase a1 = new AssetBase(uuid1, "asset one", (sbyte)AssetType.Texture, critter1.ToString()); + AssetBase a2 = new AssetBase(uuid2, "asset two", (sbyte)AssetType.Texture, critter2.ToString()); + AssetBase a3 = new AssetBase(uuid3, "asset three", (sbyte)AssetType.Texture, critter3.ToString()); + a1.Data = data1; + a2.Data = data1; + a3.Data = data1; + + scrambler.Scramble(a1); + scrambler.Scramble(a2); + scrambler.Scramble(a3); + + m_db.StoreAsset(a1); + m_db.StoreAsset(a2); + m_db.StoreAsset(a3); + a1.UploadAttempts = 0; + a2.UploadAttempts = 0; + a3.UploadAttempts = 0; + + AssetBase a1a = m_db.GetAsset(uuid1); + a1a.UploadAttempts = 0; + Assert.That(a1a, Constraints.PropertyCompareConstraint(a1)); + + AssetBase a2a = m_db.GetAsset(uuid2); + a2a.UploadAttempts = 0; + Assert.That(a2a, Constraints.PropertyCompareConstraint(a2)); + + AssetBase a3a = m_db.GetAsset(uuid3); + a3a.UploadAttempts = 0; + Assert.That(a3a, Constraints.PropertyCompareConstraint(a3)); + + scrambler.Scramble(a1a); + scrambler.Scramble(a2a); + scrambler.Scramble(a3a); + + m_db.StoreAsset(a1a); + m_db.StoreAsset(a2a); + m_db.StoreAsset(a3a); + a1a.UploadAttempts = 0; + a2a.UploadAttempts = 0; + a3a.UploadAttempts = 0; + + AssetBase a1b = m_db.GetAsset(uuid1); + a1b.UploadAttempts = 0; + Assert.That(a1b, Constraints.PropertyCompareConstraint(a1a)); + + AssetBase a2b = m_db.GetAsset(uuid2); + a2b.UploadAttempts = 0; + Assert.That(a2b, Constraints.PropertyCompareConstraint(a2a)); + + AssetBase a3b = m_db.GetAsset(uuid3); + a3b.UploadAttempts = 0; + Assert.That(a3b, Constraints.PropertyCompareConstraint(a3a)); + + bool[] exist = m_db.AssetsExist(new[] { uuid1, uuid2, uuid3 }); + Assert.IsTrue(exist[0]); + Assert.IsTrue(exist[1]); + Assert.IsTrue(exist[2]); + + List metadatas = m_db.FetchAssetMetadataSet(0, 1000); + + Assert.That(metadatas.Count >= 3, "FetchAssetMetadataSet() should have returned at least 3 assets!"); + + // It is possible that the Asset table is filled with data, in which case we don't try to find "our" + // assets there: + if (metadatas.Count < 1000) + { + AssetMetadata metadata = metadatas.Find(x => x.FullID == uuid1); + Assert.That(metadata.Name, Is.EqualTo(a1b.Name)); + Assert.That(metadata.Description, Is.EqualTo(a1b.Description)); + Assert.That(metadata.Type, Is.EqualTo(a1b.Type)); + Assert.That(metadata.Temporary, Is.EqualTo(a1b.Temporary)); + Assert.That(metadata.FullID, Is.EqualTo(a1b.FullID)); + } + } + + [Test] + public void T020_CheckForWeirdCreatorID() + { + TestHelpers.InMethod(); + + // It is expected that eventually the CreatorID might be an arbitrary string (an URI) + // rather than a valid UUID (?). This test is to make sure that the database layer does not + // attempt to convert CreatorID to GUID, but just passes it both ways as a string. + AssetBase a1 = new AssetBase(uuid1, "asset one", (sbyte)AssetType.Texture, critter1); + AssetBase a2 = new AssetBase(uuid2, "asset two", (sbyte)AssetType.Texture, "This is not a GUID!"); + AssetBase a3 = new AssetBase(uuid3, "asset three", (sbyte)AssetType.Texture, ""); + a1.Data = data1; + a2.Data = data1; + a3.Data = data1; + + m_db.StoreAsset(a1); + a1.UploadAttempts = 0; + m_db.StoreAsset(a2); + a2.UploadAttempts = 0; + m_db.StoreAsset(a3); + a3.UploadAttempts = 0; + + AssetBase a1a = m_db.GetAsset(uuid1); + a1a.UploadAttempts = 0; + Assert.That(a1a, Constraints.PropertyCompareConstraint(a1)); + + AssetBase a2a = m_db.GetAsset(uuid2); + a2a.UploadAttempts = 0; + Assert.That(a2a, Constraints.PropertyCompareConstraint(a2)); + + AssetBase a3a = m_db.GetAsset(uuid3); + a3a.UploadAttempts = 0; + Assert.That(a3a, Constraints.PropertyCompareConstraint(a3)); + } + } +} \ No newline at end of file diff --git a/Tests/OpenSim.Data.Tests/BasicDataServiceTest.cs b/Tests/OpenSim.Data.Tests/BasicDataServiceTest.cs new file mode 100644 index 00000000000..264f7bafbec --- /dev/null +++ b/Tests/OpenSim.Data.Tests/BasicDataServiceTest.cs @@ -0,0 +1,271 @@ +/* + * 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.IO; +using System.Collections.Generic; +using log4net.Config; +using NUnit.Framework; +using NUnit.Framework.Constraints; +using OpenMetaverse; +using OpenSim.Framework; +using OpenSim.Tests.Common; +using log4net; +using System.Data; +using System.Data.Common; +using System.Reflection; + +namespace OpenSim.Data.Tests +{ + /// This is a base class for testing any Data service for any DBMS. + /// Requires NUnit 2.5 or better (to support the generics). + /// + /// + /// FIXME: Should extend OpenSimTestCase but compile on mono 2.4.3 currently fails with + /// AssetTests`2 : System.MemberAccessException : Cannot create an instance of OpenSim.Data.Tests.AssetTests`2[TConn,TAssetData] because Type.ContainsGenericParameters is true. + /// and similar on EstateTests, InventoryTests and RegionTests. + /// Runs fine with mono 2.10.8.1, so easiest thing is to wait until min Mono version uplifts. + /// + /// + /// + public class BasicDataServiceTest + where TConn : DbConnection, new() + where TService : class, new() + { + protected string m_connStr; + private TService m_service; + private string m_file; + + // TODO: Is this in the right place here? + // Later: apparently it's not, but does it matter here? +// protected static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + + protected ILog m_log; // doesn't matter here that it's not static, init to correct type in instance .ctor + + public BasicDataServiceTest() + : this("") + { + } + + public BasicDataServiceTest(string conn) + { + m_connStr = !String.IsNullOrEmpty(conn) ? conn : DefaultTestConns.Get(typeof(TConn)); + + m_log = LogManager.GetLogger(this.GetType()); + TestLogging.LogToConsole(); // TODO: Is that right? + } + + /// + /// To be overridden in derived classes. Do whatever init with the m_service, like setting the conn string to it. + /// You'd probably want to to cast the 'service' to a more specific type and store it in a member var. + /// This framework takes care of disposing it, if it's disposable. + /// + /// The service being tested + protected virtual void InitService(object service) + { + } + + [OneTimeSetUp] + public void Init() + { + // Sorry, some SQLite-specific stuff goes here (not a big deal, as its just some file ops) + if (typeof(TConn).Name.StartsWith("Sqlite")) + { + // SQLite doesn't work on power or z linux + if (Directory.Exists("/proc/ppc64") || Directory.Exists("/proc/dasd")) + Assert.Ignore(); + + if (Util.IsWindows()) + Util.LoadArchSpecificWindowsDll("sqlite3.dll"); + + // for SQLite, if no explicit conn string is specified, use a temp file + if (String.IsNullOrEmpty(m_connStr)) + { + m_file = Path.GetTempFileName() + ".db"; + m_connStr = "URI=file:" + m_file + ",version=3"; + } + } + + if (String.IsNullOrEmpty(m_connStr)) + { + string msg = String.Format("Connection string for {0} is not defined, ignoring tests", typeof(TConn).Name); + m_log.Warn(msg); + Assert.Ignore(msg); + } + + // Try the connection, ignore tests if Open() fails + using (TConn conn = new TConn()) + { + conn.ConnectionString = m_connStr; + try + { + conn.Open(); + conn.Close(); + } + catch + { + string msg = String.Format("{0} is unable to connect to the database, ignoring tests", typeof(TConn).Name); + m_log.Warn(msg); + Assert.Ignore(msg); + } + } + + // If we manage to connect to the database with the user + // and password above it is our test database, and run + // these tests. If anything goes wrong, ignore these + // tests. + try + { + m_service = new TService(); + InitService(m_service); + } + catch (Exception e) + { + m_log.Error(e.ToString()); + Assert.Ignore(); + } + } + + [OneTimeTearDown] + public void Cleanup() + { + if (m_service != null) + { + if (m_service is IDisposable) + ((IDisposable)m_service).Dispose(); + m_service = null; + } + + if (!String.IsNullOrEmpty(m_file) && File.Exists(m_file)) + File.Delete(m_file); + } + + protected virtual DbConnection Connect() + { + DbConnection cnn = new TConn(); + cnn.ConnectionString = m_connStr; + cnn.Open(); + return cnn; + } + + protected virtual void ExecuteSql(string sql) + { + using (DbConnection dbcon = Connect()) + { + using (DbCommand cmd = dbcon.CreateCommand()) + { + cmd.CommandText = sql; + cmd.ExecuteNonQuery(); + } + } + } + + protected delegate bool ProcessRow(IDataReader reader); + + protected virtual int ExecQuery(string sql, bool bSingleRow, ProcessRow action) + { + int nRecs = 0; + using (DbConnection dbcon = Connect()) + { + using (DbCommand cmd = dbcon.CreateCommand()) + { + cmd.CommandText = sql; + CommandBehavior cb = bSingleRow ? CommandBehavior.SingleRow : CommandBehavior.Default; + using (DbDataReader rdr = cmd.ExecuteReader(cb)) + { + while (rdr.Read()) + { + nRecs++; + if (!action(rdr)) + break; + } + } + } + } + return nRecs; + } + + /// Drop tables (listed as parameters). There is no "DROP IF EXISTS" syntax common for all + /// databases, so we just DROP and ignore an exception. + /// + /// + protected virtual void DropTables(params string[] tables) + { + foreach (string tbl in tables) + { + try + { + ExecuteSql("DROP TABLE " + tbl + ";"); + }catch + { + } + } + } + + /// Clear tables listed as parameters (without dropping them). + /// + /// + protected virtual void ResetMigrations(params string[] stores) + { + string lst = ""; + foreach (string store in stores) + { + string s = "'" + store + "'"; + if (lst.Length == 0) + lst = s; + else + lst += ", " + s; + } + + string sCond = stores.Length > 1 ? ("in (" + lst + ")") : ("=" + lst); + try + { + ExecuteSql("DELETE FROM migrations where name " + sCond); + } + catch + { + } + } + + /// Clear tables listed as parameters (without dropping them). + /// + /// + protected virtual void ClearTables(params string[] tables) + { + foreach (string tbl in tables) + { + try + { + ExecuteSql("DELETE FROM " + tbl + ";"); + } + catch + { + } + } + } + } +} diff --git a/Tests/OpenSim.Data.Tests/DataTestUtil.cs b/Tests/OpenSim.Data.Tests/DataTestUtil.cs new file mode 100644 index 00000000000..5393529592d --- /dev/null +++ b/Tests/OpenSim.Data.Tests/DataTestUtil.cs @@ -0,0 +1,88 @@ +/* + * 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 System.Text; +using OpenMetaverse; +using NUnit.Framework; + +namespace OpenSim.Data.Tests +{ + /// + /// Shared constants and methods for database unit tests. + /// + public class DataTestUtil + { + public const uint UNSIGNED_INTEGER_MIN = uint.MinValue; + //public const uint UNSIGNED_INTEGER_MAX = uint.MaxValue; + public const uint UNSIGNED_INTEGER_MAX = INTEGER_MAX; + + public const int INTEGER_MIN = int.MinValue + 1; // Postgresql requires +1 to .NET int.MinValue + public const int INTEGER_MAX = int.MaxValue; + + public const float FLOAT_MIN = float.MinValue * (1 - FLOAT_PRECISSION); + public const float FLOAT_MAX = float.MaxValue * (1 - FLOAT_PRECISSION); + public const float FLOAT_ACCURATE = 1.234567890123456789012f; + public const float FLOAT_PRECISSION = 1E-5f; // Native MySQL is severly limited with floating accuracy + + public const double DOUBLE_MIN = -1E52 * (1 - DOUBLE_PRECISSION); + public const double DOUBLE_MAX = 1E52 * (1 - DOUBLE_PRECISSION); + public const double DOUBLE_ACCURATE = 1.2345678901234567890123456789012345678901234567890123f; + public const double DOUBLE_PRECISSION = 1E-14; // Native MySQL is severly limited with double accuracy + + public const string STRING_MIN = ""; + public static string STRING_MAX(int length) + { + StringBuilder stringBuilder = new StringBuilder(); + for (int i = 0; i < length; i++) + { + stringBuilder.Append(i % 10); + } + return stringBuilder.ToString(); + } + + public static UUID UUID_MIN = new UUID("00000000-0000-0000-0000-000000000000"); + public static UUID UUID_MAX = new UUID("ffffffff-ffff-ffff-ffff-ffffffffffff"); + + public const bool BOOLEAN_MIN = false; + public const bool BOOLEAN_MAX = true; + + public static void AssertFloatEqualsWithTolerance(float expectedValue, float actualValue) + { + Assert.GreaterOrEqual(actualValue, expectedValue - Math.Abs(expectedValue) * FLOAT_PRECISSION); + Assert.LessOrEqual(actualValue, expectedValue + Math.Abs(expectedValue) * FLOAT_PRECISSION); + } + + public static void AssertDoubleEqualsWithTolerance(double expectedValue, double actualValue) + { + Assert.GreaterOrEqual(actualValue, expectedValue - Math.Abs(expectedValue) * DOUBLE_PRECISSION); + Assert.LessOrEqual(actualValue, expectedValue + Math.Abs(expectedValue) * DOUBLE_PRECISSION); + } + } +} + diff --git a/Tests/OpenSim.Data.Tests/DefaultTestConns.cs b/Tests/OpenSim.Data.Tests/DefaultTestConns.cs new file mode 100644 index 00000000000..87b346e33f9 --- /dev/null +++ b/Tests/OpenSim.Data.Tests/DefaultTestConns.cs @@ -0,0 +1,90 @@ +/* + * 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 System.Linq; +using System.Text; +using System.Reflection; +using System.IO; +using Nini.Config; + +namespace OpenSim.Data.Tests +{ + /// This static class looks for TestDataConnections.ini file in the /bin directory to obtain + /// a connection string for testing one of the supported databases. + /// The connections must be in the section [TestConnections] with names matching the connection class + /// name for the specific database, e.g.: + /// + /// [TestConnections] + /// MySqlConnection="..." + /// SqlConnection="..." + /// SQLiteConnection="..." + /// + /// Note that the conn string may also be set explicitly in the [TestCase()] attribute of test classes + /// based on BasicDataServiceTest.cs. + /// + + static class DefaultTestConns + { + private static Dictionary conns = new Dictionary(); + + public static string Get(Type connType) + { + string sConn; + + if (conns.TryGetValue(connType, out sConn)) + return sConn; + + Assembly asm = Assembly.GetExecutingAssembly(); + string sType = connType.Name; + + // Note: when running from NUnit, the DLL is located in some temp dir, so how do we get + // to the INI file? Ok, so put it into the resources! + // string iniName = Path.Combine(Path.GetDirectoryName(asm.Location), "TestDataConnections.ini"); + + string[] allres = asm.GetManifestResourceNames(); + string sResFile = Array.Find(allres, s => s.Contains("TestDataConnections.ini")); + + if (String.IsNullOrEmpty(sResFile)) + throw new Exception(String.Format("Please add resource TestDataConnections.ini, with section [TestConnections] and settings like {0}=\"...\"", + sType)); + + using (Stream resource = asm.GetManifestResourceStream(sResFile)) + { + IConfigSource source = new IniConfigSource(resource); + var cfg = source.Configs["TestConnections"]; + sConn = cfg.Get(sType, ""); + } + + if (!String.IsNullOrEmpty(sConn)) + conns[connType] = sConn; + + return sConn; + } + } +} diff --git a/Tests/OpenSim.Data.Tests/EstateTests.cs b/Tests/OpenSim.Data.Tests/EstateTests.cs new file mode 100644 index 00000000000..4bfdc64f1da --- /dev/null +++ b/Tests/OpenSim.Data.Tests/EstateTests.cs @@ -0,0 +1,511 @@ +/* + * 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 NUnit.Framework; +using OpenMetaverse; +using OpenSim.Framework; +using OpenSim.Tests.Common; +using System.Data.Common; + +// DBMS-specific: +using OpenSim.Data.MySQL; + +using System.Data.SQLite; +using OpenSim.Data.SQLite; +using MySqlConnector; + +namespace OpenSim.Data.Tests +{ + [TestFixture(Description = "Estate store tests (SQLite)")] + public class SQLiteEstateTests : EstateTests + { + } + + [TestFixture(Description = "Estate store tests (MySQL)")] + public class MySqlEstateTests : EstateTests + { + } + + public class EstateTests : BasicDataServiceTest + where TConn : DbConnection, new() + where TEstateStore : class, IEstateDataStore, new() + { + public IEstateDataStore db; + + public static UUID REGION_ID = new UUID("250d214e-1c7e-4f9b-a488-87c5e53feed7"); + + public static UUID USER_ID_1 = new UUID("250d214e-1c7e-4f9b-a488-87c5e53feed1"); + public static UUID USER_ID_2 = new UUID("250d214e-1c7e-4f9b-a488-87c5e53feed2"); + + public static UUID MANAGER_ID_1 = new UUID("250d214e-1c7e-4f9b-a488-87c5e53feed3"); + public static UUID MANAGER_ID_2 = new UUID("250d214e-1c7e-4f9b-a488-87c5e53feed4"); + + public static UUID GROUP_ID_1 = new UUID("250d214e-1c7e-4f9b-a488-87c5e53feed5"); + public static UUID GROUP_ID_2 = new UUID("250d214e-1c7e-4f9b-a488-87c5e53feed6"); + + protected override void InitService(object service) + { + ClearDB(); + db = (IEstateDataStore)service; + db.Initialise(m_connStr); + } + + private void ClearDB() + { + // if a new table is added, it has to be dropped here + DropTables( + "estate_managers", + "estate_groups", + "estate_users", + "estateban", + "estate_settings", + "estate_map" + ); + ResetMigrations("EstateStore"); + } + + #region 0Tests + + [Test] + public void T010_EstateSettingsSimpleStorage_MinimumParameterSet() + { + TestHelpers.InMethod(); + + EstateSettingsSimpleStorage( + REGION_ID, + DataTestUtil.STRING_MIN, + DataTestUtil.UNSIGNED_INTEGER_MIN, + DataTestUtil.FLOAT_MIN, + DataTestUtil.INTEGER_MIN, + DataTestUtil.INTEGER_MIN, + DataTestUtil.INTEGER_MIN, + DataTestUtil.BOOLEAN_MIN, + DataTestUtil.BOOLEAN_MIN, + DataTestUtil.DOUBLE_MIN, + DataTestUtil.BOOLEAN_MIN, + DataTestUtil.BOOLEAN_MIN, + DataTestUtil.BOOLEAN_MIN, + DataTestUtil.BOOLEAN_MIN, + DataTestUtil.BOOLEAN_MIN, + DataTestUtil.BOOLEAN_MIN, + DataTestUtil.BOOLEAN_MIN, + DataTestUtil.BOOLEAN_MIN, + DataTestUtil.BOOLEAN_MIN, + DataTestUtil.BOOLEAN_MIN, + DataTestUtil.BOOLEAN_MIN, + DataTestUtil.BOOLEAN_MIN, + DataTestUtil.STRING_MIN, + DataTestUtil.UUID_MIN + ); + } + + [Test] + public void T011_EstateSettingsSimpleStorage_MaximumParameterSet() + { + TestHelpers.InMethod(); + + EstateSettingsSimpleStorage( + REGION_ID, + DataTestUtil.STRING_MAX(64), + DataTestUtil.UNSIGNED_INTEGER_MAX, + DataTestUtil.FLOAT_MAX, + DataTestUtil.INTEGER_MAX, + DataTestUtil.INTEGER_MAX, + DataTestUtil.INTEGER_MAX, + DataTestUtil.BOOLEAN_MAX, + DataTestUtil.BOOLEAN_MAX, + DataTestUtil.DOUBLE_MAX, + DataTestUtil.BOOLEAN_MAX, + DataTestUtil.BOOLEAN_MAX, + DataTestUtil.BOOLEAN_MAX, + DataTestUtil.BOOLEAN_MAX, + DataTestUtil.BOOLEAN_MAX, + DataTestUtil.BOOLEAN_MAX, + DataTestUtil.BOOLEAN_MAX, + DataTestUtil.BOOLEAN_MAX, + DataTestUtil.BOOLEAN_MAX, + DataTestUtil.BOOLEAN_MAX, + DataTestUtil.BOOLEAN_MAX, + DataTestUtil.BOOLEAN_MAX, + DataTestUtil.STRING_MAX(255), + DataTestUtil.UUID_MAX + ); + } + + [Test] + public void T012_EstateSettingsSimpleStorage_AccurateParameterSet() + { + TestHelpers.InMethod(); + + EstateSettingsSimpleStorage( + REGION_ID, + DataTestUtil.STRING_MAX(1), + DataTestUtil.UNSIGNED_INTEGER_MIN, + DataTestUtil.FLOAT_ACCURATE, + DataTestUtil.INTEGER_MIN, + DataTestUtil.INTEGER_MIN, + DataTestUtil.INTEGER_MIN, + DataTestUtil.BOOLEAN_MIN, + DataTestUtil.BOOLEAN_MIN, + DataTestUtil.DOUBLE_ACCURATE, + DataTestUtil.BOOLEAN_MIN, + DataTestUtil.BOOLEAN_MIN, + DataTestUtil.BOOLEAN_MIN, + DataTestUtil.BOOLEAN_MIN, + DataTestUtil.BOOLEAN_MIN, + DataTestUtil.BOOLEAN_MIN, + DataTestUtil.BOOLEAN_MIN, + DataTestUtil.BOOLEAN_MIN, + DataTestUtil.BOOLEAN_MIN, + DataTestUtil.BOOLEAN_MIN, + DataTestUtil.BOOLEAN_MIN, + DataTestUtil.BOOLEAN_MIN, + DataTestUtil.STRING_MAX(1), + DataTestUtil.UUID_MIN + ); + } + + [Test] + public void T012_EstateSettingsRandomStorage() + { + TestHelpers.InMethod(); + + // Letting estate store generate rows to database for us + EstateSettings originalSettings = db.LoadEstateSettings(REGION_ID, true); + new PropertyScrambler() + .DontScramble(x=>x.EstateID) + .Scramble(originalSettings); + + // Saving settings. + db.StoreEstateSettings(originalSettings); + + // Loading settings to another instance variable. + EstateSettings loadedSettings = db.LoadEstateSettings(REGION_ID, true); + + // Checking that loaded values are correct. + Assert.That(loadedSettings, Constraints.PropertyCompareConstraint(originalSettings)); + } + + [Test] + public void T020_EstateSettingsManagerList() + { + TestHelpers.InMethod(); + + // Letting estate store generate rows to database for us + EstateSettings originalSettings = db.LoadEstateSettings(REGION_ID, true); + + originalSettings.EstateManagers = new UUID[] { MANAGER_ID_1, MANAGER_ID_2 }; + + // Saving settings. + db.StoreEstateSettings(originalSettings); + + // Loading settings to another instance variable. + EstateSettings loadedSettings = db.LoadEstateSettings(REGION_ID, true); + + Assert.AreEqual(2, loadedSettings.EstateManagers.Length); + Assert.AreEqual(MANAGER_ID_1, loadedSettings.EstateManagers[0]); + Assert.AreEqual(MANAGER_ID_2, loadedSettings.EstateManagers[1]); + } + + [Test] + public void T021_EstateSettingsUserList() + { + TestHelpers.InMethod(); + + // Letting estate store generate rows to database for us + EstateSettings originalSettings = db.LoadEstateSettings(REGION_ID, true); + + originalSettings.EstateAccess = new UUID[] { USER_ID_1, USER_ID_2 }; + + // Saving settings. + db.StoreEstateSettings(originalSettings); + + // Loading settings to another instance variable. + EstateSettings loadedSettings = db.LoadEstateSettings(REGION_ID, true); + + Assert.AreEqual(2, loadedSettings.EstateAccess.Length); + Assert.AreEqual(USER_ID_1, loadedSettings.EstateAccess[0]); + Assert.AreEqual(USER_ID_2, loadedSettings.EstateAccess[1]); + } + + [Test] + public void T022_EstateSettingsGroupList() + { + TestHelpers.InMethod(); + + // Letting estate store generate rows to database for us + EstateSettings originalSettings = db.LoadEstateSettings(REGION_ID, true); + + originalSettings.EstateGroups = new UUID[] { GROUP_ID_1, GROUP_ID_2 }; + + // Saving settings. + db.StoreEstateSettings(originalSettings); + + // Loading settings to another instance variable. + EstateSettings loadedSettings = db.LoadEstateSettings(REGION_ID, true); + + Assert.AreEqual(2, loadedSettings.EstateAccess.Length); + Assert.AreEqual(GROUP_ID_1, loadedSettings.EstateGroups[0]); + Assert.AreEqual(GROUP_ID_2, loadedSettings.EstateGroups[1]); + } + + [Test] + public void T022_EstateSettingsBanList() + { + TestHelpers.InMethod(); + + // Letting estate store generate rows to database for us + EstateSettings originalSettings = db.LoadEstateSettings(REGION_ID, true); + + EstateBan estateBan1 = new EstateBan(); + estateBan1.BannedUserID = DataTestUtil.UUID_MIN; + + EstateBan estateBan2 = new EstateBan(); + estateBan2.BannedUserID = DataTestUtil.UUID_MAX; + + originalSettings.EstateBans = new EstateBan[] { estateBan1, estateBan2 }; + + // Saving settings. + db.StoreEstateSettings(originalSettings); + + // Loading settings to another instance variable. + EstateSettings loadedSettings = db.LoadEstateSettings(REGION_ID, true); + + Assert.AreEqual(2, loadedSettings.EstateBans.Length); + Assert.AreEqual(DataTestUtil.UUID_MIN, loadedSettings.EstateBans[0].BannedUserID); + + Assert.AreEqual(DataTestUtil.UUID_MAX, loadedSettings.EstateBans[1].BannedUserID); + + } + + #endregion + + #region Parametrizable Test Implementations + + private void EstateSettingsSimpleStorage( + UUID regionId, + string estateName, + uint parentEstateID, + float billableFactor, + int pricePerMeter, + int redirectGridX, + int redirectGridY, + bool useGlobalTime, + bool fixedSun, + double sunPosition, + bool allowVoice, + bool allowDirectTeleport, + bool resetHomeOnTeleport, + bool denyAnonymous, + bool denyIdentified, + bool denyTransacted, + bool denyMinors, + bool abuseEmailToEstateOwner, + bool blockDwell, + bool estateSkipScripts, + bool taxFree, + bool publicAccess, + string abuseEmail, + UUID estateOwner + ) + { + + // Letting estate store generate rows to database for us + EstateSettings originalSettings = db.LoadEstateSettings(regionId, true); + + SetEstateSettings(originalSettings, + estateName, + parentEstateID, + billableFactor, + pricePerMeter, + redirectGridX, + redirectGridY, + useGlobalTime, + fixedSun, + sunPosition, + allowVoice, + allowDirectTeleport, + resetHomeOnTeleport, + denyAnonymous, + denyIdentified, + denyTransacted, + denyMinors, + abuseEmailToEstateOwner, + blockDwell, + estateSkipScripts, + taxFree, + publicAccess, + abuseEmail, + estateOwner + ); + + // Saving settings. + db.StoreEstateSettings(originalSettings); + + // Loading settings to another instance variable. + EstateSettings loadedSettings = db.LoadEstateSettings(regionId, true); + + // Checking that loaded values are correct. + ValidateEstateSettings(loadedSettings, + estateName, + parentEstateID, + billableFactor, + pricePerMeter, + redirectGridX, + redirectGridY, + useGlobalTime, + fixedSun, + sunPosition, + allowVoice, + allowDirectTeleport, + resetHomeOnTeleport, + denyAnonymous, + denyIdentified, + denyTransacted, + denyMinors, + abuseEmailToEstateOwner, + blockDwell, + estateSkipScripts, + taxFree, + publicAccess, + abuseEmail, + estateOwner + ); + + } + + #endregion + + #region EstateSetting Initialization and Validation Methods + + private void SetEstateSettings( + EstateSettings estateSettings, + string estateName, + uint parentEstateID, + float billableFactor, + int pricePerMeter, + int redirectGridX, + int redirectGridY, + bool useGlobalTime, + bool fixedSun, + double sunPosition, + bool allowVoice, + bool allowDirectTeleport, + bool resetHomeOnTeleport, + bool denyAnonymous, + bool denyIdentified, + bool denyTransacted, + bool denyMinors, + bool abuseEmailToEstateOwner, + bool blockDwell, + bool estateSkipScripts, + bool taxFree, + bool publicAccess, + string abuseEmail, + UUID estateOwner + ) + { + estateSettings.EstateName = estateName; + estateSettings.ParentEstateID = parentEstateID; + estateSettings.BillableFactor = billableFactor; + estateSettings.PricePerMeter = pricePerMeter; + estateSettings.RedirectGridX = redirectGridX; + estateSettings.RedirectGridY = redirectGridY; + estateSettings.UseGlobalTime = useGlobalTime; + estateSettings.FixedSun = fixedSun; + estateSettings.SunPosition = sunPosition; + estateSettings.AllowVoice = allowVoice; + estateSettings.AllowDirectTeleport = allowDirectTeleport; + estateSettings.ResetHomeOnTeleport = resetHomeOnTeleport; + estateSettings.DenyAnonymous = denyAnonymous; + estateSettings.DenyIdentified = denyIdentified; + estateSettings.DenyTransacted = denyTransacted; + estateSettings.DenyMinors = denyMinors; + estateSettings.AbuseEmailToEstateOwner = abuseEmailToEstateOwner; + estateSettings.BlockDwell = blockDwell; + estateSettings.EstateSkipScripts = estateSkipScripts; + estateSettings.TaxFree = taxFree; + estateSettings.PublicAccess = publicAccess; + estateSettings.AbuseEmail = abuseEmail; + estateSettings.EstateOwner = estateOwner; + } + + private void ValidateEstateSettings( + EstateSettings estateSettings, + string estateName, + uint parentEstateID, + float billableFactor, + int pricePerMeter, + int redirectGridX, + int redirectGridY, + bool useGlobalTime, + bool fixedSun, + double sunPosition, + bool allowVoice, + bool allowDirectTeleport, + bool resetHomeOnTeleport, + bool denyAnonymous, + bool denyIdentified, + bool denyTransacted, + bool denyMinors, + bool abuseEmailToEstateOwner, + bool blockDwell, + bool estateSkipScripts, + bool taxFree, + bool publicAccess, + string abuseEmail, + UUID estateOwner + ) + { + Assert.AreEqual(estateName, estateSettings.EstateName); + Assert.AreEqual(parentEstateID, estateSettings.ParentEstateID); + + DataTestUtil.AssertFloatEqualsWithTolerance(billableFactor, estateSettings.BillableFactor); + + Assert.AreEqual(pricePerMeter, estateSettings.PricePerMeter); + Assert.AreEqual(redirectGridX, estateSettings.RedirectGridX); + Assert.AreEqual(redirectGridY, estateSettings.RedirectGridY); + + Assert.AreEqual(allowVoice, estateSettings.AllowVoice); + Assert.AreEqual(allowDirectTeleport, estateSettings.AllowDirectTeleport); + Assert.AreEqual(resetHomeOnTeleport, estateSettings.ResetHomeOnTeleport); + Assert.AreEqual(denyAnonymous, estateSettings.DenyAnonymous); + Assert.AreEqual(denyIdentified, estateSettings.DenyIdentified); + Assert.AreEqual(denyTransacted, estateSettings.DenyTransacted); + Assert.AreEqual(denyMinors, estateSettings.DenyMinors); + Assert.AreEqual(abuseEmailToEstateOwner, estateSettings.AbuseEmailToEstateOwner); + Assert.AreEqual(blockDwell, estateSettings.BlockDwell); + Assert.AreEqual(estateSkipScripts, estateSettings.EstateSkipScripts); + Assert.AreEqual(taxFree, estateSettings.TaxFree); + Assert.AreEqual(publicAccess, estateSettings.PublicAccess); + Assert.AreEqual(abuseEmail, estateSettings.AbuseEmail); + Assert.AreEqual(estateOwner, estateSettings.EstateOwner); + } + + #endregion + } +} \ No newline at end of file diff --git a/Tests/OpenSim.Data.Tests/InventoryTests.cs b/Tests/OpenSim.Data.Tests/InventoryTests.cs new file mode 100644 index 00000000000..dc99bf1a5a3 --- /dev/null +++ b/Tests/OpenSim.Data.Tests/InventoryTests.cs @@ -0,0 +1,369 @@ +/* + * 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 NUnit.Framework; +using OpenMetaverse; +using OpenSim.Framework; +using OpenSim.Tests.Common; +using System.Data.Common; + +// DBMS-specific: +using OpenSim.Data.MySQL; +using MySqlConnector; + +namespace OpenSim.Data.Tests +{ + [TestFixture(Description = "Inventory store tests (MySQL)")] + public class MySqlInventoryTests : InventoryTests + { + } + + public class InventoryTests : BasicDataServiceTest + where TConn : DbConnection, new() + where TInvStore : class, IInventoryDataPlugin, new() + { + public IInventoryDataPlugin db; + + public UUID zero = UUID.Zero; + + public UUID folder1 = UUID.Random(); + public UUID folder2 = UUID.Random(); + public UUID folder3 = UUID.Random(); + public UUID owner1 = UUID.Random(); + public UUID owner2 = UUID.Random(); + public UUID owner3 = UUID.Random(); + + public UUID item1 = UUID.Random(); + public UUID item2 = UUID.Random(); + public UUID item3 = UUID.Random(); + public UUID asset1 = UUID.Random(); + public UUID asset2 = UUID.Random(); + public UUID asset3 = UUID.Random(); + + public string name1; + public string name2 = "First Level folder"; + public string name3 = "First Level folder 2"; + public string niname1 = "My Shirt"; + public string iname1 = "Shirt"; + public string iname2 = "Text Board"; + public string iname3 = "No Pants Barrel"; + + public InventoryTests(string conn) : base(conn) + { + name1 = "Root Folder for " + owner1.ToString(); + } + public InventoryTests() : this("") { } + + protected override void InitService(object service) + { + ClearDB(); + db = (IInventoryDataPlugin)service; + db.Initialise(m_connStr); + } + + private void ClearDB() + { + DropTables("inventoryitems", "inventoryfolders"); + ResetMigrations("InventoryStore"); + } + + [Test] + public void T001_LoadEmpty() + { + TestHelpers.InMethod(); + + Assert.That(db.getInventoryFolder(zero), Is.Null); + Assert.That(db.getInventoryFolder(folder1), Is.Null); + Assert.That(db.getInventoryFolder(folder2), Is.Null); + Assert.That(db.getInventoryFolder(folder3), Is.Null); + + Assert.That(db.getInventoryItem(zero), Is.Null); + Assert.That(db.getInventoryItem(item1), Is.Null); + Assert.That(db.getInventoryItem(item2), Is.Null); + Assert.That(db.getInventoryItem(item3), Is.Null); + + Assert.That(db.getUserRootFolder(zero), Is.Null); + Assert.That(db.getUserRootFolder(owner1), Is.Null); + } + + // 01x - folder tests + [Test] + public void T010_FolderNonParent() + { + TestHelpers.InMethod(); + + InventoryFolderBase f1 = NewFolder(folder2, folder1, owner1, name2); + // the folder will go in + db.addInventoryFolder(f1); + InventoryFolderBase f1a = db.getUserRootFolder(owner1); + Assert.That(f1a, Is.Null); + } + + [Test] + public void T011_FolderCreate() + { + TestHelpers.InMethod(); + + InventoryFolderBase f1 = NewFolder(folder1, zero, owner1, name1); + // TODO: this is probably wrong behavior, but is what we have + // db.updateInventoryFolder(f1); + // InventoryFolderBase f1a = db.getUserRootFolder(owner1); + // Assert.That(uuid1, Is.EqualTo(f1a.ID)) + // Assert.That(name1, Text.Matches(f1a.Name), "Assert.That(name1, Text.Matches(f1a.Name))"); + // Assert.That(db.getUserRootFolder(owner1), Is.Null); + + // succeed with true + db.addInventoryFolder(f1); + InventoryFolderBase f1a = db.getUserRootFolder(owner1); + Assert.That(folder1, Is.EqualTo(f1a.ID), "Assert.That(folder1, Is.EqualTo(f1a.ID))"); + Assert.That(name1, Does.Match(f1a.Name), "Assert.That(name1, Text.Matches(f1a.Name))"); + } + + // we now have the following tree + // folder1 + // +--- folder2 + // +--- folder3 + + [Test] + public void T012_FolderList() + { + TestHelpers.InMethod(); + + InventoryFolderBase f2 = NewFolder(folder3, folder1, owner1, name3); + db.addInventoryFolder(f2); + + Assert.That(db.getInventoryFolders(zero).Count, Is.EqualTo(1), "Assert.That(db.getInventoryFolders(zero).Count, Is.EqualTo(1))"); + Assert.That(db.getInventoryFolders(folder1).Count, Is.EqualTo(2), "Assert.That(db.getInventoryFolders(folder1).Count, Is.EqualTo(2))"); + Assert.That(db.getInventoryFolders(folder2).Count, Is.EqualTo(0), "Assert.That(db.getInventoryFolders(folder2).Count, Is.EqualTo(0))"); + Assert.That(db.getInventoryFolders(folder3).Count, Is.EqualTo(0), "Assert.That(db.getInventoryFolders(folder3).Count, Is.EqualTo(0))"); + Assert.That(db.getInventoryFolders(UUID.Random()).Count, Is.EqualTo(0), "Assert.That(db.getInventoryFolders(UUID.Random()).Count, Is.EqualTo(0))"); + + } + + [Test] + public void T013_FolderHierarchy() + { + TestHelpers.InMethod(); + + int n = db.getFolderHierarchy(zero).Count; // (for dbg - easier to see what's returned) + Assert.That(n, Is.EqualTo(0), "Assert.That(db.getFolderHierarchy(zero).Count, Is.EqualTo(0))"); + n = db.getFolderHierarchy(folder1).Count; + Assert.That(n, Is.EqualTo(2), "Assert.That(db.getFolderHierarchy(folder1).Count, Is.EqualTo(2))"); + Assert.That(db.getFolderHierarchy(folder2).Count, Is.EqualTo(0), "Assert.That(db.getFolderHierarchy(folder2).Count, Is.EqualTo(0))"); + Assert.That(db.getFolderHierarchy(folder3).Count, Is.EqualTo(0), "Assert.That(db.getFolderHierarchy(folder3).Count, Is.EqualTo(0))"); + Assert.That(db.getFolderHierarchy(UUID.Random()).Count, Is.EqualTo(0), "Assert.That(db.getFolderHierarchy(UUID.Random()).Count, Is.EqualTo(0))"); + } + + + [Test] + public void T014_MoveFolder() + { + TestHelpers.InMethod(); + + InventoryFolderBase f2 = db.getInventoryFolder(folder2); + f2.ParentID = folder3; + db.moveInventoryFolder(f2); + + Assert.That(db.getInventoryFolders(zero).Count, Is.EqualTo(1), "Assert.That(db.getInventoryFolders(zero).Count, Is.EqualTo(1))"); + Assert.That(db.getInventoryFolders(folder1).Count, Is.EqualTo(1), "Assert.That(db.getInventoryFolders(folder1).Count, Is.EqualTo(1))"); + Assert.That(db.getInventoryFolders(folder2).Count, Is.EqualTo(0), "Assert.That(db.getInventoryFolders(folder2).Count, Is.EqualTo(0))"); + Assert.That(db.getInventoryFolders(folder3).Count, Is.EqualTo(1), "Assert.That(db.getInventoryFolders(folder3).Count, Is.EqualTo(1))"); + Assert.That(db.getInventoryFolders(UUID.Random()).Count, Is.EqualTo(0), "Assert.That(db.getInventoryFolders(UUID.Random()).Count, Is.EqualTo(0))"); + } + + [Test] + public void T015_FolderHierarchy() + { + TestHelpers.InMethod(); + + Assert.That(db.getFolderHierarchy(zero).Count, Is.EqualTo(0), "Assert.That(db.getFolderHierarchy(zero).Count, Is.EqualTo(0))"); + Assert.That(db.getFolderHierarchy(folder1).Count, Is.EqualTo(2), "Assert.That(db.getFolderHierarchy(folder1).Count, Is.EqualTo(2))"); + Assert.That(db.getFolderHierarchy(folder2).Count, Is.EqualTo(0), "Assert.That(db.getFolderHierarchy(folder2).Count, Is.EqualTo(0))"); + Assert.That(db.getFolderHierarchy(folder3).Count, Is.EqualTo(1), "Assert.That(db.getFolderHierarchy(folder3).Count, Is.EqualTo(1))"); + Assert.That(db.getFolderHierarchy(UUID.Random()).Count, Is.EqualTo(0), "Assert.That(db.getFolderHierarchy(UUID.Random()).Count, Is.EqualTo(0))"); + } + + // Item tests + [Test] + public void T100_NoItems() + { + TestHelpers.InMethod(); + + Assert.That(db.getInventoryInFolder(zero).Count, Is.EqualTo(0), "Assert.That(db.getInventoryInFolder(zero).Count, Is.EqualTo(0))"); + Assert.That(db.getInventoryInFolder(folder1).Count, Is.EqualTo(0), "Assert.That(db.getInventoryInFolder(folder1).Count, Is.EqualTo(0))"); + Assert.That(db.getInventoryInFolder(folder2).Count, Is.EqualTo(0), "Assert.That(db.getInventoryInFolder(folder2).Count, Is.EqualTo(0))"); + Assert.That(db.getInventoryInFolder(folder3).Count, Is.EqualTo(0), "Assert.That(db.getInventoryInFolder(folder3).Count, Is.EqualTo(0))"); + } + + // TODO: Feeding a bad inventory item down the data path will + // crash the system. This is largely due to the builder + // routines. That should be fixed and tested for. + [Test] + public void T101_CreatItems() + { + TestHelpers.InMethod(); + + db.addInventoryItem(NewItem(item1, folder3, owner1, iname1, asset1)); + db.addInventoryItem(NewItem(item2, folder3, owner1, iname2, asset2)); + db.addInventoryItem(NewItem(item3, folder3, owner1, iname3, asset3)); + Assert.That(db.getInventoryInFolder(folder3).Count, Is.EqualTo(3), "Assert.That(db.getInventoryInFolder(folder3).Count, Is.EqualTo(3))"); + } + + [Test] + public void T102_CompareItems() + { + TestHelpers.InMethod(); + + InventoryItemBase i1 = db.getInventoryItem(item1); + InventoryItemBase i2 = db.getInventoryItem(item2); + InventoryItemBase i3 = db.getInventoryItem(item3); + Assert.That(i1.Name, Is.EqualTo(iname1), "Assert.That(i1.Name, Is.EqualTo(iname1))"); + Assert.That(i2.Name, Is.EqualTo(iname2), "Assert.That(i2.Name, Is.EqualTo(iname2))"); + Assert.That(i3.Name, Is.EqualTo(iname3), "Assert.That(i3.Name, Is.EqualTo(iname3))"); + Assert.That(i1.Owner, Is.EqualTo(owner1), "Assert.That(i1.Owner, Is.EqualTo(owner1))"); + Assert.That(i2.Owner, Is.EqualTo(owner1), "Assert.That(i2.Owner, Is.EqualTo(owner1))"); + Assert.That(i3.Owner, Is.EqualTo(owner1), "Assert.That(i3.Owner, Is.EqualTo(owner1))"); + Assert.That(i1.AssetID, Is.EqualTo(asset1), "Assert.That(i1.AssetID, Is.EqualTo(asset1))"); + Assert.That(i2.AssetID, Is.EqualTo(asset2), "Assert.That(i2.AssetID, Is.EqualTo(asset2))"); + Assert.That(i3.AssetID, Is.EqualTo(asset3), "Assert.That(i3.AssetID, Is.EqualTo(asset3))"); + } + + [Test] + public void T103_UpdateItem() + { + TestHelpers.InMethod(); + + // TODO: probably shouldn't have the ability to have an + // owner of an item in a folder not owned by the user + + InventoryItemBase i1 = db.getInventoryItem(item1); + i1.Name = niname1; + i1.Description = niname1; + i1.Owner = owner2; + db.updateInventoryItem(i1); + + i1 = db.getInventoryItem(item1); + Assert.That(i1.Name, Is.EqualTo(niname1), "Assert.That(i1.Name, Is.EqualTo(niname1))"); + Assert.That(i1.Description, Is.EqualTo(niname1), "Assert.That(i1.Description, Is.EqualTo(niname1))"); + Assert.That(i1.Owner, Is.EqualTo(owner2), "Assert.That(i1.Owner, Is.EqualTo(owner2))"); + } + + [Test] + public void T104_RandomUpdateItem() + { + TestHelpers.InMethod(); + + PropertyScrambler folderScrambler = + new PropertyScrambler() + .DontScramble(x => x.Owner) + .DontScramble(x => x.ParentID) + .DontScramble(x => x.ID); + UUID owner = UUID.Random(); + UUID folder = UUID.Random(); + UUID rootId = UUID.Random(); + UUID rootAsset = UUID.Random(); + InventoryFolderBase f1 = NewFolder(folder, zero, owner, name1); + folderScrambler.Scramble(f1); + + db.addInventoryFolder(f1); + InventoryFolderBase f1a = db.getUserRootFolder(owner); + Assert.That(f1a, Constraints.PropertyCompareConstraint(f1)); + + folderScrambler.Scramble(f1a); + + db.updateInventoryFolder(f1a); + + InventoryFolderBase f1b = db.getUserRootFolder(owner); + Assert.That(f1b, Constraints.PropertyCompareConstraint(f1a)); + + //Now we have a valid folder to insert into, we can insert the item. + PropertyScrambler inventoryScrambler = + new PropertyScrambler() + .DontScramble(x => x.ID) + .DontScramble(x => x.AssetID) + .DontScramble(x => x.Owner) + .DontScramble(x => x.Folder); + InventoryItemBase root = NewItem(rootId, folder, owner, iname1, rootAsset); + inventoryScrambler.Scramble(root); + db.addInventoryItem(root); + + InventoryItemBase expected = db.getInventoryItem(rootId); + Assert.That(expected, Constraints.PropertyCompareConstraint(root) + .IgnoreProperty(x => x.InvType) + .IgnoreProperty(x => x.CreatorIdAsUuid) + .IgnoreProperty(x => x.Description) + .IgnoreProperty(x => x.CreatorIdentification) + .IgnoreProperty(x => x.CreatorData)); + + inventoryScrambler.Scramble(expected); + db.updateInventoryItem(expected); + + InventoryItemBase actual = db.getInventoryItem(rootId); + Assert.That(actual, Constraints.PropertyCompareConstraint(expected) + .IgnoreProperty(x => x.InvType) + .IgnoreProperty(x => x.CreatorIdAsUuid) + .IgnoreProperty(x => x.Description) + .IgnoreProperty(x => x.CreatorIdentification) + .IgnoreProperty(x => x.CreatorData)); + } + + [Test] + public void T999_StillNull() + { + TestHelpers.InMethod(); + + // After all tests are run, these should still return no results + Assert.That(db.getInventoryFolder(zero), Is.Null); + Assert.That(db.getInventoryItem(zero), Is.Null); + Assert.That(db.getUserRootFolder(zero), Is.Null); + Assert.That(db.getInventoryInFolder(zero).Count, Is.EqualTo(0), "Assert.That(db.getInventoryInFolder(zero).Count, Is.EqualTo(0))"); + } + + private InventoryItemBase NewItem(UUID id, UUID parent, UUID owner, string name, UUID asset) + { + InventoryItemBase i = new InventoryItemBase(); + i.ID = id; + i.Folder = parent; + i.Owner = owner; + i.CreatorId = owner.ToString(); + i.Name = name; + i.Description = name; + i.AssetID = asset; + return i; + } + + private InventoryFolderBase NewFolder(UUID id, UUID parent, UUID owner, string name) + { + InventoryFolderBase f = new InventoryFolderBase(); + f.ID = id; + f.ParentID = parent; + f.Owner = owner; + f.Name = name; + return f; + } + } +} diff --git a/Tests/OpenSim.Data.Tests/OpenSim.Data.Tests.csproj b/Tests/OpenSim.Data.Tests/OpenSim.Data.Tests.csproj new file mode 100644 index 00000000000..2188d057246 --- /dev/null +++ b/Tests/OpenSim.Data.Tests/OpenSim.Data.Tests.csproj @@ -0,0 +1,41 @@ + + + net6.0 + + + + ..\..\..\bin\Nini.dll + False + + + ..\..\..\bin\OpenMetaverse.dll + False + + + ..\..\..\bin\OpenMetaverseTypes.dll + False + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Tests/OpenSim.Data.Tests/PropertyCompareConstraint.cs b/Tests/OpenSim.Data.Tests/PropertyCompareConstraint.cs new file mode 100644 index 00000000000..b99525a74a3 --- /dev/null +++ b/Tests/OpenSim.Data.Tests/PropertyCompareConstraint.cs @@ -0,0 +1,413 @@ +/* + * 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; +using System.Collections.Generic; +using System.Drawing; +using System.Linq; +using System.Linq.Expressions; +using System.Reflection; +using NUnit.Framework; +using NUnit.Framework.Constraints; +using OpenMetaverse; +using OpenSim.Framework; +using OpenSim.Tests.Common; + +namespace OpenSim.Data.Tests +{ + public static class Constraints + { + //This is here because C# has a gap in the language, you can't infer type from a constructor + public static PropertyCompareConstraint PropertyCompareConstraint(T expected) + { + return new PropertyCompareConstraint(expected); + } + } + + public class PropertyCompareConstraint : NUnit.Framework.Constraints.Constraint + { + private readonly object _expected; + //the reason everywhere uses propertyNames.Reverse().ToArray() is because the stack is backwards of the order we want to display the properties in. + private string failingPropertyName = string.Empty; + private object failingExpected; + private object failingActual; + + public PropertyCompareConstraint(T expected) + { + _expected = expected; + } + + public override bool Matches(object actual) + { + return ObjectCompare(_expected, actual, new Stack()); + } + + private bool ObjectCompare(object expected, object actual, Stack propertyNames) + { + //If they are both null, they are equal + if (actual == null && expected == null) + return true; + + //If only one is null, then they aren't + if (actual == null || expected == null) + { + failingPropertyName = string.Join(".", propertyNames.Reverse().ToArray()); + failingActual = actual; + failingExpected = expected; + return false; + } + + //prevent loops... + if (propertyNames.Count > 50) + { + failingPropertyName = string.Join(".", propertyNames.Reverse().ToArray()); + failingActual = actual; + failingExpected = expected; + return false; + } + + if (actual.GetType() != expected.GetType()) + { + propertyNames.Push("GetType()"); + failingPropertyName = string.Join(".", propertyNames.Reverse().ToArray()); + propertyNames.Pop(); + failingActual = actual.GetType(); + failingExpected = expected.GetType(); + return false; + } + + if (actual.GetType() == typeof(Color)) + { + Color actualColor = (Color) actual; + Color expectedColor = (Color) expected; + if (actualColor.R != expectedColor.R) + { + propertyNames.Push("R"); + failingPropertyName = string.Join(".", propertyNames.Reverse().ToArray()); + propertyNames.Pop(); + failingActual = actualColor.R; + failingExpected = expectedColor.R; + return false; + } + if (actualColor.G != expectedColor.G) + { + propertyNames.Push("G"); + failingPropertyName = string.Join(".", propertyNames.Reverse().ToArray()); + propertyNames.Pop(); + failingActual = actualColor.G; + failingExpected = expectedColor.G; + return false; + } + if (actualColor.B != expectedColor.B) + { + propertyNames.Push("B"); + failingPropertyName = string.Join(".", propertyNames.Reverse().ToArray()); + propertyNames.Pop(); + failingActual = actualColor.B; + failingExpected = expectedColor.B; + return false; + } + if (actualColor.A != expectedColor.A) + { + propertyNames.Push("A"); + failingPropertyName = string.Join(".", propertyNames.Reverse().ToArray()); + propertyNames.Pop(); + failingActual = actualColor.A; + failingExpected = expectedColor.A; + return false; + } + return true; + } + + IComparable comp = actual as IComparable; + if (comp != null) + { + if (comp.CompareTo(expected) != 0) + { + failingPropertyName = string.Join(".", propertyNames.Reverse().ToArray()); + failingActual = actual; + failingExpected = expected; + return false; + } + return true; + } + + //Now try the much more annoying IComparable + Type icomparableInterface = actual.GetType().GetInterface("IComparable`1"); + if (icomparableInterface != null) + { + int result = (int)icomparableInterface.GetMethod("CompareTo").Invoke(actual, new[] { expected }); + if (result != 0) + { + failingPropertyName = string.Join(".", propertyNames.Reverse().ToArray()); + failingActual = actual; + failingExpected = expected; + return false; + } + return true; + } + + IEnumerable arr = actual as IEnumerable; + if (arr != null) + { + List actualList = arr.Cast().ToList(); + List expectedList = ((IEnumerable)expected).Cast().ToList(); + if (actualList.Count != expectedList.Count) + { + propertyNames.Push("Count"); + failingPropertyName = string.Join(".", propertyNames.Reverse().ToArray()); + failingActual = actualList.Count; + failingExpected = expectedList.Count; + propertyNames.Pop(); + return false; + } + //actualList and expectedList should be the same size. + for (int i = 0; i < actualList.Count; i++) + { + propertyNames.Push("[" + i + "]"); + if (!ObjectCompare(expectedList[i], actualList[i], propertyNames)) + return false; + propertyNames.Pop(); + } + //Everything seems okay... + return true; + } + + //Skip static properties. I had a nasty problem comparing colors because of all of the public static colors. + PropertyInfo[] properties = expected.GetType().GetProperties(BindingFlags.Public | BindingFlags.Instance); + foreach (var property in properties) + { + if (ignores.Contains(property.Name)) + continue; + + object actualValue = property.GetValue(actual, null); + object expectedValue = property.GetValue(expected, null); + + propertyNames.Push(property.Name); + if (!ObjectCompare(expectedValue, actualValue, propertyNames)) + return false; + propertyNames.Pop(); + } + + return true; + } + + public override void WriteDescriptionTo(MessageWriter writer) + { + writer.WriteExpectedValue(failingExpected); + } + + public override void WriteActualValueTo(MessageWriter writer) + { + writer.WriteActualValue(failingActual); + writer.WriteLine(); + writer.Write(" On Property: " + failingPropertyName); + } + + //These notes assume the lambda: (x=>x.Parent.Value) + //ignores should really contain like a fully dotted version of the property name, but I'm starting with small steps + readonly List ignores = new List(); + public PropertyCompareConstraint IgnoreProperty(Expression> func) + { + Expression express = func.Body; + PullApartExpression(express); + + return this; + } + + private void PullApartExpression(Expression express) + { + //This deals with any casts... like implicit casts to object. Not all UnaryExpression are casts, but this is a first attempt. + if (express is UnaryExpression) + PullApartExpression(((UnaryExpression)express).Operand); + if (express is MemberExpression) + { + //If the inside of the lambda is the access to x, we've hit the end of the chain. + // We should track by the fully scoped parameter name, but this is the first rev of doing this. + ignores.Add(((MemberExpression)express).Member.Name); + } + } + } + + [TestFixture] + public class PropertyCompareConstraintTest : OpenSimTestCase + { + public class HasInt + { + public int TheValue { get; set; } + } + + [Test] + public void IntShouldMatch() + { + HasInt actual = new HasInt { TheValue = 5 }; + HasInt expected = new HasInt { TheValue = 5 }; + var constraint = Constraints.PropertyCompareConstraint(expected); + + Assert.That(constraint.Matches(actual), Is.True); + } + + [Test] + public void IntShouldNotMatch() + { + HasInt actual = new HasInt { TheValue = 5 }; + HasInt expected = new HasInt { TheValue = 4 }; + var constraint = Constraints.PropertyCompareConstraint(expected); + + Assert.That(constraint.Matches(actual), Is.False); + } + + + [Test] + public void IntShouldIgnore() + { + HasInt actual = new HasInt { TheValue = 5 }; + HasInt expected = new HasInt { TheValue = 4 }; + var constraint = Constraints.PropertyCompareConstraint(expected).IgnoreProperty(x => x.TheValue); + + Assert.That(constraint.Matches(actual), Is.True); + } + + [Test] + public void AssetShouldMatch() + { + UUID uuid1 = UUID.Random(); + AssetBase actual = new AssetBase(uuid1, "asset one", (sbyte)AssetType.Texture, UUID.Zero.ToString()); + AssetBase expected = new AssetBase(uuid1, "asset one", (sbyte)AssetType.Texture, UUID.Zero.ToString()); + + var constraint = Constraints.PropertyCompareConstraint(expected); + + Assert.That(constraint.Matches(actual), Is.True); + } + + [Test] + public void AssetShouldNotMatch() + { + UUID uuid1 = UUID.Random(); + AssetBase actual = new AssetBase(uuid1, "asset one", (sbyte)AssetType.Texture, UUID.Zero.ToString()); + AssetBase expected = new AssetBase(UUID.Random(), "asset one", (sbyte)AssetType.Texture, UUID.Zero.ToString()); + + var constraint = Constraints.PropertyCompareConstraint(expected); + + Assert.That(constraint.Matches(actual), Is.False); + } + + [Test] + public void AssetShouldNotMatch2() + { + UUID uuid1 = UUID.Random(); + AssetBase actual = new AssetBase(uuid1, "asset one", (sbyte)AssetType.Texture, UUID.Zero.ToString()); + AssetBase expected = new AssetBase(uuid1, "asset two", (sbyte)AssetType.Texture, UUID.Zero.ToString()); + + var constraint = Constraints.PropertyCompareConstraint(expected); + + Assert.That(constraint.Matches(actual), Is.False); + } + + [Test] + public void UUIDShouldMatch() + { + UUID uuid1 = UUID.Random(); + UUID uuid2 = UUID.Parse(uuid1.ToString()); + + var constraint = Constraints.PropertyCompareConstraint(uuid1); + + Assert.That(constraint.Matches(uuid2), Is.True); + } + + [Test] + public void UUIDShouldNotMatch() + { + UUID uuid1 = UUID.Random(); + UUID uuid2 = UUID.Random(); + + var constraint = Constraints.PropertyCompareConstraint(uuid1); + + Assert.That(constraint.Matches(uuid2), Is.False); + } + + [Test] + public void TestColors() + { + Color actual = Color.Red; + Color expected = Color.FromArgb(actual.A, actual.R, actual.G, actual.B); + + var constraint = Constraints.PropertyCompareConstraint(expected); + + Assert.That(constraint.Matches(actual), Is.True); + } + + [Test] + public void ShouldCompareLists() + { + List expected = new List { 1, 2, 3 }; + List actual = new List { 1, 2, 3 }; + + var constraint = Constraints.PropertyCompareConstraint(expected); + Assert.That(constraint.Matches(actual), Is.True); + } + + + [Test] + public void ShouldFailToCompareListsThatAreDifferent() + { + List expected = new List { 1, 2, 3 }; + List actual = new List { 1, 2, 4 }; + + var constraint = Constraints.PropertyCompareConstraint(expected); + Assert.That(constraint.Matches(actual), Is.False); + } + + [Test] + public void ShouldFailToCompareListsThatAreDifferentLengths() + { + List expected = new List { 1, 2, 3 }; + List actual = new List { 1, 2 }; + + var constraint = Constraints.PropertyCompareConstraint(expected); + Assert.That(constraint.Matches(actual), Is.False); + } + + public class Recursive + { + public Recursive Other { get; set; } + } + + [Test] + public void ErrorsOutOnRecursive() + { + Recursive parent = new Recursive(); + Recursive child = new Recursive(); + parent.Other = child; + child.Other = parent; + + var constraint = Constraints.PropertyCompareConstraint(child); + Assert.That(constraint.Matches(child), Is.False); + } + } +} \ No newline at end of file diff --git a/Tests/OpenSim.Data.Tests/PropertyScrambler.cs b/Tests/OpenSim.Data.Tests/PropertyScrambler.cs new file mode 100644 index 00000000000..0d291df0b32 --- /dev/null +++ b/Tests/OpenSim.Data.Tests/PropertyScrambler.cs @@ -0,0 +1,184 @@ +/* + * 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; +using System.Collections.Generic; +using System.Linq.Expressions; +using System.Reflection; +using System.Text; +using NUnit.Framework; +using OpenMetaverse; +using OpenSim.Framework; +using OpenSim.Tests.Common; + +namespace OpenSim.Data.Tests +{ + //This is generic so that the lambda expressions will work right in IDEs. + public class PropertyScrambler + { + readonly System.Collections.Generic.List membersToNotScramble = new List(); + + private void AddExpressionToNotScrableList(Expression expression) + { + UnaryExpression unaryExpression = expression as UnaryExpression; + if (unaryExpression != null) + { + AddExpressionToNotScrableList(unaryExpression.Operand); + return; + } + + MemberExpression memberExpression = expression as MemberExpression; + if (memberExpression != null) + { + if (!(memberExpression.Member is PropertyInfo)) + { + throw new NotImplementedException("I don't know how deal with a MemberExpression that is a " + expression.Type); + } + membersToNotScramble.Add(memberExpression.Member.Name); + return; + } + + throw new NotImplementedException("I don't know how to parse a " + expression.Type); + } + + public PropertyScrambler DontScramble(Expression> expression) + { + AddExpressionToNotScrableList(expression.Body); + return this; + } + + public void Scramble(T obj) + { + internalScramble(obj); + } + + private void internalScramble(object obj) + { + PropertyInfo[] properties = obj.GetType().GetProperties(); + foreach (var property in properties) + { + //Skip indexers of classes. We will assume that everything that has an indexer + // is also IEnumberable. May not always be true, but should be true normally. + if (property.GetIndexParameters().Length > 0) + continue; + + RandomizeProperty(obj, property, null); + } + //Now if it implments IEnumberable, it's probably some kind of list, so we should randomize + // everything inside of it. + IEnumerable enumerable = obj as IEnumerable; + if (enumerable != null) + { + foreach (object value in enumerable) + { + internalScramble(value); + } + } + } + + private readonly Random random = new Random(); + private void RandomizeProperty(object obj, PropertyInfo property, object[] index) + {//I'd like a better way to compare, but I had lots of problems with InventoryFolderBase because the ID is inherited. + if (membersToNotScramble.Contains(property.Name)) + return; + Type t = property.PropertyType; + if (!property.CanWrite) + return; + object value = property.GetValue(obj, index); + if (value == null) + return; + + if (t == typeof(string)) + property.SetValue(obj, RandomName(), index); + else if (t == typeof(UUID)) + property.SetValue(obj, UUID.Random(), index); + else if (t == typeof(sbyte)) + property.SetValue(obj, (sbyte)random.Next(sbyte.MinValue, sbyte.MaxValue), index); + else if (t == typeof(short)) + property.SetValue(obj, (short)random.Next(short.MinValue, short.MaxValue), index); + else if (t == typeof(int)) + property.SetValue(obj, random.Next(), index); + else if (t == typeof(long)) + property.SetValue(obj, random.Next() * int.MaxValue, index); + else if (t == typeof(byte)) + property.SetValue(obj, (byte)random.Next(byte.MinValue, byte.MaxValue), index); + else if (t == typeof(ushort)) + property.SetValue(obj, (ushort)random.Next(ushort.MinValue, ushort.MaxValue), index); + else if (t == typeof(uint)) + property.SetValue(obj, Convert.ToUInt32(random.Next()), index); + else if (t == typeof(ulong)) + property.SetValue(obj, Convert.ToUInt64(random.Next()) * Convert.ToUInt64(UInt32.MaxValue), index); + else if (t == typeof(bool)) + property.SetValue(obj, true, index); + else if (t == typeof(byte[])) + { + byte[] bytes = new byte[30]; + random.NextBytes(bytes); + property.SetValue(obj, bytes, index); + } + else + internalScramble(value); + } + + private string RandomName() + { + StringBuilder name = new StringBuilder(); + int size = random.Next(5, 12); + for (int i = 0; i < size; i++) + { + char ch = Convert.ToChar(Convert.ToInt32(Math.Floor(26 * random.NextDouble() + 65))); + name.Append(ch); + } + return name.ToString(); + } + } + + [TestFixture] + public class PropertyScramblerTests : OpenSimTestCase + { + [Test] + public void TestScramble() + { + AssetBase actual = new AssetBase(UUID.Random(), "asset one", (sbyte)AssetType.Texture, UUID.Zero.ToString()); + new PropertyScrambler().Scramble(actual); + } + + [Test] + public void DontScramble() + { + UUID uuid = UUID.Random(); + AssetBase asset = new AssetBase(uuid, "asset", (sbyte)AssetType.Texture, UUID.Zero.ToString()); + new PropertyScrambler() + .DontScramble(x => x.Metadata) + .DontScramble(x => x.FullID) + .DontScramble(x => x.ID) + .Scramble(asset); + Assert.That(asset.FullID, Is.EqualTo(uuid)); + } + } +} \ No newline at end of file diff --git a/Tests/OpenSim.Data.Tests/RegionTests.cs b/Tests/OpenSim.Data.Tests/RegionTests.cs new file mode 100644 index 00000000000..75d644aa0af --- /dev/null +++ b/Tests/OpenSim.Data.Tests/RegionTests.cs @@ -0,0 +1,1145 @@ +/* + * 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 System.Drawing; +using System.Text; +using NUnit.Framework; +using OpenMetaverse; +using OpenSim.Framework; +using OpenSim.Region.Framework.Interfaces; +using OpenSim.Region.Framework.Scenes; +using OpenSim.Tests.Common; +using System.Data.Common; +using System.Threading; + +// DBMS-specific: +using OpenSim.Data.MySQL; + +using System.Data.SQLite; +using OpenSim.Data.SQLite; +using MySqlConnector; + +namespace OpenSim.Data.Tests +{ + [TestFixture(Description = "Region store tests (SQLite)")] + public class SQLiteRegionTests : RegionTests + { + } + + [TestFixture(Description = "Region store tests (MySQL)")] + public class MySqlRegionTests : RegionTests + { + } + + public class RegionTests : BasicDataServiceTest + where TConn : DbConnection, new() + where TRegStore : class, ISimulationDataStore, new() + { + bool m_rebuildDB; + + public ISimulationDataStore db; + public UUID zero = UUID.Zero; + public UUID region1 = UUID.Random(); + public UUID region2 = UUID.Random(); + public UUID region3 = UUID.Random(); + public UUID region4 = UUID.Random(); + public UUID prim1 = UUID.Random(); + public UUID prim2 = UUID.Random(); + public UUID prim3 = UUID.Random(); + public UUID prim4 = UUID.Random(); + public UUID prim5 = UUID.Random(); + public UUID prim6 = UUID.Random(); + public UUID item1 = UUID.Random(); + public UUID item2 = UUID.Random(); + public UUID item3 = UUID.Random(); + + public static Random random = new Random(); + + public string itemname1 = "item1"; + + public uint localID = 1; + + public double height1 = 20; + public double height2 = 100; + + public RegionTests(string conn, bool rebuild) + : base(conn) + { + m_rebuildDB = rebuild; + } + + public RegionTests() : this("", true) { } + public RegionTests(string conn) : this(conn, true) {} + public RegionTests(bool rebuild): this("", rebuild) {} + + + protected override void InitService(object service) + { + ClearDB(); + db = (ISimulationDataStore)service; + db.Initialise(m_connStr); + } + + private void ClearDB() + { + string[] reg_tables = new string[] { + "prims", "primshapes", "primitems", "terrain", "land", "landaccesslist", "regionban", "regionsettings" + }; + + if (m_rebuildDB) + { + DropTables(reg_tables); + ResetMigrations("RegionStore"); + } + else + { + ClearTables(reg_tables); + } + } + + // Test Plan + // Prims + // - empty test - 001 + // - store / retrieve basic prims (most minimal we can make) - 010, 011 + // - store / retrieve parts in a scenegroup 012 + // - store a prim with complete information for consistency check 013 + // - update existing prims, make sure it sticks - 014 + // - tests empty inventory - 020 + // - add inventory items to prims make - 021 + // - retrieves the added item - 022 + // - update inventory items to prims - 023 + // - remove inventory items make sure it sticks - 024 + // - checks if all parameters are persistent - 025 + // - adds many items and see if it is handled correctly - 026 + + [Test] + public void T001_LoadEmpty() + { + TestHelpers.InMethod(); + + List objs = db.LoadObjects(region1); + List objs3 = db.LoadObjects(region3); + List land = db.LoadLandObjects(region1); + + Assert.That(objs.Count, Is.EqualTo(0), "Assert.That(objs.Count, Is.EqualTo(0))"); + Assert.That(objs3.Count, Is.EqualTo(0), "Assert.That(objs3.Count, Is.EqualTo(0))"); + Assert.That(land.Count, Is.EqualTo(0), "Assert.That(land.Count, Is.EqualTo(0))"); + } + + // SOG round trips + // * store objects, make sure they save + // * update + + [Test] + public void T010_StoreSimpleObject() + { + TestHelpers.InMethod(); + + SceneObjectGroup sog = NewSOG("object1", prim1, region1); + SceneObjectGroup sog2 = NewSOG("object2", prim2, region1); + + // in case the objects don't store + try + { + db.StoreObject(sog, region1); + } + catch (Exception e) + { + m_log.Error(e.ToString()); + Assert.Fail(); + } + + try + { + db.StoreObject(sog2, region1); + } + catch (Exception e) + { + m_log.Error(e.ToString()); + Assert.Fail(); + } + + // This tests the ADO.NET driver + List objs = db.LoadObjects(region1); + + Assert.That(objs.Count, Is.EqualTo(2), "Assert.That(objs.Count, Is.EqualTo(2))"); + } + + [Test] + public void T011_ObjectNames() + { + TestHelpers.InMethod(); + + List objs = db.LoadObjects(region1); + foreach (SceneObjectGroup sog in objs) + { + SceneObjectPart p = sog.RootPart; + Assert.That("", Is.Not.EqualTo(p.Name), "Assert.That(\"\", Is.Not.EqualTo(p.Name))"); + Assert.That(p.Name, Is.EqualTo(p.Description), "Assert.That(p.Name, Is.EqualTo(p.Description))"); + } + } + + [Test] + public void T012_SceneParts() + { + TestHelpers.InMethod(); + + UUID tmp0 = UUID.Random(); + UUID tmp1 = UUID.Random(); + UUID tmp2 = UUID.Random(); + UUID tmp3 = UUID.Random(); + UUID newregion = UUID.Random(); + SceneObjectPart p1 = NewSOP("SoP 1",tmp1); + SceneObjectPart p2 = NewSOP("SoP 2",tmp2); + SceneObjectPart p3 = NewSOP("SoP 3",tmp3); + SceneObjectGroup sog = NewSOG("Sop 0", tmp0, newregion); + sog.AddPart(p1); + sog.AddPart(p2); + sog.AddPart(p3); + + SceneObjectPart[] parts = sog.Parts; + Assert.That(parts.Length,Is.EqualTo(4), "Assert.That(parts.Length,Is.EqualTo(4))"); + + db.StoreObject(sog, newregion); + List sogs = db.LoadObjects(newregion); + Assert.That(sogs.Count,Is.EqualTo(1), "Assert.That(sogs.Count,Is.EqualTo(1))"); + SceneObjectGroup newsog = sogs[0]; + + SceneObjectPart[] newparts = newsog.Parts; + Assert.That(newparts.Length,Is.EqualTo(4), "Assert.That(newparts.Length,Is.EqualTo(4))"); + + Assert.That(newsog.ContainsPart(tmp0), "Assert.That(newsog.ContainsPart(tmp0))"); + Assert.That(newsog.ContainsPart(tmp1), "Assert.That(newsog.ContainsPart(tmp1))"); + Assert.That(newsog.ContainsPart(tmp2), "Assert.That(newsog.ContainsPart(tmp2))"); + Assert.That(newsog.ContainsPart(tmp3), "Assert.That(newsog.ContainsPart(tmp3))"); + } + + [Test] + public void T013_DatabasePersistency() + { + TestHelpers.InMethod(); + + // Sets all ScenePart parameters, stores and retrieves them, then check for consistency with initial data + // The commented Asserts are the ones that are unchangeable (when storing on the database, their "Set" values are ignored + // The ObjectFlags is an exception, if it is entered incorrectly, the object IS REJECTED on the database silently. + UUID creator,uuid = new UUID(); + creator = UUID.Random(); + uint iserial = (uint)random.Next(); + TaskInventoryDictionary dic = new TaskInventoryDictionary(); + uint objf = (uint) random.Next() & (uint)~(PrimFlags.Touch | PrimFlags.Money | PrimFlags.AllowInventoryDrop); + uuid = prim4; + uint localid = localID+1; + localID = localID + 1; + string name = "Adam West"; + byte material = (byte) random.Next((int)SOPMaterialData.MaxMaterial); + ulong regionh = (ulong)random.NextDouble() * (ulong)random.Next(); + int pin = random.Next(); + Byte[] partsys = new byte[8]; + Byte[] textani = new byte[8]; + random.NextBytes(textani); + random.NextBytes(partsys); + DateTime expires = new DateTime(2008, 12, 20); + DateTime rezzed = new DateTime(2009, 07, 15); + Vector3 groupos = new Vector3(random.Next(100000),random.Next(100000),random.Next(100000)); + Vector3 offset = new Vector3(random.Next(100000),random.Next(100000),random.Next(100000)); + Quaternion rotoff = new Quaternion(random.Next(1),random.Next(1),random.Next(1),random.Next(1)); + rotoff.Normalize(); + Vector3 velocity = new Vector3(random.Next(100000),random.Next(100000),random.Next(100000)); + Vector3 angvelo = new Vector3(random.Next(100000),random.Next(100000),random.Next(100000)); + Vector3 accel = new Vector3(random.Next(100000),random.Next(100000),random.Next(100000)); + string description = name; + Color color = Color.FromArgb(255, 165, 50, 100); + string text = "All Your Base Are Belong to Us"; + string sitname = "SitName"; + string touchname = "TouchName"; + int linknum = random.Next(); + byte clickaction = (byte) random.Next(127); + PrimitiveBaseShape pbshap = new PrimitiveBaseShape(); + pbshap = PrimitiveBaseShape.Default; + pbshap.PathBegin = ushort.MaxValue; + pbshap.PathEnd = ushort.MaxValue; + pbshap.ProfileBegin = ushort.MaxValue; + pbshap.ProfileEnd = ushort.MaxValue; + pbshap.ProfileHollow = ushort.MaxValue; + Vector3 scale = new Vector3(random.Next(100000),random.Next(100000),random.Next(100000)); + + RegionInfo regionInfo = new RegionInfo() + { + RegionID = region3, + RegionLocX = 0, + RegionLocY = 0 + }; + + SceneObjectPart sop = new SceneObjectPart(); + SceneObjectGroup sog = new SceneObjectGroup(sop); + + sop.RegionHandle = regionh; + sop.UUID = uuid; + sop.LocalId = localid; + sop.Shape = pbshap; + sop.GroupPosition = groupos; + sop.RotationOffset = rotoff; + sop.CreatorID = creator; + sop.InventorySerial = iserial; + sop.TaskInventory = dic; + sop.Flags = (PrimFlags)objf; + sop.Name = name; + sop.Material = material; + sop.ScriptAccessPin = pin; + sop.TextureAnimation = textani; + sop.ParticleSystem = partsys; + sop.Expires = expires; + sop.Rezzed = rezzed; + sop.OffsetPosition = offset; + sop.Velocity = velocity; + sop.AngularVelocity = angvelo; + sop.Acceleration = accel; + sop.Description = description; + sop.Color = color; + sop.Text = text; + sop.SitName = sitname; + sop.TouchName = touchname; + sop.LinkNum = linknum; + sop.ClickAction = clickaction; + sop.Scale = scale; + + //Tests if local part accepted the parameters: + Assert.That(regionh,Is.EqualTo(sop.RegionHandle), "Assert.That(regionh,Is.EqualTo(sop.RegionHandle))"); + Assert.That(localid,Is.EqualTo(sop.LocalId), "Assert.That(localid,Is.EqualTo(sop.LocalId))"); + Assert.That(groupos,Is.EqualTo(sop.GroupPosition), "Assert.That(groupos,Is.EqualTo(sop.GroupPosition))"); + Assert.That(name,Is.EqualTo(sop.Name), "Assert.That(name,Is.EqualTo(sop.Name))"); + Assert.That(rotoff, new QuaternionToleranceConstraint(sop.RotationOffset, 0.001), "Assert.That(rotoff,Is.EqualTo(sop.RotationOffset))"); + Assert.That(uuid,Is.EqualTo(sop.UUID), "Assert.That(uuid,Is.EqualTo(sop.UUID))"); + Assert.That(creator,Is.EqualTo(sop.CreatorID), "Assert.That(creator,Is.EqualTo(sop.CreatorID))"); + // Modified in-class + // Assert.That(iserial,Is.EqualTo(sop.InventorySerial), "Assert.That(iserial,Is.EqualTo(sop.InventorySerial))"); + Assert.That(dic,Is.EqualTo(sop.TaskInventory), "Assert.That(dic,Is.EqualTo(sop.TaskInventory))"); + Assert.That(objf, Is.EqualTo((uint)sop.Flags), "Assert.That(objf,Is.EqualTo(sop.Flags))"); + Assert.That(name,Is.EqualTo(sop.Name), "Assert.That(name,Is.EqualTo(sop.Name))"); + Assert.That(material,Is.EqualTo(sop.Material), "Assert.That(material,Is.EqualTo(sop.Material))"); + Assert.That(pin,Is.EqualTo(sop.ScriptAccessPin), "Assert.That(pin,Is.EqualTo(sop.ScriptAccessPin))"); + Assert.That(textani,Is.EqualTo(sop.TextureAnimation), "Assert.That(textani,Is.EqualTo(sop.TextureAnimation))"); + Assert.That(partsys,Is.EqualTo(sop.ParticleSystem), "Assert.That(partsys,Is.EqualTo(sop.ParticleSystem))"); + Assert.That(expires,Is.EqualTo(sop.Expires), "Assert.That(expires,Is.EqualTo(sop.Expires))"); + Assert.That(rezzed,Is.EqualTo(sop.Rezzed), "Assert.That(rezzed,Is.EqualTo(sop.Rezzed))"); + Assert.That(offset,Is.EqualTo(sop.OffsetPosition), "Assert.That(offset,Is.EqualTo(sop.OffsetPosition))"); + Assert.That(velocity,Is.EqualTo(sop.Velocity), "Assert.That(velocity,Is.EqualTo(sop.Velocity))"); + Assert.That(angvelo,Is.EqualTo(sop.AngularVelocity), "Assert.That(angvelo,Is.EqualTo(sop.AngularVelocity))"); + Assert.That(accel,Is.EqualTo(sop.Acceleration), "Assert.That(accel,Is.EqualTo(sop.Acceleration))"); + Assert.That(description,Is.EqualTo(sop.Description), "Assert.That(description,Is.EqualTo(sop.Description))"); + Assert.That(color,Is.EqualTo(sop.Color), "Assert.That(color,Is.EqualTo(sop.Color))"); + Assert.That(text,Is.EqualTo(sop.Text), "Assert.That(text,Is.EqualTo(sop.Text))"); + Assert.That(sitname,Is.EqualTo(sop.SitName), "Assert.That(sitname,Is.EqualTo(sop.SitName))"); + Assert.That(touchname,Is.EqualTo(sop.TouchName), "Assert.That(touchname,Is.EqualTo(sop.TouchName))"); + Assert.That(linknum,Is.EqualTo(sop.LinkNum), "Assert.That(linknum,Is.EqualTo(sop.LinkNum))"); + Assert.That(clickaction,Is.EqualTo(sop.ClickAction), "Assert.That(clickaction,Is.EqualTo(sop.ClickAction))"); + Assert.That(scale,Is.EqualTo(sop.Scale), "Assert.That(scale,Is.EqualTo(sop.Scale))"); + + // This is necessary or object will not be inserted in DB + sop.Flags = PrimFlags.None; + + // Inserts group in DB + db.StoreObject(sog,region3); + List sogs = db.LoadObjects(region3); + Assert.That(sogs.Count, Is.EqualTo(1), "Assert.That(sogs.Count, Is.EqualTo(1))"); + // Makes sure there are no double insertions: + db.StoreObject(sog,region3); + sogs = db.LoadObjects(region3); + Assert.That(sogs.Count, Is.EqualTo(1), "Assert.That(sogs.Count, Is.EqualTo(1))"); + + + // Tests if the parameters were inserted correctly + SceneObjectPart p = sogs[0].RootPart; + Assert.That(regionh,Is.EqualTo(p.RegionHandle), "Assert.That(regionh,Is.EqualTo(p.RegionHandle))"); + //Assert.That(localid,Is.EqualTo(p.LocalId), "Assert.That(localid,Is.EqualTo(p.LocalId))"); + Assert.That(groupos, Is.EqualTo(p.GroupPosition), "Assert.That(groupos,Is.EqualTo(p.GroupPosition))"); + Assert.That(name,Is.EqualTo(p.Name), "Assert.That(name,Is.EqualTo(p.Name))"); + Assert.That(rotoff, Is.EqualTo(p.RotationOffset), "Assert.That(rotoff,Is.EqualTo(p.RotationOffset))"); + Assert.That(uuid,Is.EqualTo(p.UUID), "Assert.That(uuid,Is.EqualTo(p.UUID))"); + Assert.That(creator,Is.EqualTo(p.CreatorID), "Assert.That(creator,Is.EqualTo(p.CreatorID))"); + //Assert.That(iserial,Is.EqualTo(p.InventorySerial), "Assert.That(iserial,Is.EqualTo(p.InventorySerial))"); + Assert.That(dic,Is.EqualTo(p.TaskInventory), "Assert.That(dic,Is.EqualTo(p.TaskInventory))"); + //Assert.That(objf, Is.EqualTo((uint)p.Flags), "Assert.That(objf,Is.EqualTo(p.Flags))"); + Assert.That(name,Is.EqualTo(p.Name), "Assert.That(name,Is.EqualTo(p.Name))"); + Assert.That(material,Is.EqualTo(p.Material), "Assert.That(material,Is.EqualTo(p.Material))"); + Assert.That(pin,Is.EqualTo(p.ScriptAccessPin), "Assert.That(pin,Is.EqualTo(p.ScriptAccessPin))"); + Assert.That(textani,Is.EqualTo(p.TextureAnimation), "Assert.That(textani,Is.EqualTo(p.TextureAnimation))"); + Assert.That(partsys,Is.EqualTo(p.ParticleSystem), "Assert.That(partsys,Is.EqualTo(p.ParticleSystem))"); + //Assert.That(expires,Is.EqualTo(p.Expires), "Assert.That(expires,Is.EqualTo(p.Expires))"); + //Assert.That(rezzed,Is.EqualTo(p.Rezzed), "Assert.That(rezzed,Is.EqualTo(p.Rezzed))"); + Assert.That(offset,Is.EqualTo(p.OffsetPosition), "Assert.That(offset,Is.EqualTo(p.OffsetPosition))"); + Assert.That(velocity,Is.EqualTo(p.Velocity), "Assert.That(velocity,Is.EqualTo(p.Velocity))"); + Assert.That(angvelo,Is.EqualTo(p.AngularVelocity), "Assert.That(angvelo,Is.EqualTo(p.AngularVelocity))"); + Assert.That(accel,Is.EqualTo(p.Acceleration), "Assert.That(accel,Is.EqualTo(p.Acceleration))"); + Assert.That(description,Is.EqualTo(p.Description), "Assert.That(description,Is.EqualTo(p.Description))"); + Assert.That(color,Is.EqualTo(p.Color), "Assert.That(color,Is.EqualTo(p.Color))"); + Assert.That(text,Is.EqualTo(p.Text), "Assert.That(text,Is.EqualTo(p.Text))"); + Assert.That(sitname,Is.EqualTo(p.SitName), "Assert.That(sitname,Is.EqualTo(p.SitName))"); + Assert.That(touchname,Is.EqualTo(p.TouchName), "Assert.That(touchname,Is.EqualTo(p.TouchName))"); + //Assert.That(linknum,Is.EqualTo(p.LinkNum), "Assert.That(linknum,Is.EqualTo(p.LinkNum))"); + Assert.That(clickaction,Is.EqualTo(p.ClickAction), "Assert.That(clickaction,Is.EqualTo(p.ClickAction))"); + Assert.That(scale,Is.EqualTo(p.Scale), "Assert.That(scale,Is.EqualTo(p.Scale))"); + + //Assert.That(updatef,Is.EqualTo(p.UpdateFlag), "Assert.That(updatef,Is.EqualTo(p.UpdateFlag))"); + + Assert.That(pbshap.PathBegin, Is.EqualTo(p.Shape.PathBegin), "Assert.That(pbshap.PathBegin, Is.EqualTo(p.Shape.PathBegin))"); + Assert.That(pbshap.PathEnd, Is.EqualTo(p.Shape.PathEnd), "Assert.That(pbshap.PathEnd, Is.EqualTo(p.Shape.PathEnd))"); + Assert.That(pbshap.ProfileBegin, Is.EqualTo(p.Shape.ProfileBegin), "Assert.That(pbshap.ProfileBegin, Is.EqualTo(p.Shape.ProfileBegin))"); + Assert.That(pbshap.ProfileEnd, Is.EqualTo(p.Shape.ProfileEnd), "Assert.That(pbshap.ProfileEnd, Is.EqualTo(p.Shape.ProfileEnd))"); + Assert.That(pbshap.ProfileHollow, Is.EqualTo(p.Shape.ProfileHollow), "Assert.That(pbshap.ProfileHollow, Is.EqualTo(p.Shape.ProfileHollow))"); + } + + [Test] + public void T014_UpdateObject() + { + TestHelpers.InMethod(); + + string text1 = "object1 text"; + SceneObjectGroup sog = FindSOG("object1", region1); + sog.RootPart.Text = text1; + db.StoreObject(sog, region1); + + sog = FindSOG("object1", region1); + Assert.That(text1, Is.EqualTo(sog.RootPart.Text), "Assert.That(text1, Is.EqualTo(sog.RootPart.Text))"); + + // Creates random values + UUID creator = new UUID(); + creator = UUID.Random(); + TaskInventoryDictionary dic = new TaskInventoryDictionary(); + localID = localID + 1; + string name = "West Adam"; + byte material = (byte) random.Next((int)SOPMaterialData.MaxMaterial); + ulong regionh = (ulong)random.NextDouble() * (ulong)random.Next(); + int pin = random.Next(); + Byte[] partsys = new byte[8]; + Byte[] textani = new byte[8]; + random.NextBytes(textani); + random.NextBytes(partsys); + DateTime expires = new DateTime(2010, 12, 20); + DateTime rezzed = new DateTime(2005, 07, 15); + Vector3 groupos = new Vector3(random.Next(100000),random.Next(100000),random.Next(100000)); + Vector3 offset = new Vector3(random.Next(100000),random.Next(100000),random.Next(100000)); + Quaternion rotoff = new Quaternion(random.Next(100),random.Next(100),random.Next(100),random.Next(100)); + rotoff.Normalize(); + Vector3 velocity = new Vector3(random.Next(100000),random.Next(100000),random.Next(100000)); + Vector3 angvelo = new Vector3(random.Next(100000),random.Next(100000),random.Next(100000)); + Vector3 accel = new Vector3(random.Next(100000),random.Next(100000),random.Next(100000)); + string description = name; + Color color = Color.FromArgb(255, 255, 255, 0); + string text = "What You Say?{]\vz~"; + string sitname = RandomName(); + string touchname = RandomName(); + int linknum = random.Next(); + byte clickaction = (byte) random.Next(127); + PrimitiveBaseShape pbshap = new PrimitiveBaseShape(); + pbshap = PrimitiveBaseShape.Default; + Vector3 scale = new Vector3(random.Next(),random.Next(),random.Next()); + + // Updates the region with new values + SceneObjectGroup sog2 = FindSOG("Adam West", region3); + Assert.That(sog2,Is.Not.Null); + sog2.RootPart.RegionHandle = regionh; + sog2.RootPart.Shape = pbshap; + sog2.RootPart.GroupPosition = groupos; + sog2.RootPart.RotationOffset = rotoff; + sog2.RootPart.CreatorID = creator; + sog2.RootPart.TaskInventory = dic; + sog2.RootPart.Name = name; + sog2.RootPart.Material = material; + sog2.RootPart.ScriptAccessPin = pin; + sog2.RootPart.TextureAnimation = textani; + sog2.RootPart.ParticleSystem = partsys; + sog2.RootPart.Expires = expires; + sog2.RootPart.Rezzed = rezzed; + sog2.RootPart.OffsetPosition = offset; + sog2.RootPart.Velocity = velocity; + sog2.RootPart.AngularVelocity = angvelo; + sog2.RootPart.Acceleration = accel; + sog2.RootPart.Description = description; + sog2.RootPart.Color = color; + sog2.RootPart.Text = text; + sog2.RootPart.SitName = sitname; + sog2.RootPart.TouchName = touchname; + sog2.RootPart.LinkNum = linknum; + sog2.RootPart.ClickAction = clickaction; + sog2.RootPart.Scale = scale; + + db.StoreObject(sog2, region3); + List sogs = db.LoadObjects(region3); + Assert.That(sogs.Count, Is.EqualTo(1), "Assert.That(sogs.Count, Is.EqualTo(1))"); + + SceneObjectGroup retsog = FindSOG("West Adam", region3); + Assert.That(retsog,Is.Not.Null); + SceneObjectPart p = retsog.RootPart; + Assert.That(regionh,Is.EqualTo(p.RegionHandle), "Assert.That(regionh,Is.EqualTo(p.RegionHandle))"); + Assert.That(groupos,Is.EqualTo(p.GroupPosition), "Assert.That(groupos,Is.EqualTo(p.GroupPosition))"); + Assert.That(name,Is.EqualTo(p.Name), "Assert.That(name,Is.EqualTo(p.Name))"); + Assert.That(rotoff, new QuaternionToleranceConstraint(p.RotationOffset, 0.001), "Assert.That(rotoff,Is.EqualTo(p.RotationOffset))"); + Assert.That(creator,Is.EqualTo(p.CreatorID), "Assert.That(creator,Is.EqualTo(p.CreatorID))"); + Assert.That(dic,Is.EqualTo(p.TaskInventory), "Assert.That(dic,Is.EqualTo(p.TaskInventory))"); + Assert.That(name,Is.EqualTo(p.Name), "Assert.That(name,Is.EqualTo(p.Name))"); + Assert.That(material,Is.EqualTo(p.Material), "Assert.That(material,Is.EqualTo(p.Material))"); + Assert.That(pin,Is.EqualTo(p.ScriptAccessPin), "Assert.That(pin,Is.EqualTo(p.ScriptAccessPin))"); + Assert.That(textani,Is.EqualTo(p.TextureAnimation), "Assert.That(textani,Is.EqualTo(p.TextureAnimation))"); + Assert.That(partsys,Is.EqualTo(p.ParticleSystem), "Assert.That(partsys,Is.EqualTo(p.ParticleSystem))"); + Assert.That(offset,Is.EqualTo(p.OffsetPosition), "Assert.That(offset,Is.EqualTo(p.OffsetPosition))"); + Assert.That(velocity,Is.EqualTo(p.Velocity), "Assert.That(velocity,Is.EqualTo(p.Velocity))"); + Assert.That(angvelo,Is.EqualTo(p.AngularVelocity), "Assert.That(angvelo,Is.EqualTo(p.AngularVelocity))"); + Assert.That(accel,Is.EqualTo(p.Acceleration), "Assert.That(accel,Is.EqualTo(p.Acceleration))"); + Assert.That(description,Is.EqualTo(p.Description), "Assert.That(description,Is.EqualTo(p.Description))"); + Assert.That(color,Is.EqualTo(p.Color), "Assert.That(color,Is.EqualTo(p.Color))"); + Assert.That(text,Is.EqualTo(p.Text), "Assert.That(text,Is.EqualTo(p.Text))"); + Assert.That(sitname,Is.EqualTo(p.SitName), "Assert.That(sitname,Is.EqualTo(p.SitName))"); + Assert.That(touchname,Is.EqualTo(p.TouchName), "Assert.That(touchname,Is.EqualTo(p.TouchName))"); + Assert.That(clickaction,Is.EqualTo(p.ClickAction), "Assert.That(clickaction,Is.EqualTo(p.ClickAction))"); + Assert.That(scale,Is.EqualTo(p.Scale), "Assert.That(scale,Is.EqualTo(p.Scale))"); + } + + /// + /// Test storage and retrieval of a scene object with a large number of parts. + /// + [Test] + public void T015_LargeSceneObjects() + { + TestHelpers.InMethod(); + + UUID id = UUID.Random(); + Dictionary mydic = new Dictionary(); + SceneObjectGroup sog = NewSOG("Test SOG", id, region4); + mydic.Add(sog.RootPart.UUID,sog.RootPart); + for (int i = 0; i < 30; i++) + { + UUID tmp = UUID.Random(); + SceneObjectPart sop = NewSOP(("Test SOP " + i.ToString()),tmp); + Vector3 groupos = new Vector3(random.Next(100000),random.Next(100000),random.Next(100000)); + Vector3 offset = new Vector3(random.Next(100000),random.Next(100000),random.Next(100000)); + Quaternion rotoff = new Quaternion(random.Next(1000),random.Next(1000),random.Next(1000),random.Next(1000)); + rotoff.Normalize(); + Vector3 velocity = new Vector3(random.Next(100000),random.Next(100000),random.Next(100000)); + Vector3 angvelo = new Vector3(random.Next(100000),random.Next(100000),random.Next(100000)); + Vector3 accel = new Vector3(random.Next(100000),random.Next(100000),random.Next(100000)); + + sop.GroupPosition = groupos; + sop.RotationOffset = rotoff; + sop.OffsetPosition = offset; + sop.Velocity = velocity; + sop.AngularVelocity = angvelo; + sop.Acceleration = accel; + + mydic.Add(tmp,sop); + sog.AddPart(sop); + } + + db.StoreObject(sog, region4); + SceneObjectGroup retsog = FindSOG("Test SOG", region4); + SceneObjectPart[] parts = retsog.Parts; + for (int i = 0; i < 30; i++) + { + SceneObjectPart cursop = mydic[parts[i].UUID]; + Assert.That(cursop.GroupPosition,Is.EqualTo(parts[i].GroupPosition), "Assert.That(cursop.GroupPosition,Is.EqualTo(parts[i].GroupPosition))"); + Assert.That(cursop.RotationOffset, new QuaternionToleranceConstraint(parts[i].RotationOffset, 0.001), "Assert.That(rotoff,Is.EqualTo(p.RotationOffset))"); + Assert.That(cursop.OffsetPosition,Is.EqualTo(parts[i].OffsetPosition), "Assert.That(cursop.OffsetPosition,Is.EqualTo(parts[i].OffsetPosition))"); + Assert.That(cursop.Velocity,Is.EqualTo(parts[i].Velocity), "Assert.That(cursop.Velocity,Is.EqualTo(parts[i].Velocity))"); + Assert.That(cursop.AngularVelocity,Is.EqualTo(parts[i].AngularVelocity), "Assert.That(cursop.AngularVelocity,Is.EqualTo(parts[i].AngularVelocity))"); + Assert.That(cursop.Acceleration,Is.EqualTo(parts[i].Acceleration), "Assert.That(cursop.Acceleration,Is.EqualTo(parts[i].Acceleration))"); + } + } + + //[Test] + public void T016_RandomSogWithSceneParts() + { + TestHelpers.InMethod(); + + PropertyScrambler scrambler = + new PropertyScrambler() + .DontScramble(x => x.UUID); + UUID tmpSog = UUID.Random(); + UUID tmp1 = UUID.Random(); + UUID tmp2 = UUID.Random(); + UUID tmp3 = UUID.Random(); + UUID newregion = UUID.Random(); + SceneObjectPart p1 = new SceneObjectPart(); + SceneObjectPart p2 = new SceneObjectPart(); + SceneObjectPart p3 = new SceneObjectPart(); + p1.Shape = PrimitiveBaseShape.Default; + p2.Shape = PrimitiveBaseShape.Default; + p3.Shape = PrimitiveBaseShape.Default; + p1.UUID = tmp1; + p2.UUID = tmp2; + p3.UUID = tmp3; + scrambler.Scramble(p1); + scrambler.Scramble(p2); + scrambler.Scramble(p3); + + SceneObjectGroup sog = NewSOG("Sop 0", tmpSog, newregion); + PropertyScrambler sogScrambler = + new PropertyScrambler() + .DontScramble(x => x.UUID); + sogScrambler.Scramble(sog); + sog.UUID = tmpSog; + sog.AddPart(p1); + sog.AddPart(p2); + sog.AddPart(p3); + + SceneObjectPart[] parts = sog.Parts; + Assert.That(parts.Length, Is.EqualTo(4), "Assert.That(parts.Length,Is.EqualTo(4))"); + + db.StoreObject(sog, newregion); + List sogs = db.LoadObjects(newregion); + Assert.That(sogs.Count, Is.EqualTo(1), "Assert.That(sogs.Count,Is.EqualTo(1))"); + SceneObjectGroup newsog = sogs[0]; + + SceneObjectPart[] newparts = newsog.Parts; + Assert.That(newparts.Length, Is.EqualTo(4), "Assert.That(newparts.Length,Is.EqualTo(4))"); + + Assert.That(newsog, Constraints.PropertyCompareConstraint(sog) + .IgnoreProperty(x=>x.LocalId) + .IgnoreProperty(x=>x.HasGroupChanged) + .IgnoreProperty(x=>x.IsSelected) + .IgnoreProperty(x=>x.RegionHandle) + .IgnoreProperty(x=>x.RegionUUID) + .IgnoreProperty(x=>x.Scene) + .IgnoreProperty(x=>x.Parts) + .IgnoreProperty(x=>x.RootPart)); + } + + + private SceneObjectGroup GetMySOG(string name) + { + SceneObjectGroup sog = FindSOG(name, region1); + if (sog == null) + { + sog = NewSOG(name, prim1, region1); + db.StoreObject(sog, region1); + } + return sog; + } + + // NOTE: it is a bad practice to rely on some of the previous tests having been run before. + // If the tests are run manually, one at a time, each starts with full class init (DB cleared). + // Even when all tests are run, NUnit 2.5+ no longer guarantee a specific test order. + // We shouldn't expect to find anything in the DB if we haven't put it there *in the same test*! + + [Test] + public void T020_PrimInventoryEmpty() + { +/* + TestHelpers.InMethod(); + + SceneObjectGroup sog = GetMySOG("object1"); + TaskInventoryItem t = sog.GetInventoryItem(sog.RootPart.LocalId, item1); + Assert.That(t, Is.Null); +*/ + } + + // TODO: Is there any point to call StorePrimInventory on a list, rather than on the prim itself? + + private void StoreInventory(SceneObjectGroup sog) + { + List list = new List(); + // TODO: seriously??? this is the way we need to loop to get this? + foreach (UUID uuid in sog.RootPart.Inventory.GetInventoryList()) + { + list.Add(sog.GetInventoryItem(sog.RootPart.LocalId, uuid)); + } + + db.StorePrimInventory(sog.RootPart.UUID, list); + } + + [Test] + public void T021_PrimInventoryBasic() + { +/* + TestHelpers.InMethod(); + + SceneObjectGroup sog = GetMySOG("object1"); + InventoryItemBase i = NewItem(item1, zero, zero, itemname1, zero); + + Assert.That(sog.AddInventoryItem(zero, sog.RootPart.LocalId, i, zero), Is.True); + TaskInventoryItem t = sog.GetInventoryItem(sog.RootPart.LocalId, item1); + Assert.That(t.Name, Is.EqualTo(itemname1), "Assert.That(t.Name, Is.EqualTo(itemname1))"); + + StoreInventory(sog); + + SceneObjectGroup sog1 = FindSOG("object1", region1); + Assert.That(sog1, Is.Not.Null); + + TaskInventoryItem t1 = sog1.GetInventoryItem(sog1.RootPart.LocalId, item1); + Assert.That(t1, Is.Not.Null); + Assert.That(t1.Name, Is.EqualTo(itemname1), "Assert.That(t.Name, Is.EqualTo(itemname1))"); + + // Updating inventory + t1.Name = "My New Name"; + sog1.UpdateInventoryItem(t1); + + StoreInventory(sog1); + + SceneObjectGroup sog2 = FindSOG("object1", region1); + TaskInventoryItem t2 = sog2.GetInventoryItem(sog2.RootPart.LocalId, item1); + Assert.That(t2.Name, Is.EqualTo("My New Name"), "Assert.That(t.Name, Is.EqualTo(\"My New Name\"))"); + + // Removing inventory + List list = new List(); + db.StorePrimInventory(prim1, list); + + sog = FindSOG("object1", region1); + t = sog.GetInventoryItem(sog.RootPart.LocalId, item1); + Assert.That(t, Is.Null); +*/ + } + + [Test] + public void T025_PrimInventoryPersistency() + { +/* + TestHelpers.InMethod(); + + InventoryItemBase i = new InventoryItemBase(); + UUID id = UUID.Random(); + i.ID = id; + UUID folder = UUID.Random(); + i.Folder = folder; + UUID owner = UUID.Random(); + i.Owner = owner; + UUID creator = UUID.Random(); + i.CreatorId = creator.ToString(); + string name = RandomName(); + i.Name = name; + i.Description = name; + UUID assetid = UUID.Random(); + i.AssetID = assetid; + int invtype = random.Next(); + i.InvType = invtype; + uint nextperm = (uint) random.Next(); + i.NextPermissions = nextperm; + uint curperm = (uint) random.Next(); + i.CurrentPermissions = curperm; + uint baseperm = (uint) random.Next(); + i.BasePermissions = baseperm; + uint eoperm = (uint) random.Next(); + i.EveryOnePermissions = eoperm; + int assettype = random.Next(); + i.AssetType = assettype; + UUID groupid = UUID.Random(); + i.GroupID = groupid; + bool groupown = true; + i.GroupOwned = groupown; + int saleprice = random.Next(); + i.SalePrice = saleprice; + byte saletype = (byte) random.Next(127); + i.SaleType = saletype; + uint flags = (uint) random.Next(); + i.Flags = flags; + int creationd = random.Next(); + i.CreationDate = creationd; + + SceneObjectGroup sog = GetMySOG("object1"); + Assert.That(sog.AddInventoryItem(zero, sog.RootPart.LocalId, i, zero), Is.True); + TaskInventoryItem t = sog.GetInventoryItem(sog.RootPart.LocalId, id); + + Assert.That(t.Name, Is.EqualTo(name), "Assert.That(t.Name, Is.EqualTo(name))"); + Assert.That(t.AssetID,Is.EqualTo(assetid), "Assert.That(t.AssetID,Is.EqualTo(assetid))"); + Assert.That(t.BasePermissions,Is.EqualTo(baseperm), "Assert.That(t.BasePermissions,Is.EqualTo(baseperm))"); + Assert.That(t.CreationDate,Is.EqualTo(creationd), "Assert.That(t.CreationDate,Is.EqualTo(creationd))"); + Assert.That(t.CreatorID,Is.EqualTo(creator), "Assert.That(t.CreatorID,Is.EqualTo(creator))"); + Assert.That(t.Description,Is.EqualTo(name), "Assert.That(t.Description,Is.EqualTo(name))"); + Assert.That(t.EveryonePermissions,Is.EqualTo(eoperm), "Assert.That(t.EveryonePermissions,Is.EqualTo(eoperm))"); + Assert.That(t.Flags,Is.EqualTo(flags), "Assert.That(t.Flags,Is.EqualTo(flags))"); + Assert.That(t.GroupID,Is.EqualTo(sog.RootPart.GroupID), "Assert.That(t.GroupID,Is.EqualTo(sog.RootPart.GroupID))"); + // Where is this group permissions?? + // Assert.That(t.GroupPermissions,Is.EqualTo(), "Assert.That(t.GroupPermissions,Is.EqualTo())"); + Assert.That(t.Type,Is.EqualTo(assettype), "Assert.That(t.Type,Is.EqualTo(assettype))"); + Assert.That(t.InvType, Is.EqualTo(invtype), "Assert.That(t.InvType, Is.EqualTo(invtype))"); + Assert.That(t.ItemID, Is.EqualTo(id), "Assert.That(t.ItemID, Is.EqualTo(id))"); + Assert.That(t.LastOwnerID, Is.EqualTo(sog.RootPart.LastOwnerID), "Assert.That(t.LastOwnerID, Is.EqualTo(sog.RootPart.LastOwnerID))"); + Assert.That(t.NextPermissions, Is.EqualTo(nextperm), "Assert.That(t.NextPermissions, Is.EqualTo(nextperm))"); + // Ownership changes when you drop an object into an object + // owned by someone else + Assert.That(t.OwnerID,Is.EqualTo(sog.RootPart.OwnerID), "Assert.That(t.OwnerID,Is.EqualTo(sog.RootPart.OwnerID))"); +// Assert.That(t.CurrentPermissions, Is.EqualTo(curperm | 16), "Assert.That(t.CurrentPermissions, Is.EqualTo(curperm | 8))"); + Assert.That(t.ParentID,Is.EqualTo(sog.RootPart.FolderID), "Assert.That(t.ParentID,Is.EqualTo(sog.RootPart.FolderID))"); + Assert.That(t.ParentPartID,Is.EqualTo(sog.RootPart.UUID), "Assert.That(t.ParentPartID,Is.EqualTo(sog.RootPart.UUID))"); +*/ + } +/* + [Test] + [ExpectedException(typeof(ArgumentException))] + public void T026_PrimInventoryMany() + { + + TestHelpers.InMethod(); + + UUID i1,i2,i3,i4; + i1 = UUID.Random(); + i2 = UUID.Random(); + i3 = UUID.Random(); + i4 = i3; + InventoryItemBase ib1 = NewItem(i1, zero, zero, RandomName(), zero); + InventoryItemBase ib2 = NewItem(i2, zero, zero, RandomName(), zero); + InventoryItemBase ib3 = NewItem(i3, zero, zero, RandomName(), zero); + InventoryItemBase ib4 = NewItem(i4, zero, zero, RandomName(), zero); + + SceneObjectGroup sog = FindSOG("object1", region1); + + Assert.That(sog.AddInventoryItem(zero, sog.RootPart.LocalId, ib1, zero), Is.True); + Assert.That(sog.AddInventoryItem(zero, sog.RootPart.LocalId, ib2, zero), Is.True); + Assert.That(sog.AddInventoryItem(zero, sog.RootPart.LocalId, ib3, zero), Is.True); + Assert.That(sog.AddInventoryItem(zero, sog.RootPart.LocalId, ib4, zero), Is.True); + + TaskInventoryItem t1 = sog.GetInventoryItem(sog.RootPart.LocalId, i1); + Assert.That(t1.Name, Is.EqualTo(ib1.Name), "Assert.That(t1.Name, Is.EqualTo(ib1.Name))"); + TaskInventoryItem t2 = sog.GetInventoryItem(sog.RootPart.LocalId, i2); + Assert.That(t2.Name, Is.EqualTo(ib2.Name), "Assert.That(t2.Name, Is.EqualTo(ib2.Name))"); + TaskInventoryItem t3 = sog.GetInventoryItem(sog.RootPart.LocalId, i3); + Assert.That(t3.Name, Is.EqualTo(ib3.Name), "Assert.That(t3.Name, Is.EqualTo(ib3.Name))"); + TaskInventoryItem t4 = sog.GetInventoryItem(sog.RootPart.LocalId, i4); + Assert.That(t4, Is.Null); + + } +*/ + [Test] + public void T052_RemoveObject() + { + TestHelpers.InMethod(); + + db.RemoveObject(prim1, region1); + SceneObjectGroup sog = FindSOG("object1", region1); + Assert.That(sog, Is.Null); + } + + [Test] + public void T100_DefaultRegionInfo() + { + TestHelpers.InMethod(); + + RegionSettings r1 = db.LoadRegionSettings(region1); + Assert.That(r1.RegionUUID, Is.EqualTo(region1), "Assert.That(r1.RegionUUID, Is.EqualTo(region1))"); + + RegionSettings r2 = db.LoadRegionSettings(region2); + Assert.That(r2.RegionUUID, Is.EqualTo(region2), "Assert.That(r2.RegionUUID, Is.EqualTo(region2))"); + } + + [Test] + public void T101_UpdateRegionInfo() + { + TestHelpers.InMethod(); + + int agentlimit = random.Next(); + double objectbonus = random.Next(); + int maturity = random.Next(); + UUID tertex1 = UUID.Random(); + UUID tertex2 = UUID.Random(); + UUID tertex3 = UUID.Random(); + UUID tertex4 = UUID.Random(); + double elev1nw = 1000; + double elev2nw = 1001; + double elev1ne = 1002; + double elev2ne = 1003; + double elev1se = 1004; + double elev2se = 1425; + double elev1sw = 352; + double elev2sw = 774; + double waterh = 125; + double terrainraise = 74; + double terrainlower = -79; + Vector3 sunvector = new Vector3((float)Math.Round(random.NextDouble(),5),(float)Math.Round(random.NextDouble(),5),(float)Math.Round(random.NextDouble(),5)); + UUID terimgid = UUID.Random(); + UUID cov = UUID.Random(); + + RegionSettings r1 = db.LoadRegionSettings(region1); + r1.BlockTerraform = true; + r1.BlockFly = true; + r1.AllowDamage = true; + r1.RestrictPushing = true; + r1.AllowLandResell = false; + r1.AllowLandJoinDivide = false; + r1.BlockShowInSearch = true; + r1.AgentLimit = agentlimit; + r1.ObjectBonus = objectbonus; + r1.Maturity = maturity; + r1.DisableScripts = true; + r1.DisableCollisions = true; + r1.DisablePhysics = true; + r1.TerrainTexture1 = tertex1; + r1.TerrainTexture2 = tertex2; + r1.TerrainTexture3 = tertex3; + r1.TerrainTexture4 = tertex4; + r1.Elevation1NW = elev1nw; + r1.Elevation2NW = elev2nw; + r1.Elevation1NE = elev1ne; + r1.Elevation2NE = elev2ne; + r1.Elevation1SE = elev1se; + r1.Elevation2SE = elev2se; + r1.Elevation1SW = elev1sw; + r1.Elevation2SW = elev2sw; + r1.WaterHeight = waterh; + r1.TerrainRaiseLimit = terrainraise; + r1.TerrainLowerLimit = terrainlower; + r1.UseEstateSun = false; + r1.Sandbox = true; + r1.TerrainImageID = terimgid; + r1.FixedSun = true; + r1.Covenant = cov; + + db.StoreRegionSettings(r1); + + RegionSettings r1a = db.LoadRegionSettings(region1); + Assert.That(r1a.RegionUUID, Is.EqualTo(region1), "Assert.That(r1a.RegionUUID, Is.EqualTo(region1))"); + Assert.That(r1a.BlockTerraform,Is.True); + Assert.That(r1a.BlockFly,Is.True); + Assert.That(r1a.AllowDamage,Is.True); + Assert.That(r1a.RestrictPushing,Is.True); + Assert.That(r1a.AllowLandResell,Is.False); + Assert.That(r1a.AllowLandJoinDivide,Is.False); + Assert.That(r1a.BlockShowInSearch,Is.True); + Assert.That(r1a.AgentLimit,Is.EqualTo(agentlimit), "Assert.That(r1a.AgentLimit,Is.EqualTo(agentlimit))"); + Assert.That(r1a.ObjectBonus,Is.EqualTo(objectbonus), "Assert.That(r1a.ObjectBonus,Is.EqualTo(objectbonus))"); + Assert.That(r1a.Maturity,Is.EqualTo(maturity), "Assert.That(r1a.Maturity,Is.EqualTo(maturity))"); + Assert.That(r1a.DisableScripts,Is.True); + Assert.That(r1a.DisableCollisions,Is.True); + Assert.That(r1a.DisablePhysics,Is.True); + Assert.That(r1a.TerrainTexture1,Is.EqualTo(tertex1), "Assert.That(r1a.TerrainTexture1,Is.EqualTo(tertex1))"); + Assert.That(r1a.TerrainTexture2,Is.EqualTo(tertex2), "Assert.That(r1a.TerrainTexture2,Is.EqualTo(tertex2))"); + Assert.That(r1a.TerrainTexture3,Is.EqualTo(tertex3), "Assert.That(r1a.TerrainTexture3,Is.EqualTo(tertex3))"); + Assert.That(r1a.TerrainTexture4,Is.EqualTo(tertex4), "Assert.That(r1a.TerrainTexture4,Is.EqualTo(tertex4))"); + Assert.That(r1a.Elevation1NW,Is.EqualTo(elev1nw), "Assert.That(r1a.Elevation1NW,Is.EqualTo(elev1nw))"); + Assert.That(r1a.Elevation2NW,Is.EqualTo(elev2nw), "Assert.That(r1a.Elevation2NW,Is.EqualTo(elev2nw))"); + Assert.That(r1a.Elevation1NE,Is.EqualTo(elev1ne), "Assert.That(r1a.Elevation1NE,Is.EqualTo(elev1ne))"); + Assert.That(r1a.Elevation2NE,Is.EqualTo(elev2ne), "Assert.That(r1a.Elevation2NE,Is.EqualTo(elev2ne))"); + Assert.That(r1a.Elevation1SE,Is.EqualTo(elev1se), "Assert.That(r1a.Elevation1SE,Is.EqualTo(elev1se))"); + Assert.That(r1a.Elevation2SE,Is.EqualTo(elev2se), "Assert.That(r1a.Elevation2SE,Is.EqualTo(elev2se))"); + Assert.That(r1a.Elevation1SW,Is.EqualTo(elev1sw), "Assert.That(r1a.Elevation1SW,Is.EqualTo(elev1sw))"); + Assert.That(r1a.Elevation2SW,Is.EqualTo(elev2sw), "Assert.That(r1a.Elevation2SW,Is.EqualTo(elev2sw))"); + Assert.That(r1a.WaterHeight,Is.EqualTo(waterh), "Assert.That(r1a.WaterHeight,Is.EqualTo(waterh))"); + Assert.That(r1a.TerrainRaiseLimit,Is.EqualTo(terrainraise), "Assert.That(r1a.TerrainRaiseLimit,Is.EqualTo(terrainraise))"); + Assert.That(r1a.TerrainLowerLimit,Is.EqualTo(terrainlower), "Assert.That(r1a.TerrainLowerLimit,Is.EqualTo(terrainlower))"); + Assert.That(r1a.Sandbox,Is.True); + //Assert.That(r1a.TerrainImageID,Is.EqualTo(terimgid), "Assert.That(r1a.TerrainImageID,Is.EqualTo(terimgid))"); + Assert.That(r1a.Covenant, Is.EqualTo(cov), "Assert.That(r1a.Covenant, Is.EqualTo(cov))"); + } + + [Test] + public void T300_NoTerrain() + { + TestHelpers.InMethod(); + + Assert.That(db.LoadTerrain(zero), Is.Null); + Assert.That(db.LoadTerrain(region1), Is.Null); + Assert.That(db.LoadTerrain(region2), Is.Null); + Assert.That(db.LoadTerrain(UUID.Random()), Is.Null); + } + + [Test] + public void T301_CreateTerrain() + { + TestHelpers.InMethod(); + + double[,] t1 = GenTerrain(height1); + db.StoreTerrain(t1, region1); + + // store terrain is async + Thread.Sleep(500); + + Assert.That(db.LoadTerrain(zero), Is.Null); + Assert.That(db.LoadTerrain(region1), Is.Not.Null); + Assert.That(db.LoadTerrain(region2), Is.Null); + Assert.That(db.LoadTerrain(UUID.Random()), Is.Null); + } + + [Test] + public void T302_FetchTerrain() + { + TestHelpers.InMethod(); + + double[,] baseterrain1 = GenTerrain(height1); + double[,] baseterrain2 = GenTerrain(height2); + double[,] t1 = db.LoadTerrain(region1); + Assert.That(CompareTerrain(t1, baseterrain1), Is.True); + Assert.That(CompareTerrain(t1, baseterrain2), Is.False); + } + + [Test] + public void T303_UpdateTerrain() + { + TestHelpers.InMethod(); + + double[,] baseterrain1 = GenTerrain(height1); + double[,] baseterrain2 = GenTerrain(height2); + db.StoreTerrain(baseterrain2, region1); + + // store terrain is async + Thread.Sleep(500); + + double[,] t1 = db.LoadTerrain(region1); + Assert.That(CompareTerrain(t1, baseterrain1), Is.False); + Assert.That(CompareTerrain(t1, baseterrain2), Is.True); + } + + [Test] + public void T400_EmptyLand() + { + TestHelpers.InMethod(); + + Assert.That(db.LoadLandObjects(zero).Count, Is.EqualTo(0), "Assert.That(db.LoadLandObjects(zero).Count, Is.EqualTo(0))"); + Assert.That(db.LoadLandObjects(region1).Count, Is.EqualTo(0), "Assert.That(db.LoadLandObjects(region1).Count, Is.EqualTo(0))"); + Assert.That(db.LoadLandObjects(region2).Count, Is.EqualTo(0), "Assert.That(db.LoadLandObjects(region2).Count, Is.EqualTo(0))"); + Assert.That(db.LoadLandObjects(UUID.Random()).Count, Is.EqualTo(0), "Assert.That(db.LoadLandObjects(UUID.Random()).Count, Is.EqualTo(0))"); + } + + // TODO: we should have real land tests, but Land is so + // intermingled with scene that you can't test it without a + // valid scene. That requires some disagregation. + + + //************************************************************************************// + // Extra private methods + + private double[,] GenTerrain(double value) + { + double[,] terret = new double[Constants.RegionSize, Constants.RegionSize]; + terret.Initialize(); + for (int x = 0; x < Constants.RegionSize; x++) + for (int y = 0; y < Constants.RegionSize; y++) + terret[x,y] = value; + + return terret; + } + + private bool CompareTerrain(double[,] one, double[,] two) + { + for (int x = 0; x < Constants.RegionSize; x++) + for (int y = 0; y < Constants.RegionSize; y++) + if (one[x,y] != two[x,y]) + return false; + + return true; + } + + private SceneObjectGroup FindSOG(string name, UUID r) + { + List objs = db.LoadObjects(r); + foreach (SceneObjectGroup sog in objs) + if (sog.Name == name) + return sog; + + return null; + } + + // This builds a minimalistic Prim, 1 SOG with 1 root SOP. A + // common failure case is people adding new fields that aren't + // initialized, but have non-null db constraints. We should + // honestly be passing more and more null things in here. + // + // Please note that in Sqlite.BuildPrim there is a commented out inline version + // of this so you can debug and step through the build process and check the fields + // + // Real World Value: Tests for situation where extending a SceneObjectGroup/SceneObjectPart + // causes the application to crash at the database layer because of null values + // in NOT NULL fields + // + private SceneObjectGroup NewSOG(string name, UUID uuid, UUID regionId) + { + RegionInfo regionInfo = new RegionInfo + { + RegionID = regionId, + RegionLocX = 0, + RegionLocY = 0 + }; + + SceneObjectPart sop = new SceneObjectPart + { + Name = name, + Description = name, + Text = RandomName(), + SitName = RandomName(), + TouchName = RandomName(), + UUID = uuid, + Shape = PrimitiveBaseShape.Default + }; + + SceneObjectGroup sog = new SceneObjectGroup(sop); + + return sog; + } + + private SceneObjectPart NewSOP(string name, UUID uuid) + { + SceneObjectPart sop = new SceneObjectPart + { + Name = name, + Description = name, + Text = RandomName(), + SitName = RandomName(), + TouchName = RandomName(), + UUID = uuid, + Shape = PrimitiveBaseShape.Default + }; + return sop; + } + + // These are copied from the Inventory Item tests + + private InventoryItemBase NewItem(UUID id, UUID parent, UUID owner, string name, UUID asset) + { + InventoryItemBase i = new InventoryItemBase + { + ID = id, + Folder = parent, + Owner = owner, + CreatorId = owner.ToString(), + Name = name, + Description = name, + AssetID = asset + }; + return i; + } + + private static string RandomName() + { + StringBuilder name = new StringBuilder(); + int size = random.Next(5,12); + char ch ; + for (int i=0; i\n\n 128\n 0\n 00000000-0000-0000-0000-000000000000\n 10\n 0\n 0\n 54ff9641-dd40-4a2c-b1f1-47dd3af24e50\n d740204e-bbbf-44aa-949d-02c7d739f6a5\n False\n AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=\n land data to test LandDataSerializer\n 536870944\n 2\n LandDataSerializerTest Land\n 0\n 0\n 1\n d4452578-2f25-4b97-a81b-819af559cfd7\n http://videos.opensimulator.org/bumblebee.mp4\n \n 1b8eedf9-6d15-448b-8015-24286f1756bf\n \n 0\n 0\n 0\n 00000000-0000-0000-0000-000000000000\n <0, 0, 0>\n <0, 0, 0>\n 0\n 0\n"; + private static string preSerializedWithParcelAccessList + = "\n\n 128\n 0\n 00000000-0000-0000-0000-000000000000\n 10\n 0\n 0\n 54ff9641-dd40-4a2c-b1f1-47dd3af24e50\n d740204e-bbbf-44aa-949d-02c7d739f6a5\n False\n AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=\n land data to test LandDataSerializer\n 536870944\n 2\n LandDataSerializerTest Land\n 0\n 0\n 1\n d4452578-2f25-4b97-a81b-819af559cfd7\n http://videos.opensimulator.org/bumblebee.mp4\n \n 1b8eedf9-6d15-448b-8015-24286f1756bf\n \n \n 62d65d45-c91a-4f77-862c-46557d978b6c\n \n 2\n \n \n ec2a8d18-2378-4fe0-8b68-2a31b57c481e\n \n 1\n \n \n 0\n 0\n 0\n 00000000-0000-0000-0000-000000000000\n <0, 0, 0>\n <0, 0, 0>\n 0\n 0\n"; + + [SetUp] + public void setup() + { + // setup LandData object + this.land = new LandData(); + this.land.AABBMax = new Vector3(1, 2, 3); + this.land.AABBMin = new Vector3(129, 130, 131); + this.land.Area = 128; + this.land.AuctionID = 4; + this.land.AuthBuyerID = new UUID("7176df0c-6c50-45db-8a37-5e78be56a0cd"); + this.land.Category = ParcelCategory.Residential; + this.land.ClaimDate = 1; + this.land.ClaimPrice = 2; + this.land.GlobalID = new UUID("54ff9641-dd40-4a2c-b1f1-47dd3af24e50"); + this.land.GroupID = new UUID("d740204e-bbbf-44aa-949d-02c7d739f6a5"); + this.land.Description = "land data to test LandDataSerializer"; + this.land.Flags = (uint)(ParcelFlags.AllowDamage | ParcelFlags.AllowVoiceChat); + this.land.LandingType = (byte)LandingType.Direct; + this.land.Name = "LandDataSerializerTest Land"; + this.land.Status = ParcelStatus.Leased; + this.land.LocalID = 1; + this.land.MediaAutoScale = (byte)0x01; + this.land.MediaID = new UUID("d4452578-2f25-4b97-a81b-819af559cfd7"); + this.land.MediaURL = "http://videos.opensimulator.org/bumblebee.mp4"; + this.land.OwnerID = new UUID("1b8eedf9-6d15-448b-8015-24286f1756bf"); + + this.landWithParcelAccessList = this.land.Copy(); + this.landWithParcelAccessList.ParcelAccessList.Clear(); + + LandAccessEntry pae0 = new LandAccessEntry(); + pae0.AgentID = new UUID("62d65d45-c91a-4f77-862c-46557d978b6c"); + pae0.Flags = AccessList.Ban; + pae0.Expires = 0; + this.landWithParcelAccessList.ParcelAccessList.Add(pae0); + + LandAccessEntry pae1 = new LandAccessEntry(); + pae1.AgentID = new UUID("ec2a8d18-2378-4fe0-8b68-2a31b57c481e"); + pae1.Flags = AccessList.Access; + pae1.Expires = 0; + this.landWithParcelAccessList.ParcelAccessList.Add(pae1); + } + + /// + /// Test the LandDataSerializer.Serialize() method + /// +// [Test] +// public void LandDataSerializerSerializeTest() +// { +// TestHelpers.InMethod(); +// +// string serialized = LandDataSerializer.Serialize(this.land).Replace("\r\n", "\n"); +// Assert.That(serialized.Length > 0, "Serialize(LandData) returned empty string"); +// +// // adding a simple boolean variable because resharper nUnit integration doesn't like this +// // XML data in the Assert.That statement. Not sure why. +// bool result = (serialized == preSerialized); +// Assert.That(result, "result of Serialize LandData does not match expected result"); +// +// string serializedWithParcelAccessList = LandDataSerializer.Serialize(this.landWithParcelAccessList).Replace("\r\n", "\n"); +// Assert.That(serializedWithParcelAccessList.Length > 0, +// "Serialize(LandData) returned empty string for LandData object with ParcelAccessList"); +// result = (serializedWithParcelAccessList == preSerializedWithParcelAccessList); +// Assert.That(result, +// "result of Serialize(LandData) does not match expected result (pre-serialized with parcel access list"); +// } + + /// + /// Test the LandDataSerializer.Deserialize() method + /// + [Test] + public void TestLandDataDeserializeNoAccessLists() + { + TestHelpers.InMethod(); +// log4net.Config.XmlConfigurator.Configure(); + + Dictionary options = new Dictionary(); + LandData ld = LandDataSerializer.Deserialize(LandDataSerializer.Serialize(this.land, options)); + Assert.That(ld, Is.Not.Null, "Deserialize(string) returned null"); +// Assert.That(ld.AABBMax, Is.EqualTo(land.AABBMax)); +// Assert.That(ld.AABBMin, Is.EqualTo(land.AABBMin)); + Assert.That(ld.Area, Is.EqualTo(land.Area)); + Assert.That(ld.AuctionID, Is.EqualTo(land.AuctionID)); + Assert.That(ld.AuthBuyerID, Is.EqualTo(land.AuthBuyerID)); + Assert.That(ld.Category, Is.EqualTo(land.Category)); + Assert.That(ld.ClaimDate, Is.EqualTo(land.ClaimDate)); + Assert.That(ld.ClaimPrice, Is.EqualTo(land.ClaimPrice)); + Assert.That(ld.GlobalID, Is.EqualTo(land.GlobalID), "Reified LandData.GlobalID != original LandData.GlobalID"); + Assert.That(ld.GroupID, Is.EqualTo(land.GroupID)); + Assert.That(ld.Description, Is.EqualTo(land.Description)); + Assert.That(ld.Flags, Is.EqualTo(land.Flags)); + Assert.That(ld.LandingType, Is.EqualTo(land.LandingType)); + Assert.That(ld.Name, Is.EqualTo(land.Name), "Reified LandData.Name != original LandData.Name"); + Assert.That(ld.Status, Is.EqualTo(land.Status)); + Assert.That(ld.LocalID, Is.EqualTo(land.LocalID)); + Assert.That(ld.MediaAutoScale, Is.EqualTo(land.MediaAutoScale)); + Assert.That(ld.MediaID, Is.EqualTo(land.MediaID)); + Assert.That(ld.MediaURL, Is.EqualTo(land.MediaURL)); + Assert.That(ld.OwnerID, Is.EqualTo(land.OwnerID)); + } + + [Test] + public void TestLandDataDeserializeWithAccessLists() + { + TestHelpers.InMethod(); +// log4net.Config.XmlConfigurator.Configure(); + + LandData ld = LandDataSerializer.Deserialize(LandDataSerializerTest.preSerializedWithParcelAccessList); + Assert.That(ld != null, + "Deserialize(string) returned null (pre-serialized with parcel access list)"); + Assert.That(ld.GlobalID == this.landWithParcelAccessList.GlobalID, + "Reified LandData.GlobalID != original LandData.GlobalID (pre-serialized with parcel access list)"); + Assert.That(ld.Name == this.landWithParcelAccessList.Name, + "Reified LandData.Name != original LandData.Name (pre-serialized with parcel access list)"); + Assert.That(ld.ParcelAccessList.Count, Is.EqualTo(2)); + Assert.That(ld.ParcelAccessList[0].AgentID, Is.EqualTo(UUID.Parse("62d65d45-c91a-4f77-862c-46557d978b6c"))); + } + } +} diff --git a/Tests/OpenSim.Framework.Serialization.Tests/OpenSim.Framework.Serialization.Tests.csproj b/Tests/OpenSim.Framework.Serialization.Tests/OpenSim.Framework.Serialization.Tests.csproj new file mode 100644 index 00000000000..9e0ae2b11d9 --- /dev/null +++ b/Tests/OpenSim.Framework.Serialization.Tests/OpenSim.Framework.Serialization.Tests.csproj @@ -0,0 +1,32 @@ + + + net6.0 + + + + + + + + + + ..\..\..\..\bin\OpenMetaverse.dll + False + + + ..\..\..\..\bin\OpenMetaverse.StructuredData.dll + False + + + ..\..\..\..\bin\OpenMetaverseTypes.dll + False + + + + + + + + + + \ No newline at end of file diff --git a/Tests/OpenSim.Framework.Serialization.Tests/RegionSettingsSerializerTests.cs b/Tests/OpenSim.Framework.Serialization.Tests/RegionSettingsSerializerTests.cs new file mode 100644 index 00000000000..4f3f2ddde31 --- /dev/null +++ b/Tests/OpenSim.Framework.Serialization.Tests/RegionSettingsSerializerTests.cs @@ -0,0 +1,142 @@ +/* + * 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 OpenMetaverse; +using OpenMetaverse.StructuredData; +using NUnit.Framework; +using OpenSim.Framework; +using OpenSim.Framework.Serialization.External; +using OpenSim.Tests.Common; + +namespace OpenSim.Framework.Serialization.Tests +{ + [TestFixture] + public class RegionSettingsSerializerTests : OpenSimTestCase + { + private string m_serializedRs = @" + + + True + True + True + True + True + True + True + True + True + 1 + True + 40 + 1.4 + + + 00000000-0000-0000-0000-000000000020 + 00000000-0000-0000-0000-000000000040 + 00000000-0000-0000-0000-000000000060 + 00000000-0000-0000-0000-000000000080 + 1.9 + 15.9 + 49 + 45.3 + 2.1 + 4.5 + 9.2 + 19.2 + + + 23 + 17.9 + 0.4 + True + true + 12 + + + 00000000-0000-0000-0000-111111111111 + 1,-2,0.33 + +"; + + private RegionSettings m_rs; + + [SetUp] + public void Setup() + { + m_rs = new RegionSettings(); + m_rs.AgentLimit = 17; + m_rs.AllowDamage = true; + m_rs.AllowLandJoinDivide = true; + m_rs.AllowLandResell = true; + m_rs.BlockFly = true; + m_rs.BlockShowInSearch = true; + m_rs.BlockTerraform = true; + m_rs.DisableCollisions = true; + m_rs.DisablePhysics = true; + m_rs.DisableScripts = true; + m_rs.Elevation1NW = 15.9; + m_rs.Elevation1NE = 45.3; + m_rs.Elevation1SE = 49; + m_rs.Elevation1SW = 1.9; + m_rs.Elevation2NW = 4.5; + m_rs.Elevation2NE = 19.2; + m_rs.Elevation2SE = 9.2; + m_rs.Elevation2SW = 2.1; + m_rs.FixedSun = true; + m_rs.SunPosition = 12.0; + m_rs.ObjectBonus = 1.4; + m_rs.RestrictPushing = true; + m_rs.TerrainLowerLimit = 0.4; + m_rs.TerrainRaiseLimit = 17.9; + m_rs.TerrainTexture1 = UUID.Parse("00000000-0000-0000-0000-000000000020"); + m_rs.TerrainTexture2 = UUID.Parse("00000000-0000-0000-0000-000000000040"); + m_rs.TerrainTexture3 = UUID.Parse("00000000-0000-0000-0000-000000000060"); + m_rs.TerrainTexture4 = UUID.Parse("00000000-0000-0000-0000-000000000080"); + m_rs.UseEstateSun = true; + m_rs.WaterHeight = 23; + m_rs.TelehubObject = UUID.Parse("00000000-0000-0000-0000-111111111111"); + m_rs.AddSpawnPoint(SpawnPoint.Parse("1,-2,0.33")); + } + + [Test] + public void TestRegionSettingsDeserialize() + { + TestHelpers.InMethod(); +// log4net.Config.XmlConfigurator.Configure(); + + RegionSettings deserRs = RegionSettingsSerializer.Deserialize(m_serializedRs, out ViewerEnvironment dummy, new EstateSettings()); + Assert.That(deserRs, Is.Not.Null); + Assert.That(deserRs.TerrainTexture2, Is.EqualTo(m_rs.TerrainTexture2)); + Assert.That(deserRs.DisablePhysics, Is.EqualTo(m_rs.DisablePhysics)); + Assert.That(deserRs.TerrainLowerLimit, Is.EqualTo(m_rs.TerrainLowerLimit)); + Assert.That(deserRs.TelehubObject, Is.EqualTo(m_rs.TelehubObject)); + Assert.That(deserRs.SpawnPoints()[0].ToString(), Is.EqualTo(m_rs.SpawnPoints()[0].ToString())); + } + } +} diff --git a/Tests/OpenSim.Framework.Servers.Tests/OpenSim.Framework.Servers.Tests.csproj b/Tests/OpenSim.Framework.Servers.Tests/OpenSim.Framework.Servers.Tests.csproj new file mode 100644 index 00000000000..fb8f1c05bec --- /dev/null +++ b/Tests/OpenSim.Framework.Servers.Tests/OpenSim.Framework.Servers.Tests.csproj @@ -0,0 +1,19 @@ + + + net6.0 + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Tests/OpenSim.Framework.Servers.Tests/VersionInfoTests.cs b/Tests/OpenSim.Framework.Servers.Tests/VersionInfoTests.cs new file mode 100644 index 00000000000..68a1c78aa4b --- /dev/null +++ b/Tests/OpenSim.Framework.Servers.Tests/VersionInfoTests.cs @@ -0,0 +1,45 @@ +/* + * 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 System.Text; +using NUnit.Framework; +using OpenSim.Tests.Common; + +namespace OpenSim.Framework.Servers.Tests +{ + [TestFixture] + public class VersionInfoTests : OpenSimTestCase + { + [Test] + public void TestVersionLength() + { + Assert.AreEqual(VersionInfo.VERSIONINFO_VERSION_LENGTH, VersionInfo.Version.Length," VersionInfo.Version string not " + VersionInfo.VERSIONINFO_VERSION_LENGTH + " chars."); + } + } +} diff --git a/Tests/OpenSim.Framework.Tests/AgentCircuitDataTest.cs b/Tests/OpenSim.Framework.Tests/AgentCircuitDataTest.cs new file mode 100644 index 00000000000..c8eb57dd591 --- /dev/null +++ b/Tests/OpenSim.Framework.Tests/AgentCircuitDataTest.cs @@ -0,0 +1,351 @@ +/* + * 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.Collections.Generic; +using OpenMetaverse; +using OpenMetaverse.StructuredData; +using NUnit.Framework; +using OpenSim.Tests.Common; + +namespace OpenSim.Framework.Tests +{ + [TestFixture] + public class AgentCircuitDataTest : OpenSimTestCase + { + private UUID AgentId; + private AvatarAppearance AvAppearance; + private byte[] VisualParams; + private UUID BaseFolder; + private string CapsPath; + private Dictionary ChildrenCapsPaths; + private uint circuitcode = 0949030; + private string firstname; + private string lastname; + private UUID SecureSessionId; + private UUID SessionId; + private Vector3 StartPos; + + + [SetUp] + public void setup() + { + AgentId = UUID.Random(); + BaseFolder = UUID.Random(); + CapsPath = "http://www.opensimulator.org/Caps/Foo"; + ChildrenCapsPaths = new Dictionary(); + ChildrenCapsPaths.Add(ulong.MaxValue, "http://www.opensimulator.org/Caps/Foo2"); + firstname = "CoolAvatarTest"; + lastname = "test"; + StartPos = new Vector3(5,23,125); + + SecureSessionId = UUID.Random(); + SessionId = UUID.Random(); + + AvAppearance = new AvatarAppearance(); + VisualParams = new byte[218]; + + //body + VisualParams[(int)AvatarAppearance.VPElement.SHAPE_HEIGHT] = 155; + VisualParams[(int)AvatarAppearance.VPElement.SHAPE_THICKNESS] = 00; + VisualParams[(int)AvatarAppearance.VPElement.SHAPE_BODY_FAT] = 0; + + //Torso + VisualParams[(int)AvatarAppearance.VPElement.SHAPE_TORSO_MUSCLES] = 48; + VisualParams[(int)AvatarAppearance.VPElement.SHAPE_NECK_THICKNESS] = 43; + VisualParams[(int)AvatarAppearance.VPElement.SHAPE_NECK_LENGTH] = 255; + VisualParams[(int)AvatarAppearance.VPElement.SHAPE_SHOULDERS] = 94; + VisualParams[(int)AvatarAppearance.VPElement.SHAPE_CHEST_MALE_NO_PECS] = 199; + VisualParams[(int)AvatarAppearance.VPElement.SHAPE_ARM_LENGTH] = 255; + VisualParams[(int)AvatarAppearance.VPElement.SHAPE_HAND_SIZE] = 33; + VisualParams[(int)AvatarAppearance.VPElement.SHAPE_TORSO_LENGTH] = 240; + VisualParams[(int)AvatarAppearance.VPElement.SHAPE_LOVE_HANDLES] = 0; + VisualParams[(int)AvatarAppearance.VPElement.SHAPE_BELLY_SIZE] = 0; + + // legs + VisualParams[(int)AvatarAppearance.VPElement.SHAPE_LEG_MUSCLES] = 82; + VisualParams[(int)AvatarAppearance.VPElement.SHAPE_LEG_LENGTH] = 255; + VisualParams[(int)AvatarAppearance.VPElement.SHAPE_HIP_WIDTH] = 84; + VisualParams[(int)AvatarAppearance.VPElement.SHAPE_HIP_LENGTH] = 166; + VisualParams[(int)AvatarAppearance.VPElement.SHAPE_BUTT_SIZE] = 64; + VisualParams[(int)AvatarAppearance.VPElement.SHAPE_SADDLEBAGS] = 89; + VisualParams[(int)AvatarAppearance.VPElement.SHAPE_BOWED_LEGS] = 127; + VisualParams[(int)AvatarAppearance.VPElement.SHAPE_FOOT_SIZE] = 45; + + + // head + VisualParams[(int)AvatarAppearance.VPElement.SHAPE_HEAD_SIZE] = 255; + VisualParams[(int)AvatarAppearance.VPElement.SHAPE_SQUASH_STRETCH_HEAD] = 0; // head stretch + VisualParams[(int)AvatarAppearance.VPElement.SHAPE_HEAD_SHAPE] = 155; + VisualParams[(int)AvatarAppearance.VPElement.SHAPE_EGG_HEAD] = 127; + VisualParams[(int)AvatarAppearance.VPElement.SHAPE_POINTY_EARS] = 255; + VisualParams[(int)AvatarAppearance.VPElement.SHAPE_HEAD_LENGTH] = 45; + VisualParams[(int)AvatarAppearance.VPElement.SHAPE_FACE_SHEAR] = 127; + VisualParams[(int)AvatarAppearance.VPElement.SHAPE_FOREHEAD_ANGLE] = 104; + VisualParams[(int)AvatarAppearance.VPElement.SHAPE_BIG_BROW] = 94; + VisualParams[(int)AvatarAppearance.VPElement.SHAPE_PUFFY_UPPER_CHEEKS] = 0; // upper cheeks + VisualParams[(int)AvatarAppearance.VPElement.SHAPE_DOUBLE_CHIN] = 122; // lower cheeks + VisualParams[(int)AvatarAppearance.VPElement.SHAPE_HIGH_CHEEK_BONES] = 130; + + + + // eyes + VisualParams[(int)AvatarAppearance.VPElement.SHAPE_EYE_SIZE] = 105; + VisualParams[(int)AvatarAppearance.VPElement.SHAPE_WIDE_EYES] = 135; + VisualParams[(int)AvatarAppearance.VPElement.SHAPE_EYE_SPACING] = 184; + VisualParams[(int)AvatarAppearance.VPElement.SHAPE_EYELID_CORNER_UP] = 230; + VisualParams[(int)AvatarAppearance.VPElement.SHAPE_EYELID_INNER_CORNER_UP] = 120; + VisualParams[(int)AvatarAppearance.VPElement.SHAPE_EYE_DEPTH] = 158; + VisualParams[(int)AvatarAppearance.VPElement.SHAPE_UPPER_EYELID_FOLD] = 69; + VisualParams[(int)AvatarAppearance.VPElement.SHAPE_BAGGY_EYES] = 38; + VisualParams[(int)AvatarAppearance.VPElement.SHAPE_EYELASHES_LONG] = 127; + VisualParams[(int)AvatarAppearance.VPElement.SHAPE_POP_EYE] = 127; + + VisualParams[(int)AvatarAppearance.VPElement.EYES_EYE_COLOR] = 25; + VisualParams[(int)AvatarAppearance.VPElement.EYES_EYE_LIGHTNESS] = 127; + + // ears + VisualParams[(int)AvatarAppearance.VPElement.SHAPE_BIG_EARS] = 255; + VisualParams[(int)AvatarAppearance.VPElement.SHAPE_EARS_OUT] = 127; + VisualParams[(int)AvatarAppearance.VPElement.SHAPE_ATTACHED_EARLOBES] = 127; + VisualParams[(int)AvatarAppearance.VPElement.SHAPE_POINTY_EARS] = 255; + + // nose + VisualParams[(int)AvatarAppearance.VPElement.SHAPE_NOSE_BIG_OUT] = 79; + VisualParams[(int)AvatarAppearance.VPElement.SHAPE_WIDE_NOSE] = 35; + VisualParams[(int)AvatarAppearance.VPElement.SHAPE_BROAD_NOSTRILS] = 86; + VisualParams[(int)AvatarAppearance.VPElement.SHAPE_LOW_SEPTUM_NOSE] = 112; // nostril division + VisualParams[(int)AvatarAppearance.VPElement.SHAPE_BULBOUS_NOSE] = 25; + VisualParams[(int)AvatarAppearance.VPElement.SHAPE_NOBLE_NOSE_BRIDGE] = 25; // upper bridge + VisualParams[(int)AvatarAppearance.VPElement.SHAPE_LOWER_BRIDGE_NOSE] = 25; // lower bridge + VisualParams[(int)AvatarAppearance.VPElement.SHAPE_WIDE_NOSE_BRIDGE] = 25; + VisualParams[(int)AvatarAppearance.VPElement.SHAPE_UPTURNED_NOSE_TIP] = 107; + VisualParams[(int)AvatarAppearance.VPElement.SHAPE_BULBOUS_NOSE_TIP] = 25; + VisualParams[(int)AvatarAppearance.VPElement.SHAPE_CROOKED_NOSE] = 127; + + + // Mouth + VisualParams[(int)AvatarAppearance.VPElement.SHAPE_LIP_WIDTH] = 122; + VisualParams[(int)AvatarAppearance.VPElement.SHAPE_TALL_LIPS] = 10; // lip fullness + VisualParams[(int)AvatarAppearance.VPElement.SHAPE_LIP_THICKNESS] = 112; + VisualParams[(int)AvatarAppearance.VPElement.SHAPE_LIP_RATIO] = 137; + VisualParams[(int)AvatarAppearance.VPElement.SHAPE_MOUTH_HEIGHT] = 176; + VisualParams[(int)AvatarAppearance.VPElement.SHAPE_MOUTH_CORNER] = 140; // Sad --> happy + VisualParams[(int)AvatarAppearance.VPElement.SHAPE_LIP_CLEFT_DEEP] = 84; + VisualParams[(int)AvatarAppearance.VPElement.SHAPE_WIDE_LIP_CLEFT] = 84; + VisualParams[(int)AvatarAppearance.VPElement.SHAPE_SHIFT_MOUTH] = 127; + + + // chin + VisualParams[(int)AvatarAppearance.VPElement.SHAPE_WEAK_CHIN] = 119; + VisualParams[(int)AvatarAppearance.VPElement.SHAPE_SQUARE_JAW] = 5; + VisualParams[(int)AvatarAppearance.VPElement.SHAPE_DEEP_CHIN] = 132; + VisualParams[(int)AvatarAppearance.VPElement.SHAPE_JAW_ANGLE] = 153; + VisualParams[(int)AvatarAppearance.VPElement.SHAPE_JAW_JUT] = 100; + VisualParams[(int)AvatarAppearance.VPElement.SHAPE_JOWLS] = 38; + VisualParams[(int)AvatarAppearance.VPElement.SHAPE_CLEFT_CHIN] = 89; + VisualParams[(int)AvatarAppearance.VPElement.SHAPE_CLEFT_CHIN_UPPER] = 89; + VisualParams[(int)AvatarAppearance.VPElement.SHAPE_DOUBLE_CHIN] = 0; + + + // hair color + VisualParams[(int)AvatarAppearance.VPElement.HAIR_WHITE_HAIR] = 0; + VisualParams[(int)AvatarAppearance.VPElement.HAIR_RAINBOW_COLOR_39] = 0; + VisualParams[(int)AvatarAppearance.VPElement.HAIR_BLONDE_HAIR] = 24; + VisualParams[(int)AvatarAppearance.VPElement.HAIR_RED_HAIR] = 0; + + // hair style + VisualParams[(int)AvatarAppearance.VPElement.HAIR_HAIR_VOLUME] = 160; + VisualParams[(int)AvatarAppearance.VPElement.HAIR_HAIR_FRONT] = 153; + VisualParams[(int)AvatarAppearance.VPElement.HAIR_HAIR_SIDES] = 153; + VisualParams[(int)AvatarAppearance.VPElement.HAIR_HAIR_BACK] = 170; + VisualParams[(int)AvatarAppearance.VPElement.HAIR_HAIR_BIG_FRONT] = 0; + VisualParams[(int)AvatarAppearance.VPElement.HAIR_HAIR_BIG_TOP] = 117; + VisualParams[(int)AvatarAppearance.VPElement.HAIR_HAIR_BIG_BACK] = 170; + VisualParams[(int)AvatarAppearance.VPElement.HAIR_FRONT_FRINGE] = 0; + VisualParams[(int)AvatarAppearance.VPElement.HAIR_SIDE_FRINGE] = 142; + VisualParams[(int)AvatarAppearance.VPElement.HAIR_BACK_FRINGE] = 0; + VisualParams[(int)AvatarAppearance.VPElement.HAIR_HAIR_SIDES_FULL] = 146; + VisualParams[(int)AvatarAppearance.VPElement.HAIR_HAIR_SWEEP] = 0; + VisualParams[(int)AvatarAppearance.VPElement.HAIR_HAIR_SHEAR_FRONT] = 0; + VisualParams[(int)AvatarAppearance.VPElement.HAIR_HAIR_SHEAR_BACK] = 0; + VisualParams[(int)AvatarAppearance.VPElement.HAIR_HAIR_TAPER_FRONT] = 0; + VisualParams[(int)AvatarAppearance.VPElement.HAIR_HAIR_TAPER_BACK] = 0; + VisualParams[(int)AvatarAppearance.VPElement.HAIR_HAIR_RUMPLED] = 0; + VisualParams[(int)AvatarAppearance.VPElement.HAIR_PIGTAILS] = 0; + VisualParams[(int)AvatarAppearance.VPElement.HAIR_PONYTAIL] = 0; + VisualParams[(int)AvatarAppearance.VPElement.HAIR_HAIR_SPIKED] = 0; + VisualParams[(int)AvatarAppearance.VPElement.HAIR_HAIR_TILT] = 0; + VisualParams[(int)AvatarAppearance.VPElement.HAIR_HAIR_PART_MIDDLE] = 0; + VisualParams[(int)AvatarAppearance.VPElement.HAIR_HAIR_PART_RIGHT] = 0; + VisualParams[(int)AvatarAppearance.VPElement.HAIR_HAIR_PART_LEFT] = 0; + VisualParams[(int)AvatarAppearance.VPElement.HAIR_BANGS_PART_MIDDLE] = 155; + + //Eyebrows + VisualParams[(int)AvatarAppearance.VPElement.HAIR_EYEBROW_SIZE] = 20; + VisualParams[(int)AvatarAppearance.VPElement.HAIR_EYEBROW_DENSITY] = 140; + VisualParams[(int)AvatarAppearance.VPElement.HAIR_LOWER_EYEBROWS] = 200; // eyebrow height + VisualParams[(int)AvatarAppearance.VPElement.HAIR_ARCED_EYEBROWS] = 124; + VisualParams[(int)AvatarAppearance.VPElement.HAIR_POINTY_EYEBROWS] = 65; + + //Facial hair + VisualParams[(int)AvatarAppearance.VPElement.HAIR_HAIR_THICKNESS] = 65; + VisualParams[(int)AvatarAppearance.VPElement.HAIR_SIDEBURNS] = 235; + VisualParams[(int)AvatarAppearance.VPElement.HAIR_MOUSTACHE] = 75; + VisualParams[(int)AvatarAppearance.VPElement.HAIR_CHIN_CURTAINS] = 140; + VisualParams[(int)AvatarAppearance.VPElement.HAIR_SOULPATCH] = 0; + + AvAppearance.VisualParams = VisualParams; + + AvAppearance.SetAppearance(AvAppearance.Texture, (byte[])VisualParams.Clone()); + } + + /// + /// Test to ensure that the serialization format is the same and the underlying types don't change without notice + /// oldSerialization is just a json serialization of the OSDMap packed for the AgentCircuitData. + /// The idea is that if the current json serializer cannot parse the old serialization, then the underlying types + /// have changed and are incompatible. + /// + [Test] + public void HistoricalAgentCircuitDataOSDConversion() + { + string oldSerialization = "{\"agent_id\":\"522675bd-8214-40c1-b3ca-9c7f7fd170be\",\"base_folder\":\"c40b5f5f-476f-496b-bd69-b5a539c434d8\",\"caps_path\":\"http://www.opensimulator.org/Caps/Foo\",\"children_seeds\":[{\"handle\":\"18446744073709551615\",\"seed\":\"http://www.opensimulator.org/Caps/Foo2\"}],\"child\":false,\"circuit_code\":\"949030\",\"first_name\":\"CoolAvatarTest\",\"last_name\":\"test\",\"inventory_folder\":\"c40b5f5f-476f-496b-bd69-b5a539c434d8\",\"secure_session_id\":\"1e608e2b-0ddb-41f6-be0f-926f61cd3e0a\",\"session_id\":\"aa06f798-9d70-4bdb-9bbf-012a02ee2baf\",\"start_pos\":\"<5, 23, 125>\"}"; + AgentCircuitData Agent1Data = new AgentCircuitData(); + Agent1Data.AgentID = new UUID("522675bd-8214-40c1-b3ca-9c7f7fd170be"); + Agent1Data.Appearance = AvAppearance; + Agent1Data.BaseFolder = new UUID("c40b5f5f-476f-496b-bd69-b5a539c434d8"); + Agent1Data.CapsPath = CapsPath; + Agent1Data.child = false; + Agent1Data.ChildrenCapSeeds = ChildrenCapsPaths; + Agent1Data.circuitcode = circuitcode; + Agent1Data.firstname = firstname; + Agent1Data.InventoryFolder = new UUID("c40b5f5f-476f-496b-bd69-b5a539c434d8"); + Agent1Data.lastname = lastname; + Agent1Data.SecureSessionID = new UUID("1e608e2b-0ddb-41f6-be0f-926f61cd3e0a"); + Agent1Data.SessionID = new UUID("aa06f798-9d70-4bdb-9bbf-012a02ee2baf"); + Agent1Data.startpos = StartPos; + + + OSDMap map2; + try + { + map2 = (OSDMap) OSDParser.DeserializeJson(oldSerialization); + + + AgentCircuitData Agent2Data = new AgentCircuitData(); + Agent2Data.UnpackAgentCircuitData(map2); + + Assert.That((Agent1Data.AgentID == Agent2Data.AgentID)); + Assert.That((Agent1Data.BaseFolder == Agent2Data.BaseFolder)); + + Assert.That((Agent1Data.CapsPath == Agent2Data.CapsPath)); + Assert.That((Agent1Data.child == Agent2Data.child)); + Assert.That((Agent1Data.ChildrenCapSeeds.Count == Agent2Data.ChildrenCapSeeds.Count)); + Assert.That((Agent1Data.circuitcode == Agent2Data.circuitcode)); + Assert.That((Agent1Data.firstname == Agent2Data.firstname)); + Assert.That((Agent1Data.InventoryFolder == Agent2Data.InventoryFolder)); + Assert.That((Agent1Data.lastname == Agent2Data.lastname)); + Assert.That((Agent1Data.SecureSessionID == Agent2Data.SecureSessionID)); + Assert.That((Agent1Data.SessionID == Agent2Data.SessionID)); + Assert.That((Agent1Data.startpos == Agent2Data.startpos)); + } + catch (LitJson.JsonException) + { + //intermittant litjson errors :P + Assert.That(1 == 1); + } + /* + Enable this once VisualParams go in the packing method + for (int i=0;i<208;i++) + Assert.That((Agent1Data.Appearance.VisualParams[i] == Agent2Data.Appearance.VisualParams[i])); + */ + } + + /// + /// Test to ensure that the packing and unpacking methods work. + /// + [Test] + public void TestAgentCircuitDataOSDConversion() + { + AgentCircuitData Agent1Data = new AgentCircuitData(); + Agent1Data.AgentID = AgentId; + Agent1Data.Appearance = AvAppearance; + Agent1Data.BaseFolder = BaseFolder; + Agent1Data.CapsPath = CapsPath; + Agent1Data.child = false; + Agent1Data.ChildrenCapSeeds = ChildrenCapsPaths; + Agent1Data.circuitcode = circuitcode; + Agent1Data.firstname = firstname; + Agent1Data.InventoryFolder = BaseFolder; + Agent1Data.lastname = lastname; + Agent1Data.SecureSessionID = SecureSessionId; + Agent1Data.SessionID = SessionId; + Agent1Data.startpos = StartPos; + + EntityTransferContext ctx = new EntityTransferContext(); + OSDMap map2; + OSDMap map = Agent1Data.PackAgentCircuitData(ctx); + try + { + string str = OSDParser.SerializeJsonString(map); + //System.Console.WriteLine(str); + map2 = (OSDMap) OSDParser.DeserializeJson(str); + } + catch (System.NullReferenceException) + { + //spurious litjson errors :P + map2 = map; + Assert.That(1==1); + return; + } + + AgentCircuitData Agent2Data = new AgentCircuitData(); + Agent2Data.UnpackAgentCircuitData(map2); + + Assert.That((Agent1Data.AgentID == Agent2Data.AgentID)); + Assert.That((Agent1Data.BaseFolder == Agent2Data.BaseFolder)); + + Assert.That((Agent1Data.CapsPath == Agent2Data.CapsPath)); + Assert.That((Agent1Data.child == Agent2Data.child)); + Assert.That((Agent1Data.ChildrenCapSeeds.Count == Agent2Data.ChildrenCapSeeds.Count)); + Assert.That((Agent1Data.circuitcode == Agent2Data.circuitcode)); + Assert.That((Agent1Data.firstname == Agent2Data.firstname)); + Assert.That((Agent1Data.InventoryFolder == Agent2Data.InventoryFolder)); + Assert.That((Agent1Data.lastname == Agent2Data.lastname)); + Assert.That((Agent1Data.SecureSessionID == Agent2Data.SecureSessionID)); + Assert.That((Agent1Data.SessionID == Agent2Data.SessionID)); + Assert.That((Agent1Data.startpos == Agent2Data.startpos)); + + /* + Enable this once VisualParams go in the packing method + for (int i = 0; i < 208; i++) + Assert.That((Agent1Data.Appearance.VisualParams[i] == Agent2Data.Appearance.VisualParams[i])); + */ + + + } + } +} diff --git a/Tests/OpenSim.Framework.Tests/AgentCircuitManagerTests.cs b/Tests/OpenSim.Framework.Tests/AgentCircuitManagerTests.cs new file mode 100644 index 00000000000..2558f300385 --- /dev/null +++ b/Tests/OpenSim.Framework.Tests/AgentCircuitManagerTests.cs @@ -0,0 +1,199 @@ +/* + * 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.Collections.Generic; +using OpenMetaverse; +using NUnit.Framework; +using System; + +namespace OpenSim.Framework.Tests +{ + [TestFixture] + public class AgentCircuitManagerTests + { + private AgentCircuitData m_agentCircuitData1; + private AgentCircuitData m_agentCircuitData2; + private UUID AgentId1; + private UUID AgentId2; + private uint circuitcode1; + private uint circuitcode2; + + private UUID SessionId1; + private UUID SessionId2; + private Random rnd = new Random(Environment.TickCount); + + [SetUp] + public void setup() + { + + AgentId1 = UUID.Random(); + AgentId2 = UUID.Random(); + circuitcode1 = (uint) rnd.Next((int)uint.MinValue, int.MaxValue); + circuitcode2 = (uint) rnd.Next((int)uint.MinValue, int.MaxValue); + SessionId1 = UUID.Random(); + SessionId2 = UUID.Random(); + UUID BaseFolder = UUID.Random(); + string CapsPath = "http://www.opensimulator.org/Caps/Foo"; + Dictionary ChildrenCapsPaths = new Dictionary(); + ChildrenCapsPaths.Add(ulong.MaxValue, "http://www.opensimulator.org/Caps/Foo2"); + string firstname = "CoolAvatarTest"; + string lastname = "test"; + Vector3 StartPos = new Vector3(5, 23, 125); + + UUID SecureSessionId = UUID.Random(); + // TODO: unused: UUID SessionId = UUID.Random(); + + m_agentCircuitData1 = new AgentCircuitData(); + m_agentCircuitData1.AgentID = AgentId1; + m_agentCircuitData1.Appearance = new AvatarAppearance(); + m_agentCircuitData1.BaseFolder = BaseFolder; + m_agentCircuitData1.CapsPath = CapsPath; + m_agentCircuitData1.child = false; + m_agentCircuitData1.ChildrenCapSeeds = ChildrenCapsPaths; + m_agentCircuitData1.circuitcode = circuitcode1; + m_agentCircuitData1.firstname = firstname; + m_agentCircuitData1.InventoryFolder = BaseFolder; + m_agentCircuitData1.lastname = lastname; + m_agentCircuitData1.SecureSessionID = SecureSessionId; + m_agentCircuitData1.SessionID = SessionId1; + m_agentCircuitData1.startpos = StartPos; + + m_agentCircuitData2 = new AgentCircuitData(); + m_agentCircuitData2.AgentID = AgentId2; + m_agentCircuitData2.Appearance = new AvatarAppearance(); + m_agentCircuitData2.BaseFolder = BaseFolder; + m_agentCircuitData2.CapsPath = CapsPath; + m_agentCircuitData2.child = false; + m_agentCircuitData2.ChildrenCapSeeds = ChildrenCapsPaths; + m_agentCircuitData2.circuitcode = circuitcode2; + m_agentCircuitData2.firstname = firstname; + m_agentCircuitData2.InventoryFolder = BaseFolder; + m_agentCircuitData2.lastname = lastname; + m_agentCircuitData2.SecureSessionID = SecureSessionId; + m_agentCircuitData2.SessionID = SessionId2; + m_agentCircuitData2.startpos = StartPos; + } + + /// + /// Validate that adding the circuit works appropriately + /// + [Test] + public void AddAgentCircuitTest() + { + AgentCircuitManager agentCircuitManager = new AgentCircuitManager(); + agentCircuitManager.AddNewCircuit(circuitcode1,m_agentCircuitData1); + agentCircuitManager.AddNewCircuit(circuitcode2, m_agentCircuitData2); + AgentCircuitData agent = agentCircuitManager.GetAgentCircuitData(circuitcode1); + + Assert.That((m_agentCircuitData1.AgentID == agent.AgentID)); + Assert.That((m_agentCircuitData1.BaseFolder == agent.BaseFolder)); + + Assert.That((m_agentCircuitData1.CapsPath == agent.CapsPath)); + Assert.That((m_agentCircuitData1.child == agent.child)); + Assert.That((m_agentCircuitData1.ChildrenCapSeeds.Count == agent.ChildrenCapSeeds.Count)); + Assert.That((m_agentCircuitData1.circuitcode == agent.circuitcode)); + Assert.That((m_agentCircuitData1.firstname == agent.firstname)); + Assert.That((m_agentCircuitData1.InventoryFolder == agent.InventoryFolder)); + Assert.That((m_agentCircuitData1.lastname == agent.lastname)); + Assert.That((m_agentCircuitData1.SecureSessionID == agent.SecureSessionID)); + Assert.That((m_agentCircuitData1.SessionID == agent.SessionID)); + Assert.That((m_agentCircuitData1.startpos == agent.startpos)); + } + + /// + /// Validate that removing the circuit code removes it appropriately + /// + [Test] + public void RemoveAgentCircuitTest() + { + AgentCircuitManager agentCircuitManager = new AgentCircuitManager(); + agentCircuitManager.AddNewCircuit(circuitcode1, m_agentCircuitData1); + agentCircuitManager.AddNewCircuit(circuitcode2, m_agentCircuitData2); + agentCircuitManager.RemoveCircuit(circuitcode2); + + AgentCircuitData agent = agentCircuitManager.GetAgentCircuitData(circuitcode2); + Assert.That(agent == null); + + } + + /// + /// Validate that changing the circuit code works + /// + [Test] + public void ChangeAgentCircuitCodeTest() + { + AgentCircuitManager agentCircuitManager = new AgentCircuitManager(); + agentCircuitManager.AddNewCircuit(circuitcode1, m_agentCircuitData1); + agentCircuitManager.AddNewCircuit(circuitcode2, m_agentCircuitData2); + bool result = false; + + result = agentCircuitManager.TryChangeCircuitCode(circuitcode1, 393930); + + AgentCircuitData agent = agentCircuitManager.GetAgentCircuitData(393930); + AgentCircuitData agent2 = agentCircuitManager.GetAgentCircuitData(circuitcode1); + Assert.That(agent != null); + Assert.That(agent2 == null); + Assert.That(result); + + } + + /// + /// Validates that the login authentication scheme is working + /// First one should be authorized + /// Rest should not be authorized + /// + [Test] + public void ValidateLoginTest() + { + AgentCircuitManager agentCircuitManager = new AgentCircuitManager(); + agentCircuitManager.AddNewCircuit(circuitcode1, m_agentCircuitData1); + agentCircuitManager.AddNewCircuit(circuitcode2, m_agentCircuitData2); + + // should be authorized + AuthenticateResponse resp = agentCircuitManager.AuthenticateSession(SessionId1, AgentId1, circuitcode1); + Assert.That(resp.Authorised); + + + //should not be authorized + resp = agentCircuitManager.AuthenticateSession(SessionId1, UUID.Random(), circuitcode1); + Assert.That(!resp.Authorised); + + resp = agentCircuitManager.AuthenticateSession(UUID.Random(), AgentId1, circuitcode1); + Assert.That(!resp.Authorised); + + resp = agentCircuitManager.AuthenticateSession(SessionId1, AgentId1, circuitcode2); + Assert.That(!resp.Authorised); + + resp = agentCircuitManager.AuthenticateSession(SessionId2, AgentId1, circuitcode2); + Assert.That(!resp.Authorised); + + agentCircuitManager.RemoveCircuit(circuitcode2); + + resp = agentCircuitManager.AuthenticateSession(SessionId2, AgentId2, circuitcode2); + Assert.That(!resp.Authorised); + } + } +} diff --git a/Tests/OpenSim.Framework.Tests/AnimationTests.cs b/Tests/OpenSim.Framework.Tests/AnimationTests.cs new file mode 100644 index 00000000000..daf86118755 --- /dev/null +++ b/Tests/OpenSim.Framework.Tests/AnimationTests.cs @@ -0,0 +1,91 @@ +/* + * 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.Reflection; +using NUnit.Framework; +using OpenMetaverse; +using OpenMetaverse.StructuredData; +using OpenSim.Framework; +using OpenSim.Tests.Common; +using Animation = OpenSim.Framework.Animation; + +namespace OpenSim.Framework.Tests +{ + [TestFixture] + public class AnimationTests : OpenSimTestCase + { + private Animation anim1 = null; + private Animation anim2 = null; + private UUID animUUID1 = UUID.Zero; + private UUID objUUID1 = UUID.Zero; + private UUID animUUID2 = UUID.Zero; + private UUID objUUID2 = UUID.Zero; + + [SetUp] + public void Setup() + { + animUUID1 = UUID.Random(); + animUUID2 = UUID.Random(); + objUUID1 = UUID.Random(); + objUUID2 = UUID.Random(); + + anim1 = new Animation(animUUID1, 1, objUUID1); + anim2 = new Animation(animUUID2, 1, objUUID2); + } + + [Test] + public void AnimationOSDTest() + { + Assert.That(anim1.AnimID==animUUID1 && anim1.ObjectID == objUUID1 && anim1.SequenceNum ==1, "The Animation Constructor didn't set the fields correctly"); + OSD updateMessage = anim1.PackUpdateMessage(); + Assert.That(updateMessage is OSDMap, "Packed UpdateMessage isn't an OSDMap"); + OSDMap updateMap = (OSDMap) updateMessage; + Assert.That(updateMap.ContainsKey("animation"), "Packed Message doesn't contain an animation element"); + Assert.That(updateMap.ContainsKey("object_id"), "Packed Message doesn't contain an object_id element"); + Assert.That(updateMap.ContainsKey("seq_num"), "Packed Message doesn't contain a seq_num element"); + Assert.That(updateMap["animation"].AsUUID() == animUUID1); + Assert.That(updateMap["object_id"].AsUUID() == objUUID1); + Assert.That(updateMap["seq_num"].AsInteger() == 1); + + Animation anim3 = new Animation(updateMap); + + Assert.That(anim3.ObjectID == anim1.ObjectID && anim3.AnimID == anim1.AnimID && anim3.SequenceNum == anim1.SequenceNum, "OSDMap Constructor failed to set the properties correctly."); + + anim3.UnpackUpdateMessage(anim2.PackUpdateMessage()); + + Assert.That(anim3.ObjectID == objUUID2 && anim3.AnimID == animUUID2 && anim3.SequenceNum == 1, "Animation.UnpackUpdateMessage failed to set the properties correctly."); + + Animation anim4 = new Animation(); + anim4.AnimID = anim2.AnimID; + anim4.ObjectID = anim2.ObjectID; + anim4.SequenceNum = anim2.SequenceNum; + + Assert.That(anim4.ObjectID == objUUID2 && anim4.AnimID == animUUID2 && anim4.SequenceNum == 1, "void constructor and manual field population failed to set the properties correctly."); + } + } +} \ No newline at end of file diff --git a/Tests/OpenSim.Framework.Tests/AssetBaseTest.cs b/Tests/OpenSim.Framework.Tests/AssetBaseTest.cs new file mode 100644 index 00000000000..1975a4df7e5 --- /dev/null +++ b/Tests/OpenSim.Framework.Tests/AssetBaseTest.cs @@ -0,0 +1,72 @@ +/* + * 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 System.Text; +using NUnit.Framework; +using OpenMetaverse; +using OpenSim.Tests.Common; + +namespace OpenSim.Framework.Tests +{ + [TestFixture] + public class AssetBaseTest : OpenSimTestCase + { + [Test] + public void TestContainsReferences() + { + CheckContainsReferences(AssetType.Bodypart, true); + CheckContainsReferences(AssetType.Clothing, true); + + CheckContainsReferences(AssetType.Animation, false); + CheckContainsReferences(AssetType.CallingCard, false); + CheckContainsReferences(AssetType.Folder , false); + CheckContainsReferences(AssetType.Gesture , false); + CheckContainsReferences(AssetType.ImageJPEG , false); + CheckContainsReferences(AssetType.ImageTGA , false); + CheckContainsReferences(AssetType.Landmark , false); + CheckContainsReferences(AssetType.LSLBytecode, false); + CheckContainsReferences(AssetType.LSLText, false); + CheckContainsReferences(AssetType.Notecard, false); + CheckContainsReferences(AssetType.Object, false); + CheckContainsReferences(AssetType.Simstate, false); + CheckContainsReferences(AssetType.Sound, false); + CheckContainsReferences(AssetType.SoundWAV, false); + CheckContainsReferences(AssetType.Texture, false); + CheckContainsReferences(AssetType.TextureTGA, false); + CheckContainsReferences(AssetType.Unknown, false); + } + + private void CheckContainsReferences(AssetType assetType, bool expected) + { + AssetBase asset = new AssetBase(UUID.Zero, String.Empty, (sbyte)assetType, UUID.Zero.ToString()); + bool actual = asset.ContainsReferences; + Assert.AreEqual(expected, actual, "Expected "+assetType+".ContainsReferences to be "+expected+" but was "+actual+"."); + } + } +} diff --git a/Tests/OpenSim.Framework.Tests/CacheTests.cs b/Tests/OpenSim.Framework.Tests/CacheTests.cs new file mode 100644 index 00000000000..fc7df692b97 --- /dev/null +++ b/Tests/OpenSim.Framework.Tests/CacheTests.cs @@ -0,0 +1,125 @@ +/* + * 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 NUnit.Framework; +using OpenMetaverse; +using OpenSim.Tests.Common; + +namespace OpenSim.Framework.Tests +{ + [TestFixture] + public class CacheTests : OpenSimTestCase + { + private Cache cache; + private UUID cacheItemUUID; + [SetUp] + public void Build() + { + cache = new Cache(); + cache = new Cache(CacheMedium.Memory,CacheStrategy.Aggressive,CacheFlags.AllowUpdate); + cacheItemUUID = UUID.Random(); + MemoryCacheItem cachedItem = new MemoryCacheItem(cacheItemUUID.ToString(),DateTime.Now + TimeSpan.FromDays(1)); + byte[] foo = new byte[1]; + foo[0] = 255; + cachedItem.Store(foo); + cache.Store(cacheItemUUID.ToString(), cachedItem); + } + [Test] + public void TestRetreive() + { + CacheItemBase citem = (CacheItemBase)cache.Get(cacheItemUUID.ToString()); + byte[] data = (byte[]) citem.Retrieve(); + Assert.That(data.Length == 1, "Cached Item should have one byte element"); + Assert.That(data[0] == 255, "Cached Item element should be 255"); + } + + [Test] + public void TestNotInCache() + { + UUID randomNotIn = UUID.Random(); + while (randomNotIn == cacheItemUUID) + { + randomNotIn = UUID.Random(); + } + object citem = cache.Get(randomNotIn.ToString()); + Assert.That(citem == null, "Item should not be in Cache"); + } + + + [Test] + public void ExpireItemManually() + { + UUID ImmediateExpiryUUID = UUID.Random(); + MemoryCacheItem cachedItem = new MemoryCacheItem(ImmediateExpiryUUID.ToString(), TimeSpan.FromDays(1)); + byte[] foo = new byte[1]; + foo[0] = 1; + cachedItem.Store(foo); + cache.Store(cacheItemUUID.ToString(), cachedItem); + cache.Invalidate(cacheItemUUID.ToString()); + cache.Get(cacheItemUUID.ToString()); + object citem = cache.Get(cacheItemUUID.ToString()); + Assert.That(citem == null, "Item should not be in Cache because we manually invalidated it"); + } + + [Test] + public void ClearCacheTest() + { + UUID ImmediateExpiryUUID = UUID.Random(); + MemoryCacheItem cachedItem = new MemoryCacheItem(ImmediateExpiryUUID.ToString(), DateTime.Now - TimeSpan.FromDays(1)); + byte[] foo = new byte[1]; + foo[0] = 1; + cachedItem.Store(foo); + cache.Store(cacheItemUUID.ToString(), cachedItem); + cache.Clear(); + + object citem = cache.Get(cacheItemUUID.ToString()); + Assert.That(citem == null, "Item should not be in Cache because we manually invalidated it"); + } + + [Test] + public void CacheItemMundane() + { + UUID Random1 = UUID.Random(); + UUID Random2 = UUID.Random(); + byte[] data = Array.Empty(); + CacheItemBase cb1 = new CacheItemBase(Random1.ToString(), DateTime.Now + TimeSpan.FromDays(1)); + CacheItemBase cb2 = new CacheItemBase(Random2.ToString(), DateTime.Now + TimeSpan.FromDays(1)); + CacheItemBase cb3 = new CacheItemBase(Random1.ToString(), DateTime.Now + TimeSpan.FromDays(1)); + + cb1.Store(data); + + Assert.That(cb1.Equals(cb3), "cb1 should equal cb3, their uuids are the same"); + Assert.That(!cb2.Equals(cb1), "cb2 should not equal cb1, their uuids are NOT the same"); + Assert.That(cb1.IsLocked() == false, "CacheItemBase default is false"); + Assert.That(cb1.Retrieve() == null, "Virtual Retrieve method should return null"); + + + } + + } +} diff --git a/Tests/OpenSim.Framework.Tests/LocationTest.cs b/Tests/OpenSim.Framework.Tests/LocationTest.cs new file mode 100644 index 00000000000..5e84026708a --- /dev/null +++ b/Tests/OpenSim.Framework.Tests/LocationTest.cs @@ -0,0 +1,90 @@ +/* + * 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 NUnit.Framework; +using OpenSim.Tests.Common; + +namespace OpenSim.Framework.Tests +{ + [TestFixture] + public class LocationTest : OpenSimTestCase + { + [Test] + public void locationRegionHandleRegionHandle() + { + //1099511628032000 + // 256000 + // 256000 + Location TestLocation1 = new Location(1099511628032000); + Location TestLocation2 = new Location(1099511628032000); + Assert.That(TestLocation1 == TestLocation2); + + TestLocation1 = new Location(1099511628032001); + TestLocation2 = new Location(1099511628032000); + Assert.That(TestLocation1 != TestLocation2); + } + + [Test] + public void locationXYRegionHandle() + { + Location TestLocation1 = new Location(255000,256000); + Location TestLocation2 = new Location(1095216660736000); + Assert.That(TestLocation1 == TestLocation2); + + Assert.That(TestLocation1.X == 255000 && TestLocation1.Y == 256000, "Test xy location doesn't match position in the constructor"); + Assert.That(TestLocation2.X == 255000 && TestLocation2.Y == 256000, "Test xy location doesn't match regionhandle provided"); + + Assert.That(TestLocation2.RegionHandle == 1095216660736000, + "Location RegionHandle Property didn't match regionhandle provided in constructor"); + + ulong RegionHandle = TestLocation1.RegionHandle; + Assert.That(RegionHandle.Equals(1095216660736000), "Equals(regionhandle) failed to match the position in the constructor"); + + TestLocation2 = new Location(RegionHandle); + Assert.That(TestLocation2.Equals(255000, 256000), "Decoded regionhandle failed to match the original position in the constructor"); + + + TestLocation1 = new Location(255001, 256001); + TestLocation2 = new Location(1095216660736000); + Assert.That(TestLocation1 != TestLocation2); + + Assert.That(TestLocation1.Equals(255001, 256001), "Equals(x,y) failed to match the position in the constructor"); + + Assert.That(TestLocation2.GetHashCode() == (TestLocation2.X.GetHashCode() ^ TestLocation2.Y.GetHashCode()), "GetHashCode failed to produce the expected hashcode"); + + Location TestLocation3; + object cln = TestLocation2.Clone(); + TestLocation3 = (Location) cln; + Assert.That(TestLocation3.X == TestLocation2.X && TestLocation3.Y == TestLocation2.Y, + "Cloned Location values do not match"); + + Assert.That(TestLocation2.Equals(cln), "Cloned object failed .Equals(obj) Test"); + + } + + } +} diff --git a/Tests/OpenSim.Framework.Tests/MundaneFrameworkTests.cs b/Tests/OpenSim.Framework.Tests/MundaneFrameworkTests.cs new file mode 100644 index 00000000000..3d99c412246 --- /dev/null +++ b/Tests/OpenSim.Framework.Tests/MundaneFrameworkTests.cs @@ -0,0 +1,289 @@ +/* + * 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 NUnit.Framework; +using OpenSim.Framework; +using OpenMetaverse; +using OpenMetaverse.StructuredData; +using System; +using System.Globalization; +using System.Threading; +using OpenSim.Tests.Common; + +namespace OpenSim.Framework.Tests +{ + [TestFixture] + public class MundaneFrameworkTests : OpenSimTestCase + { + private bool m_RegionSettingsOnSaveEventFired; + + [Test] + public void ChildAgentDataUpdate01() + { + // code coverage + ChildAgentDataUpdate cadu = new ChildAgentDataUpdate(); + Assert.IsFalse(cadu.alwaysrun, "Default is false"); + } + + [Test] + public void AgentPositionTest01() + { + UUID AgentId1 = UUID.Random(); + UUID SessionId1 = UUID.Random(); + uint CircuitCode1 = uint.MinValue; + Vector3 Size1 = Vector3.UnitZ; + Vector3 Position1 = Vector3.UnitX; + Vector3 LeftAxis1 = Vector3.UnitY; + Vector3 UpAxis1 = Vector3.UnitZ; + Vector3 AtAxis1 = Vector3.UnitX; + + ulong RegionHandle1 = ulong.MinValue; + byte[] Throttles1 = new byte[] {0, 1, 0}; + + Vector3 Velocity1 = Vector3.Zero; + float Far1 = 256; + + bool ChangedGrid1 = false; + Vector3 Center1 = Vector3.Zero; + + AgentPosition position1 = new AgentPosition(); + position1.AgentID = AgentId1; + position1.SessionID = SessionId1; + position1.CircuitCode = CircuitCode1; + position1.Size = Size1; + position1.Position = Position1; + position1.LeftAxis = LeftAxis1; + position1.UpAxis = UpAxis1; + position1.AtAxis = AtAxis1; + position1.RegionHandle = RegionHandle1; + position1.Throttles = Throttles1; + position1.Velocity = Velocity1; + position1.Far = Far1; + position1.ChangedGrid = ChangedGrid1; + position1.Center = Center1; + + ChildAgentDataUpdate cadu = new ChildAgentDataUpdate(); + cadu.AgentID = AgentId1.Guid; + cadu.ActiveGroupID = UUID.Zero.Guid; + cadu.throttles = Throttles1; + cadu.drawdistance = Far1; + cadu.Position = Position1; + cadu.Velocity = Velocity1; + cadu.regionHandle = RegionHandle1; + cadu.cameraPosition = Center1; + cadu.AVHeight = Size1.Z; + + AgentPosition position2 = new AgentPosition(); + position2.CopyFrom(cadu, position1.SessionID); + + Assert.IsTrue( + position2.AgentID == position1.AgentID + && position2.Size == position1.Size + && position2.Position == position1.Position + && position2.Velocity == position1.Velocity + && position2.Center == position1.Center + && position2.RegionHandle == position1.RegionHandle + && position2.Far == position1.Far + + ,"Copy From ChildAgentDataUpdate failed"); + + position2 = new AgentPosition(); + + Assert.IsFalse(position2.AgentID == position1.AgentID, "Test Error, position2 should be a blank uninitialized AgentPosition"); + EntityTransferContext ctx = new EntityTransferContext(); + position2.Unpack(position1.Pack(ctx), null, ctx); + + Assert.IsTrue(position2.AgentID == position1.AgentID, "Agent ID didn't unpack the same way it packed"); + Assert.IsTrue(position2.Position == position1.Position, "Position didn't unpack the same way it packed"); + Assert.IsTrue(position2.Velocity == position1.Velocity, "Velocity didn't unpack the same way it packed"); + Assert.IsTrue(position2.SessionID == position1.SessionID, "SessionID didn't unpack the same way it packed"); + Assert.IsTrue(position2.CircuitCode == position1.CircuitCode, "CircuitCode didn't unpack the same way it packed"); + Assert.IsTrue(position2.LeftAxis == position1.LeftAxis, "LeftAxis didn't unpack the same way it packed"); + Assert.IsTrue(position2.UpAxis == position1.UpAxis, "UpAxis didn't unpack the same way it packed"); + Assert.IsTrue(position2.AtAxis == position1.AtAxis, "AtAxis didn't unpack the same way it packed"); + Assert.IsTrue(position2.RegionHandle == position1.RegionHandle, "RegionHandle didn't unpack the same way it packed"); + Assert.IsTrue(position2.ChangedGrid == position1.ChangedGrid, "ChangedGrid didn't unpack the same way it packed"); + Assert.IsTrue(position2.Center == position1.Center, "Center didn't unpack the same way it packed"); + Assert.IsTrue(position2.Size == position1.Size, "Size didn't unpack the same way it packed"); + + } + + [Test] + public void RegionSettingsTest01() + { + RegionSettings settings = new RegionSettings(); + settings.OnSave += RegionSaveFired; + settings.Save(); + settings.OnSave -= RegionSaveFired; + +// string str = settings.LoadedCreationDate; +// int dt = settings.LoadedCreationDateTime; +// string id = settings.LoadedCreationID; +// string time = settings.LoadedCreationTime; + + Assert.That(m_RegionSettingsOnSaveEventFired, "RegionSettings Save Event didn't Fire"); + + } + public void RegionSaveFired(RegionSettings settings) + { + m_RegionSettingsOnSaveEventFired = true; + } + + [Test] + public void InventoryItemBaseConstructorTest01() + { + InventoryItemBase b1 = new InventoryItemBase(); + Assert.That(b1.ID == UUID.Zero, "void constructor should create an inventory item with ID = UUID.Zero"); + Assert.That(b1.Owner == UUID.Zero, "void constructor should create an inventory item with Owner = UUID.Zero"); + + UUID ItemID = UUID.Random(); + UUID OwnerID = UUID.Random(); + + InventoryItemBase b2 = new InventoryItemBase(ItemID); + Assert.That(b2.ID == ItemID, "ID constructor should create an inventory item with ID = ItemID"); + Assert.That(b2.Owner == UUID.Zero, "ID constructor should create an inventory item with Owner = UUID.Zero"); + + InventoryItemBase b3 = new InventoryItemBase(ItemID,OwnerID); + Assert.That(b3.ID == ItemID, "ID,OwnerID constructor should create an inventory item with ID = ItemID"); + Assert.That(b3.Owner == OwnerID, "ID,OwnerID constructor should create an inventory item with Owner = OwnerID"); + + } + + [Test] + public void AssetMetaDataNonNullContentTypeTest01() + { + AssetMetadata assetMetadata = new AssetMetadata(); + assetMetadata.ContentType = "image/jp2"; + Assert.That(assetMetadata.Type == (sbyte)AssetType.Texture, "Content type should be AssetType.Texture"); + Assert.That(assetMetadata.ContentType == "image/jp2", "Text of content type should be image/jp2"); + UUID rndID = UUID.Random(); + assetMetadata.ID = rndID.ToString(); + Assert.That(assetMetadata.ID.ToLower() == rndID.ToString().ToLower(), "assetMetadata.ID Setter/Getter not Consistent"); + DateTime fixedTime = DateTime.Now; + assetMetadata.CreationDate = fixedTime; + } + + [Test] + public void EstateSettingsMundateTests() + { + EstateSettings es = new EstateSettings(); + es.AddBan(null); + UUID bannedUserId = UUID.Random(); + es.AddBan(new EstateBan() + { BannedHostAddress = string.Empty, + BannedHostIPMask = string.Empty, + BannedHostNameMask = string.Empty, + BannedUserID = bannedUserId} + ); + Assert.IsTrue(es.IsBanned(bannedUserId, 32), "User Should be banned but is not."); + Assert.IsFalse(es.IsBanned(UUID.Zero, 32), "User Should not be banned but is."); + + es.RemoveBan(bannedUserId); + + Assert.IsFalse(es.IsBanned(bannedUserId, 32), "User Should not be banned but is."); + + es.AddEstateManager(UUID.Zero); + + es.AddEstateManager(bannedUserId); + Assert.IsTrue(es.IsEstateManagerOrOwner(bannedUserId), "bannedUserId should be EstateManager but isn't."); + + es.RemoveEstateManager(bannedUserId); + Assert.IsFalse(es.IsEstateManagerOrOwner(bannedUserId), "bannedUserID is estateManager but shouldn't be"); + + Assert.IsFalse(es.HasAccess(bannedUserId), "bannedUserID has access but shouldn't"); + + es.AddEstateUser(bannedUserId); + + Assert.IsTrue(es.HasAccess(bannedUserId), "bannedUserID doesn't have access but should"); + es.RemoveEstateUser(bannedUserId); + + es.AddEstateManager(bannedUserId); + + Assert.IsTrue(es.HasAccess(bannedUserId), "bannedUserID doesn't have access but should"); + + Assert.That(es.EstateGroups.Length == 0, "No Estate Groups Added.. so the array should be 0 length"); + + es.AddEstateGroup(bannedUserId); + + Assert.That(es.EstateGroups.Length == 1, "1 Estate Groups Added.. so the array should be 1 length"); + + Assert.That(es.EstateGroups[0] == bannedUserId,"User ID should be in EstateGroups"); + + } + + [Test] + public void InventoryFolderBaseConstructorTest01() + { + UUID uuid1 = UUID.Random(); + UUID uuid2 = UUID.Random(); + + InventoryFolderBase fld = new InventoryFolderBase(uuid1); + Assert.That(fld.ID == uuid1, "ID constructor failed to save value in ID field."); + + fld = new InventoryFolderBase(uuid1, uuid2); + Assert.That(fld.ID == uuid1, "ID,Owner constructor failed to save value in ID field."); + Assert.That(fld.Owner == uuid2, "ID,Owner constructor failed to save value in ID field."); + } + + [Test] + public void AsssetBaseConstructorTest01() + { + AssetBase abase = new AssetBase(); + Assert.IsNotNull(abase.Metadata, "void constructor of AssetBase should have created a MetaData element but didn't."); + UUID itemID = UUID.Random(); + UUID creatorID = UUID.Random(); + abase = new AssetBase(itemID.ToString(), "test item", (sbyte) AssetType.Texture, creatorID.ToString()); + + Assert.IsNotNull(abase.Metadata, "string,string,sbyte,string constructor of AssetBase should have created a MetaData element but didn't."); + Assert.That(abase.ID == itemID.ToString(), "string,string,sbyte,string constructor failed to set ID property"); + Assert.That(abase.Metadata.CreatorID == creatorID.ToString(), "string,string,sbyte,string constructor failed to set Creator ID"); + + + abase = new AssetBase(itemID.ToString(), "test item", -1, creatorID.ToString()); + Assert.IsNotNull(abase.Metadata, "string,string,sbyte,string constructor of AssetBase with unknown type should have created a MetaData element but didn't."); + Assert.That(abase.Metadata.Type == -1, "Unknown Type passed to string,string,sbyte,string constructor and was a known type when it came out again"); + + AssetMetadata metts = new AssetMetadata(); + metts.FullID = itemID; + metts.ID = string.Empty; + metts.Name = "test item"; + abase.Metadata = metts; + + Assert.That(abase.ToString() == itemID.ToString(), "ToString is overriden to be fullID.ToString()"); + Assert.That(abase.ID == itemID.ToString(),"ID should be MetaData.FullID.ToString() when string.empty or null is provided to the ID property"); + } + + [Test] + public void CultureSetCultureTest01() + { + CultureInfo ci = new CultureInfo("en-US", false); + Culture.SetCurrentCulture(); + Assert.That(Thread.CurrentThread.CurrentCulture.Name == ci.Name, "SetCurrentCulture failed to set thread culture to en-US"); + + } + } +} diff --git a/Tests/OpenSim.Framework.Tests/OpenSim.Framework.Tests.csproj b/Tests/OpenSim.Framework.Tests/OpenSim.Framework.Tests.csproj new file mode 100644 index 00000000000..eb32413c9e5 --- /dev/null +++ b/Tests/OpenSim.Framework.Tests/OpenSim.Framework.Tests.csproj @@ -0,0 +1,39 @@ + + + net6.0 + + + + + + + + + + ..\..\..\bin\Nini.dll + False + + + ..\..\..\bin\OpenMetaverse.dll + False + + + ..\..\..\bin\OpenMetaverse.StructuredData.dll + False + + + ..\..\..\bin\OpenMetaverseTypes.dll + False + + + ..\..\..\bin\XMLRPC.dll + False + + + + + + + + + \ No newline at end of file diff --git a/Tests/OpenSim.Framework.Tests/PrimeNumberHelperTests.cs b/Tests/OpenSim.Framework.Tests/PrimeNumberHelperTests.cs new file mode 100644 index 00000000000..cc30fb97d6a --- /dev/null +++ b/Tests/OpenSim.Framework.Tests/PrimeNumberHelperTests.cs @@ -0,0 +1,144 @@ +/* + * 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.Reflection; +using NUnit.Framework; +using OpenMetaverse; +using OpenMetaverse.StructuredData; +using OpenSim.Framework; +using OpenSim.Tests.Common; + +namespace OpenSim.Framework.Tests +{ + [TestFixture] + public class PrimeNumberHelperTests : OpenSimTestCase + { + [Test] + public void TestGetPrime() + { + int prime1 = PrimeNumberHelper.GetPrime(7919); + Assert.That(prime1 == 8419, "Prime Number Get Prime Failed, 7919 is prime"); + Assert.That(PrimeNumberHelper.IsPrime(prime1),"Prime1 should be prime"); + Assert.That(PrimeNumberHelper.IsPrime(7919), "7919 is prime but is falsely failing the prime test"); + prime1 = PrimeNumberHelper.GetPrime(Int32.MaxValue - 1); + Assert.That(prime1 == -1, "prime1 should have been -1 since there are no primes between Int32.MaxValue-1 and Int32.MaxValue"); + + } + + [Test] + public void Test1000SmallPrimeNumbers() + { + int[] primes = { + 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, + 97, 101, 103, 107, 109, 113, 127, 131, 137, 139, 149, 151, 157, 163, 167, 173, 179, 181, 191 + , 193, 197, 199, 211, 223, 227, 229, 233, 239, 241, 251, 257, 263, 269, 271, 277, 281, 283, + 293, 307, 311, 313, 317, 331, 337, 347, 349, 353, 359, 367, 373, 379, 383, 389, 397, 401, + 409, 419, 421, 431, 433, 439, 443, 449, 457, 461, 463, 467, 479, 487, 491, 499, 503, 509, + 521, 523, 541, 547, 557, 563, 569, 571, 577, 587, 593, 599, 601, 607, 613, 617, 619, 631, + 641, 643, 647, 653, 659, 661, 673, 677, 683, 691, 701, 709, 719, 727, 733, 739, 743, 751, + 757, 761, 769, 773, 787, 797, 809, 811, 821, 823, 827, 829, 839, 853, 857, 859, 863, 877, + 881, 883, 887, 907, 911, 919, 929, 937, 941, 947, 953, 967, 971, 977, 983, 991, 997, 1009, + 1013, 1019, 1021, 1031, 1033, 1039, 1049, 1051, 1061, 1063, 1069, 1087, 1091, 1093, 1097, + 1103, 1109, 1117, 1123, 1129, 1151, 1153, 1163, 1171, 1181, 1187, 1193, 1201, 1213, 1217, + 1223, 1229, 1231, 1237, 1249, 1259, 1277, 1279, 1283, 1289, 1291, 1297, 1301, 1303, 1307, + 1319, 1321, 1327, 1361, 1367, 1373, 1381, 1399, 1409, 1423, 1427, 1429, 1433, 1439, 1447, + 1451, 1453, 1459, 1471, 1481, 1483, 1487, 1489, 1493, 1499, 1511, 1523, 1531, 1543, 1549, + 1553, 1559, 1567, 1571, 1579, 1583, 1597, 1601, 1607, 1609, 1613, 1619, 1621, 1627, 1637, + 1657, 1663, 1667, 1669, 1693, 1697, 1699, 1709, 1721, 1723, 1733, 1741, 1747, 1753, 1759, + 1777, 1783, 1787, 1789, 1801, 1811, 1823, 1831, 1847, 1861, 1867, 1871, 1873, 1877, 1879, + 1889, 1901, 1907, 1913, 1931, 1933, 1949, 1951, 1973, 1979, 1987, 1993, 1997, 1999, 2003, + 2011, 2017, 2027, 2029, 2039, 2053, 2063, 2069, 2081, 2083, 2087, 2089, 2099, 2111, 2113, + 2129, 2131, 2137, 2141, 2143, 2153, 2161, 2179, 2203, 2207, 2213, 2221, 2237, 2239, 2243, + 2251, 2267, 2269, 2273, 2281, 2287, 2293, 2297, 2309, 2311, 2333, 2339, 2341, 2347, 2351, + 2357, 2371, 2377, 2381, 2383, 2389, 2393, 2399, 2411, 2417, 2423, 2437, 2441, 2447, 2459, + 2467, 2473, 2477, 2503, 2521, 2531, 2539, 2543, 2549, 2551, 2557, 2579, 2591, 2593, 2609, + 2617, 2621, 2633, 2647, 2657, 2659, 2663, 2671, 2677, 2683, 2687, 2689, 2693, 2699, 2707, + 2711, 2713, 2719, 2729, 2731, 2741, 2749, 2753, 2767, 2777, 2789, 2791, 2797, 2801, 2803, + 2819, 2833, 2837, 2843, 2851, 2857, 2861, 2879, 2887, 2897, 2903, 2909, 2917, 2927, 2939, + 2953, 2957, 2963, 2969, 2971, 2999, 3001, 3011, 3019, 3023, 3037, 3041, 3049, 3061, 3067, + 3079, 3083, 3089, 3109, 3119, 3121, 3137, 3163, 3167, 3169, 3181, 3187, 3191, 3203, 3209, + 3217, 3221, 3229, 3251, 3253, 3257, 3259, 3271, 3299, 3301, 3307, 3313, 3319, 3323, 3329, + 3331, 3343, 3347, 3359, 3361, 3371, 3373, 3389, 3391, 3407, 3413, 3433, 3449, 3457, 3461, + 3463, 3467, 3469, 3491, 3499, 3511, 3517, 3527, 3529, 3533, 3539, 3541, 3547, 3557, 3559, + 3571, 3581, 3583, 3593, 3607, 3613, 3617, 3623, 3631, 3637, 3643, 3659, 3671, 3673, 3677, + 3691, 3697, 3701, 3709, 3719, 3727, 3733, 3739, 3761, 3767, 3769, 3779, 3793, 3797, 3803, + 3821, 3823, 3833, 3847, 3851, 3853, 3863, 3877, 3881, 3889, 3907, 3911, 3917, 3919, 3923, + 3929, 3931, 3943, 3947, 3967, 3989, 4001, 4003, 4007, 4013, 4019, 4021, 4027, 4049, 4051, + 4057, 4073, 4079, 4091, 4093, 4099, 4111, 4127, 4129, 4133, 4139, 4153, 4157, 4159, 4177, + 4201, 4211, 4217, 4219, 4229, 4231, 4241, 4243, 4253, 4259, 4261, 4271, 4273, 4283, 4289, + 4297, 4327, 4337, 4339, 4349, 4357, 4363, 4373, 4391, 4397, 4409, 4421, 4423, 4441, 4447, + 4451, 4457, 4463, 4481, 4483, 4493, 4507, 4513, 4517, 4519, 4523, 4547, 4549, 4561, 4567, + 4583, 4591, 4597, 4603, 4621, 4637, 4639, 4643, 4649, 4651, 4657, 4663, 4673, 4679, 4691, + 4703, 4721, 4723, 4729, 4733, 4751, 4759, 4783, 4787, 4789, 4793, 4799, 4801, 4813, 4817, + 4831, 4861, 4871, 4877, 4889, 4903, 4909, 4919, 4931, 4933, 4937, 4943, 4951, 4957, 4967, + 4969, 4973, 4987, 4993, 4999, 5003, 5009, 5011, 5021, 5023, 5039, 5051, 5059, 5077, 5081, + 5087, 5099, 5101, 5107, 5113, 5119, 5147, 5153, 5167, 5171, 5179, 5189, 5197, 5209, 5227, + 5231, 5233, 5237, 5261, 5273, 5279, 5281, 5297, 5303, 5309, 5323, 5333, 5347, 5351, 5381, + 5387, 5393, 5399, 5407, 5413, 5417, 5419, 5431, 5437, 5441, 5443, 5449, 5471, 5477, 5479, + 5483, 5501, 5503, 5507, 5519, 5521, 5527, 5531, 5557, 5563, 5569, 5573, 5581, 5591, 5623, + 5639, 5641, 5647, 5651, 5653, 5657, 5659, 5669, 5683, 5689, 5693, 5701, 5711, 5717, 5737, + 5741, 5743, 5749, 5779, 5783, 5791, 5801, 5807, 5813, 5821, 5827, 5839, 5843, 5849, 5851, + 5857, 5861, 5867, 5869, 5879, 5881, 5897, 5903, 5923, 5927, 5939, 5953, 5981, 5987, 6007, + 6011, 6029, 6037, 6043, 6047, 6053, 6067, 6073, 6079, 6089, 6091, 6101, 6113, 6121, 6131, + 6133, 6143, 6151, 6163, 6173, 6197, 6199, 6203, 6211, 6217, 6221, 6229, 6247, 6257, 6263, + 6269, 6271, 6277, 6287, 6299, 6301, 6311, 6317, 6323, 6329, 6337, 6343, 6353, 6359, 6361, + 6367, 6373, 6379, 6389, 6397, 6421, 6427, 6449, 6451, 6469, 6473, 6481, 6491, 6521, 6529, + 6547, 6551, 6553, 6563, 6569, 6571, 6577, 6581, 6599, 6607, 6619, 6637, 6653, 6659, 6661, + 6673, 6679, 6689, 6691, 6701, 6703, 6709, 6719, 6733, 6737, 6761, 6763, 6779, 6781, 6791, + 6793, 6803, 6823, 6827, 6829, 6833, 6841, 6857, 6863, 6869, 6871, 6883, 6899, 6907, 6911, + 6917, 6947, 6949, 6959, 6961, 6967, 6971, 6977, 6983, 6991, 6997, 7001, 7013, 7019, 7027, + 7039, 7043, 7057, 7069, 7079, 7103, 7109, 7121, 7127, 7129, 7151, 7159, 7177, 7187, 7193, + 7207, 7211, 7213, 7219, 7229, 7237, 7243, 7247, 7253, 7283, 7297, 7307, 7309, 7321, 7331, + 7333, 7349, 7351, 7369, 7393, 7411, 7417, 7433, 7451, 7457, 7459, 7477, 7481, 7487, 7489, + 7499, 7507, 7517, 7523, 7529, 7537, 7541, 7547, 7549, 7559, 7561, 7573, 7577, 7583, 7589, + 7591, 7603, 7607, 7621, 7639, 7643, 7649, 7669, 7673, 7681, 7687, 7691, 7699, 7703, 7717, + 7723, 7727, 7741, 7753, 7757, 7759, 7789, 7793, 7817, 7823, 7829, 7841, 7853, 7867, 7873, + 7877, 7879, 7883, 7901, 7907, 7919 + }; + for (int i = 0; i < primes.Length; i++) + { + Assert.That(PrimeNumberHelper.IsPrime(primes[i]),primes[i] + " is prime but is erroniously failing the prime test"); + } + + int[] nonprimes = { + 4, 6, 8, 10, 14, 16, 18, 22, 28, 30, 36, 40, 42, 46, 52, 58, 60, 66, 70, 72, 78, 82, 88, + 96, 366, 372, 378, 382, 388, 396, 400, 408, 418, 420, 430, 432, 438, 442, 448, 456, 460, 462, + 466, 478, 486, 490, 498, 502, 508, 856, 858, 862, 876, 880, 882, 886, 906, 910, 918, 928, 936, + 940, 946, 952, 966, 970, 976, 982, 990, 996, 1008, 1740, 1746, 1752, 1758, 4650, 4656, 4662, + 4672, 4678, 4690, 7740, 7752, 7756, 7758, 7788, 7792, 7816, 7822, 7828, 7840, 7852, 7866, 7872, + 7876, 7878, 7882, 7900, 7906, 7918 + }; + for (int i = 0; i < nonprimes.Length; i++) + { + Assert.That(!PrimeNumberHelper.IsPrime(nonprimes[i]), nonprimes[i] + " is not prime but is erroniously passing the prime test"); + } + + Assert.That(PrimeNumberHelper.IsPrime(3)); + } + } +} \ No newline at end of file diff --git a/Tests/OpenSim.Framework.Tests/UtilTest.cs b/Tests/OpenSim.Framework.Tests/UtilTest.cs new file mode 100644 index 00000000000..b3d79eec971 --- /dev/null +++ b/Tests/OpenSim.Framework.Tests/UtilTest.cs @@ -0,0 +1,360 @@ +/* + * 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 NUnit.Framework; +using OpenMetaverse; +using OpenSim.Tests.Common; + +namespace OpenSim.Framework.Tests +{ + [TestFixture] + public class UtilTests : OpenSimTestCase + { + [Test] + public void VectorOperationTests() + { + Vector3 v1, v2; + double expectedDistance; + double expectedMagnitude; + double lowPrecisionTolerance = 0.001; + + //Lets test a simple case of <0,0,0> and <5,5,5> + { + v1 = new Vector3(0, 0, 0); + v2 = new Vector3(5, 5, 5); + expectedDistance = 8.66; + Assert.That(Util.GetDistanceTo(v1, v2), + new DoubleToleranceConstraint(expectedDistance, lowPrecisionTolerance), + "Calculated distance between two vectors was not within tolerances."); + + expectedMagnitude = 0; + Assert.That(Util.GetMagnitude(v1), Is.EqualTo(0), "Magnitude of null vector was not zero."); + + expectedMagnitude = 8.66; + Assert.That(Util.GetMagnitude(v2), + new DoubleToleranceConstraint(expectedMagnitude, lowPrecisionTolerance), + "Magnitude of vector was incorrect."); +/* + TestDelegate d = delegate() { Util.GetNormalizedVector(v1); }; + bool causesArgumentException = TestHelpers.AssertThisDelegateCausesArgumentException(d); + Assert.That(causesArgumentException, Is.True, + "Getting magnitude of null vector did not cause argument exception."); +*/ + Vector3 expectedNormalizedVector = new Vector3(.577f, .577f, .577f); + double expectedNormalizedMagnitude = 1; + Vector3 normalizedVector = Util.GetNormalizedVector(v2); + Assert.That(normalizedVector, + new VectorToleranceConstraint(expectedNormalizedVector, lowPrecisionTolerance), + "Normalized vector generated from vector was not what was expected."); + Assert.That(Util.GetMagnitude(normalizedVector), + new DoubleToleranceConstraint(expectedNormalizedMagnitude, lowPrecisionTolerance), + "Normalized vector generated from vector does not have magnitude of 1."); + } + + //Lets test a simple case of <0,0,0> and <0,0,0> + { + v1 = new Vector3(0, 0, 0); + v2 = new Vector3(0, 0, 0); + expectedDistance = 0; + Assert.That(Util.GetDistanceTo(v1, v2), + new DoubleToleranceConstraint(expectedDistance, lowPrecisionTolerance), + "Calculated distance between two vectors was not within tolerances."); + + expectedMagnitude = 0; + Assert.That(Util.GetMagnitude(v1), Is.EqualTo(0), "Magnitude of null vector was not zero."); + + expectedMagnitude = 0; + Assert.That(Util.GetMagnitude(v2), + new DoubleToleranceConstraint(expectedMagnitude, lowPrecisionTolerance), + "Magnitude of vector was incorrect."); +/* + TestDelegate d = delegate() { Util.GetNormalizedVector(v1); }; + bool causesArgumentException = TestHelpers.AssertThisDelegateCausesArgumentException(d); + Assert.That(causesArgumentException, Is.True, + "Getting magnitude of null vector did not cause argument exception."); + + d = delegate() { Util.GetNormalizedVector(v2); }; + causesArgumentException = TestHelpers.AssertThisDelegateCausesArgumentException(d); + Assert.That(causesArgumentException, Is.True, + "Getting magnitude of null vector did not cause argument exception."); +*/ + } + + //Lets test a simple case of <0,0,0> and <-5,-5,-5> + { + v1 = new Vector3(0, 0, 0); + v2 = new Vector3(-5, -5, -5); + expectedDistance = 8.66; + Assert.That(Util.GetDistanceTo(v1, v2), + new DoubleToleranceConstraint(expectedDistance, lowPrecisionTolerance), + "Calculated distance between two vectors was not within tolerances."); + + expectedMagnitude = 0; + Assert.That(Util.GetMagnitude(v1), Is.EqualTo(0), "Magnitude of null vector was not zero."); + + expectedMagnitude = 8.66; + Assert.That(Util.GetMagnitude(v2), + new DoubleToleranceConstraint(expectedMagnitude, lowPrecisionTolerance), + "Magnitude of vector was incorrect."); +/* + TestDelegate d = delegate() { Util.GetNormalizedVector(v1); }; + bool causesArgumentException = TestHelpers.AssertThisDelegateCausesArgumentException(d); + Assert.That(causesArgumentException, Is.True, + "Getting magnitude of null vector did not cause argument exception."); +*/ + Vector3 expectedNormalizedVector = new Vector3(-.577f, -.577f, -.577f); + double expectedNormalizedMagnitude = 1; + Vector3 normalizedVector = Util.GetNormalizedVector(v2); + Assert.That(normalizedVector, + new VectorToleranceConstraint(expectedNormalizedVector, lowPrecisionTolerance), + "Normalized vector generated from vector was not what was expected."); + Assert.That(Util.GetMagnitude(normalizedVector), + new DoubleToleranceConstraint(expectedNormalizedMagnitude, lowPrecisionTolerance), + "Normalized vector generated from vector does not have magnitude of 1."); + } + } + + [Test] + public void UUIDTests() + { + Assert.IsTrue(Util.isUUID("01234567-89ab-Cdef-0123-456789AbCdEf"), + "A correct UUID wasn't recognized."); + Assert.IsFalse(Util.isUUID("FOOBAR67-89ab-Cdef-0123-456789AbCdEf"), + "UUIDs with non-hex characters are recognized as correct UUIDs."); + Assert.IsFalse(Util.isUUID("01234567"), + "Too short UUIDs are recognized as correct UUIDs."); + Assert.IsFalse(Util.isUUID("01234567-89ab-Cdef-0123-456789AbCdEf0"), + "Too long UUIDs are recognized as correct UUIDs."); + Assert.IsFalse(Util.isUUID("01234567-89ab-Cdef-0123+456789AbCdEf"), + "UUIDs with wrong format are recognized as correct UUIDs."); + } + + [Test] + public void GetHashGuidTests() + { + string string1 = "This is one string"; + string string2 = "This is another"; + + // Two consecutive runs should equal the same + Assert.AreEqual(Util.GetHashGuid(string1, "secret1"), Util.GetHashGuid(string1, "secret1")); + Assert.AreEqual(Util.GetHashGuid(string2, "secret1"), Util.GetHashGuid(string2, "secret1")); + + // Varying data should not eqal the same + Assert.AreNotEqual(Util.GetHashGuid(string1, "secret1"), Util.GetHashGuid(string2, "secret1")); + + // Varying secrets should not eqal the same + Assert.AreNotEqual(Util.GetHashGuid(string1, "secret1"), Util.GetHashGuid(string1, "secret2")); + } + + [Test] + public void SLUtilTypeConvertTests() + { + int[] assettypes = new int[]{-1,0,1,2,3,5,6,7,8,10,11,12,13,17,18,19,20,21,22 + ,24,25}; + string[] contenttypes = new string[] + { + "application/octet-stream", + "image/x-j2c", + "audio/ogg", + "application/vnd.ll.callingcard", + "application/vnd.ll.landmark", + "application/vnd.ll.clothing", + "application/vnd.ll.primitive", + "application/vnd.ll.notecard", + "application/vnd.ll.folder", + "application/vnd.ll.lsltext", + "application/vnd.ll.lslbyte", + "image/tga", + "application/vnd.ll.bodypart", + "audio/x-wav", + "image/tga", + "image/jpeg", + "application/vnd.ll.animation", + "application/vnd.ll.gesture", + "application/x-metaverse-simstate", + "application/vnd.ll.link", + "application/vnd.ll.linkfolder", + }; + for (int i=0;i + /// NPC performance tests + /// + /// + /// Don't rely on the numbers given by these tests - they will vary a lot depending on what is already cached, + /// how much memory is free, etc. In some cases, later larger tests will apparently take less time than smaller + /// earlier tests. + /// + [TestFixture] + public class NPCPerformanceTests : OpenSimTestCase + { + private TestScene scene; + private AvatarFactoryModule afm; + private UserManagementModule umm; + private AttachmentsModule am; + + [OneTimeSetUp] + public void FixtureInit() + { + // Don't allow tests to be bamboozled by asynchronous events. Execute everything on the same thread. + Util.FireAndForgetMethod = FireAndForgetMethod.None; + } + + [OneTimeTearDown] + public void TearDown() + { + scene.Close(); + scene = null; + GC.Collect(); + GC.WaitForPendingFinalizers(); + + // We must set this back afterwards, otherwise later tests will fail since they're expecting multiple + // threads. Possibly, later tests should be rewritten not to worry about such things. + Util.FireAndForgetMethod = Util.DefaultFireAndForgetMethod; + } + + [SetUp] + public void Init() + { + IConfigSource config = new IniConfigSource(); + config.AddConfig("NPC"); + config.Configs["NPC"].Set("Enabled", "true"); + config.AddConfig("Modules"); + config.Configs["Modules"].Set("InventoryAccessModule", "BasicInventoryAccessModule"); + + afm = new AvatarFactoryModule(); + umm = new UserManagementModule(); + am = new AttachmentsModule(); + + scene = new SceneHelpers().SetupScene(); + SceneHelpers.SetupSceneModules(scene, config, afm, umm, am, new BasicInventoryAccessModule(), new NPCModule()); + } + + [Test] + public void Test_0001_AddRemove100NPCs() + { + TestHelpers.InMethod(); +// log4net.Config.XmlConfigurator.Configure(); + + TestAddRemoveNPCs(100); + } + + [Test] + public void Test_0002_AddRemove1000NPCs() + { + TestHelpers.InMethod(); +// log4net.Config.XmlConfigurator.Configure(); + + TestAddRemoveNPCs(1000); + } + + [Test] + public void Test_0003_AddRemove2000NPCs() + { + TestHelpers.InMethod(); +// log4net.Config.XmlConfigurator.Configure(); + + TestAddRemoveNPCs(2000); + } + + private void TestAddRemoveNPCs(int numberOfNpcs) + { + ScenePresence sp = SceneHelpers.AddScenePresence(scene, TestHelpers.ParseTail(0x1)); +// ScenePresence originalAvatar = scene.GetScenePresence(originalClient.AgentId); + + // 8 is the index of the first baked texture in AvatarAppearance + UUID originalFace8TextureId = TestHelpers.ParseTail(0x10); + Primitive.TextureEntry originalTe = new Primitive.TextureEntry(UUID.Zero); + Primitive.TextureEntryFace originalTef = originalTe.CreateFace(8); + originalTef.TextureID = originalFace8TextureId; + + // We also need to add the texture to the asset service, otherwise the AvatarFactoryModule will tell + // ScenePresence.SendInitialData() to reset our entire appearance. + scene.AssetService.Store(AssetHelpers.CreateNotecardAsset(originalFace8TextureId)); + + afm.SetAppearance(sp, originalTe, null, new WearableCacheItem[0]); + + INPCModule npcModule = scene.RequestModuleInterface(); + + List npcs = new List(); + + long startGcMemory = GC.GetTotalMemory(true); + Stopwatch sw = new Stopwatch(); + sw.Start(); + + for (int i = 0; i < numberOfNpcs; i++) + { + npcs.Add( + npcModule.CreateNPC("John", "Smith", new Vector3(128, 128, 30), UUID.Zero, true, scene, sp.Appearance)); + } + + for (int i = 0; i < numberOfNpcs; i++) + { + Assert.That(npcs[i], Is.Not.Null); + + ScenePresence npc = scene.GetScenePresence(npcs[i]); + Assert.That(npc, Is.Not.Null); + } + + for (int i = 0; i < numberOfNpcs; i++) + { + Assert.That(npcModule.DeleteNPC(npcs[i], scene), Is.True); + ScenePresence npc = scene.GetScenePresence(npcs[i]); + Assert.That(npc, Is.Null); + } + + sw.Stop(); + + long endGcMemory = GC.GetTotalMemory(true); + + Console.WriteLine("Took {0} ms", sw.ElapsedMilliseconds); + Console.WriteLine( + "End {0} MB, Start {1} MB, Diff {2} MB", + endGcMemory / 1024 / 1024, + startGcMemory / 1024 / 1024, + (endGcMemory - startGcMemory) / 1024 / 1024); + } + } +} diff --git a/Tests/OpenSim.Performance.Tests/ObjectPerformanceTests.cs b/Tests/OpenSim.Performance.Tests/ObjectPerformanceTests.cs new file mode 100644 index 00000000000..9dad423a5fe --- /dev/null +++ b/Tests/OpenSim.Performance.Tests/ObjectPerformanceTests.cs @@ -0,0 +1,174 @@ +/* + * 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.Diagnostics; +using System.Reflection; +using log4net; +using NUnit.Framework; +using OpenMetaverse; +using OpenSim.Framework; +using OpenSim.Region.Framework.Scenes; +using OpenSim.Tests.Common; + +namespace OpenSim.Tests.Performance +{ + /// + /// Object performance tests + /// + /// + /// Don't rely on the numbers given by these tests - they will vary a lot depending on what is already cached, + /// how much memory is free, etc. In some cases, later larger tests will apparently take less time than smaller + /// earlier tests. + /// + [TestFixture] + public class ObjectPerformanceTests : OpenSimTestCase + { + [TearDown] + public void TearDown() + { + GC.Collect(); + GC.WaitForPendingFinalizers(); + } + +// [Test] +// public void Test0000Clean() +// { +// TestHelpers.InMethod(); +//// log4net.Config.XmlConfigurator.Configure(); +// +// TestAddObjects(200000); +// } + + [Test] + public void Test_0001_10K_1PrimObjects() + { + TestHelpers.InMethod(); +// log4net.Config.XmlConfigurator.Configure(); + + TestAddObjects(1, 10000); + } + + [Test] + public void Test_0002_100K_1PrimObjects() + { + TestHelpers.InMethod(); +// log4net.Config.XmlConfigurator.Configure(); + + TestAddObjects(1, 100000); + } + + [Test] + public void Test_0003_200K_1PrimObjects() + { + TestHelpers.InMethod(); +// log4net.Config.XmlConfigurator.Configure(); + + TestAddObjects(1, 200000); + } + + [Test] + public void Test_0011_100_100PrimObjects() + { + TestHelpers.InMethod(); +// log4net.Config.XmlConfigurator.Configure(); + + TestAddObjects(100, 100); + } + + [Test] + public void Test_0012_1K_100PrimObjects() + { + TestHelpers.InMethod(); +// log4net.Config.XmlConfigurator.Configure(); + + TestAddObjects(100, 1000); + } + + [Test] + public void Test_0013_2K_100PrimObjects() + { + TestHelpers.InMethod(); +// log4net.Config.XmlConfigurator.Configure(); + + TestAddObjects(100, 2000); + } + + private void TestAddObjects(int primsInEachObject, int objectsToAdd) + { + UUID ownerId = new UUID("F0000000-0000-0000-0000-000000000000"); + + // Using a local variable for scene, at least on mono 2.6.7, means that it's much more likely to be garbage + // collected when we teardown this test. If it's done in a member variable, even if that is subsequently + // nulled out, the garbage collect can be delayed. + TestScene scene = new SceneHelpers().SetupScene(); + +// Process process = Process.GetCurrentProcess(); +// long startProcessMemory = process.PrivateMemorySize64; + long startGcMemory = GC.GetTotalMemory(true); + DateTime start = DateTime.Now; + + for (int i = 1; i <= objectsToAdd; i++) + { + SceneObjectGroup so = SceneHelpers.CreateSceneObject(primsInEachObject, ownerId, "part_", i); + Assert.That(scene.AddNewSceneObject(so, false), Is.True, string.Format("Object {0} was not created", i)); + } + + TimeSpan elapsed = DateTime.Now - start; +// long processMemoryAlloc = process.PrivateMemorySize64 - startProcessMemory; + long endGcMemory = GC.GetTotalMemory(false); + + for (int i = 1; i <= objectsToAdd; i++) + { + Assert.That( + scene.GetSceneObjectGroup(TestHelpers.ParseTail(i)), + Is.Not.Null, + string.Format("Object {0} could not be retrieved", i)); + } + + // When a scene object is added to a scene, it is placed in the update list for sending to viewers + // (though in this case we have none). When it is deleted, it is not removed from the update which is + // fine since it will later be ignored. + // + // However, that means that we need to manually run an update here to clear out that list so that deleted + // objects will be clean up by the garbage collector before the next stress test is run. + scene.Update(1); + + Console.WriteLine( + "Took {0}ms, {1}MB ({2} - {3}) to create {4} objects each containing {5} prim(s)", + Math.Round(elapsed.TotalMilliseconds), + (endGcMemory - startGcMemory) / 1024 / 1024, + endGcMemory / 1024 / 1024, + startGcMemory / 1024 / 1024, + objectsToAdd, + primsInEachObject); + + scene.Close(); +// scene = null; + } + } +} \ No newline at end of file diff --git a/Tests/OpenSim.Performance.Tests/OpenSim.Tests.Performance.csproj b/Tests/OpenSim.Performance.Tests/OpenSim.Tests.Performance.csproj new file mode 100644 index 00000000000..b393c77af9d --- /dev/null +++ b/Tests/OpenSim.Performance.Tests/OpenSim.Tests.Performance.csproj @@ -0,0 +1,45 @@ + + + net6.0 + + + + + + + + + + ..\..\..\bin\Nini.dll + False + + + ..\..\..\bin\OpenMetaverse.dll + False + + + ..\..\..\bin\OpenMetaverse.StructuredData.dll + False + + + ..\..\..\bin\OpenMetaverseTypes.dll + False + + + ..\..\..\bin\XMLRPC.dll + False + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Tests/OpenSim.Performance.Tests/ScriptPerformanceTests.cs b/Tests/OpenSim.Performance.Tests/ScriptPerformanceTests.cs new file mode 100644 index 00000000000..550771d34c7 --- /dev/null +++ b/Tests/OpenSim.Performance.Tests/ScriptPerformanceTests.cs @@ -0,0 +1,169 @@ +/* + * 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 System.Diagnostics; +using System.Reflection; +using System.Threading; +using log4net; +using Nini.Config; +using NUnit.Framework; +using OpenMetaverse; +using OpenSim.Framework; +using OpenSim.Region.CoreModules.Scripting.WorldComm; +using OpenSim.Region.Framework.Interfaces; +using OpenSim.Region.Framework.Scenes; +using OpenSim.Region.ScriptEngine.XEngine; +using OpenSim.Tests.Common; + +namespace OpenSim.Tests.Performance +{ + /// + /// Script performance tests + /// + /// + /// Don't rely on the numbers given by these tests - they will vary a lot depending on what is already cached, + /// how much memory is free, etc. In some cases, later larger tests will apparently take less time than smaller + /// earlier tests. + /// + [TestFixture] + public class ScriptPerformanceTests : OpenSimTestCase + { + /* + * private TestScene m_scene; + private XEngine m_xEngine; + private AutoResetEvent m_chatEvent = new AutoResetEvent(false); + + private int m_expectedChatMessages; + private List m_osChatMessagesReceived = new List(); + + [SetUp] + public void Init() + { + //AppDomain.CurrentDomain.SetData("APPBASE", Environment.CurrentDirectory + "/bin"); +// Console.WriteLine(AppDomain.CurrentDomain.BaseDirectory); + m_xEngine = new XEngine(); + + // Necessary to stop serialization complaining + WorldCommModule wcModule = new WorldCommModule(); + + IniConfigSource configSource = new IniConfigSource(); + + IConfig startupConfig = configSource.AddConfig("Startup"); + startupConfig.Set("DefaultScriptEngine", "XEngine"); + + IConfig xEngineConfig = configSource.AddConfig("XEngine"); + xEngineConfig.Set("Enabled", "true"); + + // 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"); + + m_scene = new SceneHelpers().SetupScene("My Test", UUID.Random(), 1000, 1000, configSource); + SceneHelpers.SetupSceneModules(m_scene, configSource, m_xEngine, wcModule); + + m_scene.EventManager.OnChatFromWorld += OnChatFromWorld; + m_scene.StartScripts(); + } + + [TearDown] + public void TearDown() + { + m_scene.Close(); + m_scene = null; + GC.Collect(); + GC.WaitForPendingFinalizers(); + } + + [Test] + public void TestCompileAndStart100Scripts() + { + TestHelpers.InMethod(); + log4net.Config.XmlConfigurator.Configure(); + + TestCompileAndStartScripts(100); + } + + private void TestCompileAndStartScripts(int scriptsToCreate) + { + UUID userId = TestHelpers.ParseTail(0x1); + + m_expectedChatMessages = scriptsToCreate; + int startingObjectIdTail = 0x100; + + GC.Collect(); + + for (int idTail = startingObjectIdTail;idTail < startingObjectIdTail + scriptsToCreate; idTail++) + { + AddObjectAndScript(idTail, userId); + } + + m_chatEvent.WaitOne(40000 + scriptsToCreate * 1000); + + Assert.That(m_osChatMessagesReceived.Count, Is.EqualTo(m_expectedChatMessages)); + + foreach (OSChatMessage msg in m_osChatMessagesReceived) + Assert.That( + msg.Message, + Is.EqualTo("Script running"), + string.Format( + "Message from {0} was {1} rather than {2}", msg.SenderUUID, msg.Message, "Script running")); + } + + private void AddObjectAndScript(int objectIdTail, UUID userId) + { +// UUID itemId = TestHelpers.ParseTail(0x3); + string itemName = string.Format("AddObjectAndScript() Item for object {0}", objectIdTail); + + SceneObjectGroup so = SceneHelpers.CreateSceneObject(1, userId, "AddObjectAndScriptPart_", objectIdTail); + m_scene.AddNewSceneObject(so, true); + + InventoryItemBase itemTemplate = new InventoryItemBase(); +// itemTemplate.ID = itemId; + itemTemplate.Name = itemName; + itemTemplate.Folder = so.UUID; + itemTemplate.InvType = (int)InventoryType.LSL; + + m_scene.RezNewScript(userId, itemTemplate); + } + + private void OnChatFromWorld(object sender, OSChatMessage oscm) + { +// Console.WriteLine("Got chat [{0}]", oscm.Message); + + lock (m_osChatMessagesReceived) + { + m_osChatMessagesReceived.Add(oscm); + + if (m_osChatMessagesReceived.Count == m_expectedChatMessages) + m_chatEvent.Set(); + } + } + } + */ +} \ No newline at end of file diff --git a/Tests/OpenSim.Permissions.Tests/Common.cs b/Tests/OpenSim.Permissions.Tests/Common.cs new file mode 100644 index 00000000000..90a3dce1b3c --- /dev/null +++ b/Tests/OpenSim.Permissions.Tests/Common.cs @@ -0,0 +1,374 @@ +/* + * 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 System.Threading; +using Nini.Config; +using NUnit.Framework; +using OpenMetaverse; +using OpenSim.Framework; +using OpenSim.Region.Framework.Scenes; +using OpenSim.Region.CoreModules.World.Permissions; +using OpenSim.Region.CoreModules.Avatar.Inventory.Transfer; +using OpenSim.Region.CoreModules.Framework.InventoryAccess; +using OpenSim.Services.Interfaces; +using OpenSim.Tests.Common; +using PermissionMask = OpenSim.Framework.PermissionMask; + +namespace OpenSim.Tests.Permissions +{ + [SetUpFixture] + public class Common : OpenSimTestCase + { + public static Common TheInstance; + + public static TestScene TheScene + { + get { return TheInstance.m_Scene; } + } + + public static ScenePresence[] TheAvatars + { + get { return TheInstance.m_Avatars; } + } + + private static string Perms = "Owner: {0}; Group: {1}; Everyone: {2}; Next: {3}"; + private TestScene m_Scene; + private ScenePresence[] m_Avatars = new ScenePresence[3]; + + [SetUp] + public override void SetUp() + { + if (TheInstance == null) + TheInstance = this; + + base.SetUp(); + TestHelpers.EnableLogging(); + + IConfigSource config = new IniConfigSource(); + config.AddConfig("Messaging"); + config.Configs["Messaging"].Set("InventoryTransferModule", "InventoryTransferModule"); + + config.AddConfig("Modules"); + config.Configs["Modules"].Set("InventoryAccessModule", "BasicInventoryAccessModule"); + + config.AddConfig("InventoryService"); + config.Configs["InventoryService"].Set("LocalServiceModule", "OpenSim.Services.InventoryService.dll:XInventoryService"); + config.Configs["InventoryService"].Set("StorageProvider", "OpenSim.Tests.Common.dll:TestXInventoryDataPlugin"); + + config.AddConfig("Groups"); + config.Configs["Groups"].Set("Enabled", "true"); + config.Configs["Groups"].Set("Module", "Groups Module V2"); + config.Configs["Groups"].Set("StorageProvider", "OpenSim.Tests.Common.dll:TestGroupsDataPlugin"); + config.Configs["Groups"].Set("ServicesConnectorModule", "Groups Local Service Connector"); + config.Configs["Groups"].Set("LocalService", "local"); + + m_Scene = new SceneHelpers().SetupScene("Test", UUID.Random(), 1000, 1000, config); + // Add modules + SceneHelpers.SetupSceneModules(m_Scene, config, new DefaultPermissionsModule(), new InventoryTransferModule(), new BasicInventoryAccessModule()); + + SetUpBasicEnvironment(); + } + + /// + /// The basic environment consists of: + /// - 3 avatars: A1, A2, A3 + /// - 6 simple boxes inworld belonging to A0 and with Next Owner perms: + /// C, CT, MC, MCT, MT, T + /// - Copies of all of these boxes in A0's inventory in the Objects folder + /// - One additional box inworld and in A0's inventory which is a copy of MCT, but + /// with C removed in inventory. This one is called MCT-C + /// + private void SetUpBasicEnvironment() + { + Console.WriteLine("===> SetUpBasicEnvironment <==="); + + // Add 3 avatars + for (int i = 0; i < 3; i++) + { + UUID id = TestHelpers.ParseTail(i + 1); + + m_Avatars[i] = AddScenePresence("Bot", "Bot_" + (i+1), id); + Assert.That(m_Avatars[i], Is.Not.Null); + Assert.That(m_Avatars[i].IsChildAgent, Is.False); + Assert.That(m_Avatars[i].UUID, Is.EqualTo(id)); + Assert.That(m_Scene.GetScenePresences().Count, Is.EqualTo(i + 1)); + } + + AddA1Object("Box C", 10, PermissionMask.Copy); + AddA1Object("Box CT", 11, PermissionMask.Copy | PermissionMask.Transfer); + AddA1Object("Box MC", 12, PermissionMask.Modify | PermissionMask.Copy); + AddA1Object("Box MCT", 13, PermissionMask.Modify | PermissionMask.Copy | PermissionMask.Transfer); + AddA1Object("Box MT", 14, PermissionMask.Modify | PermissionMask.Transfer); + AddA1Object("Box T", 15, PermissionMask.Transfer); + + // MCT-C + AddA1Object("Box MCT-C", 16, PermissionMask.Modify | PermissionMask.Copy | PermissionMask.Transfer); + + Thread.Sleep(5000); + + InventoryFolderBase objsFolder = UserInventoryHelpers.GetInventoryFolder(m_Scene.InventoryService, m_Avatars[0].UUID, "Objects"); + List items = m_Scene.InventoryService.GetFolderItems(m_Avatars[0].UUID, objsFolder.ID); + Assert.That(items.Count, Is.EqualTo(7)); + + RevokePermission(0, "Box MCT-C", PermissionMask.Copy); + } + + private ScenePresence AddScenePresence(string first, string last, UUID id) + { + UserAccount ua1 = UserAccountHelpers.CreateUserWithInventory(m_Scene, first, last, id, "pw"); + ScenePresence sp = SceneHelpers.AddScenePresence(m_Scene, id); + Assert.That(m_Scene.AuthenticateHandler.GetAgentCircuitData(id), Is.Not.Null); + + return sp; + } + + private void AddA1Object(string name, int suffix, PermissionMask nextOwnerPerms) + { + // Create a Box. Default permissions are just T + SceneObjectGroup box = AddSceneObject(name, suffix, 1, m_Avatars[0].UUID); + Assert.True((box.RootPart.NextOwnerMask & (int)PermissionMask.Copy) == 0); + Assert.True((box.RootPart.NextOwnerMask & (int)PermissionMask.Modify) == 0); + Assert.True((box.RootPart.NextOwnerMask & (int)PermissionMask.Transfer) != 0); + + // field = 16 is NextOwner + // set = 1 means add the permission; set = 0 means remove permission + + if ((nextOwnerPerms & PermissionMask.Copy) != 0) + m_Scene.HandleObjectPermissionsUpdate(m_Avatars[0].ControllingClient, m_Avatars[0].UUID, + m_Avatars[0].ControllingClient.SessionId, 16, box.LocalId, (uint)PermissionMask.Copy, 1); + + if ((nextOwnerPerms & PermissionMask.Modify) != 0) + m_Scene.HandleObjectPermissionsUpdate(m_Avatars[0].ControllingClient, m_Avatars[0].UUID, + m_Avatars[0].ControllingClient.SessionId, 16, box.LocalId, (uint)PermissionMask.Modify, 1); + + if ((nextOwnerPerms & PermissionMask.Transfer) == 0) + m_Scene.HandleObjectPermissionsUpdate(m_Avatars[0].ControllingClient, m_Avatars[0].UUID, + m_Avatars[0].ControllingClient.SessionId, 16, box.LocalId, (uint)PermissionMask.Transfer, 0); + + PrintPerms(box); + AssertPermissions(nextOwnerPerms, (PermissionMask)box.RootPart.NextOwnerMask, box.OwnerID.ToString().Substring(34) + " : " + box.Name); + + TakeCopyToInventory(0, box); + + } + + public void RevokePermission(int ownerIndex, string name, PermissionMask perm) + { + InventoryItemBase item = Common.TheInstance.GetItemFromInventory(m_Avatars[ownerIndex].UUID, "Objects", name); + Assert.That(item, Is.Not.Null); + + // Clone it, so to avoid aliasing -- just like the viewer does. + InventoryItemBase clone = Common.TheInstance.CloneInventoryItem(item); + // Revoke the permission in this copy + clone.NextPermissions &= ~(uint)perm; + Common.TheInstance.AssertPermissions((PermissionMask)clone.NextPermissions & ~perm, + (PermissionMask)clone.NextPermissions, Common.TheInstance.IdStr(clone)); + Assert.That(clone.ID == item.ID); + + // Update properties of the item in inventory. This should affect the original item above. + Common.TheScene.UpdateInventoryItem(m_Avatars[ownerIndex].ControllingClient, UUID.Zero, clone.ID, clone); + + item = Common.TheInstance.GetItemFromInventory(m_Avatars[ownerIndex].UUID, "Objects", name); + Assert.That(item, Is.Not.Null); + Common.TheInstance.PrintPerms(item); + Common.TheInstance.AssertPermissions((PermissionMask)item.NextPermissions & ~perm, + (PermissionMask)item.NextPermissions, Common.TheInstance.IdStr(item)); + + } + + public void PrintPerms(SceneObjectGroup sog) + { + Console.WriteLine("SOG " + sog.Name + " (" + sog.OwnerID.ToString().Substring(34) + "): " + + String.Format(Perms, (PermissionMask)sog.EffectiveOwnerPerms, + (PermissionMask)sog.EffectiveGroupPerms, (PermissionMask)sog.EffectiveEveryOnePerms, (PermissionMask)sog.RootPart.NextOwnerMask)); + + } + + public void PrintPerms(InventoryItemBase item) + { + Console.WriteLine("Inv " + item.Name + " (" + item.Owner.ToString().Substring(34) + "): " + + String.Format(Perms, (PermissionMask)item.BasePermissions, + (PermissionMask)item.GroupPermissions, (PermissionMask)item.EveryOnePermissions, (PermissionMask)item.NextPermissions)); + + } + + public void AssertPermissions(PermissionMask desired, PermissionMask actual, string message) + { + if ((desired & PermissionMask.Copy) != 0) + Assert.True((actual & PermissionMask.Copy) != 0, message); + else + Assert.True((actual & PermissionMask.Copy) == 0, message); + + if ((desired & PermissionMask.Modify) != 0) + Assert.True((actual & PermissionMask.Modify) != 0, message); + else + Assert.True((actual & PermissionMask.Modify) == 0, message); + + if ((desired & PermissionMask.Transfer) != 0) + Assert.True((actual & PermissionMask.Transfer) != 0, message); + else + Assert.True((actual & PermissionMask.Transfer) == 0, message); + + } + + public SceneObjectGroup AddSceneObject(string name, int suffix, int partsToTestCount, UUID ownerID) + { + SceneObjectGroup so = SceneHelpers.CreateSceneObject(partsToTestCount, ownerID, name, suffix); + so.Name = name; + so.Description = name; + + Assert.That(m_Scene.AddNewSceneObject(so, false), Is.True); + SceneObjectGroup retrievedSo = m_Scene.GetSceneObjectGroup(so.UUID); + + // If the parts have the same UUID then we will consider them as one and the same + Assert.That(retrievedSo.PrimCount, Is.EqualTo(partsToTestCount)); + + return so; + } + + public void TakeCopyToInventory(int userIndex, SceneObjectGroup sog) + { + InventoryFolderBase objsFolder = UserInventoryHelpers.GetInventoryFolder(m_Scene.InventoryService, m_Avatars[userIndex].UUID, "Objects"); + Assert.That(objsFolder, Is.Not.Null); + + List localIds = new List(); localIds.Add(sog.LocalId); + // This is an async operation + m_Scene.DeRezObjects(m_Avatars[userIndex].ControllingClient, localIds, m_Avatars[userIndex].UUID, DeRezAction.TakeCopy, objsFolder.ID); + } + + public InventoryItemBase GetItemFromInventory(UUID userID, string folderName, string itemName) + { + InventoryFolderBase objsFolder = UserInventoryHelpers.GetInventoryFolder(m_Scene.InventoryService, userID, folderName); + Assert.That(objsFolder, Is.Not.Null); + List items = m_Scene.InventoryService.GetFolderItems(userID, objsFolder.ID); + InventoryItemBase item = items.Find(i => i.Name == itemName); + Assert.That(item, Is.Not.Null); + + return item; + } + + public InventoryItemBase CloneInventoryItem(InventoryItemBase item) + { + InventoryItemBase clone = new InventoryItemBase(item.ID); + clone.Name = item.Name; + clone.Description = item.Description; + clone.AssetID = item.AssetID; + clone.AssetType = item.AssetType; + clone.BasePermissions = item.BasePermissions; + clone.CreatorId = item.CreatorId; + clone.CurrentPermissions = item.CurrentPermissions; + clone.EveryOnePermissions = item.EveryOnePermissions; + clone.Flags = item.Flags; + clone.Folder = item.Folder; + clone.GroupID = item.GroupID; + clone.GroupOwned = item.GroupOwned; + clone.GroupPermissions = item.GroupPermissions; + clone.InvType = item.InvType; + clone.NextPermissions = item.NextPermissions; + clone.Owner = item.Owner; + + return clone; + } + + public void DeleteObjectsFolders() + { + // Delete everything in A2 and A3's Objects folders, so we can restart + for (int i = 1; i < 3; i++) + { + InventoryFolderBase objsFolder = UserInventoryHelpers.GetInventoryFolder(Common.TheScene.InventoryService, Common.TheAvatars[i].UUID, "Objects"); + Assert.That(objsFolder, Is.Not.Null); + + List items = Common.TheScene.InventoryService.GetFolderItems(Common.TheAvatars[i].UUID, objsFolder.ID); + List ids = new List(); + foreach (InventoryItemBase it in items) + ids.Add(it.ID); + + Common.TheScene.InventoryService.DeleteItems(Common.TheAvatars[i].UUID, ids); + items = Common.TheScene.InventoryService.GetFolderItems(Common.TheAvatars[i].UUID, objsFolder.ID); + Assert.That(items.Count, Is.EqualTo(0), "A" + (i + 1)); + } + + } + + public string IdStr(InventoryItemBase item) + { + return item.Owner.ToString().Substring(34) + " : " + item.Name; + } + + public string IdStr(SceneObjectGroup sog) + { + return sog.OwnerID.ToString().Substring(34) + " : " + sog.Name; + } + + public void GiveInventoryItem(UUID itemId, ScenePresence giverSp, ScenePresence receiverSp) + { + TestClient giverClient = (TestClient)giverSp.ControllingClient; + TestClient receiverClient = (TestClient)receiverSp.ControllingClient; + + UUID initialSessionId = TestHelpers.ParseTail(0x10); + byte[] giveImBinaryBucket = new byte[17]; + byte[] itemIdBytes = itemId.GetBytes(); + Array.Copy(itemIdBytes, 0, giveImBinaryBucket, 1, itemIdBytes.Length); + + GridInstantMessage giveIm + = new GridInstantMessage( + m_Scene, + giverSp.UUID, + giverSp.Name, + receiverSp.UUID, + (byte)InstantMessageDialog.InventoryOffered, + false, + "inventory offered msg", + initialSessionId, + false, + Vector3.Zero, + giveImBinaryBucket, + true); + + giverClient.HandleImprovedInstantMessage(giveIm); + + // These details might not all be correct. + GridInstantMessage acceptIm + = new GridInstantMessage( + m_Scene, + receiverSp.UUID, + receiverSp.Name, + giverSp.UUID, + (byte)InstantMessageDialog.InventoryAccepted, + false, + "inventory accepted msg", + initialSessionId, + false, + Vector3.Zero, + null, + true); + + receiverClient.HandleImprovedInstantMessage(acceptIm); + } + } +} diff --git a/Tests/OpenSim.Permissions.Tests/DirectTransferTests.cs b/Tests/OpenSim.Permissions.Tests/DirectTransferTests.cs new file mode 100644 index 00000000000..0f251dba436 --- /dev/null +++ b/Tests/OpenSim.Permissions.Tests/DirectTransferTests.cs @@ -0,0 +1,153 @@ +/* + * 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 NUnit.Framework; +using OpenMetaverse; +using OpenSim.Framework; +using OpenSim.Region.Framework.Scenes; +using OpenSim.Tests.Common; +using PermissionMask = OpenSim.Framework.PermissionMask; + +namespace OpenSim.Tests.Permissions +{ + /// + /// Basic scene object tests (create, read and delete but not update). + /// + [TestFixture] + public class DirectTransferTests + { + + [SetUp] + public void SetUp() + { + // In case we're dealing with some older version of nunit + if (Common.TheInstance == null) + { + Common.TheInstance = new Common(); + Common.TheInstance.SetUp(); + } + + Common.TheInstance.DeleteObjectsFolders(); + } + + /// + /// Test giving simple objecta with various combinations of next owner perms. + /// + [Test] + public void TestGiveBox() + { + TestHelpers.InMethod(); + + // C, CT, MC, MCT, MT, T + string[] names = new string[6] { "Box C", "Box CT", "Box MC", "Box MCT", "Box MT", "Box T" }; + PermissionMask[] perms = new PermissionMask[6] { + PermissionMask.Copy, + PermissionMask.Copy | PermissionMask.Transfer, + PermissionMask.Modify | PermissionMask.Copy, + PermissionMask.Modify | PermissionMask.Copy | PermissionMask.Transfer, + PermissionMask.Modify | PermissionMask.Transfer, + PermissionMask.Transfer + }; + + for (int i = 0; i < 6; i++) + TestOneBox(names[i], perms[i]); + } + + private void TestOneBox(string name, PermissionMask mask) + { + InventoryItemBase item = Common.TheInstance.GetItemFromInventory(Common.TheAvatars[0].UUID, "Objects", name); + + Common.TheInstance.GiveInventoryItem(item.ID, Common.TheAvatars[0], Common.TheAvatars[1]); + + item = Common.TheInstance.GetItemFromInventory(Common.TheAvatars[1].UUID, "Objects", name); + + // Check the receiver + Common.TheInstance.PrintPerms(item); + Common.TheInstance.AssertPermissions(mask, (PermissionMask)item.BasePermissions, item.Owner.ToString().Substring(34) + " : " + item.Name); + + int nObjects = Common.TheScene.GetSceneObjectGroups().Count; + // Rez it and check perms in scene too + Common.TheScene.RezObject(Common.TheAvatars[1].ControllingClient, item.ID, UUID.Zero, Vector3.One, Vector3.Zero, UUID.Zero, 0, false, false, false, UUID.Zero); + Assert.That(Common.TheScene.GetSceneObjectGroups().Count, Is.EqualTo(nObjects + 1)); + + SceneObjectGroup box = Common.TheScene.GetSceneObjectGroups().Find(sog => sog.OwnerID == Common.TheAvatars[1].UUID && sog.Name == name); + Common.TheInstance.PrintPerms(box); + Assert.That(box, Is.Not.Null); + + // Check Owner permissions + Common.TheInstance.AssertPermissions(mask, (PermissionMask)box.EffectiveOwnerPerms, box.OwnerID.ToString().Substring(34) + " : " + box.Name); + + // Check Next Owner permissions + Common.TheInstance.AssertPermissions(mask, (PermissionMask)box.RootPart.NextOwnerMask, box.OwnerID.ToString().Substring(34) + " : " + box.Name); + + } + + /// + /// Test giving simple objecta with variour combinations of next owner perms. + /// + [Test] + public void TestDoubleGiveWithChange() + { + TestHelpers.InMethod(); + + string name = "Box MCT-C"; + InventoryItemBase item = Common.TheInstance.GetItemFromInventory(Common.TheAvatars[0].UUID, "Objects", name); + + // Now give the item to A2. We give the original item, not a clone. + // The giving methods are supposed to duplicate it. + Common.TheInstance.GiveInventoryItem(item.ID, Common.TheAvatars[0], Common.TheAvatars[1]); + + item = Common.TheInstance.GetItemFromInventory(Common.TheAvatars[1].UUID, "Objects", name); + + // Check the receiver + Common.TheInstance.PrintPerms(item); + Common.TheInstance.AssertPermissions(PermissionMask.Modify | PermissionMask.Transfer, + (PermissionMask)item.BasePermissions, Common.TheInstance.IdStr(item)); + + // --------------------------- + // Second transfer + //---------------------------- + + // A2 revokes M + Common.TheInstance.RevokePermission(1, name, PermissionMask.Modify); + + item = Common.TheInstance.GetItemFromInventory(Common.TheAvatars[1].UUID, "Objects", name); + + // Now give the item to A3. We give the original item, not a clone. + // The giving methods are supposed to duplicate it. + Common.TheInstance.GiveInventoryItem(item.ID, Common.TheAvatars[1], Common.TheAvatars[2]); + + item = Common.TheInstance.GetItemFromInventory(Common.TheAvatars[2].UUID, "Objects", name); + + // Check the receiver + Common.TheInstance.PrintPerms(item); + Common.TheInstance.AssertPermissions(PermissionMask.Transfer, + (PermissionMask)item.BasePermissions, Common.TheInstance.IdStr(item)); + + } + } +} \ No newline at end of file diff --git a/Tests/OpenSim.Permissions.Tests/IndirectTransferTests.cs b/Tests/OpenSim.Permissions.Tests/IndirectTransferTests.cs new file mode 100644 index 00000000000..909bda31b1d --- /dev/null +++ b/Tests/OpenSim.Permissions.Tests/IndirectTransferTests.cs @@ -0,0 +1,132 @@ +/* + * 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.Collections.Generic; +using System.Threading; +using NUnit.Framework; +using OpenMetaverse; +using OpenSim.Framework; +using OpenSim.Region.Framework.Scenes; +using OpenSim.Tests.Common; +using PermissionMask = OpenSim.Framework.PermissionMask; + +namespace OpenSim.Tests.Permissions +{ + /// + /// Basic scene object tests (create, read and delete but not update). + /// + [TestFixture] + public class IndirectTransferTests + { + + [SetUp] + public void SetUp() + { + // In case we're dealing with some older version of nunit + if (Common.TheInstance == null) + { + Common.TheInstance = new Common(); + Common.TheInstance.SetUp(); + } + Common.TheInstance.DeleteObjectsFolders(); + } + + /// + /// Test giving simple objecta with various combinations of next owner perms. + /// + [Test] + public void SimpleTakeCopy() + { + TestHelpers.InMethod(); + + // The Objects folder of A2 + InventoryFolderBase objsFolder = UserInventoryHelpers.GetInventoryFolder(Common.TheScene.InventoryService, Common.TheAvatars[1].UUID, "Objects"); + + // C, CT, MC, MCT, MT, T + string[] names = new string[6] { "Box C", "Box CT", "Box MC", "Box MCT", "Box MT", "Box T" }; + PermissionMask[] perms = new PermissionMask[6] { + PermissionMask.Copy, + PermissionMask.Copy | PermissionMask.Transfer, + PermissionMask.Modify | PermissionMask.Copy, + PermissionMask.Modify | PermissionMask.Copy | PermissionMask.Transfer, + PermissionMask.Modify | PermissionMask.Transfer, + PermissionMask.Transfer + }; + + // Try A2 takes copies of objects that cannot be copied. + for (int i = 0; i < 6; i++) + TakeOneBox(Common.TheScene.GetSceneObjectGroups(), names[i], perms[i]); + // Ad-hoc. Enough time to let the take work. + Thread.Sleep(6000); + + List items = Common.TheScene.InventoryService.GetFolderItems(Common.TheAvatars[1].UUID, objsFolder.ID); + Assert.That(items.Count, Is.EqualTo(0)); + + // A1 makes the objects copyable + for (int i = 0; i < 6; i++) + MakeCopyable(Common.TheScene.GetSceneObjectGroups(), names[i]); + + // Try A2 takes copies of objects that can be copied. + for (int i = 0; i < 6; i++) + TakeOneBox(Common.TheScene.GetSceneObjectGroups(), names[i], perms[i]); + // Ad-hoc. Enough time to let the take work. + Thread.Sleep(6000); + + items = Common.TheScene.InventoryService.GetFolderItems(Common.TheAvatars[1].UUID, objsFolder.ID); + Assert.That(items.Count, Is.EqualTo(6)); + + for (int i = 0; i < 6; i++) + { + InventoryItemBase item = Common.TheInstance.GetItemFromInventory(Common.TheAvatars[1].UUID, "Objects", names[i]); + Assert.That(item, Is.Not.Null); + Common.TheInstance.AssertPermissions(perms[i], (PermissionMask)item.BasePermissions, Common.TheInstance.IdStr(item)); + } + } + + private void TakeOneBox(List objs, string name, PermissionMask mask) + { + // Find the object inworld + SceneObjectGroup box = objs.Find(sog => sog.Name == name && sog.OwnerID == Common.TheAvatars[0].UUID); + Assert.That(box, Is.Not.Null, name); + + // A2's inventory (index 1) + Common.TheInstance.TakeCopyToInventory(1, box); + } + + private void MakeCopyable(List objs, string name) + { + SceneObjectGroup box = objs.Find(sog => sog.Name == name && sog.OwnerID == Common.TheAvatars[0].UUID); + Assert.That(box, Is.Not.Null, name); + + // field = 8 is Everyone + // set = 1 means add the permission; set = 0 means remove permission + Common.TheScene.HandleObjectPermissionsUpdate(Common.TheAvatars[0].ControllingClient, Common.TheAvatars[0].UUID, + Common.TheAvatars[0].ControllingClient.SessionId, 8, box.LocalId, (uint)PermissionMask.Copy, 1); + Common.TheInstance.PrintPerms(box); + } + } +} \ No newline at end of file diff --git a/Tests/OpenSim.Permissions.Tests/OpenSim.Tests.Permissions.csproj b/Tests/OpenSim.Permissions.Tests/OpenSim.Tests.Permissions.csproj new file mode 100644 index 00000000000..d0ed42a2902 --- /dev/null +++ b/Tests/OpenSim.Permissions.Tests/OpenSim.Tests.Permissions.csproj @@ -0,0 +1,35 @@ + + + net6.0 + + + + + + + + + + + ..\..\..\bin\Nini.dll + False + + + ..\..\..\bin\OpenMetaverse.dll + False + + + ..\..\..\bin\OpenMetaverseTypes.dll + False + + + + + + + + + + + + \ No newline at end of file diff --git a/Tests/OpenSim.Region.ClientStack.LindenCaps.Tests/EventQueue/Tests/EventQueueTests.cs b/Tests/OpenSim.Region.ClientStack.LindenCaps.Tests/EventQueue/Tests/EventQueueTests.cs new file mode 100644 index 00000000000..16b341a2dce --- /dev/null +++ b/Tests/OpenSim.Region.ClientStack.LindenCaps.Tests/EventQueue/Tests/EventQueueTests.cs @@ -0,0 +1,201 @@ +/* + * 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; +using System.Collections.Generic; +using System.Net; +using System.Text; +using log4net.Config; +using Nini.Config; +using NUnit.Framework; +using OpenMetaverse; +using OpenMetaverse.Packets; +using OpenMetaverse.StructuredData; +using OpenSim.Framework; +using OpenSim.Framework.Servers; +using OpenSim.Framework.Servers.HttpServer; +using OpenSim.Region.ClientStack.Linden; +using OpenSim.Region.CoreModules.Framework; +using OpenSim.Region.Framework.Scenes; +using OpenSim.Region.OptionalModules.World.NPC; +using OpenSim.Tests.Common; + +namespace OpenSim.Region.ClientStack.Linden.Tests +{ + [TestFixture] + public class EventQueueTests : OpenSimTestCase + { + private TestScene m_scene; + private EventQueueGetModule m_eqgMod; + private NPCModule m_npcMod; + + [SetUp] + public override void SetUp() + { + base.SetUp(); + + uint port = 9999; + + // This is an unfortunate bit of clean up we have to do because MainServer manages things through static + // variables and the VM is not restarted between tests. + MainServer.RemoveHttpServer(port); + + BaseHttpServer server = new BaseHttpServer(port, false, "","",""); + MainServer.AddHttpServer(server); + MainServer.Instance = server; + + IConfigSource config = new IniConfigSource(); + config.AddConfig("Startup"); + + CapabilitiesModule capsModule = new CapabilitiesModule(); + m_eqgMod = new EventQueueGetModule(); + + // For NPC test support + config.AddConfig("NPC"); + config.Configs["NPC"].Set("Enabled", "true"); + m_npcMod = new NPCModule(); + + m_scene = new SceneHelpers().SetupScene(); + SceneHelpers.SetupSceneModules(m_scene, config, capsModule, m_eqgMod, m_npcMod); + } + + [Test] + public void TestAddForClient() + { + TestHelpers.InMethod(); +// log4net.Config.XmlConfigurator.Configure(); + + SceneHelpers.AddScenePresence(m_scene, TestHelpers.ParseTail(0x1)); + + // TODO: Add more assertions for the other aspects of event queues + Assert.That(MainServer.Instance.GetPollServiceHandlerKeys().Count, Is.EqualTo(1)); + } + + [Test] + public void TestRemoveForClient() + { + TestHelpers.InMethod(); +// TestHelpers.EnableLogging(); + + UUID spId = TestHelpers.ParseTail(0x1); + + SceneHelpers.AddScenePresence(m_scene, spId); + m_scene.CloseAgent(spId, false); + + // TODO: Add more assertions for the other aspects of event queues + Assert.That(MainServer.Instance.GetPollServiceHandlerKeys().Count, Is.EqualTo(0)); + } + + [Test] + public void TestEnqueueMessage() + { + TestHelpers.InMethod(); +// log4net.Config.XmlConfigurator.Configure(); + + ScenePresence sp = SceneHelpers.AddScenePresence(m_scene, TestHelpers.ParseTail(0x1)); + + string messageName = "TestMessage"; + + m_eqgMod.Enqueue(m_eqgMod.BuildEvent(messageName, new OSDMap()), sp.UUID); + + Hashtable eventsResponse = m_eqgMod.GetEvents(UUID.Zero, sp.UUID); + + // initial queue as null events +// eventsResponse = m_eqgMod.GetEvents(UUID.Zero, sp.UUID); + if((int)eventsResponse["int_response_code"] != (int)HttpStatusCode.OK) + { + eventsResponse = m_eqgMod.GetEvents(UUID.Zero, sp.UUID); + if((int)eventsResponse["int_response_code"] != (int)HttpStatusCode.OK) + eventsResponse = m_eqgMod.GetEvents(UUID.Zero, sp.UUID); + } + + Assert.That((int)eventsResponse["int_response_code"], Is.EqualTo((int)HttpStatusCode.OK)); + +// Console.WriteLine("Response [{0}]", (string)eventsResponse["str_response_string"]); + string data = String.Empty; + if(eventsResponse["bin_response_data"] != null) + data = Encoding.UTF8.GetString((byte[])eventsResponse["bin_response_data"]); + + OSDMap rawOsd = (OSDMap)OSDParser.DeserializeLLSDXml(data); + OSDArray eventsOsd = (OSDArray)rawOsd["events"]; + + bool foundUpdate = false; + foreach (OSD osd in eventsOsd) + { + OSDMap eventOsd = (OSDMap)osd; + + if (eventOsd["message"] == messageName) + foundUpdate = true; + } + + Assert.That(foundUpdate, Is.True, string.Format("Did not find {0} in response", messageName)); + } + + /// + /// Test an attempt to put a message on the queue of a user that is not in the region. + /// + [Test] + public void TestEnqueueMessageNoUser() + { + TestHelpers.InMethod(); + TestHelpers.EnableLogging(); + + string messageName = "TestMessage"; + + m_eqgMod.Enqueue(m_eqgMod.BuildEvent(messageName, new OSDMap()), TestHelpers.ParseTail(0x1)); + + Hashtable eventsResponse = m_eqgMod.GetEvents(UUID.Zero, TestHelpers.ParseTail(0x1)); + + Assert.That((int)eventsResponse["int_response_code"], Is.EqualTo((int)HttpStatusCode.NotFound)); + } + + /// + /// NPCs do not currently have an event queue but a caller may try to send a message anyway, so check behaviour. + /// + [Test] + public void TestEnqueueMessageToNpc() + { + TestHelpers.InMethod(); +// TestHelpers.EnableLogging(); + + UUID npcId + = m_npcMod.CreateNPC( + "John", "Smith", new Vector3(128, 128, 30), UUID.Zero, true, m_scene, new AvatarAppearance()); + + ScenePresence npc = m_scene.GetScenePresence(npcId); + + string messageName = "TestMessage"; + + m_eqgMod.Enqueue(m_eqgMod.BuildEvent(messageName, new OSDMap()), npc.UUID); + + Hashtable eventsResponse = m_eqgMod.GetEvents(UUID.Zero, npc.UUID); + + Assert.That((int)eventsResponse["int_response_code"], Is.EqualTo((int)HttpStatusCode.NotFound)); + } + } +} diff --git a/Tests/OpenSim.Region.ClientStack.LindenCaps.Tests/OpenSim.Region.ClientStack.LindenCaps.Tests.csproj b/Tests/OpenSim.Region.ClientStack.LindenCaps.Tests/OpenSim.Region.ClientStack.LindenCaps.Tests.csproj new file mode 100644 index 00000000000..23806a1dc51 --- /dev/null +++ b/Tests/OpenSim.Region.ClientStack.LindenCaps.Tests/OpenSim.Region.ClientStack.LindenCaps.Tests.csproj @@ -0,0 +1,66 @@ + + + net6.0 + + + + ..\..\..\..\..\bin\Nini.dll + False + + + ..\..\..\..\..\bin\OpenMetaverse.dll + False + + + ..\..\..\..\..\bin\OpenMetaverse.StructuredData.dll + False + + + ..\..\..\..\..\bin\OpenMetaverseTypes.dll + False + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Tests/OpenSim.Region.ClientStack.LindenCaps.Tests/Tests/WebFetchInvDescModuleTests.cs b/Tests/OpenSim.Region.ClientStack.LindenCaps.Tests/Tests/WebFetchInvDescModuleTests.cs new file mode 100644 index 00000000000..050b779887a --- /dev/null +++ b/Tests/OpenSim.Region.ClientStack.LindenCaps.Tests/Tests/WebFetchInvDescModuleTests.cs @@ -0,0 +1,161 @@ +/* + * 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; +using System.Collections.Generic; +using System.IO; +using System.Net; +using System.Text; +using OSHttpServer; +using log4net.Config; +using Nini.Config; +using NUnit.Framework; +using OpenMetaverse; +using OpenMetaverse.Packets; +using OpenMetaverse.StructuredData; +using OpenSim.Framework; +using OpenSim.Framework.Capabilities; +using OpenSim.Framework.Servers; +using OpenSim.Framework.Servers.HttpServer; +using OpenSim.Region.ClientStack.Linden; +using OpenSim.Region.CoreModules.Framework; +using OpenSim.Region.Framework.Scenes; +using OpenSim.Services.Interfaces; +using OpenSim.Tests.Common; +using OSDArray = OpenMetaverse.StructuredData.OSDArray; +using OSDMap = OpenMetaverse.StructuredData.OSDMap; + +namespace OpenSim.Region.ClientStack.Linden.Caps.Tests +{ + /* + [TestFixture] + public class WebFetchInvDescModuleTests : OpenSimTestCase + { + [TestFixtureSetUp] + public void TestFixtureSetUp() + { + // Don't allow tests to be bamboozled by asynchronous events. Execute everything on the same thread. + Util.FireAndForgetMethod = FireAndForgetMethod.RegressionTest; + } + + [TestFixtureTearDown] + public void TestFixureTearDown() + { + // 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; + } + + [SetUp] + public override void SetUp() + { + base.SetUp(); + + // This is an unfortunate bit of clean up we have to do because MainServer manages things through static + // variables and the VM is not restarted between tests. + uint port = 9999; + MainServer.RemoveHttpServer(port); + + BaseHttpServer server = new BaseHttpServer(port, false, 0, ""); + MainServer.AddHttpServer(server); + MainServer.Instance = server; + + server.Start(false); + } + + [Test] + public void TestInventoryDescendentsFetch() + { + TestHelpers.InMethod(); + TestHelpers.EnableLogging(); + + BaseHttpServer httpServer = MainServer.Instance; + Scene scene = new SceneHelpers().SetupScene(); + + CapabilitiesModule capsModule = new CapabilitiesModule(); + WebFetchInvDescModule wfidModule = new WebFetchInvDescModule(false); + + IConfigSource config = new IniConfigSource(); + config.AddConfig("ClientStack.LindenCaps"); + config.Configs["ClientStack.LindenCaps"].Set("Cap_FetchInventoryDescendents2", "localhost"); + + SceneHelpers.SetupSceneModules(scene, config, capsModule, wfidModule); + + UserAccount ua = UserAccountHelpers.CreateUserWithInventory(scene, TestHelpers.ParseTail(0x1)); + + // We need a user present to have any capabilities set up + SceneHelpers.AddScenePresence(scene, ua.PrincipalID); + + TestHttpRequest req = new TestHttpRequest(); + OpenSim.Framework.Capabilities.Caps userCaps = capsModule.GetCapsForUser(ua.PrincipalID); + PollServiceEventArgs pseArgs; + userCaps.TryGetPollHandler("FetchInventoryDescendents2", out pseArgs); + req.UriPath = pseArgs.Url; + req.Uri = new Uri("file://" + req.UriPath); + + // Retrieve root folder details directly so that we can request + InventoryFolderBase folder = scene.InventoryService.GetRootFolder(ua.PrincipalID); + + OSDMap osdFolder = new OSDMap(); + osdFolder["folder_id"] = folder.ID; + osdFolder["owner_id"] = ua.PrincipalID; + osdFolder["fetch_folders"] = true; + osdFolder["fetch_items"] = true; + osdFolder["sort_order"] = 0; + + OSDArray osdFoldersArray = new OSDArray(); + osdFoldersArray.Add(osdFolder); + + OSDMap osdReqMap = new OSDMap(); + osdReqMap["folders"] = osdFoldersArray; + + req.Body = new MemoryStream(OSDParser.SerializeLLSDXmlBytes(osdReqMap)); + + TestHttpClientContext context = new TestHttpClientContext(false); + + // WARNING: This results in a caught exception, because queryString is null + MainServer.Instance.OnRequest(context, new RequestEventArgs(req)); + + // Drive processing of the queued inventory request synchronously. + wfidModule.WaitProcessQueuedInventoryRequest(); + MainServer.Instance.PollServiceRequestManager.WaitPerformResponse(); + +// System.Threading.Thread.Sleep(10000); + + OSDMap responseOsd = (OSDMap)OSDParser.DeserializeLLSDXml(context.ResponseBody); + OSDArray foldersOsd = (OSDArray)responseOsd["folders"]; + OSDMap folderOsd = (OSDMap)foldersOsd[0]; + + // A sanity check that the response has the expected number of descendents for a default inventory + // TODO: Need a more thorough check. + Assert.That((int)folderOsd["descendents"], Is.EqualTo(16)); + } + } + */ +} \ No newline at end of file diff --git a/Tests/OpenSim.Region.ClientStack.LindenUDP.Tests/BasicCircuitTests.cs b/Tests/OpenSim.Region.ClientStack.LindenUDP.Tests/BasicCircuitTests.cs new file mode 100644 index 00000000000..c61ea2104db --- /dev/null +++ b/Tests/OpenSim.Region.ClientStack.LindenUDP.Tests/BasicCircuitTests.cs @@ -0,0 +1,273 @@ +/* + * 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.Net; +using log4net.Config; +using Nini.Config; +using NUnit.Framework; +using OpenMetaverse; +using OpenMetaverse.Packets; +using OpenSim.Framework; +using OpenSim.Framework.Monitoring; +using OpenSim.Region.Framework.Scenes; +using OpenSim.Tests.Common; + +namespace OpenSim.Region.ClientStack.LindenUDP.Tests +{ + /// + /// This will contain basic tests for the LindenUDP client stack + /// + [TestFixture] + public class BasicCircuitTests : OpenSimTestCase + { + private Scene m_scene; + + [OneTimeSetUp] + public void FixtureInit() + { + // Don't allow tests to be bamboozled by asynchronous events. Execute everything on the same thread. + Util.FireAndForgetMethod = FireAndForgetMethod.RegressionTest; + } + + [OneTimeTearDown] + 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; + } + + [SetUp] + public override void SetUp() + { + base.SetUp(); + m_scene = new SceneHelpers().SetupScene(); + StatsManager.SimExtraStats = new SimExtraStatsCollector(); + } + +// /// +// /// Build an object name packet for test purposes +// /// +// /// +// /// +// private ObjectNamePacket BuildTestObjectNamePacket(uint objectLocalId, string objectName) +// { +// ObjectNamePacket onp = new ObjectNamePacket(); +// ObjectNamePacket.ObjectDataBlock odb = new ObjectNamePacket.ObjectDataBlock(); +// odb.LocalID = objectLocalId; +// odb.Name = Utils.StringToBytes(objectName); +// onp.ObjectData = new ObjectNamePacket.ObjectDataBlock[] { odb }; +// onp.Header.Zerocoded = false; +// +// return onp; +// } +// + /// + /// Test adding a client to the stack + /// +/* + [Test] + public void TestAddClient() + { + TestHelpers.InMethod(); +// TestHelpers.EnableLogging(); + + TestLLUDPServer udpServer = ClientStackHelpers.AddUdpServer(m_scene); + + UUID myAgentUuid = TestHelpers.ParseTail(0x1); + UUID mySessionUuid = TestHelpers.ParseTail(0x2); + uint myCircuitCode = 123456; + IPEndPoint testEp = new IPEndPoint(IPAddress.Loopback, 999); + + UseCircuitCodePacket uccp = new UseCircuitCodePacket(); + + UseCircuitCodePacket.CircuitCodeBlock uccpCcBlock + = new UseCircuitCodePacket.CircuitCodeBlock(); + uccpCcBlock.Code = myCircuitCode; + uccpCcBlock.ID = myAgentUuid; + uccpCcBlock.SessionID = mySessionUuid; + uccp.CircuitCode = uccpCcBlock; + + byte[] uccpBytes = uccp.ToBytes(); + UDPPacketBuffer upb = new UDPPacketBuffer(testEp, uccpBytes.Length); + upb.DataLength = uccpBytes.Length; // God knows why this isn't set by the constructor. + Buffer.BlockCopy(uccpBytes, 0, upb.Data, 0, uccpBytes.Length); + + udpServer.PacketReceived(upb); + + // Presence shouldn't exist since the circuit manager doesn't know about this circuit for authentication yet + Assert.That(m_scene.GetScenePresence(myAgentUuid), Is.Null); + + AgentCircuitData acd = new AgentCircuitData(); + acd.AgentID = myAgentUuid; + acd.SessionID = mySessionUuid; + + m_scene.AuthenticateHandler.AddNewCircuit(myCircuitCode, acd); + + udpServer.PacketReceived(upb); + + // Should succeed now + ScenePresence sp = m_scene.GetScenePresence(myAgentUuid); + Assert.That(sp.UUID, Is.EqualTo(myAgentUuid)); + + Assert.That(udpServer.PacketsSent.Count, Is.EqualTo(1)); + + Packet packet = udpServer.PacketsSent[0]; + Assert.That(packet, Is.InstanceOf(typeof(PacketAckPacket))); + + PacketAckPacket ackPacket = packet as PacketAckPacket; + Assert.That(ackPacket.Packets.Length, Is.EqualTo(1)); + Assert.That(ackPacket.Packets[0].ID, Is.EqualTo(0)); + } + + [Test] + public void TestLogoutClientDueToAck() + { + TestHelpers.InMethod(); +// TestHelpers.EnableLogging(); + + IniConfigSource ics = new IniConfigSource(); + IConfig config = ics.AddConfig("ClientStack.LindenUDP"); + config.Set("AckTimeout", -1); + TestLLUDPServer udpServer = ClientStackHelpers.AddUdpServer(m_scene, ics); + + ScenePresence sp + = ClientStackHelpers.AddChildClient( + m_scene, udpServer, TestHelpers.ParseTail(0x1), TestHelpers.ParseTail(0x2), 123456); + + udpServer.ClientOutgoingPacketHandler(sp.ControllingClient, true, false, false); + + ScenePresence spAfterAckTimeout = m_scene.GetScenePresence(sp.UUID); + Assert.That(spAfterAckTimeout, Is.Null); + } +*/ +// /// +// /// Test removing a client from the stack +// /// +// [Test] +// public void TestRemoveClient() +// { +// TestHelper.InMethod(); +// +// uint myCircuitCode = 123457; +// +// TestLLUDPServer testLLUDPServer; +// TestLLPacketServer testLLPacketServer; +// AgentCircuitManager acm; +// SetupStack(new MockScene(), out testLLUDPServer, out testLLPacketServer, out acm); +// AddClient(myCircuitCode, new IPEndPoint(IPAddress.Loopback, 1000), testLLUDPServer, acm); +// +// testLLUDPServer.RemoveClientCircuit(myCircuitCode); +// Assert.IsFalse(testLLUDPServer.HasCircuit(myCircuitCode)); +// +// // Check that removing a non-existent circuit doesn't have any bad effects +// testLLUDPServer.RemoveClientCircuit(101); +// Assert.IsFalse(testLLUDPServer.HasCircuit(101)); +// } +// +// /// +// /// Make sure that the client stack reacts okay to malformed packets +// /// +// [Test] +// public void TestMalformedPacketSend() +// { +// TestHelper.InMethod(); +// +// uint myCircuitCode = 123458; +// EndPoint testEp = new IPEndPoint(IPAddress.Loopback, 1001); +// MockScene scene = new MockScene(); +// +// TestLLUDPServer testLLUDPServer; +// TestLLPacketServer testLLPacketServer; +// AgentCircuitManager acm; +// SetupStack(scene, out testLLUDPServer, out testLLPacketServer, out acm); +// AddClient(myCircuitCode, testEp, testLLUDPServer, acm); +// +// byte[] data = new byte[] { 0x01, 0x02, 0x03, 0x04 }; +// +// // Send two garbled 'packets' in succession +// testLLUDPServer.LoadReceive(data, testEp); +// testLLUDPServer.LoadReceive(data, testEp); +// testLLUDPServer.ReceiveData(null); +// +// // Check that we are still here +// Assert.IsTrue(testLLUDPServer.HasCircuit(myCircuitCode)); +// Assert.That(testLLPacketServer.GetTotalPacketsReceived(), Is.EqualTo(0)); +// +// // Check that sending a valid packet to same circuit still succeeds +// Assert.That(scene.ObjectNameCallsReceived, Is.EqualTo(0)); +// +// testLLUDPServer.LoadReceive(BuildTestObjectNamePacket(1, "helloooo"), testEp); +// testLLUDPServer.ReceiveData(null); +// +// Assert.That(testLLPacketServer.GetTotalPacketsReceived(), Is.EqualTo(1)); +// Assert.That(testLLPacketServer.GetPacketsReceivedFor(PacketType.ObjectName), Is.EqualTo(1)); +// } +// +// /// +// /// Test that the stack continues to work even if some client has caused a +// /// SocketException on Socket.BeginReceive() +// /// +// [Test] +// public void TestExceptionOnBeginReceive() +// { +// TestHelper.InMethod(); +// +// MockScene scene = new MockScene(); +// +// uint circuitCodeA = 130000; +// EndPoint epA = new IPEndPoint(IPAddress.Loopback, 1300); +// UUID agentIdA = UUID.Parse("00000000-0000-0000-0000-000000001300"); +// UUID sessionIdA = UUID.Parse("00000000-0000-0000-0000-000000002300"); +// +// uint circuitCodeB = 130001; +// EndPoint epB = new IPEndPoint(IPAddress.Loopback, 1301); +// UUID agentIdB = UUID.Parse("00000000-0000-0000-0000-000000001301"); +// UUID sessionIdB = UUID.Parse("00000000-0000-0000-0000-000000002301"); +// +// TestLLUDPServer testLLUDPServer; +// TestLLPacketServer testLLPacketServer; +// AgentCircuitManager acm; +// SetupStack(scene, out testLLUDPServer, out testLLPacketServer, out acm); +// AddClient(circuitCodeA, epA, agentIdA, sessionIdA, testLLUDPServer, acm); +// AddClient(circuitCodeB, epB, agentIdB, sessionIdB, testLLUDPServer, acm); +// +// testLLUDPServer.LoadReceive(BuildTestObjectNamePacket(1, "packet1"), epA); +// testLLUDPServer.LoadReceive(BuildTestObjectNamePacket(1, "packet2"), epB); +// testLLUDPServer.LoadReceiveWithBeginException(epA); +// testLLUDPServer.LoadReceive(BuildTestObjectNamePacket(2, "packet3"), epB); +// testLLUDPServer.ReceiveData(null); +// +// Assert.IsFalse(testLLUDPServer.HasCircuit(circuitCodeA)); +// +// Assert.That(testLLPacketServer.GetTotalPacketsReceived(), Is.EqualTo(3)); +// Assert.That(testLLPacketServer.GetPacketsReceivedFor(PacketType.ObjectName), Is.EqualTo(3)); +// } + } +} diff --git a/Tests/OpenSim.Region.ClientStack.LindenUDP.Tests/LLImageManagerTests.cs b/Tests/OpenSim.Region.ClientStack.LindenUDP.Tests/LLImageManagerTests.cs new file mode 100644 index 00000000000..2e8aacefd36 --- /dev/null +++ b/Tests/OpenSim.Region.ClientStack.LindenUDP.Tests/LLImageManagerTests.cs @@ -0,0 +1,174 @@ +/* + * 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.IO; +using System.Net; +using System.Reflection; +using System.Threading; +using log4net.Config; +using Nini.Config; +using NUnit.Framework; +using OpenMetaverse; +using OpenMetaverse.Packets; +using OpenSim.Framework; +using OpenSim.Region.CoreModules.Agent.TextureSender; +using OpenSim.Region.Framework.Scenes; +using OpenSim.Tests.Common; + +namespace OpenSim.Region.ClientStack.LindenUDP.Tests +{ + [TestFixture] + public class LLImageManagerTests : OpenSimTestCase + { + private AssetBase m_testImageAsset; + private Scene scene; + private LLImageManager llim; + private TestClient tc; + + [OneTimeSetUp] + public void FixtureInit() + { + // Don't allow tests to be bamboozled by asynchronous events. Execute everything on the same thread. + Util.FireAndForgetMethod = FireAndForgetMethod.None; + + using ( + Stream resource + = GetType().Assembly.GetManifestResourceStream( + "OpenSim.Region.ClientStack.LindenUDP.Tests.Resources.4-tile2.jp2")) + { + using (BinaryReader br = new BinaryReader(resource)) + { + m_testImageAsset + = new AssetBase( + TestHelpers.ParseTail(0x1), + "Test Image", + (sbyte)AssetType.Texture, + TestHelpers.ParseTail(0x2).ToString()); + + m_testImageAsset.Data = br.ReadBytes(99999999); + } + } + } + + [OneTimeTearDown] + 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 not to worry about such things. + Util.FireAndForgetMethod = Util.DefaultFireAndForgetMethod; + } + + [SetUp] + public override void SetUp() + { + base.SetUp(); + + UUID userId = TestHelpers.ParseTail(0x3); + + J2KDecoderModule j2kdm = new J2KDecoderModule(); + + SceneHelpers sceneHelpers = new SceneHelpers(); + scene = sceneHelpers.SetupScene(); + SceneHelpers.SetupSceneModules(scene, j2kdm); + + tc = new TestClient(SceneHelpers.GenerateAgentData(userId), scene); + llim = new LLImageManager(tc, scene.AssetService, j2kdm); + } + + [Test] + public void TestSendImage() + { + TestHelpers.InMethod(); +// XmlConfigurator.Configure(); + + scene.AssetService.Store(m_testImageAsset); + + TextureRequestArgs args = new TextureRequestArgs(); + args.RequestedAssetID = m_testImageAsset.FullID; + args.DiscardLevel = 0; + args.PacketNumber = 1; + args.Priority = 5; + args.requestSequence = 1; + + llim.EnqueueReq(args); + llim.ProcessImageQueue(20); + + Assert.That(tc.SentImageDataPackets.Count, Is.EqualTo(1)); + } + + [Test] + public void TestDiscardImage() + { + TestHelpers.InMethod(); +// XmlConfigurator.Configure(); + + scene.AssetService.Store(m_testImageAsset); + + TextureRequestArgs args = new TextureRequestArgs(); + args.RequestedAssetID = m_testImageAsset.FullID; + args.DiscardLevel = 0; + args.PacketNumber = 1; + args.Priority = 5; + args.requestSequence = 1; + llim.EnqueueReq(args); + + // Now create a discard request + TextureRequestArgs discardArgs = new TextureRequestArgs(); + discardArgs.RequestedAssetID = m_testImageAsset.FullID; + discardArgs.DiscardLevel = -1; + discardArgs.PacketNumber = 1; + discardArgs.Priority = 0; + discardArgs.requestSequence = 2; + llim.EnqueueReq(discardArgs); + + llim.ProcessImageQueue(20); + + Assert.That(tc.SentImageDataPackets.Count, Is.EqualTo(0)); + } + + [Test] + public void TestMissingImage() + { + TestHelpers.InMethod(); +// XmlConfigurator.Configure(); + + TextureRequestArgs args = new TextureRequestArgs(); + args.RequestedAssetID = m_testImageAsset.FullID; + args.DiscardLevel = 0; + args.PacketNumber = 1; + args.Priority = 5; + args.requestSequence = 1; + + llim.EnqueueReq(args); + llim.ProcessImageQueue(20); + + Assert.That(tc.SentImageDataPackets.Count, Is.EqualTo(0)); + Assert.That(tc.SentImageNotInDatabasePackets.Count, Is.EqualTo(1)); + } + } +} \ No newline at end of file diff --git a/Tests/OpenSim.Region.ClientStack.LindenUDP.Tests/OpenSim.Region.ClientStack.LindenUDP.Tests.csproj b/Tests/OpenSim.Region.ClientStack.LindenUDP.Tests/OpenSim.Region.ClientStack.LindenUDP.Tests.csproj new file mode 100644 index 00000000000..3b6c25c9ac0 --- /dev/null +++ b/Tests/OpenSim.Region.ClientStack.LindenUDP.Tests/OpenSim.Region.ClientStack.LindenUDP.Tests.csproj @@ -0,0 +1,36 @@ + + + net6.0 + + + + ..\..\..\..\..\..\bin\Nini.dll + False + + + ..\..\..\..\..\..\bin\OpenMetaverse.dll + False + + + ..\..\..\..\..\..\bin\OpenMetaverseTypes.dll + False + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Tests/OpenSim.Region.ClientStack.LindenUDP.Tests/PacketHandlerTests.cs b/Tests/OpenSim.Region.ClientStack.LindenUDP.Tests/PacketHandlerTests.cs new file mode 100644 index 00000000000..1731aa97b04 --- /dev/null +++ b/Tests/OpenSim.Region.ClientStack.LindenUDP.Tests/PacketHandlerTests.cs @@ -0,0 +1,104 @@ +/* + * 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 Nini.Config; +using NUnit.Framework; +using OpenMetaverse; +using OpenMetaverse.Packets; +using OpenSim.Framework; +using OpenSim.Tests.Common; + +namespace OpenSim.Region.ClientStack.LindenUDP.Tests +{ + /// + /// Tests for the LL packet handler + /// + [TestFixture] + public class PacketHandlerTests : OpenSimTestCase + { +// [Test] +// /// +// /// More a placeholder, really +// /// +// public void InPacketTest() +// { +// TestHelper.InMethod(); +// +// AgentCircuitData agent = new AgentCircuitData(); +// agent.AgentID = UUID.Random(); +// agent.firstname = "testfirstname"; +// agent.lastname = "testlastname"; +// agent.SessionID = UUID.Zero; +// agent.SecureSessionID = UUID.Zero; +// agent.circuitcode = 123; +// agent.BaseFolder = UUID.Zero; +// agent.InventoryFolder = UUID.Zero; +// agent.startpos = Vector3.Zero; +// agent.CapsPath = "http://wibble.com"; +// +// TestLLUDPServer testLLUDPServer; +// TestLLPacketServer testLLPacketServer; +// AgentCircuitManager acm; +// IScene scene = new MockScene(); +// SetupStack(scene, out testLLUDPServer, out testLLPacketServer, out acm); +// +// TestClient testClient = new TestClient(agent, scene); +// +// LLPacketHandler packetHandler +// = new LLPacketHandler(testClient, testLLPacketServer, new ClientStackUserSettings()); +// +// packetHandler.InPacket(new AgentAnimationPacket()); +// LLQueItem receivedPacket = packetHandler.PacketQueue.Dequeue(); +// +// Assert.That(receivedPacket, Is.Not.Null); +// Assert.That(receivedPacket.Incoming, Is.True); +// Assert.That(receivedPacket.Packet, Is.TypeOf(typeof(AgentAnimationPacket))); +// } +// +// /// +// /// Add a client for testing +// /// +// /// +// /// +// /// +// /// Agent circuit manager used in setting up the stack +// protected void SetupStack( +// IScene scene, out TestLLUDPServer testLLUDPServer, out TestLLPacketServer testPacketServer, +// out AgentCircuitManager acm) +// { +// IConfigSource configSource = new IniConfigSource(); +// ClientStackUserSettings userSettings = new ClientStackUserSettings(); +// testLLUDPServer = new TestLLUDPServer(); +// acm = new AgentCircuitManager(); +// +// uint port = 666; +// testLLUDPServer.Initialise(null, ref port, 0, false, configSource, acm); +// testPacketServer = new TestLLPacketServer(testLLUDPServer, userSettings); +// testLLUDPServer.LocalScene = scene; +// } + } +} diff --git a/Tests/OpenSim.Region.ClientStack.LindenUDP.Tests/Resources/4-tile2.jp2 b/Tests/OpenSim.Region.ClientStack.LindenUDP.Tests/Resources/4-tile2.jp2 new file mode 100644 index 00000000000..8c631046e87 Binary files /dev/null and b/Tests/OpenSim.Region.ClientStack.LindenUDP.Tests/Resources/4-tile2.jp2 differ diff --git a/Tests/OpenSim.Region.ClientStack.LindenUDP.Tests/ThrottleTests.cs b/Tests/OpenSim.Region.ClientStack.LindenUDP.Tests/ThrottleTests.cs new file mode 100644 index 00000000000..873b1e50e7c --- /dev/null +++ b/Tests/OpenSim.Region.ClientStack.LindenUDP.Tests/ThrottleTests.cs @@ -0,0 +1,432 @@ +/* + * 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 Nini.Config; +using NUnit.Framework; +using OpenMetaverse.Packets; +using OpenSim.Framework; +using OpenSim.Region.Framework.Scenes; +using OpenSim.Tests.Common; + +namespace OpenSim.Region.ClientStack.LindenUDP.Tests +{ + /* + [TestFixture] + public class ThrottleTests : 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] + public void TestSetRequestDripRate() + { + + TestHelpers.InMethod(); + + TokenBucket tb = new TokenBucket(null, 5000f,10000f); + AssertRates(tb, 5000, 0, 5000, 0); + + tb.RequestedDripRate = 4000f; + AssertRates(tb, 4000, 0, 4000, 0); + + tb.RequestedDripRate = 6000; + AssertRates(tb, 6000, 0, 6000, 0); + + } + + [Test] + public void TestSetRequestDripRateWithMax() + { + TestHelpers.InMethod(); + + TokenBucket tb = new TokenBucket(null, 5000,15000); + AssertRates(tb, 5000, 0, 5000, 10000); + + tb.RequestedDripRate = 4000; + AssertRates(tb, 4000, 0, 4000, 10000); + + tb.RequestedDripRate = 6000; + AssertRates(tb, 6000, 0, 6000, 10000); + + tb.RequestedDripRate = 12000; + AssertRates(tb, 10000, 0, 10000, 10000); + } + + [Test] + public void TestSetRequestDripRateWithChildren() + { + TestHelpers.InMethod(); + + TokenBucket tbParent = new TokenBucket("tbParent", null, 0); + TokenBucket tbChild1 = new TokenBucket("tbChild1", tbParent, 3000); + TokenBucket tbChild2 = new TokenBucket("tbChild2", tbParent, 5000); + + AssertRates(tbParent, 8000, 8000, 8000, 0); + AssertRates(tbChild1, 3000, 0, 3000, 0); + AssertRates(tbChild2, 5000, 0, 5000, 0); + + // Test: Setting a parent request greater than total children requests. + tbParent.RequestedDripRate = 10000; + + AssertRates(tbParent, 10000, 8000, 8000, 0); + AssertRates(tbChild1, 3000, 0, 3000, 0); + AssertRates(tbChild2, 5000, 0, 5000, 0); + + // Test: Setting a parent request lower than total children requests. + tbParent.RequestedDripRate = 6000; + + AssertRates(tbParent, 6000, 8000, 6000, 0); + AssertRates(tbChild1, 3000, 0, 6000 / 8 * 3, 0); + AssertRates(tbChild2, 5000, 0, 6000 / 8 * 5, 0); + + } + + private void AssertRates( + TokenBucket tb, double requestedDripRate, double totalDripRequest, double dripRate, double maxDripRate) + { + Assert.AreEqual((int)requestedDripRate, tb.RequestedDripRate, "Requested drip rate"); + Assert.AreEqual((int)totalDripRequest, tb.TotalDripRequest, "Total drip request"); + Assert.AreEqual((int)dripRate, tb.DripRate, "Drip rate"); + Assert.AreEqual((int)maxDripRate, tb.MaxDripRate, "Max drip rate"); + } + + [Test] + public void TestClientThrottleSetNoLimit() + { + TestHelpers.InMethod(); +// TestHelpers.EnableLogging(); + + Scene scene = new SceneHelpers().SetupScene(); + TestLLUDPServer udpServer = ClientStackHelpers.AddUdpServer(scene); + + ScenePresence sp + = ClientStackHelpers.AddChildClient( + scene, udpServer, TestHelpers.ParseTail(0x1), TestHelpers.ParseTail(0x2), 123456); + + LLUDPClient udpClient = ((LLClientView)sp.ControllingClient).UDPClient; + + udpServer.Throttle.DebugLevel = 1; + udpClient.ThrottleDebugLevel = 1; + + int resendBytes = 1000; + int landBytes = 2000; + int windBytes = 3000; + int cloudBytes = 4000; + int taskBytes = 5000; + int textureBytes = 6000; + int assetBytes = 7000; + + SetThrottles( + udpClient, resendBytes, landBytes, windBytes, cloudBytes, taskBytes, textureBytes, assetBytes); + + // We expect this to be lower because of the minimum bound set by MTU + int totalBytes = LLUDPServer.MTU + landBytes + windBytes + cloudBytes + taskBytes + textureBytes + assetBytes; + + AssertThrottles( + udpClient, + LLUDPServer.MTU, landBytes, windBytes, cloudBytes, taskBytes, + textureBytes, assetBytes, totalBytes, 0, 0); + } + + [Test] + public void TestClientThrottleAdaptiveNoLimit() + { + TestHelpers.InMethod(); +// TestHelpers.EnableLogging(); + + Scene scene = new SceneHelpers().SetupScene(); + + IniConfigSource ics = new IniConfigSource(); + IConfig config = ics.AddConfig("ClientStack.LindenUDP"); + config.Set("enable_adaptive_throttles", true); + config.Set("adaptive_throttle_min_bps", 32000); + + TestLLUDPServer udpServer = ClientStackHelpers.AddUdpServer(scene, ics); + + ScenePresence sp + = ClientStackHelpers.AddChildClient( + scene, udpServer, TestHelpers.ParseTail(0x1), TestHelpers.ParseTail(0x2), 123456); + + LLUDPClient udpClient = ((LLClientView)sp.ControllingClient).UDPClient; + + udpServer.Throttle.DebugLevel = 1; + udpClient.ThrottleDebugLevel = 1; + + // Total is 275000 + int resendBytes = 5000; // this is set low to test the minimum throttle override + int landBytes = 20000; + int windBytes = 30000; + int cloudBytes = 40000; + int taskBytes = 50000; + int textureBytes = 60000; + int assetBytes = 70000; + int totalBytes = resendBytes + landBytes + windBytes + cloudBytes + taskBytes + textureBytes + assetBytes; + + SetThrottles( + udpClient, resendBytes, landBytes, windBytes, cloudBytes, taskBytes, textureBytes, assetBytes); + + // Ratio of current adaptive drip rate to requested bytes, minimum rate is 32000 + double commitRatio = 32000.0 / totalBytes; + + AssertThrottles( + udpClient, + LLUDPServer.MTU, landBytes * commitRatio, windBytes * commitRatio, cloudBytes * commitRatio, taskBytes * commitRatio, + textureBytes * commitRatio, assetBytes * commitRatio, udpClient.FlowThrottle.AdjustedDripRate, totalBytes, 0); + + // Test an increase in target throttle, ack of 20 packets adds 20 * LLUDPServer.MTU bytes + // to the throttle, recompute commitratio from those numbers + udpClient.FlowThrottle.AcknowledgePackets(20); + commitRatio = (32000.0 + 20.0 * LLUDPServer.MTU) / totalBytes; + + AssertThrottles( + udpClient, + LLUDPServer.MTU, landBytes * commitRatio, windBytes * commitRatio, cloudBytes * commitRatio, taskBytes * commitRatio, + textureBytes * commitRatio, assetBytes * commitRatio, udpClient.FlowThrottle.AdjustedDripRate, totalBytes, 0); + + // Test a decrease in target throttle, adaptive throttle should cut the rate by 50% with a floor + // set by the minimum adaptive rate + udpClient.FlowThrottle.ExpirePackets(1); + commitRatio = (32000.0 + (20.0 * LLUDPServer.MTU)/Math.Pow(2,1)) / totalBytes; + + AssertThrottles( + udpClient, + LLUDPServer.MTU, landBytes * commitRatio, windBytes * commitRatio, cloudBytes * commitRatio, taskBytes * commitRatio, + textureBytes * commitRatio, assetBytes * commitRatio, udpClient.FlowThrottle.AdjustedDripRate, totalBytes, 0); + } + + /// + /// Test throttle setttings where max client throttle has been limited server side. + /// + [Test] + public void TestSingleClientThrottleRegionLimited() + { + TestHelpers.InMethod(); + // TestHelpers.EnableLogging(); + + int resendBytes = 6000; + int landBytes = 8000; + int windBytes = 10000; + int cloudBytes = 12000; + int taskBytes = 14000; + int textureBytes = 16000; + int assetBytes = 18000; + int totalBytes + = (int)((resendBytes + landBytes + windBytes + cloudBytes + taskBytes + textureBytes + assetBytes) / 2); + + Scene scene = new SceneHelpers().SetupScene(); + TestLLUDPServer udpServer = ClientStackHelpers.AddUdpServer(scene); + udpServer.Throttle.RequestedDripRate = totalBytes; + + ScenePresence sp1 + = ClientStackHelpers.AddChildClient( + scene, udpServer, TestHelpers.ParseTail(0x1), TestHelpers.ParseTail(0x2), 123456); + + LLUDPClient udpClient1 = ((LLClientView)sp1.ControllingClient).UDPClient; + + SetThrottles( + udpClient1, resendBytes, landBytes, windBytes, cloudBytes, taskBytes, textureBytes, assetBytes); + + AssertThrottles( + udpClient1, + resendBytes / 2, landBytes / 2, windBytes / 2, cloudBytes / 2, taskBytes / 2, + textureBytes / 2, assetBytes / 2, totalBytes, 0, 0); + + // Test: Now add another client + ScenePresence sp2 + = ClientStackHelpers.AddChildClient( + scene, udpServer, TestHelpers.ParseTail(0x10), TestHelpers.ParseTail(0x20), 123457); + + LLUDPClient udpClient2 = ((LLClientView)sp2.ControllingClient).UDPClient; + // udpClient.ThrottleDebugLevel = 1; + + SetThrottles( + udpClient2, resendBytes, landBytes, windBytes, cloudBytes, taskBytes, textureBytes, assetBytes); + + AssertThrottles( + udpClient1, + resendBytes / 4, landBytes / 4, windBytes / 4, cloudBytes / 4, taskBytes / 4, + textureBytes / 4, assetBytes / 4, totalBytes / 2, 0, 0); + + AssertThrottles( + udpClient2, + resendBytes / 4, landBytes / 4, windBytes / 4, cloudBytes / 4, taskBytes / 4, + textureBytes / 4, assetBytes / 4, totalBytes / 2, 0, 0); + } + + /// + /// Test throttle setttings where max client throttle has been limited server side. + /// + [Test] + public void TestClientThrottlePerClientLimited() + { + TestHelpers.InMethod(); + // TestHelpers.EnableLogging(); + + int resendBytes = 4000; + int landBytes = 6000; + int windBytes = 8000; + int cloudBytes = 10000; + int taskBytes = 12000; + int textureBytes = 14000; + int assetBytes = 16000; + int totalBytes + = (int)((resendBytes + landBytes + windBytes + cloudBytes + taskBytes + textureBytes + assetBytes) / 2); + + Scene scene = new SceneHelpers().SetupScene(); + TestLLUDPServer udpServer = ClientStackHelpers.AddUdpServer(scene); + udpServer.ThrottleRates.Total = totalBytes; + + ScenePresence sp + = ClientStackHelpers.AddChildClient( + scene, udpServer, TestHelpers.ParseTail(0x1), TestHelpers.ParseTail(0x2), 123456); + + LLUDPClient udpClient = ((LLClientView)sp.ControllingClient).UDPClient; + // udpClient.ThrottleDebugLevel = 1; + + SetThrottles( + udpClient, resendBytes, landBytes, windBytes, cloudBytes, taskBytes, textureBytes, assetBytes); + + AssertThrottles( + udpClient, + resendBytes / 2, landBytes / 2, windBytes / 2, cloudBytes / 2, taskBytes / 2, + textureBytes / 2, assetBytes / 2, totalBytes, 0, totalBytes); + } + + [Test] + public void TestClientThrottlePerClientAndRegionLimited() + { + TestHelpers.InMethod(); + //TestHelpers.EnableLogging(); + + int resendBytes = 4000; + int landBytes = 6000; + int windBytes = 8000; + int cloudBytes = 10000; + int taskBytes = 12000; + int textureBytes = 14000; + int assetBytes = 16000; + + // current total 70000 + int totalBytes = resendBytes + landBytes + windBytes + cloudBytes + taskBytes + textureBytes + assetBytes; + + Scene scene = new SceneHelpers().SetupScene(); + TestLLUDPServer udpServer = ClientStackHelpers.AddUdpServer(scene); + udpServer.ThrottleRates.Total = (int)(totalBytes * 1.1); + udpServer.Throttle.RequestedDripRate = (int)(totalBytes * 1.5); + + ScenePresence sp1 + = ClientStackHelpers.AddChildClient( + scene, udpServer, TestHelpers.ParseTail(0x1), TestHelpers.ParseTail(0x2), 123456); + + LLUDPClient udpClient1 = ((LLClientView)sp1.ControllingClient).UDPClient; + udpClient1.ThrottleDebugLevel = 1; + + SetThrottles( + udpClient1, resendBytes, landBytes, windBytes, cloudBytes, taskBytes, textureBytes, assetBytes); + + AssertThrottles( + udpClient1, + resendBytes, landBytes, windBytes, cloudBytes, taskBytes, + textureBytes, assetBytes, totalBytes, 0, totalBytes * 1.1); + + // Now add another client + ScenePresence sp2 + = ClientStackHelpers.AddChildClient( + scene, udpServer, TestHelpers.ParseTail(0x10), TestHelpers.ParseTail(0x20), 123457); + + LLUDPClient udpClient2 = ((LLClientView)sp2.ControllingClient).UDPClient; + udpClient2.ThrottleDebugLevel = 1; + + SetThrottles( + udpClient2, resendBytes, landBytes, windBytes, cloudBytes, taskBytes, textureBytes, assetBytes); + + AssertThrottles( + udpClient1, + resendBytes * 0.75, landBytes * 0.75, windBytes * 0.75, cloudBytes * 0.75, taskBytes * 0.75, + textureBytes * 0.75, assetBytes * 0.75, totalBytes * 0.75, 0, totalBytes * 1.1); + + AssertThrottles( + udpClient2, + resendBytes * 0.75, landBytes * 0.75, windBytes * 0.75, cloudBytes * 0.75, taskBytes * 0.75, + textureBytes * 0.75, assetBytes * 0.75, totalBytes * 0.75, 0, totalBytes * 1.1); + } + + private void AssertThrottles( + LLUDPClient udpClient, + double resendBytes, double landBytes, double windBytes, double cloudBytes, double taskBytes, double textureBytes, double assetBytes, + double totalBytes, double targetBytes, double maxBytes) + { + ClientInfo ci = udpClient.GetClientInfo(); + +// Console.WriteLine( +// "Resend={0}, Land={1}, Wind={2}, Cloud={3}, Task={4}, Texture={5}, Asset={6}, TOTAL = {7}", +// ci.resendThrottle, ci.landThrottle, ci.windThrottle, ci.cloudThrottle, ci.taskThrottle, ci.textureThrottle, ci.assetThrottle, ci.totalThrottle); + + Assert.AreEqual((int)resendBytes, ci.resendThrottle, "Resend"); + Assert.AreEqual((int)landBytes, ci.landThrottle, "Land"); + Assert.AreEqual((int)windBytes, ci.windThrottle, "Wind"); + Assert.AreEqual((int)cloudBytes, ci.cloudThrottle, "Cloud"); + Assert.AreEqual((int)taskBytes, ci.taskThrottle, "Task"); + Assert.AreEqual((int)textureBytes, ci.textureThrottle, "Texture"); + Assert.AreEqual((int)assetBytes, ci.assetThrottle, "Asset"); + Assert.AreEqual((int)totalBytes, ci.totalThrottle, "Total"); + Assert.AreEqual((int)targetBytes, ci.targetThrottle, "Target"); + Assert.AreEqual((int)maxBytes, ci.maxThrottle, "Max"); + } + + private void SetThrottles( + LLUDPClient udpClient, int resendBytes, int landBytes, int windBytes, int cloudBytes, int taskBytes, int textureBytes, int assetBytes) + { + byte[] throttles = new byte[28]; + + Array.Copy(BitConverter.GetBytes((float)resendBytes * 8), 0, throttles, 0, 4); + Array.Copy(BitConverter.GetBytes((float)landBytes * 8), 0, throttles, 4, 4); + Array.Copy(BitConverter.GetBytes((float)windBytes * 8), 0, throttles, 8, 4); + Array.Copy(BitConverter.GetBytes((float)cloudBytes * 8), 0, throttles, 12, 4); + Array.Copy(BitConverter.GetBytes((float)taskBytes * 8), 0, throttles, 16, 4); + Array.Copy(BitConverter.GetBytes((float)textureBytes * 8), 0, throttles, 20, 4); + Array.Copy(BitConverter.GetBytes((float)assetBytes * 8), 0, throttles, 24, 4); + + udpClient.SetThrottles(throttles); + } + } + */ +} \ No newline at end of file diff --git a/Tests/OpenSim.Region.CoreModules.Tests/Asset/Tests/FlotsamAssetCacheTests.cs b/Tests/OpenSim.Region.CoreModules.Tests/Asset/Tests/FlotsamAssetCacheTests.cs new file mode 100644 index 00000000000..dbb794142e6 --- /dev/null +++ b/Tests/OpenSim.Region.CoreModules.Tests/Asset/Tests/FlotsamAssetCacheTests.cs @@ -0,0 +1,127 @@ +/* + * 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 System.IO; +using System.Reflection; +using System.Threading; +using log4net.Config; +using Nini.Config; +using NUnit.Framework; +using OpenMetaverse; +using OpenMetaverse.Assets; +using OpenSim.Framework; +using OpenSim.Region.Framework.Scenes; +using OpenSim.Region.Framework.Scenes.Serialization; +using OpenSim.Tests.Common; + +namespace OpenSim.Region.CoreModules.Asset.Tests +{ + /// + /// At the moment we're only test the in-memory part of the FlotsamAssetCache. This is a considerable weakness. + /// + [TestFixture] + public class FlotsamAssetCacheTests : OpenSimTestCase + { + protected TestScene m_scene; + protected FlotsamAssetCache m_cache; + + [SetUp] + public override void SetUp() + { + base.SetUp(); + + IConfigSource config = new IniConfigSource(); + + config.AddConfig("Modules"); + config.Configs["Modules"].Set("AssetCaching", "FlotsamAssetCache"); + config.AddConfig("AssetCache"); + config.Configs["AssetCache"].Set("FileCacheEnabled", "false"); + config.Configs["AssetCache"].Set("MemoryCacheEnabled", "true"); + + m_cache = new FlotsamAssetCache(); + m_scene = new SceneHelpers().SetupScene(); + SceneHelpers.SetupSceneModules(m_scene, config, m_cache); + } + + [Test] + public void TestCacheAsset() + { + TestHelpers.InMethod(); +// log4net.Config.XmlConfigurator.Configure(); + + AssetBase asset = AssetHelpers.CreateNotecardAsset(); + asset.ID = TestHelpers.ParseTail(0x1).ToString(); + + // Check we don't get anything before the asset is put in the cache + AssetBase retrievedAsset = m_cache.Get(asset.ID.ToString()); + Assert.That(retrievedAsset, Is.Null); + + m_cache.Store(asset); + + // Check that asset is now in cache + retrievedAsset = m_cache.Get(asset.ID.ToString()); + Assert.That(retrievedAsset, Is.Not.Null); + Assert.That(retrievedAsset.ID, Is.EqualTo(asset.ID)); + } + + [Test] + public void TestExpireAsset() + { + TestHelpers.InMethod(); +// log4net.Config.XmlConfigurator.Configure(); + + AssetBase asset = AssetHelpers.CreateNotecardAsset(); + asset.ID = TestHelpers.ParseTail(0x2).ToString(); + + m_cache.Store(asset); + + m_cache.Expire(asset.ID); + + AssetBase retrievedAsset = m_cache.Get(asset.ID.ToString()); + Assert.That(retrievedAsset, Is.Null); + } + + [Test] + public void TestClearCache() + { + TestHelpers.InMethod(); +// log4net.Config.XmlConfigurator.Configure(); + + AssetBase asset = AssetHelpers.CreateNotecardAsset(); + asset.ID = TestHelpers.ParseTail(0x2).ToString(); + + m_cache.Store(asset); + + m_cache.Clear(); + + AssetBase retrievedAsset = m_cache.Get(asset.ID.ToString()); + Assert.That(retrievedAsset, Is.Null); + } + } +} \ No newline at end of file diff --git a/Tests/OpenSim.Region.CoreModules.Tests/Avatar/Attachments/Tests/AttachmentsModuleTests.cs b/Tests/OpenSim.Region.CoreModules.Tests/Avatar/Attachments/Tests/AttachmentsModuleTests.cs new file mode 100644 index 00000000000..941853c947a --- /dev/null +++ b/Tests/OpenSim.Region.CoreModules.Tests/Avatar/Attachments/Tests/AttachmentsModuleTests.cs @@ -0,0 +1,1030 @@ +/* + * 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 System.Reflection; +using System.Text; +using System.Threading; +using System.Timers; +using System.Xml; +using Timer=System.Timers.Timer; +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.Attachments; +using OpenSim.Region.CoreModules.Framework; +using OpenSim.Region.CoreModules.Framework.EntityTransfer; +using OpenSim.Region.CoreModules.Framework.InventoryAccess; +using OpenSim.Region.CoreModules.Scripting.WorldComm; +using OpenSim.Region.CoreModules.ServiceConnectorsOut.Simulation; +using OpenSim.Region.CoreModules.World.Serialiser; +using OpenSim.Region.Framework.Scenes; +using OpenSim.Region.Framework.Interfaces; +using OpenSim.Region.ScriptEngine.Interfaces; +using OpenSim.Region.ScriptEngine.XEngine; +using OpenSim.Services.Interfaces; +using OpenSim.Tests.Common; + +namespace OpenSim.Region.CoreModules.Avatar.Attachments.Tests +{ +/* + /// + /// Attachment tests + /// + [TestFixture] + public class AttachmentsModuleTests : OpenSimTestCase + { + private AutoResetEvent m_chatEvent = new AutoResetEvent(false); +// private OSChatMessage m_osChatMessageReceived; + + // Used to test whether the operations have fired the attach event. Must be reset after each test. + private int m_numberOfAttachEventsFired; + + [TestFixtureSetUp] + public void FixtureInit() + { + // Don't allow tests to be bamboozled by asynchronous events. Execute everything on the same thread. + Util.FireAndForgetMethod = FireAndForgetMethod.None; + } + + [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 not to worry about such things. + Util.FireAndForgetMethod = Util.DefaultFireAndForgetMethod; + } + + private void OnChatFromWorld(object sender, OSChatMessage oscm) + { +// Console.WriteLine("Got chat [{0}]", oscm.Message); + +// m_osChatMessageReceived = oscm; + m_chatEvent.Set(); + } + + private Scene CreateTestScene() + { + IConfigSource config = new IniConfigSource(); + List modules = new List(); + + AddCommonConfig(config, modules); + + Scene scene + = new SceneHelpers().SetupScene( + "attachments-test-scene", TestHelpers.ParseTail(999), 1000, 1000, config); + SceneHelpers.SetupSceneModules(scene, config, modules.ToArray()); + + scene.EventManager.OnAttach += (localID, itemID, avatarID) => m_numberOfAttachEventsFired++; + + return scene; + } + + private Scene CreateScriptingEnabledTestScene() + { + IConfigSource config = new IniConfigSource(); + List modules = new List(); + + AddCommonConfig(config, modules); + AddScriptingConfig(config, modules); + + Scene scene + = new SceneHelpers().SetupScene( + "attachments-test-scene", TestHelpers.ParseTail(999), 1000, 1000, config); + SceneHelpers.SetupSceneModules(scene, config, modules.ToArray()); + + scene.StartScripts(); + + return scene; + } + + private void AddCommonConfig(IConfigSource config, List modules) + { + config.AddConfig("Modules"); + config.Configs["Modules"].Set("InventoryAccessModule", "BasicInventoryAccessModule"); + + AttachmentsModule attMod = new AttachmentsModule(); + attMod.DebugLevel = 1; + modules.Add(attMod); + modules.Add(new BasicInventoryAccessModule()); + } + + private void AddScriptingConfig(IConfigSource config, List modules) + { + IConfig startupConfig = config.AddConfig("Startup"); + startupConfig.Set("DefaultScriptEngine", "XEngine"); + + IConfig xEngineConfig = config.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"); + + modules.Add(new XEngine()); + + // Necessary to stop serialization complaining + // FIXME: Stop this being necessary if at all possible +// modules.Add(new WorldCommModule()); + } + + /// + /// Creates an attachment item in the given user's inventory. Does not attach. + /// + /// + /// A user with the given ID and an inventory must already exist. + /// + /// + /// The attachment item. + /// + /// + /// + /// + /// + /// + private InventoryItemBase CreateAttachmentItem( + Scene scene, UUID userId, string attName, int rawItemId, int rawAssetId) + { + return UserInventoryHelpers.CreateInventoryItem( + scene, + attName, + TestHelpers.ParseTail(rawItemId), + TestHelpers.ParseTail(rawAssetId), + userId, + InventoryType.Object); + } + + [Test] + public void TestAddAttachmentFromGround() + { + TestHelpers.InMethod(); +// TestHelpers.EnableLogging(); + + m_numberOfAttachEventsFired = 0; + + Scene scene = CreateTestScene(); + UserAccount ua1 = UserAccountHelpers.CreateUserWithInventory(scene, 0x1); + ScenePresence sp = SceneHelpers.AddScenePresence(scene, ua1); + + string attName = "att"; + + SceneObjectGroup so = SceneHelpers.AddSceneObject(scene, attName, sp.UUID); + Assert.That(so.Backup, Is.True); + + m_numberOfAttachEventsFired = 0; + scene.AttachmentsModule.AttachObject(sp, so, (uint)AttachmentPoint.Chest, false, true, false); + + // Check status on scene presence + Assert.That(sp.HasAttachments(), Is.True); + List attachments = sp.GetAttachments(); + Assert.That(attachments.Count, Is.EqualTo(1)); + SceneObjectGroup attSo = attachments[0]; + Assert.That(attSo.Name, Is.EqualTo(attName)); + Assert.That(attSo.AttachmentPoint, Is.EqualTo((byte)AttachmentPoint.Chest)); + Assert.That(attSo.IsAttachment); + Assert.That(attSo.UsesPhysics, Is.False); + Assert.That(attSo.IsTemporary, Is.False); + Assert.That(attSo.Backup, Is.False); + + // Check item status +// Assert.That( +// sp.Appearance.GetAttachpoint(attSo.FromItemID), +// Is.EqualTo((int)AttachmentPoint.Chest)); + + InventoryItemBase attachmentItem = scene.InventoryService.GetItem(sp.UUID, attSo.FromItemID); + Assert.That(attachmentItem, Is.Not.Null); + Assert.That(attachmentItem.Name, Is.EqualTo(attName)); + + InventoryFolderBase targetFolder = scene.InventoryService.GetFolderForType(sp.UUID, FolderType.Object); + Assert.That(attachmentItem.Folder, Is.EqualTo(targetFolder.ID)); + + Assert.That(scene.GetSceneObjectGroups().Count, Is.EqualTo(1)); + + // Check events + Assert.That(m_numberOfAttachEventsFired, Is.EqualTo(1)); + } + + [Test] + public void TestWearAttachmentFromGround() + { + TestHelpers.InMethod(); +// TestHelpers.EnableLogging(); + + Scene scene = CreateTestScene(); + UserAccount ua1 = UserAccountHelpers.CreateUserWithInventory(scene, 0x1); + ScenePresence sp = SceneHelpers.AddScenePresence(scene, ua1); + + SceneObjectGroup so2 = SceneHelpers.AddSceneObject(scene, "att2", sp.UUID); + + { + SceneObjectGroup so = SceneHelpers.AddSceneObject(scene, "att1", sp.UUID); + + m_numberOfAttachEventsFired = 0; + scene.AttachmentsModule.AttachObject(sp, so, (uint)AttachmentPoint.Default, false, true, false); + + // Check status on scene presence + Assert.That(sp.HasAttachments(), Is.True); + List attachments = sp.GetAttachments(); + Assert.That(attachments.Count, Is.EqualTo(1)); + SceneObjectGroup attSo = attachments[0]; + Assert.That(attSo.Name, Is.EqualTo(so.Name)); + Assert.That(attSo.AttachmentPoint, Is.EqualTo((byte)AttachmentPoint.LeftHand)); + Assert.That(attSo.IsAttachment); + Assert.That(attSo.UsesPhysics, Is.False); + Assert.That(attSo.IsTemporary, Is.False); + + // Check item status +// Assert.That( +// sp.Appearance.GetAttachpoint(attSo.FromItemID), +// Is.EqualTo((int)AttachmentPoint.LeftHand)); + + InventoryItemBase attachmentItem = scene.InventoryService.GetItem(sp.UUID, attSo.FromItemID); + Assert.That(attachmentItem, Is.Not.Null); + Assert.That(attachmentItem.Name, Is.EqualTo(so.Name)); + + InventoryFolderBase targetFolder = scene.InventoryService.GetFolderForType(sp.UUID, FolderType.Object); + Assert.That(attachmentItem.Folder, Is.EqualTo(targetFolder.ID)); + + Assert.That(scene.GetSceneObjectGroups().Count, Is.EqualTo(2)); + + // Check events + Assert.That(m_numberOfAttachEventsFired, Is.EqualTo(1)); + } + + // Test wearing a different attachment from the ground. + { + scene.AttachmentsModule.AttachObject(sp, so2, (uint)AttachmentPoint.Default, false, true, false); + + // Check status on scene presence + Assert.That(sp.HasAttachments(), Is.True); + List attachments = sp.GetAttachments(); + Assert.That(attachments.Count, Is.EqualTo(1)); + SceneObjectGroup attSo = attachments[0]; + Assert.That(attSo.Name, Is.EqualTo(so2.Name)); + Assert.That(attSo.AttachmentPoint, Is.EqualTo((byte)AttachmentPoint.LeftHand)); + Assert.That(attSo.IsAttachment); + Assert.That(attSo.UsesPhysics, Is.False); + Assert.That(attSo.IsTemporary, Is.False); + + // Check item status +// Assert.That( +// sp.Appearance.GetAttachpoint(attSo.FromItemID), +// Is.EqualTo((int)AttachmentPoint.LeftHand)); + + InventoryItemBase attachmentItem = scene.InventoryService.GetItem(sp.UUID, attSo.FromItemID); + Assert.That(attachmentItem, Is.Not.Null); + Assert.That(attachmentItem.Name, Is.EqualTo(so2.Name)); + + InventoryFolderBase targetFolder = scene.InventoryService.GetFolderForType(sp.UUID, FolderType.Object); + Assert.That(attachmentItem.Folder, Is.EqualTo(targetFolder.ID)); + + Assert.That(scene.GetSceneObjectGroups().Count, Is.EqualTo(1)); + + // Check events + Assert.That(m_numberOfAttachEventsFired, Is.EqualTo(3)); + } + + // Test rewearing an already worn attachment from ground. Nothing should happen. + { + scene.AttachmentsModule.AttachObject(sp, so2, (uint)AttachmentPoint.Default, false, true, false); + + // Check status on scene presence + Assert.That(sp.HasAttachments(), Is.True); + List attachments = sp.GetAttachments(); + Assert.That(attachments.Count, Is.EqualTo(1)); + SceneObjectGroup attSo = attachments[0]; + Assert.That(attSo.Name, Is.EqualTo(so2.Name)); + Assert.That(attSo.AttachmentPoint, Is.EqualTo((byte)AttachmentPoint.LeftHand)); + Assert.That(attSo.IsAttachment); + Assert.That(attSo.UsesPhysics, Is.False); + Assert.That(attSo.IsTemporary, Is.False); + + // Check item status +// Assert.That( +// sp.Appearance.GetAttachpoint(attSo.FromItemID), +// Is.EqualTo((int)AttachmentPoint.LeftHand)); + + InventoryItemBase attachmentItem = scene.InventoryService.GetItem(sp.UUID, attSo.FromItemID); + Assert.That(attachmentItem, Is.Not.Null); + Assert.That(attachmentItem.Name, Is.EqualTo(so2.Name)); + + InventoryFolderBase targetFolder = scene.InventoryService.GetFolderForType(sp.UUID, FolderType.Object); + Assert.That(attachmentItem.Folder, Is.EqualTo(targetFolder.ID)); + + Assert.That(scene.GetSceneObjectGroups().Count, Is.EqualTo(1)); + + // Check events + Assert.That(m_numberOfAttachEventsFired, Is.EqualTo(3)); + } + } + + /// + /// Test that we do not attempt to attach an in-world object that someone else is sitting on. + /// + [Test] + public void TestAddSatOnAttachmentFromGround() + { + TestHelpers.InMethod(); +// TestHelpers.EnableLogging(); + + m_numberOfAttachEventsFired = 0; + + Scene scene = CreateTestScene(); + UserAccount ua1 = UserAccountHelpers.CreateUserWithInventory(scene, 0x1); + ScenePresence sp = SceneHelpers.AddScenePresence(scene, ua1); + + string attName = "att"; + + SceneObjectGroup so = SceneHelpers.AddSceneObject(scene, attName, sp.UUID); + + UserAccount ua2 = UserAccountHelpers.CreateUserWithInventory(scene, 0x2); + ScenePresence sp2 = SceneHelpers.AddScenePresence(scene, ua2); + + // Put avatar within 10m of the prim so that sit doesn't fail. + sp2.AbsolutePosition = new Vector3(0, 0, 0); + sp2.HandleAgentRequestSit(sp2.ControllingClient, sp2.UUID, so.UUID, Vector3.Zero); + + scene.AttachmentsModule.AttachObject(sp, so, (uint)AttachmentPoint.Chest, false, true, false); + + Assert.That(sp.HasAttachments(), Is.False); + Assert.That(scene.GetSceneObjectGroups().Count, Is.EqualTo(1)); + + // Check events + Assert.That(m_numberOfAttachEventsFired, Is.EqualTo(0)); + } + + [Test] + public void TestRezAttachmentFromInventory() + { + TestHelpers.InMethod(); +// TestHelpers.EnableLogging(); + + Scene scene = CreateTestScene(); + UserAccount ua1 = UserAccountHelpers.CreateUserWithInventory(scene, 0x1); + ScenePresence sp = SceneHelpers.AddScenePresence(scene, ua1.PrincipalID); + + InventoryItemBase attItem = CreateAttachmentItem(scene, ua1.PrincipalID, "att", 0x10, 0x20); + + { + scene.AttachmentsModule.RezSingleAttachmentFromInventory( + sp, attItem.ID, (uint)AttachmentPoint.Chest); + + // Check scene presence status + Assert.That(sp.HasAttachments(), Is.True); + List attachments = sp.GetAttachments(); + Assert.That(attachments.Count, Is.EqualTo(1)); + SceneObjectGroup attSo = attachments[0]; + Assert.That(attSo.Name, Is.EqualTo(attItem.Name)); + Assert.That(attSo.AttachmentPoint, Is.EqualTo((byte)AttachmentPoint.Chest)); + Assert.That(attSo.IsAttachment); + Assert.That(attSo.UsesPhysics, Is.False); + Assert.That(attSo.IsTemporary, Is.False); + Assert.IsFalse(attSo.Backup); + + // Check appearance status +// Assert.That(sp.Appearance.GetAttachments().Count, Is.EqualTo(1)); +// Assert.That(sp.Appearance.GetAttachpoint(attItem.ID), Is.EqualTo((int)AttachmentPoint.Chest)); + Assert.That(scene.GetSceneObjectGroups().Count, Is.EqualTo(1)); + + // Check events + Assert.That(m_numberOfAttachEventsFired, Is.EqualTo(1)); + } + + // Test attaching an already attached attachment + { + scene.AttachmentsModule.RezSingleAttachmentFromInventory( + sp, attItem.ID, (uint)AttachmentPoint.Chest); + + // Check scene presence status + Assert.That(sp.HasAttachments(), Is.True); + List attachments = sp.GetAttachments(); + Assert.That(attachments.Count, Is.EqualTo(1)); + SceneObjectGroup attSo = attachments[0]; + Assert.That(attSo.Name, Is.EqualTo(attItem.Name)); + Assert.That(attSo.AttachmentPoint, Is.EqualTo((byte)AttachmentPoint.Chest)); + Assert.That(attSo.IsAttachment); + Assert.That(attSo.UsesPhysics, Is.False); + Assert.That(attSo.IsTemporary, Is.False); + + // Check appearance status +// Assert.That(sp.Appearance.GetAttachments().Count, Is.EqualTo(1)); +// Assert.That(sp.Appearance.GetAttachpoint(attItem.ID), Is.EqualTo((int)AttachmentPoint.Chest)); + Assert.That(scene.GetSceneObjectGroups().Count, Is.EqualTo(1)); + + // Check events + Assert.That(m_numberOfAttachEventsFired, Is.EqualTo(1)); + } + } + + /// + /// Test wearing an attachment from inventory, as opposed to explicit choosing the rez point + /// + [Test] + public void TestWearAttachmentFromInventory() + { + TestHelpers.InMethod(); +// TestHelpers.EnableLogging(); + + Scene scene = CreateTestScene(); + UserAccount ua1 = UserAccountHelpers.CreateUserWithInventory(scene, 0x1); + ScenePresence sp = SceneHelpers.AddScenePresence(scene, ua1.PrincipalID); + + InventoryItemBase attItem1 = CreateAttachmentItem(scene, ua1.PrincipalID, "att1", 0x10, 0x20); + InventoryItemBase attItem2 = CreateAttachmentItem(scene, ua1.PrincipalID, "att2", 0x11, 0x21); + + { + m_numberOfAttachEventsFired = 0; + scene.AttachmentsModule.RezSingleAttachmentFromInventory(sp, attItem1.ID, (uint)AttachmentPoint.Default); + + // default attachment point is currently the left hand. + Assert.That(sp.HasAttachments(), Is.True); + List attachments = sp.GetAttachments(); + Assert.That(attachments.Count, Is.EqualTo(1)); + SceneObjectGroup attSo = attachments[0]; + Assert.That(attSo.Name, Is.EqualTo(attItem1.Name)); + Assert.That(attSo.AttachmentPoint, Is.EqualTo((byte)AttachmentPoint.LeftHand)); + Assert.That(attSo.IsAttachment); + + // Check appearance status +// Assert.That(sp.Appearance.GetAttachments().Count, Is.EqualTo(1)); +// Assert.That(sp.Appearance.GetAttachpoint(attItem1.ID), Is.EqualTo((int)AttachmentPoint.LeftHand)); + Assert.That(scene.GetSceneObjectGroups().Count, Is.EqualTo(1)); + + // Check events + Assert.That(m_numberOfAttachEventsFired, Is.EqualTo(1)); + } + + // Test wearing a second attachment at the same position + // Until multiple attachments at one point is implemented, this will remove the first attachment + // This test relies on both attachments having the same default attachment point (in this case LeftHand + // since none other has been set). + { + scene.AttachmentsModule.RezSingleAttachmentFromInventory(sp, attItem2.ID, (uint)AttachmentPoint.Default); + + // default attachment point is currently the left hand. + Assert.That(sp.HasAttachments(), Is.True); + List attachments = sp.GetAttachments(); + Assert.That(attachments.Count, Is.EqualTo(1)); + SceneObjectGroup attSo = attachments[0]; + Assert.That(attSo.Name, Is.EqualTo(attItem2.Name)); + Assert.That(attSo.AttachmentPoint, Is.EqualTo((byte)AttachmentPoint.LeftHand)); + Assert.That(attSo.IsAttachment); + + // Check appearance status +// Assert.That(sp.Appearance.GetAttachments().Count, Is.EqualTo(1)); +// Assert.That(sp.Appearance.GetAttachpoint(attItem2.ID), Is.EqualTo((int)AttachmentPoint.LeftHand)); + Assert.That(scene.GetSceneObjectGroups().Count, Is.EqualTo(1)); + + // Check events + Assert.That(m_numberOfAttachEventsFired, Is.EqualTo(3)); + } + + // Test wearing an already attached attachment + { + scene.AttachmentsModule.RezSingleAttachmentFromInventory(sp, attItem2.ID, (uint)AttachmentPoint.Default); + + // default attachment point is currently the left hand. + Assert.That(sp.HasAttachments(), Is.True); + List attachments = sp.GetAttachments(); + Assert.That(attachments.Count, Is.EqualTo(1)); + SceneObjectGroup attSo = attachments[0]; + Assert.That(attSo.Name, Is.EqualTo(attItem2.Name)); + Assert.That(attSo.AttachmentPoint, Is.EqualTo((byte)AttachmentPoint.LeftHand)); + Assert.That(attSo.IsAttachment); + + // Check appearance status +// Assert.That(sp.Appearance.GetAttachments().Count, Is.EqualTo(1)); +// Assert.That(sp.Appearance.GetAttachpoint(attItem2.ID), Is.EqualTo((int)AttachmentPoint.LeftHand)); + Assert.That(scene.GetSceneObjectGroups().Count, Is.EqualTo(1)); + + // Check events + Assert.That(m_numberOfAttachEventsFired, Is.EqualTo(3)); + } + } + + /// + /// Test specific conditions associated with rezzing a scripted attachment from inventory. + /// + [Test] + public void TestRezScriptedAttachmentFromInventory() + { + TestHelpers.InMethod(); + + Scene scene = CreateScriptingEnabledTestScene(); + UserAccount ua1 = UserAccountHelpers.CreateUserWithInventory(scene, 0x1); + ScenePresence sp = SceneHelpers.AddScenePresence(scene, ua1); + + SceneObjectGroup so = SceneHelpers.CreateSceneObject(1, sp.UUID, "att-name", 0x10); + TaskInventoryItem scriptItem + = TaskInventoryHelpers.AddScript( + scene.AssetService, + so.RootPart, + "scriptItem", + "default { attach(key id) { if (id != NULL_KEY) { llSay(0, \"Hello World\"); } } }"); + + InventoryItemBase userItem = UserInventoryHelpers.AddInventoryItem(scene, so, 0x100, 0x1000); + + // FIXME: Right now, we have to do a tricksy chat listen to make sure we know when the script is running. + // In the future, we need to be able to do this programatically more predicably. + scene.EventManager.OnChatFromWorld += OnChatFromWorld; + + m_chatEvent.Reset(); + scene.AttachmentsModule.RezSingleAttachmentFromInventory(sp, userItem.ID, (uint)AttachmentPoint.Chest); + + m_chatEvent.WaitOne(60000); + + // TODO: Need to have a test that checks the script is actually started but this involves a lot more + // plumbing of the script engine and either pausing for events or more infrastructure to turn off various + // script engine delays/asychronicity that isn't helpful in an automated regression testing context. + SceneObjectGroup attSo = scene.GetSceneObjectGroup(so.Name); + Assert.That(attSo.ContainsScripts(), Is.True); + + TaskInventoryItem reRezzedScriptItem = attSo.RootPart.Inventory.GetInventoryItem(scriptItem.Name); + IScriptModule xengine = scene.RequestModuleInterface(); + Assert.That(xengine.GetScriptState(reRezzedScriptItem.ItemID), Is.True); + } + + [Test] + public void TestDetachAttachmentToGround() + { + TestHelpers.InMethod(); +// log4net.Config.XmlConfigurator.Configure(); + + Scene scene = CreateTestScene(); + UserAccount ua1 = UserAccountHelpers.CreateUserWithInventory(scene, 0x1); + ScenePresence sp = SceneHelpers.AddScenePresence(scene, ua1.PrincipalID); + + InventoryItemBase attItem = CreateAttachmentItem(scene, ua1.PrincipalID, "att", 0x10, 0x20); + + ISceneEntity so + = scene.AttachmentsModule.RezSingleAttachmentFromInventory( + sp, attItem.ID, (uint)AttachmentPoint.Chest); + + m_numberOfAttachEventsFired = 0; + scene.AttachmentsModule.DetachSingleAttachmentToGround(sp, so.LocalId); + + // Check scene presence status + Assert.That(sp.HasAttachments(), Is.False); + List attachments = sp.GetAttachments(); + Assert.That(attachments.Count, Is.EqualTo(0)); + + // Check appearance status +// Assert.That(sp.Appearance.GetAttachments().Count, Is.EqualTo(0)); + + // Check item status + Assert.That(scene.InventoryService.GetItem(sp.UUID, attItem.ID), Is.Null); + + // Check object in scene + SceneObjectGroup soInScene = scene.GetSceneObjectGroup("att"); + Assert.That(soInScene, Is.Not.Null); + Assert.IsTrue(soInScene.Backup); + + // Check events + Assert.That(m_numberOfAttachEventsFired, Is.EqualTo(1)); + } + + [Test] + public void TestDetachAttachmentToInventory() + { + TestHelpers.InMethod(); + + Scene scene = CreateTestScene(); + UserAccount ua1 = UserAccountHelpers.CreateUserWithInventory(scene, 0x1); + ScenePresence sp = SceneHelpers.AddScenePresence(scene, ua1.PrincipalID); + + InventoryItemBase attItem = CreateAttachmentItem(scene, ua1.PrincipalID, "att", 0x10, 0x20); + + SceneObjectGroup so + = (SceneObjectGroup)scene.AttachmentsModule.RezSingleAttachmentFromInventory( + sp, attItem.ID, (uint)AttachmentPoint.Chest); + + m_numberOfAttachEventsFired = 0; + scene.AttachmentsModule.DetachSingleAttachmentToInv(sp, so); + + // Check status on scene presence + Assert.That(sp.HasAttachments(), Is.False); + List attachments = sp.GetAttachments(); + Assert.That(attachments.Count, Is.EqualTo(0)); + + // Check item status +// Assert.That(sp.Appearance.GetAttachpoint(attItem.ID), Is.EqualTo(0)); + + Assert.That(scene.GetSceneObjectGroups().Count, Is.EqualTo(0)); + + // Check events + Assert.That(m_numberOfAttachEventsFired, Is.EqualTo(1)); + } + + /// + /// Test specific conditions associated with detaching a scripted attachment from inventory. + /// + [Test] + public void TestDetachScriptedAttachmentToInventory() + { + TestHelpers.InMethod(); +// TestHelpers.EnableLogging(); + + Scene scene = CreateScriptingEnabledTestScene(); + UserAccount ua1 = UserAccountHelpers.CreateUserWithInventory(scene, 0x1); + ScenePresence sp = SceneHelpers.AddScenePresence(scene, ua1); + + SceneObjectGroup so = SceneHelpers.CreateSceneObject(1, sp.UUID, "att-name", 0x10); + TaskInventoryItem scriptTaskItem + = TaskInventoryHelpers.AddScript( + scene.AssetService, + so.RootPart, + "scriptItem", + "default { attach(key id) { if (id != NULL_KEY) { llSay(0, \"Hello World\"); } } }"); + + InventoryItemBase userItem = UserInventoryHelpers.AddInventoryItem(scene, so, 0x100, 0x1000); + + // FIXME: Right now, we have to do a tricksy chat listen to make sure we know when the script is running. + // In the future, we need to be able to do this programatically more predicably. + scene.EventManager.OnChatFromWorld += OnChatFromWorld; + + m_chatEvent.Reset(); + SceneObjectGroup rezzedSo + = (SceneObjectGroup)(scene.AttachmentsModule.RezSingleAttachmentFromInventory(sp, userItem.ID, (uint)AttachmentPoint.Chest)); + + // Wait for chat to signal rezzed script has been started. + m_chatEvent.WaitOne(60000); + + scene.AttachmentsModule.DetachSingleAttachmentToInv(sp, rezzedSo); + + InventoryItemBase userItemUpdated = scene.InventoryService.GetItem(userItem.Owner, userItem.ID); + AssetBase asset = scene.AssetService.Get(userItemUpdated.AssetID.ToString()); + + // TODO: It would probably be better here to check script state via the saving and retrieval of state + // information at a higher level, rather than having to inspect the serialization. + XmlDocument soXml = new XmlDocument(); + soXml.LoadXml(Encoding.UTF8.GetString(asset.Data)); + + XmlNodeList scriptStateNodes = soXml.GetElementsByTagName("ScriptState"); + Assert.That(scriptStateNodes.Count, Is.EqualTo(1)); + + // Re-rez the attachment to check script running state + SceneObjectGroup reRezzedSo = (SceneObjectGroup)(scene.AttachmentsModule.RezSingleAttachmentFromInventory(sp, userItem.ID, (uint)AttachmentPoint.Chest)); + + // Wait for chat to signal rezzed script has been started. + m_chatEvent.WaitOne(60000); + + TaskInventoryItem reRezzedScriptItem = reRezzedSo.RootPart.Inventory.GetInventoryItem(scriptTaskItem.Name); + IScriptModule xengine = scene.RequestModuleInterface(); + Assert.That(xengine.GetScriptState(reRezzedScriptItem.ItemID), Is.True); + +// Console.WriteLine(soXml.OuterXml); + } + + /// + /// Test that attachments don't hang about in the scene when the agent is closed + /// + [Test] + public void TestRemoveAttachmentsOnAvatarExit() + { + TestHelpers.InMethod(); +// log4net.Config.XmlConfigurator.Configure(); + + Scene scene = CreateTestScene(); + UserAccount ua1 = UserAccountHelpers.CreateUserWithInventory(scene, 0x1); + InventoryItemBase attItem = CreateAttachmentItem(scene, ua1.PrincipalID, "att", 0x10, 0x20); + + AgentCircuitData acd = SceneHelpers.GenerateAgentData(ua1.PrincipalID); + acd.Appearance = new AvatarAppearance(); + acd.Appearance.SetAttachment((int)AttachmentPoint.Chest, attItem.ID, attItem.AssetID); + ScenePresence presence = SceneHelpers.AddScenePresence(scene, acd); + + UUID rezzedAttID = presence.GetAttachments()[0].UUID; + + m_numberOfAttachEventsFired = 0; + scene.CloseAgent(presence.UUID, false); + + // Check that we can't retrieve this attachment from the scene. + Assert.That(scene.GetSceneObjectGroup(rezzedAttID), Is.Null); + + // Check events + Assert.That(m_numberOfAttachEventsFired, Is.EqualTo(0)); + } + + [Test] + public void TestRezAttachmentsOnAvatarEntrance() + { + TestHelpers.InMethod(); +// TestHelpers.EnableLogging(); + + Scene scene = CreateTestScene(); + UserAccount ua1 = UserAccountHelpers.CreateUserWithInventory(scene, 0x1); + InventoryItemBase attItem = CreateAttachmentItem(scene, ua1.PrincipalID, "att", 0x10, 0x20); + + AgentCircuitData acd = SceneHelpers.GenerateAgentData(ua1.PrincipalID); + acd.Appearance = new AvatarAppearance(); + acd.Appearance.SetAttachment((int)AttachmentPoint.Chest, attItem.ID, attItem.AssetID); + + m_numberOfAttachEventsFired = 0; + ScenePresence presence = SceneHelpers.AddScenePresence(scene, acd); + + Assert.That(presence.HasAttachments(), Is.True); + List attachments = presence.GetAttachments(); + + Assert.That(attachments.Count, Is.EqualTo(1)); + SceneObjectGroup attSo = attachments[0]; + Assert.That(attSo.Name, Is.EqualTo(attItem.Name)); + Assert.That(attSo.AttachmentPoint, Is.EqualTo((byte)AttachmentPoint.Chest)); + Assert.That(attSo.IsAttachment); + Assert.That(attSo.UsesPhysics, Is.False); + Assert.That(attSo.IsTemporary, Is.False); + Assert.IsFalse(attSo.Backup); + + // Check appearance status + List retreivedAttachments = presence.Appearance.GetAttachments(); + Assert.That(retreivedAttachments.Count, Is.EqualTo(1)); + Assert.That(retreivedAttachments[0].AttachPoint, Is.EqualTo((int)AttachmentPoint.Chest)); + Assert.That(retreivedAttachments[0].ItemID, Is.EqualTo(attItem.ID)); + Assert.That(retreivedAttachments[0].AssetID, Is.EqualTo(attItem.AssetID)); + Assert.That(presence.Appearance.GetAttachpoint(attItem.ID), Is.EqualTo((int)AttachmentPoint.Chest)); + + Assert.That(scene.GetSceneObjectGroups().Count, Is.EqualTo(1)); + + // Check events. We expect OnAttach to fire on login. + Assert.That(m_numberOfAttachEventsFired, Is.EqualTo(1)); + } + + [Test] + public void TestUpdateAttachmentPosition() + { + TestHelpers.InMethod(); + + Scene scene = CreateTestScene(); + UserAccount ua1 = UserAccountHelpers.CreateUserWithInventory(scene, 0x1); + InventoryItemBase attItem = CreateAttachmentItem(scene, ua1.PrincipalID, "att", 0x10, 0x20); + + AgentCircuitData acd = SceneHelpers.GenerateAgentData(ua1.PrincipalID); + acd.Appearance = new AvatarAppearance(); + acd.Appearance.SetAttachment((int)AttachmentPoint.Chest, attItem.ID, attItem.AssetID); + ScenePresence sp = SceneHelpers.AddScenePresence(scene, acd); + + SceneObjectGroup attSo = sp.GetAttachments()[0]; + + Vector3 newPosition = new Vector3(1, 2, 4); + + m_numberOfAttachEventsFired = 0; + scene.SceneGraph.UpdatePrimGroupPosition(attSo.LocalId, newPosition, sp.ControllingClient); + + Assert.That(attSo.AbsolutePosition, Is.EqualTo(sp.AbsolutePosition)); + Assert.That(attSo.RootPart.AttachedPos, Is.EqualTo(newPosition)); + + // Check events + Assert.That(m_numberOfAttachEventsFired, Is.EqualTo(0)); + } + + + [Test] + public void TestSameSimulatorNeighbouringRegionsTeleportV1() + { + TestHelpers.InMethod(); +// TestHelpers.EnableLogging(); + + BaseHttpServer httpServer = new BaseHttpServer(99999); + MainServer.AddHttpServer(httpServer); + MainServer.Instance = httpServer; + + AttachmentsModule attModA = new AttachmentsModule(); + AttachmentsModule attModB = new AttachmentsModule(); + EntityTransferModule etmA = new EntityTransferModule(); + EntityTransferModule etmB = new EntityTransferModule(); + LocalSimulationConnectorModule lscm = new LocalSimulationConnectorModule(); + + IConfigSource config = new IniConfigSource(); + IConfig modulesConfig = config.AddConfig("Modules"); + modulesConfig.Set("EntityTransferModule", etmA.Name); + modulesConfig.Set("SimulationServices", lscm.Name); + IConfig entityTransferConfig = config.AddConfig("EntityTransfer"); + + // In order to run a single threaded regression test we do not want the entity transfer module waiting + // for a callback from the destination scene before removing its avatar data. + entityTransferConfig.Set("wait_for_callback", false); + + modulesConfig.Set("InventoryAccessModule", "BasicInventoryAccessModule"); + + SceneHelpers sh = new SceneHelpers(); + TestScene sceneA = sh.SetupScene("sceneA", TestHelpers.ParseTail(0x100), 1000, 1000); + TestScene sceneB = sh.SetupScene("sceneB", TestHelpers.ParseTail(0x200), 1001, 1000); + + SceneHelpers.SetupSceneModules(new Scene[] { sceneA, sceneB }, config, lscm); + SceneHelpers.SetupSceneModules( + sceneA, config, new CapabilitiesModule(), etmA, attModA, new BasicInventoryAccessModule()); + SceneHelpers.SetupSceneModules( + sceneB, config, new CapabilitiesModule(), etmB, attModB, new BasicInventoryAccessModule()); + + // FIXME: Hack - this is here temporarily to revert back to older entity transfer behaviour + //lscm.ServiceVersion = 0.1f; + + UserAccount ua1 = UserAccountHelpers.CreateUserWithInventory(sceneA, 0x1); + + AgentCircuitData acd = SceneHelpers.GenerateAgentData(ua1.PrincipalID); + TestClient tc = new TestClient(acd, sceneA); + List destinationTestClients = new List(); + EntityTransferHelpers.SetupInformClientOfNeighbourTriggersNeighbourClientCreate(tc, destinationTestClients); + + ScenePresence beforeTeleportSp = SceneHelpers.AddScenePresence(sceneA, tc, acd); + beforeTeleportSp.AbsolutePosition = new Vector3(30, 31, 32); + + InventoryItemBase attItem = CreateAttachmentItem(sceneA, ua1.PrincipalID, "att", 0x10, 0x20); + + sceneA.AttachmentsModule.RezSingleAttachmentFromInventory( + beforeTeleportSp, attItem.ID, (uint)AttachmentPoint.Chest); + + Vector3 teleportPosition = new Vector3(10, 11, 12); + Vector3 teleportLookAt = new Vector3(20, 21, 22); + + m_numberOfAttachEventsFired = 0; + sceneA.RequestTeleportLocation( + beforeTeleportSp.ControllingClient, + sceneB.RegionInfo.RegionHandle, + teleportPosition, + teleportLookAt, + (uint)TeleportFlags.ViaLocation); + + destinationTestClients[0].CompleteMovement(); + + // Check attachments have made it into sceneB + ScenePresence afterTeleportSceneBSp = sceneB.GetScenePresence(ua1.PrincipalID); + + // This is appearance data, as opposed to actually rezzed attachments + List sceneBAttachments = afterTeleportSceneBSp.Appearance.GetAttachments(); + Assert.That(sceneBAttachments.Count, Is.EqualTo(1)); + Assert.That(sceneBAttachments[0].AttachPoint, Is.EqualTo((int)AttachmentPoint.Chest)); + Assert.That(sceneBAttachments[0].ItemID, Is.EqualTo(attItem.ID)); + Assert.That(sceneBAttachments[0].AssetID, Is.EqualTo(attItem.AssetID)); + Assert.That(afterTeleportSceneBSp.Appearance.GetAttachpoint(attItem.ID), Is.EqualTo((int)AttachmentPoint.Chest)); + + // This is the actual attachment + List actualSceneBAttachments = afterTeleportSceneBSp.GetAttachments(); + Assert.That(actualSceneBAttachments.Count, Is.EqualTo(1)); + SceneObjectGroup actualSceneBAtt = actualSceneBAttachments[0]; + Assert.That(actualSceneBAtt.Name, Is.EqualTo(attItem.Name)); + Assert.That(actualSceneBAtt.AttachmentPoint, Is.EqualTo((uint)AttachmentPoint.Chest)); + Assert.IsFalse(actualSceneBAtt.Backup); + + Assert.That(sceneB.GetSceneObjectGroups().Count, Is.EqualTo(1)); + + // Check attachments have been removed from sceneA + ScenePresence afterTeleportSceneASp = sceneA.GetScenePresence(ua1.PrincipalID); + + // Since this is appearance data, it is still present on the child avatar! + List sceneAAttachments = afterTeleportSceneASp.Appearance.GetAttachments(); + Assert.That(sceneAAttachments.Count, Is.EqualTo(1)); + Assert.That(afterTeleportSceneASp.Appearance.GetAttachpoint(attItem.ID), Is.EqualTo((int)AttachmentPoint.Chest)); + + // This is the actual attachment, which should no longer exist + List actualSceneAAttachments = afterTeleportSceneASp.GetAttachments(); + Assert.That(actualSceneAAttachments.Count, Is.EqualTo(0)); + + Assert.That(sceneA.GetSceneObjectGroups().Count, Is.EqualTo(0)); + + // Check events + Assert.That(m_numberOfAttachEventsFired, Is.EqualTo(0)); + } + + + [Test] + public void TestSameSimulatorNeighbouringRegionsTeleportV2() + { + TestHelpers.InMethod(); +// TestHelpers.EnableLogging(); + + BaseHttpServer httpServer = new BaseHttpServer(99999); + MainServer.AddHttpServer(httpServer); + MainServer.Instance = httpServer; + + AttachmentsModule attModA = new AttachmentsModule(); + AttachmentsModule attModB = new AttachmentsModule(); + EntityTransferModule etmA = new EntityTransferModule(); + EntityTransferModule etmB = new EntityTransferModule(); + LocalSimulationConnectorModule lscm = new LocalSimulationConnectorModule(); + + IConfigSource config = new IniConfigSource(); + IConfig modulesConfig = config.AddConfig("Modules"); + modulesConfig.Set("EntityTransferModule", etmA.Name); + modulesConfig.Set("SimulationServices", lscm.Name); + + modulesConfig.Set("InventoryAccessModule", "BasicInventoryAccessModule"); + + SceneHelpers sh = new SceneHelpers(); + TestScene sceneA = sh.SetupScene("sceneA", TestHelpers.ParseTail(0x100), 1000, 1000); + TestScene sceneB = sh.SetupScene("sceneB", TestHelpers.ParseTail(0x200), 1001, 1000); + + SceneHelpers.SetupSceneModules(new Scene[] { sceneA, sceneB }, config, lscm); + SceneHelpers.SetupSceneModules( + sceneA, config, new CapabilitiesModule(), etmA, attModA, new BasicInventoryAccessModule()); + SceneHelpers.SetupSceneModules( + sceneB, config, new CapabilitiesModule(), etmB, attModB, new BasicInventoryAccessModule()); + + UserAccount ua1 = UserAccountHelpers.CreateUserWithInventory(sceneA, 0x1); + + AgentCircuitData acd = SceneHelpers.GenerateAgentData(ua1.PrincipalID); + TestClient tc = new TestClient(acd, sceneA); + List destinationTestClients = new List(); + EntityTransferHelpers.SetupInformClientOfNeighbourTriggersNeighbourClientCreate(tc, destinationTestClients); + + ScenePresence beforeTeleportSp = SceneHelpers.AddScenePresence(sceneA, tc, acd); + beforeTeleportSp.AbsolutePosition = new Vector3(30, 31, 32); + + Assert.That(destinationTestClients.Count, Is.EqualTo(1)); + Assert.That(destinationTestClients[0], Is.Not.Null); + + InventoryItemBase attItem = CreateAttachmentItem(sceneA, ua1.PrincipalID, "att", 0x10, 0x20); + + sceneA.AttachmentsModule.RezSingleAttachmentFromInventory( + beforeTeleportSp, attItem.ID, (uint)AttachmentPoint.Chest); + + Vector3 teleportPosition = new Vector3(10, 11, 12); + Vector3 teleportLookAt = new Vector3(20, 21, 22); + + // Here, we need to make clientA's receipt of SendRegionTeleport trigger clientB's CompleteMovement(). This + // is to operate the teleport V2 mechanism where the EntityTransferModule will first request the client to + // CompleteMovement to the region and then call UpdateAgent to the destination region to confirm the receipt + // Both these operations will occur on different threads and will wait for each other. + // We have to do this via ThreadPool directly since FireAndForget has been switched to sync for the V1 + // test protocol, where we are trying to avoid unpredictable async operations in regression tests. + tc.OnTestClientSendRegionTeleport + += (regionHandle, simAccess, regionExternalEndPoint, locationID, flags, capsURL) + => ThreadPool.UnsafeQueueUserWorkItem(o => destinationTestClients[0].CompleteMovement(), null); + + m_numberOfAttachEventsFired = 0; + sceneA.RequestTeleportLocation( + beforeTeleportSp.ControllingClient, + sceneB.RegionInfo.RegionHandle, + teleportPosition, + teleportLookAt, + (uint)TeleportFlags.ViaLocation); + + // Check attachments have made it into sceneB + ScenePresence afterTeleportSceneBSp = sceneB.GetScenePresence(ua1.PrincipalID); + + // This is appearance data, as opposed to actually rezzed attachments + List sceneBAttachments = afterTeleportSceneBSp.Appearance.GetAttachments(); + Assert.That(sceneBAttachments.Count, Is.EqualTo(1)); + Assert.That(sceneBAttachments[0].AttachPoint, Is.EqualTo((int)AttachmentPoint.Chest)); + Assert.That(sceneBAttachments[0].ItemID, Is.EqualTo(attItem.ID)); + Assert.That(sceneBAttachments[0].AssetID, Is.EqualTo(attItem.AssetID)); + Assert.That(afterTeleportSceneBSp.Appearance.GetAttachpoint(attItem.ID), Is.EqualTo((int)AttachmentPoint.Chest)); + + // This is the actual attachment + List actualSceneBAttachments = afterTeleportSceneBSp.GetAttachments(); + Assert.That(actualSceneBAttachments.Count, Is.EqualTo(1)); + SceneObjectGroup actualSceneBAtt = actualSceneBAttachments[0]; + Assert.That(actualSceneBAtt.Name, Is.EqualTo(attItem.Name)); + Assert.That(actualSceneBAtt.AttachmentPoint, Is.EqualTo((uint)AttachmentPoint.Chest)); + Assert.IsFalse(actualSceneBAtt.Backup); + + Assert.That(sceneB.GetSceneObjectGroups().Count, Is.EqualTo(1)); + + // Check attachments have been removed from sceneA + ScenePresence afterTeleportSceneASp = sceneA.GetScenePresence(ua1.PrincipalID); + + // Since this is appearance data, it is still present on the child avatar! + List sceneAAttachments = afterTeleportSceneASp.Appearance.GetAttachments(); + Assert.That(sceneAAttachments.Count, Is.EqualTo(1)); + Assert.That(afterTeleportSceneASp.Appearance.GetAttachpoint(attItem.ID), Is.EqualTo((int)AttachmentPoint.Chest)); + + // This is the actual attachment, which should no longer exist + List actualSceneAAttachments = afterTeleportSceneASp.GetAttachments(); + Assert.That(actualSceneAAttachments.Count, Is.EqualTo(0)); + + Assert.That(sceneA.GetSceneObjectGroups().Count, Is.EqualTo(0)); + + // Check events + Assert.That(m_numberOfAttachEventsFired, Is.EqualTo(0)); + } + } +*/ +} diff --git a/Tests/OpenSim.Region.CoreModules.Tests/Avatar/AvatarFactory/Tests/AvatarFactoryModuleTests.cs b/Tests/OpenSim.Region.CoreModules.Tests/Avatar/AvatarFactory/Tests/AvatarFactoryModuleTests.cs new file mode 100644 index 00000000000..f55baa83cf4 --- /dev/null +++ b/Tests/OpenSim.Region.CoreModules.Tests/Avatar/AvatarFactory/Tests/AvatarFactoryModuleTests.cs @@ -0,0 +1,197 @@ +/* + * 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 Nini.Config; +using NUnit.Framework; +using OpenMetaverse; +using OpenSim.Framework; +using OpenSim.Region.CoreModules.Asset; +using OpenSim.Region.Framework.Scenes; +using OpenSim.Tests.Common; + +namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory +{ + [TestFixture] + public class AvatarFactoryModuleTests : OpenSimTestCase + { + /// + /// Only partial right now since we don't yet test that it's ended up in the avatar appearance service. + /// + [Test] + public void TestSetAppearance() + { + TestHelpers.InMethod(); +// TestHelpers.EnableLogging(); + + UUID userId = TestHelpers.ParseTail(0x1); + UUID bakedTextureID = TestHelpers.ParseTail(0x2); + + // We need an asset cache because otherwise the LocalAssetServiceConnector will short-circuit directly + // to the AssetService, which will then store temporary and local assets permanently + TestsAssetCache assetCache = new TestsAssetCache(); + + AvatarFactoryModule afm = new AvatarFactoryModule(); + TestScene scene = new SceneHelpers(assetCache).SetupScene(); + SceneHelpers.SetupSceneModules(scene, afm); + ScenePresence sp = SceneHelpers.AddScenePresence(scene, userId); + + // TODO: Use the actual BunchOfCaps functionality once we slot in the CapabilitiesModules + AssetBase bakedTextureAsset; + bakedTextureAsset + = new AssetBase( + bakedTextureID, "Test Baked Texture", (sbyte)AssetType.Texture, userId.ToString()); + bakedTextureAsset.Data = new byte[] { 2 }; // Not necessary to have a genuine JPEG2000 asset here yet + bakedTextureAsset.Temporary = true; + bakedTextureAsset.Local = true; + scene.AssetService.Store(bakedTextureAsset); + + byte[] visualParams = new byte[AvatarAppearance.VISUALPARAM_COUNT]; + for (byte i = 0; i < visualParams.Length; i++) + visualParams[i] = i; + + Primitive.TextureEntry bakedTextureEntry = new Primitive.TextureEntry(TestHelpers.ParseTail(0x10)); + uint eyesFaceIndex = (uint)AppearanceManager.BakeTypeToAgentTextureIndex(BakeType.Eyes); + Primitive.TextureEntryFace eyesFace = bakedTextureEntry.CreateFace(eyesFaceIndex); + + int rebakeRequestsReceived = 0; + ((TestClient)sp.ControllingClient).OnReceivedSendRebakeAvatarTextures += id => rebakeRequestsReceived++; + + // This is the alpha texture + eyesFace.TextureID = bakedTextureID; + afm.SetAppearance(sp, bakedTextureEntry, visualParams, null); + + Assert.That(rebakeRequestsReceived, Is.EqualTo(0)); + + AssetBase eyesBake = scene.AssetService.Get(bakedTextureID.ToString()); + Assert.That(eyesBake, Is.Not.Null); + Assert.That(eyesBake.Temporary, Is.True); + Assert.That(eyesBake.Local, Is.True); + } + + /// + /// Test appearance setting where the baked texture UUID are library alpha textures. + /// + /// + /// For a mesh avatar, it appears these 'baked textures' are used. So these should not trigger a request to + /// rebake. + /// + [Test] + public void TestSetAppearanceAlphaBakedTextures() + { + TestHelpers.InMethod(); +// TestHelpers.EnableLogging(); + + UUID userId = TestHelpers.ParseTail(0x1); + UUID alphaTextureID = new UUID("3a367d1c-bef1-6d43-7595-e88c1e3aadb3"); + + // We need an asset cache because otherwise the LocalAssetServiceConnector will short-circuit directly + // to the AssetService, which will then store temporary and local assets permanently + TestsAssetCache assetCache = new TestsAssetCache(); + + AvatarFactoryModule afm = new AvatarFactoryModule(); + TestScene scene = new SceneHelpers(assetCache).SetupScene(); + SceneHelpers.SetupSceneModules(scene, afm); + ScenePresence sp = SceneHelpers.AddScenePresence(scene, userId); + + AssetBase libraryAsset; + libraryAsset + = new AssetBase( + alphaTextureID, "Default Alpha Layer Texture", (sbyte)AssetType.Texture, userId.ToString()); + libraryAsset.Data = new byte[] { 2 }; // Not necessary to have a genuine JPEG2000 asset here yet + libraryAsset.Temporary = false; + libraryAsset.Local = false; + scene.AssetService.Store(libraryAsset); + + byte[] visualParams = new byte[AvatarAppearance.VISUALPARAM_COUNT]; + for (byte i = 0; i < visualParams.Length; i++) + visualParams[i] = i; + + Primitive.TextureEntry bakedTextureEntry = new Primitive.TextureEntry(TestHelpers.ParseTail(0x10)); + uint eyesFaceIndex = (uint)AppearanceManager.BakeTypeToAgentTextureIndex(BakeType.Eyes); + Primitive.TextureEntryFace eyesFace = bakedTextureEntry.CreateFace(eyesFaceIndex); + + int rebakeRequestsReceived = 0; + ((TestClient)sp.ControllingClient).OnReceivedSendRebakeAvatarTextures += id => rebakeRequestsReceived++; + + // This is the alpha texture + eyesFace.TextureID = alphaTextureID; + afm.SetAppearance(sp, bakedTextureEntry, visualParams, null); + + Assert.That(rebakeRequestsReceived, Is.EqualTo(0)); + } + + [Test] + public void TestSaveBakedTextures() + { + TestHelpers.InMethod(); +// log4net.Config.XmlConfigurator.Configure(); + + UUID userId = TestHelpers.ParseTail(0x1); + UUID eyesTextureId = TestHelpers.ParseTail(0x2); + + // We need an asset cache because otherwise the LocalAssetServiceConnector will short-circuit directly + // to the AssetService, which will then store temporary and local assets permanently + TestsAssetCache assetCache = new TestsAssetCache(); + + AvatarFactoryModule afm = new AvatarFactoryModule(); + TestScene scene = new SceneHelpers(assetCache).SetupScene(); + SceneHelpers.SetupSceneModules(scene, afm); + ScenePresence sp = SceneHelpers.AddScenePresence(scene, userId); + + // TODO: Use the actual BunchOfCaps functionality once we slot in the CapabilitiesModules + AssetBase uploadedAsset; + uploadedAsset = new AssetBase(eyesTextureId, "Baked Texture", (sbyte)AssetType.Texture, userId.ToString()); + uploadedAsset.Data = new byte[] { 2 }; + uploadedAsset.Temporary = true; + uploadedAsset.Local = true; // Local assets aren't persisted, non-local are + scene.AssetService.Store(uploadedAsset); + + byte[] visualParams = new byte[AvatarAppearance.VISUALPARAM_COUNT]; + for (byte i = 0; i < visualParams.Length; i++) + visualParams[i] = i; + + Primitive.TextureEntry bakedTextureEntry = new Primitive.TextureEntry(TestHelpers.ParseTail(0x10)); + uint eyesFaceIndex = (uint)AppearanceManager.BakeTypeToAgentTextureIndex(BakeType.Eyes); + Primitive.TextureEntryFace eyesFace = bakedTextureEntry.CreateFace(eyesFaceIndex); + eyesFace.TextureID = eyesTextureId; + + afm.SetAppearance(sp, bakedTextureEntry, visualParams, new WearableCacheItem[0]); + afm.SaveBakedTextures(userId); +// Dictionary bakedTextures = afm.GetBakedTextureFaces(userId); + + // We should also inpsect the asset data store layer directly, but this is difficult to get at right now. + assetCache.Clear(); + + AssetBase eyesBake = scene.AssetService.Get(eyesTextureId.ToString()); + Assert.That(eyesBake, Is.Not.Null); + Assert.That(eyesBake.Temporary, Is.False); + Assert.That(eyesBake.Local, Is.False); + } + } +} \ No newline at end of file diff --git a/Tests/OpenSim.Region.CoreModules.Tests/Avatar/Chat/Tests/ChatModuleTests.cs b/Tests/OpenSim.Region.CoreModules.Tests/Avatar/Chat/Tests/ChatModuleTests.cs new file mode 100644 index 00000000000..2813c11d487 --- /dev/null +++ b/Tests/OpenSim.Region.CoreModules.Tests/Avatar/Chat/Tests/ChatModuleTests.cs @@ -0,0 +1,320 @@ +/* + * 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 + { + [OneTimeSetUp] + 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; + } + + [OneTimeTearDown] + 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); + } + } +} \ No newline at end of file diff --git a/Tests/OpenSim.Region.CoreModules.Tests/Avatar/Friends/Tests/FriendModuleTests.cs b/Tests/OpenSim.Region.CoreModules.Tests/Avatar/Friends/Tests/FriendModuleTests.cs new file mode 100644 index 00000000000..d79d6504443 --- /dev/null +++ b/Tests/OpenSim.Region.CoreModules.Tests/Avatar/Friends/Tests/FriendModuleTests.cs @@ -0,0 +1,209 @@ +/* + * 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 Nini.Config; +using NUnit.Framework; +using OpenMetaverse; +using OpenSim.Data.Null; +using OpenSim.Framework; +using OpenSim.Region.CoreModules.Avatar.Friends; +using OpenSim.Region.Framework.Scenes; +using OpenSim.Tests.Common; + +namespace OpenSim.Region.CoreModules.Avatar.Friends.Tests +{ + [TestFixture] + public class FriendsModuleTests : OpenSimTestCase + { + private FriendsModule m_fm; + private TestScene m_scene; + + [OneTimeSetUp] + public void FixtureInit() + { + // Don't allow tests to be bamboozled by asynchronous events. Execute everything on the same thread. + Util.FireAndForgetMethod = FireAndForgetMethod.RegressionTest; + } + + [OneTimeTearDown] + 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; + } + + [SetUp] + public void Init() + { + // We must clear friends data between tests since Data.Null holds it in static properties. This is necessary + // so that different services and simulator can share the data in standalone mode. This is pretty horrible + // effectively the statics are global variables. + NullFriendsData.Clear(); + + IConfigSource config = new IniConfigSource(); + config.AddConfig("Modules"); + // Not strictly necessary since FriendsModule assumes it is the default (!) + config.Configs["Modules"].Set("FriendsModule", "FriendsModule"); + config.AddConfig("Friends"); + config.Configs["Friends"].Set("Connector", "OpenSim.Services.FriendsService.dll"); + config.AddConfig("FriendsService"); + config.Configs["FriendsService"].Set("StorageProvider", "OpenSim.Data.Null.dll"); + + m_scene = new SceneHelpers().SetupScene(); + m_fm = new FriendsModule(); + SceneHelpers.SetupSceneModules(m_scene, config, m_fm); + } + + [Test] + public void TestLoginWithNoFriends() + { + TestHelpers.InMethod(); +// log4net.Config.XmlConfigurator.Configure(); + + UUID userId = TestHelpers.ParseTail(0x1); + + ScenePresence sp = SceneHelpers.AddScenePresence(m_scene, userId); + + Assert.That(((TestClient)sp.ControllingClient).ReceivedOfflineNotifications.Count, Is.EqualTo(0)); + Assert.That(((TestClient)sp.ControllingClient).ReceivedOnlineNotifications.Count, Is.EqualTo(0)); + } + + [Test] + public void TestLoginWithOfflineFriends() + { + TestHelpers.InMethod(); +// log4net.Config.XmlConfigurator.Configure(); + + UUID user1Id = TestHelpers.ParseTail(0x1); + UUID user2Id = TestHelpers.ParseTail(0x2); + +// UserAccountHelpers.CreateUserWithInventory(m_scene, user1Id); +// UserAccountHelpers.CreateUserWithInventory(m_scene, user2Id); +// +// m_fm.AddFriendship(user1Id, user2Id); + + ScenePresence sp1 = SceneHelpers.AddScenePresence(m_scene, user1Id); + ScenePresence sp2 = SceneHelpers.AddScenePresence(m_scene, user2Id); + + m_fm.AddFriendship(sp1.ControllingClient, user2Id); + + // Not necessary for this test. CanSeeOnline is automatically granted. +// m_fm.GrantRights(sp1.ControllingClient, user2Id, (int)FriendRights.CanSeeOnline); + + // We must logout from the client end so that the presence service is correctly updated by the presence + // detector. This is listening to the OnConnectionClosed event on the client. + ((TestClient)sp1.ControllingClient).Logout(); + ((TestClient)sp2.ControllingClient).Logout(); +// m_scene.RemoveClient(sp1.UUID, true); +// m_scene.RemoveClient(sp2.UUID, true); + + ScenePresence sp1Redux = SceneHelpers.AddScenePresence(m_scene, user1Id); + + // We don't expect to receive notifications of offline friends on login, just online. + Assert.That(((TestClient)sp1Redux.ControllingClient).ReceivedOfflineNotifications.Count, Is.EqualTo(0)); + Assert.That(((TestClient)sp1Redux.ControllingClient).ReceivedOnlineNotifications.Count, Is.EqualTo(0)); + } + + [Test] + public void TestLoginWithOnlineFriends() + { + TestHelpers.InMethod(); +// log4net.Config.XmlConfigurator.Configure(); + + UUID user1Id = TestHelpers.ParseTail(0x1); + UUID user2Id = TestHelpers.ParseTail(0x2); + +// UserAccountHelpers.CreateUserWithInventory(m_scene, user1Id); +// UserAccountHelpers.CreateUserWithInventory(m_scene, user2Id); +// +// m_fm.AddFriendship(user1Id, user2Id); + + ScenePresence sp1 = SceneHelpers.AddScenePresence(m_scene, user1Id); + ScenePresence sp2 = SceneHelpers.AddScenePresence(m_scene, user2Id); + + m_fm.AddFriendship(sp1.ControllingClient, user2Id); + + // Not necessary for this test. CanSeeOnline is automatically granted. +// m_fm.GrantRights(sp1.ControllingClient, user2Id, (int)FriendRights.CanSeeOnline); + + // We must logout from the client end so that the presence service is correctly updated by the presence + // detector. This is listening to the OnConnectionClosed event on the client. +// ((TestClient)sp1.ControllingClient).Logout(); + ((TestClient)sp2.ControllingClient).Logout(); +// m_scene.RemoveClient(user2Id, true); + + ScenePresence sp2Redux = SceneHelpers.AddScenePresence(m_scene, user2Id); + + Assert.That(((TestClient)sp2Redux.ControllingClient).ReceivedOfflineNotifications.Count, Is.EqualTo(0)); + Assert.That(((TestClient)sp2Redux.ControllingClient).ReceivedOnlineNotifications.Count, Is.EqualTo(1)); + } + + [Test] + public void TestAddFriendshipWhileOnline() + { + TestHelpers.InMethod(); +// log4net.Config.XmlConfigurator.Configure(); + + UUID userId = TestHelpers.ParseTail(0x1); + UUID user2Id = TestHelpers.ParseTail(0x2); + + ScenePresence sp = SceneHelpers.AddScenePresence(m_scene, userId); + SceneHelpers.AddScenePresence(m_scene, user2Id); + + // This fiendship is two-way but without a connector, only the first user will receive the online + // notification. + m_fm.AddFriendship(sp.ControllingClient, user2Id); + + Assert.That(((TestClient)sp.ControllingClient).ReceivedOfflineNotifications.Count, Is.EqualTo(0)); + Assert.That(((TestClient)sp.ControllingClient).ReceivedOnlineNotifications.Count, Is.EqualTo(1)); + } + + [Test] + public void TestRemoveFriendshipWhileOnline() + { + TestHelpers.InMethod(); +// log4net.Config.XmlConfigurator.Configure(); + + UUID user1Id = TestHelpers.ParseTail(0x1); + UUID user2Id = TestHelpers.ParseTail(0x2); + + ScenePresence sp = SceneHelpers.AddScenePresence(m_scene, user1Id); + SceneHelpers.AddScenePresence(m_scene, user2Id); + + m_fm.AddFriendship(sp.ControllingClient, user2Id); + m_fm.RemoveFriendship(sp.ControllingClient, user2Id); + + TestClient user1Client = sp.ControllingClient as TestClient; + Assert.That(user1Client.ReceivedFriendshipTerminations.Count, Is.EqualTo(1)); + Assert.That(user1Client.ReceivedFriendshipTerminations[0], Is.EqualTo(user2Id)); + } + } +} \ No newline at end of file diff --git a/Tests/OpenSim.Region.CoreModules.Tests/Avatar/Inventory/Archiver/Tests/InventoryArchiveLoadPathTests.cs b/Tests/OpenSim.Region.CoreModules.Tests/Avatar/Inventory/Archiver/Tests/InventoryArchiveLoadPathTests.cs new file mode 100644 index 00000000000..aec4bd44c17 --- /dev/null +++ b/Tests/OpenSim.Region.CoreModules.Tests/Avatar/Inventory/Archiver/Tests/InventoryArchiveLoadPathTests.cs @@ -0,0 +1,361 @@ +/* + * 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 System.IO; +using System.Reflection; +using System.Threading; +using NUnit.Framework; +using OpenMetaverse; +using OpenSim.Data; +using OpenSim.Framework; +using OpenSim.Framework.Serialization; +using OpenSim.Framework.Serialization.External; +using OpenSim.Region.CoreModules.Avatar.Inventory.Archiver; +using OpenSim.Region.CoreModules.World.Serialiser; +using OpenSim.Region.Framework.Scenes; +using OpenSim.Region.Framework.Scenes.Serialization; +using OpenSim.Services.Interfaces; +using OpenSim.Tests.Common; + +namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver.Tests +{ + [TestFixture] + public class InventoryArchiveLoadPathTests : InventoryArchiveTestCase + { + /// + /// Test loading an IAR to various different inventory paths. + /// + [Test] + public void TestLoadIarToInventoryPaths() + { + TestHelpers.InMethod(); +// log4net.Config.XmlConfigurator.Configure(); + + SerialiserModule serialiserModule = new SerialiserModule(); + InventoryArchiverModule archiverModule = new InventoryArchiverModule(); + + // Annoyingly, we have to set up a scene even though inventory loading has nothing to do with a scene + Scene scene = new SceneHelpers().SetupScene(); + + SceneHelpers.SetupSceneModules(scene, serialiserModule, archiverModule); + + UserAccountHelpers.CreateUserWithInventory(scene, m_uaMT, "meowfood"); + UserAccountHelpers.CreateUserWithInventory(scene, m_uaLL1, "hampshire"); + + archiverModule.DearchiveInventory(UUID.Random(), m_uaMT.FirstName, m_uaMT.LastName, "/", "meowfood", m_iarStream); + InventoryItemBase foundItem1 + = InventoryArchiveUtils.FindItemByPath(scene.InventoryService, m_uaMT.PrincipalID, m_item1Name); + + Assert.That(foundItem1, Is.Not.Null, "Didn't find loaded item 1"); + + // Now try loading to a root child folder + UserInventoryHelpers.CreateInventoryFolder(scene.InventoryService, m_uaMT.PrincipalID, "xA", false); + MemoryStream archiveReadStream = new MemoryStream(m_iarStream.ToArray()); + archiverModule.DearchiveInventory(UUID.Random(), m_uaMT.FirstName, m_uaMT.LastName, "xA", "meowfood", archiveReadStream); + + InventoryItemBase foundItem2 + = InventoryArchiveUtils.FindItemByPath(scene.InventoryService, m_uaMT.PrincipalID, "xA/" + m_item1Name); + Assert.That(foundItem2, Is.Not.Null, "Didn't find loaded item 2"); + + // Now try loading to a more deeply nested folder + UserInventoryHelpers.CreateInventoryFolder(scene.InventoryService, m_uaMT.PrincipalID, "xB/xC", false); + archiveReadStream = new MemoryStream(archiveReadStream.ToArray()); + archiverModule.DearchiveInventory(UUID.Random(), m_uaMT.FirstName, m_uaMT.LastName, "xB/xC", "meowfood", archiveReadStream); + + InventoryItemBase foundItem3 + = InventoryArchiveUtils.FindItemByPath(scene.InventoryService, m_uaMT.PrincipalID, "xB/xC/" + m_item1Name); + Assert.That(foundItem3, Is.Not.Null, "Didn't find loaded item 3"); + } + + /// + /// Test that things work when the load path specified starts with a slash + /// + [Test] + public void TestLoadIarPathStartsWithSlash() + { + TestHelpers.InMethod(); +// log4net.Config.XmlConfigurator.Configure(); + + SerialiserModule serialiserModule = new SerialiserModule(); + InventoryArchiverModule archiverModule = new InventoryArchiverModule(); + Scene scene = new SceneHelpers().SetupScene(); + SceneHelpers.SetupSceneModules(scene, serialiserModule, archiverModule); + + UserAccountHelpers.CreateUserWithInventory(scene, m_uaMT, "password"); + archiverModule.DearchiveInventory(UUID.Random(), m_uaMT.FirstName, m_uaMT.LastName, "/Objects", "password", m_iarStream); + + InventoryItemBase foundItem1 + = InventoryArchiveUtils.FindItemByPath( + scene.InventoryService, m_uaMT.PrincipalID, "/Objects/" + m_item1Name); + + Assert.That(foundItem1, Is.Not.Null, "Didn't find loaded item 1 in TestLoadIarFolderStartsWithSlash()"); + } + + [Test] + public void TestLoadIarPathWithEscapedChars() + { + TestHelpers.InMethod(); + //log4net.Config.XmlConfigurator.Configure(); + + string itemName = "You & you are a mean/man/"; + string humanEscapedItemName = @"You & you are a mean\/man\/"; + string userPassword = "meowfood"; + + InventoryArchiverModule archiverModule = new InventoryArchiverModule(); + + Scene scene = new SceneHelpers().SetupScene(); + SceneHelpers.SetupSceneModules(scene, archiverModule); + + // Create user + string userFirstName = "Jock"; + string userLastName = "Stirrup"; + UUID userId = UUID.Parse("00000000-0000-0000-0000-000000000020"); + UserAccountHelpers.CreateUserWithInventory(scene, userFirstName, userLastName, userId, "meowfood"); + + // Create asset + SceneObjectGroup object1; + SceneObjectPart part1; + { + string partName = "part name"; + UUID ownerId = UUID.Parse("00000000-0000-0000-0000-000000000040"); + PrimitiveBaseShape shape = PrimitiveBaseShape.CreateSphere(); + Vector3 groupPosition = new Vector3(10, 20, 30); + Quaternion rotationOffset = new Quaternion(20, 30, 40, 50); + Vector3 offsetPosition = new Vector3(5, 10, 15); + + part1 + = new SceneObjectPart( + ownerId, shape, groupPosition, rotationOffset, offsetPosition); + part1.Name = partName; + + object1 = new SceneObjectGroup(part1); + scene.AddNewSceneObject(object1, false); + } + + UUID asset1Id = UUID.Parse("00000000-0000-0000-0000-000000000060"); + AssetBase asset1 = AssetHelpers.CreateAsset(asset1Id, object1); + scene.AssetService.Store(asset1); + + // Create item + UUID item1Id = UUID.Parse("00000000-0000-0000-0000-000000000080"); + InventoryItemBase item1 = new InventoryItemBase(); + item1.Name = itemName; + item1.AssetID = asset1.FullID; + item1.ID = item1Id; + item1.Owner = userId; + InventoryFolderBase objsFolder + = InventoryArchiveUtils.FindFoldersByPath(scene.InventoryService, userId, "Objects")[0]; + item1.Folder = objsFolder.ID; + scene.AddInventoryItem(item1); + + MemoryStream archiveWriteStream = new MemoryStream(); + archiverModule.OnInventoryArchiveSaved += SaveCompleted; + + mre.Reset(); + archiverModule.ArchiveInventory( + UUID.Random(), userFirstName, userLastName, "Objects", userPassword, archiveWriteStream); + mre.WaitOne(60000, false); + + // LOAD ITEM + MemoryStream archiveReadStream = new MemoryStream(archiveWriteStream.ToArray()); + + archiverModule.DearchiveInventory(UUID.Random(), userFirstName, userLastName, "Scripts", userPassword, archiveReadStream); + + InventoryItemBase foundItem1 + = InventoryArchiveUtils.FindItemByPath( + scene.InventoryService, userId, "Scripts/Objects/" + humanEscapedItemName); + + Assert.That(foundItem1, Is.Not.Null, "Didn't find loaded item 1"); +// Assert.That( +// foundItem1.CreatorId, Is.EqualTo(userUuid), +// "Loaded item non-uuid creator doesn't match that of the loading user"); + Assert.That( + foundItem1.Name, Is.EqualTo(itemName), + "Loaded item name doesn't match saved name"); + } + + /// + /// Test replication of an archive path to the user's inventory. + /// + [Test] + public void TestNewIarPath() + { + TestHelpers.InMethod(); +// log4net.Config.XmlConfigurator.Configure(); + + Scene scene = new SceneHelpers().SetupScene(); + UserAccount ua1 = UserAccountHelpers.CreateUserWithInventory(scene); + + Dictionary foldersCreated = new Dictionary(); + Dictionary nodesLoaded = new Dictionary(); + + string folder1Name = "1"; + string folder2aName = "2a"; + string folder2bName = "2b"; + + string folder1ArchiveName = InventoryArchiveWriteRequest.CreateArchiveFolderName(folder1Name, UUID.Random()); + string folder2aArchiveName = InventoryArchiveWriteRequest.CreateArchiveFolderName(folder2aName, UUID.Random()); + string folder2bArchiveName = InventoryArchiveWriteRequest.CreateArchiveFolderName(folder2bName, UUID.Random()); + + string iarPath1 = string.Join("", new string[] { folder1ArchiveName, folder2aArchiveName }); + string iarPath2 = string.Join("", new string[] { folder1ArchiveName, folder2bArchiveName }); + + { + // Test replication of path1 + new InventoryArchiveReadRequest(UUID.Random(), null, scene.InventoryService, scene.AssetService, scene.UserAccountService, ua1, null, (Stream)null, false) + .ReplicateArchivePathToUserInventory( + iarPath1, scene.InventoryService.GetRootFolder(ua1.PrincipalID), + foldersCreated, nodesLoaded); + + List folder1Candidates + = InventoryArchiveUtils.FindFoldersByPath(scene.InventoryService, ua1.PrincipalID, folder1Name); + Assert.That(folder1Candidates.Count, Is.EqualTo(1)); + + InventoryFolderBase folder1 = folder1Candidates[0]; + List folder2aCandidates + = InventoryArchiveUtils.FindFoldersByPath(scene.InventoryService, folder1, folder2aName); + Assert.That(folder2aCandidates.Count, Is.EqualTo(1)); + } + + { + // Test replication of path2 + new InventoryArchiveReadRequest(UUID.Random(), null, scene.InventoryService, scene.AssetService, scene.UserAccountService, ua1, null, (Stream)null, false) + .ReplicateArchivePathToUserInventory( + iarPath2, scene.InventoryService.GetRootFolder(ua1.PrincipalID), + foldersCreated, nodesLoaded); + + List folder1Candidates + = InventoryArchiveUtils.FindFoldersByPath(scene.InventoryService, ua1.PrincipalID, folder1Name); + Assert.That(folder1Candidates.Count, Is.EqualTo(1)); + + InventoryFolderBase folder1 = folder1Candidates[0]; + + List folder2aCandidates + = InventoryArchiveUtils.FindFoldersByPath(scene.InventoryService, folder1, folder2aName); + Assert.That(folder2aCandidates.Count, Is.EqualTo(1)); + + List folder2bCandidates + = InventoryArchiveUtils.FindFoldersByPath(scene.InventoryService, folder1, folder2bName); + Assert.That(folder2bCandidates.Count, Is.EqualTo(1)); + } + } + + /// + /// Test replication of a partly existing archive path to the user's inventory. This should create + /// a duplicate path without the merge option. + /// + [Test] + public void TestPartExistingIarPath() + { + TestHelpers.InMethod(); + //log4net.Config.XmlConfigurator.Configure(); + + Scene scene = new SceneHelpers().SetupScene(); + UserAccount ua1 = UserAccountHelpers.CreateUserWithInventory(scene); + + string folder1ExistingName = "a"; + string folder2Name = "b"; + + InventoryFolderBase folder1 + = UserInventoryHelpers.CreateInventoryFolder( + scene.InventoryService, ua1.PrincipalID, folder1ExistingName, false); + + string folder1ArchiveName = InventoryArchiveWriteRequest.CreateArchiveFolderName(folder1ExistingName, UUID.Random()); + string folder2ArchiveName = InventoryArchiveWriteRequest.CreateArchiveFolderName(folder2Name, UUID.Random()); + + string itemArchivePath = string.Join("", new string[] { folder1ArchiveName, folder2ArchiveName }); + + new InventoryArchiveReadRequest(UUID.Random(), null, scene.InventoryService, scene.AssetService, scene.UserAccountService, ua1, null, (Stream)null, false) + .ReplicateArchivePathToUserInventory( + itemArchivePath, scene.InventoryService.GetRootFolder(ua1.PrincipalID), + new Dictionary(), new Dictionary()); + + List folder1PostCandidates + = InventoryArchiveUtils.FindFoldersByPath(scene.InventoryService, ua1.PrincipalID, folder1ExistingName); + Assert.That(folder1PostCandidates.Count, Is.EqualTo(2)); + + // FIXME: Temporarily, we're going to do something messy to make sure we pick up the created folder. + InventoryFolderBase folder1Post = null; + foreach (InventoryFolderBase folder in folder1PostCandidates) + { + if (folder.ID != folder1.ID) + { + folder1Post = folder; + break; + } + } +// Assert.That(folder1Post.ID, Is.EqualTo(folder1.ID)); + + List folder2PostCandidates + = InventoryArchiveUtils.FindFoldersByPath(scene.InventoryService, folder1Post, "b"); + Assert.That(folder2PostCandidates.Count, Is.EqualTo(1)); + } + + /// + /// Test replication of a partly existing archive path to the user's inventory. This should create + /// a merged path. + /// + [Test] + public void TestMergeIarPath() + { + TestHelpers.InMethod(); +// log4net.Config.XmlConfigurator.Configure(); + + Scene scene = new SceneHelpers().SetupScene(); + UserAccount ua1 = UserAccountHelpers.CreateUserWithInventory(scene); + + string folder1ExistingName = "a"; + string folder2Name = "b"; + + InventoryFolderBase folder1 + = UserInventoryHelpers.CreateInventoryFolder( + scene.InventoryService, ua1.PrincipalID, folder1ExistingName, false); + + string folder1ArchiveName = InventoryArchiveWriteRequest.CreateArchiveFolderName(folder1ExistingName, UUID.Random()); + string folder2ArchiveName = InventoryArchiveWriteRequest.CreateArchiveFolderName(folder2Name, UUID.Random()); + + string itemArchivePath = string.Join("", new string[] { folder1ArchiveName, folder2ArchiveName }); + + new InventoryArchiveReadRequest(UUID.Random(), null, scene.InventoryService, scene.AssetService, scene.UserAccountService, ua1, folder1ExistingName, (Stream)null, true) + .ReplicateArchivePathToUserInventory( + itemArchivePath, scene.InventoryService.GetRootFolder(ua1.PrincipalID), + new Dictionary(), new Dictionary()); + + List folder1PostCandidates + = InventoryArchiveUtils.FindFoldersByPath(scene.InventoryService, ua1.PrincipalID, folder1ExistingName); + Assert.That(folder1PostCandidates.Count, Is.EqualTo(1)); + Assert.That(folder1PostCandidates[0].ID, Is.EqualTo(folder1.ID)); + + List folder2PostCandidates + = InventoryArchiveUtils.FindFoldersByPath(scene.InventoryService, folder1PostCandidates[0], "b"); + Assert.That(folder2PostCandidates.Count, Is.EqualTo(1)); + } + } +} + diff --git a/Tests/OpenSim.Region.CoreModules.Tests/Avatar/Inventory/Archiver/Tests/InventoryArchiveLoadTests.cs b/Tests/OpenSim.Region.CoreModules.Tests/Avatar/Inventory/Archiver/Tests/InventoryArchiveLoadTests.cs new file mode 100644 index 00000000000..d0bdc91a12f --- /dev/null +++ b/Tests/OpenSim.Region.CoreModules.Tests/Avatar/Inventory/Archiver/Tests/InventoryArchiveLoadTests.cs @@ -0,0 +1,192 @@ +/* + * 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 System.IO; +using System.Reflection; +using System.Threading; +using NUnit.Framework; +using OpenMetaverse; +using OpenSim.Data; +using OpenSim.Framework; +using OpenSim.Framework.Serialization; +using OpenSim.Framework.Serialization.External; +using OpenSim.Region.CoreModules.Avatar.Inventory.Archiver; +using OpenSim.Region.CoreModules.World.Serialiser; +using OpenSim.Region.Framework.Scenes; +using OpenSim.Region.Framework.Scenes.Serialization; +using OpenSim.Services.Interfaces; +using OpenSim.Tests.Common; + +namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver.Tests +{ + [TestFixture] + public class InventoryArchiveLoadTests : InventoryArchiveTestCase + { + protected TestScene m_scene; + protected InventoryArchiverModule m_archiverModule; + + [SetUp] + public override void SetUp() + { + base.SetUp(); + + SerialiserModule serialiserModule = new SerialiserModule(); + m_archiverModule = new InventoryArchiverModule(); + + m_scene = new SceneHelpers().SetupScene(); + SceneHelpers.SetupSceneModules(m_scene, serialiserModule, m_archiverModule); + } + + [Test] + public void TestLoadCoalesecedItem() + { + TestHelpers.InMethod(); +// TestHelpers.EnableLogging(); + + UserAccountHelpers.CreateUserWithInventory(m_scene, m_uaLL1, "password"); + m_archiverModule.DearchiveInventory(UUID.Random(), m_uaLL1.FirstName, m_uaLL1.LastName, "/", "password", m_iarStream); + + InventoryItemBase coaItem + = InventoryArchiveUtils.FindItemByPath(m_scene.InventoryService, m_uaLL1.PrincipalID, m_coaItemName); + + Assert.That(coaItem, Is.Not.Null, "Didn't find loaded item 1"); + + string assetXml = AssetHelpers.ReadAssetAsString(m_scene.AssetService, coaItem.AssetID); + + CoalescedSceneObjects coa; + bool readResult = CoalescedSceneObjectsSerializer.TryFromXml(assetXml, out coa); + + Assert.That(readResult, Is.True); + Assert.That(coa.Count, Is.EqualTo(2)); + + List coaObjects = coa.Objects; + Assert.That(coaObjects[0].UUID, Is.EqualTo(UUID.Parse("00000000-0000-0000-0000-000000000120"))); + Assert.That(coaObjects[0].AbsolutePosition, Is.EqualTo(new Vector3(15, 30, 45))); + + Assert.That(coaObjects[1].UUID, Is.EqualTo(UUID.Parse("00000000-0000-0000-0000-000000000140"))); + Assert.That(coaObjects[1].AbsolutePosition, Is.EqualTo(new Vector3(25, 50, 75))); + } + + /// + /// Test case where a creator account exists for the creator UUID embedded in item metadata and serialized + /// objects. + /// + [Test] + public void TestLoadIarCreatorAccountPresent() + { + TestHelpers.InMethod(); +// log4net.Config.XmlConfigurator.Configure(); + + UserAccountHelpers.CreateUserWithInventory(m_scene, m_uaLL1, "meowfood"); + + m_archiverModule.DearchiveInventory(UUID.Random(), m_uaLL1.FirstName, m_uaLL1.LastName, "/", "meowfood", m_iarStream); + InventoryItemBase foundItem1 + = InventoryArchiveUtils.FindItemByPath(m_scene.InventoryService, m_uaLL1.PrincipalID, m_item1Name); + + Assert.That( + foundItem1.CreatorId, Is.EqualTo(m_uaLL1.PrincipalID.ToString()), + "Loaded item non-uuid creator doesn't match original"); + Assert.That( + foundItem1.CreatorIdAsUuid, Is.EqualTo(m_uaLL1.PrincipalID), + "Loaded item uuid creator doesn't match original"); + Assert.That(foundItem1.Owner, Is.EqualTo(m_uaLL1.PrincipalID), + "Loaded item owner doesn't match inventory reciever"); + + AssetBase asset1 = m_scene.AssetService.Get(foundItem1.AssetID.ToString()); + string xmlData = Utils.BytesToString(asset1.Data); + SceneObjectGroup sog1 = SceneObjectSerializer.FromOriginalXmlFormat(xmlData); + + Assert.That(sog1.RootPart.CreatorID, Is.EqualTo(m_uaLL1.PrincipalID)); + } + +// /// +// /// Test loading a V0.1 OpenSim Inventory Archive (subject to change since there is no fixed format yet) where +// /// an account exists with the same name as the creator, though not the same id. +// /// +// [Test] +// public void TestLoadIarV0_1SameNameCreator() +// { +// TestHelpers.InMethod(); +// TestHelpers.EnableLogging(); +// +// UserAccountHelpers.CreateUserWithInventory(m_scene, m_uaMT, "meowfood"); +// UserAccountHelpers.CreateUserWithInventory(m_scene, m_uaLL2, "hampshire"); +// +// m_archiverModule.DearchiveInventory(m_uaMT.FirstName, m_uaMT.LastName, "/", "meowfood", m_iarStream); +// InventoryItemBase foundItem1 +// = InventoryArchiveUtils.FindItemByPath(m_scene.InventoryService, m_uaMT.PrincipalID, m_item1Name); +// +// Assert.That( +// foundItem1.CreatorId, Is.EqualTo(m_uaLL2.PrincipalID.ToString()), +// "Loaded item non-uuid creator doesn't match original"); +// Assert.That( +// foundItem1.CreatorIdAsUuid, Is.EqualTo(m_uaLL2.PrincipalID), +// "Loaded item uuid creator doesn't match original"); +// Assert.That(foundItem1.Owner, Is.EqualTo(m_uaMT.PrincipalID), +// "Loaded item owner doesn't match inventory reciever"); +// +// AssetBase asset1 = m_scene.AssetService.Get(foundItem1.AssetID.ToString()); +// string xmlData = Utils.BytesToString(asset1.Data); +// SceneObjectGroup sog1 = SceneObjectSerializer.FromOriginalXmlFormat(xmlData); +// +// Assert.That(sog1.RootPart.CreatorID, Is.EqualTo(m_uaLL2.PrincipalID)); +// } + + /// + /// Test loading a V0.1 OpenSim Inventory Archive (subject to change since there is no fixed format yet) where + /// the creator or an account with the creator's name does not exist within the system. + /// + [Test] + public void TestLoadIarV0_1AbsentCreator() + { + TestHelpers.InMethod(); +// log4net.Config.XmlConfigurator.Configure(); + + UserAccountHelpers.CreateUserWithInventory(m_scene, m_uaMT, "password"); + m_archiverModule.DearchiveInventory(UUID.Random(), m_uaMT.FirstName, m_uaMT.LastName, "/", "password", m_iarStream); + + InventoryItemBase foundItem1 + = InventoryArchiveUtils.FindItemByPath(m_scene.InventoryService, m_uaMT.PrincipalID, m_item1Name); + + Assert.That(foundItem1, Is.Not.Null, "Didn't find loaded item 1"); + Assert.That( + foundItem1.CreatorId, Is.EqualTo(m_uaMT.PrincipalID.ToString()), + "Loaded item non-uuid creator doesn't match that of the loading user"); + Assert.That( + foundItem1.CreatorIdAsUuid, Is.EqualTo(m_uaMT.PrincipalID), + "Loaded item uuid creator doesn't match that of the loading user"); + + AssetBase asset1 = m_scene.AssetService.Get(foundItem1.AssetID.ToString()); + string xmlData = Utils.BytesToString(asset1.Data); + SceneObjectGroup sog1 = SceneObjectSerializer.FromOriginalXmlFormat(xmlData); + + Assert.That(sog1.RootPart.CreatorID, Is.EqualTo(m_uaMT.PrincipalID)); + } + } +} \ No newline at end of file diff --git a/Tests/OpenSim.Region.CoreModules.Tests/Avatar/Inventory/Archiver/Tests/InventoryArchiveSaveTests.cs b/Tests/OpenSim.Region.CoreModules.Tests/Avatar/Inventory/Archiver/Tests/InventoryArchiveSaveTests.cs new file mode 100644 index 00000000000..bd112b43782 --- /dev/null +++ b/Tests/OpenSim.Region.CoreModules.Tests/Avatar/Inventory/Archiver/Tests/InventoryArchiveSaveTests.cs @@ -0,0 +1,422 @@ +/* + * 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 System.IO; +using System.Reflection; +using System.Threading; +using NUnit.Framework; +using OpenMetaverse; +using OpenSim.Data; +using OpenSim.Framework; +using OpenSim.Framework.Serialization; +using OpenSim.Framework.Serialization.External; +using OpenSim.Region.CoreModules.Avatar.Inventory.Archiver; +using OpenSim.Region.CoreModules.World.Serialiser; +using OpenSim.Region.Framework.Scenes; +using OpenSim.Region.Framework.Scenes.Serialization; +using OpenSim.Services.Interfaces; +using OpenSim.Tests.Common; + +namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver.Tests +{ + [TestFixture] + public class InventoryArchiveSaveTests : InventoryArchiveTestCase + { + protected TestScene m_scene; + protected InventoryArchiverModule m_archiverModule; + + [SetUp] + public override void SetUp() + { + base.SetUp(); + + SerialiserModule serialiserModule = new SerialiserModule(); + m_archiverModule = new InventoryArchiverModule(); + + m_scene = new SceneHelpers().SetupScene(); + SceneHelpers.SetupSceneModules(m_scene, serialiserModule, m_archiverModule); + } + + /// + /// Test that the IAR has the required files in the right order. + /// + /// + /// At the moment, the only thing that matters is that the control file is the very first one. + /// + [Test] + public void TestOrder() + { + TestHelpers.InMethod(); +// log4net.Config.XmlConfigurator.Configure(); + + MemoryStream archiveReadStream = new MemoryStream(m_iarStreamBytes); + TarArchiveReader tar = new TarArchiveReader(archiveReadStream); + string filePath; + TarArchiveReader.TarEntryType tarEntryType; + + byte[] data = tar.ReadEntry(out filePath, out tarEntryType); + Assert.That(filePath, Is.EqualTo(ArchiveConstants.CONTROL_FILE_PATH)); + + InventoryArchiveReadRequest iarr + = new InventoryArchiveReadRequest(UUID.Random(), null, null, null, null, null, null, (Stream)null, false); + iarr.LoadControlFile(filePath, data); + + Assert.That(iarr.ControlFileLoaded, Is.True); + } + + [Test] + public void TestSaveRootFolderToIar() + { + TestHelpers.InMethod(); +// TestHelpers.EnableLogging(); + + string userFirstName = "Jock"; + string userLastName = "Stirrup"; + string userPassword = "troll"; + UUID userId = TestHelpers.ParseTail(0x20); + + UserAccountHelpers.CreateUserWithInventory(m_scene, userFirstName, userLastName, userId, userPassword); + + MemoryStream archiveWriteStream = new MemoryStream(); + m_archiverModule.OnInventoryArchiveSaved += SaveCompleted; + + mre.Reset(); + m_archiverModule.ArchiveInventory( + UUID.Random(), userFirstName, userLastName, "/", userPassword, archiveWriteStream); + mre.WaitOne(60000, false); + + // Test created iar + byte[] archive = archiveWriteStream.ToArray(); + MemoryStream archiveReadStream = new MemoryStream(archive); + TarArchiveReader tar = new TarArchiveReader(archiveReadStream); + +// InventoryArchiveUtils. + bool gotObjectsFolder = false; + + string objectsFolderName + = string.Format( + "{0}{1}", + ArchiveConstants.INVENTORY_PATH, + InventoryArchiveWriteRequest.CreateArchiveFolderName( + UserInventoryHelpers.GetInventoryFolder(m_scene.InventoryService, userId, "Objects"))); + + string filePath; + TarArchiveReader.TarEntryType tarEntryType; + + while (tar.ReadEntry(out filePath, out tarEntryType) != null) + { +// Console.WriteLine("Got {0}", filePath); + + // Lazily, we only bother to look for the system objects folder created when we call CreateUserWithInventory() + // XXX: But really we need to stop all that stuff being created in tests or check for such folders + // more thoroughly + if (filePath == objectsFolderName) + gotObjectsFolder = true; + } + + Assert.That(gotObjectsFolder, Is.True); + } + + [Test] + public void TestSaveNonRootFolderToIar() + { + TestHelpers.InMethod(); +// TestHelpers.EnableLogging(); + + string userFirstName = "Jock"; + string userLastName = "Stirrup"; + string userPassword = "troll"; + UUID userId = TestHelpers.ParseTail(0x20); + + UserAccountHelpers.CreateUserWithInventory(m_scene, userFirstName, userLastName, userId, userPassword); + + // Create base folder + InventoryFolderBase f1 + = UserInventoryHelpers.CreateInventoryFolder(m_scene.InventoryService, userId, "f1", true); + + // Create item1 + SceneObjectGroup so1 = SceneHelpers.CreateSceneObject(1, userId, "My Little Dog Object", 0x5); + InventoryItemBase i1 = UserInventoryHelpers.AddInventoryItem(m_scene, so1, 0x50, 0x60, "f1"); + + // Create embedded folder + InventoryFolderBase f1_1 + = UserInventoryHelpers.CreateInventoryFolder(m_scene.InventoryService, userId, "f1/f1.1", true); + + // Create embedded item + SceneObjectGroup so1_1 = SceneHelpers.CreateSceneObject(1, userId, "My Little Cat Object", 0x6); + InventoryItemBase i2 = UserInventoryHelpers.AddInventoryItem(m_scene, so1_1, 0x500, 0x600, "f1/f1.1"); + + MemoryStream archiveWriteStream = new MemoryStream(); + m_archiverModule.OnInventoryArchiveSaved += SaveCompleted; + + mre.Reset(); + m_archiverModule.ArchiveInventory( + UUID.Random(), userFirstName, userLastName, "f1", userPassword, archiveWriteStream); + mre.WaitOne(60000, false); + + // Test created iar + byte[] archive = archiveWriteStream.ToArray(); + MemoryStream archiveReadStream = new MemoryStream(archive); + TarArchiveReader tar = new TarArchiveReader(archiveReadStream); + +// InventoryArchiveUtils. + bool gotf1 = false, gotf1_1 = false, gotso1 = false, gotso2 = false; + + string f1FileName + = string.Format("{0}{1}", ArchiveConstants.INVENTORY_PATH, InventoryArchiveWriteRequest.CreateArchiveFolderName(f1)); + string f1_1FileName + = string.Format("{0}{1}", f1FileName, InventoryArchiveWriteRequest.CreateArchiveFolderName(f1_1)); + string so1FileName + = string.Format("{0}{1}", f1FileName, InventoryArchiveWriteRequest.CreateArchiveItemName(i1)); + string so2FileName + = string.Format("{0}{1}", f1_1FileName, InventoryArchiveWriteRequest.CreateArchiveItemName(i2)); + + string filePath; + TarArchiveReader.TarEntryType tarEntryType; + + while (tar.ReadEntry(out filePath, out tarEntryType) != null) + { +// Console.WriteLine("Got {0}", filePath); + + if (filePath == f1FileName) + gotf1 = true; + else if (filePath == f1_1FileName) + gotf1_1 = true; + else if (filePath == so1FileName) + gotso1 = true; + else if (filePath == so2FileName) + gotso2 = true; + } + +// Assert.That(gotControlFile, Is.True, "No control file in archive"); + Assert.That(gotf1, Is.True); + Assert.That(gotf1_1, Is.True); + Assert.That(gotso1, Is.True); + Assert.That(gotso2, Is.True); + + // TODO: Test presence of more files and contents of files. + } + + /// + /// Test saving a single inventory item to an IAR + /// (subject to change since there is no fixed format yet). + /// + [Test] + public void TestSaveItemToIar() + { + TestHelpers.InMethod(); +// log4net.Config.XmlConfigurator.Configure(); + + // Create user + string userFirstName = "Jock"; + string userLastName = "Stirrup"; + string userPassword = "troll"; + UUID userId = UUID.Parse("00000000-0000-0000-0000-000000000020"); + UserAccountHelpers.CreateUserWithInventory(m_scene, userFirstName, userLastName, userId, userPassword); + + // Create asset + UUID ownerId = UUID.Parse("00000000-0000-0000-0000-000000000040"); + SceneObjectGroup object1 = SceneHelpers.CreateSceneObject(1, ownerId, "My Little Dog Object", 0x50); + + UUID asset1Id = UUID.Parse("00000000-0000-0000-0000-000000000060"); + AssetBase asset1 = AssetHelpers.CreateAsset(asset1Id, object1); + m_scene.AssetService.Store(asset1); + + // Create item + UUID item1Id = UUID.Parse("00000000-0000-0000-0000-000000000080"); + string item1Name = "My Little Dog"; + InventoryItemBase item1 = new InventoryItemBase(); + item1.Name = item1Name; + item1.AssetID = asset1.FullID; + item1.ID = item1Id; + InventoryFolderBase objsFolder + = InventoryArchiveUtils.FindFoldersByPath(m_scene.InventoryService, userId, "Objects")[0]; + item1.Folder = objsFolder.ID; + m_scene.AddInventoryItem(item1); + + MemoryStream archiveWriteStream = new MemoryStream(); + m_archiverModule.OnInventoryArchiveSaved += SaveCompleted; + + mre.Reset(); + m_archiverModule.ArchiveInventory( + UUID.Random(), userFirstName, userLastName, "Objects/" + item1Name, userPassword, archiveWriteStream); + mre.WaitOne(60000, false); + + byte[] archive = archiveWriteStream.ToArray(); + MemoryStream archiveReadStream = new MemoryStream(archive); + TarArchiveReader tar = new TarArchiveReader(archiveReadStream); + + //bool gotControlFile = false; + bool gotObject1File = false; + //bool gotObject2File = false; + string expectedObject1FileName = InventoryArchiveWriteRequest.CreateArchiveItemName(item1); + string expectedObject1FilePath = string.Format( + "{0}{1}", + ArchiveConstants.INVENTORY_PATH, + expectedObject1FileName); + + string filePath; + TarArchiveReader.TarEntryType tarEntryType; + +// Console.WriteLine("Reading archive"); + + while (tar.ReadEntry(out filePath, out tarEntryType) != null) + { + Console.WriteLine("Got {0}", filePath); + +// if (ArchiveConstants.CONTROL_FILE_PATH == filePath) +// { +// gotControlFile = true; +// } + + if (filePath.StartsWith(ArchiveConstants.INVENTORY_PATH) && filePath.EndsWith(".xml")) + { +// string fileName = filePath.Remove(0, "Objects/".Length); +// +// if (fileName.StartsWith(part1.Name)) +// { + Assert.That(expectedObject1FilePath, Is.EqualTo(filePath)); + gotObject1File = true; +// } +// else if (fileName.StartsWith(part2.Name)) +// { +// Assert.That(fileName, Is.EqualTo(expectedObject2FileName)); +// gotObject2File = true; +// } + } + } + +// Assert.That(gotControlFile, Is.True, "No control file in archive"); + Assert.That(gotObject1File, Is.True, "No item1 file in archive"); +// Assert.That(gotObject2File, Is.True, "No object2 file in archive"); + + // TODO: Test presence of more files and contents of files. + } + + /// + /// Test saving a single inventory item to an IAR without its asset + /// + [Test] + public void TestSaveItemToIarNoAssets() + { + TestHelpers.InMethod(); +// log4net.Config.XmlConfigurator.Configure(); + + // Create user + string userFirstName = "Jock"; + string userLastName = "Stirrup"; + string userPassword = "troll"; + UUID userId = UUID.Parse("00000000-0000-0000-0000-000000000020"); + UserAccountHelpers.CreateUserWithInventory(m_scene, userFirstName, userLastName, userId, userPassword); + + // Create asset + UUID ownerId = UUID.Parse("00000000-0000-0000-0000-000000000040"); + SceneObjectGroup object1 = SceneHelpers.CreateSceneObject(1, ownerId, "My Little Dog Object", 0x50); + + UUID asset1Id = UUID.Parse("00000000-0000-0000-0000-000000000060"); + AssetBase asset1 = AssetHelpers.CreateAsset(asset1Id, object1); + m_scene.AssetService.Store(asset1); + + // Create item + UUID item1Id = UUID.Parse("00000000-0000-0000-0000-000000000080"); + string item1Name = "My Little Dog"; + InventoryItemBase item1 = new InventoryItemBase(); + item1.Name = item1Name; + item1.AssetID = asset1.FullID; + item1.ID = item1Id; + InventoryFolderBase objsFolder + = InventoryArchiveUtils.FindFoldersByPath(m_scene.InventoryService, userId, "Objects")[0]; + item1.Folder = objsFolder.ID; + m_scene.AddInventoryItem(item1); + + MemoryStream archiveWriteStream = new MemoryStream(); + + Dictionary options = new Dictionary(); + options.Add("noassets", true); + + // When we're not saving assets, archiving is being done synchronously. + m_archiverModule.ArchiveInventory( + UUID.Random(), userFirstName, userLastName, "Objects/" + item1Name, userPassword, archiveWriteStream, options); + + byte[] archive = archiveWriteStream.ToArray(); + MemoryStream archiveReadStream = new MemoryStream(archive); + TarArchiveReader tar = new TarArchiveReader(archiveReadStream); + + //bool gotControlFile = false; + bool gotObject1File = false; + //bool gotObject2File = false; + string expectedObject1FileName = InventoryArchiveWriteRequest.CreateArchiveItemName(item1); + string expectedObject1FilePath = string.Format( + "{0}{1}", + ArchiveConstants.INVENTORY_PATH, + expectedObject1FileName); + + string filePath; + TarArchiveReader.TarEntryType tarEntryType; + +// Console.WriteLine("Reading archive"); + + while (tar.ReadEntry(out filePath, out tarEntryType) != null) + { + Console.WriteLine("Got {0}", filePath); + +// if (ArchiveConstants.CONTROL_FILE_PATH == filePath) +// { +// gotControlFile = true; +// } + + if (filePath.StartsWith(ArchiveConstants.INVENTORY_PATH) && filePath.EndsWith(".xml")) + { +// string fileName = filePath.Remove(0, "Objects/".Length); +// +// if (fileName.StartsWith(part1.Name)) +// { + Assert.That(expectedObject1FilePath, Is.EqualTo(filePath)); + gotObject1File = true; +// } +// else if (fileName.StartsWith(part2.Name)) +// { +// Assert.That(fileName, Is.EqualTo(expectedObject2FileName)); +// gotObject2File = true; +// } + } + else if (filePath.StartsWith(ArchiveConstants.ASSETS_PATH)) + { + Assert.Fail("Found asset path in TestSaveItemToIarNoAssets()"); + } + } + +// Assert.That(gotControlFile, Is.True, "No control file in archive"); + Assert.That(gotObject1File, Is.True, "No item1 file in archive"); +// Assert.That(gotObject2File, Is.True, "No object2 file in archive"); + + // TODO: Test presence of more files and contents of files. + } + } +} \ No newline at end of file diff --git a/Tests/OpenSim.Region.CoreModules.Tests/Avatar/Inventory/Archiver/Tests/InventoryArchiveTestCase.cs b/Tests/OpenSim.Region.CoreModules.Tests/Avatar/Inventory/Archiver/Tests/InventoryArchiveTestCase.cs new file mode 100644 index 00000000000..deb6375a5be --- /dev/null +++ b/Tests/OpenSim.Region.CoreModules.Tests/Avatar/Inventory/Archiver/Tests/InventoryArchiveTestCase.cs @@ -0,0 +1,179 @@ +/* + * 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 System.IO; +using System.Reflection; +using System.Threading; +using NUnit.Framework; +using OpenMetaverse; +using OpenSim.Data; +using OpenSim.Framework; +using OpenSim.Framework.Serialization; +using OpenSim.Framework.Serialization.External; +using OpenSim.Region.CoreModules.Avatar.Inventory.Archiver; +using OpenSim.Region.CoreModules.World.Serialiser; +using OpenSim.Region.Framework.Scenes; +using OpenSim.Region.Framework.Scenes.Serialization; +using OpenSim.Services.Interfaces; +using OpenSim.Tests.Common; + +namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver.Tests +{ + [TestFixture] + public class InventoryArchiveTestCase : OpenSimTestCase + { + protected ManualResetEvent mre = new ManualResetEvent(false); + + /// + /// A raw array of bytes that we'll use to create an IAR memory stream suitable for isolated use in each test. + /// + protected byte[] m_iarStreamBytes; + + /// + /// Stream of data representing a common IAR for load tests. + /// + protected MemoryStream m_iarStream; + + protected UserAccount m_uaMT + = new UserAccount { + PrincipalID = UUID.Parse("00000000-0000-0000-0000-000000000555"), + FirstName = "Mr", + LastName = "Tiddles" }; + + protected UserAccount m_uaLL1 + = new UserAccount { + PrincipalID = UUID.Parse("00000000-0000-0000-0000-000000000666"), + FirstName = "Lord", + LastName = "Lucan" }; + + protected UserAccount m_uaLL2 + = new UserAccount { + PrincipalID = UUID.Parse("00000000-0000-0000-0000-000000000777"), + FirstName = "Lord", + LastName = "Lucan" }; + + protected string m_item1Name = "Ray Gun Item"; + protected string m_coaItemName = "Coalesced Item"; + + [OneTimeSetUp] + public void FixtureSetup() + { + // Don't allow tests to be bamboozled by asynchronous events. Execute everything on the same thread. + Util.FireAndForgetMethod = FireAndForgetMethod.RegressionTest; + + ConstructDefaultIarBytesForTestLoad(); + } + + [OneTimeTearDown] + 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; + } + + [SetUp] + public override void SetUp() + { + base.SetUp(); + m_iarStream = new MemoryStream(m_iarStreamBytes); + } + + protected void ConstructDefaultIarBytesForTestLoad() + { +// log4net.Config.XmlConfigurator.Configure(); + + InventoryArchiverModule archiverModule = new InventoryArchiverModule(); + Scene scene = new SceneHelpers().SetupScene(); + SceneHelpers.SetupSceneModules(scene, archiverModule); + + UserAccountHelpers.CreateUserWithInventory(scene, m_uaLL1, "hampshire"); + + MemoryStream archiveWriteStream = new MemoryStream(); + + //InventoryFolderBase objects = scene.InventoryService.GetFolderForType(m_uaLL1.PrincipalID, FolderType.Object); + // Create scene object asset + UUID ownerId = UUID.Parse("00000000-0000-0000-0000-000000000040"); + SceneObjectGroup object1 = SceneHelpers.CreateSceneObject(1, ownerId, "Ray Gun Object", 0x50); + + UUID asset1Id = UUID.Parse("00000000-0000-0000-0000-000000000060"); + AssetBase asset1 = AssetHelpers.CreateAsset(asset1Id, object1); + scene.AssetService.Store(asset1); + + // Create scene object item + InventoryItemBase item1 = new InventoryItemBase(); + item1.Name = m_item1Name; + item1.ID = UUID.Parse("00000000-0000-0000-0000-000000000020"); + item1.AssetID = asset1.FullID; + item1.GroupID = UUID.Random(); + item1.CreatorId = m_uaLL1.PrincipalID.ToString(); + item1.Owner = m_uaLL1.PrincipalID; + //item1.Folder = objects.ID; + item1.Folder = scene.InventoryService.GetRootFolder(m_uaLL1.PrincipalID).ID; + scene.AddInventoryItem(item1); + + // Create coalesced objects asset + SceneObjectGroup cobj1 = SceneHelpers.CreateSceneObject(1, m_uaLL1.PrincipalID, "Object1", 0x120); + cobj1.AbsolutePosition = new Vector3(15, 30, 45); + + SceneObjectGroup cobj2 = SceneHelpers.CreateSceneObject(1, m_uaLL1.PrincipalID, "Object2", 0x140); + cobj2.AbsolutePosition = new Vector3(25, 50, 75); + + CoalescedSceneObjects coa = new CoalescedSceneObjects(m_uaLL1.PrincipalID, cobj1, cobj2); + + AssetBase coaAsset = AssetHelpers.CreateAsset(0x160, coa); + scene.AssetService.Store(coaAsset); + + // Create coalesced objects inventory item + InventoryItemBase coaItem = new InventoryItemBase(); + coaItem.Name = m_coaItemName; + coaItem.ID = UUID.Parse("00000000-0000-0000-0000-000000000180"); + coaItem.AssetID = coaAsset.FullID; + coaItem.GroupID = UUID.Random(); + coaItem.CreatorId = m_uaLL1.PrincipalID.ToString(); + coaItem.Owner = m_uaLL1.PrincipalID; + //coaItem.Folder = objects.ID; + coaItem.Folder = scene.InventoryService.GetRootFolder(m_uaLL1.PrincipalID).ID; + scene.AddInventoryItem(coaItem); + + archiverModule.ArchiveInventory( + UUID.Random(), m_uaLL1.FirstName, m_uaLL1.LastName, "/*", "hampshire", archiveWriteStream); + + m_iarStreamBytes = archiveWriteStream.ToArray(); + } + + protected void SaveCompleted( + UUID id, bool succeeded, UserAccount userInfo, string invPath, Stream saveStream, + Exception reportedException, int SaveCount, int FilterCount) + { + mre.Set(); + } + } +} \ No newline at end of file diff --git a/Tests/OpenSim.Region.CoreModules.Tests/Avatar/Inventory/Transfer/Tests/InventoryTransferModuleTests.cs b/Tests/OpenSim.Region.CoreModules.Tests/Avatar/Inventory/Transfer/Tests/InventoryTransferModuleTests.cs new file mode 100644 index 00000000000..82ed0918aa1 --- /dev/null +++ b/Tests/OpenSim.Region.CoreModules.Tests/Avatar/Inventory/Transfer/Tests/InventoryTransferModuleTests.cs @@ -0,0 +1,448 @@ +/* + * 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 System.Reflection; +using log4net.Config; +using Nini.Config; +using NUnit.Framework; +using OpenMetaverse; +using OpenMetaverse.Assets; +using OpenSim.Framework; +using OpenSim.Region.CoreModules.Avatar.Inventory.Transfer; +using OpenSim.Region.Framework.Interfaces; +using OpenSim.Region.Framework.Scenes; +using OpenSim.Services.Interfaces; +using OpenSim.Tests.Common; + +namespace OpenSim.Region.CoreModules.Avatar.Inventory.Transfer.Tests +{ + [TestFixture] + public class InventoryTransferModuleTests : OpenSimTestCase + { + protected TestScene m_scene; + + [SetUp] + public override void SetUp() + { + base.SetUp(); + + IConfigSource config = new IniConfigSource(); + config.AddConfig("Messaging"); + config.Configs["Messaging"].Set("InventoryTransferModule", "InventoryTransferModule"); + + m_scene = new SceneHelpers().SetupScene(); + SceneHelpers.SetupSceneModules(m_scene, config, new InventoryTransferModule()); + } + + [Test] + public void TestAcceptGivenItem() + { +// TestHelpers.EnableLogging(); + + UUID initialSessionId = TestHelpers.ParseTail(0x10); + UUID itemId = TestHelpers.ParseTail(0x100); + UUID assetId = TestHelpers.ParseTail(0x200); + + UserAccount ua1 + = UserAccountHelpers.CreateUserWithInventory(m_scene, "User", "One", TestHelpers.ParseTail(0x1), "pw"); + UserAccount ua2 + = UserAccountHelpers.CreateUserWithInventory(m_scene, "User", "Two", TestHelpers.ParseTail(0x2), "pw"); + + ScenePresence giverSp = SceneHelpers.AddScenePresence(m_scene, ua1); + TestClient giverClient = (TestClient)giverSp.ControllingClient; + + ScenePresence receiverSp = SceneHelpers.AddScenePresence(m_scene, ua2); + TestClient receiverClient = (TestClient)receiverSp.ControllingClient; + + // Create the object to test give + InventoryItemBase originalItem + = UserInventoryHelpers.CreateInventoryItem( + m_scene, "givenObj", itemId, assetId, giverSp.UUID, InventoryType.Object); + + byte[] giveImBinaryBucket = new byte[17]; + byte[] itemIdBytes = itemId.GetBytes(); + Array.Copy(itemIdBytes, 0, giveImBinaryBucket, 1, itemIdBytes.Length); + + GridInstantMessage giveIm + = new GridInstantMessage( + m_scene, + giverSp.UUID, + giverSp.Name, + receiverSp.UUID, + (byte)InstantMessageDialog.InventoryOffered, + false, + "inventory offered msg", + initialSessionId, + false, + Vector3.Zero, + giveImBinaryBucket, + true); + + giverClient.HandleImprovedInstantMessage(giveIm); + + // These details might not all be correct. + GridInstantMessage acceptIm + = new GridInstantMessage( + m_scene, + receiverSp.UUID, + receiverSp.Name, + giverSp.UUID, + (byte)InstantMessageDialog.InventoryAccepted, + false, + "inventory accepted msg", + initialSessionId, + false, + Vector3.Zero, + null, + true); + + receiverClient.HandleImprovedInstantMessage(acceptIm); + + // Test for item remaining in the giver's inventory (here we assume a copy item) + // TODO: Test no-copy items. + InventoryItemBase originalItemAfterGive + = UserInventoryHelpers.GetInventoryItem(m_scene.InventoryService, giverSp.UUID, "Objects/givenObj"); + + Assert.That(originalItemAfterGive, Is.Not.Null); + Assert.That(originalItemAfterGive.ID, Is.EqualTo(originalItem.ID)); + + // Test for item successfully making it into the receiver's inventory + InventoryItemBase receivedItem + = UserInventoryHelpers.GetInventoryItem(m_scene.InventoryService, receiverSp.UUID, "Objects/givenObj"); + + Assert.That(receivedItem, Is.Not.Null); + Assert.That(receivedItem.ID, Is.Not.EqualTo(originalItem.ID)); + + // Test that on a delete, item still exists and is accessible for the giver. + m_scene.InventoryService.DeleteItems(receiverSp.UUID, new List() { receivedItem.ID }); + + InventoryItemBase originalItemAfterDelete + = UserInventoryHelpers.GetInventoryItem(m_scene.InventoryService, giverSp.UUID, "Objects/givenObj"); + + Assert.That(originalItemAfterDelete, Is.Not.Null); + + // TODO: Test scenario where giver deletes their item first. + } + + /// + /// Test user rejection of a given item. + /// + /// + /// A rejected item still ends up in the user's trash folder. + /// + [Test] + public void TestRejectGivenItem() + { +// TestHelpers.EnableLogging(); + + UUID initialSessionId = TestHelpers.ParseTail(0x10); + UUID itemId = TestHelpers.ParseTail(0x100); + UUID assetId = TestHelpers.ParseTail(0x200); + + UserAccount ua1 + = UserAccountHelpers.CreateUserWithInventory(m_scene, "User", "One", TestHelpers.ParseTail(0x1), "pw"); + UserAccount ua2 + = UserAccountHelpers.CreateUserWithInventory(m_scene, "User", "Two", TestHelpers.ParseTail(0x2), "pw"); + + ScenePresence giverSp = SceneHelpers.AddScenePresence(m_scene, ua1); + TestClient giverClient = (TestClient)giverSp.ControllingClient; + + ScenePresence receiverSp = SceneHelpers.AddScenePresence(m_scene, ua2); + TestClient receiverClient = (TestClient)receiverSp.ControllingClient; + + // Create the object to test give + InventoryItemBase originalItem + = UserInventoryHelpers.CreateInventoryItem( + m_scene, "givenObj", itemId, assetId, giverSp.UUID, InventoryType.Object); + + GridInstantMessage receivedIm = null; + receiverClient.OnReceivedInstantMessage += im => receivedIm = im; + + byte[] giveImBinaryBucket = new byte[17]; + byte[] itemIdBytes = itemId.GetBytes(); + Array.Copy(itemIdBytes, 0, giveImBinaryBucket, 1, itemIdBytes.Length); + + GridInstantMessage giveIm + = new GridInstantMessage( + m_scene, + giverSp.UUID, + giverSp.Name, + receiverSp.UUID, + (byte)InstantMessageDialog.InventoryOffered, + false, + "inventory offered msg", + initialSessionId, + false, + Vector3.Zero, + giveImBinaryBucket, + true); + + giverClient.HandleImprovedInstantMessage(giveIm); + + // These details might not all be correct. + // Session ID is now the created item ID (!) + GridInstantMessage rejectIm + = new GridInstantMessage( + m_scene, + receiverSp.UUID, + receiverSp.Name, + giverSp.UUID, + (byte)InstantMessageDialog.InventoryDeclined, + false, + "inventory declined msg", + new UUID(receivedIm.imSessionID), + false, + Vector3.Zero, + null, + true); + + receiverClient.HandleImprovedInstantMessage(rejectIm); + + // Test for item remaining in the giver's inventory (here we assume a copy item) + // TODO: Test no-copy items. + InventoryItemBase originalItemAfterGive + = UserInventoryHelpers.GetInventoryItem(m_scene.InventoryService, giverSp.UUID, "Objects/givenObj"); + + Assert.That(originalItemAfterGive, Is.Not.Null); + Assert.That(originalItemAfterGive.ID, Is.EqualTo(originalItem.ID)); + + // Test for item successfully making it into the receiver's inventory + InventoryItemBase receivedItem + = UserInventoryHelpers.GetInventoryItem(m_scene.InventoryService, receiverSp.UUID, "Trash/givenObj"); + + InventoryFolderBase trashFolder + = m_scene.InventoryService.GetFolderForType(receiverSp.UUID, FolderType.Trash); + + Assert.That(receivedItem, Is.Not.Null); + Assert.That(receivedItem.ID, Is.Not.EqualTo(originalItem.ID)); + Assert.That(receivedItem.Folder, Is.EqualTo(trashFolder.ID)); + + // Test that on a delete, item still exists and is accessible for the giver. + m_scene.InventoryService.PurgeFolder(trashFolder); + + InventoryItemBase originalItemAfterDelete + = UserInventoryHelpers.GetInventoryItem(m_scene.InventoryService, giverSp.UUID, "Objects/givenObj"); + + Assert.That(originalItemAfterDelete, Is.Not.Null); + } + + [Test] + public void TestAcceptGivenFolder() + { + TestHelpers.InMethod(); +// TestHelpers.EnableLogging(); + + UUID initialSessionId = TestHelpers.ParseTail(0x10); + UUID folderId = TestHelpers.ParseTail(0x100); + + UserAccount ua1 + = UserAccountHelpers.CreateUserWithInventory(m_scene, "User", "One", TestHelpers.ParseTail(0x1), "pw"); + UserAccount ua2 + = UserAccountHelpers.CreateUserWithInventory(m_scene, "User", "Two", TestHelpers.ParseTail(0x2), "pw"); + + ScenePresence giverSp = SceneHelpers.AddScenePresence(m_scene, ua1); + TestClient giverClient = (TestClient)giverSp.ControllingClient; + + ScenePresence receiverSp = SceneHelpers.AddScenePresence(m_scene, ua2); + TestClient receiverClient = (TestClient)receiverSp.ControllingClient; + + InventoryFolderBase originalFolder + = UserInventoryHelpers.CreateInventoryFolder( + m_scene.InventoryService, giverSp.UUID, folderId, "f1", true); + + byte[] giveImBinaryBucket = new byte[17]; + giveImBinaryBucket[0] = (byte)AssetType.Folder; + byte[] itemIdBytes = folderId.GetBytes(); + Array.Copy(itemIdBytes, 0, giveImBinaryBucket, 1, itemIdBytes.Length); + + GridInstantMessage giveIm + = new GridInstantMessage( + m_scene, + giverSp.UUID, + giverSp.Name, + receiverSp.UUID, + (byte)InstantMessageDialog.InventoryOffered, + false, + "inventory offered msg", + initialSessionId, + false, + Vector3.Zero, + giveImBinaryBucket, + true); + + giverClient.HandleImprovedInstantMessage(giveIm); + + // These details might not all be correct. + GridInstantMessage acceptIm + = new GridInstantMessage( + m_scene, + receiverSp.UUID, + receiverSp.Name, + giverSp.UUID, + (byte)InstantMessageDialog.InventoryAccepted, + false, + "inventory accepted msg", + initialSessionId, + false, + Vector3.Zero, + null, + true); + + receiverClient.HandleImprovedInstantMessage(acceptIm); + + // Test for item remaining in the giver's inventory (here we assume a copy item) + // TODO: Test no-copy items. + InventoryFolderBase originalFolderAfterGive + = UserInventoryHelpers.GetInventoryFolder(m_scene.InventoryService, giverSp.UUID, "f1"); + + Assert.That(originalFolderAfterGive, Is.Not.Null); + Assert.That(originalFolderAfterGive.ID, Is.EqualTo(originalFolder.ID)); + + // Test for item successfully making it into the receiver's inventory + InventoryFolderBase receivedFolder + = UserInventoryHelpers.GetInventoryFolder(m_scene.InventoryService, receiverSp.UUID, "f1"); + + Assert.That(receivedFolder, Is.Not.Null); + Assert.That(receivedFolder.ID, Is.Not.EqualTo(originalFolder.ID)); + + // Test that on a delete, item still exists and is accessible for the giver. + m_scene.InventoryService.DeleteFolders(receiverSp.UUID, new List() { receivedFolder.ID }); + + InventoryFolderBase originalFolderAfterDelete + = UserInventoryHelpers.GetInventoryFolder(m_scene.InventoryService, giverSp.UUID, "f1"); + + Assert.That(originalFolderAfterDelete, Is.Not.Null); + + // TODO: Test scenario where giver deletes their item first. + } + + /// + /// Test user rejection of a given item. + /// + /// + /// A rejected item still ends up in the user's trash folder. + /// + [Test] + public void TestRejectGivenFolder() + { + TestHelpers.InMethod(); +// TestHelpers.EnableLogging(); + + UUID initialSessionId = TestHelpers.ParseTail(0x10); + UUID folderId = TestHelpers.ParseTail(0x100); + + UserAccount ua1 + = UserAccountHelpers.CreateUserWithInventory(m_scene, "User", "One", TestHelpers.ParseTail(0x1), "pw"); + UserAccount ua2 + = UserAccountHelpers.CreateUserWithInventory(m_scene, "User", "Two", TestHelpers.ParseTail(0x2), "pw"); + + ScenePresence giverSp = SceneHelpers.AddScenePresence(m_scene, ua1); + TestClient giverClient = (TestClient)giverSp.ControllingClient; + + ScenePresence receiverSp = SceneHelpers.AddScenePresence(m_scene, ua2); + TestClient receiverClient = (TestClient)receiverSp.ControllingClient; + + // Create the folder to test give + InventoryFolderBase originalFolder + = UserInventoryHelpers.CreateInventoryFolder( + m_scene.InventoryService, giverSp.UUID, folderId, "f1", true); + + GridInstantMessage receivedIm = null; + receiverClient.OnReceivedInstantMessage += im => receivedIm = im; + + byte[] giveImBinaryBucket = new byte[17]; + giveImBinaryBucket[0] = (byte)AssetType.Folder; + byte[] itemIdBytes = folderId.GetBytes(); + Array.Copy(itemIdBytes, 0, giveImBinaryBucket, 1, itemIdBytes.Length); + + GridInstantMessage giveIm + = new GridInstantMessage( + m_scene, + giverSp.UUID, + giverSp.Name, + receiverSp.UUID, + (byte)InstantMessageDialog.InventoryOffered, + false, + "inventory offered msg", + initialSessionId, + false, + Vector3.Zero, + giveImBinaryBucket, + true); + + giverClient.HandleImprovedInstantMessage(giveIm); + + // These details might not all be correct. + // Session ID is now the created item ID (!) + GridInstantMessage rejectIm + = new GridInstantMessage( + m_scene, + receiverSp.UUID, + receiverSp.Name, + giverSp.UUID, + (byte)InstantMessageDialog.InventoryDeclined, + false, + "inventory declined msg", + new UUID(receivedIm.imSessionID), + false, + Vector3.Zero, + null, + true); + + receiverClient.HandleImprovedInstantMessage(rejectIm); + + // Test for item remaining in the giver's inventory (here we assume a copy item) + // TODO: Test no-copy items. + InventoryFolderBase originalFolderAfterGive + = UserInventoryHelpers.GetInventoryFolder(m_scene.InventoryService, giverSp.UUID, "f1"); + + Assert.That(originalFolderAfterGive, Is.Not.Null); + Assert.That(originalFolderAfterGive.ID, Is.EqualTo(originalFolder.ID)); + + // Test for folder successfully making it into the receiver's inventory + InventoryFolderBase receivedFolder + = UserInventoryHelpers.GetInventoryFolder(m_scene.InventoryService, receiverSp.UUID, "Trash/f1"); + + InventoryFolderBase trashFolder + = m_scene.InventoryService.GetFolderForType(receiverSp.UUID, FolderType.Trash); + + Assert.That(receivedFolder, Is.Not.Null); + Assert.That(receivedFolder.ID, Is.Not.EqualTo(originalFolder.ID)); + Assert.That(receivedFolder.ParentID, Is.EqualTo(trashFolder.ID)); + + // Test that on a delete, item still exists and is accessible for the giver. + m_scene.InventoryService.PurgeFolder(trashFolder); + + InventoryFolderBase originalFolderAfterDelete + = UserInventoryHelpers.GetInventoryFolder(m_scene.InventoryService, giverSp.UUID, "f1"); + + Assert.That(originalFolderAfterDelete, Is.Not.Null); + } + } +} \ No newline at end of file diff --git a/Tests/OpenSim.Region.CoreModules.Tests/Framework/InventoryAccess/Tests/HGAssetMapperTests.cs b/Tests/OpenSim.Region.CoreModules.Tests/Framework/InventoryAccess/Tests/HGAssetMapperTests.cs new file mode 100644 index 00000000000..7515e0edd0d --- /dev/null +++ b/Tests/OpenSim.Region.CoreModules.Tests/Framework/InventoryAccess/Tests/HGAssetMapperTests.cs @@ -0,0 +1,148 @@ +/* + * 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 System.Xml; +using Nini.Config; +using NUnit.Framework; +using OpenMetaverse; +using OpenSim.Framework; +using OpenSim.Region.CoreModules.Framework.InventoryAccess; +using OpenSim.Region.Framework.Scenes; +//using OpenSim.Region.ScriptEngine.XEngine; +using OpenSim.Services.Interfaces; +using OpenSim.Tests.Common; + +namespace OpenSim.Region.CoreModules.Framework.InventoryAccess.Tests +{ + [TestFixture] + public class HGAssetMapperTests : OpenSimTestCase + { + /* + [Test] + public void TestPostAssetRewrite() + { + TestHelpers.InMethod(); +// TestHelpers.EnableLogging(); + + XEngine xengine = new XEngine(); + xengine.DebugLevel = 1; + + IniConfigSource configSource = new IniConfigSource(); + + IConfig startupConfig = configSource.AddConfig("Startup"); + startupConfig.Set("DefaultScriptEngine", "XEngine"); + + IConfig xEngineConfig = configSource.AddConfig("XEngine"); + xEngineConfig.Set("Enabled", "true"); + xEngineConfig.Set("StartDelay", "0"); + xEngineConfig.Set("AppDomainLoading", "false"); + + string homeUrl = "http://hg.HomeTestPostAssetRewriteGrid.com"; + string foreignUrl = "http://hg.ForeignTestPostAssetRewriteGrid.com"; + int soIdTail = 0x1; + UUID assetId = TestHelpers.ParseTail(0x10); + UUID userId = TestHelpers.ParseTail(0x100); + UUID sceneId = TestHelpers.ParseTail(0x1000); + string userFirstName = "TestPostAsset"; + string userLastName = "Rewrite"; + int soPartsCount = 3; + + Scene scene = new SceneHelpers().SetupScene("TestPostAssetRewriteScene", sceneId, 1000, 1000, configSource); + SceneHelpers.SetupSceneModules(scene, configSource, xengine); + scene.StartScripts(); + + HGAssetMapper hgam = new HGAssetMapper(scene, homeUrl); + UserAccount ua + = UserAccountHelpers.CreateUserWithInventory(scene, userFirstName, userLastName, userId, "password"); + + SceneObjectGroup so = SceneHelpers.AddSceneObject(scene, soPartsCount, ua.PrincipalID, "part", soIdTail); + RezScript( + scene, so.UUID, "default { state_entry() { llSay(0, \"Hello World\"); } }", "item1", ua.PrincipalID); + + AssetBase asset = AssetHelpers.CreateAsset(assetId, so); + asset.CreatorID = foreignUrl; + hgam.PostAsset(foreignUrl, asset); + + // Check transformed asset. + AssetBase ncAssetGet = scene.AssetService.Get(assetId.ToString()); + Assert.AreEqual(foreignUrl, ncAssetGet.CreatorID); + string xmlData = Utils.BytesToString(ncAssetGet.Data); + XmlDocument ncAssetGetXmlDoc = new XmlDocument(); + ncAssetGetXmlDoc.LoadXml(xmlData); + + // Console.WriteLine(ncAssetGetXmlDoc.OuterXml); + + XmlNodeList creatorDataNodes = ncAssetGetXmlDoc.GetElementsByTagName("CreatorData"); + + Assert.AreEqual(soPartsCount, creatorDataNodes.Count); + //Console.WriteLine("creatorDataNodes {0}", creatorDataNodes.Count); + + foreach (XmlNode creatorDataNode in creatorDataNodes) + { + Assert.AreEqual( + string.Format("{0};{1} {2}", homeUrl, ua.FirstName, ua.LastName), creatorDataNode.InnerText); + } + + // Check that saved script nodes have attributes + XmlNodeList savedScriptStateNodes = ncAssetGetXmlDoc.GetElementsByTagName("SavedScriptState"); + + Assert.AreEqual(1, savedScriptStateNodes.Count); + Assert.AreEqual(1, savedScriptStateNodes[0].Attributes.Count); + XmlNode uuidAttribute = savedScriptStateNodes[0].Attributes.GetNamedItem("UUID"); + Assert.NotNull(uuidAttribute); + // XXX: To check the actual UUID attribute we would have to do some work to retreive the UUID of the task + // item created earlier. + } + + private void RezScript(Scene scene, UUID soId, string script, string itemName, UUID userId) + { + InventoryItemBase itemTemplate = new InventoryItemBase(); + // itemTemplate.ID = itemId; + itemTemplate.Name = itemName; + itemTemplate.Folder = soId; + itemTemplate.InvType = (int)InventoryType.LSL; + + // XXX: Ultimately it would be better to be able to directly manipulate the script engine to rez a script + // immediately for tests rather than chunter through it's threaded mechanisms. + AutoResetEvent chatEvent = new AutoResetEvent(false); + + scene.EventManager.OnChatFromWorld += (s, c) => + { +// Console.WriteLine("Got chat [{0}]", c.Message); + chatEvent.Set(); + }; + + scene.RezNewScript(userId, itemTemplate, script); + +// Console.WriteLine("HERE"); + Assert.IsTrue(chatEvent.WaitOne(60000), "Chat event in HGAssetMapperTests.RezScript not received"); + } + } + */ +} \ No newline at end of file diff --git a/Tests/OpenSim.Region.CoreModules.Tests/Framework/InventoryAccess/Tests/InventoryAccessModuleTests.cs b/Tests/OpenSim.Region.CoreModules.Tests/Framework/InventoryAccess/Tests/InventoryAccessModuleTests.cs new file mode 100644 index 00000000000..80cfdae49f9 --- /dev/null +++ b/Tests/OpenSim.Region.CoreModules.Tests/Framework/InventoryAccess/Tests/InventoryAccessModuleTests.cs @@ -0,0 +1,178 @@ +/* + * 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 System.IO; +using System.Reflection; +using System.Threading; +using Nini.Config; +using NUnit.Framework; +using OpenMetaverse; +using OpenSim.Data; +using OpenSim.Framework; +using OpenSim.Framework.Serialization; +using OpenSim.Framework.Serialization.External; +using OpenSim.Region.CoreModules.Avatar.Inventory.Archiver; +using OpenSim.Region.CoreModules.Framework.InventoryAccess; +using OpenSim.Region.Framework.Scenes; +using OpenSim.Region.Framework.Scenes.Serialization; +using OpenSim.Services.Interfaces; +using OpenSim.Tests.Common; + +namespace OpenSim.Region.CoreModules.Framework.InventoryAccess.Tests +{ + [TestFixture] + public class InventoryAccessModuleTests : OpenSimTestCase + { + protected TestScene m_scene; + protected BasicInventoryAccessModule m_iam; + protected UUID m_userId = UUID.Parse("00000000-0000-0000-0000-000000000020"); + protected TestClient m_tc; + + [SetUp] + public override void SetUp() + { + base.SetUp(); + + m_iam = new BasicInventoryAccessModule(); + + IConfigSource config = new IniConfigSource(); + config.AddConfig("Modules"); + config.Configs["Modules"].Set("InventoryAccessModule", "BasicInventoryAccessModule"); + + SceneHelpers sceneHelpers = new SceneHelpers(); + m_scene = sceneHelpers.SetupScene(); + SceneHelpers.SetupSceneModules(m_scene, config, m_iam); + + // Create user + string userFirstName = "Jock"; + string userLastName = "Stirrup"; + string userPassword = "troll"; + UserAccountHelpers.CreateUserWithInventory(m_scene, userFirstName, userLastName, m_userId, userPassword); + + AgentCircuitData acd = new AgentCircuitData(); + acd.AgentID = m_userId; + m_tc = new TestClient(acd, m_scene); + } + + [Test] + public void TestRezCoalescedObject() + { +/* + TestHelpers.InMethod(); +// log4net.Config.XmlConfigurator.Configure(); + + // Create asset + SceneObjectGroup object1 = SceneHelpers.CreateSceneObject(1, m_userId, "Object1", 0x20); + object1.AbsolutePosition = new Vector3(15, 30, 45); + + SceneObjectGroup object2 = SceneHelpers.CreateSceneObject(1, m_userId, "Object2", 0x40); + object2.AbsolutePosition = new Vector3(25, 50, 75); + + CoalescedSceneObjects coa = new CoalescedSceneObjects(m_userId, object1, object2); + + UUID asset1Id = UUID.Parse("00000000-0000-0000-0000-000000000060"); + AssetBase asset1 = AssetHelpers.CreateAsset(asset1Id, coa); + m_scene.AssetService.Store(asset1); + + // Create item + UUID item1Id = UUID.Parse("00000000-0000-0000-0000-000000000080"); + string item1Name = "My Little Dog"; + InventoryItemBase item1 = new InventoryItemBase(); + item1.Name = item1Name; + item1.AssetID = asset1.FullID; + item1.ID = item1Id; + InventoryFolderBase objsFolder + = InventoryArchiveUtils.FindFoldersByPath(m_scene.InventoryService, m_userId, "Objects")[0]; + item1.Folder = objsFolder.ID; + item1.Flags |= (uint)InventoryItemFlags.ObjectHasMultipleItems; + m_scene.AddInventoryItem(item1); + + SceneObjectGroup so + = m_iam.RezObject( + m_tc, item1Id, new Vector3(100, 100, 100), Vector3.Zero, UUID.Zero, 1, false, false, false, UUID.Zero, false); + + Assert.That(so, Is.Not.Null); + + Assert.That(m_scene.SceneGraph.GetTotalObjectsCount(), Is.EqualTo(2)); + + SceneObjectPart retrievedObj1Part = m_scene.GetSceneObjectPart(object1.Name); + Assert.That(retrievedObj1Part, Is.Null); + + retrievedObj1Part = m_scene.GetSceneObjectPart(item1.Name); + Assert.That(retrievedObj1Part, Is.Not.Null); + Assert.That(retrievedObj1Part.Name, Is.EqualTo(item1.Name)); + + // Bottom of coalescence is placed on ground, hence we end up with 100.5 rather than 85 since the bottom + // object is unit square. + Assert.That(retrievedObj1Part.AbsolutePosition, Is.EqualTo(new Vector3(95, 90, 100.5f))); + + SceneObjectPart retrievedObj2Part = m_scene.GetSceneObjectPart(object2.Name); + Assert.That(retrievedObj2Part, Is.Not.Null); + Assert.That(retrievedObj2Part.Name, Is.EqualTo(object2.Name)); + Assert.That(retrievedObj2Part.AbsolutePosition, Is.EqualTo(new Vector3(105, 110, 130.5f))); +*/ + } + + [Test] + public void TestRezObject() + { + TestHelpers.InMethod(); + //log4net.Config.XmlConfigurator.Configure(); + + // Create asset + SceneObjectGroup object1 = SceneHelpers.CreateSceneObject(1, m_userId, "My Little Dog Object", 0x40); + + UUID asset1Id = UUID.Parse("00000000-0000-0000-0000-000000000060"); + AssetBase asset1 = AssetHelpers.CreateAsset(asset1Id, object1); + m_scene.AssetService.Store(asset1); + + // Create item + UUID item1Id = UUID.Parse("00000000-0000-0000-0000-000000000080"); + string item1Name = "My Little Dog"; + InventoryItemBase item1 = new InventoryItemBase(); + item1.Name = item1Name; + item1.AssetID = asset1.FullID; + item1.ID = item1Id; + item1.Owner = m_userId; + InventoryFolderBase objsFolder + = InventoryArchiveUtils.FindFoldersByPath(m_scene.InventoryService, m_userId, "Objects")[0]; + item1.Folder = objsFolder.ID; + m_scene.AddInventoryItem(item1); + + SceneObjectGroup so + = m_iam.RezObject( + m_tc, item1Id, UUID.Zero, Vector3.Zero, Vector3.Zero, UUID.Zero, 1, false, false, false, UUID.Zero, false); + + Assert.That(so, Is.Not.Null); + + SceneObjectPart retrievedPart = m_scene.GetSceneObjectPart(so.UUID); + Assert.That(retrievedPart, Is.Not.Null); + } + } +} \ No newline at end of file diff --git a/Tests/OpenSim.Region.CoreModules.Tests/Framework/UserManagement/Tests/HGUserManagementModuleTests.cs b/Tests/OpenSim.Region.CoreModules.Tests/Framework/UserManagement/Tests/HGUserManagementModuleTests.cs new file mode 100644 index 00000000000..8d07ffe2284 --- /dev/null +++ b/Tests/OpenSim.Region.CoreModules.Tests/Framework/UserManagement/Tests/HGUserManagementModuleTests.cs @@ -0,0 +1,75 @@ +/* + * 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 Nini.Config; +using NUnit.Framework; +using OpenMetaverse; +using OpenSim.Framework; +using OpenSim.Region.CoreModules.Framework.UserManagement; +using OpenSim.Tests.Common; + +namespace OpenSim.Region.CoreModules.Framework.UserManagement.Tests +{ + [TestFixture] + public class HGUserManagementModuleTests : OpenSimTestCase + { + /// + /// Test that a new HG agent (i.e. one without a user account) has their name cached in the UMM upon creation. + /// + [Test] + public void TestCachedUserNameForNewAgent() + { + TestHelpers.InMethod(); +// TestHelpers.EnableLogging(); + + HGUserManagementModule hgumm = new HGUserManagementModule(); + UUID userId = TestHelpers.ParseStem("11"); + string firstName = "Fred"; + string lastName = "Astaire"; + string homeUri = "example.com:8002"; + + IConfigSource config = new IniConfigSource(); + config.AddConfig("Modules"); + config.Configs["Modules"].Set("UserManagementModule", hgumm.Name); + + SceneHelpers sceneHelpers = new SceneHelpers(); + TestScene scene = sceneHelpers.SetupScene(); + SceneHelpers.SetupSceneModules(scene, config, hgumm); + + AgentCircuitData acd = SceneHelpers.GenerateAgentData(userId); + acd.firstname = firstName; + acd.lastname = lastName; + acd.ServiceURLs["HomeURI"] = "http://" + homeUri; + + SceneHelpers.AddScenePresence(scene, acd); + + string name = hgumm.GetUserName(userId); + Assert.That(name, Is.EqualTo(string.Format("{0}.{1} @{2}", firstName, lastName, homeUri))); + } + } +} \ No newline at end of file diff --git a/Tests/OpenSim.Region.CoreModules.Tests/OpenSim.Region.CoreModules.Tests.csproj b/Tests/OpenSim.Region.CoreModules.Tests/OpenSim.Region.CoreModules.Tests.csproj new file mode 100644 index 00000000000..b81ebdea1fc --- /dev/null +++ b/Tests/OpenSim.Region.CoreModules.Tests/OpenSim.Region.CoreModules.Tests.csproj @@ -0,0 +1,282 @@ + + + net6.0 + + + + ..\..\..\bin\Nini.dll + False + + + ..\..\..\bin\OpenMetaverse.dll + False + + + ..\..\..\bin\OpenMetaverse.StructuredData.dll + False + + + ..\..\..\bin\OpenMetaverseTypes.dll + False + + + False + + + ..\..\..\bin\XMLRPC.dll + False + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Tests/OpenSim.Region.CoreModules.Tests/Scripting/HttpRequest/Tests/ScriptsHttpRequestsTests.cs b/Tests/OpenSim.Region.CoreModules.Tests/Scripting/HttpRequest/Tests/ScriptsHttpRequestsTests.cs new file mode 100644 index 00000000000..7e223d70c5b --- /dev/null +++ b/Tests/OpenSim.Region.CoreModules.Tests/Scripting/HttpRequest/Tests/ScriptsHttpRequestsTests.cs @@ -0,0 +1,199 @@ +/* + * 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 System.IO; +using System.Net; +using System.Reflection; +using System.Runtime.Serialization; +using System.Text; +using System.Threading; +using log4net.Config; +using NUnit.Framework; +using OpenMetaverse; +using OpenMetaverse.Assets; +using OpenSim.Framework; +using OpenSim.Region.CoreModules.Scripting.HttpRequest; +using OpenSim.Region.Framework.Scenes; +using OpenSim.Tests.Common; + +namespace OpenSim.Region.CoreModules.Scripting.HttpRequest.Tests +{ + class TestWebRequestCreate : IWebRequestCreate + { + public TestWebRequest NextRequest { get; set; } + + public WebRequest Create(Uri uri) + { +// NextRequest.RequestUri = uri; + + return NextRequest; + +// return new TestWebRequest(new SerializationInfo(typeof(TestWebRequest), new FormatterConverter()), new StreamingContext()); + } + } + + class TestWebRequest : WebRequest + { + public override string ContentType { get; set; } + public override string Method { get; set; } + + public Func OnEndGetResponse { get; set; } + + public TestWebRequest() : base() + { +// Console.WriteLine("created"); + } + +// public TestWebRequest(SerializationInfo serializationInfo, StreamingContext streamingContext) +// : base(serializationInfo, streamingContext) +// { +// Console.WriteLine("created"); +// } + + public override IAsyncResult BeginGetResponse(AsyncCallback callback, object state) + { +// Console.WriteLine("bish"); + TestAsyncResult tasr = new TestAsyncResult(); + callback(tasr); + + return tasr; + } + + public override WebResponse EndGetResponse(IAsyncResult asyncResult) + { +// Console.WriteLine("bosh"); + return OnEndGetResponse(asyncResult); + } + } + + class TestHttpWebResponse : HttpWebResponse + { + public string Response { get; set; } + +#pragma warning disable 0618 + public TestHttpWebResponse(SerializationInfo serializationInfo, StreamingContext streamingContext) + : base(serializationInfo, streamingContext) {} +#pragma warning restore 0618 + + public override Stream GetResponseStream() + { + return new MemoryStream(Encoding.UTF8.GetBytes(Response)); + } + } + + class TestAsyncResult : IAsyncResult + { + WaitHandle m_wh = new ManualResetEvent(true); + + object IAsyncResult.AsyncState + { + get { + throw new System.NotImplementedException (); + } + } + + WaitHandle IAsyncResult.AsyncWaitHandle + { + get { return m_wh; } + } + + bool IAsyncResult.CompletedSynchronously + { + get { return false; } + } + + bool IAsyncResult.IsCompleted + { + get { return true; } + } + } + + /// + /// Test script http request code. + /// + /// + /// This class uses some very hacky workarounds in order to mock HttpWebResponse which are Mono dependent (though + /// alternative code can be written to make this work for Windows). However, the value of being able to + /// regression test this kind of code is very high. + /// + [TestFixture] + public class ScriptsHttpRequestsTests : OpenSimTestCase + { + /// + /// Test what happens when we get a 404 response from a call. + /// +// [Test] + public void Test404Response() + { + TestHelpers.InMethod(); + TestHelpers.EnableLogging(); + + if (!Util.IsPlatformMono) + Assert.Ignore("Ignoring test since can only currently run on Mono"); + + string rawResponse = "boom"; + + TestWebRequestCreate twrc = new TestWebRequestCreate(); + + TestWebRequest twr = new TestWebRequest(); + //twr.OnEndGetResponse += ar => new TestHttpWebResponse(null, new StreamingContext()); + twr.OnEndGetResponse += ar => + { + SerializationInfo si = new SerializationInfo(typeof(HttpWebResponse), new FormatterConverter()); + StreamingContext sc = new StreamingContext(); +// WebHeaderCollection headers = new WebHeaderCollection(); +// si.AddValue("m_HttpResponseHeaders", headers); + si.AddValue("uri", new Uri("test://arrg")); +// si.AddValue("m_Certificate", null); + si.AddValue("version", HttpVersion.Version11); + si.AddValue("statusCode", HttpStatusCode.NotFound); + si.AddValue("contentLength", 0); + si.AddValue("method", "GET"); + si.AddValue("statusDescription", "Not Found"); + si.AddValue("contentType", null); + si.AddValue("cookieCollection", new CookieCollection()); + + TestHttpWebResponse thwr = new TestHttpWebResponse(si, sc); + thwr.Response = rawResponse; + + throw new WebException("no message", null, WebExceptionStatus.ProtocolError, thwr); + }; + + twrc.NextRequest = twr; + + WebRequest.RegisterPrefix("test", twrc); + HttpRequestClass hr = new HttpRequestClass(); + hr.Url = "test://something"; + hr.SendRequest(); + + Assert.That(hr.Status, Is.EqualTo((int)HttpStatusCode.NotFound)); + Assert.That(hr.ResponseBody, Is.EqualTo(rawResponse)); + } + } +} \ No newline at end of file diff --git a/Tests/OpenSim.Region.CoreModules.Tests/Scripting/VectorRender/Tests/VectorRenderModuleTests.cs b/Tests/OpenSim.Region.CoreModules.Tests/Scripting/VectorRender/Tests/VectorRenderModuleTests.cs new file mode 100644 index 00000000000..726e808c17a --- /dev/null +++ b/Tests/OpenSim.Region.CoreModules.Tests/Scripting/VectorRender/Tests/VectorRenderModuleTests.cs @@ -0,0 +1,321 @@ +/* + * 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 System.IO; +using System.Reflection; +using System.Threading; +using log4net.Config; +using NUnit.Framework; +using OpenMetaverse; +using OpenMetaverse.Assets; +using OpenSim.Framework; +using OpenSim.Region.CoreModules.Scripting.DynamicTexture; +using OpenSim.Region.CoreModules.Scripting.VectorRender; +using OpenSim.Region.Framework.Scenes; +using OpenSim.Region.Framework.Scenes.Serialization; +using OpenSim.Tests.Common; + +namespace OpenSim.Region.CoreModules.Scripting.VectorRender.Tests +{ + [TestFixture] + public class VectorRenderModuleTests : OpenSimTestCase + { + Scene m_scene; + DynamicTextureModule m_dtm; + VectorRenderModule m_vrm; + + private void SetupScene(bool reuseTextures) + { + + TestsAssetCache cache = new TestsAssetCache(); + m_scene = new SceneHelpers(cache).SetupScene(); + + m_dtm = new DynamicTextureModule(); + m_dtm.ReuseTextures = reuseTextures; +// m_dtm.ReuseLowDataTextures = reuseTextures; + + m_vrm = new VectorRenderModule(); + + SceneHelpers.SetupSceneModules(m_scene, m_dtm, m_vrm); + } + + [Test] + public void TestDraw() + { + TestHelpers.InMethod(); + + SetupScene(false); + SceneObjectGroup so = SceneHelpers.AddSceneObject(m_scene); + UUID originalTextureID = so.RootPart.Shape.Textures.GetFace(0).TextureID; + + m_dtm.AddDynamicTextureData( + m_scene.RegionInfo.RegionID, + so.UUID, + m_vrm.GetContentType(), + "PenColour BLACK; MoveTo 40,220; FontSize 32; Text Hello World;", + ""); + + Assert.That(originalTextureID, Is.Not.EqualTo(so.RootPart.Shape.Textures.GetFace(0).TextureID)); + } + + [Test] + public void TestRepeatSameDraw() + { + TestHelpers.InMethod(); + + string dtText = "PenColour BLACK; MoveTo 40,220; FontSize 32; Text Hello World;"; + + SetupScene(false); + SceneObjectGroup so = SceneHelpers.AddSceneObject(m_scene); + + m_dtm.AddDynamicTextureData( + m_scene.RegionInfo.RegionID, + so.UUID, + m_vrm.GetContentType(), + dtText, + ""); + + UUID firstDynamicTextureID = so.RootPart.Shape.Textures.GetFace(0).TextureID; + + m_dtm.AddDynamicTextureData( + m_scene.RegionInfo.RegionID, + so.UUID, + m_vrm.GetContentType(), + dtText, + ""); + + Assert.That(firstDynamicTextureID, Is.Not.EqualTo(so.RootPart.Shape.Textures.GetFace(0).TextureID)); + } + + [Test] + public void TestRepeatSameDrawDifferentExtraParams() + { + TestHelpers.InMethod(); + + string dtText = "PenColour BLACK; MoveTo 40,220; FontSize 32; Text Hello World;"; + + SetupScene(false); + SceneObjectGroup so = SceneHelpers.AddSceneObject(m_scene); + + m_dtm.AddDynamicTextureData( + m_scene.RegionInfo.RegionID, + so.UUID, + m_vrm.GetContentType(), + dtText, + ""); + + UUID firstDynamicTextureID = so.RootPart.Shape.Textures.GetFace(0).TextureID; + + m_dtm.AddDynamicTextureData( + m_scene.RegionInfo.RegionID, + so.UUID, + m_vrm.GetContentType(), + dtText, + "alpha:250"); + + Assert.That(firstDynamicTextureID, Is.Not.EqualTo(so.RootPart.Shape.Textures.GetFace(0).TextureID)); + } + + [Test] + public void TestRepeatSameDrawContainingImage() + { + TestHelpers.InMethod(); + + string dtText + = "PenColour BLACK; MoveTo 40,220; FontSize 32; Text Hello World; Image http://0.0.0.0/shouldnotexist.png"; + + SetupScene(false); + SceneObjectGroup so = SceneHelpers.AddSceneObject(m_scene); + + m_dtm.AddDynamicTextureData( + m_scene.RegionInfo.RegionID, + so.UUID, + m_vrm.GetContentType(), + dtText, + ""); + + UUID firstDynamicTextureID = so.RootPart.Shape.Textures.GetFace(0).TextureID; + + m_dtm.AddDynamicTextureData( + m_scene.RegionInfo.RegionID, + so.UUID, + m_vrm.GetContentType(), + dtText, + ""); + + Assert.That(firstDynamicTextureID, Is.Not.EqualTo(so.RootPart.Shape.Textures.GetFace(0).TextureID)); + } + + [Test] + public void TestDrawReusingTexture() + { + TestHelpers.InMethod(); + + SetupScene(true); + SceneObjectGroup so = SceneHelpers.AddSceneObject(m_scene); + UUID originalTextureID = so.RootPart.Shape.Textures.GetFace(0).TextureID; + + m_dtm.AddDynamicTextureData( + m_scene.RegionInfo.RegionID, + so.UUID, + m_vrm.GetContentType(), + "PenColour BLACK; MoveTo 40,220; FontSize 32; Text Hello World;", + ""); + + Assert.That(originalTextureID, Is.Not.EqualTo(so.RootPart.Shape.Textures.GetFace(0).TextureID)); + } + + [Test] + public void TestRepeatSameDrawReusingTexture() + { + TestHelpers.InMethod(); +// TestHelpers.EnableLogging(); + + string dtText = "PenColour BLACK; MoveTo 40,220; FontSize 32; Text Hello World;"; + + SetupScene(true); + SceneObjectGroup so = SceneHelpers.AddSceneObject(m_scene); + + m_dtm.AddDynamicTextureData( + m_scene.RegionInfo.RegionID, + so.UUID, + m_vrm.GetContentType(), + dtText, + ""); + + UUID firstDynamicTextureID = so.RootPart.Shape.Textures.GetFace(0).TextureID; + + m_dtm.AddDynamicTextureData( + m_scene.RegionInfo.RegionID, + so.UUID, + m_vrm.GetContentType(), + dtText, + ""); + + Assert.That(firstDynamicTextureID, Is.EqualTo(so.RootPart.Shape.Textures.GetFace(0).TextureID)); + } + + /// + /// Test a low data dynamically generated texture such that it is treated as a low data texture that causes + /// problems for current viewers. + /// + /// + /// As we do not set DynamicTextureModule.ReuseLowDataTextures = true in this test, it should not reuse the + /// texture + /// + [Test] + public void TestRepeatSameDrawLowDataTexture() + { + TestHelpers.InMethod(); +// TestHelpers.EnableLogging(); + + string dtText = "PenColour BLACK; MoveTo 40,220; FontSize 32; Text Hello World;"; + + SetupScene(true); + SceneObjectGroup so = SceneHelpers.AddSceneObject(m_scene); + + m_dtm.AddDynamicTextureData( + m_scene.RegionInfo.RegionID, + so.UUID, + m_vrm.GetContentType(), + dtText, + "1024"); + + UUID firstDynamicTextureID = so.RootPart.Shape.Textures.GetFace(0).TextureID; + + m_dtm.AddDynamicTextureData( + m_scene.RegionInfo.RegionID, + so.UUID, + m_vrm.GetContentType(), + dtText, + "1024"); + + Assert.That(firstDynamicTextureID, Is.Not.EqualTo(so.RootPart.Shape.Textures.GetFace(0).TextureID)); + } + + [Test] + public void TestRepeatSameDrawDifferentExtraParamsReusingTexture() + { + TestHelpers.InMethod(); + + string dtText = "PenColour BLACK; MoveTo 40,220; FontSize 32; Text Hello World;"; + + SetupScene(true); + SceneObjectGroup so = SceneHelpers.AddSceneObject(m_scene); + + m_dtm.AddDynamicTextureData( + m_scene.RegionInfo.RegionID, + so.UUID, + m_vrm.GetContentType(), + dtText, + ""); + + UUID firstDynamicTextureID = so.RootPart.Shape.Textures.GetFace(0).TextureID; + + m_dtm.AddDynamicTextureData( + m_scene.RegionInfo.RegionID, + so.UUID, + m_vrm.GetContentType(), + dtText, + "alpha:250"); + + Assert.That(firstDynamicTextureID, Is.Not.EqualTo(so.RootPart.Shape.Textures.GetFace(0).TextureID)); + } + + [Test] + public void TestRepeatSameDrawContainingImageReusingTexture() + { + TestHelpers.InMethod(); + + string dtText + = "PenColour BLACK; MoveTo 40,220; FontSize 32; Text Hello World; Image http://0.0.0.0/shouldnotexist.png"; + + SetupScene(true); + SceneObjectGroup so = SceneHelpers.AddSceneObject(m_scene); + + m_dtm.AddDynamicTextureData( + m_scene.RegionInfo.RegionID, + so.UUID, + m_vrm.GetContentType(), + dtText, + ""); + + UUID firstDynamicTextureID = so.RootPart.Shape.Textures.GetFace(0).TextureID; + + m_dtm.AddDynamicTextureData( + m_scene.RegionInfo.RegionID, + so.UUID, + m_vrm.GetContentType(), + dtText, + ""); + + Assert.That(firstDynamicTextureID, Is.Not.EqualTo(so.RootPart.Shape.Textures.GetFace(0).TextureID)); + } + } +} \ No newline at end of file diff --git a/Tests/OpenSim.Region.CoreModules.Tests/ServiceConnectorsOut/Asset/Tests/AssetConnectorTests.cs b/Tests/OpenSim.Region.CoreModules.Tests/ServiceConnectorsOut/Asset/Tests/AssetConnectorTests.cs new file mode 100644 index 00000000000..4f75191cf29 --- /dev/null +++ b/Tests/OpenSim.Region.CoreModules.Tests/ServiceConnectorsOut/Asset/Tests/AssetConnectorTests.cs @@ -0,0 +1,174 @@ +/* + * 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 System.IO; +using System.Reflection; +using System.Threading; +using log4net.Config; +using Nini.Config; +using NUnit.Framework; +using OpenMetaverse; +using OpenSim.Framework; +using OpenSim.Region.Framework.Scenes; +using OpenSim.Region.CoreModules.ServiceConnectorsOut.Asset; +using OpenSim.Tests.Common; + +namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Asset.Tests +{ + [TestFixture] + public class AssetConnectorTests : OpenSimTestCase + { + [Test] + public void TestAddAsset() + { + TestHelpers.InMethod(); +// TestHelpers.EnableLogging(); + + IConfigSource config = new IniConfigSource(); + config.AddConfig("Modules"); + config.Configs["Modules"].Set("AssetServices", "LocalAssetServicesConnector"); + config.AddConfig("AssetService"); + config.Configs["AssetService"].Set("LocalServiceModule", "OpenSim.Services.AssetService.dll:AssetService"); + config.Configs["AssetService"].Set("StorageProvider", "OpenSim.Tests.Common.dll"); + + LocalAssetServicesConnector lasc = new LocalAssetServicesConnector(); + lasc.Initialise(config); + + AssetBase a1 = AssetHelpers.CreateNotecardAsset(); + lasc.Store(a1); + + AssetBase retreivedA1 = lasc.Get(a1.ID); + Assert.That(retreivedA1.ID, Is.EqualTo(a1.ID)); + Assert.That(retreivedA1.Metadata.ID, Is.EqualTo(a1.Metadata.ID)); + Assert.That(retreivedA1.Data.Length, Is.EqualTo(a1.Data.Length)); + + AssetMetadata retrievedA1Metadata = lasc.GetMetadata(a1.ID); + Assert.That(retrievedA1Metadata.ID, Is.EqualTo(a1.ID)); + + byte[] retrievedA1Data = lasc.GetData(a1.ID); + Assert.That(retrievedA1Data.Length, Is.EqualTo(a1.Data.Length)); + + // TODO: Add cache and check that this does receive a copy of the asset + } + + public void TestAddTemporaryAsset() + { + TestHelpers.InMethod(); +// TestHelpers.EnableLogging(); + + IConfigSource config = new IniConfigSource(); + config.AddConfig("Modules"); + config.Configs["Modules"].Set("AssetServices", "LocalAssetServicesConnector"); + config.AddConfig("AssetService"); + config.Configs["AssetService"].Set("LocalServiceModule", "OpenSim.Services.AssetService.dll:AssetService"); + config.Configs["AssetService"].Set("StorageProvider", "OpenSim.Tests.Common.dll"); + + LocalAssetServicesConnector lasc = new LocalAssetServicesConnector(); + lasc.Initialise(config); + + // If it is remote, it should be stored + AssetBase a2 = AssetHelpers.CreateNotecardAsset(); + a2.Local = false; + a2.Temporary = true; + + lasc.Store(a2); + + AssetBase retreivedA2 = lasc.Get(a2.ID); + Assert.That(retreivedA2.ID, Is.EqualTo(a2.ID)); + Assert.That(retreivedA2.Metadata.ID, Is.EqualTo(a2.Metadata.ID)); + Assert.That(retreivedA2.Data.Length, Is.EqualTo(a2.Data.Length)); + + AssetMetadata retrievedA2Metadata = lasc.GetMetadata(a2.ID); + Assert.That(retrievedA2Metadata.ID, Is.EqualTo(a2.ID)); + + byte[] retrievedA2Data = lasc.GetData(a2.ID); + Assert.That(retrievedA2Data.Length, Is.EqualTo(a2.Data.Length)); + + // TODO: Add cache and check that this does receive a copy of the asset + } + + [Test] + public void TestAddLocalAsset() + { + TestHelpers.InMethod(); +// TestHelpers.EnableLogging(); + + IConfigSource config = new IniConfigSource(); + config.AddConfig("Modules"); + config.Configs["Modules"].Set("AssetServices", "LocalAssetServicesConnector"); + config.AddConfig("AssetService"); + config.Configs["AssetService"].Set("LocalServiceModule", "OpenSim.Services.AssetService.dll:AssetService"); + config.Configs["AssetService"].Set("StorageProvider", "OpenSim.Tests.Common.dll"); + + LocalAssetServicesConnector lasc = new LocalAssetServicesConnector(); + lasc.Initialise(config); + + AssetBase a1 = AssetHelpers.CreateNotecardAsset(); + a1.Local = true; + + lasc.Store(a1); + + Assert.That(lasc.Get(a1.ID), Is.Null); + Assert.That(lasc.GetData(a1.ID), Is.Null); + Assert.That(lasc.GetMetadata(a1.ID), Is.Null); + + // TODO: Add cache and check that this does receive a copy of the asset + } + + [Test] + public void TestAddTemporaryLocalAsset() + { + TestHelpers.InMethod(); +// TestHelpers.EnableLogging(); + + IConfigSource config = new IniConfigSource(); + config.AddConfig("Modules"); + config.Configs["Modules"].Set("AssetServices", "LocalAssetServicesConnector"); + config.AddConfig("AssetService"); + config.Configs["AssetService"].Set("LocalServiceModule", "OpenSim.Services.AssetService.dll:AssetService"); + config.Configs["AssetService"].Set("StorageProvider", "OpenSim.Tests.Common.dll"); + + LocalAssetServicesConnector lasc = new LocalAssetServicesConnector(); + lasc.Initialise(config); + + // If it is local, it should not be stored + AssetBase a1 = AssetHelpers.CreateNotecardAsset(); + a1.Local = true; + a1.Temporary = true; + + lasc.Store(a1); + + Assert.That(lasc.Get(a1.ID), Is.Null); + Assert.That(lasc.GetData(a1.ID), Is.Null); + Assert.That(lasc.GetMetadata(a1.ID), Is.Null); + + // TODO: Add cache and check that this does receive a copy of the asset + } + } +} \ No newline at end of file diff --git a/Tests/OpenSim.Region.CoreModules.Tests/ServiceConnectorsOut/Grid/Tests/GridConnectorsTests.cs b/Tests/OpenSim.Region.CoreModules.Tests/ServiceConnectorsOut/Grid/Tests/GridConnectorsTests.cs new file mode 100644 index 00000000000..d76c98de008 --- /dev/null +++ b/Tests/OpenSim.Region.CoreModules.Tests/ServiceConnectorsOut/Grid/Tests/GridConnectorsTests.cs @@ -0,0 +1,201 @@ +/* + * 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 System.IO; +using System.Reflection; +using System.Threading; +using log4net.Config; +using Nini.Config; +using NUnit.Framework; +using OpenMetaverse; + +using OpenSim.Framework; +using OpenSim.Region.CoreModules.ServiceConnectorsOut.Grid; +using OpenSim.Region.Framework.Scenes; +using GridRegion = OpenSim.Services.Interfaces.GridRegion; +using OpenSim.Tests.Common; + +namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Grid.Tests +{ + [TestFixture] + public class GridConnectorsTests : OpenSimTestCase + { + RegionGridServicesConnector m_LocalConnector; + + [SetUp] + public override void SetUp() + { + base.SetUp(); + + IConfigSource config = new IniConfigSource(); + config.AddConfig("Modules"); + config.AddConfig("GridService"); + config.Configs["Modules"].Set("GridServices", "RegionGridServicesConnector"); + config.Configs["GridService"].Set("LocalServiceModule", "OpenSim.Services.GridService.dll:GridService"); + config.Configs["GridService"].Set("StorageProvider", "OpenSim.Data.Null.dll"); + config.Configs["GridService"].Set("Region_Test_Region_1", "DefaultRegion"); + config.Configs["GridService"].Set("Region_Test_Region_2", "FallbackRegion"); + config.Configs["GridService"].Set("Region_Test_Region_3", "FallbackRegion"); + config.Configs["GridService"].Set("Region_Other_Region_4", "FallbackRegion"); + + m_LocalConnector = new RegionGridServicesConnector(config); + } + + /// + /// Test region registration. + /// + [Test] + public void TestRegisterRegion() + { + TestHelpers.InMethod(); +// log4net.Config.XmlConfigurator.Configure(); + + // Create 4 regions + GridRegion r1 = new GridRegion(); + r1.RegionName = "Test Region 1"; + r1.RegionID = new UUID(1); + r1.RegionLocX = 1000 * (int)Constants.RegionSize; + r1.RegionLocY = 1000 * (int)Constants.RegionSize; + r1.ExternalHostName = "127.0.0.1"; + r1.HttpPort = 9001; + r1.InternalEndPoint = new System.Net.IPEndPoint(System.Net.IPAddress.Parse("0.0.0.0"), 0); + Scene s = new Scene(new RegionInfo()); + s.RegionInfo.RegionID = r1.RegionID; + m_LocalConnector.AddRegion(s); + + GridRegion r2 = new GridRegion(); + r2.RegionName = "Test Region 2"; + r2.RegionID = new UUID(2); + r2.RegionLocX = 1001 * (int)Constants.RegionSize; + r2.RegionLocY = 1000 * (int)Constants.RegionSize; + r2.ExternalHostName = "127.0.0.1"; + r2.HttpPort = 9002; + r2.InternalEndPoint = new System.Net.IPEndPoint(System.Net.IPAddress.Parse("0.0.0.0"), 0); + s = new Scene(new RegionInfo()); + s.RegionInfo.RegionID = r2.RegionID; + m_LocalConnector.AddRegion(s); + + GridRegion r3 = new GridRegion(); + r3.RegionName = "Test Region 3"; + r3.RegionID = new UUID(3); + r3.RegionLocX = 1005 * (int)Constants.RegionSize; + r3.RegionLocY = 1000 * (int)Constants.RegionSize; + r3.ExternalHostName = "127.0.0.1"; + r3.HttpPort = 9003; + r3.InternalEndPoint = new System.Net.IPEndPoint(System.Net.IPAddress.Parse("0.0.0.0"), 0); + s = new Scene(new RegionInfo()); + s.RegionInfo.RegionID = r3.RegionID; + m_LocalConnector.AddRegion(s); + + GridRegion r4 = new GridRegion(); + r4.RegionName = "Other Region 4"; + r4.RegionID = new UUID(4); + r4.RegionLocX = 1004 * (int)Constants.RegionSize; + r4.RegionLocY = 1002 * (int)Constants.RegionSize; + r4.ExternalHostName = "127.0.0.1"; + r4.HttpPort = 9004; + r4.InternalEndPoint = new System.Net.IPEndPoint(System.Net.IPAddress.Parse("0.0.0.0"), 0); + s = new Scene(new RegionInfo()); + s.RegionInfo.RegionID = r4.RegionID; + m_LocalConnector.AddRegion(s); + + m_LocalConnector.RegisterRegion(UUID.Zero, r1); + + GridRegion result = m_LocalConnector.GetRegionByName(UUID.Zero, "Test"); + Assert.IsNull(result, "Retrieved GetRegionByName \"Test\" is not null"); + + result = m_LocalConnector.GetRegionByName(UUID.Zero, "Test Region 1"); + Assert.IsNotNull(result, "Retrieved GetRegionByName is null"); + Assert.That(result.RegionName, Is.EqualTo("Test Region 1"), "Retrieved region's name does not match"); + + m_LocalConnector.RegisterRegion(UUID.Zero, r2); + m_LocalConnector.RegisterRegion(UUID.Zero, r3); + m_LocalConnector.RegisterRegion(UUID.Zero, r4); + + result = m_LocalConnector.GetRegionByUUID(UUID.Zero, new UUID(1)); + Assert.IsNotNull(result, "Retrieved GetRegionByUUID is null"); + Assert.That(result.RegionID, Is.EqualTo(new UUID(1)), "Retrieved region's UUID does not match"); + + result = m_LocalConnector.GetRegionByPosition(UUID.Zero, (int)Util.RegionToWorldLoc(1000), (int)Util.RegionToWorldLoc(1000)); + Assert.IsNotNull(result, "Retrieved GetRegionByPosition is null"); + Assert.That(result.RegionLocX, Is.EqualTo(1000 * (int)Constants.RegionSize), "Retrieved region's position does not match"); + + List results = m_LocalConnector.GetNeighbours(UUID.Zero, new UUID(1)); + Assert.IsNotNull(results, "Retrieved neighbours list is null"); + Assert.That(results.Count, Is.EqualTo(1), "Retrieved neighbour collection is greater than expected"); + Assert.That(results[0].RegionID, Is.EqualTo(new UUID(2)), "Retrieved region's UUID does not match"); + + results = m_LocalConnector.GetRegionsByName(UUID.Zero, "Test", 10); + Assert.IsNotNull(results, "Retrieved GetRegionsByName collection is null"); + Assert.That(results.Count, Is.EqualTo(3), "Retrieved neighbour collection is less than expected"); + + results = m_LocalConnector.GetRegionRange(UUID.Zero, 900 * (int)Constants.RegionSize, 1002 * (int)Constants.RegionSize, + 900 * (int)Constants.RegionSize, 1100 * (int)Constants.RegionSize); + Assert.IsNotNull(results, "Retrieved GetRegionRange collection is null"); + Assert.That(results.Count, Is.EqualTo(2), "Retrieved neighbour collection is not the number expected"); + + results = m_LocalConnector.GetDefaultRegions(UUID.Zero); + Assert.IsNotNull(results, "Retrieved GetDefaultRegions collection is null"); + Assert.That(results.Count, Is.EqualTo(1), "Retrieved default regions collection has not the expected size"); + Assert.That(results[0].RegionID, Is.EqualTo(new UUID(1)), "Retrieved default region's UUID does not match"); + + results = m_LocalConnector.GetFallbackRegions(UUID.Zero, r1.RegionLocX, r1.RegionLocY); + Assert.IsNotNull(results, "Retrieved GetFallbackRegions collection for region 1 is null"); + Assert.That(results.Count, Is.EqualTo(3), "Retrieved fallback regions collection for region 1 has not the expected size"); + Assert.That(results[0].RegionID, Is.EqualTo(new UUID(2)), "Retrieved fallback regions for default region are not in the expected order 2-4-3"); + Assert.That(results[1].RegionID, Is.EqualTo(new UUID(4)), "Retrieved fallback regions for default region are not in the expected order 2-4-3"); + Assert.That(results[2].RegionID, Is.EqualTo(new UUID(3)), "Retrieved fallback regions for default region are not in the expected order 2-4-3"); + + results = m_LocalConnector.GetFallbackRegions(UUID.Zero, r2.RegionLocX, r2.RegionLocY); + Assert.IsNotNull(results, "Retrieved GetFallbackRegions collection for region 2 is null"); + Assert.That(results.Count, Is.EqualTo(3), "Retrieved fallback regions collection for region 2 has not the expected size"); + Assert.That(results[0].RegionID, Is.EqualTo(new UUID(2)), "Retrieved fallback regions are not in the expected order 2-4-3"); + Assert.That(results[1].RegionID, Is.EqualTo(new UUID(4)), "Retrieved fallback regions are not in the expected order 2-4-3"); + Assert.That(results[2].RegionID, Is.EqualTo(new UUID(3)), "Retrieved fallback regions are not in the expected order 2-4-3"); + + results = m_LocalConnector.GetFallbackRegions(UUID.Zero, r3.RegionLocX, r3.RegionLocY); + Assert.IsNotNull(results, "Retrieved GetFallbackRegions collection for region 3 is null"); + Assert.That(results.Count, Is.EqualTo(3), "Retrieved fallback regions collection for region 3 has not the expected size"); + Assert.That(results[0].RegionID, Is.EqualTo(new UUID(3)), "Retrieved fallback regions are not in the expected order 3-4-2"); + Assert.That(results[1].RegionID, Is.EqualTo(new UUID(4)), "Retrieved fallback regions are not in the expected order 3-4-2"); + Assert.That(results[2].RegionID, Is.EqualTo(new UUID(2)), "Retrieved fallback regions are not in the expected order 3-4-2"); + + results = m_LocalConnector.GetFallbackRegions(UUID.Zero, r4.RegionLocX, r4.RegionLocY); + Assert.IsNotNull(results, "Retrieved GetFallbackRegions collection for region 4 is null"); + Assert.That(results.Count, Is.EqualTo(3), "Retrieved fallback regions collection for region 4 has not the expected size"); + Assert.That(results[0].RegionID, Is.EqualTo(new UUID(4)), "Retrieved fallback regions are not in the expected order 4-3-2"); + Assert.That(results[1].RegionID, Is.EqualTo(new UUID(3)), "Retrieved fallback regions are not in the expected order 4-3-2"); + Assert.That(results[2].RegionID, Is.EqualTo(new UUID(2)), "Retrieved fallback regions are not in the expected order 4-3-2"); + + results = m_LocalConnector.GetHyperlinks(UUID.Zero); + Assert.IsNotNull(results, "Retrieved GetHyperlinks list is null"); + Assert.That(results.Count, Is.EqualTo(0), "Retrieved linked regions collection is not the number expected"); + } + } +} diff --git a/Tests/OpenSim.Region.CoreModules.Tests/ServiceConnectorsOut/Presence/Tests/PresenceConnectorsTests.cs b/Tests/OpenSim.Region.CoreModules.Tests/ServiceConnectorsOut/Presence/Tests/PresenceConnectorsTests.cs new file mode 100644 index 00000000000..7838d123e8a --- /dev/null +++ b/Tests/OpenSim.Region.CoreModules.Tests/ServiceConnectorsOut/Presence/Tests/PresenceConnectorsTests.cs @@ -0,0 +1,116 @@ +/* + * 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 System.IO; +using System.Reflection; +using System.Threading; +using log4net.Config; +using NUnit.Framework; +using OpenMetaverse; +using OpenSim.Framework; +using Nini.Config; +using OpenSim.Region.CoreModules.ServiceConnectorsOut.Presence; +using OpenSim.Region.Framework.Scenes; +using PresenceInfo = OpenSim.Services.Interfaces.PresenceInfo; +using OpenSim.Tests.Common; + +namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Presence.Tests +{ + [TestFixture] + public class PresenceConnectorsTests : OpenSimTestCase + { + LocalPresenceServicesConnector m_LocalConnector; + + public override void SetUp() + { + base.SetUp(); + + IConfigSource config = new IniConfigSource(); + config.AddConfig("Modules"); + config.AddConfig("PresenceService"); + config.Configs["Modules"].Set("PresenceServices", "LocalPresenceServicesConnector"); + config.Configs["PresenceService"].Set("LocalServiceModule", "OpenSim.Services.PresenceService.dll:PresenceService"); + config.Configs["PresenceService"].Set("StorageProvider", "OpenSim.Data.Null.dll"); + + m_LocalConnector = new LocalPresenceServicesConnector(); + m_LocalConnector.Initialise(config); + + // Let's stick in a test presence + m_LocalConnector.m_PresenceService.LoginAgent(UUID.Zero.ToString(), UUID.Zero, UUID.Zero); + } + + /// + /// Test OpenSim Presence. + /// + [Test] + public void TestPresenceV0_1() + { + SetUp(); + + // Let's stick in a test presence + /* + PresenceData p = new PresenceData(); + p.SessionID = UUID.Zero; + p.UserID = UUID.Zero.ToString(); + p.Data = new Dictionary(); + p.Data["Online"] = true.ToString(); + m_presenceData.Add(UUID.Zero, p); + */ + + string user1 = UUID.Zero.ToString(); + UUID session1 = UUID.Zero; + + // this is not implemented by this connector + //m_LocalConnector.LoginAgent(user1, session1, UUID.Zero); + PresenceInfo result = m_LocalConnector.GetAgent(session1); + Assert.IsNotNull(result, "Retrieved GetAgent is null"); + Assert.That(result.UserID, Is.EqualTo(user1), "Retrieved userID does not match"); + + UUID region1 = UUID.Random(); + bool r = m_LocalConnector.ReportAgent(session1, region1); + Assert.IsTrue(r, "First ReportAgent returned false"); + result = m_LocalConnector.GetAgent(session1); + Assert.That(result.RegionID, Is.EqualTo(region1), "Agent is not in the right region (region1)"); + + UUID region2 = UUID.Random(); + r = m_LocalConnector.ReportAgent(session1, region2); + Assert.IsTrue(r, "Second ReportAgent returned false"); + result = m_LocalConnector.GetAgent(session1); + Assert.That(result.RegionID, Is.EqualTo(region2), "Agent is not in the right region (region2)"); + + r = m_LocalConnector.LogoutAgent(session1); + Assert.IsTrue(r, "LogoutAgent returned false"); + result = m_LocalConnector.GetAgent(session1); + Assert.IsNull(result, "Agent session is still stored after logout"); + + r = m_LocalConnector.ReportAgent(session1, region1); + Assert.IsFalse(r, "ReportAgent of non-logged in user returned true"); + } + } +} diff --git a/Tests/OpenSim.Region.CoreModules.Tests/World/Archiver/Tests/ArchiverTests.cs b/Tests/OpenSim.Region.CoreModules.Tests/World/Archiver/Tests/ArchiverTests.cs new file mode 100644 index 00000000000..35427dc679f --- /dev/null +++ b/Tests/OpenSim.Region.CoreModules.Tests/World/Archiver/Tests/ArchiverTests.cs @@ -0,0 +1,1056 @@ +/* + * 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 System.IO; +using System.Reflection; +using System.Threading; +using log4net.Config; +using Nini.Config; +using NUnit.Framework; +using OpenMetaverse; +using OpenMetaverse.Assets; +using OpenSim.Framework; +using OpenSim.Framework.Serialization; +using OpenSim.Framework.Serialization.External; +using OpenSim.Region.CoreModules.World.Land; +using OpenSim.Region.CoreModules.World.Serialiser; +using OpenSim.Region.CoreModules.World.Terrain; +using OpenSim.Region.Framework.Scenes; +using OpenSim.Region.Framework.Scenes.Serialization; +using OpenSim.Region.OptionalModules.Avatar.XmlRpcGroups; +using OpenSim.Tests.Common; +using ArchiveConstants = OpenSim.Framework.Serialization.ArchiveConstants; +using TarArchiveReader = OpenSim.Framework.Serialization.TarArchiveReader; +using TarArchiveWriter = OpenSim.Framework.Serialization.TarArchiveWriter; +using RegionSettings = OpenSim.Framework.RegionSettings; +using OpenSim.Region.Framework.Interfaces; + +namespace OpenSim.Region.CoreModules.World.Archiver.Tests +{ + [TestFixture] + public class ArchiverTests : OpenSimTestCase + { + private Guid m_lastRequestId; + private string m_lastErrorMessage; + + protected SceneHelpers m_sceneHelpers; + protected TestScene m_scene; + protected ArchiverModule m_archiverModule; + protected SerialiserModule m_serialiserModule; + + protected TaskInventoryItem m_soundItem; + + private AutoResetEvent m_oarEvent = new AutoResetEvent(false); + + [SetUp] + public override void SetUp() + { + base.SetUp(); + + m_archiverModule = new ArchiverModule(); + m_serialiserModule = new SerialiserModule(); + TerrainModule terrainModule = new TerrainModule(); + + m_sceneHelpers = new SceneHelpers(); + m_scene = m_sceneHelpers.SetupScene(); + SceneHelpers.SetupSceneModules(m_scene, m_archiverModule, m_serialiserModule, terrainModule); + } + + private void LoadCompleted(Guid requestId, List loadedScenes, string errorMessage) + { + lock (this) + { + m_lastRequestId = requestId; + m_lastErrorMessage = errorMessage; + Console.WriteLine("About to pulse ArchiverTests on LoadCompleted"); + m_oarEvent.Set(); + } + } + + private void SaveCompleted(Guid requestId, string errorMessage) + { + lock (this) + { + m_lastRequestId = requestId; + m_lastErrorMessage = errorMessage; + Console.WriteLine("About to pulse ArchiverTests on SaveCompleted"); + m_oarEvent.Set(); + } + } + + protected SceneObjectPart CreateSceneObjectPart1() + { + string partName = "My Little Pony"; + UUID ownerId = UUID.Parse("00000000-0000-0000-0000-000000000015"); + PrimitiveBaseShape shape = PrimitiveBaseShape.CreateSphere(); + Vector3 groupPosition = new Vector3(10, 20, 30); + Quaternion rotationOffset = new Quaternion(20, 30, 40, 50); + rotationOffset.Normalize(); +// Vector3 offsetPosition = new Vector3(5, 10, 15); + + return new SceneObjectPart(ownerId, shape, groupPosition, rotationOffset, Vector3.Zero) { Name = partName }; + } + + protected SceneObjectPart CreateSceneObjectPart2() + { + string partName = "Action Man"; + UUID ownerId = UUID.Parse("00000000-0000-0000-0000-000000000016"); + PrimitiveBaseShape shape = PrimitiveBaseShape.CreateCylinder(); + Vector3 groupPosition = new Vector3(90, 80, 70); + Quaternion rotationOffset = new Quaternion(60, 70, 80, 90); + rotationOffset.Normalize(); + Vector3 offsetPosition = new Vector3(20, 25, 30); + + return new SceneObjectPart(ownerId, shape, groupPosition, rotationOffset, offsetPosition) { Name = partName }; + } + + private void CreateTestObjects(Scene scene, out SceneObjectGroup sog1, out SceneObjectGroup sog2, out UUID ncAssetUuid) + { + SceneObjectPart part1 = CreateSceneObjectPart1(); + sog1 = new SceneObjectGroup(part1); + scene.AddNewSceneObject(sog1, false); + + AssetNotecard nc = new AssetNotecard(); + nc.BodyText = "Hello World!"; + nc.Encode(); + ncAssetUuid = UUID.Random(); + UUID ncItemUuid = UUID.Random(); + AssetBase ncAsset + = AssetHelpers.CreateAsset(ncAssetUuid, AssetType.Notecard, nc.AssetData, UUID.Zero); + m_scene.AssetService.Store(ncAsset); + + TaskInventoryItem ncItem + = new TaskInventoryItem { Name = "ncItem", AssetID = ncAssetUuid, ItemID = ncItemUuid }; + SceneObjectPart part2 = CreateSceneObjectPart2(); + sog2 = new SceneObjectGroup(part2); + part2.Inventory.AddInventoryItem(ncItem, true); + + scene.AddNewSceneObject(sog2, false); + } + + private static void CreateSoundAsset(TarArchiveWriter tar, Assembly assembly, string soundDataResourceName, out byte[] soundData, out UUID soundUuid) + { + using (Stream resource = assembly.GetManifestResourceStream(soundDataResourceName)) + { + using (BinaryReader br = new BinaryReader(resource)) + { + // FIXME: Use the inspector instead + soundData = br.ReadBytes(99999999); + soundUuid = UUID.Parse("00000000-0000-0000-0000-000000000001"); + string soundAssetFileName + = ArchiveConstants.ASSETS_PATH + soundUuid + + ArchiveConstants.ASSET_TYPE_TO_EXTENSION[(sbyte)AssetType.SoundWAV]; + tar.WriteFile(soundAssetFileName, soundData); + + /* + AssetBase soundAsset = AssetHelpers.CreateAsset(soundUuid, soundData); + scene.AssetService.Store(soundAsset); + asset1FileName = ArchiveConstants.ASSETS_PATH + soundUuid + ".wav"; + */ + } + } + } + + /// + /// Test saving an OpenSim Region Archive. + /// + [Test] + public void TestSaveOar() + { + TestHelpers.InMethod(); +// log4net.Config.XmlConfigurator.Configure(); + + SceneObjectGroup sog1; + SceneObjectGroup sog2; + UUID ncAssetUuid; + CreateTestObjects(m_scene, out sog1, out sog2, out ncAssetUuid); + + MemoryStream archiveWriteStream = new MemoryStream(); + m_scene.EventManager.OnOarFileSaved += SaveCompleted; + + Guid requestId = new Guid("00000000-0000-0000-0000-808080808080"); + + m_oarEvent.Reset(); + m_archiverModule.ArchiveRegion(archiveWriteStream, requestId); + //AssetServerBase assetServer = (AssetServerBase)scene.CommsManager.AssetCache.AssetServer; + //while (assetServer.HasWaitingRequests()) + // assetServer.ProcessNextRequest(); + + m_oarEvent.WaitOne(60000); + + Assert.That(m_lastRequestId, Is.EqualTo(requestId)); + + byte[] archive = archiveWriteStream.ToArray(); + MemoryStream archiveReadStream = new MemoryStream(archive); + TarArchiveReader tar = new TarArchiveReader(archiveReadStream); + + bool gotNcAssetFile = false; + + string expectedNcAssetFileName = string.Format("{0}_{1}", ncAssetUuid, "notecard.txt"); + + List foundPaths = new List(); + List expectedPaths = new List(); + expectedPaths.Add(ArchiveHelpers.CreateObjectPath(sog1)); + expectedPaths.Add(ArchiveHelpers.CreateObjectPath(sog2)); + + string filePath; + TarArchiveReader.TarEntryType tarEntryType; + + byte[] data = tar.ReadEntry(out filePath, out tarEntryType); + Assert.That(filePath, Is.EqualTo(ArchiveConstants.CONTROL_FILE_PATH)); + + Dictionary archiveOptions = new Dictionary(); + ArchiveReadRequest arr = new ArchiveReadRequest(m_scene, (Stream)null, Guid.Empty, archiveOptions); + arr.LoadControlFile(filePath, data, new DearchiveScenesInfo()); + + Assert.That(arr.ControlFileLoaded, Is.True); + + while (tar.ReadEntry(out filePath, out tarEntryType) != null) + { + if (filePath.StartsWith(ArchiveConstants.ASSETS_PATH)) + { + string fileName = filePath.Remove(0, ArchiveConstants.ASSETS_PATH.Length); + + Assert.That(fileName, Is.EqualTo(expectedNcAssetFileName)); + gotNcAssetFile = true; + } + else if (filePath.StartsWith(ArchiveConstants.OBJECTS_PATH)) + { + foundPaths.Add(filePath); + } + } + + Assert.That(gotNcAssetFile, Is.True, "No notecard asset file in archive"); + Assert.That(foundPaths, Is.EquivalentTo(expectedPaths)); + + // TODO: Test presence of more files and contents of files. + } + + /// + /// Test saving an OpenSim Region Archive with the no assets option + /// + [Test] + public void TestSaveOarNoAssets() + { + TestHelpers.InMethod(); +// log4net.Config.XmlConfigurator.Configure(); + + SceneObjectPart part1 = CreateSceneObjectPart1(); + SceneObjectGroup sog1 = new SceneObjectGroup(part1); + m_scene.AddNewSceneObject(sog1, false); + + SceneObjectPart part2 = CreateSceneObjectPart2(); + + AssetNotecard nc = new AssetNotecard(); + nc.BodyText = "Hello World!"; + nc.Encode(); + UUID ncAssetUuid = new UUID("00000000-0000-0000-1000-000000000000"); + UUID ncItemUuid = new UUID("00000000-0000-0000-1100-000000000000"); + AssetBase ncAsset + = AssetHelpers.CreateAsset(ncAssetUuid, AssetType.Notecard, nc.AssetData, UUID.Zero); + m_scene.AssetService.Store(ncAsset); + SceneObjectGroup sog2 = new SceneObjectGroup(part2); + TaskInventoryItem ncItem + = new TaskInventoryItem { Name = "ncItem", AssetID = ncAssetUuid, ItemID = ncItemUuid }; + part2.Inventory.AddInventoryItem(ncItem, true); + + m_scene.AddNewSceneObject(sog2, false); + + MemoryStream archiveWriteStream = new MemoryStream(); + + Guid requestId = new Guid("00000000-0000-0000-0000-808080808080"); + + Dictionary options = new Dictionary(); + options.Add("noassets", true); + + m_archiverModule.ArchiveRegion(archiveWriteStream, requestId, options); + + // Don't wait for completion - with --noassets save oar happens synchronously +// Monitor.Wait(this, 60000); + + Assert.That(m_lastRequestId, Is.EqualTo(requestId)); + + byte[] archive = archiveWriteStream.ToArray(); + MemoryStream archiveReadStream = new MemoryStream(archive); + TarArchiveReader tar = new TarArchiveReader(archiveReadStream); + + List foundPaths = new List(); + List expectedPaths = new List(); + expectedPaths.Add(ArchiveHelpers.CreateObjectPath(sog1)); + expectedPaths.Add(ArchiveHelpers.CreateObjectPath(sog2)); + + string filePath; + TarArchiveReader.TarEntryType tarEntryType; + + byte[] data = tar.ReadEntry(out filePath, out tarEntryType); + Assert.That(filePath, Is.EqualTo(ArchiveConstants.CONTROL_FILE_PATH)); + + Dictionary archiveOptions = new Dictionary(); + ArchiveReadRequest arr = new ArchiveReadRequest(m_scene, (Stream)null, Guid.Empty, archiveOptions); + arr.LoadControlFile(filePath, data, new DearchiveScenesInfo()); + + Assert.That(arr.ControlFileLoaded, Is.True); + + while (tar.ReadEntry(out filePath, out tarEntryType) != null) + { + if (filePath.StartsWith(ArchiveConstants.ASSETS_PATH)) + { + Assert.Fail("Asset was found in saved oar of TestSaveOarNoAssets()"); + } + else if (filePath.StartsWith(ArchiveConstants.OBJECTS_PATH)) + { + foundPaths.Add(filePath); + } + } + + Assert.That(foundPaths, Is.EquivalentTo(expectedPaths)); + + // TODO: Test presence of more files and contents of files. + } + + /// + /// Test loading an OpenSim Region Archive. + /// + [Test] + public void TestLoadOar() + { + TestHelpers.InMethod(); +// log4net.Config.XmlConfigurator.Configure(); + + MemoryStream archiveWriteStream = new MemoryStream(); + TarArchiveWriter tar = new TarArchiveWriter(archiveWriteStream); + + // Put in a random blank directory to check that this doesn't upset the load process + tar.WriteDir("ignoreme"); + + // Also check that direct entries which will also have a file entry containing that directory doesn't + // upset load + tar.WriteDir(ArchiveConstants.TERRAINS_PATH); + + tar.WriteFile( + ArchiveConstants.CONTROL_FILE_PATH, + new ArchiveWriteRequest(m_scene, (Stream)null, Guid.Empty).CreateControlFile(new ArchiveScenesGroup())); + SceneObjectPart part1 = CreateSceneObjectPart1(); + + part1.SitTargetOrientation = new Quaternion(0.2f, 0.3f, 0.4f, 0.5f); + part1.SitTargetPosition = new Vector3(1, 2, 3); + + SceneObjectGroup object1 = new SceneObjectGroup(part1); + + // Let's put some inventory items into our object + string soundItemName = "sound-item1"; + UUID soundItemUuid = UUID.Parse("00000000-0000-0000-0000-000000000002"); + Type type = GetType(); + Assembly assembly = type.Assembly; + string soundDataResourceName = null; + string[] names = assembly.GetManifestResourceNames(); + foreach (string name in names) + { + if (name.EndsWith(".Resources.test-sound.wav")) + soundDataResourceName = name; + } + Assert.That(soundDataResourceName, Is.Not.Null); + + byte[] soundData; + UUID soundUuid; + CreateSoundAsset(tar, assembly, soundDataResourceName, out soundData, out soundUuid); + + TaskInventoryItem item1 + = new TaskInventoryItem { AssetID = soundUuid, ItemID = soundItemUuid, Name = soundItemName }; + part1.Inventory.AddInventoryItem(item1, true); + m_scene.AddNewSceneObject(object1, false); + + string object1FileName = string.Format( + "{0}_{1:000}-{2:000}-{3:000}__{4}.xml", + part1.Name, + Math.Round(part1.GroupPosition.X), Math.Round(part1.GroupPosition.Y), Math.Round(part1.GroupPosition.Z), + part1.UUID); + tar.WriteFile(ArchiveConstants.OBJECTS_PATH + object1FileName, SceneObjectSerializer.ToXml2Format(object1)); + + tar.Close(); + + MemoryStream archiveReadStream = new MemoryStream(archiveWriteStream.ToArray()); + + m_scene.EventManager.OnOarFileLoaded += LoadCompleted; + m_oarEvent.Reset(); + m_archiverModule.DearchiveRegion(archiveReadStream); + + m_oarEvent.WaitOne(60000); + + Assert.That(m_lastErrorMessage, Is.Null); + + TestLoadedRegion(part1, soundItemName, soundData); + } + + /// + /// Test loading an OpenSim Region Archive where the scene object parts are not ordered by link number (e.g. + /// 2 can come after 3). + /// + [Test] + public void TestLoadOarUnorderedParts() + { + TestHelpers.InMethod(); + + UUID ownerId = TestHelpers.ParseTail(0xaaaa); + + MemoryStream archiveWriteStream = new MemoryStream(); + TarArchiveWriter tar = new TarArchiveWriter(archiveWriteStream); + + tar.WriteFile( + ArchiveConstants.CONTROL_FILE_PATH, + new ArchiveWriteRequest(m_scene, (Stream)null, Guid.Empty).CreateControlFile(new ArchiveScenesGroup())); + + SceneObjectGroup sog1 = SceneHelpers.CreateSceneObject(1, ownerId, "obj1-", 0x11); + SceneObjectPart sop2 + = SceneHelpers.CreateSceneObjectPart("obj1-Part2", TestHelpers.ParseTail(0x12), ownerId); + SceneObjectPart sop3 + = SceneHelpers.CreateSceneObjectPart("obj1-Part3", TestHelpers.ParseTail(0x13), ownerId); + + // Add the parts so they will be written out in reverse order to the oar + sog1.AddPart(sop3); + sop3.LinkNum = 3; + sog1.AddPart(sop2); + sop2.LinkNum = 2; + + tar.WriteFile( + ArchiveConstants.CreateOarObjectPath(sog1.Name, sog1.UUID, sog1.AbsolutePosition), + SceneObjectSerializer.ToXml2Format(sog1)); + + tar.Close(); + + MemoryStream archiveReadStream = new MemoryStream(archiveWriteStream.ToArray()); + + m_scene.EventManager.OnOarFileLoaded += LoadCompleted; + m_oarEvent.Reset(); + m_archiverModule.DearchiveRegion(archiveReadStream); + + m_oarEvent.WaitOne(60000); + + Assert.That(m_lastErrorMessage, Is.Null); + + SceneObjectPart part2 = m_scene.GetSceneObjectPart("obj1-Part2"); + Assert.That(part2.LinkNum, Is.EqualTo(2)); + + SceneObjectPart part3 = m_scene.GetSceneObjectPart("obj1-Part3"); + Assert.That(part3.LinkNum, Is.EqualTo(3)); + } + + /// + /// Test loading an OpenSim Region Archive saved with the --publish option. + /// + [Test] + public void TestLoadPublishedOar() + { + TestHelpers.InMethod(); +// log4net.Config.XmlConfigurator.Configure(); + + SceneObjectPart part1 = CreateSceneObjectPart1(); + SceneObjectGroup sog1 = new SceneObjectGroup(part1); + m_scene.AddNewSceneObject(sog1, false); + + SceneObjectPart part2 = CreateSceneObjectPart2(); + + AssetNotecard nc = new AssetNotecard(); + nc.BodyText = "Hello World!"; + nc.Encode(); + UUID ncAssetUuid = new UUID("00000000-0000-0000-1000-000000000000"); + UUID ncItemUuid = new UUID("00000000-0000-0000-1100-000000000000"); + AssetBase ncAsset + = AssetHelpers.CreateAsset(ncAssetUuid, AssetType.Notecard, nc.AssetData, UUID.Zero); + m_scene.AssetService.Store(ncAsset); + SceneObjectGroup sog2 = new SceneObjectGroup(part2); + TaskInventoryItem ncItem + = new TaskInventoryItem { Name = "ncItem", AssetID = ncAssetUuid, ItemID = ncItemUuid }; + part2.Inventory.AddInventoryItem(ncItem, true); + + m_scene.AddNewSceneObject(sog2, false); + + MemoryStream archiveWriteStream = new MemoryStream(); + m_scene.EventManager.OnOarFileSaved += SaveCompleted; + + Guid requestId = new Guid("00000000-0000-0000-0000-808080808080"); + + m_oarEvent.Reset(); + m_archiverModule.ArchiveRegion( + archiveWriteStream, requestId, new Dictionary() { { "wipe-owners", Boolean.TrueString } }); + + m_oarEvent.WaitOne(60000); + + Assert.That(m_lastRequestId, Is.EqualTo(requestId)); + + byte[] archive = archiveWriteStream.ToArray(); + MemoryStream archiveReadStream = new MemoryStream(archive); + + { + UUID estateOwner = TestHelpers.ParseTail(0x4747); + UUID objectOwner = TestHelpers.ParseTail(0x15); + + // Reload to new scene + ArchiverModule archiverModule = new ArchiverModule(); + SerialiserModule serialiserModule = new SerialiserModule(); + TerrainModule terrainModule = new TerrainModule(); + + SceneHelpers m_sceneHelpers2 = new SceneHelpers(); + TestScene scene2 = m_sceneHelpers2.SetupScene(); + SceneHelpers.SetupSceneModules(scene2, archiverModule, serialiserModule, terrainModule); + + // Make sure there's a valid owner for the owner we saved (this should have been wiped if the code is + // behaving correctly + UserAccountHelpers.CreateUserWithInventory(scene2, objectOwner); + + scene2.RegionInfo.EstateSettings.EstateOwner = estateOwner; + + scene2.EventManager.OnOarFileLoaded += LoadCompleted; + m_oarEvent.Reset(); + archiverModule.DearchiveRegion(archiveReadStream); + + m_oarEvent.WaitOne(60000); + + Assert.That(m_lastErrorMessage, Is.Null); + + SceneObjectGroup loadedSog = scene2.GetSceneObjectGroup(part1.Name); + Assert.That(loadedSog.OwnerID, Is.EqualTo(estateOwner)); + Assert.That(loadedSog.LastOwnerID, Is.EqualTo(estateOwner)); + } + } + + /// + /// Test OAR loading where the land parcel is group deeded. + /// + /// + /// In this situation, the owner ID is set to the group ID. + /// + [Test] + public void TestLoadOarDeededLand() + { + TestHelpers.InMethod(); +// TestHelpers.EnableLogging(); + + UUID landID = TestHelpers.ParseTail(0x10); + + MockGroupsServicesConnector groupsService = new MockGroupsServicesConnector(); + + IConfigSource configSource = new IniConfigSource(); + IConfig config = configSource.AddConfig("Groups"); + config.Set("Enabled", true); + config.Set("Module", "GroupsModule"); + config.Set("DebugEnabled", true); + SceneHelpers.SetupSceneModules( + m_scene, configSource, new object[] { new GroupsModule(), groupsService, new LandManagementModule() }); + + // Create group in scene for loading + // FIXME: For now we'll put up with the issue that we'll get a group ID that varies across tests. + UUID groupID + = groupsService.CreateGroup(UUID.Zero, "group1", "", true, UUID.Zero, 3, true, true, true, UUID.Zero); + + // Construct OAR + MemoryStream oarStream = new MemoryStream(); + TarArchiveWriter tar = new TarArchiveWriter(oarStream); + + tar.WriteDir(ArchiveConstants.LANDDATA_PATH); + tar.WriteFile( + ArchiveConstants.CONTROL_FILE_PATH, + new ArchiveWriteRequest(m_scene, (Stream)null, Guid.Empty).CreateControlFile(new ArchiveScenesGroup())); + + LandObject lo = new LandObject(groupID, true, m_scene); + lo.SetLandBitmap(lo.BasicFullRegionLandBitmap()); + LandData ld = lo.LandData; + ld.GlobalID = landID; + + string ldPath = ArchiveConstants.CreateOarLandDataPath(ld); + Dictionary options = new Dictionary(); + tar.WriteFile(ldPath, LandDataSerializer.Serialize(ld, options)); + tar.Close(); + + oarStream = new MemoryStream(oarStream.ToArray()); + + // Load OAR + m_scene.EventManager.OnOarFileLoaded += LoadCompleted; + m_oarEvent.Reset(); + m_archiverModule.DearchiveRegion(oarStream); + + m_oarEvent.WaitOne(60000); + + ILandObject rLo = m_scene.LandChannel.GetLandObject(16, 16); + LandData rLd = rLo.LandData; + + Assert.That(rLd.GlobalID, Is.EqualTo(landID)); + Assert.That(rLd.OwnerID, Is.EqualTo(groupID)); + Assert.That(rLd.GroupID, Is.EqualTo(groupID)); + Assert.That(rLd.IsGroupOwned, Is.EqualTo(true)); + } + + /// + /// Test loading the region settings of an OpenSim Region Archive. + /// + [Test] + public void TestLoadOarRegionSettings() + { + TestHelpers.InMethod(); + //log4net.Config.XmlConfigurator.Configure(); + + MemoryStream archiveWriteStream = new MemoryStream(); + TarArchiveWriter tar = new TarArchiveWriter(archiveWriteStream); + + tar.WriteDir(ArchiveConstants.TERRAINS_PATH); + tar.WriteFile( + ArchiveConstants.CONTROL_FILE_PATH, + new ArchiveWriteRequest(m_scene, (Stream)null, Guid.Empty).CreateControlFile(new ArchiveScenesGroup())); + + RegionSettings rs = new RegionSettings(); + rs.AgentLimit = 17; + rs.AllowDamage = true; + rs.AllowLandJoinDivide = true; + rs.AllowLandResell = true; + rs.BlockFly = true; + rs.BlockShowInSearch = true; + rs.BlockTerraform = true; + rs.DisableCollisions = true; + rs.DisablePhysics = true; + rs.DisableScripts = true; + rs.Elevation1NW = 15.9; + rs.Elevation1NE = 45.3; + rs.Elevation1SE = 49; + rs.Elevation1SW = 1.9; + rs.Elevation2NW = 4.5; + rs.Elevation2NE = 19.2; + rs.Elevation2SE = 9.2; + rs.Elevation2SW = 2.1; + rs.FixedSun = true; + rs.SunPosition = 12.0; + rs.ObjectBonus = 1.4; + rs.RestrictPushing = true; + rs.TerrainLowerLimit = -17.9; + rs.TerrainRaiseLimit = 17.9; + rs.TerrainTexture1 = UUID.Parse("00000000-0000-0000-0000-000000000020"); + rs.TerrainTexture2 = UUID.Parse("00000000-0000-0000-0000-000000000040"); + rs.TerrainTexture3 = UUID.Parse("00000000-0000-0000-0000-000000000060"); + rs.TerrainTexture4 = UUID.Parse("00000000-0000-0000-0000-000000000080"); + rs.UseEstateSun = true; + rs.WaterHeight = 23; + rs.TelehubObject = UUID.Parse("00000000-0000-0000-0000-111111111111"); + rs.AddSpawnPoint(SpawnPoint.Parse("1,-2,0.33")); + + tar.WriteFile(ArchiveConstants.SETTINGS_PATH + "region1.xml", RegionSettingsSerializer.Serialize(rs, null, new EstateSettings())); + + tar.Close(); + + MemoryStream archiveReadStream = new MemoryStream(archiveWriteStream.ToArray()); + + m_scene.EventManager.OnOarFileLoaded += LoadCompleted; + m_oarEvent.Reset(); + m_archiverModule.DearchiveRegion(archiveReadStream); + + m_oarEvent.WaitOne(60000); + + Assert.That(m_lastErrorMessage, Is.Null); + RegionSettings loadedRs = m_scene.RegionInfo.RegionSettings; + + Assert.That(loadedRs.AgentLimit, Is.EqualTo(17)); + Assert.That(loadedRs.AllowDamage, Is.True); + Assert.That(loadedRs.AllowLandJoinDivide, Is.True); + Assert.That(loadedRs.AllowLandResell, Is.True); + Assert.That(loadedRs.BlockFly, Is.True); + Assert.That(loadedRs.BlockShowInSearch, Is.True); + Assert.That(loadedRs.BlockTerraform, Is.True); + Assert.That(loadedRs.DisableCollisions, Is.True); + Assert.That(loadedRs.DisablePhysics, Is.True); + Assert.That(loadedRs.DisableScripts, Is.True); + Assert.That(loadedRs.Elevation1NW, Is.EqualTo(15.9)); + Assert.That(loadedRs.Elevation1NE, Is.EqualTo(45.3)); + Assert.That(loadedRs.Elevation1SE, Is.EqualTo(49)); + Assert.That(loadedRs.Elevation1SW, Is.EqualTo(1.9)); + Assert.That(loadedRs.Elevation2NW, Is.EqualTo(4.5)); + Assert.That(loadedRs.Elevation2NE, Is.EqualTo(19.2)); + Assert.That(loadedRs.Elevation2SE, Is.EqualTo(9.2)); + Assert.That(loadedRs.Elevation2SW, Is.EqualTo(2.1)); + Assert.That(loadedRs.ObjectBonus, Is.EqualTo(1.4)); + Assert.That(loadedRs.RestrictPushing, Is.True); + Assert.That(loadedRs.TerrainLowerLimit, Is.EqualTo(-17.9)); + Assert.That(loadedRs.TerrainRaiseLimit, Is.EqualTo(17.9)); + Assert.That(loadedRs.TerrainTexture1, Is.EqualTo(UUID.Parse("00000000-0000-0000-0000-000000000020"))); + Assert.That(loadedRs.TerrainTexture2, Is.EqualTo(UUID.Parse("00000000-0000-0000-0000-000000000040"))); + Assert.That(loadedRs.TerrainTexture3, Is.EqualTo(UUID.Parse("00000000-0000-0000-0000-000000000060"))); + Assert.That(loadedRs.TerrainTexture4, Is.EqualTo(UUID.Parse("00000000-0000-0000-0000-000000000080"))); + Assert.That(loadedRs.WaterHeight, Is.EqualTo(23)); + Assert.AreEqual(UUID.Zero, loadedRs.TelehubObject); // because no object was found with the original UUID + Assert.AreEqual(0, loadedRs.SpawnPoints().Count); + } + + /// + /// Test merging an OpenSim Region Archive into an existing scene + /// + //[Test] + public void TestMergeOar() + { + TestHelpers.InMethod(); + //XmlConfigurator.Configure(); + + MemoryStream archiveWriteStream = new MemoryStream(); + +// string part2Name = "objectMerge"; +// PrimitiveBaseShape part2Shape = PrimitiveBaseShape.CreateCylinder(); +// Vector3 part2GroupPosition = new Vector3(90, 80, 70); +// Quaternion part2RotationOffset = new Quaternion(60, 70, 80, 90); +// Vector3 part2OffsetPosition = new Vector3(20, 25, 30); + + SceneObjectPart part2 = CreateSceneObjectPart2(); + + // Create an oar file that we can use for the merge + { + ArchiverModule archiverModule = new ArchiverModule(); + SerialiserModule serialiserModule = new SerialiserModule(); + TerrainModule terrainModule = new TerrainModule(); + + Scene scene = m_sceneHelpers.SetupScene(); + SceneHelpers.SetupSceneModules(scene, archiverModule, serialiserModule, terrainModule); + + m_scene.AddNewSceneObject(new SceneObjectGroup(part2), false); + + // Write out this scene + + scene.EventManager.OnOarFileSaved += SaveCompleted; + m_oarEvent.Reset(); + m_archiverModule.ArchiveRegion(archiveWriteStream); + + m_oarEvent.WaitOne(60000); + } + + { + SceneObjectPart part1 = CreateSceneObjectPart1(); + m_scene.AddNewSceneObject(new SceneObjectGroup(part1), false); + + // Merge in the archive we created earlier + byte[] archive = archiveWriteStream.ToArray(); + MemoryStream archiveReadStream = new MemoryStream(archive); + + m_scene.EventManager.OnOarFileLoaded += LoadCompleted; + Dictionary archiveOptions = new Dictionary(); + archiveOptions.Add("merge", null); + m_oarEvent.Reset(); + m_archiverModule.DearchiveRegion(archiveReadStream, Guid.Empty, archiveOptions); + + m_oarEvent.WaitOne(60000); + + SceneObjectPart object1Existing = m_scene.GetSceneObjectPart(part1.Name); + Assert.That(object1Existing, Is.Not.Null, "object1 was not present after merge"); + Assert.That(object1Existing.Name, Is.EqualTo(part1.Name), "object1 names not identical after merge"); + Assert.That(object1Existing.GroupPosition, Is.EqualTo(part1.GroupPosition), "object1 group position not equal after merge"); + + SceneObjectPart object2PartMerged = m_scene.GetSceneObjectPart(part2.Name); + Assert.That(object2PartMerged, Is.Not.Null, "object2 was not present after merge"); + Assert.That(object2PartMerged.Name, Is.EqualTo(part2.Name), "object2 names not identical after merge"); + Assert.That(object2PartMerged.GroupPosition, Is.EqualTo(part2.GroupPosition), "object2 group position not equal after merge"); + } + } + + /// + /// Test saving a multi-region OAR. + /// + [Test] + public void TestSaveMultiRegionOar() + { + TestHelpers.InMethod(); + + // Create test regions + + int WIDTH = 2; + int HEIGHT = 2; + + List scenes = new List(); + + // Maps (Directory in OAR file -> scene) + Dictionary regionPaths = new Dictionary(); + + // Maps (Scene -> expected object paths) + Dictionary> expectedPaths = new Dictionary>(); + + // List of expected assets + List expectedAssets = new List(); + + for (uint y = 0; y < HEIGHT; y++) + { + for (uint x = 0; x < WIDTH; x++) + { + Scene scene; + if (x == 0 && y == 0) + { + scene = m_scene; // this scene was already created in SetUp() + } + else + { + scene = m_sceneHelpers.SetupScene(string.Format("Unit test region {0}", (y * WIDTH) + x + 1), UUID.Random(), 1000 + x, 1000 + y); + SceneHelpers.SetupSceneModules(scene, new ArchiverModule(), m_serialiserModule, new TerrainModule()); + } + scenes.Add(scene); + + string dir = String.Format("{0}_{1}_{2}", x + 1, y + 1, scene.RegionInfo.RegionName.Replace(" ", "_")); + regionPaths[dir] = scene; + + SceneObjectGroup sog1; + SceneObjectGroup sog2; + UUID ncAssetUuid; + + CreateTestObjects(scene, out sog1, out sog2, out ncAssetUuid); + + expectedPaths[scene.RegionInfo.RegionID] = new List(); + expectedPaths[scene.RegionInfo.RegionID].Add(ArchiveHelpers.CreateObjectPath(sog1)); + expectedPaths[scene.RegionInfo.RegionID].Add(ArchiveHelpers.CreateObjectPath(sog2)); + + expectedAssets.Add(ncAssetUuid); + } + } + + // Save OAR + MemoryStream archiveWriteStream = new MemoryStream(); + + Guid requestId = new Guid("00000000-0000-0000-0000-808080808080"); + + Dictionary options = new Dictionary(); + options.Add("all", true); + + m_scene.EventManager.OnOarFileSaved += SaveCompleted; + m_oarEvent.Reset(); + m_archiverModule.ArchiveRegion(archiveWriteStream, requestId, options); + + m_oarEvent.WaitOne(60000); + + + // Check that the OAR contains the expected data + Assert.That(m_lastRequestId, Is.EqualTo(requestId)); + + byte[] archive = archiveWriteStream.ToArray(); + MemoryStream archiveReadStream = new MemoryStream(archive); + TarArchiveReader tar = new TarArchiveReader(archiveReadStream); + + Dictionary> foundPaths = new Dictionary>(); + List foundAssets = new List(); + + foreach (Scene scene in scenes) + { + foundPaths[scene.RegionInfo.RegionID] = new List(); + } + + string filePath; + TarArchiveReader.TarEntryType tarEntryType; + + byte[] data = tar.ReadEntry(out filePath, out tarEntryType); + Assert.That(filePath, Is.EqualTo(ArchiveConstants.CONTROL_FILE_PATH)); + + Dictionary archiveOptions = new Dictionary(); + ArchiveReadRequest arr = new ArchiveReadRequest(m_scene, (Stream)null, Guid.Empty, archiveOptions); + arr.LoadControlFile(filePath, data, new DearchiveScenesInfo()); + + Assert.That(arr.ControlFileLoaded, Is.True); + + while (tar.ReadEntry(out filePath, out tarEntryType) != null) + { + if (filePath.StartsWith(ArchiveConstants.ASSETS_PATH)) + { + // Assets are shared, so this file doesn't belong to any specific region. + string fileName = filePath.Remove(0, ArchiveConstants.ASSETS_PATH.Length); + if (fileName.EndsWith("_notecard.txt")) + foundAssets.Add(UUID.Parse(fileName.Substring(0, fileName.Length - "_notecard.txt".Length))); + } + else + { + // This file belongs to one of the regions. Find out which one. + Assert.IsTrue(filePath.StartsWith(ArchiveConstants.REGIONS_PATH)); + string[] parts = filePath.Split(new Char[] { '/' }, 3); + Assert.AreEqual(3, parts.Length); + string regionDirectory = parts[1]; + string relativePath = parts[2]; + Scene scene = regionPaths[regionDirectory]; + + if (relativePath.StartsWith(ArchiveConstants.OBJECTS_PATH)) + { + foundPaths[scene.RegionInfo.RegionID].Add(relativePath); + } + } + } + + Assert.AreEqual(scenes.Count, foundPaths.Count); + foreach (Scene scene in scenes) + { + Assert.That(foundPaths[scene.RegionInfo.RegionID], Is.EquivalentTo(expectedPaths[scene.RegionInfo.RegionID])); + } + + Assert.That(foundAssets, Is.EquivalentTo(expectedAssets)); + } + + /// + /// Test loading a multi-region OAR. + /// + [Test] + public void TestLoadMultiRegionOar() + { + TestHelpers.InMethod(); + + // Create an ArchiveScenesGroup with the regions in the OAR. This is needed to generate the control file. + + int WIDTH = 2; + int HEIGHT = 2; + + for (uint y = 0; y < HEIGHT; y++) + { + for (uint x = 0; x < WIDTH; x++) + { + Scene scene; + if (x == 0 && y == 0) + { + scene = m_scene; // this scene was already created in SetUp() + } + else + { + scene = m_sceneHelpers.SetupScene(string.Format("Unit test region {0}", (y * WIDTH) + x + 1), UUID.Random(), 1000 + x, 1000 + y); + SceneHelpers.SetupSceneModules(scene, new ArchiverModule(), m_serialiserModule, new TerrainModule()); + } + } + } + + ArchiveScenesGroup scenesGroup = new ArchiveScenesGroup(); + m_sceneHelpers.SceneManager.ForEachScene(delegate(Scene scene) + { + scenesGroup.AddScene(scene); + }); + scenesGroup.CalcSceneLocations(); + + // Generate the OAR file + + MemoryStream archiveWriteStream = new MemoryStream(); + TarArchiveWriter tar = new TarArchiveWriter(archiveWriteStream); + + ArchiveWriteRequest writeRequest = new ArchiveWriteRequest(m_scene, (Stream)null, Guid.Empty); + writeRequest.MultiRegionFormat = true; + tar.WriteFile( + ArchiveConstants.CONTROL_FILE_PATH, writeRequest.CreateControlFile(scenesGroup)); + + SceneObjectPart part1 = CreateSceneObjectPart1(); + part1.SitTargetOrientation = new Quaternion(0.2f, 0.3f, 0.4f, 0.5f); + part1.SitTargetPosition = new Vector3(1, 2, 3); + + SceneObjectGroup object1 = new SceneObjectGroup(part1); + + // Let's put some inventory items into our object + string soundItemName = "sound-item1"; + UUID soundItemUuid = UUID.Parse("00000000-0000-0000-0000-000000000002"); + Type type = GetType(); + Assembly assembly = type.Assembly; + string soundDataResourceName = null; + string[] names = assembly.GetManifestResourceNames(); + foreach (string name in names) + { + if (name.EndsWith(".Resources.test-sound.wav")) + soundDataResourceName = name; + } + Assert.That(soundDataResourceName, Is.Not.Null); + + byte[] soundData; + UUID soundUuid; + CreateSoundAsset(tar, assembly, soundDataResourceName, out soundData, out soundUuid); + + TaskInventoryItem item1 + = new TaskInventoryItem { AssetID = soundUuid, ItemID = soundItemUuid, Name = soundItemName }; + part1.Inventory.AddInventoryItem(item1, true); + m_scene.AddNewSceneObject(object1, false); + + string object1FileName = string.Format( + "{0}_{1:000}-{2:000}-{3:000}__{4}.xml", + part1.Name, + Math.Round(part1.GroupPosition.X), Math.Round(part1.GroupPosition.Y), Math.Round(part1.GroupPosition.Z), + part1.UUID); + string path = "regions/1_1_Unit_test_region/" + ArchiveConstants.OBJECTS_PATH + object1FileName; + tar.WriteFile(path, SceneObjectSerializer.ToXml2Format(object1)); + + tar.Close(); + + + // Delete the current objects, to test that they're loaded from the OAR and didn't + // just remain in the scene. + m_sceneHelpers.SceneManager.ForEachScene(delegate(Scene scene) + { + scene.DeleteAllSceneObjects(); + }); + + // Create a "hole", to test that that the corresponding region isn't loaded from the OAR + m_sceneHelpers.SceneManager.CloseScene(SceneManager.Instance.Scenes[1]); + + + // Check thay the OAR file contains the expected data + + MemoryStream archiveReadStream = new MemoryStream(archiveWriteStream.ToArray()); + + m_scene.EventManager.OnOarFileLoaded += LoadCompleted; + m_oarEvent.Reset(); + m_archiverModule.DearchiveRegion(archiveReadStream); + + m_oarEvent.WaitOne(60000); + + Assert.That(m_lastErrorMessage, Is.Null); + + Assert.AreEqual(3, m_sceneHelpers.SceneManager.Scenes.Count); + + TestLoadedRegion(part1, soundItemName, soundData); + } + + private void TestLoadedRegion(SceneObjectPart part1, string soundItemName, byte[] soundData) + { + SceneObjectPart object1PartLoaded = m_scene.GetSceneObjectPart(part1.Name); + + Assert.That(object1PartLoaded, Is.Not.Null, "object1 was not loaded"); + Assert.That(object1PartLoaded.Name, Is.EqualTo(part1.Name), "object1 names not identical"); + Assert.That(object1PartLoaded.GroupPosition, Is.EqualTo(part1.GroupPosition), "object1 group position not equal"); + + Quaternion qtmp1 = new Quaternion ( + (float)Math.Round(object1PartLoaded.RotationOffset.X,5), + (float)Math.Round(object1PartLoaded.RotationOffset.Y,5), + (float)Math.Round(object1PartLoaded.RotationOffset.Z,5), + (float)Math.Round(object1PartLoaded.RotationOffset.W,5)); + Quaternion qtmp2 = new Quaternion ( + (float)Math.Round(part1.RotationOffset.X,5), + (float)Math.Round(part1.RotationOffset.Y,5), + (float)Math.Round(part1.RotationOffset.Z,5), + (float)Math.Round(part1.RotationOffset.W,5)); + + Assert.That(qtmp1, Is.EqualTo(qtmp2), "object1 rotation offset not equal"); + Assert.That( + object1PartLoaded.OffsetPosition, Is.EqualTo(part1.OffsetPosition), "object1 offset position not equal"); + Assert.That(object1PartLoaded.SitTargetOrientation, Is.EqualTo(part1.SitTargetOrientation)); + Assert.That(object1PartLoaded.SitTargetPosition, Is.EqualTo(part1.SitTargetPosition)); + + TaskInventoryItem loadedSoundItem = object1PartLoaded.Inventory.GetInventoryItems(soundItemName)[0]; + Assert.That(loadedSoundItem, Is.Not.Null, "loaded sound item was null"); + AssetBase loadedSoundAsset = m_scene.AssetService.Get(loadedSoundItem.AssetID.ToString()); + Assert.That(loadedSoundAsset, Is.Not.Null, "loaded sound asset was null"); + Assert.That(loadedSoundAsset.Data, Is.EqualTo(soundData), "saved and loaded sound data do not match"); + + Assert.Greater(m_scene.LandChannel.AllParcels().Count, 0, "incorrect number of parcels"); + } + } +} \ No newline at end of file diff --git a/Tests/OpenSim.Region.CoreModules.Tests/World/Archiver/Tests/Resources/test-sound.wav b/Tests/OpenSim.Region.CoreModules.Tests/World/Archiver/Tests/Resources/test-sound.wav new file mode 100644 index 00000000000..b45ee54d354 Binary files /dev/null and b/Tests/OpenSim.Region.CoreModules.Tests/World/Archiver/Tests/Resources/test-sound.wav differ diff --git a/Tests/OpenSim.Region.CoreModules.Tests/World/Land/Tests/LandManagementModuleTests.cs b/Tests/OpenSim.Region.CoreModules.Tests/World/Land/Tests/LandManagementModuleTests.cs new file mode 100644 index 00000000000..c512eac3e8c --- /dev/null +++ b/Tests/OpenSim.Region.CoreModules.Tests/World/Land/Tests/LandManagementModuleTests.cs @@ -0,0 +1,266 @@ +/* + * 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 NUnit.Framework; +using OpenMetaverse; +using OpenSim.Framework; +using OpenSim.Region.Framework.Scenes; +using OpenSim.Tests.Common; + +namespace OpenSim.Region.CoreModules.World.Land.Tests +{ + public class LandManagementModuleTests : OpenSimTestCase + { + [Test] + public void TestAddLandObject() + { + TestHelpers.InMethod(); +// TestHelpers.EnableLogging(); + + UUID userId = TestHelpers.ParseTail(0x1); + + LandManagementModule lmm = new LandManagementModule(); + Scene scene = new SceneHelpers().SetupScene(); + SceneHelpers.SetupSceneModules(scene, lmm); + + ILandObject lo = new LandObject(userId, false, scene); + lo.LandData.Name = "lo1"; + lo.SetLandBitmap( + lo.GetSquareLandBitmap(0, 0, (int)Constants.RegionSize, (int)Constants.RegionSize)); + lo = lmm.AddLandObject(lo); + + // TODO: Should add asserts to check that land object was added properly. + + // At the moment, this test just makes sure that we can't add a land object that overlaps the areas that + // the first still holds. + ILandObject lo2 = new LandObject(userId, false, scene); + lo2.SetLandBitmap( + lo2.GetSquareLandBitmap(0, 0, (int)Constants.RegionSize, (int)Constants.RegionSize)); + lo2.LandData.Name = "lo2"; + lo2 = lmm.AddLandObject(lo2); + + { + ILandObject loAtCoord = lmm.GetLandObject(0, 0); + Assert.That(loAtCoord.LandData.LocalID, Is.EqualTo(lo.LandData.LocalID)); + Assert.That(loAtCoord.LandData.GlobalID, Is.EqualTo(lo.LandData.GlobalID)); + } + + { + ILandObject loAtCoord = lmm.GetLandObject((int)Constants.RegionSize - 1, ((int)Constants.RegionSize - 1)); + Assert.That(loAtCoord.LandData.LocalID, Is.EqualTo(lo.LandData.LocalID)); + Assert.That(loAtCoord.LandData.GlobalID, Is.EqualTo(lo.LandData.GlobalID)); + } + } + + /// + /// Test parcels on region when no land data exists to be loaded. + /// + [Test] + public void TestLoadWithNoParcels() + { + TestHelpers.InMethod(); +// TestHelpers.EnableLogging(); + + SceneHelpers sh = new SceneHelpers(); + LandManagementModule lmm = new LandManagementModule(); + Scene scene = sh.SetupScene(); + SceneHelpers.SetupSceneModules(scene, lmm); + + scene.loadAllLandObjectsFromStorage(scene.RegionInfo.RegionID); + + ILandObject loAtCoord1 = lmm.GetLandObject(0, 0); + Assert.That(loAtCoord1.LandData.LocalID, Is.Not.EqualTo(0)); + Assert.That(loAtCoord1.LandData.GlobalID, Is.Not.EqualTo(UUID.Zero)); + + ILandObject loAtCoord2 = lmm.GetLandObject((int)Constants.RegionSize - 1, ((int)Constants.RegionSize - 1)); + Assert.That(loAtCoord2.LandData.LocalID, Is.EqualTo(loAtCoord1.LandData.LocalID)); + Assert.That(loAtCoord2.LandData.GlobalID, Is.EqualTo(loAtCoord1.LandData.GlobalID)); + } + + /// + /// Test parcels on region when a single parcel already exists but it does not cover the whole region. + /// + [Test] + public void TestLoadWithSinglePartialCoveringParcel() + { + TestHelpers.InMethod(); +// TestHelpers.EnableLogging(); + + UUID userId = TestHelpers.ParseTail(0x1); + + SceneHelpers sh = new SceneHelpers(); + LandManagementModule lmm = new LandManagementModule(); + Scene scene = sh.SetupScene(); + SceneHelpers.SetupSceneModules(scene, lmm); + + ILandObject originalLo1 = new LandObject(userId, false, scene); + originalLo1.LandData.Name = "lo1"; + originalLo1.SetLandBitmap( + originalLo1.GetSquareLandBitmap(0, 0, (int)Constants.RegionSize, (int)Constants.RegionSize / 2)); + + sh.SimDataService.StoreLandObject(originalLo1); + + scene.loadAllLandObjectsFromStorage(scene.RegionInfo.RegionID); + + ILandObject loAtCoord1 = lmm.GetLandObject(0, 0); + Assert.That(loAtCoord1.LandData.Name, Is.EqualTo(originalLo1.LandData.Name)); + Assert.That(loAtCoord1.LandData.GlobalID, Is.EqualTo(originalLo1.LandData.GlobalID)); + + ILandObject loAtCoord2 = lmm.GetLandObject((int)Constants.RegionSize - 1, ((int)Constants.RegionSize - 1)); + Assert.That(loAtCoord2.LandData.LocalID, Is.EqualTo(loAtCoord1.LandData.LocalID)); + Assert.That(loAtCoord2.LandData.GlobalID, Is.EqualTo(loAtCoord1.LandData.GlobalID)); + } + + /// + /// Test parcels on region when a single parcel already exists but it does not cover the whole region. + /// + [Test] + public void TestLoadWithMultiplePartialCoveringParcels() + { + TestHelpers.InMethod(); +// TestHelpers.EnableLogging(); + + UUID userId = TestHelpers.ParseTail(0x1); + + SceneHelpers sh = new SceneHelpers(); + LandManagementModule lmm = new LandManagementModule(); + Scene scene = sh.SetupScene(); + SceneHelpers.SetupSceneModules(scene, lmm); + + ILandObject originalLo1 = new LandObject(userId, false, scene); + originalLo1.LandData.Name = "lo1"; + originalLo1.SetLandBitmap( + originalLo1.GetSquareLandBitmap(0, 0, (int)Constants.RegionSize, (int)Constants.RegionSize / 2)); + + sh.SimDataService.StoreLandObject(originalLo1); + + ILandObject originalLo2 = new LandObject(userId, false, scene); + originalLo2.LandData.Name = "lo2"; + originalLo2.SetLandBitmap( + originalLo2.GetSquareLandBitmap( + 0, (int)Constants.RegionSize / 2, (int)Constants.RegionSize, ((int)Constants.RegionSize / 4) * 3)); + + sh.SimDataService.StoreLandObject(originalLo2); + + scene.loadAllLandObjectsFromStorage(scene.RegionInfo.RegionID); + + ILandObject loAtCoord1 = lmm.GetLandObject(0, 0); + Assert.That(loAtCoord1.LandData.Name, Is.EqualTo(originalLo1.LandData.Name)); + Assert.That(loAtCoord1.LandData.GlobalID, Is.EqualTo(originalLo1.LandData.GlobalID)); + + ILandObject loAtCoord2 + = lmm.GetLandObject((int)Constants.RegionSize - 1, (((int)Constants.RegionSize / 4) * 3) - 1); + Assert.That(loAtCoord2.LandData.Name, Is.EqualTo(originalLo2.LandData.Name)); + Assert.That(loAtCoord2.LandData.GlobalID, Is.EqualTo(originalLo2.LandData.GlobalID)); + + ILandObject loAtCoord3 = lmm.GetLandObject((int)Constants.RegionSize - 1, ((int)Constants.RegionSize - 1)); + Assert.That(loAtCoord3.LandData.LocalID, Is.Not.EqualTo(loAtCoord1.LandData.LocalID)); + Assert.That(loAtCoord3.LandData.LocalID, Is.Not.EqualTo(loAtCoord2.LandData.LocalID)); + Assert.That(loAtCoord3.LandData.GlobalID, Is.Not.EqualTo(loAtCoord1.LandData.GlobalID)); + Assert.That(loAtCoord3.LandData.GlobalID, Is.Not.EqualTo(loAtCoord2.LandData.GlobalID)); + } + + /// + /// Test parcels on region when whole region is parcelled (which should normally always be the case). + /// + [Test] + public void TestLoad() + { + TestHelpers.InMethod(); +// TestHelpers.EnableLogging(); + + UUID userId = TestHelpers.ParseTail(0x1); + + SceneHelpers sh = new SceneHelpers(); + LandManagementModule lmm = new LandManagementModule(); + Scene scene = sh.SetupScene(); + SceneHelpers.SetupSceneModules(scene, lmm); + + ILandObject originalLo1 = new LandObject(userId, false, scene); + originalLo1.LandData.Name = "lo1"; + originalLo1.SetLandBitmap( + originalLo1.GetSquareLandBitmap(0, 0, (int)Constants.RegionSize, (int)Constants.RegionSize / 2)); + + sh.SimDataService.StoreLandObject(originalLo1); + + ILandObject originalLo2 = new LandObject(userId, false, scene); + originalLo2.LandData.Name = "lo2"; + originalLo2.SetLandBitmap( + originalLo2.GetSquareLandBitmap(0, (int)Constants.RegionSize / 2, (int)Constants.RegionSize, (int)Constants.RegionSize)); + + sh.SimDataService.StoreLandObject(originalLo2); + + scene.loadAllLandObjectsFromStorage(scene.RegionInfo.RegionID); + + { + ILandObject loAtCoord = lmm.GetLandObject(0, 0); + Assert.That(loAtCoord.LandData.Name, Is.EqualTo(originalLo1.LandData.Name)); + Assert.That(loAtCoord.LandData.GlobalID, Is.EqualTo(originalLo1.LandData.GlobalID)); + } + + { + ILandObject loAtCoord = lmm.GetLandObject((int)Constants.RegionSize - 1, ((int)Constants.RegionSize - 1)); + Assert.That(loAtCoord.LandData.Name, Is.EqualTo(originalLo2.LandData.Name)); + Assert.That(loAtCoord.LandData.GlobalID, Is.EqualTo(originalLo2.LandData.GlobalID)); + } + } + + [Test] + public void TestSubdivide() + { + TestHelpers.InMethod(); +// TestHelpers.EnableLogging(); + + UUID userId = TestHelpers.ParseTail(0x1); + + LandManagementModule lmm = new LandManagementModule(); + Scene scene = new SceneHelpers().SetupScene(); + SceneHelpers.SetupSceneModules(scene, lmm); + + ILandObject lo = new LandObject(userId, false, scene); + lo.LandData.Name = "lo1"; + lo.SetLandBitmap( + lo.GetSquareLandBitmap(0, 0, (int)Constants.RegionSize, (int)Constants.RegionSize)); + lo = lmm.AddLandObject(lo); + + lmm.Subdivide(0, 0, Constants.LandUnit, Constants.LandUnit, userId); + + { + ILandObject loAtCoord = lmm.GetLandObject(0, 0); + Assert.That(loAtCoord.LandData.LocalID, Is.Not.EqualTo(lo.LandData.LocalID)); + Assert.That(loAtCoord.LandData.GlobalID, Is.Not.EqualTo(lo.LandData.GlobalID)); + } + + { + ILandObject loAtCoord = lmm.GetLandObject(Constants.LandUnit, Constants.LandUnit); + Assert.That(loAtCoord.LandData.LocalID, Is.EqualTo(lo.LandData.LocalID)); + Assert.That(loAtCoord.LandData.GlobalID, Is.EqualTo(lo.LandData.GlobalID)); + } + } + } +} \ No newline at end of file diff --git a/Tests/OpenSim.Region.CoreModules.Tests/World/Land/Tests/PrimCountModuleTests.cs b/Tests/OpenSim.Region.CoreModules.Tests/World/Land/Tests/PrimCountModuleTests.cs new file mode 100644 index 00000000000..a349aa1be58 --- /dev/null +++ b/Tests/OpenSim.Region.CoreModules.Tests/World/Land/Tests/PrimCountModuleTests.cs @@ -0,0 +1,382 @@ +/* + * 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 System.Reflection; +using log4net.Config; +using NUnit.Framework; +using OpenMetaverse; +using OpenMetaverse.Assets; +using OpenSim.Framework; +using OpenSim.Region.Framework.Interfaces; +using OpenSim.Region.Framework.Scenes; +using OpenSim.Tests.Common; + +namespace OpenSim.Region.CoreModules.World.Land.Tests +{ + [TestFixture] + public class PrimCountModuleTests : OpenSimTestCase + { + protected UUID m_userId = new UUID("00000000-0000-0000-0000-100000000000"); + protected UUID m_groupId = new UUID("00000000-0000-0000-8888-000000000000"); + protected UUID m_otherUserId = new UUID("99999999-9999-9999-9999-999999999999"); + protected TestScene m_scene; + protected PrimCountModule m_pcm; + + /// + /// A parcel that covers the entire sim except for a 1 unit wide strip on the eastern side. + /// + protected ILandObject m_lo; + + /// + /// A parcel that covers just the eastern strip of the sim. + /// + protected ILandObject m_lo2; + + [SetUp] + public override void SetUp() + { + base.SetUp(); + + m_pcm = new PrimCountModule(); + LandManagementModule lmm = new LandManagementModule(); + m_scene = new SceneHelpers().SetupScene(); + SceneHelpers.SetupSceneModules(m_scene, lmm, m_pcm); + + int xParcelDivider = (int)Constants.RegionSize - 1; + + ILandObject lo = new LandObject(m_userId, false, m_scene); + lo.LandData.Name = "m_lo"; + lo.SetLandBitmap( + lo.GetSquareLandBitmap(0, 0, xParcelDivider, (int)Constants.RegionSize)); + m_lo = lmm.AddLandObject(lo); + + ILandObject lo2 = new LandObject(m_userId, false, m_scene); + lo2.SetLandBitmap( + lo2.GetSquareLandBitmap(xParcelDivider, 0, (int)Constants.RegionSize, (int)Constants.RegionSize)); + lo2.LandData.Name = "m_lo2"; + m_lo2 = lmm.AddLandObject(lo2); + } + + /// + /// Test that counts before we do anything are correct. + /// + [Test] + public void TestInitialCounts() + { + IPrimCounts pc = m_lo.PrimCounts; + + Assert.That(pc.Owner, Is.EqualTo(0)); + Assert.That(pc.Group, Is.EqualTo(0)); + Assert.That(pc.Others, Is.EqualTo(0)); + Assert.That(pc.Total, Is.EqualTo(0)); + Assert.That(pc.Selected, Is.EqualTo(0)); + Assert.That(pc.Users[m_userId], Is.EqualTo(0)); + Assert.That(pc.Users[m_otherUserId], Is.EqualTo(0)); + Assert.That(pc.Simulator, Is.EqualTo(0)); + } + + /// + /// Test count after a parcel owner owned object is added. + /// + [Test] + public void TestAddOwnerObject() + { + TestHelpers.InMethod(); +// log4net.Config.XmlConfigurator.Configure(); + + IPrimCounts pc = m_lo.PrimCounts; + + SceneObjectGroup sog = SceneHelpers.CreateSceneObject(3, m_userId, "a", 0x01); + m_scene.AddNewSceneObject(sog, false); + + Assert.That(pc.Owner, Is.EqualTo(3)); + Assert.That(pc.Group, Is.EqualTo(0)); + Assert.That(pc.Others, Is.EqualTo(0)); + Assert.That(pc.Total, Is.EqualTo(3)); + Assert.That(pc.Selected, Is.EqualTo(0)); + Assert.That(pc.Users[m_userId], Is.EqualTo(3)); + Assert.That(pc.Users[m_otherUserId], Is.EqualTo(0)); + Assert.That(pc.Simulator, Is.EqualTo(3)); + + // Add a second object and retest + SceneObjectGroup sog2 = SceneHelpers.CreateSceneObject(2, m_userId, "b", 0x10); + m_scene.AddNewSceneObject(sog2, false); + + Assert.That(pc.Owner, Is.EqualTo(5)); + Assert.That(pc.Group, Is.EqualTo(0)); + Assert.That(pc.Others, Is.EqualTo(0)); + Assert.That(pc.Total, Is.EqualTo(5)); + Assert.That(pc.Selected, Is.EqualTo(0)); + Assert.That(pc.Users[m_userId], Is.EqualTo(5)); + Assert.That(pc.Users[m_otherUserId], Is.EqualTo(0)); + Assert.That(pc.Simulator, Is.EqualTo(5)); + } + + /// + /// Test count after a parcel owner owned copied object is added. + /// + [Test] + public void TestCopyOwnerObject() + { + TestHelpers.InMethod(); +// log4net.Config.XmlConfigurator.Configure(); + + IPrimCounts pc = m_lo.PrimCounts; + + SceneObjectGroup sog = SceneHelpers.CreateSceneObject(3, m_userId, "a", 0x01); + m_scene.AddNewSceneObject(sog, false); + m_scene.SceneGraph.DuplicateObject(sog.LocalId, Vector3.Zero, m_userId, UUID.Zero, Quaternion.Identity, false); + + Assert.That(pc.Owner, Is.EqualTo(6)); + Assert.That(pc.Group, Is.EqualTo(0)); + Assert.That(pc.Others, Is.EqualTo(0)); + Assert.That(pc.Total, Is.EqualTo(6)); + Assert.That(pc.Selected, Is.EqualTo(0)); + Assert.That(pc.Users[m_userId], Is.EqualTo(6)); + Assert.That(pc.Users[m_otherUserId], Is.EqualTo(0)); + Assert.That(pc.Simulator, Is.EqualTo(6)); + } + + /// + /// Test that parcel counts update correctly when an object is moved between parcels, where that movement + /// is not done directly by the user/ + /// + [Test] + public void TestMoveOwnerObject() + { + TestHelpers.InMethod(); +// log4net.Config.XmlConfigurator.Configure(); + + SceneObjectGroup sog = SceneHelpers.CreateSceneObject(3, m_userId, "a", 0x01); + m_scene.AddNewSceneObject(sog, false); + SceneObjectGroup sog2 = SceneHelpers.CreateSceneObject(2, m_userId, "b", 0x10); + m_scene.AddNewSceneObject(sog2, false); + + // Move the first scene object to the eastern strip parcel + sog.AbsolutePosition = new Vector3(254, 2, 2); + + IPrimCounts pclo1 = m_lo.PrimCounts; + + Assert.That(pclo1.Owner, Is.EqualTo(2)); + Assert.That(pclo1.Group, Is.EqualTo(0)); + Assert.That(pclo1.Others, Is.EqualTo(0)); + Assert.That(pclo1.Total, Is.EqualTo(2)); + Assert.That(pclo1.Selected, Is.EqualTo(0)); + Assert.That(pclo1.Users[m_userId], Is.EqualTo(2)); + Assert.That(pclo1.Users[m_otherUserId], Is.EqualTo(0)); + Assert.That(pclo1.Simulator, Is.EqualTo(5)); + + IPrimCounts pclo2 = m_lo2.PrimCounts; + + Assert.That(pclo2.Owner, Is.EqualTo(3)); + Assert.That(pclo2.Group, Is.EqualTo(0)); + Assert.That(pclo2.Others, Is.EqualTo(0)); + Assert.That(pclo2.Total, Is.EqualTo(3)); + Assert.That(pclo2.Selected, Is.EqualTo(0)); + Assert.That(pclo2.Users[m_userId], Is.EqualTo(3)); + Assert.That(pclo2.Users[m_otherUserId], Is.EqualTo(0)); + Assert.That(pclo2.Simulator, Is.EqualTo(5)); + + // Now move it back again + sog.AbsolutePosition = new Vector3(2, 2, 2); + + Assert.That(pclo1.Owner, Is.EqualTo(5)); + Assert.That(pclo1.Group, Is.EqualTo(0)); + Assert.That(pclo1.Others, Is.EqualTo(0)); + Assert.That(pclo1.Total, Is.EqualTo(5)); + Assert.That(pclo1.Selected, Is.EqualTo(0)); + Assert.That(pclo1.Users[m_userId], Is.EqualTo(5)); + Assert.That(pclo1.Users[m_otherUserId], Is.EqualTo(0)); + Assert.That(pclo1.Simulator, Is.EqualTo(5)); + + Assert.That(pclo2.Owner, Is.EqualTo(0)); + Assert.That(pclo2.Group, Is.EqualTo(0)); + Assert.That(pclo2.Others, Is.EqualTo(0)); + Assert.That(pclo2.Total, Is.EqualTo(0)); + Assert.That(pclo2.Selected, Is.EqualTo(0)); + Assert.That(pclo2.Users[m_userId], Is.EqualTo(0)); + Assert.That(pclo2.Users[m_otherUserId], Is.EqualTo(0)); + Assert.That(pclo2.Simulator, Is.EqualTo(5)); + } + + /// + /// Test count after a parcel owner owned object is removed. + /// + [Test] + public void TestRemoveOwnerObject() + { + TestHelpers.InMethod(); +// log4net.Config.XmlConfigurator.Configure(); + + IPrimCounts pc = m_lo.PrimCounts; + + m_scene.AddNewSceneObject(SceneHelpers.CreateSceneObject(1, m_userId, "a", 0x1), false); + SceneObjectGroup sogToDelete = SceneHelpers.CreateSceneObject(3, m_userId, "b", 0x10); + m_scene.AddNewSceneObject(sogToDelete, false); + m_scene.DeleteSceneObject(sogToDelete, false); + + Assert.That(pc.Owner, Is.EqualTo(1)); + Assert.That(pc.Group, Is.EqualTo(0)); + Assert.That(pc.Others, Is.EqualTo(0)); + Assert.That(pc.Total, Is.EqualTo(1)); + Assert.That(pc.Selected, Is.EqualTo(0)); + Assert.That(pc.Users[m_userId], Is.EqualTo(1)); + Assert.That(pc.Users[m_otherUserId], Is.EqualTo(0)); + Assert.That(pc.Simulator, Is.EqualTo(1)); + } + + [Test] + public void TestAddGroupObject() + { + TestHelpers.InMethod(); +// log4net.Config.XmlConfigurator.Configure(); + + m_lo.DeedToGroup(m_groupId); + + IPrimCounts pc = m_lo.PrimCounts; + + SceneObjectGroup sog = SceneHelpers.CreateSceneObject(3, m_otherUserId, "a", 0x01); + sog.GroupID = m_groupId; + m_scene.AddNewSceneObject(sog, false); + + Assert.That(pc.Owner, Is.EqualTo(0)); + Assert.That(pc.Group, Is.EqualTo(3)); + Assert.That(pc.Others, Is.EqualTo(0)); + Assert.That(pc.Total, Is.EqualTo(3)); + Assert.That(pc.Selected, Is.EqualTo(0)); + + // Is this desired behaviour? Not totally sure. + Assert.That(pc.Users[m_userId], Is.EqualTo(0)); + Assert.That(pc.Users[m_groupId], Is.EqualTo(0)); + Assert.That(pc.Users[m_otherUserId], Is.EqualTo(3)); + + Assert.That(pc.Simulator, Is.EqualTo(3)); + } + + /// + /// Test count after a parcel owner owned object is removed. + /// + [Test] + public void TestRemoveGroupObject() + { + TestHelpers.InMethod(); +// log4net.Config.XmlConfigurator.Configure(); + + m_lo.DeedToGroup(m_groupId); + + IPrimCounts pc = m_lo.PrimCounts; + + SceneObjectGroup sogToKeep = SceneHelpers.CreateSceneObject(1, m_userId, "a", 0x1); + sogToKeep.GroupID = m_groupId; + m_scene.AddNewSceneObject(sogToKeep, false); + + SceneObjectGroup sogToDelete = SceneHelpers.CreateSceneObject(3, m_userId, "b", 0x10); + m_scene.AddNewSceneObject(sogToDelete, false); + m_scene.DeleteSceneObject(sogToDelete, false); + + Assert.That(pc.Owner, Is.EqualTo(0)); + Assert.That(pc.Group, Is.EqualTo(1)); + Assert.That(pc.Others, Is.EqualTo(0)); + Assert.That(pc.Total, Is.EqualTo(1)); + Assert.That(pc.Selected, Is.EqualTo(0)); + Assert.That(pc.Users[m_userId], Is.EqualTo(1)); + Assert.That(pc.Users[m_groupId], Is.EqualTo(0)); + Assert.That(pc.Users[m_otherUserId], Is.EqualTo(0)); + Assert.That(pc.Simulator, Is.EqualTo(1)); + } + + [Test] + public void TestAddOthersObject() + { + TestHelpers.InMethod(); +// log4net.Config.XmlConfigurator.Configure(); + + IPrimCounts pc = m_lo.PrimCounts; + + SceneObjectGroup sog = SceneHelpers.CreateSceneObject(3, m_otherUserId, "a", 0x01); + m_scene.AddNewSceneObject(sog, false); + + Assert.That(pc.Owner, Is.EqualTo(0)); + Assert.That(pc.Group, Is.EqualTo(0)); + Assert.That(pc.Others, Is.EqualTo(3)); + Assert.That(pc.Total, Is.EqualTo(3)); + Assert.That(pc.Selected, Is.EqualTo(0)); + Assert.That(pc.Users[m_userId], Is.EqualTo(0)); + Assert.That(pc.Users[m_otherUserId], Is.EqualTo(3)); + Assert.That(pc.Simulator, Is.EqualTo(3)); + } + + [Test] + public void TestRemoveOthersObject() + { + TestHelpers.InMethod(); +// log4net.Config.XmlConfigurator.Configure(); + + IPrimCounts pc = m_lo.PrimCounts; + + m_scene.AddNewSceneObject(SceneHelpers.CreateSceneObject(1, m_otherUserId, "a", 0x1), false); + SceneObjectGroup sogToDelete = SceneHelpers.CreateSceneObject(3, m_otherUserId, "b", 0x10); + m_scene.AddNewSceneObject(sogToDelete, false); + m_scene.DeleteSceneObject(sogToDelete, false); + + Assert.That(pc.Owner, Is.EqualTo(0)); + Assert.That(pc.Group, Is.EqualTo(0)); + Assert.That(pc.Others, Is.EqualTo(1)); + Assert.That(pc.Total, Is.EqualTo(1)); + Assert.That(pc.Selected, Is.EqualTo(0)); + Assert.That(pc.Users[m_userId], Is.EqualTo(0)); + Assert.That(pc.Users[m_otherUserId], Is.EqualTo(1)); + Assert.That(pc.Simulator, Is.EqualTo(1)); + } + + /// + /// Test the count is correct after is has been tainted. + /// + [Test] + public void TestTaint() + { + TestHelpers.InMethod(); + IPrimCounts pc = m_lo.PrimCounts; + + SceneObjectGroup sog = SceneHelpers.CreateSceneObject(3, m_userId, "a", 0x01); + m_scene.AddNewSceneObject(sog, false); + + m_pcm.TaintPrimCount(); + + Assert.That(pc.Owner, Is.EqualTo(3)); + Assert.That(pc.Group, Is.EqualTo(0)); + Assert.That(pc.Others, Is.EqualTo(0)); + Assert.That(pc.Total, Is.EqualTo(3)); + Assert.That(pc.Selected, Is.EqualTo(0)); + Assert.That(pc.Users[m_userId], Is.EqualTo(3)); + Assert.That(pc.Users[m_otherUserId], Is.EqualTo(0)); + Assert.That(pc.Simulator, Is.EqualTo(3)); + } + } +} \ No newline at end of file diff --git a/Tests/OpenSim.Region.CoreModules.Tests/World/Media/Moap/Tests/MoapTests.cs b/Tests/OpenSim.Region.CoreModules.Tests/World/Media/Moap/Tests/MoapTests.cs new file mode 100644 index 00000000000..0ac9e10b407 --- /dev/null +++ b/Tests/OpenSim.Region.CoreModules.Tests/World/Media/Moap/Tests/MoapTests.cs @@ -0,0 +1,102 @@ +/* + * 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 System.IO; +using System.Reflection; +using System.Threading; +using log4net.Config; +using NUnit.Framework; +using OpenMetaverse; +using OpenMetaverse.Assets; +using OpenSim.Framework; +using OpenSim.Region.CoreModules.World.Media.Moap; +using OpenSim.Region.Framework.Scenes; +using OpenSim.Region.Framework.Scenes.Serialization; +using OpenSim.Tests.Common; + +namespace OpenSim.Region.CoreModules.World.Media.Moap.Tests +{ + [TestFixture] + public class MoapTests : OpenSimTestCase + { + protected TestScene m_scene; + protected MoapModule m_module; + + [SetUp] + public override void SetUp() + { + base.SetUp(); + + m_module = new MoapModule(); + m_scene = new SceneHelpers().SetupScene(); + SceneHelpers.SetupSceneModules(m_scene, m_module); + } + + [Test] + public void TestClearMediaUrl() + { + TestHelpers.InMethod(); +// log4net.Config.XmlConfigurator.Configure(); + + SceneObjectPart part = SceneHelpers.AddSceneObject(m_scene).RootPart; + MediaEntry me = new MediaEntry(); + + m_module.SetMediaEntry(part, 1, me); + m_module.ClearMediaEntry(part, 1); + + Assert.That(part.Shape.Media[1], Is.EqualTo(null)); + + // Although we've cleared one face, other faces may still be present. So we need to check for an + // update media url version + Assert.That(part.MediaUrl, Is.EqualTo("x-mv:0000000002/" + UUID.Zero)); + + // By changing media flag to false, the face texture once again becomes identical to the DefaultTexture. + // Therefore, when libOMV reserializes it, it disappears and we are left with no face texture in this slot. + // Not at all confusing, eh? + Assert.That(part.Shape.Textures.FaceTextures[1], Is.Null); + } + + [Test] + public void TestSetMediaUrl() + { + TestHelpers.InMethod(); + + string homeUrl = "opensimulator.org"; + + SceneObjectPart part = SceneHelpers.AddSceneObject(m_scene).RootPart; + MediaEntry me = new MediaEntry() { HomeURL = homeUrl }; + + m_module.SetMediaEntry(part, 1, me); + + Assert.That(part.Shape.Media[1].HomeURL, Is.EqualTo(homeUrl)); + Assert.That(part.MediaUrl, Is.EqualTo("x-mv:0000000001/" + UUID.Zero)); + Assert.That(part.Shape.Textures.FaceTextures[1].MediaFlags, Is.True); + } + } +} \ No newline at end of file diff --git a/Tests/OpenSim.Region.CoreModules.Tests/World/Serialiser/Tests/SerialiserTests.cs b/Tests/OpenSim.Region.CoreModules.Tests/World/Serialiser/Tests/SerialiserTests.cs new file mode 100644 index 00000000000..aba520edd21 --- /dev/null +++ b/Tests/OpenSim.Region.CoreModules.Tests/World/Serialiser/Tests/SerialiserTests.cs @@ -0,0 +1,884 @@ +/* + * 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 OpenSim 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.Collections.Generic; +using System.IO; +using System.Text; +using System.Xml; +using log4net.Config; +using NUnit.Framework; +using OpenMetaverse; +using OpenSim.Framework; +using OpenSim.Region.Framework.Scenes; +using OpenSim.Region.Framework.Scenes.Serialization; +using OpenSim.Tests.Common; +using OpenMetaverse.StructuredData; + +namespace OpenSim.Region.CoreModules.World.Serialiser.Tests +{ + [TestFixture] + public class SerialiserTests : OpenSimTestCase + { + private const string ObjectRootPartStubXml = +@" + + + false + a6dacf01-4636-4bb9-8a97-30609438af9d + e6a5a05e-e8cc-4816-8701-04165e335790 + 1 + + 0 + e6a5a05e-e8cc-4816-8701-04165e335790 + 2698615125 + PrimMyRide + 0 + false + 1099511628032000 + 0 + 147.2392.69822.78084 + 000 + -4.371139E-08-1-4.371139E-080 + 000 + 000 + 000 + 000 + + + + + + 0 + 0 + + 1 + AAAAAAAAERGZmQAAAAAABQCVlZUAAAAAQEAAAABAQAAAAAAAAAAAAAAAAAAAAA== + AA== + 0 + 16 + 0 + 0 + 0 + 100 + 100 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 9 + 0 + 0 + 0 + 10100.5 + 0 + Square + Same + 00000000-0000-0000-0000-000000000000 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 1 + false + false + false + + 10100.5 + 0 + 0001 + 000 + 000 + 0001 + 0 + 1211330445 + 0 + 0 + 0 + 0 + 00000000-0000-0000-0000-000000000000 + a6dacf01-4636-4bb9-8a97-30609438af9d + a6dacf01-4636-4bb9-8a97-30609438af9d + 2147483647 + 2147483647 + 0 + 0 + 2147483647 + None + 00000000-0000-0000-0000-000000000000 + 0 + + + + MyNamespace + + MyStore + + the answer + 42 + + + + + + + "; + + private const string ObjectWithNoOtherPartsXml = ObjectRootPartStubXml + +@" + +"; + + private const string ObjectWithOtherPartsXml = ObjectRootPartStubXml + +@" + + + + false + a6dacf01-4636-4bb9-8a97-30609438af9d + 9958feb1-02a6-49e4-a4ce-eba6f578ee13 + 3 + 9958feb1-02a6-49e4-a4ce-eba6f578ee13 + 1154704500 + Alien Head 1 + 3 + false + false + 21990232560640000 + 0 + 125.5655127.34622.48036 + -0.21719360.10839840.0009994507 + -0.51221060.4851225-0.49574540.5064908 + 000 + 000 + 000 + (No Description) + 000255 + + + + 253 + 0 + + 5 + Vw3dpvgTRUOiIUOGsnpWlAB/f38AAAAAgL8AAACAPwAAAAAAAAAF4ABAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AA== + 0 + 32 + 0 + 0 + 0 + 100 + 100 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 9 + 0 + 0 + 0 + 9 + 0 + HalfCircle + Same + 00000000-0000-0000-0000-000000000000 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 1 + false + false + false + + 0.11481950.01438910.02768878 + 0001 + 000 + 000 + 0001 + 1154704499 + 1256611042 + 0 + 10 + 0 + 0 + 00000000-0000-0000-0000-000000000000 + 7b2022f0-5f19-488c-b7e5-829d8f96b448 + 7b2022f0-5f19-488c-b7e5-829d8f96b448 + 647168 + 647168 + 0 + 0 + 581632 + None + 00000000-0000-0000-0000-000000000000 + 0 + 000 + + + -2 + -2 + -2 + -2 + -2 + + + + + false + a6dacf01-4636-4bb9-8a97-30609438af9d + 674b6b86-f5aa-439a-8e00-0d75bc08c80a + 3 + 674b6b86-f5aa-439a-8e00-0d75bc08c80a + 1154704501 + Alien Head 2 + 3 + false + false + 21990232560640000 + 0 + 125.5655127.34622.48036 + -0.24909970.085201260.0009002686 + -0.47653680.5194498-0.53013720.4712104 + 000 + 000 + 000 + (No Description) + 000255 + + + + 252 + 0 + + 0 + Vw3dpvgTRUOiIUOGsnpWlAB/f38AAAAAgL8AAACAPwAAAAAAAAAF4ABAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AA== + 0 + 32 + 0 + 0 + 0 + 100 + 150 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 9 + 0 + 0 + 0 + 9 + 0 + Circle + Same + 00000000-0000-0000-0000-000000000000 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 1 + false + false + false + + 0.035743850.059580320.04764182 + 0001 + 000 + 000 + 0001 + 1154704499 + 1256611042 + 0 + 10 + 0 + 0 + 00000000-0000-0000-0000-000000000000 + 7b2022f0-5f19-488c-b7e5-829d8f96b448 + 7b2022f0-5f19-488c-b7e5-829d8f96b448 + 647168 + 647168 + 0 + 0 + 581632 + None + 00000000-0000-0000-0000-000000000000 + 0 + 000 + + + -2 + -2 + -2 + -2 + -2 + + + +"; + + private const string ObjectWithBadFloatsXml = @" + + + + false + a6dacf01-4636-4bb9-8a97-30609438af9d + e6a5a05e-e8cc-4816-8701-04165e335790 + 1 + + 0 + e6a5a05e-e8cc-4816-8701-04165e335790 + 2698615125 + NaughtyPrim + 0 + false + 1099511628032000 + 0 + 147.2392.69822.78084 + 000 + -4.371139E-08-1-4.371139E-080 + 000 + 000 + 000 + 000 + + + + + + 0 + 0 + + 1 + AAAAAAAAERGZmQAAAAAABQCVlZUAAAAAQEAAAABAQAAAAAAAAAAAAAAAAAAAAA== + AA== + 0 + 16 + 0 + 0 + 0 + 100 + 100 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 9 + 0 + 0 + 0 + 10100.5 + 0 + Square + Same + 00000000-0000-0000-0000-000000000000 + 0 + 0 + 0,5 + yo mamma + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 1 + false + false + false + + 10100.5 + 0 + 0001 + 000 + 000 + 0001 + 0 + 1211330445 + 0 + 0 + 0 + 0 + 00000000-0000-0000-0000-000000000000 + a6dacf01-4636-4bb9-8a97-30609438af9d + a6dacf01-4636-4bb9-8a97-30609438af9d + 2147483647 + 2147483647 + 0 + 0 + 2147483647 + None + 00000000-0000-0000-0000-000000000000 + 0 + + + + "; + + private const string ObjectWithNoPartsXml2 = @" + + + b46ef588-411e-4a8b-a284-d7dcfe8e74ef + 9be68fdd-f740-4a0f-9675-dfbbb536b946 + 0 + + 0 + 9be68fdd-f740-4a0f-9675-dfbbb536b946 + 720005 + PrimFun + 0 + 1099511628032000 + 0 + 153.9854121.490862.21781 + 000 + 0001 + 000 + 000 + 000 + 000 + + + + + + 0 + 0 + + 0 + 16 + 0 + 0 + 0 + 200 + 200 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 9 + 0 + 0 + 0 + 1.2831315.9038584.266288 + 0 + Circle + Same + 0 + iVVnRyTLQ+2SC0fK7RVGXwJ6yc/SU4RDA5nhJbLUw3R1AAAAAAAAaOw8QQOhPSRAAKE9JEAAAAAAAAAAAAAAAAAAAAA= + AA== + + 1.2831315.9038584.266288 + 0 + 0001 + 000 + 000 + 0010 + 0 + 1216066902 + 0 + 0 + 0 + 0 + 00000000-0000-0000-0000-000000000000 + b46ef588-411e-4a8b-a284-d7dcfe8e74ef + b46ef588-411e-4a8b-a284-d7dcfe8e74ef + 2147483647 + 2147483647 + 0 + 0 + 2147483647 + None + + + + MyNamespace + + MyStore + + last words + Rosebud + + + + + + 00000000-0000-0000-0000-000000000000 + + + "; + + protected Scene m_scene; + protected SerialiserModule m_serialiserModule; + + [OneTimeSetUp] + public void Init() + { + m_serialiserModule = new SerialiserModule(); + m_scene = new SceneHelpers().SetupScene(); + SceneHelpers.SetupSceneModules(m_scene, m_serialiserModule); + } + + [Test] + public void TestDeserializeXmlObjectWithNoOtherParts() + { + TestHelpers.InMethod(); + TestHelpers.EnableLogging(); + + SceneObjectGroup so = SceneObjectSerializer.FromOriginalXmlFormat(ObjectWithNoOtherPartsXml); + SceneObjectPart rootPart = so.RootPart; + + Assert.That(rootPart.UUID, Is.EqualTo(new UUID("e6a5a05e-e8cc-4816-8701-04165e335790"))); + Assert.That(rootPart.CreatorID, Is.EqualTo(new UUID("a6dacf01-4636-4bb9-8a97-30609438af9d"))); + Assert.That(rootPart.Name, Is.EqualTo("PrimMyRide")); + OSDMap store = rootPart.DynAttrs.GetStore("MyNamespace", "MyStore"); + Assert.AreEqual(42, store["the answer"].AsInteger()); + + // TODO: Check other properties + } + + [Test] + public void TestDeserializeXmlObjectWithOtherParts() + { + TestHelpers.InMethod(); + TestHelpers.EnableLogging(); + + SceneObjectGroup so = SceneObjectSerializer.FromOriginalXmlFormat(ObjectWithOtherPartsXml); + SceneObjectPart[] parts = so.Parts; + Assert.AreEqual(3, so.Parts.Length); + + { + SceneObjectPart part = parts[0]; + + Assert.That(part.UUID, Is.EqualTo(new UUID("e6a5a05e-e8cc-4816-8701-04165e335790"))); + Assert.That(part.CreatorID, Is.EqualTo(new UUID("a6dacf01-4636-4bb9-8a97-30609438af9d"))); + Assert.That(part.Name, Is.EqualTo("PrimMyRide")); + OSDMap store = part.DynAttrs.GetStore("MyNamespace", "MyStore"); + Assert.AreEqual(42, store["the answer"].AsInteger()); + } + + { + SceneObjectPart part = parts[1]; + + Assert.That(part.UUID, Is.EqualTo(new UUID("9958feb1-02a6-49e4-a4ce-eba6f578ee13"))); + Assert.That(part.CreatorID, Is.EqualTo(new UUID("a6dacf01-4636-4bb9-8a97-30609438af9d"))); + Assert.That(part.Name, Is.EqualTo("Alien Head 1")); + } + + { + SceneObjectPart part = parts[2]; + + Assert.That(part.UUID, Is.EqualTo(new UUID("674b6b86-f5aa-439a-8e00-0d75bc08c80a"))); + Assert.That(part.CreatorID, Is.EqualTo(new UUID("a6dacf01-4636-4bb9-8a97-30609438af9d"))); + Assert.That(part.Name, Is.EqualTo("Alien Head 2")); + } + + // TODO: Check other properties + } + + [Test] + public void TestDeserializeBadFloatsXml() + { + TestHelpers.InMethod(); +// log4net.Config.XmlConfigurator.Configure(); + + SceneObjectGroup so = SceneObjectSerializer.FromOriginalXmlFormat(ObjectWithBadFloatsXml); + SceneObjectPart rootPart = so.RootPart; + + Assert.That(rootPart.UUID, Is.EqualTo(new UUID("e6a5a05e-e8cc-4816-8701-04165e335790"))); + Assert.That(rootPart.CreatorID, Is.EqualTo(new UUID("a6dacf01-4636-4bb9-8a97-30609438af9d"))); + Assert.That(rootPart.Name, Is.EqualTo("NaughtyPrim")); + + // This terminates the deserialization earlier if couldn't be parsed. + // TODO: Need to address this + Assert.That(rootPart.GroupPosition.X, Is.EqualTo(147.23f)); + + Assert.That(rootPart.Shape.PathCurve, Is.EqualTo(16)); + + // Defaults for bad parses + Assert.That(rootPart.Shape.FlexiTension, Is.EqualTo(0)); + Assert.That(rootPart.Shape.FlexiDrag, Is.EqualTo(0)); + + // TODO: Check other properties + } + + [Test] + public void TestSerializeXml() + { + TestHelpers.InMethod(); + //log4net.Config.XmlConfigurator.Configure(); + + string rpName = "My Little Donkey"; + UUID rpUuid = UUID.Parse("00000000-0000-0000-0000-000000000964"); + UUID rpCreatorId = UUID.Parse("00000000-0000-0000-0000-000000000915"); + PrimitiveBaseShape shape = PrimitiveBaseShape.CreateSphere(); +// Vector3 groupPosition = new Vector3(10, 20, 30); +// Quaternion rotationOffset = new Quaternion(20, 30, 40, 50); +// Vector3 offsetPosition = new Vector3(5, 10, 15); + + SceneObjectPart rp = new SceneObjectPart(); + rp.UUID = rpUuid; + rp.Name = rpName; + rp.CreatorID = rpCreatorId; + rp.Shape = shape; + + string daNamespace = "MyNamespace"; + string daStoreName = "MyStore"; + string daKey = "foo"; + string daValue = "bar"; + OSDMap myStore = new OSDMap(); + myStore.Add(daKey, daValue); + rp.DynAttrs = new DAMap(); + rp.DynAttrs.SetStore(daNamespace, daStoreName, myStore); + + SceneObjectGroup so = new SceneObjectGroup(rp); + + // Need to add the object to the scene so that the request to get script state succeeds + m_scene.AddSceneObject(so); + + string xml = SceneObjectSerializer.ToOriginalXmlFormat(so); + + XmlTextReader xtr = new XmlTextReader(new StringReader(xml)); + xtr.DtdProcessing = DtdProcessing.Ignore; + xtr.ReadStartElement("SceneObjectGroup"); + xtr.ReadStartElement("RootPart"); + xtr.ReadStartElement("SceneObjectPart"); + + UUID uuid = UUID.Zero; + string name = null; + UUID creatorId = UUID.Zero; + DAMap daMap = null; + + while (xtr.Read() && xtr.Name != "SceneObjectPart") + { + if (xtr.NodeType != XmlNodeType.Element) + continue; + + switch (xtr.Name) + { + case "UUID": + xtr.ReadStartElement("UUID"); + try + { + uuid = UUID.Parse(xtr.ReadElementString("UUID")); + xtr.ReadEndElement(); + } + catch { } // ignore everything but ... + break; + case "Name": + name = xtr.ReadElementContentAsString(); + break; + case "CreatorID": + xtr.ReadStartElement("CreatorID"); + creatorId = UUID.Parse(xtr.ReadElementString("UUID")); + xtr.ReadEndElement(); + break; + case "DynAttrs": + daMap = new DAMap(); + daMap.ReadXml(xtr); + break; + } + } + + xtr.ReadEndElement(); + xtr.ReadEndElement(); + xtr.ReadStartElement("OtherParts"); + xtr.ReadEndElement(); + xtr.Close(); + + // TODO: More checks + Assert.That(uuid, Is.EqualTo(rpUuid)); + Assert.That(name, Is.EqualTo(rpName)); + Assert.That(creatorId, Is.EqualTo(rpCreatorId)); + Assert.NotNull(daMap); + Assert.AreEqual(daValue, daMap.GetStore(daNamespace, daStoreName)[daKey].AsString()); + } + + [Test] + public void TestDeserializeXml2() + { + TestHelpers.InMethod(); + //log4net.Config.XmlConfigurator.Configure(); + + SceneObjectGroup so = m_serialiserModule.DeserializeGroupFromXml2(ObjectWithNoPartsXml2); + SceneObjectPart rootPart = so.RootPart; + + Assert.That(rootPart.UUID, Is.EqualTo(new UUID("9be68fdd-f740-4a0f-9675-dfbbb536b946"))); + Assert.That(rootPart.CreatorID, Is.EqualTo(new UUID("b46ef588-411e-4a8b-a284-d7dcfe8e74ef"))); + Assert.That(rootPart.Name, Is.EqualTo("PrimFun")); + OSDMap store = rootPart.DynAttrs.GetStore("MyNamespace", "MyStore"); + Assert.AreEqual("Rosebud", store["last words"].AsString()); + + // TODO: Check other properties + } + + [Test] + public void TestSerializeXml2() + { + TestHelpers.InMethod(); + //log4net.Config.XmlConfigurator.Configure(); + + string rpName = "My Little Pony"; + UUID rpUuid = UUID.Parse("00000000-0000-0000-0000-000000000064"); + UUID rpCreatorId = UUID.Parse("00000000-0000-0000-0000-000000000015"); + PrimitiveBaseShape shape = PrimitiveBaseShape.CreateSphere(); +// Vector3 groupPosition = new Vector3(10, 20, 30); +// Quaternion rotationOffset = new Quaternion(20, 30, 40, 50); +// Vector3 offsetPosition = new Vector3(5, 10, 15); + + SceneObjectPart rp = new SceneObjectPart(); + rp.UUID = rpUuid; + rp.Name = rpName; + rp.CreatorID = rpCreatorId; + rp.Shape = shape; + + string daNamespace = "MyNamespace"; + string daStoreName = "MyStore"; + string daKey = "foo"; + string daValue = "bar"; + OSDMap myStore = new OSDMap(); + myStore.Add(daKey, daValue); + rp.DynAttrs = new DAMap(); + rp.DynAttrs.SetStore(daNamespace, daStoreName, myStore); + + SceneObjectGroup so = new SceneObjectGroup(rp); + + // Need to add the object to the scene so that the request to get script state succeeds + m_scene.AddSceneObject(so); + + Dictionary options = new Dictionary(); + options["old-guids"] = true; + string xml2 = m_serialiserModule.SerializeGroupToXml2(so, options); + + XmlTextReader xtr = new XmlTextReader(new StringReader(xml2)); + xtr.DtdProcessing = DtdProcessing.Ignore; + xtr.ReadStartElement("SceneObjectGroup"); + xtr.ReadStartElement("SceneObjectPart"); + + UUID uuid = UUID.Zero; + string name = null; + UUID creatorId = UUID.Zero; + DAMap daMap = null; + + while (xtr.Read() && xtr.Name != "SceneObjectPart") + { + if (xtr.NodeType != XmlNodeType.Element) + continue; + + switch (xtr.Name) + { + case "UUID": + xtr.ReadStartElement("UUID"); + uuid = UUID.Parse(xtr.ReadElementString("Guid")); + xtr.ReadEndElement(); + break; + case "Name": + name = xtr.ReadElementContentAsString(); + break; + case "CreatorID": + xtr.ReadStartElement("CreatorID"); + creatorId = UUID.Parse(xtr.ReadElementString("Guid")); + xtr.ReadEndElement(); + break; + case "DynAttrs": + daMap = new DAMap(); + daMap.ReadXml(xtr); + break; + } + } + + xtr.ReadEndElement(); + xtr.ReadStartElement("OtherParts"); + xtr.ReadEndElement(); + xtr.Close(); + + // TODO: More checks + Assert.That(uuid, Is.EqualTo(rpUuid)); + Assert.That(name, Is.EqualTo(rpName)); + Assert.That(creatorId, Is.EqualTo(rpCreatorId)); + Assert.NotNull(daMap); + Assert.AreEqual(daValue, daMap.GetStore(daNamespace, daStoreName)[daKey].AsString()); + } + } +} \ No newline at end of file diff --git a/Tests/OpenSim.Region.CoreModules.Tests/World/Terrain/Tests/TerrainModuleTests.cs b/Tests/OpenSim.Region.CoreModules.Tests/World/Terrain/Tests/TerrainModuleTests.cs new file mode 100644 index 00000000000..9a679662f3b --- /dev/null +++ b/Tests/OpenSim.Region.CoreModules.Tests/World/Terrain/Tests/TerrainModuleTests.cs @@ -0,0 +1,75 @@ +/* + * 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 NUnit.Framework; +using OpenSim.Framework; +using OpenSim.Region.CoreModules.World.Terrain; +using OpenSim.Region.Framework.Scenes; +using OpenSim.Tests.Common; + +namespace OpenSim.Region.CoreModules.Terrain.Tests +{ + public class TerrainModuleTests : OpenSimTestCase + { + [Test] + public void TestTerrainFill() + { + TestHelpers.InMethod(); +// TestHelpers.EnableLogging(); + + //UUID userId = TestHelpers.ParseTail(0x1); + + TerrainModule tm = new TerrainModule(); + Scene scene = new SceneHelpers().SetupScene(); + SceneHelpers.SetupSceneModules(scene, tm); + + // Fillheight of 30 + { + float fillHeight = 30; + + tm.InterfaceFillTerrain(new object[] { fillHeight }); + + float height = scene.Heightmap[128, 128]; + + Assert.AreEqual(fillHeight, height); + } + + // Max fillheight of 30 + // According to http://wiki.secondlife.com/wiki/Tips_for_Creating_Heightfields_and_Details_on_Terrain_RAW_Files#Notes_for_Creating_Height_Field_Maps_for_Second_Life + { + float fillHeight = 508; + + tm.InterfaceFillTerrain(new object[] { fillHeight }); + + float height = scene.Heightmap[128, 128]; + + Assert.AreEqual(fillHeight, height); + } + } + } +} \ No newline at end of file diff --git a/Tests/OpenSim.Region.CoreModules.Tests/World/Terrain/Tests/TerrainTest.cs b/Tests/OpenSim.Region.CoreModules.Tests/World/Terrain/Tests/TerrainTest.cs new file mode 100644 index 00000000000..e5e2e5ed17c --- /dev/null +++ b/Tests/OpenSim.Region.CoreModules.Tests/World/Terrain/Tests/TerrainTest.cs @@ -0,0 +1,119 @@ +/* + * 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 NUnit.Framework; +using OpenSim.Framework; +using OpenSim.Region.CoreModules.World.Terrain.PaintBrushes; +using OpenSim.Region.Framework.Scenes; +using OpenSim.Tests.Common; + +namespace OpenSim.Region.CoreModules.World.Terrain.Tests +{ + [TestFixture] + public class TerrainTest : OpenSimTestCase + { + [Test] + public void BrushTest() + { + int midRegion = (int)Constants.RegionSize / 2; + + // Create a mask that covers only the left half of the region + bool[,] allowMask = new bool[(int)Constants.RegionSize, 256]; + int x; + int y; + for (x = 0; x < midRegion; x++) + { + for (y = 0; y < (int)Constants.RegionSize; y++) + { + allowMask[x,y] = true; + } + } + + // + // Test RaiseSphere + // + TerrainChannel map = new TerrainChannel((int)Constants.RegionSize, (int)Constants.RegionSize); + ITerrainPaintableEffect effect = new RaiseSphere(); + + effect.PaintEffect(map, allowMask, midRegion, midRegion, -1.0f, 5, 6.0f, + 0, midRegion - 1,0, (int)Constants.RegionSize -1); + Assert.That(map[127, midRegion] > 0.0, "Raise brush should raising value at this point (127,128)."); + Assert.That(map[124, midRegion] > 0.0, "Raise brush should raising value at this point (124,128)."); + Assert.That(map[120, midRegion] == 0.0, "Raise brush should not change value at this point (120,128)."); + Assert.That(map[128, midRegion] == 0.0, "Raise brush should not change value at this point (128,128)."); +// Assert.That(map[0, midRegion] == 0.0, "Raise brush should not change value at this point (0,128)."); + // + // Test LowerSphere + // + map = new TerrainChannel((int)Constants.RegionSize, (int)Constants.RegionSize); + for (x=0; x= 0.0, "Lower should not lowering value below 0.0 at this point (127,128)."); + Assert.That(map[127, midRegion] == 0.0, "Lower brush should lowering value to 0.0 at this point (127,128)."); + Assert.That(map[125, midRegion] < 1.0, "Lower brush should lowering value at this point (124,128)."); + Assert.That(map[120, midRegion] == 1.0, "Lower brush should not change value at this point (120,128)."); + Assert.That(map[128, midRegion] == 1.0, "Lower brush should not change value at this point (128,128)."); +// Assert.That(map[0, midRegion] == 1.0, "Lower brush should not change value at this point (0,128)."); + } + + [Test] + public void TerrainChannelTest() + { + TerrainChannel x = new TerrainChannel((int)Constants.RegionSize, (int)Constants.RegionSize); + Assert.That(x[0, 0] == 0.0, "Terrain not initialising correctly."); + + x[0, 0] = 1.0f; + Assert.That(x[0, 0] == 1.0, "Terrain not setting values correctly."); + + x[0, 0] = 0; + x[0, 0] += 5.0f; + x[0, 0] -= 1.0f; + Assert.That(x[0, 0] == 4.0f, "Terrain addition/subtraction error."); + + x[0, 0] = 1.0f; + float[] floatsExport = x.GetFloatsSerialised(); + Assert.That(floatsExport[0] == 1.0f, "Export to float[] not working correctly."); + + x[0, 0] = 1.0f; + Assert.That(x.Tainted(0, 0), "Terrain channel tainting not working correctly."); + + TerrainChannel y = x.Copy(); + Assert.That(!ReferenceEquals(x, y), "Terrain copy not duplicating correctly."); + Assert.That(!ReferenceEquals(x.GetDoubles(), y.GetDoubles()), "Terrain array not duplicating correctly."); + } + } +} diff --git a/Tests/OpenSim.Region.Framework.Tests/OpenSim.Region.Framework.Tests.csproj b/Tests/OpenSim.Region.Framework.Tests/OpenSim.Region.Framework.Tests.csproj new file mode 100644 index 00000000000..adac462be4d --- /dev/null +++ b/Tests/OpenSim.Region.Framework.Tests/OpenSim.Region.Framework.Tests.csproj @@ -0,0 +1,189 @@ + + + net6.0 + + + + ..\..\..\bin\Nini.dll + False + + + ..\..\..\bin\OpenMetaverse.dll + False + + + ..\..\..\bin\OpenMetaverseTypes.dll + False + + + False + + + False + + + ..\..\..\bin\XMLRPC.dll + False + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Tests/OpenSim.Region.Framework.Tests/Scenes/Tests/EntityManagerTests.cs b/Tests/OpenSim.Region.Framework.Tests/Scenes/Tests/EntityManagerTests.cs new file mode 100644 index 00000000000..fa698a9e683 --- /dev/null +++ b/Tests/OpenSim.Region.Framework.Tests/Scenes/Tests/EntityManagerTests.cs @@ -0,0 +1,177 @@ +/* + * 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.Reflection; +using System.Threading; +using System.Text; +using System.Collections.Generic; +using Nini.Config; +using NUnit.Framework; +using OpenMetaverse; +using OpenSim.Framework; +using OpenSim.Region.Framework.Scenes; +using OpenSim.Tests.Common; + +namespace OpenSim.Region.Framework.Scenes.Tests +{ + [TestFixture, LongRunning] + public class EntityManagerTests : OpenSimTestCase + { + static public Random random; + SceneObjectGroup found; + Scene scene = new SceneHelpers().SetupScene(); + + [Test] + public void T010_AddObjects() + { + TestHelpers.InMethod(); + + random = new Random(); + SceneObjectGroup found; + EntityManager entman = new EntityManager(); + SceneObjectGroup sog = NewSOG(); + UUID obj1 = sog.UUID; + uint li1 = sog.LocalId; + entman.Add(sog); + sog = NewSOG(); + UUID obj2 = sog.UUID; + uint li2 = sog.LocalId; + entman.Add(sog); + + found = (SceneObjectGroup)entman[obj1]; + Assert.That(found.UUID ,Is.EqualTo(obj1)); + found = (SceneObjectGroup)entman[li1]; + Assert.That(found.UUID ,Is.EqualTo(obj1)); + found = (SceneObjectGroup)entman[obj2]; + Assert.That(found.UUID ,Is.EqualTo(obj2)); + found = (SceneObjectGroup)entman[li2]; + Assert.That(found.UUID ,Is.EqualTo(obj2)); + + entman.Remove(obj1); + entman.Remove(li2); + + Assert.That(entman.ContainsKey(obj1), Is.False); + Assert.That(entman.ContainsKey(li1), Is.False); + Assert.That(entman.ContainsKey(obj2), Is.False); + Assert.That(entman.ContainsKey(li2), Is.False); + } + + [Test] + public void T011_ThreadAddRemoveTest() + { + TestHelpers.InMethod(); + + // This test adds and removes with mutiple threads, attempting to break the + // uuid and localid dictionary coherence. + EntityManager entman = new EntityManager(); + SceneObjectGroup sog = NewSOG(); + for (int j=0; j<20; j++) + { + List trdlist = new List(); + + for (int i=0; i<4; i++) + { + // Adds scene object + NewTestThreads test = new NewTestThreads(entman,sog); + Thread start = new Thread(new ThreadStart(test.TestAddSceneObject)); + start.Start(); + trdlist.Add(start); + + // Removes it + test = new NewTestThreads(entman,sog); + start = new Thread(new ThreadStart(test.TestRemoveSceneObject)); + start.Start(); + trdlist.Add(start); + } + foreach (Thread thread in trdlist) + { + thread.Join(); + } + if (entman.ContainsKey(sog.UUID) || entman.ContainsKey(sog.LocalId)) { + found = (SceneObjectGroup)entman[sog.UUID]; + Assert.That(found.UUID,Is.EqualTo(sog.UUID)); + found = (SceneObjectGroup)entman[sog.LocalId]; + Assert.That(found.UUID,Is.EqualTo(sog.UUID)); + } + } + } + + private SceneObjectGroup NewSOG() + { + SceneObjectPart sop = new SceneObjectPart(UUID.Random(), PrimitiveBaseShape.Default, Vector3.Zero, Quaternion.Identity, Vector3.Zero); + sop.Name = RandomName(); + sop.Description = sop.Name; + sop.Text = RandomName(); + sop.SitName = RandomName(); + sop.TouchName = RandomName(); + sop.Flags |= PrimFlags.Phantom; + + SceneObjectGroup sog = new SceneObjectGroup(sop); + scene.AddNewSceneObject(sog, false); + + return sog; + } + + private static string RandomName() + { + StringBuilder name = new StringBuilder(); + int size = random.Next(40,80); + char ch ; + for (int i=0; i + /// Basic scene object tests (create, read and delete but not update). + /// + [TestFixture] + public class SceneObjectBasicTests : OpenSimTestCase + { +// [TearDown] +// public void TearDown() +// { +// Console.WriteLine("TearDown"); +// GC.Collect(); +// Thread.Sleep(3000); +// } + +// public class GcNotify +// { +// public static AutoResetEvent gcEvent = new AutoResetEvent(false); +// private static bool _initialized = false; +// +// public static void Initialize() +// { +// if (!_initialized) +// { +// _initialized = true; +// new GcNotify(); +// } +// } +// +// private GcNotify(){} +// +// ~GcNotify() +// { +// if (!Environment.HasShutdownStarted && +// !AppDomain.CurrentDomain.IsFinalizingForUnload()) +// { +// Console.WriteLine("GcNotify called"); +// gcEvent.Set(); +// new GcNotify(); +// } +// } +// } + + /// + /// Test adding an object to a scene. + /// + [Test] + public void TestAddSceneObject() + { + TestHelpers.InMethod(); + + Scene scene = new SceneHelpers().SetupScene(); + int partsToTestCount = 3; + + SceneObjectGroup so + = SceneHelpers.CreateSceneObject(partsToTestCount, TestHelpers.ParseTail(0x1), "obj1", 0x10); + SceneObjectPart[] parts = so.Parts; + + Assert.That(scene.AddNewSceneObject(so, false), Is.True); + SceneObjectGroup retrievedSo = scene.GetSceneObjectGroup(so.UUID); + SceneObjectPart[] retrievedParts = retrievedSo.Parts; + + //m_log.Debug("retrievedPart : {0}", retrievedPart); + // If the parts have the same UUID then we will consider them as one and the same + Assert.That(retrievedSo.PrimCount, Is.EqualTo(partsToTestCount)); + + for (int i = 0; i < partsToTestCount; i++) + { + Assert.That(retrievedParts[i].Name, Is.EqualTo(parts[i].Name)); + Assert.That(retrievedParts[i].UUID, Is.EqualTo(parts[i].UUID)); + } + } + + [Test] + /// + /// It shouldn't be possible to add a scene object if one with that uuid already exists in the scene. + /// + public void TestAddExistingSceneObjectUuid() + { + TestHelpers.InMethod(); + + Scene scene = new SceneHelpers().SetupScene(); + + string obj1Name = "Alfred"; + string obj2Name = "Betty"; + UUID objUuid = new UUID("00000000-0000-0000-0000-000000000001"); + + SceneObjectPart part1 + = new SceneObjectPart(UUID.Zero, PrimitiveBaseShape.Default, Vector3.Zero, Quaternion.Identity, Vector3.Zero) + { Name = obj1Name, UUID = objUuid }; + + Assert.That(scene.AddNewSceneObject(new SceneObjectGroup(part1), false), Is.True); + + SceneObjectPart part2 + = new SceneObjectPart(UUID.Zero, PrimitiveBaseShape.Default, Vector3.Zero, Quaternion.Identity, Vector3.Zero) + { Name = obj2Name, UUID = objUuid }; + + Assert.That(scene.AddNewSceneObject(new SceneObjectGroup(part2), false), Is.False); + + SceneObjectPart retrievedPart = scene.GetSceneObjectPart(objUuid); + + //m_log.Debug("retrievedPart : {0}", retrievedPart); + // If the parts have the same UUID then we will consider them as one and the same + Assert.That(retrievedPart.Name, Is.EqualTo(obj1Name)); + Assert.That(retrievedPart.UUID, Is.EqualTo(objUuid)); + } + + /// + /// Test retrieving a scene object via the local id of one of its parts. + /// + [Test] + public void TestGetSceneObjectByPartLocalId() + { + TestHelpers.InMethod(); + + Scene scene = new SceneHelpers().SetupScene(); + int partsToTestCount = 3; + + SceneObjectGroup so + = SceneHelpers.CreateSceneObject(partsToTestCount, TestHelpers.ParseTail(0x1), "obj1", 0x10); + SceneObjectPart[] parts = so.Parts; + + scene.AddNewSceneObject(so, false); + + // Test getting via the root part's local id + Assert.That(scene.GetGroupByPrim(so.LocalId), Is.Not.Null); + + // Test getting via a non root part's local id + Assert.That(scene.GetGroupByPrim(parts[partsToTestCount - 1].LocalId), Is.Not.Null); + + // Test that we don't get back an object for a local id that doesn't exist + Assert.That(scene.GetGroupByPrim(999), Is.Null); + + uint soid = so.LocalId; + uint spid = parts[partsToTestCount - 1].LocalId; + + // Now delete the scene object and check again + scene.DeleteSceneObject(so, false); + + Assert.That(scene.GetGroupByPrim(soid), Is.Null); + Assert.That(scene.GetGroupByPrim(spid), Is.Null); + } + + /// + /// Test deleting an object from a scene. + /// + /// + /// This is the most basic form of delete. For all more sophisticated forms of derez (done asynchrnously + /// and where object can be taken to user inventory, etc.), see SceneObjectDeRezTests. + /// + [Test] + public void TestDeleteSceneObject() + { + TestHelpers.InMethod(); + + TestScene scene = new SceneHelpers().SetupScene(); + SceneObjectGroup so = SceneHelpers.AddSceneObject(scene); + + Assert.That(so.IsDeleted, Is.False); + uint retrievedPartID = so.LocalId; + + scene.DeleteSceneObject(so, false); + + SceneObjectPart retrievedPart = scene.GetSceneObjectPart(retrievedPartID); + + Assert.That(retrievedPart, Is.Null); + } + + /// + /// Changing a scene object uuid changes the root part uuid. This is a valid operation if the object is not + /// in a scene and is useful if one wants to supply a UUID directly rather than use the one generated by + /// OpenSim. + /// + [Test] + public void TestChangeSceneObjectUuid() + { + string rootPartName = "rootpart"; + UUID rootPartUuid = new UUID("00000000-0000-0000-0000-000000000001"); + string childPartName = "childPart"; + UUID childPartUuid = new UUID("00000000-0000-0000-0001-000000000000"); + + SceneObjectPart rootPart + = new SceneObjectPart(UUID.Zero, PrimitiveBaseShape.Default, Vector3.Zero, Quaternion.Identity, Vector3.Zero) + { Name = rootPartName, UUID = rootPartUuid }; + SceneObjectPart linkPart + = new SceneObjectPart(UUID.Zero, PrimitiveBaseShape.Default, Vector3.Zero, Quaternion.Identity, Vector3.Zero) + { Name = childPartName, UUID = childPartUuid }; + + SceneObjectGroup sog = new SceneObjectGroup(rootPart); + sog.AddPart(linkPart); + + Assert.That(sog.UUID, Is.EqualTo(rootPartUuid)); + Assert.That(sog.RootPart.UUID, Is.EqualTo(rootPartUuid)); + Assert.That(sog.Parts.Length, Is.EqualTo(2)); + + UUID newRootPartUuid = new UUID("00000000-0000-0000-0000-000000000002"); + sog.UUID = newRootPartUuid; + + Assert.That(sog.UUID, Is.EqualTo(newRootPartUuid)); + Assert.That(sog.RootPart.UUID, Is.EqualTo(newRootPartUuid)); + Assert.That(sog.Parts.Length, Is.EqualTo(2)); + } + } +} \ No newline at end of file diff --git a/Tests/OpenSim.Region.Framework.Tests/Scenes/Tests/SceneObjectCopyTests.cs b/Tests/OpenSim.Region.Framework.Tests/Scenes/Tests/SceneObjectCopyTests.cs new file mode 100644 index 00000000000..c27bc1a818d --- /dev/null +++ b/Tests/OpenSim.Region.Framework.Tests/Scenes/Tests/SceneObjectCopyTests.cs @@ -0,0 +1,348 @@ +/* + * 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 System.Reflection; +using Nini.Config; +using NUnit.Framework; +using OpenMetaverse; +using OpenSim.Framework; +using OpenSim.Region.CoreModules.Framework.EntityTransfer; +using OpenSim.Region.CoreModules.Framework.InventoryAccess; +using OpenSim.Region.CoreModules.ServiceConnectorsOut.Simulation; +using OpenSim.Region.CoreModules.World.Permissions; +using OpenSim.Region.Framework.Scenes; +using OpenSim.Services.Interfaces; +using OpenSim.Tests.Common; + +namespace OpenSim.Region.Framework.Scenes.Tests +{ + /* + /// + /// Test copying of scene objects. + /// + /// + /// This is at a level above the SceneObjectBasicTests, which act on the scene directly. + /// + [TestFixture] + public class SceneObjectCopyTests : OpenSimTestCase + { + [TestFixtureSetUp] + public void FixtureInit() + { + // Don't allow tests to be bamboozled by asynchronous events. Execute everything on the same thread. + // This facility was added after the original async delete tests were written, so it may be possible now + // to not bother explicitly disabling their async (since everything will be running sync). + 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] + public void TestTakeCopyWhenCopierIsOwnerWithPerms() + { + TestHelpers.InMethod(); +// TestHelpers.EnableLogging(); + + IConfigSource config = new IniConfigSource(); + config.AddConfig("Modules"); + config.Configs["Modules"].Set("InventoryAccessModule", "BasicInventoryAccessModule"); + + TestScene scene = new SceneHelpers().SetupScene("s1", TestHelpers.ParseTail(0x99), 1000, 1000, config); + SceneHelpers.SetupSceneModules(scene, config, new PermissionsModule(), new BasicInventoryAccessModule()); + UserAccount ua = UserAccountHelpers.CreateUserWithInventory(scene, TestHelpers.ParseTail(0x1)); + TestClient client = (TestClient)SceneHelpers.AddScenePresence(scene, ua.PrincipalID).ControllingClient; + + // Turn off the timer on the async sog deleter - we'll crank it by hand for this test. + AsyncSceneObjectGroupDeleter sogd = scene.SceneObjectGroupDeleter; + sogd.Enabled = false; + + SceneObjectGroup so = SceneHelpers.AddSceneObject(scene, "so1", ua.PrincipalID); + uint soLocalId = so.LocalId; +// so.UpdatePermissions( +// ua.PrincipalID, (byte)PermissionWho.Owner, so.LocalId, (uint)OpenMetaverse.PermissionMask.Copy, 1); +// so.UpdatePermissions( +// ua.PrincipalID, (byte)PermissionWho.Owner, so.LocalId, (uint)OpenMetaverse.PermissionMask.Transfer, 0); +// so.UpdatePermissions( +// ua.PrincipalID, (byte)PermissionWho.Base, so.LocalId, (uint)OpenMetaverse.PermissionMask.Transfer, 0); +// scene.HandleObjectPermissionsUpdate(client, client.AgentId, client.SessionId, (byte)PermissionWho.Owner, so.LocalId, (uint)OpenMetaverse.PermissionMask.Transfer, 0); + + // Ideally we might change these via client-focussed method calls as commented out above. However, this + // becomes very convoluted so we will set only the copy perm directly. + so.RootPart.BaseMask = (uint)OpenMetaverse.PermissionMask.Copy; +// so.RootPart.OwnerMask = (uint)OpenMetaverse.PermissionMask.Copy; + + List localIds = new List(); + localIds.Add(so.LocalId); + + // Specifying a UUID.Zero in this case will currently plop it in Lost and Found + scene.DeRezObjects(client, localIds, UUID.Zero, DeRezAction.TakeCopy, UUID.Zero); + + // Check that object isn't copied until we crank the sogd handle. + SceneObjectPart retrievedPart = scene.GetSceneObjectPart(so.LocalId); + Assert.That(retrievedPart, Is.Not.Null); + Assert.That(retrievedPart.ParentGroup.IsDeleted, Is.False); + + sogd.InventoryDeQueueAndDelete(); + + // Check that object is still there. + SceneObjectPart retrievedPart2 = scene.GetSceneObjectPart(so.LocalId); + Assert.That(retrievedPart2, Is.Not.Null); + Assert.That(client.ReceivedKills.Count, Is.EqualTo(0)); + + // Check that we have a copy in inventory + InventoryItemBase item + = UserInventoryHelpers.GetInventoryItem(scene.InventoryService, ua.PrincipalID, "Lost And Found/so1"); + Assert.That(item, Is.Not.Null); + } + + [Test] + public void TestTakeCopyWhenCopierIsOwnerWithoutPerms() + { + TestHelpers.InMethod(); +// TestHelpers.EnableLogging(); + + IConfigSource config = new IniConfigSource(); + config.AddConfig("Modules"); + config.Configs["Modules"].Set("InventoryAccessModule", "BasicInventoryAccessModule"); + + TestScene scene = new SceneHelpers().SetupScene("s1", TestHelpers.ParseTail(0x99), 1000, 1000, config); + SceneHelpers.SetupSceneModules(scene, config, new PermissionsModule(), new BasicInventoryAccessModule()); + UserAccount ua = UserAccountHelpers.CreateUserWithInventory(scene, TestHelpers.ParseTail(0x1)); + TestClient client = (TestClient)SceneHelpers.AddScenePresence(scene, ua.PrincipalID).ControllingClient; + + // Turn off the timer on the async sog deleter - we'll crank it by hand for this test. + AsyncSceneObjectGroupDeleter sogd = scene.SceneObjectGroupDeleter; + sogd.Enabled = false; + + SceneObjectGroup so = SceneHelpers.AddSceneObject(scene, "so1", ua.PrincipalID); + uint soLocalId = so.LocalId; + + so.RootPart.BaseMask = (uint)(OpenMetaverse.PermissionMask.All & ~OpenMetaverse.PermissionMask.Copy); + //so.RootPart.OwnerMask = (uint)(OpenMetaverse.PermissionMask.Copy & ~OpenMetaverse.PermissionMask.Copy); + + List localIds = new List(); + localIds.Add(so.LocalId); + + // Specifying a UUID.Zero in this case will currently plop it in Lost and Found + scene.DeRezObjects(client, localIds, UUID.Zero, DeRezAction.TakeCopy, UUID.Zero); + + // Check that object isn't copied until we crank the sogd handle. + SceneObjectPart retrievedPart = scene.GetSceneObjectPart(so.LocalId); + Assert.That(retrievedPart, Is.Not.Null); + Assert.That(retrievedPart.ParentGroup.IsDeleted, Is.False); + + sogd.InventoryDeQueueAndDelete(); + + // Check that object is still there. + SceneObjectPart retrievedPart2 = scene.GetSceneObjectPart(so.LocalId); + Assert.That(retrievedPart2, Is.Not.Null); + Assert.That(client.ReceivedKills.Count, Is.EqualTo(0)); + + // Check that we do not have a copy in inventory + InventoryItemBase item + = UserInventoryHelpers.GetInventoryItem(scene.InventoryService, ua.PrincipalID, "Lost And Found/so1"); + Assert.That(item, Is.Null); + } + + [Test] + public void TestTakeCopyWhenCopierIsNotOwnerWithPerms() + { + TestHelpers.InMethod(); +// TestHelpers.EnableLogging(); + + IConfigSource config = new IniConfigSource(); + config.AddConfig("Modules"); + config.Configs["Modules"].Set("InventoryAccessModule", "BasicInventoryAccessModule"); + + TestScene scene = new SceneHelpers().SetupScene("s1", TestHelpers.ParseTail(0x99), 1000, 1000, config); + SceneHelpers.SetupSceneModules(scene, config, new PermissionsModule(), new BasicInventoryAccessModule()); + UserAccount ua = UserAccountHelpers.CreateUserWithInventory(scene, TestHelpers.ParseTail(0x1)); + TestClient client = (TestClient)SceneHelpers.AddScenePresence(scene, ua.PrincipalID).ControllingClient; + + // Turn off the timer on the async sog deleter - we'll crank it by hand for this test. + AsyncSceneObjectGroupDeleter sogd = scene.SceneObjectGroupDeleter; + sogd.Enabled = false; + + SceneObjectGroup so = SceneHelpers.AddSceneObject(scene, "so1", TestHelpers.ParseTail(0x2)); + uint soLocalId = so.LocalId; + + // Base must allow transfer and copy + so.RootPart.BaseMask = (uint)(OpenMetaverse.PermissionMask.Copy | OpenMetaverse.PermissionMask.Transfer); + // Must be set so anyone can copy + so.RootPart.EveryoneMask = (uint)OpenMetaverse.PermissionMask.Copy; + + List localIds = new List(); + localIds.Add(so.LocalId); + + // Specifying a UUID.Zero in this case will plop it in the Objects folder + scene.DeRezObjects(client, localIds, UUID.Zero, DeRezAction.TakeCopy, UUID.Zero); + + // Check that object isn't copied until we crank the sogd handle. + SceneObjectPart retrievedPart = scene.GetSceneObjectPart(so.LocalId); + Assert.That(retrievedPart, Is.Not.Null); + Assert.That(retrievedPart.ParentGroup.IsDeleted, Is.False); + + sogd.InventoryDeQueueAndDelete(); + + // Check that object is still there. + SceneObjectPart retrievedPart2 = scene.GetSceneObjectPart(so.LocalId); + Assert.That(retrievedPart2, Is.Not.Null); + Assert.That(client.ReceivedKills.Count, Is.EqualTo(0)); + + // Check that we have a copy in inventory + InventoryItemBase item + = UserInventoryHelpers.GetInventoryItem(scene.InventoryService, ua.PrincipalID, "Objects/so1"); + Assert.That(item, Is.Not.Null); + } + + [Test] + public void TestTakeCopyWhenCopierIsNotOwnerWithoutPerms() + { + TestHelpers.InMethod(); +// TestHelpers.EnableLogging(); + + IConfigSource config = new IniConfigSource(); + config.AddConfig("Modules"); + config.Configs["Modules"].Set("InventoryAccessModule", "BasicInventoryAccessModule"); + + TestScene scene = new SceneHelpers().SetupScene("s1", TestHelpers.ParseTail(0x99), 1000, 1000, config); + SceneHelpers.SetupSceneModules(scene, config, new PermissionsModule(), new BasicInventoryAccessModule()); + UserAccount ua = UserAccountHelpers.CreateUserWithInventory(scene, TestHelpers.ParseTail(0x1)); + TestClient client = (TestClient)SceneHelpers.AddScenePresence(scene, ua.PrincipalID).ControllingClient; + + // Turn off the timer on the async sog deleter - we'll crank it by hand for this test. + AsyncSceneObjectGroupDeleter sogd = scene.SceneObjectGroupDeleter; + sogd.Enabled = false; + + SceneObjectGroup so = SceneHelpers.AddSceneObject(scene, "so1", TestHelpers.ParseTail(0x2)); + uint soLocalId = so.LocalId; + + { + // Check that object is not copied if copy base perms is missing. + // Should not allow copy if base does not have this. + so.RootPart.BaseMask = (uint)OpenMetaverse.PermissionMask.Transfer; + // Must be set so anyone can copy + so.RootPart.EveryoneMask = (uint)OpenMetaverse.PermissionMask.Copy; + + // Check that object is not copied + List localIds = new List(); + localIds.Add(so.LocalId); + + // Specifying a UUID.Zero in this case will plop it in the Objects folder if we have perms + scene.DeRezObjects(client, localIds, UUID.Zero, DeRezAction.TakeCopy, UUID.Zero); + + // Check that object isn't copied until we crank the sogd handle. + SceneObjectPart retrievedPart = scene.GetSceneObjectPart(so.LocalId); + Assert.That(retrievedPart, Is.Not.Null); + Assert.That(retrievedPart.ParentGroup.IsDeleted, Is.False); + + sogd.InventoryDeQueueAndDelete(); + // Check that object is still there. + SceneObjectPart retrievedPart2 = scene.GetSceneObjectPart(so.LocalId); + Assert.That(retrievedPart2, Is.Not.Null); + Assert.That(client.ReceivedKills.Count, Is.EqualTo(0)); + + // Check that we have a copy in inventory + InventoryItemBase item + = UserInventoryHelpers.GetInventoryItem(scene.InventoryService, ua.PrincipalID, "Objects/so1"); + Assert.That(item, Is.Null); + } + + { + // Check that object is not copied if copy trans perms is missing. + // Should not allow copy if base does not have this. + so.RootPart.BaseMask = (uint)OpenMetaverse.PermissionMask.Copy; + // Must be set so anyone can copy + so.RootPart.EveryoneMask = (uint)OpenMetaverse.PermissionMask.Copy; + + // Check that object is not copied + List localIds = new List(); + localIds.Add(so.LocalId); + + // Specifying a UUID.Zero in this case will plop it in the Objects folder if we have perms + scene.DeRezObjects(client, localIds, UUID.Zero, DeRezAction.TakeCopy, UUID.Zero); + + // Check that object isn't copied until we crank the sogd handle. + SceneObjectPart retrievedPart = scene.GetSceneObjectPart(so.LocalId); + Assert.That(retrievedPart, Is.Not.Null); + Assert.That(retrievedPart.ParentGroup.IsDeleted, Is.False); + + sogd.InventoryDeQueueAndDelete(); + // Check that object is still there. + SceneObjectPart retrievedPart2 = scene.GetSceneObjectPart(so.LocalId); + Assert.That(retrievedPart2, Is.Not.Null); + Assert.That(client.ReceivedKills.Count, Is.EqualTo(0)); + + // Check that we have a copy in inventory + InventoryItemBase item + = UserInventoryHelpers.GetInventoryItem(scene.InventoryService, ua.PrincipalID, "Objects/so1"); + Assert.That(item, Is.Null); + } + + { + // Check that object is not copied if everyone copy perms is missing. + // Should not allow copy if base does not have this. + so.RootPart.BaseMask = (uint)(OpenMetaverse.PermissionMask.Copy | OpenMetaverse.PermissionMask.Transfer); + // Make sure everyone perm does not allow copy + so.RootPart.EveryoneMask = (uint)(OpenMetaverse.PermissionMask.All & ~OpenMetaverse.PermissionMask.Copy); + + // Check that object is not copied + List localIds = new List(); + localIds.Add(so.LocalId); + + // Specifying a UUID.Zero in this case will plop it in the Objects folder if we have perms + scene.DeRezObjects(client, localIds, UUID.Zero, DeRezAction.TakeCopy, UUID.Zero); + + // Check that object isn't copied until we crank the sogd handle. + SceneObjectPart retrievedPart = scene.GetSceneObjectPart(so.LocalId); + Assert.That(retrievedPart, Is.Not.Null); + Assert.That(retrievedPart.ParentGroup.IsDeleted, Is.False); + + sogd.InventoryDeQueueAndDelete(); + // Check that object is still there. + SceneObjectPart retrievedPart2 = scene.GetSceneObjectPart(so.LocalId); + Assert.That(retrievedPart2, Is.Not.Null); + Assert.That(client.ReceivedKills.Count, Is.EqualTo(0)); + + // Check that we have a copy in inventory + InventoryItemBase item + = UserInventoryHelpers.GetInventoryItem(scene.InventoryService, ua.PrincipalID, "Objects/so1"); + Assert.That(item, Is.Null); + } + } + } + */ +} \ No newline at end of file diff --git a/Tests/OpenSim.Region.Framework.Tests/Scenes/Tests/SceneObjectCrossingTests.cs b/Tests/OpenSim.Region.Framework.Tests/Scenes/Tests/SceneObjectCrossingTests.cs new file mode 100644 index 00000000000..eb7b6f8526b --- /dev/null +++ b/Tests/OpenSim.Region.Framework.Tests/Scenes/Tests/SceneObjectCrossingTests.cs @@ -0,0 +1,287 @@ +/* + * 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 Nini.Config; +using NUnit.Framework; +using OpenMetaverse; +using OpenSim.Framework; +using OpenSim.Region.CoreModules.Framework; +using OpenSim.Region.CoreModules.Framework.EntityTransfer; +using OpenSim.Region.CoreModules.ServiceConnectorsOut.Simulation; +using OpenSim.Region.CoreModules.World.Land; +using OpenSim.Region.OptionalModules; +using OpenSim.Tests.Common; +using System.Threading; + +namespace OpenSim.Region.Framework.Scenes.Tests +{ + public class SceneObjectCrossingTests : OpenSimTestCase + { + [OneTimeSetUp] + public void FixtureInit() + { + // Don't allow tests to be bamboozled by asynchronous events. Execute everything on the same thread. + Util.FireAndForgetMethod = FireAndForgetMethod.RegressionTest; + } + + [OneTimeTearDown] + 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 cross with no prim limit module. + /// + [Test] + public void TestCrossOnSameSimulator() + { + + TestHelpers.InMethod(); +// TestHelpers.EnableLogging(); + + UUID userId = TestHelpers.ParseTail(0x1); + int sceneObjectIdTail = 0x2; + + EntityTransferModule etmA = new EntityTransferModule(); + EntityTransferModule etmB = new EntityTransferModule(); + LocalSimulationConnectorModule lscm = new LocalSimulationConnectorModule(); + + IConfigSource config = new IniConfigSource(); + IConfig modulesConfig = config.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); + TestScene sceneB = sh.SetupScene("sceneB", TestHelpers.ParseTail(0x200), 1000, 999); + + SceneHelpers.SetupSceneModules(new Scene[] { sceneA, sceneB }, config, lscm); + SceneHelpers.SetupSceneModules(sceneA, config, etmA); + SceneHelpers.SetupSceneModules(sceneB, config, etmB); + + SceneObjectGroup so1 = SceneHelpers.AddSceneObject(sceneA, 1, userId, "", sceneObjectIdTail); + UUID so1Id = so1.UUID; + so1.AbsolutePosition = new Vector3(128, 10, 20); + + // Cross with a negative value + so1.AbsolutePosition = new Vector3(128, -10, 20); + + // crossing is async + Thread.Sleep(500); + + Assert.IsNull(sceneA.GetSceneObjectGroup(so1Id)); + Assert.NotNull(sceneB.GetSceneObjectGroup(so1Id)); + } + + /// + /// Test cross with no prim limit module. + /// + /// + /// Possibly this should belong in ScenePresenceCrossingTests, though here it is the object that is being moved + /// where the avatar is just a passenger. + /// + [Test] + public void TestCrossOnSameSimulatorWithSittingAvatar() + { + TestHelpers.InMethod(); +// TestHelpers.EnableLogging(); + + UUID userId = TestHelpers.ParseTail(0x1); + int sceneObjectIdTail = 0x2; + Vector3 so1StartPos = new Vector3(128, 10, 20); + + EntityTransferModule etmA = new EntityTransferModule(); + EntityTransferModule etmB = new EntityTransferModule(); + LocalSimulationConnectorModule lscm = new LocalSimulationConnectorModule(); + + IConfigSource config = new IniConfigSource(); + IConfig modulesConfig = config.AddConfig("Modules"); + modulesConfig.Set("EntityTransferModule", etmA.Name); + modulesConfig.Set("SimulationServices", lscm.Name); + IConfig entityTransferConfig = config.AddConfig("EntityTransfer"); + + // In order to run a single threaded regression test we do not want the entity transfer module waiting + // for a callback from the destination scene before removing its avatar data. + entityTransferConfig.Set("wait_for_callback", false); + + SceneHelpers sh = new SceneHelpers(); + TestScene sceneA = sh.SetupScene("sceneA", TestHelpers.ParseTail(0x100), 1000, 1000); + TestScene sceneB = sh.SetupScene("sceneB", TestHelpers.ParseTail(0x200), 1000, 999); + + SceneHelpers.SetupSceneModules(new Scene[] { sceneA, sceneB }, config, lscm); + SceneHelpers.SetupSceneModules(sceneA, config, new CapabilitiesModule(), etmA); + SceneHelpers.SetupSceneModules(sceneB, config, new CapabilitiesModule(), etmB); + + SceneObjectGroup so1 = SceneHelpers.AddSceneObject(sceneA, 1, userId, "", sceneObjectIdTail); + UUID so1Id = so1.UUID; + so1.AbsolutePosition = so1StartPos; + + AgentCircuitData acd = SceneHelpers.GenerateAgentData(userId); + TestClient tc = new TestClient(acd, sceneA); + List destinationTestClients = new List(); + EntityTransferHelpers.SetupInformClientOfNeighbourTriggersNeighbourClientCreate(tc, destinationTestClients); + + ScenePresence sp1SceneA = SceneHelpers.AddScenePresence(sceneA, tc, acd); + sp1SceneA.AbsolutePosition = so1StartPos; + sp1SceneA.HandleAgentRequestSit(sp1SceneA.ControllingClient, sp1SceneA.UUID, so1.UUID, Vector3.Zero); + + sceneA.Update(4); + sceneB.Update(4); + // Cross + sceneA.SceneGraph.UpdatePrimGroupPosition( + so1.LocalId, new Vector3(so1StartPos.X, so1StartPos.Y - 20, so1StartPos.Z), sp1SceneA.ControllingClient); + + // crossing is async + sceneA.Update(4); + sceneB.Update(4); + Thread.Sleep(500); + + SceneObjectGroup so1PostCross; + + ScenePresence sp1SceneAPostCross = sceneA.GetScenePresence(userId); + Assert.IsTrue(sp1SceneAPostCross.IsChildAgent, "sp1SceneAPostCross.IsChildAgent unexpectedly false"); + + ScenePresence sp1SceneBPostCross = sceneB.GetScenePresence(userId); + TestClient sceneBTc = ((TestClient)sp1SceneBPostCross.ControllingClient); + sceneBTc.CompleteMovement(); + + sceneA.Update(4); + sceneB.Update(4); + + Assert.IsFalse(sp1SceneBPostCross.IsChildAgent, "sp1SceneAPostCross.IsChildAgent unexpectedly true"); + Assert.IsTrue(sp1SceneBPostCross.IsSatOnObject); + + Assert.IsNull(sceneA.GetSceneObjectGroup(so1Id), "uck"); + so1PostCross = sceneB.GetSceneObjectGroup(so1Id); + Assert.NotNull(so1PostCross); + Assert.AreEqual(1, so1PostCross.GetSittingAvatarsCount()); + + + Vector3 so1PostCrossPos = so1PostCross.AbsolutePosition; + +// Console.WriteLine("CRISSCROSS"); + + // Recross + sceneB.SceneGraph.UpdatePrimGroupPosition( + so1PostCross.LocalId, new Vector3(so1PostCrossPos.X, so1PostCrossPos.Y + 20, so1PostCrossPos.Z), sp1SceneBPostCross.ControllingClient); + + sceneA.Update(4); + sceneB.Update(4); + // crossing is async + Thread.Sleep(500); + + { + ScenePresence sp1SceneBPostReCross = sceneB.GetScenePresence(userId); + Assert.IsTrue(sp1SceneBPostReCross.IsChildAgent, "sp1SceneBPostReCross.IsChildAgent unexpectedly false"); + + ScenePresence sp1SceneAPostReCross = sceneA.GetScenePresence(userId); + TestClient sceneATc = ((TestClient)sp1SceneAPostReCross.ControllingClient); + sceneATc.CompleteMovement(); + + Assert.IsFalse(sp1SceneAPostReCross.IsChildAgent, "sp1SceneAPostCross.IsChildAgent unexpectedly true"); + Assert.IsTrue(sp1SceneAPostReCross.IsSatOnObject); + + Assert.IsNull(sceneB.GetSceneObjectGroup(so1Id), "uck2"); + SceneObjectGroup so1PostReCross = sceneA.GetSceneObjectGroup(so1Id); + Assert.NotNull(so1PostReCross); + Assert.AreEqual(1, so1PostReCross.GetSittingAvatarsCount()); + } + } + + /// + /// Test cross with no prim limit module. + /// + /// + /// XXX: This test may FCbe better off in a specific PrimLimitsModuleTest class in optional module tests in the + /// future (though it is configured as active by default, so not really optional). + /// + [Test] + public void TestCrossOnSameSimulatorPrimLimitsOkay() + { + TestHelpers.InMethod(); +// TestHelpers.EnableLogging(); + + UUID userId = TestHelpers.ParseTail(0x1); + int sceneObjectIdTail = 0x2; + + EntityTransferModule etmA = new EntityTransferModule(); + EntityTransferModule etmB = new EntityTransferModule(); + LocalSimulationConnectorModule lscm = new LocalSimulationConnectorModule(); + LandManagementModule lmmA = new LandManagementModule(); + LandManagementModule lmmB = new LandManagementModule(); + + IConfigSource config = new IniConfigSource(); + IConfig modulesConfig = config.AddConfig("Modules"); + modulesConfig.Set("EntityTransferModule", etmA.Name); + modulesConfig.Set("SimulationServices", lscm.Name); + + IConfig permissionsConfig = config.AddConfig("Permissions"); + permissionsConfig.Set("permissionmodules", "PrimLimitsModule"); + + SceneHelpers sh = new SceneHelpers(); + TestScene sceneA = sh.SetupScene("sceneA", TestHelpers.ParseTail(0x100), 1000, 1000); + TestScene sceneB = sh.SetupScene("sceneB", TestHelpers.ParseTail(0x200), 1000, 999); + + SceneHelpers.SetupSceneModules(new Scene[] { sceneA, sceneB }, config, lscm); + SceneHelpers.SetupSceneModules( + sceneA, config, etmA, lmmA, new PrimLimitsModule(), new PrimCountModule()); + SceneHelpers.SetupSceneModules( + sceneB, config, etmB, lmmB, new PrimLimitsModule(), new PrimCountModule()); + + // We must set up the parcel for this to work. Normally this is taken care of by OpenSimulator startup + // code which is not yet easily invoked by tests. + lmmA.EventManagerOnNoLandDataFromStorage(); + lmmB.EventManagerOnNoLandDataFromStorage(); + + AgentCircuitData acd = SceneHelpers.GenerateAgentData(userId); + TestClient tc = new TestClient(acd, sceneA); + List destinationTestClients = new List(); + EntityTransferHelpers.SetupInformClientOfNeighbourTriggersNeighbourClientCreate(tc, destinationTestClients); + ScenePresence sp1SceneA = SceneHelpers.AddScenePresence(sceneA, tc, acd); + + SceneObjectGroup so1 = SceneHelpers.AddSceneObject(sceneA, 1, userId, "", sceneObjectIdTail); + UUID so1Id = so1.UUID; + so1.AbsolutePosition = new Vector3(128, 10, 20); + + // Cross with a negative value. We must make this call rather than setting AbsolutePosition directly + // because only this will execute permission checks in the source region. + sceneA.SceneGraph.UpdatePrimGroupPosition(so1.LocalId, new Vector3(128, -10, 20), sp1SceneA.ControllingClient); + + // crossing is async + Thread.Sleep(500); + + Assert.IsNull(sceneA.GetSceneObjectGroup(so1Id)); + Assert.NotNull(sceneB.GetSceneObjectGroup(so1Id)); + } + } +} \ No newline at end of file diff --git a/Tests/OpenSim.Region.Framework.Tests/Scenes/Tests/SceneObjectDeRezTests.cs b/Tests/OpenSim.Region.Framework.Tests/Scenes/Tests/SceneObjectDeRezTests.cs new file mode 100644 index 00000000000..0c0376e247a --- /dev/null +++ b/Tests/OpenSim.Region.Framework.Tests/Scenes/Tests/SceneObjectDeRezTests.cs @@ -0,0 +1,260 @@ +/* + * 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 System.Reflection; +using Nini.Config; +using NUnit.Framework; +using OpenMetaverse; +using OpenSim.Framework; +using OpenSim.Region.CoreModules.Framework.EntityTransfer; +using OpenSim.Region.CoreModules.Framework.InventoryAccess; +using OpenSim.Region.CoreModules.ServiceConnectorsOut.Simulation; +using OpenSim.Region.CoreModules.World.Permissions; +using OpenSim.Region.Framework.Scenes; +using OpenSim.Services.Interfaces; +using OpenSim.Tests.Common; + +namespace OpenSim.Region.Framework.Scenes.Tests +{ + /// + /// Tests derez of scene objects. + /// + /// + /// This is at a level above the SceneObjectBasicTests, which act on the scene directly. + /// TODO: These tests are incomplete - need to test more kinds of derez (e.g. return object). + /// + [TestFixture] + public class SceneObjectDeRezTests : OpenSimTestCase + { + [OneTimeSetUp] + public void FixtureInit() + { + // Don't allow tests to be bamboozled by asynchronous events. Execute everything on the same thread. + // This facility was added after the original async delete tests were written, so it may be possible now + // to not bother explicitly disabling their async (since everything will be running sync). + Util.FireAndForgetMethod = FireAndForgetMethod.RegressionTest; + } + + [OneTimeTearDown] + 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 deleting an object from a scene. + /// + [Test] + public void TestDeRezSceneObject() + { + TestHelpers.InMethod(); + + UUID userId = UUID.Parse("10000000-0000-0000-0000-000000000001"); + + TestScene scene = new SceneHelpers().SetupScene(); + IConfigSource configSource = new IniConfigSource(); + IConfig config = configSource.AddConfig("Startup"); + config.Set("serverside_object_permissions", true); + SceneHelpers.SetupSceneModules(scene, configSource, new object[] { new DefaultPermissionsModule() }); + IClientAPI client = SceneHelpers.AddScenePresence(scene, userId).ControllingClient; + + // Turn off the timer on the async sog deleter - we'll crank it by hand for this test. + AsyncSceneObjectGroupDeleter sogd = scene.SceneObjectGroupDeleter; + sogd.Enabled = false; + + SceneObjectGroup so = SceneHelpers.AddSceneObject(scene, "so1", userId); + uint soLocalId = so.LocalId; + + List localIds = new List(); + localIds.Add(so.LocalId); + scene.DeRezObjects(client, localIds, UUID.Zero, DeRezAction.Delete, UUID.Zero); + + // Check that object isn't deleted until we crank the sogd handle. + SceneObjectPart retrievedPart = scene.GetSceneObjectPart(so.LocalId); +// Assert.That(retrievedPart, Is.Not.Null); +// Assert.That(retrievedPart.ParentGroup.IsDeleted, Is.False); + + sogd.InventoryDeQueueAndDelete(); + +// SceneObjectPart retrievedPart2 = scene.GetSceneObjectPart(so.LocalId); + Assert.That(retrievedPart, Is.Null); + } + + /// + /// Test that child and root agents correctly receive KillObject notifications. + /// + [Test] + public void TestDeRezSceneObjectToAgents() + { + TestHelpers.InMethod(); +// TestHelpers.EnableLogging(); + + SceneHelpers sh = new SceneHelpers(); + TestScene sceneA = sh.SetupScene("sceneA", TestHelpers.ParseTail(0x100), 1000, 1000); + TestScene sceneB = sh.SetupScene("sceneB", TestHelpers.ParseTail(0x200), 1000, 999); + + // We need this so that the creation of the root client for userB in sceneB can trigger the creation of a child client in sceneA + LocalSimulationConnectorModule lscm = new LocalSimulationConnectorModule(); + EntityTransferModule etmB = new EntityTransferModule(); + IConfigSource config = new IniConfigSource(); + IConfig modulesConfig = config.AddConfig("Modules"); + modulesConfig.Set("EntityTransferModule", etmB.Name); + modulesConfig.Set("SimulationServices", lscm.Name); + SceneHelpers.SetupSceneModules(new Scene[] { sceneA, sceneB }, config, lscm); + SceneHelpers.SetupSceneModules(sceneB, config, etmB); + + // We need this for derez + //SceneHelpers.SetupSceneModules(sceneA, new PermissionsModule()); + + UserAccount uaA = UserAccountHelpers.CreateUserWithInventory(sceneA, "Andy", "AAA", 0x1, ""); + UserAccount uaB = UserAccountHelpers.CreateUserWithInventory(sceneA, "Brian", "BBB", 0x2, ""); + + TestClient clientA = (TestClient)SceneHelpers.AddScenePresence(sceneA, uaA).ControllingClient; + + // This is the more long-winded route we have to take to get a child client created for userB in sceneA + // rather than just calling AddScenePresence() as for userA + AgentCircuitData acd = SceneHelpers.GenerateAgentData(uaB); + TestClient clientB = new TestClient(acd, sceneB); + List childClientsB = new List(); + EntityTransferHelpers.SetupInformClientOfNeighbourTriggersNeighbourClientCreate(clientB, childClientsB); + + SceneHelpers.AddScenePresence(sceneB, clientB, acd); + + SceneObjectGroup so = SceneHelpers.AddSceneObject(sceneA); + uint soLocalId = so.LocalId; + + sceneA.DeleteSceneObject(so, false); + } + + /// + /// Test deleting an object from a scene where the deleter is not the owner + /// + /// + /// This test assumes that the deleter is not a god. + /// + [Test] + public void TestDeRezSceneObjectNotOwner() + { + TestHelpers.InMethod(); +// log4net.Config.XmlConfigurator.Configure(); + + UUID userId = UUID.Parse("10000000-0000-0000-0000-000000000001"); + UUID objectOwnerId = UUID.Parse("20000000-0000-0000-0000-000000000001"); + + TestScene scene = new SceneHelpers().SetupScene(); + IConfigSource configSource = new IniConfigSource(); + IConfig config = configSource.AddConfig("Startup"); + config.Set("serverside_object_permissions", true); + SceneHelpers.SetupSceneModules(scene, configSource, new object[] { new DefaultPermissionsModule() }); + IClientAPI client = SceneHelpers.AddScenePresence(scene, userId).ControllingClient; + + // Turn off the timer on the async sog deleter - we'll crank it by hand for this test. + AsyncSceneObjectGroupDeleter sogd = scene.SceneObjectGroupDeleter; + sogd.Enabled = false; + + SceneObjectPart part + = new SceneObjectPart(objectOwnerId, PrimitiveBaseShape.Default, Vector3.Zero, Quaternion.Identity, Vector3.Zero); + part.Name = "obj1"; + scene.AddNewSceneObject(new SceneObjectGroup(part), false); + List localIds = new List(); + localIds.Add(part.LocalId); + + scene.DeRezObjects(client, localIds, UUID.Zero, DeRezAction.Delete, UUID.Zero); + sogd.InventoryDeQueueAndDelete(); + + // Object should still be in the scene. + SceneObjectPart retrievedPart = scene.GetSceneObjectPart(part.LocalId); + Assert.That(retrievedPart.UUID, Is.EqualTo(part.UUID)); + } + + /// + /// Test deleting an object asynchronously to user inventory. + /// + [Test] + public void TestDeleteSceneObjectAsyncToUserInventory() + { + TestHelpers.InMethod(); +// TestHelpers.EnableLogging(); + + UUID agentId = UUID.Parse("00000000-0000-0000-0000-000000000001"); + string myObjectName = "Fred"; + + TestScene scene = new SceneHelpers().SetupScene(); + + IConfigSource configSource = new IniConfigSource(); + IConfig config = configSource.AddConfig("Modules"); + config.Set("InventoryAccessModule", "BasicInventoryAccessModule"); + SceneHelpers.SetupSceneModules( + scene, configSource, new object[] { new BasicInventoryAccessModule() }); + + SceneHelpers.SetupSceneModules(scene, new object[] { }); + + // Turn off the timer on the async sog deleter - we'll crank it by hand for this test. + AsyncSceneObjectGroupDeleter sogd = scene.SceneObjectGroupDeleter; + sogd.Enabled = false; + + SceneObjectGroup so = SceneHelpers.AddSceneObject(scene, myObjectName, agentId); + + UserAccount ua = UserAccountHelpers.CreateUserWithInventory(scene, agentId); + InventoryFolderBase folder1 + = UserInventoryHelpers.CreateInventoryFolder(scene.InventoryService, ua.PrincipalID, "folder1", false); + + IClientAPI client = SceneHelpers.AddScenePresence(scene, agentId).ControllingClient; + scene.DeRezObjects(client, new List() { so.LocalId }, UUID.Zero, DeRezAction.Take, folder1.ID); + +// SceneObjectPart retrievedPart = scene.GetSceneObjectPart(so.LocalId); + +// Assert.That(retrievedPart, Is.Not.Null); +// Assert.That(so.IsDeleted, Is.False); + + sogd.InventoryDeQueueAndDelete(); + + Assert.That(so.IsDeleted, Is.True); + + SceneObjectPart retrievedPart2 = scene.GetSceneObjectPart(so.LocalId); + Assert.That(retrievedPart2, Is.Null); + +// SceneSetupHelpers.DeleteSceneObjectAsync(scene, part, DeRezAction.Take, userInfo.RootFolder.ID, client); + + InventoryItemBase retrievedItem + = UserInventoryHelpers.GetInventoryItem( + scene.InventoryService, ua.PrincipalID, "folder1/" + myObjectName); + + // Check that we now have the taken part in our inventory + Assert.That(retrievedItem, Is.Not.Null); + + // Check that the taken part has actually disappeared +// SceneObjectPart retrievedPart = scene.GetSceneObjectPart(part.LocalId); +// Assert.That(retrievedPart, Is.Null); + } + } +} diff --git a/Tests/OpenSim.Region.Framework.Tests/Scenes/Tests/SceneObjectLinkingTests.cs b/Tests/OpenSim.Region.Framework.Tests/Scenes/Tests/SceneObjectLinkingTests.cs new file mode 100644 index 00000000000..41f61ac424d --- /dev/null +++ b/Tests/OpenSim.Region.Framework.Tests/Scenes/Tests/SceneObjectLinkingTests.cs @@ -0,0 +1,373 @@ +/* + * 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 System.Reflection; +using NUnit.Framework; +using OpenMetaverse; +using OpenSim.Framework; +using OpenSim.Region.Framework.Scenes; +using OpenSim.Tests.Common; +using log4net; + +namespace OpenSim.Region.Framework.Scenes.Tests +{ + [TestFixture] + public class SceneObjectLinkingTests : OpenSimTestCase + { + private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + + /// + /// Links to self should be ignored. + /// + [Test] + public void TestLinkToSelf() + { + TestHelpers.InMethod(); + + UUID ownerId = TestHelpers.ParseTail(0x1); + int nParts = 3; + + TestScene scene = new SceneHelpers().SetupScene(); + SceneObjectGroup sog1 = SceneHelpers.CreateSceneObject(nParts, ownerId, "TestLinkToSelf_", 0x10); + scene.AddSceneObject(sog1); + scene.LinkObjects(ownerId, sog1.LocalId, new List() { sog1.Parts[1].LocalId }); +// sog1.LinkToGroup(sog1); + + Assert.That(sog1.Parts.Length, Is.EqualTo(nParts)); + } + + [Test] + public void TestLinkDelink2SceneObjects() + { + TestHelpers.InMethod(); + + bool debugtest = false; + + Scene scene = new SceneHelpers().SetupScene(); + SceneObjectGroup grp1 = SceneHelpers.AddSceneObject(scene); + SceneObjectPart part1 = grp1.RootPart; + SceneObjectGroup grp2 = SceneHelpers.AddSceneObject(scene); + SceneObjectPart part2 = grp2.RootPart; + + grp1.AbsolutePosition = new Vector3(10, 10, 10); + grp2.AbsolutePosition = Vector3.Zero; + + // <90,0,0> +// grp1.UpdateGroupRotationR(Quaternion.CreateFromEulers(90 * Utils.DEG_TO_RAD, 0, 0)); + + // <180,0,0> + grp2.UpdateGroupRotationR(Quaternion.CreateFromEulers(180 * Utils.DEG_TO_RAD, 0, 0)); + + // Required for linking + grp1.RootPart.ClearUpdateSchedule(); + grp2.RootPart.ClearUpdateSchedule(); + + // Link grp2 to grp1. part2 becomes child prim to grp1. grp2 is eliminated. + Assert.IsFalse(grp1.GroupContainsForeignPrims); + grp1.LinkToGroup(grp2); + Assert.IsTrue(grp1.GroupContainsForeignPrims); + + scene.Backup(true); + Assert.IsFalse(grp1.GroupContainsForeignPrims); + + // FIXME: Can't do this test yet since group 2 still has its root part! We can't yet null this since + // it might cause SOG.ProcessBackup() to fail due to the race condition. This really needs to be fixed. + Assert.That(grp2.IsDeleted, "SOG 2 was not registered as deleted after link."); + Assert.That(grp2.Parts.Length, Is.EqualTo(0), "Group 2 still contained children after delink."); + Assert.That(grp1.Parts.Length == 2); + + if (debugtest) + { + m_log.Debug("parts: " + grp1.Parts.Length); + m_log.Debug("Group1: Pos:"+grp1.AbsolutePosition+", Rot:"+grp1.GroupRotation); + m_log.Debug("Group1: Prim1: OffsetPosition:"+ part1.OffsetPosition+", OffsetRotation:"+part1.RotationOffset); + m_log.Debug("Group1: Prim2: OffsetPosition:"+part2.OffsetPosition+", OffsetRotation:"+part2.RotationOffset); + } + + // root part should have no offset position or rotation + Assert.That(part1.OffsetPosition == Vector3.Zero && part1.RotationOffset == Quaternion.Identity, + "root part should have no offset position or rotation"); + + // offset position should be root part position - part2.absolute position. + Assert.That(part2.OffsetPosition == new Vector3(-10, -10, -10), + "offset position should be root part position - part2.absolute position."); + + float roll = 0; + float pitch = 0; + float yaw = 0; + + // There's a euler anomoly at 180, 0, 0 so expect 180 to turn into -180. + part1.RotationOffset.GetEulerAngles(out roll, out pitch, out yaw); + Vector3 rotEuler1 = new Vector3(roll * Utils.RAD_TO_DEG, pitch * Utils.RAD_TO_DEG, yaw * Utils.RAD_TO_DEG); + + if (debugtest) + m_log.Debug(rotEuler1); + + part2.RotationOffset.GetEulerAngles(out roll, out pitch, out yaw); + Vector3 rotEuler2 = new Vector3(roll * Utils.RAD_TO_DEG, pitch * Utils.RAD_TO_DEG, yaw * Utils.RAD_TO_DEG); + + if (debugtest) + m_log.Debug(rotEuler2); + + Assert.That(rotEuler2.ApproxEquals(new Vector3(-180, 0, 0), 0.001f) || rotEuler2.ApproxEquals(new Vector3(180, 0, 0), 0.001f), + "Not exactly sure what this is asserting..."); + + // Delink part 2 + SceneObjectGroup grp3 = grp1.DelinkFromGroup(part2.LocalId); + + if (debugtest) + m_log.Debug("Group2: Prim2: OffsetPosition:" + part2.AbsolutePosition + ", OffsetRotation:" + part2.RotationOffset); + + Assert.That(grp1.Parts.Length, Is.EqualTo(1), "Group 1 still contained part2 after delink."); + Assert.That(part2.AbsolutePosition == Vector3.Zero, "The absolute position should be zero"); + Assert.NotNull(grp3); + } + + [Test] + public void TestLinkDelink2groups4SceneObjects() + { + TestHelpers.InMethod(); + + bool debugtest = false; + + Scene scene = new SceneHelpers().SetupScene(); + SceneObjectGroup grp1 = SceneHelpers.AddSceneObject(scene); + SceneObjectPart part1 = grp1.RootPart; + SceneObjectGroup grp2 = SceneHelpers.AddSceneObject(scene); + SceneObjectPart part2 = grp2.RootPart; + SceneObjectGroup grp3 = SceneHelpers.AddSceneObject(scene); + SceneObjectPart part3 = grp3.RootPart; + SceneObjectGroup grp4 = SceneHelpers.AddSceneObject(scene); + SceneObjectPart part4 = grp4.RootPart; + + grp1.AbsolutePosition = new Vector3(10, 10, 10); + grp2.AbsolutePosition = Vector3.Zero; + grp3.AbsolutePosition = new Vector3(20, 20, 20); + grp4.AbsolutePosition = new Vector3(40, 40, 40); + + // <90,0,0> +// grp1.UpdateGroupRotationR(Quaternion.CreateFromEulers(90 * Utils.DEG_TO_RAD, 0, 0)); + + // <180,0,0> + grp2.UpdateGroupRotationR(Quaternion.CreateFromEulers(180 * Utils.DEG_TO_RAD, 0, 0)); + + // <270,0,0> +// grp3.UpdateGroupRotationR(Quaternion.CreateFromEulers(270 * Utils.DEG_TO_RAD, 0, 0)); + + // <0,90,0> + grp4.UpdateGroupRotationR(Quaternion.CreateFromEulers(0, 90 * Utils.DEG_TO_RAD, 0)); + + // Required for linking + grp1.RootPart.ClearUpdateSchedule(); + grp2.RootPart.ClearUpdateSchedule(); + grp3.RootPart.ClearUpdateSchedule(); + grp4.RootPart.ClearUpdateSchedule(); + + // Link grp2 to grp1. part2 becomes child prim to grp1. grp2 is eliminated. + grp1.LinkToGroup(grp2); + + // Link grp4 to grp3. + grp3.LinkToGroup(grp4); + + // At this point we should have 4 parts total in two groups. + Assert.That(grp1.Parts.Length == 2, "Group1 children count should be 2"); + Assert.That(grp2.IsDeleted, "Group 2 was not registered as deleted after link."); + Assert.That(grp2.Parts.Length, Is.EqualTo(0), "Group 2 still contained parts after delink."); + Assert.That(grp3.Parts.Length == 2, "Group3 children count should be 2"); + Assert.That(grp4.IsDeleted, "Group 4 was not registered as deleted after link."); + Assert.That(grp4.Parts.Length, Is.EqualTo(0), "Group 4 still contained parts after delink."); + + if (debugtest) + { + m_log.Debug("--------After Link-------"); + m_log.Debug("Group1: parts:" + grp1.Parts.Length); + m_log.Debug("Group1: Pos:"+grp1.AbsolutePosition+", Rot:"+grp1.GroupRotation); + m_log.Debug("Group1: Prim1: OffsetPosition:" + part1.OffsetPosition + ", OffsetRotation:" + part1.RotationOffset); + m_log.Debug("Group1: Prim2: OffsetPosition:"+part2.OffsetPosition+", OffsetRotation:"+ part2.RotationOffset); + + m_log.Debug("Group3: parts:" + grp3.Parts.Length); + m_log.Debug("Group3: Pos:"+grp3.AbsolutePosition+", Rot:"+grp3.GroupRotation); + m_log.Debug("Group3: Prim1: OffsetPosition:"+part3.OffsetPosition+", OffsetRotation:"+part3.RotationOffset); + m_log.Debug("Group3: Prim2: OffsetPosition:"+part4.OffsetPosition+", OffsetRotation:"+part4.RotationOffset); + } + + // Required for linking + grp1.RootPart.ClearUpdateSchedule(); + grp3.RootPart.ClearUpdateSchedule(); + + // root part should have no offset position or rotation + Assert.That(part1.OffsetPosition == Vector3.Zero && part1.RotationOffset == Quaternion.Identity, + "root part should have no offset position or rotation (again)"); + + // offset position should be root part position - part2.absolute position. + Assert.That(part2.OffsetPosition == new Vector3(-10, -10, -10), + "offset position should be root part position - part2.absolute position (again)"); + + float roll = 0; + float pitch = 0; + float yaw = 0; + + // There's a euler anomoly at 180, 0, 0 so expect 180 to turn into -180. + part1.RotationOffset.GetEulerAngles(out roll, out pitch, out yaw); + Vector3 rotEuler1 = new Vector3(roll * Utils.RAD_TO_DEG, pitch * Utils.RAD_TO_DEG, yaw * Utils.RAD_TO_DEG); + + if (debugtest) + m_log.Debug(rotEuler1); + + part2.RotationOffset.GetEulerAngles(out roll, out pitch, out yaw); + Vector3 rotEuler2 = new Vector3(roll * Utils.RAD_TO_DEG, pitch * Utils.RAD_TO_DEG, yaw * Utils.RAD_TO_DEG); + + if (debugtest) + m_log.Debug(rotEuler2); + + Assert.That(rotEuler2.ApproxEquals(new Vector3(-180, 0, 0), 0.001f) || rotEuler2.ApproxEquals(new Vector3(180, 0, 0), 0.001f), + "Not sure what this assertion is all about..."); + + // Now we're linking the first group to the third group. This will make the first group child parts of the third one. + grp3.LinkToGroup(grp1); + + // Delink parts 2 and 3 + grp3.DelinkFromGroup(part2.LocalId); + grp3.DelinkFromGroup(part3.LocalId); + + if (debugtest) + { + m_log.Debug("--------After De-Link-------"); + m_log.Debug("Group1: parts:" + grp1.Parts.Length); + m_log.Debug("Group1: Pos:" + grp1.AbsolutePosition + ", Rot:" + grp1.GroupRotation); + m_log.Debug("Group1: Prim1: OffsetPosition:" + part1.OffsetPosition + ", OffsetRotation:" + part1.RotationOffset); + m_log.Debug("Group1: Prim2: OffsetPosition:" + part2.OffsetPosition + ", OffsetRotation:" + part2.RotationOffset); + + m_log.Debug("Group3: parts:" + grp3.Parts.Length); + m_log.Debug("Group3: Pos:" + grp3.AbsolutePosition + ", Rot:" + grp3.GroupRotation); + m_log.Debug("Group3: Prim1: OffsetPosition:" + part3.OffsetPosition + ", OffsetRotation:" + part3.RotationOffset); + m_log.Debug("Group3: Prim2: OffsetPosition:" + part4.OffsetPosition + ", OffsetRotation:" + part4.RotationOffset); + } + + Assert.That(part2.AbsolutePosition == Vector3.Zero, "Badness 1"); + Assert.That(part4.OffsetPosition == new Vector3(20, 20, 20), "Badness 2"); + Quaternion compareQuaternion = new Quaternion(0, 0.7071068f, 0, 0.7071068f); + Assert.That((part4.RotationOffset.X - compareQuaternion.X < 0.00003) + && (part4.RotationOffset.Y - compareQuaternion.Y < 0.00003) + && (part4.RotationOffset.Z - compareQuaternion.Z < 0.00003) + && (part4.RotationOffset.W - compareQuaternion.W < 0.00003), + "Badness 3"); + } + + /// + /// Test that a new scene object which is already linked is correctly persisted to the persistence layer. + /// + [Test] + public void TestNewSceneObjectLinkPersistence() + { + TestHelpers.InMethod(); + //log4net.Config.XmlConfigurator.Configure(); + + TestScene scene = new SceneHelpers().SetupScene(); + + string rootPartName = "rootpart"; + UUID rootPartUuid = new UUID("00000000-0000-0000-0000-000000000001"); + string linkPartName = "linkpart"; + UUID linkPartUuid = new UUID("00000000-0000-0000-0001-000000000000"); + + SceneObjectPart rootPart + = new SceneObjectPart(UUID.Zero, PrimitiveBaseShape.Default, Vector3.Zero, Quaternion.Identity, Vector3.Zero) + { Name = rootPartName, UUID = rootPartUuid }; + SceneObjectPart linkPart + = new SceneObjectPart(UUID.Zero, PrimitiveBaseShape.Default, Vector3.Zero, Quaternion.Identity, Vector3.Zero) + { Name = linkPartName, UUID = linkPartUuid }; + + SceneObjectGroup sog = new SceneObjectGroup(rootPart); + sog.AddPart(linkPart); + scene.AddNewSceneObject(sog, true); + + // In a test, we have to crank the backup handle manually. Normally this would be done by the timer invoked + // scene backup thread. + scene.Backup(true); + + List storedObjects = scene.SimulationDataService.LoadObjects(scene.RegionInfo.RegionID); + + Assert.That(storedObjects.Count, Is.EqualTo(1)); + Assert.That(storedObjects[0].Parts.Length, Is.EqualTo(2)); + Assert.That(storedObjects[0].ContainsPart(rootPartUuid)); + Assert.That(storedObjects[0].ContainsPart(linkPartUuid)); + } + + /// + /// Test that a delink of a previously linked object is correctly persisted to the database + /// + [Test] + public void TestDelinkPersistence() + { + TestHelpers.InMethod(); + //log4net.Config.XmlConfigurator.Configure(); + + TestScene scene = new SceneHelpers().SetupScene(); + + string rootPartName = "rootpart"; + UUID rootPartUuid = new UUID("00000000-0000-0000-0000-000000000001"); + string linkPartName = "linkpart"; + UUID linkPartUuid = new UUID("00000000-0000-0000-0001-000000000000"); + + SceneObjectPart rootPart + = new SceneObjectPart(UUID.Zero, PrimitiveBaseShape.Default, Vector3.Zero, Quaternion.Identity, Vector3.Zero) + { Name = rootPartName, UUID = rootPartUuid }; + + SceneObjectPart linkPart + = new SceneObjectPart(UUID.Zero, PrimitiveBaseShape.Default, Vector3.Zero, Quaternion.Identity, Vector3.Zero) + { Name = linkPartName, UUID = linkPartUuid }; + SceneObjectGroup linkGroup = new SceneObjectGroup(linkPart); + scene.AddNewSceneObject(linkGroup, true); + + SceneObjectGroup sog = new SceneObjectGroup(rootPart); + scene.AddNewSceneObject(sog, true); + + Assert.IsFalse(sog.GroupContainsForeignPrims); + sog.LinkToGroup(linkGroup); + Assert.IsTrue(sog.GroupContainsForeignPrims); + + scene.Backup(true); + Assert.AreEqual(1, scene.SimulationDataService.LoadObjects(scene.RegionInfo.RegionID).Count); + + // These changes should occur immediately without waiting for a backup pass + SceneObjectGroup groupToDelete = sog.DelinkFromGroup(linkPart, false); + Assert.IsFalse(groupToDelete.GroupContainsForeignPrims); + +/* backup is async + scene.DeleteSceneObject(groupToDelete, false); + + List storedObjects = scene.SimulationDataService.LoadObjects(scene.RegionInfo.RegionID); + + Assert.AreEqual(1, storedObjects.Count); + Assert.AreEqual(1, storedObjects[0].Parts.Length); + Assert.IsTrue(storedObjects[0].ContainsPart(rootPartUuid)); +*/ + } + } +} diff --git a/Tests/OpenSim.Region.Framework.Tests/Scenes/Tests/SceneObjectResizeTests.cs b/Tests/OpenSim.Region.Framework.Tests/Scenes/Tests/SceneObjectResizeTests.cs new file mode 100644 index 00000000000..8b3a7e99cef --- /dev/null +++ b/Tests/OpenSim.Region.Framework.Tests/Scenes/Tests/SceneObjectResizeTests.cs @@ -0,0 +1,102 @@ +/* + * 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.Reflection; +using NUnit.Framework; +using OpenMetaverse; +using OpenSim.Framework; +using OpenSim.Region.Framework.Scenes; +using OpenSim.Tests.Common; + +namespace OpenSim.Region.Framework.Scenes.Tests +{ + /// + /// Basic scene object resize tests + /// + [TestFixture] + public class SceneObjectResizeTests : OpenSimTestCase + { + /// + /// Test resizing an object + /// + [Test] + public void TestResizeSceneObject() + { + TestHelpers.InMethod(); +// log4net.Config.XmlConfigurator.Configure(); + + Scene scene = new SceneHelpers().SetupScene(); + SceneObjectGroup g1 = SceneHelpers.AddSceneObject(scene); + + g1.GroupResize(new Vector3(2, 3, 4)); + + SceneObjectGroup g1Post = scene.GetSceneObjectGroup(g1.UUID); + + Assert.That(g1Post.RootPart.Scale.X, Is.EqualTo(2)); + Assert.That(g1Post.RootPart.Scale.Y, Is.EqualTo(3)); + Assert.That(g1Post.RootPart.Scale.Z, Is.EqualTo(4)); + +// Assert.That(g1Post.RootPart.UndoCount, Is.EqualTo(1)); + } + + /// + /// Test resizing an individual part in a scene object. + /// + [Test] + public void TestResizeSceneObjectPart() + { + TestHelpers.InMethod(); + //log4net.Config.XmlConfigurator.Configure(); + + Scene scene = new SceneHelpers().SetupScene(); + UUID owner = UUID.Random(); + SceneObjectGroup g1 = SceneHelpers.CreateSceneObject(2, owner); + g1.RootPart.Scale = new Vector3(2, 3, 4); + g1.Parts[1].Scale = new Vector3(5, 6, 7); + + scene.AddSceneObject(g1); + + SceneObjectGroup g1Post = scene.GetSceneObjectGroup(g1.UUID); + + g1Post.Parts[1].Resize(new Vector3(8, 9, 10)); + + SceneObjectGroup g1PostPost = scene.GetSceneObjectGroup(g1.UUID); + + SceneObjectPart g1RootPart = g1PostPost.RootPart; + SceneObjectPart g1ChildPart = g1PostPost.Parts[1]; + + Assert.That(g1RootPart.Scale.X, Is.EqualTo(2)); + Assert.That(g1RootPart.Scale.Y, Is.EqualTo(3)); + Assert.That(g1RootPart.Scale.Z, Is.EqualTo(4)); + + Assert.That(g1ChildPart.Scale.X, Is.EqualTo(8)); + Assert.That(g1ChildPart.Scale.Y, Is.EqualTo(9)); + Assert.That(g1ChildPart.Scale.Z, Is.EqualTo(10)); + } + } +} \ No newline at end of file diff --git a/Tests/OpenSim.Region.Framework.Tests/Scenes/Tests/SceneObjectScriptTests.cs b/Tests/OpenSim.Region.Framework.Tests/Scenes/Tests/SceneObjectScriptTests.cs new file mode 100644 index 00000000000..8a2d2af90ff --- /dev/null +++ b/Tests/OpenSim.Region.Framework.Tests/Scenes/Tests/SceneObjectScriptTests.cs @@ -0,0 +1,74 @@ +/* + * 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 System.Reflection; +using NUnit.Framework; +using OpenMetaverse; +using OpenSim.Framework; +using OpenSim.Region.Framework.Interfaces; +using OpenSim.Region.Framework.Scenes; +using OpenSim.Tests.Common; + +namespace OpenSim.Region.Framework.Scenes.Tests +{ + [TestFixture] + public class SceneObjectScriptTests : OpenSimTestCase + { + [Test] + public void TestAddScript() + { + TestHelpers.InMethod(); +// log4net.Config.XmlConfigurator.Configure(); + + UUID userId = TestHelpers.ParseTail(0x1); +// UUID itemId = TestHelpers.ParseTail(0x2); + string itemName = "Test Script Item"; + + Scene scene = new SceneHelpers().SetupScene(); + SceneObjectGroup so = SceneHelpers.CreateSceneObject(1, userId); + scene.AddNewSceneObject(so, true); + + InventoryItemBase itemTemplate = new InventoryItemBase(); + itemTemplate.Name = itemName; + itemTemplate.Folder = so.UUID; + itemTemplate.InvType = (int)InventoryType.LSL; + + SceneObjectPart partWhereScriptAdded = scene.RezNewScript(userId, itemTemplate); + + Assert.That(partWhereScriptAdded, Is.Not.Null); + + IEntityInventory primInventory = partWhereScriptAdded.Inventory; + Assert.That(primInventory.GetInventoryList().Count, Is.EqualTo(1)); + Assert.That(primInventory.ContainsScripts(), Is.True); + + IList primItems = primInventory.GetInventoryItems(itemName); + Assert.That(primItems.Count, Is.EqualTo(1)); + } + } +} \ No newline at end of file diff --git a/Tests/OpenSim.Region.Framework.Tests/Scenes/Tests/SceneObjectSerializationTests.cs b/Tests/OpenSim.Region.Framework.Tests/Scenes/Tests/SceneObjectSerializationTests.cs new file mode 100644 index 00000000000..e3ceb04e88f --- /dev/null +++ b/Tests/OpenSim.Region.Framework.Tests/Scenes/Tests/SceneObjectSerializationTests.cs @@ -0,0 +1,135 @@ +/* + * 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 System.Reflection; +using System.Threading; +using System.Xml; +using System.Linq; +using Nini.Config; +using NUnit.Framework; +using OpenMetaverse; +using OpenSim.Framework; +using OpenSim.Framework.Serialization.External; +using OpenSim.Region.Framework.Scenes; +using OpenSim.Region.Framework.Scenes.Serialization; +using OpenSim.Services.Interfaces; +using OpenSim.Tests.Common; + +namespace OpenSim.Region.Framework.Scenes.Tests +{ + /// + /// Basic scene object serialization tests. + /// + [TestFixture] + public class SceneObjectSerializationTests : OpenSimTestCase + { + + /// + /// Serialize and deserialize. + /// + [Test] + public void TestSerialDeserial() + { + TestHelpers.InMethod(); + + Scene scene = new SceneHelpers().SetupScene(); + int partsToTestCount = 3; + + SceneObjectGroup so + = SceneHelpers.CreateSceneObject(partsToTestCount, TestHelpers.ParseTail(0x1), "obj1", 0x10); + SceneObjectPart[] parts = so.Parts; + so.Name = "obj1"; + so.Description = "xpto"; + + string xml = SceneObjectSerializer.ToXml2Format(so); + Assert.That(!string.IsNullOrEmpty(xml), "SOG serialization resulted in empty or null string"); + + XmlDocument doc = new XmlDocument(); + doc.LoadXml(xml); + XmlNodeList nodes = doc.GetElementsByTagName("SceneObjectPart"); + Assert.That(nodes.Count, Is.EqualTo(3), "SOG serialization resulted in wrong number of SOPs"); + + SceneObjectGroup so2 = SceneObjectSerializer.FromXml2Format(xml); + Assert.IsNotNull(so2, "SOG deserialization resulted in null object"); + Assert.That(so2.Name == so.Name, "Name of deserialized object does not match original name"); + Assert.That(so2.Description == so.Description, "Description of deserialized object does not match original name"); + } + + /// + /// This checks for a bug reported in mantis #7514 + /// + [Test] + public void TestNamespaceAttribute() + { + TestHelpers.InMethod(); + + Scene scene = new SceneHelpers().SetupScene(); + UserAccount account = new UserAccount(UUID.Zero, UUID.Random(), "Test", "User", string.Empty); + scene.UserAccountService.StoreUserAccount(account); + int partsToTestCount = 1; + + SceneObjectGroup so + = SceneHelpers.CreateSceneObject(partsToTestCount, TestHelpers.ParseTail(0x1), "obj1", 0x10); + SceneObjectPart[] parts = so.Parts; + so.Name = "obj1"; + so.Description = "xpto"; + so.OwnerID = account.PrincipalID; + so.RootPart.CreatorID = so.OwnerID; + + string xml = SceneObjectSerializer.ToXml2Format(so); + Assert.That(!string.IsNullOrEmpty(xml), "SOG serialization resulted in empty or null string"); + + xml = ExternalRepresentationUtils.RewriteSOP(xml, "Test Scene", "http://localhost", scene.UserAccountService, UUID.Zero); + //Console.WriteLine(xml); + + XmlDocument doc = new XmlDocument(); + doc.LoadXml(xml); + + XmlNodeList nodes = doc.GetElementsByTagName("SceneObjectPart"); + Assert.That(nodes.Count, Is.GreaterThan(0), "SOG serialization resulted in no SOPs"); + foreach (XmlAttribute a in nodes[0].Attributes) + { + int count = a.Name.Count(c => c == ':'); + Assert.That(count, Is.EqualTo(1), "Cannot have multiple ':' in attribute name in SOP"); + } + nodes = doc.GetElementsByTagName("CreatorData"); + Assert.That(nodes.Count, Is.GreaterThan(0), "SOG serialization resulted in no CreatorData"); + foreach (XmlAttribute a in nodes[0].Attributes) + { + int count = a.Name.Count(c => c == ':'); + Assert.That(count, Is.EqualTo(1), "Cannot have multiple ':' in attribute name in CreatorData"); + } + + SceneObjectGroup so2 = SceneObjectSerializer.FromXml2Format(xml); + Assert.IsNotNull(so2, "SOG deserialization resulted in null object"); + Assert.AreNotEqual(so.RootPart.CreatorIdentification, so2.RootPart.CreatorIdentification, "RewriteSOP failed to transform CreatorData."); + Assert.That(so2.RootPart.CreatorIdentification.Contains("http://"), "RewriteSOP failed to add the homeURL to CreatorData"); + } + } +} \ No newline at end of file diff --git a/Tests/OpenSim.Region.Framework.Tests/Scenes/Tests/SceneObjectSpatialTests.cs b/Tests/OpenSim.Region.Framework.Tests/Scenes/Tests/SceneObjectSpatialTests.cs new file mode 100644 index 00000000000..c2c78228807 --- /dev/null +++ b/Tests/OpenSim.Region.Framework.Tests/Scenes/Tests/SceneObjectSpatialTests.cs @@ -0,0 +1,153 @@ +/* + * 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.Reflection; +using System.Threading; +using NUnit.Framework; +using OpenMetaverse; +using OpenSim.Framework; +using OpenSim.Region.Framework.Scenes; +using OpenSim.Tests.Common; + +namespace OpenSim.Region.Framework.Scenes.Tests +{ + /// + /// Spatial scene object tests (will eventually cover root and child part position, rotation properties, etc.) + /// + [TestFixture] + public class SceneObjectSpatialTests : OpenSimTestCase + { + TestScene m_scene; + UUID m_ownerId = TestHelpers.ParseTail(0x1); + + [SetUp] + public override void SetUp() + { + base.SetUp(); + + m_scene = new SceneHelpers().SetupScene(); + } + + [Test] + public void TestGetSceneObjectGroupPosition() + { + TestHelpers.InMethod(); + + Vector3 position = new Vector3(10, 20, 30); + + SceneObjectGroup so + = SceneHelpers.CreateSceneObject(1, m_ownerId, "obj1", 0x10); + so.AbsolutePosition = position; + m_scene.AddNewSceneObject(so, false); + + Assert.That(so.AbsolutePosition, Is.EqualTo(position)); + } + + [Test] + public void TestGetRootPartPosition() + { + TestHelpers.InMethod(); + + Vector3 partPosition = new Vector3(10, 20, 30); + + SceneObjectGroup so + = SceneHelpers.CreateSceneObject(1, m_ownerId, "obj1", 0x10); + so.AbsolutePosition = partPosition; + m_scene.AddNewSceneObject(so, false); + + Assert.That(so.RootPart.AbsolutePosition, Is.EqualTo(partPosition)); + Assert.That(so.RootPart.GroupPosition, Is.EqualTo(partPosition)); + Assert.That(so.RootPart.GetWorldPosition(), Is.EqualTo(partPosition)); + Assert.That(so.RootPart.RelativePosition, Is.EqualTo(partPosition)); + Assert.That(so.RootPart.OffsetPosition, Is.EqualTo(Vector3.Zero)); + } + + [Test] + public void TestGetChildPartPosition() + { + TestHelpers.InMethod(); + + Vector3 rootPartPosition = new Vector3(10, 20, 30); + Vector3 childOffsetPosition = new Vector3(2, 3, 4); + + SceneObjectGroup so + = SceneHelpers.CreateSceneObject(2, m_ownerId, "obj1", 0x10); + so.AbsolutePosition = rootPartPosition; + so.Parts[1].OffsetPosition = childOffsetPosition; + + m_scene.AddNewSceneObject(so, false); + + // Calculate child absolute position. + Vector3 childPosition = new Vector3(rootPartPosition + childOffsetPosition); + + SceneObjectPart childPart = so.Parts[1]; + Assert.That(childPart.AbsolutePosition, Is.EqualTo(childPosition)); + Assert.That(childPart.GroupPosition, Is.EqualTo(rootPartPosition)); + Assert.That(childPart.GetWorldPosition(), Is.EqualTo(childPosition)); + Assert.That(childPart.RelativePosition, Is.EqualTo(childOffsetPosition)); + Assert.That(childPart.OffsetPosition, Is.EqualTo(childOffsetPosition)); + } + + [Test] + public void TestGetChildPartPositionAfterObjectRotation() + { + TestHelpers.InMethod(); + + Vector3 rootPartPosition = new Vector3(10, 20, 30); + Vector3 childOffsetPosition = new Vector3(2, 3, 4); + + SceneObjectGroup so + = SceneHelpers.CreateSceneObject(2, m_ownerId, "obj1", 0x10); + so.AbsolutePosition = rootPartPosition; + so.Parts[1].OffsetPosition = childOffsetPosition; + + m_scene.AddNewSceneObject(so, false); + + so.UpdateGroupRotationR(Quaternion.CreateFromEulers(0, 0, -90 * Utils.DEG_TO_RAD)); + + // Calculate child absolute position. + Vector3 rotatedChildOffsetPosition + = new Vector3(childOffsetPosition.Y, -childOffsetPosition.X, childOffsetPosition.Z); + + Vector3 childPosition = new Vector3(rootPartPosition + rotatedChildOffsetPosition); + + SceneObjectPart childPart = so.Parts[1]; + + Assert.That(childPart.AbsolutePosition, Is.EqualTo(childPosition)); + + Assert.That(childPart.GroupPosition, Is.EqualTo(rootPartPosition)); + Assert.That(childPart.GetWorldPosition(), Is.EqualTo(childPosition)); + + // Relative to root part as (0, 0, 0) + Assert.That(childPart.RelativePosition, Is.EqualTo(childOffsetPosition)); + + // Relative to root part as (0, 0, 0) + Assert.That(childPart.OffsetPosition, Is.EqualTo(childOffsetPosition)); + } + } +} \ No newline at end of file diff --git a/Tests/OpenSim.Region.Framework.Tests/Scenes/Tests/SceneObjectStatusTests.cs b/Tests/OpenSim.Region.Framework.Tests/Scenes/Tests/SceneObjectStatusTests.cs new file mode 100644 index 00000000000..8d880830799 --- /dev/null +++ b/Tests/OpenSim.Region.Framework.Tests/Scenes/Tests/SceneObjectStatusTests.cs @@ -0,0 +1,242 @@ +/* + * 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 System.Reflection; +using NUnit.Framework; +using OpenMetaverse; +using OpenSim.Framework; +using OpenSim.Region.Framework.Scenes; +using OpenSim.Tests.Common; + +namespace OpenSim.Region.Framework.Scenes.Tests +{ + /// + /// Basic scene object status tests + /// + [TestFixture] + public class SceneObjectStatusTests : OpenSimTestCase + { + private TestScene m_scene; + private UUID m_ownerId = TestHelpers.ParseTail(0x1); + private SceneObjectGroup m_so1; + private SceneObjectGroup m_so2; + + [SetUp] + public void Init() + { + m_scene = new SceneHelpers().SetupScene(); + m_so1 = SceneHelpers.CreateSceneObject(1, m_ownerId, "so1", 0x10); + m_so2 = SceneHelpers.CreateSceneObject(1, m_ownerId, "so2", 0x20); + } + + [Test] + public void TestSetTemporary() + { + TestHelpers.InMethod(); + + m_scene.AddSceneObject(m_so1); + m_so1.ScriptSetTemporaryStatus(true); + + // Is this really the correct flag? + Assert.That(m_so1.RootPart.Flags, Is.EqualTo(PrimFlags.TemporaryOnRez)); + Assert.That(m_so1.Backup, Is.False); + + // Test setting back to non-temporary + m_so1.ScriptSetTemporaryStatus(false); + + Assert.That(m_so1.RootPart.Flags, Is.EqualTo(PrimFlags.None)); + Assert.That(m_so1.Backup, Is.True); + } + + [Test] + public void TestSetPhantomSinglePrim() + { + TestHelpers.InMethod(); + + m_scene.AddSceneObject(m_so1); + + SceneObjectPart rootPart = m_so1.RootPart; + Assert.That(rootPart.Flags, Is.EqualTo(PrimFlags.None)); + + m_so1.ScriptSetPhantomStatus(true); + +// Console.WriteLine("so.RootPart.Flags [{0}]", so.RootPart.Flags); + Assert.That(rootPart.Flags, Is.EqualTo(PrimFlags.Phantom)); + + m_so1.ScriptSetPhantomStatus(false); + + Assert.That(rootPart.Flags, Is.EqualTo(PrimFlags.None)); + } + + [Test] + public void TestSetNonPhysicsVolumeDetectSinglePrim() + { + TestHelpers.InMethod(); + + m_scene.AddSceneObject(m_so1); + + SceneObjectPart rootPart = m_so1.RootPart; + Assert.That(rootPart.Flags, Is.EqualTo(PrimFlags.None)); + + m_so1.ScriptSetVolumeDetect(true); + +// Console.WriteLine("so.RootPart.Flags [{0}]", so.RootPart.Flags); + // PrimFlags.JointLP2P is incorrect it now means VolumeDetect (as defined by viewers) + Assert.That(rootPart.Flags, Is.EqualTo(PrimFlags.Phantom | PrimFlags.JointLP2P)); + + m_so1.ScriptSetVolumeDetect(false); + + Assert.That(rootPart.Flags, Is.EqualTo(PrimFlags.None)); + } + + [Test] + public void TestSetPhysicsSinglePrim() + { + TestHelpers.InMethod(); + + m_scene.AddSceneObject(m_so1); + + SceneObjectPart rootPart = m_so1.RootPart; + Assert.That(rootPart.Flags, Is.EqualTo(PrimFlags.None)); + + m_so1.ScriptSetPhysicsStatus(true); + + Assert.That(rootPart.Flags, Is.EqualTo(PrimFlags.Physics)); + + m_so1.ScriptSetPhysicsStatus(false); + + Assert.That(rootPart.Flags, Is.EqualTo(PrimFlags.None)); + } + + [Test] + public void TestSetPhysicsVolumeDetectSinglePrim() + { + TestHelpers.InMethod(); + + m_scene.AddSceneObject(m_so1); + + SceneObjectPart rootPart = m_so1.RootPart; + Assert.That(rootPart.Flags, Is.EqualTo(PrimFlags.None)); + + m_so1.ScriptSetPhysicsStatus(true); + m_so1.ScriptSetVolumeDetect(true); + + // PrimFlags.JointLP2P is incorrect it now means VolumeDetect (as defined by viewers) + Assert.That(rootPart.Flags, Is.EqualTo(PrimFlags.Phantom | PrimFlags.Physics | PrimFlags.JointLP2P)); + + m_so1.ScriptSetVolumeDetect(false); + + Assert.That(rootPart.Flags, Is.EqualTo(PrimFlags.Physics)); + } + + [Test] + public void TestSetPhysicsLinkset() + { + TestHelpers.InMethod(); + + m_scene.AddSceneObject(m_so1); + m_scene.AddSceneObject(m_so2); + + m_scene.LinkObjects(m_ownerId, m_so1.LocalId, new List() { m_so2.LocalId }); + + m_so1.ScriptSetPhysicsStatus(true); + + Assert.That(m_so1.RootPart.Flags, Is.EqualTo(PrimFlags.Physics)); + Assert.That(m_so1.Parts[1].Flags, Is.EqualTo(PrimFlags.Physics)); + + m_so1.ScriptSetPhysicsStatus(false); + + Assert.That(m_so1.RootPart.Flags, Is.EqualTo(PrimFlags.None)); + Assert.That(m_so1.Parts[1].Flags, Is.EqualTo(PrimFlags.None)); + + m_so1.ScriptSetPhysicsStatus(true); + + Assert.That(m_so1.RootPart.Flags, Is.EqualTo(PrimFlags.Physics)); + Assert.That(m_so1.Parts[1].Flags, Is.EqualTo(PrimFlags.Physics)); + } + + /// + /// Test that linking results in the correct physical status for all linkees. + /// + [Test] + public void TestLinkPhysicsBothPhysical() + { + TestHelpers.InMethod(); + + m_scene.AddSceneObject(m_so1); + m_scene.AddSceneObject(m_so2); + + m_so1.ScriptSetPhysicsStatus(true); + m_so2.ScriptSetPhysicsStatus(true); + + m_scene.LinkObjects(m_ownerId, m_so1.LocalId, new List() { m_so2.LocalId }); + + Assert.That(m_so1.RootPart.Flags, Is.EqualTo(PrimFlags.Physics)); + Assert.That(m_so1.Parts[1].Flags, Is.EqualTo(PrimFlags.Physics)); + } + + /// + /// Test that linking results in the correct physical status for all linkees. + /// + [Test] + public void TestLinkPhysicsRootPhysicalOnly() + { + TestHelpers.InMethod(); + + m_scene.AddSceneObject(m_so1); + m_scene.AddSceneObject(m_so2); + + m_so1.ScriptSetPhysicsStatus(true); + + m_scene.LinkObjects(m_ownerId, m_so1.LocalId, new List() { m_so2.LocalId }); + + Assert.That(m_so1.RootPart.Flags, Is.EqualTo(PrimFlags.Physics)); + Assert.That(m_so1.Parts[1].Flags, Is.EqualTo(PrimFlags.Physics)); + } + + /// + /// Test that linking results in the correct physical status for all linkees. + /// + [Test] + public void TestLinkPhysicsChildPhysicalOnly() + { + TestHelpers.InMethod(); + + m_scene.AddSceneObject(m_so1); + m_scene.AddSceneObject(m_so2); + + m_so2.ScriptSetPhysicsStatus(true); + + m_scene.LinkObjects(m_ownerId, m_so1.LocalId, new List() { m_so2.LocalId }); + + Assert.That(m_so1.RootPart.Flags, Is.EqualTo(PrimFlags.None)); + Assert.That(m_so1.Parts[1].Flags, Is.EqualTo(PrimFlags.None)); + } + } +} \ No newline at end of file diff --git a/Tests/OpenSim.Region.Framework.Tests/Scenes/Tests/SceneObjectUndoRedoTests.cs b/Tests/OpenSim.Region.Framework.Tests/Scenes/Tests/SceneObjectUndoRedoTests.cs new file mode 100644 index 00000000000..340da9cef3d --- /dev/null +++ b/Tests/OpenSim.Region.Framework.Tests/Scenes/Tests/SceneObjectUndoRedoTests.cs @@ -0,0 +1,184 @@ +/* + * 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. + */ + +/* undo has changed, this tests dont apply without large changes +using System; +using System.Reflection; +using NUnit.Framework; +using OpenMetaverse; +using OpenSim.Framework; +using OpenSim.Region.Framework.Scenes; +using OpenSim.Tests.Common; + +namespace OpenSim.Region.Framework.Scenes.Tests +{ + /// + /// Tests for undo/redo + /// + public class SceneObjectUndoRedoTests : OpenSimTestCase + { + [Test] + public void TestUndoRedoResizeSceneObject() + { + TestHelpers.InMethod(); +// TestHelpers.EnableLogging(); + + Vector3 firstSize = new Vector3(2, 3, 4); + Vector3 secondSize = new Vector3(5, 6, 7); + + Scene scene = new SceneHelpers().SetupScene(); + scene.MaxUndoCount = 20; + SceneObjectGroup g1 = SceneHelpers.AddSceneObject(scene); + + // TODO: It happens to be the case that we are not storing undo states for SOPs which are not yet in a SOG, + // which is the way that AddSceneObject() sets up the object (i.e. it creates the SOP first). However, + // this is somewhat by chance. Really, we shouldn't be storing undo states at all if the object is not + // in a scene. + Assert.That(g1.RootPart.UndoCount, Is.EqualTo(0)); + + g1.GroupResize(firstSize); + Assert.That(g1.RootPart.UndoCount, Is.EqualTo(1)); + + g1.GroupResize(secondSize); + Assert.That(g1.RootPart.UndoCount, Is.EqualTo(2)); + + g1.RootPart.Undo(); + Assert.That(g1.RootPart.UndoCount, Is.EqualTo(1)); + Assert.That(g1.GroupScale, Is.EqualTo(firstSize)); + + g1.RootPart.Redo(); + Assert.That(g1.RootPart.UndoCount, Is.EqualTo(2)); + Assert.That(g1.GroupScale, Is.EqualTo(secondSize)); + } + + [Test] + public void TestUndoLimit() + { + TestHelpers.InMethod(); + + Vector3 firstSize = new Vector3(2, 3, 4); + Vector3 secondSize = new Vector3(5, 6, 7); + Vector3 thirdSize = new Vector3(8, 9, 10); + Vector3 fourthSize = new Vector3(11, 12, 13); + + Scene scene = new SceneHelpers().SetupScene(); + scene.MaxUndoCount = 2; + SceneObjectGroup g1 = SceneHelpers.AddSceneObject(scene); + + g1.GroupResize(firstSize); + g1.GroupResize(secondSize); + g1.GroupResize(thirdSize); + g1.GroupResize(fourthSize); + + g1.RootPart.Undo(); + g1.RootPart.Undo(); + g1.RootPart.Undo(); + + Assert.That(g1.RootPart.UndoCount, Is.EqualTo(0)); + Assert.That(g1.GroupScale, Is.EqualTo(secondSize)); + } + + [Test] + public void TestNoUndoOnObjectsNotInScene() + { + TestHelpers.InMethod(); + + Vector3 firstSize = new Vector3(2, 3, 4); + Vector3 secondSize = new Vector3(5, 6, 7); +// Vector3 thirdSize = new Vector3(8, 9, 10); +// Vector3 fourthSize = new Vector3(11, 12, 13); + + Scene scene = new SceneHelpers().SetupScene(); + scene.MaxUndoCount = 20; + SceneObjectGroup g1 = SceneHelpers.CreateSceneObject(1, TestHelpers.ParseTail(0x1)); + + g1.GroupResize(firstSize); + g1.GroupResize(secondSize); + + Assert.That(g1.RootPart.UndoCount, Is.EqualTo(0)); + + g1.RootPart.Undo(); + + Assert.That(g1.GroupScale, Is.EqualTo(secondSize)); + } + + [Test] + public void TestUndoBeyondAvailable() + { + TestHelpers.InMethod(); + + Vector3 newSize = new Vector3(2, 3, 4); + + Scene scene = new SceneHelpers().SetupScene(); + scene.MaxUndoCount = 20; + SceneObjectGroup g1 = SceneHelpers.AddSceneObject(scene); + Vector3 originalSize = g1.GroupScale; + + g1.RootPart.Undo(); + + Assert.That(g1.RootPart.UndoCount, Is.EqualTo(0)); + Assert.That(g1.GroupScale, Is.EqualTo(originalSize)); + + g1.GroupResize(newSize); + Assert.That(g1.RootPart.UndoCount, Is.EqualTo(1)); + Assert.That(g1.GroupScale, Is.EqualTo(newSize)); + + g1.RootPart.Undo(); + g1.RootPart.Undo(); + + Assert.That(g1.RootPart.UndoCount, Is.EqualTo(0)); + Assert.That(g1.GroupScale, Is.EqualTo(originalSize)); + } + + [Test] + public void TestRedoBeyondAvailable() + { + TestHelpers.InMethod(); + + Vector3 newSize = new Vector3(2, 3, 4); + + Scene scene = new SceneHelpers().SetupScene(); + scene.MaxUndoCount = 20; + SceneObjectGroup g1 = SceneHelpers.AddSceneObject(scene); + Vector3 originalSize = g1.GroupScale; + + g1.RootPart.Redo(); + + Assert.That(g1.RootPart.UndoCount, Is.EqualTo(0)); + Assert.That(g1.GroupScale, Is.EqualTo(originalSize)); + + g1.GroupResize(newSize); + g1.RootPart.Undo(); + g1.RootPart.Redo(); + g1.RootPart.Redo(); + + Assert.That(g1.RootPart.UndoCount, Is.EqualTo(1)); + Assert.That(g1.GroupScale, Is.EqualTo(newSize)); + } + } +} +*/ \ No newline at end of file diff --git a/Tests/OpenSim.Region.Framework.Tests/Scenes/Tests/SceneObjectUserGroupTests.cs b/Tests/OpenSim.Region.Framework.Tests/Scenes/Tests/SceneObjectUserGroupTests.cs new file mode 100644 index 00000000000..4ec69cd8fdf --- /dev/null +++ b/Tests/OpenSim.Region.Framework.Tests/Scenes/Tests/SceneObjectUserGroupTests.cs @@ -0,0 +1,83 @@ +/* + * 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 System.Reflection; +using Nini.Config; +using NUnit.Framework; +using OpenMetaverse; +using OpenSim.Framework; +using OpenSim.Region.CoreModules.Avatar.InstantMessage; +using OpenSim.Region.CoreModules.World.Permissions; +using OpenSim.Region.Framework.Interfaces; +using OpenSim.Region.Framework.Scenes; +using OpenSim.Region.OptionalModules.Avatar.XmlRpcGroups; +using OpenSim.Tests.Common; + +namespace OpenSim.Region.Framework.Scenes.Tests +{ + [TestFixture] + public class SceneObjectUserGroupTests + { + /// + /// Test share with group object functionality + /// + /// This test is not yet fully implemented + [Test] + public void TestShareWithGroup() + { + TestHelpers.InMethod(); +// log4net.Config.XmlConfigurator.Configure(); + + UUID userId = UUID.Parse("10000000-0000-0000-0000-000000000001"); + + TestScene scene = new SceneHelpers().SetupScene(); + IConfigSource configSource = new IniConfigSource(); + + IConfig startupConfig = configSource.AddConfig("Startup"); + startupConfig.Set("serverside_object_permissions", true); + + IConfig groupsConfig = configSource.AddConfig("Groups"); + groupsConfig.Set("Enabled", true); + groupsConfig.Set("Module", "GroupsModule"); + groupsConfig.Set("DebugEnabled", true); + + SceneHelpers.SetupSceneModules( + scene, configSource, new object[] + { new DefaultPermissionsModule(), + new GroupsModule(), + new MockGroupsServicesConnector() }); + + IClientAPI client = SceneHelpers.AddScenePresence(scene, userId).ControllingClient; + + IGroupsModule groupsModule = scene.RequestModuleInterface(); + + groupsModule.CreateGroup(client, "group1", "To boldly go", true, UUID.Zero, 5, true, true, true); + } + } +} diff --git a/Tests/OpenSim.Region.Framework.Tests/Scenes/Tests/ScenePresenceAgentTests.cs b/Tests/OpenSim.Region.Framework.Tests/Scenes/Tests/ScenePresenceAgentTests.cs new file mode 100644 index 00000000000..0f386bc57cc --- /dev/null +++ b/Tests/OpenSim.Region.Framework.Tests/Scenes/Tests/ScenePresenceAgentTests.cs @@ -0,0 +1,291 @@ +/* + * 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 System.Reflection; +using System.Text; +using System.Threading; +using System.Timers; +using Timer = System.Timers.Timer; +using Nini.Config; +using NUnit.Framework; +using OpenMetaverse; +using OpenSim.Framework; +using OpenSim.Region.Framework.Scenes; +using OpenSim.Region.Framework.Interfaces; +using OpenSim.Region.ClientStack.Linden; +using OpenSim.Region.CoreModules.Framework.EntityTransfer; +using OpenSim.Region.CoreModules.World.Serialiser; +using OpenSim.Region.CoreModules.ServiceConnectorsOut.Simulation; +using OpenSim.Tests.Common; +using GridRegion = OpenSim.Services.Interfaces.GridRegion; +using OpenSim.Services.Interfaces; + +namespace OpenSim.Region.Framework.Scenes.Tests +{ + /// + /// Scene presence tests + /// + [TestFixture] + public class ScenePresenceAgentTests : OpenSimTestCase + { +// public Scene scene, scene2, scene3; +// public UUID agent1, agent2, agent3; +// public static Random random; +// public ulong region1, region2, region3; +// public AgentCircuitData acd1; +// public TestClient testclient; + +// [TestFixtureSetUp] +// public void Init() +// { +//// TestHelpers.InMethod(); +//// +//// SceneHelpers sh = new SceneHelpers(); +//// +//// scene = sh.SetupScene("Neighbour x", UUID.Random(), 1000, 1000); +//// scene2 = sh.SetupScene("Neighbour x+1", UUID.Random(), 1001, 1000); +//// scene3 = sh.SetupScene("Neighbour x-1", UUID.Random(), 999, 1000); +//// +//// ISharedRegionModule interregionComms = new LocalSimulationConnectorModule(); +//// interregionComms.Initialise(new IniConfigSource()); +//// interregionComms.PostInitialise(); +//// SceneHelpers.SetupSceneModules(scene, new IniConfigSource(), interregionComms); +//// SceneHelpers.SetupSceneModules(scene2, new IniConfigSource(), interregionComms); +//// SceneHelpers.SetupSceneModules(scene3, new IniConfigSource(), interregionComms); +// +//// agent1 = UUID.Random(); +//// agent2 = UUID.Random(); +//// agent3 = UUID.Random(); +// +//// region1 = scene.RegionInfo.RegionHandle; +//// region2 = scene2.RegionInfo.RegionHandle; +//// region3 = scene3.RegionInfo.RegionHandle; +// } + + [Test] + public void TestCreateRootScenePresence() + { + TestHelpers.InMethod(); +// TestHelpers.EnableLogging(); + + UUID spUuid = TestHelpers.ParseTail(0x1); + + TestScene scene = new SceneHelpers().SetupScene(); + SceneHelpers.AddScenePresence(scene, spUuid); + + Assert.That(scene.AuthenticateHandler.GetAgentCircuitData(spUuid), Is.Not.Null); + Assert.That(scene.AuthenticateHandler.GetAgentCircuits().Count, Is.EqualTo(1)); + + ScenePresence sp = scene.GetScenePresence(spUuid); + Assert.That(sp, Is.Not.Null); + Assert.That(sp.IsChildAgent, Is.False); + Assert.That(sp.UUID, Is.EqualTo(spUuid)); + + Assert.That(scene.GetScenePresences().Count, Is.EqualTo(1)); + } + + /// + /// Test that duplicate complete movement calls are ignored. + /// + /// + /// If duplicate calls are not ignored then there is a risk of race conditions or other unexpected effects. + /// + [Test] + public void TestDupeCompleteMovementCalls() + { + TestHelpers.InMethod(); +// TestHelpers.EnableLogging(); + + UUID spUuid = TestHelpers.ParseTail(0x1); + + TestScene scene = new SceneHelpers().SetupScene(); + + int makeRootAgentEvents = 0; + scene.EventManager.OnMakeRootAgent += spi => makeRootAgentEvents++; + + ScenePresence sp = SceneHelpers.AddScenePresence(scene, spUuid); + + Assert.That(makeRootAgentEvents, Is.EqualTo(1)); + + // Normally these would be invoked by a CompleteMovement message coming in to the UDP stack. But for + // convenience, here we will invoke it manually. + sp.CompleteMovement(sp.ControllingClient, true); + + Assert.That(makeRootAgentEvents, Is.EqualTo(1)); + + // Check rest of exepcted parameters. + Assert.That(scene.AuthenticateHandler.GetAgentCircuitData(spUuid), Is.Not.Null); + Assert.That(scene.AuthenticateHandler.GetAgentCircuits().Count, Is.EqualTo(1)); + + Assert.That(sp.IsChildAgent, Is.False); + Assert.That(sp.UUID, Is.EqualTo(spUuid)); + + Assert.That(scene.GetScenePresences().Count, Is.EqualTo(1)); + } + + [Test] + public void TestCreateDuplicateRootScenePresence() + { + TestHelpers.InMethod(); +// TestHelpers.EnableLogging(); + + UUID spUuid = TestHelpers.ParseTail(0x1); + + // The etm is only invoked by this test to check whether an agent is still in transit if there is a dupe + EntityTransferModule etm = new EntityTransferModule(); + + IConfigSource config = new IniConfigSource(); + IConfig modulesConfig = config.AddConfig("Modules"); + modulesConfig.Set("EntityTransferModule", etm.Name); + IConfig entityTransferConfig = config.AddConfig("EntityTransfer"); + + // In order to run a single threaded regression test we do not want the entity transfer module waiting + // for a callback from the destination scene before removing its avatar data. + entityTransferConfig.Set("wait_for_callback", false); + + TestScene scene = new SceneHelpers().SetupScene(); + SceneHelpers.SetupSceneModules(scene, config, etm); + SceneHelpers.AddScenePresence(scene, spUuid); + SceneHelpers.AddScenePresence(scene, spUuid); + + Assert.That(scene.AuthenticateHandler.GetAgentCircuitData(spUuid), Is.Not.Null); + Assert.That(scene.AuthenticateHandler.GetAgentCircuits().Count, Is.EqualTo(1)); + + ScenePresence sp = scene.GetScenePresence(spUuid); + Assert.That(sp, Is.Not.Null); + Assert.That(sp.IsChildAgent, Is.False); + Assert.That(sp.UUID, Is.EqualTo(spUuid)); + } + + [Test] + public void TestCloseClient() + { + TestHelpers.InMethod(); +// TestHelpers.EnableLogging(); + + TestScene scene = new SceneHelpers().SetupScene(); + ScenePresence sp = SceneHelpers.AddScenePresence(scene, TestHelpers.ParseTail(0x1)); + + scene.CloseAgent(sp.UUID, false); + + Assert.That(scene.GetScenePresence(sp.UUID), Is.Null); + Assert.That(scene.AuthenticateHandler.GetAgentCircuitData(sp.UUID), Is.Null); + Assert.That(scene.AuthenticateHandler.GetAgentCircuits().Count, Is.EqualTo(0)); + +// TestHelpers.DisableLogging(); + } + + [Test] + public void TestCreateChildScenePresence() + { + TestHelpers.InMethod(); +// log4net.Config.XmlConfigurator.Configure(); + + LocalSimulationConnectorModule lsc = new LocalSimulationConnectorModule(); + + IConfigSource configSource = new IniConfigSource(); + IConfig config = configSource.AddConfig("Modules"); + config.Set("SimulationServices", "LocalSimulationConnectorModule"); + + SceneHelpers sceneHelpers = new SceneHelpers(); + TestScene scene = sceneHelpers.SetupScene(); + SceneHelpers.SetupSceneModules(scene, configSource, lsc); + + UUID agentId = TestHelpers.ParseTail(0x01); + AgentCircuitData acd = SceneHelpers.GenerateAgentData(agentId); + acd.child = true; + + GridRegion region = scene.GridService.GetRegionByName(UUID.Zero, scene.RegionInfo.RegionName); + string reason; + + // *** This is the first stage, when a neighbouring region is told that a viewer is about to try and + // establish a child scene presence. We pass in the circuit code that the client has to connect with *** + // XXX: ViaLogin may not be correct here. + EntityTransferContext ctx = new EntityTransferContext(); + scene.SimulationService.CreateAgent(null, region, acd, (uint)TeleportFlags.ViaLogin, ctx, out reason); + + Assert.That(scene.AuthenticateHandler.GetAgentCircuitData(agentId), Is.Not.Null); + Assert.That(scene.AuthenticateHandler.GetAgentCircuits().Count, Is.EqualTo(1)); + + // There's no scene presence yet since only an agent circuit has been established. + Assert.That(scene.GetScenePresence(agentId), Is.Null); + + // *** This is the second stage, where the client established a child agent/scene presence using the + // circuit code given to the scene in stage 1 *** + TestClient client = new TestClient(acd, scene); + scene.AddNewAgent(client, PresenceType.User); + + Assert.That(scene.AuthenticateHandler.GetAgentCircuitData(agentId), Is.Not.Null); + Assert.That(scene.AuthenticateHandler.GetAgentCircuits().Count, Is.EqualTo(1)); + + ScenePresence sp = scene.GetScenePresence(agentId); + Assert.That(sp, Is.Not.Null); + Assert.That(sp.UUID, Is.EqualTo(agentId)); + Assert.That(sp.IsChildAgent, Is.True); + } + + /// + /// Test that if a root agent logs into a region, a child agent is also established in the neighbouring region + /// + /// + /// Please note that unlike the other tests here, this doesn't rely on anything set up in the instance fields. + /// INCOMPLETE + /// + [Test] + public void TestChildAgentEstablishedInNeighbour() + { + TestHelpers.InMethod(); +// log4net.Config.XmlConfigurator.Configure(); + +// UUID agent1Id = UUID.Parse("00000000-0000-0000-0000-000000000001"); + + TestScene myScene1 = new SceneHelpers().SetupScene("Neighbour y", UUID.Random(), 1000, 1000); + TestScene myScene2 = new SceneHelpers().SetupScene("Neighbour y + 1", UUID.Random(), 1001, 1000); + + IConfigSource configSource = new IniConfigSource(); + IConfig config = configSource.AddConfig("Startup"); + config.Set("serverside_object_permissions", true); + + EntityTransferModule etm = new EntityTransferModule(); + + EventQueueGetModule eqgm1 = new EventQueueGetModule(); + SceneHelpers.SetupSceneModules(myScene1, configSource, etm, eqgm1); + + EventQueueGetModule eqgm2 = new EventQueueGetModule(); + SceneHelpers.SetupSceneModules(myScene2, configSource, etm, eqgm2); + +// SceneHelpers.AddScenePresence(myScene1, agent1Id); +// ScenePresence childPresence = myScene2.GetScenePresence(agent1); +// +// // TODO: Need to do a fair amount of work to allow synchronous establishment of child agents +// Assert.That(childPresence, Is.Not.Null); +// Assert.That(childPresence.IsChildAgent, Is.True); + } + } +} diff --git a/Tests/OpenSim.Region.Framework.Tests/Scenes/Tests/ScenePresenceAnimationTests.cs b/Tests/OpenSim.Region.Framework.Tests/Scenes/Tests/ScenePresenceAnimationTests.cs new file mode 100644 index 00000000000..d650c4346d9 --- /dev/null +++ b/Tests/OpenSim.Region.Framework.Tests/Scenes/Tests/ScenePresenceAnimationTests.cs @@ -0,0 +1,68 @@ +/* + * 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 System.Reflection; +using System.Text; +using System.Threading; +using System.Timers; +using Nini.Config; +using NUnit.Framework; +using OpenMetaverse; +using OpenSim.Framework; +using OpenSim.Region.Framework.Scenes; +using OpenSim.Region.Framework.Interfaces; +using OpenSim.Region.CoreModules.Framework.EntityTransfer; +using OpenSim.Region.CoreModules.World.Serialiser; +using OpenSim.Region.CoreModules.ServiceConnectorsOut.Simulation; +using OpenSim.Region.PhysicsModules.SharedBase; +using OpenSim.Tests.Common; + +namespace OpenSim.Region.Framework.Scenes.Tests +{ + /// + /// Scene presence animation tests + /// + [TestFixture] + public class ScenePresenceAnimationTests : OpenSimTestCase + { + [Test] + public void TestFlyingAnimation() + { + TestHelpers.InMethod(); +// log4net.Config.XmlConfigurator.Configure(); + + TestScene scene = new SceneHelpers().SetupScene(); + ScenePresence sp = SceneHelpers.AddScenePresence(scene, TestHelpers.ParseTail(0x1)); + sp.Flying = true; + sp.Animator.UpdateMovementAnimations(); + + Assert.That(sp.Animator.CurrentMovementAnimation, Is.EqualTo("HOVER")); + } + } +} \ No newline at end of file diff --git a/Tests/OpenSim.Region.Framework.Tests/Scenes/Tests/ScenePresenceAutopilotTests.cs b/Tests/OpenSim.Region.Framework.Tests/Scenes/Tests/ScenePresenceAutopilotTests.cs new file mode 100644 index 00000000000..60baaf2de1d --- /dev/null +++ b/Tests/OpenSim.Region.Framework.Tests/Scenes/Tests/ScenePresenceAutopilotTests.cs @@ -0,0 +1,131 @@ +/* + * 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 System.Reflection; +using log4net; +using Nini.Config; +using NUnit.Framework; +using OpenMetaverse; +using OpenSim.Framework; +using OpenSim.Region.Framework.Interfaces; +using OpenSim.Region.Framework.Scenes; +using OpenSim.Tests.Common; + +namespace OpenSim.Region.Framework.Scenes.Tests +{ + [TestFixture] + public class ScenePresenceAutopilotTests : OpenSimTestCase + { + private TestScene m_scene; + + [OneTimeSetUp] + public void FixtureInit() + { + // Don't allow tests to be bamboozled by asynchronous events. Execute everything on the same thread. + Util.FireAndForgetMethod = FireAndForgetMethod.None; + } + + [OneTimeTearDown] + 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 not to worry about such things. + Util.FireAndForgetMethod = Util.DefaultFireAndForgetMethod; + } + + [SetUp] + public void Init() + { + m_scene = new SceneHelpers().SetupScene(); + } + + [Test] + public void TestMove() + { + TestHelpers.InMethod(); +// log4net.Config.XmlConfigurator.Configure(); + + ScenePresence sp = SceneHelpers.AddScenePresence(m_scene, TestHelpers.ParseTail(0x1)); + + Vector3 startPos = sp.AbsolutePosition; +// Vector3 startPos = new Vector3(128, 128, 30); + + // For now, we'll make the scene presence fly to simplify this test, but this needs to change. + sp.Flying = true; + + m_scene.Update(1); + Assert.That(sp.AbsolutePosition, Is.EqualTo(startPos)); + + Vector3 targetPos = startPos + new Vector3(0, 10, 0); + sp.MoveToTarget(targetPos, false, false, false); + + Assert.That(sp.AbsolutePosition, Is.EqualTo(startPos)); + Assert.That( + sp.Rotation, new QuaternionToleranceConstraint(new Quaternion(0, 0, 0.7071068f, 0.7071068f), 0.000001)); + + m_scene.Update(1); + + // We should really check the exact figure. + Assert.That(sp.AbsolutePosition.X, Is.EqualTo(startPos.X)); + Assert.That(sp.AbsolutePosition.Y, Is.GreaterThan(startPos.Y)); + Assert.That(sp.AbsolutePosition.Z, Is.EqualTo(startPos.Z)); + Assert.That(sp.AbsolutePosition.Z, Is.LessThan(targetPos.X)); + + m_scene.Update(50); + + double distanceToTarget = Util.GetDistanceTo(sp.AbsolutePosition, targetPos); + Assert.That(distanceToTarget, Is.LessThan(1), "Avatar not within 1 unit of target position on first move"); + Assert.That(sp.AbsolutePosition, Is.EqualTo(targetPos)); + Assert.That(sp.AgentControlFlags, Is.EqualTo((uint)AgentManager.ControlFlags.NONE)); + + // Try a second movement + startPos = sp.AbsolutePosition; + targetPos = startPos + new Vector3(10, 0, 0); + sp.MoveToTarget(targetPos, false, false, false); + + Assert.That(sp.AbsolutePosition, Is.EqualTo(startPos)); + Assert.That( + sp.Rotation, new QuaternionToleranceConstraint(new Quaternion(0, 0, 0, 1), 0.000001)); + + m_scene.Update(1); + + // We should really check the exact figure. + Assert.That(sp.AbsolutePosition.X, Is.GreaterThan(startPos.X)); + Assert.That(sp.AbsolutePosition.X, Is.LessThan(targetPos.X)); + Assert.That(sp.AbsolutePosition.Y, Is.EqualTo(startPos.Y)); + Assert.That(sp.AbsolutePosition.Z, Is.EqualTo(startPos.Z)); + + m_scene.Update(50); + + distanceToTarget = Util.GetDistanceTo(sp.AbsolutePosition, targetPos); + Assert.That(distanceToTarget, Is.LessThan(1), "Avatar not within 1 unit of target position on second move"); + Assert.That(sp.AbsolutePosition, Is.EqualTo(targetPos)); + } + } +} \ No newline at end of file diff --git a/Tests/OpenSim.Region.Framework.Tests/Scenes/Tests/ScenePresenceCapabilityTests.cs b/Tests/OpenSim.Region.Framework.Tests/Scenes/Tests/ScenePresenceCapabilityTests.cs new file mode 100644 index 00000000000..aa2676768cd --- /dev/null +++ b/Tests/OpenSim.Region.Framework.Tests/Scenes/Tests/ScenePresenceCapabilityTests.cs @@ -0,0 +1,88 @@ +/* + * 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 System.Reflection; +using System.Text; +using System.Threading; +using System.Timers; +using Timer = System.Timers.Timer; +using Nini.Config; +using NUnit.Framework; +using OpenMetaverse; +using OpenSim.Framework; +using OpenSim.Framework.Servers; +using OpenSim.Framework.Servers.HttpServer; +using OpenSim.Region.ClientStack.Linden; +using OpenSim.Region.CoreModules.Framework; +using OpenSim.Region.CoreModules.Framework.EntityTransfer; +using OpenSim.Region.CoreModules.World.Serialiser; +using OpenSim.Region.CoreModules.ServiceConnectorsOut.Simulation; +using OpenSim.Region.Framework.Scenes; +using OpenSim.Region.Framework.Interfaces; +using OpenSim.Tests.Common; +using GridRegion = OpenSim.Services.Interfaces.GridRegion; + +namespace OpenSim.Region.Framework.Scenes.Tests +{ + [TestFixture] + public class ScenePresenceCapabilityTests : OpenSimTestCase + { + [Test] + public void TestChildAgentSingleRegionCapabilities() + { + TestHelpers.InMethod(); +// TestHelpers.EnableLogging(); + + UUID spUuid = TestHelpers.ParseTail(0x1); + + // XXX: This is not great since the use of statics will mean that this has to be manually cleaned up for + // any subsequent test. + // XXX: May replace with a mock IHttpServer later. + BaseHttpServer httpServer = new BaseHttpServer(99999); + MainServer.AddHttpServer(httpServer); + MainServer.Instance = httpServer; + + CapabilitiesModule capsMod = new CapabilitiesModule(); + TestScene scene = new SceneHelpers().SetupScene(); + SceneHelpers.SetupSceneModules(scene, capsMod); + + ScenePresence sp = SceneHelpers.AddChildScenePresence(scene, spUuid); + //Assert.That(capsMod.GetCapsForUser(spUuid), Is.Not.Null); + + // TODO: Need to add tests for other ICapabiltiesModule methods. + +// scene.IncomingCloseAgent(sp.UUID, false); +// //Assert.That(capsMod.GetCapsForUser(spUuid), Is.Null); + scene.CloseAgent(sp.UUID, false); +// Assert.That(capsMod.GetCapsForUser(spUuid), Is.Null); + + // TODO: Need to add tests for other ICapabiltiesModule methods. + } + } +} diff --git a/Tests/OpenSim.Region.Framework.Tests/Scenes/Tests/ScenePresenceCrossingTests.cs b/Tests/OpenSim.Region.Framework.Tests/Scenes/Tests/ScenePresenceCrossingTests.cs new file mode 100644 index 00000000000..34e1a87ab4b --- /dev/null +++ b/Tests/OpenSim.Region.Framework.Tests/Scenes/Tests/ScenePresenceCrossingTests.cs @@ -0,0 +1,247 @@ +/* + * 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 System.Reflection; +using Nini.Config; +using NUnit.Framework; +using OpenMetaverse; +using OpenSim.Framework; +using OpenSim.Framework.Servers; +using OpenSim.Region.Framework.Interfaces; +using OpenSim.Region.CoreModules.Framework; +using OpenSim.Region.CoreModules.Framework.EntityTransfer; +using OpenSim.Region.CoreModules.ServiceConnectorsOut.Simulation; +using OpenSim.Region.CoreModules.World.Permissions; +using OpenSim.Tests.Common; +using OpenSim.Region.OptionalModules.Avatar.XmlRpcGroups; +using System.Threading; + +namespace OpenSim.Region.Framework.Scenes.Tests +{ + [TestFixture] + public class ScenePresenceCrossingTests : OpenSimTestCase + { + [OneTimeSetUp] + public void FixtureInit() + { + // Don't allow tests to be bamboozled by asynchronous events. Execute everything on the same thread. + Util.FireAndForgetMethod = FireAndForgetMethod.RegressionTest; + } + + [OneTimeTearDown] + 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] + public void TestCrossOnSameSimulator() + { + TestHelpers.InMethod(); +// TestHelpers.EnableLogging(); + + UUID userId = TestHelpers.ParseTail(0x1); + +// TestEventQueueGetModule eqmA = new TestEventQueueGetModule(); + EntityTransferModule etmA = new EntityTransferModule(); + EntityTransferModule etmB = new EntityTransferModule(); + LocalSimulationConnectorModule lscm = new LocalSimulationConnectorModule(); + + IConfigSource config = new IniConfigSource(); + IConfig modulesConfig = config.AddConfig("Modules"); + modulesConfig.Set("EntityTransferModule", etmA.Name); + modulesConfig.Set("SimulationServices", lscm.Name); +// IConfig entityTransferConfig = config.AddConfig("EntityTransfer"); + + // In order to run a single threaded regression test we do not want the entity transfer module waiting + // for a callback from the destination scene before removing its avatar data. +// entityTransferConfig.Set("wait_for_callback", false); + + SceneHelpers sh = new SceneHelpers(); + TestScene sceneA = sh.SetupScene("sceneA", TestHelpers.ParseTail(0x100), 1000, 1000); + TestScene sceneB = sh.SetupScene("sceneB", TestHelpers.ParseTail(0x200), 1000, 999); + + SceneHelpers.SetupSceneModules(new Scene[] { sceneA, sceneB }, config, lscm); + SceneHelpers.SetupSceneModules(sceneA, config, new CapabilitiesModule(), etmA); +// SceneHelpers.SetupSceneModules(sceneA, config, new CapabilitiesModule(), etmA, eqmA); + SceneHelpers.SetupSceneModules(sceneB, config, new CapabilitiesModule(), etmB); + + AgentCircuitData acd = SceneHelpers.GenerateAgentData(userId); + TestClient tc = new TestClient(acd, sceneA); + List destinationTestClients = new List(); + EntityTransferHelpers.SetupInformClientOfNeighbourTriggersNeighbourClientCreate(tc, destinationTestClients); + + ScenePresence originalSp = SceneHelpers.AddScenePresence(sceneA, tc, acd); + originalSp.AbsolutePosition = new Vector3(128, 32, 10); + +// originalSp.Flying = true; + +// Console.WriteLine("First pos {0}", originalSp.AbsolutePosition); + +// eqmA.ClearEvents(); + + AgentUpdateArgs moveArgs = new AgentUpdateArgs(); + //moveArgs.BodyRotation = Quaternion.CreateFromEulers(Vector3.Zero); + moveArgs.BodyRotation = Quaternion.CreateFromEulers(new Vector3(0, 0, (float)-(Math.PI / 2))); + moveArgs.ControlFlags = (uint)(AgentManager.ControlFlags.AGENT_CONTROL_AT_POS | AgentManager.ControlFlags.AGENT_CONTROL_FAST_AT); + + originalSp.HandleAgentUpdate(originalSp.ControllingClient, moveArgs); + + sceneA.Update(1); + +// Console.WriteLine("Second pos {0}", originalSp.AbsolutePosition); + + // FIXME: This is a sufficient number of updates to for the presence to reach the northern border. + // But really we want to do this in a more robust way. + for (int i = 0; i < 100; i++) + { + sceneA.Update(1); +// Console.WriteLine("Pos {0}", originalSp.AbsolutePosition); + } + + // Need to sort processing of EnableSimulator message on adding scene presences before we can test eqm + // messages +// Dictionary> eqmEvents = eqmA.Events; +// +// Assert.That(eqmEvents.Count, Is.EqualTo(1)); +// Assert.That(eqmEvents.ContainsKey(originalSp.UUID), Is.True); +// +// List spEqmEvents = eqmEvents[originalSp.UUID]; +// +// Assert.That(spEqmEvents.Count, Is.EqualTo(1)); +// Assert.That(spEqmEvents[0].Name, Is.EqualTo("CrossRegion")); + + // sceneA should now only have a child agent + ScenePresence spAfterCrossSceneA = sceneA.GetScenePresence(originalSp.UUID); + Assert.That(spAfterCrossSceneA.IsChildAgent, Is.True); + + ScenePresence spAfterCrossSceneB = sceneB.GetScenePresence(originalSp.UUID); + + // Agent remains a child until the client triggers complete movement + Assert.That(spAfterCrossSceneB.IsChildAgent, Is.True); + + TestClient sceneBTc = ((TestClient)spAfterCrossSceneB.ControllingClient); + + int agentMovementCompleteReceived = 0; + sceneBTc.OnReceivedMoveAgentIntoRegion += (ri, pos, look) => agentMovementCompleteReceived++; + + sceneBTc.CompleteMovement(); + + Assert.That(agentMovementCompleteReceived, Is.EqualTo(1)); + Assert.That(spAfterCrossSceneB.IsChildAgent, Is.False); + } + + /// + /// Test a cross attempt where the user can see into the neighbour but does not have permission to become + /// root there. + /// + [Test] + public void TestCrossOnSameSimulatorNoRootDestPerm() + { + TestHelpers.InMethod(); +// TestHelpers.EnableLogging(); + + UUID userId = TestHelpers.ParseTail(0x1); + + EntityTransferModule etmA = new EntityTransferModule(); + EntityTransferModule etmB = new EntityTransferModule(); + LocalSimulationConnectorModule lscm = new LocalSimulationConnectorModule(); + + IConfigSource config = new IniConfigSource(); + IConfig modulesConfig = config.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); + TestScene sceneB = sh.SetupScene("sceneB", TestHelpers.ParseTail(0x200), 1000, 999); + + SceneHelpers.SetupSceneModules(new Scene[] { sceneA, sceneB }, config, lscm); + SceneHelpers.SetupSceneModules(sceneA, config, new CapabilitiesModule(), etmA); + + // We need to set up the permisions module on scene B so that our later use of agent limit to deny + // QueryAccess won't succeed anyway because administrators are always allowed in and the default + // IsAdministrator if no permissions module is present is true. + SceneHelpers.SetupSceneModules(sceneB, config, new CapabilitiesModule(), new DefaultPermissionsModule(), etmB); + + AgentCircuitData acd = SceneHelpers.GenerateAgentData(userId); + TestClient tc = new TestClient(acd, sceneA); + List destinationTestClients = new List(); + EntityTransferHelpers.SetupInformClientOfNeighbourTriggersNeighbourClientCreate(tc, destinationTestClients); + + // Make sure sceneB will not accept this avatar. + sceneB.RegionInfo.EstateSettings.PublicAccess = false; + + ScenePresence originalSp = SceneHelpers.AddScenePresence(sceneA, tc, acd); + originalSp.AbsolutePosition = new Vector3(128, 32, 10); + + AgentUpdateArgs moveArgs = new AgentUpdateArgs(); + //moveArgs.BodyRotation = Quaternion.CreateFromEulers(Vector3.Zero); + moveArgs.BodyRotation = Quaternion.CreateFromEulers(new Vector3(0, 0, (float)-(Math.PI / 2))); + moveArgs.ControlFlags = (uint)(AgentManager.ControlFlags.AGENT_CONTROL_AT_POS | AgentManager.ControlFlags.AGENT_CONTROL_FAST_AT); + + originalSp.HandleAgentUpdate(originalSp.ControllingClient, moveArgs); + + sceneA.Update(1); + +// Console.WriteLine("Second pos {0}", originalSp.AbsolutePosition); + + // FIXME: This is a sufficient number of updates to for the presence to reach the northern border. + // But really we want to do this in a more robust way. + for (int i = 0; i < 100; i++) + { + sceneA.Update(1); +// Console.WriteLine("Pos {0}", originalSp.AbsolutePosition); + } + + // sceneA agent should still be root + ScenePresence spAfterCrossSceneA = sceneA.GetScenePresence(originalSp.UUID); + Assert.That(spAfterCrossSceneA.IsChildAgent, Is.False); + + ScenePresence spAfterCrossSceneB = sceneB.GetScenePresence(originalSp.UUID); + + // sceneB agent should still be child + Assert.That(spAfterCrossSceneB.IsChildAgent, Is.True); + + // sceneB should ignore unauthorized attempt to upgrade agent to root + TestClient sceneBTc = ((TestClient)spAfterCrossSceneB.ControllingClient); + + int agentMovementCompleteReceived = 0; + sceneBTc.OnReceivedMoveAgentIntoRegion += (ri, pos, look) => agentMovementCompleteReceived++; + + sceneBTc.CompleteMovement(); + + Assert.That(agentMovementCompleteReceived, Is.EqualTo(0)); + Assert.That(spAfterCrossSceneB.IsChildAgent, Is.True); + } + } +} diff --git a/Tests/OpenSim.Region.Framework.Tests/Scenes/Tests/ScenePresenceSitTests.cs b/Tests/OpenSim.Region.Framework.Tests/Scenes/Tests/ScenePresenceSitTests.cs new file mode 100644 index 00000000000..e3ebf365133 --- /dev/null +++ b/Tests/OpenSim.Region.Framework.Tests/Scenes/Tests/ScenePresenceSitTests.cs @@ -0,0 +1,251 @@ +/* + * 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 System.Reflection; +using Nini.Config; +using NUnit.Framework; +using OpenMetaverse; +using OpenSim.Framework; +using OpenSim.Framework.Servers; +using OpenSim.Region.Framework.Interfaces; +using OpenSim.Region.CoreModules.ServiceConnectorsOut.Simulation; +using OpenSim.Tests.Common; +using System.Threading; + +namespace OpenSim.Region.Framework.Scenes.Tests +{ + [TestFixture] + public class ScenePresenceSitTests : OpenSimTestCase + { + private TestScene m_scene; + private ScenePresence m_sp; + + [SetUp] + public void Init() + { + m_scene = new SceneHelpers().SetupScene(); + m_sp = SceneHelpers.AddScenePresence(m_scene, TestHelpers.ParseTail(0x1)); + } + + [Test] + public void TestSitOutsideRangeNoTarget() + { + TestHelpers.InMethod(); +// log4net.Config.XmlConfigurator.Configure(); + + // More than 10 meters away from 0, 0, 0 (default part position) + Vector3 startPos = new Vector3(10.1f, 0, 0); + m_sp.AbsolutePosition = startPos; + + SceneObjectPart part = SceneHelpers.AddSceneObject(m_scene).RootPart; + + m_sp.HandleAgentRequestSit(m_sp.ControllingClient, m_sp.UUID, part.UUID, Vector3.Zero); + + Assert.That(part.SitTargetAvatar, Is.EqualTo(UUID.Zero)); + Assert.That(part.GetSittingAvatarsCount(), Is.EqualTo(0)); + Assert.That(part.GetSittingAvatars(), Is.Null); + Assert.That(m_sp.ParentID, Is.EqualTo(0)); + Assert.AreEqual(startPos, m_sp.AbsolutePosition); + } + + [Test] + public void TestSitWithinRangeNoTarget() + { + TestHelpers.InMethod(); +// log4net.Config.XmlConfigurator.Configure(); + + // Less than 10 meters away from 0, 0, 0 (default part position) + Vector3 startPos = new Vector3(9.9f, 0, 0); + m_sp.AbsolutePosition = startPos; + + SceneObjectPart part = SceneHelpers.AddSceneObject(m_scene).RootPart; + + // We need to preserve this here because phys actor is removed by the sit. + Vector3 spPhysActorSize = m_sp.PhysicsActor.Size; + m_sp.HandleAgentRequestSit(m_sp.ControllingClient, m_sp.UUID, part.UUID, Vector3.Zero); + + Assert.That(m_sp.PhysicsActor, Is.Null); + + Assert.That( + m_sp.AbsolutePosition, + Is.EqualTo(part.AbsolutePosition + new Vector3(0, 0, spPhysActorSize.Z / 2))); + + Assert.That(part.SitTargetAvatar, Is.EqualTo(UUID.Zero)); + Assert.That(part.GetSittingAvatarsCount(), Is.EqualTo(1)); + HashSet sittingAvatars = part.GetSittingAvatars(); + Assert.That(sittingAvatars.Count, Is.EqualTo(1)); + Assert.That(sittingAvatars.Contains(m_sp)); + Assert.That(m_sp.ParentID, Is.EqualTo(part.LocalId)); + } + + [Test] + public void TestSitAndStandWithNoSitTarget() + { + TestHelpers.InMethod(); +// log4net.Config.XmlConfigurator.Configure(); + + // Make sure we're within range to sit + Vector3 startPos = new Vector3(1, 1, 1); + m_sp.AbsolutePosition = startPos; + + SceneObjectPart part = SceneHelpers.AddSceneObject(m_scene).RootPart; + + // We need to preserve this here because phys actor is removed by the sit. + Vector3 spPhysActorSize = m_sp.PhysicsActor.Size; + m_sp.HandleAgentRequestSit(m_sp.ControllingClient, m_sp.UUID, part.UUID, Vector3.Zero); + + Assert.That( + m_sp.AbsolutePosition, + Is.EqualTo(part.AbsolutePosition + new Vector3(0, 0, spPhysActorSize.Z / 2))); + + m_sp.StandUp(); + + Assert.That(part.SitTargetAvatar, Is.EqualTo(UUID.Zero)); + Assert.That(part.GetSittingAvatarsCount(), Is.EqualTo(0)); + Assert.That(part.GetSittingAvatars(), Is.Null); + Assert.That(m_sp.ParentID, Is.EqualTo(0)); + Assert.That(m_sp.PhysicsActor, Is.Not.Null); + } + + [Test] + public void TestSitAndStandWithNoSitTargetChildPrim() + { + TestHelpers.InMethod(); +// log4net.Config.XmlConfigurator.Configure(); + + // Make sure we're within range to sit + Vector3 startPos = new Vector3(1, 1, 1); + m_sp.AbsolutePosition = startPos; + + SceneObjectPart part = SceneHelpers.AddSceneObject(m_scene, 2, m_sp.UUID, "part", 0x10).Parts[1]; + part.OffsetPosition = new Vector3(2, 3, 4); + + // We need to preserve this here because phys actor is removed by the sit. + Vector3 spPhysActorSize = m_sp.PhysicsActor.Size; + m_sp.HandleAgentRequestSit(m_sp.ControllingClient, m_sp.UUID, part.UUID, Vector3.Zero); + + Assert.That( + m_sp.AbsolutePosition, + Is.EqualTo(part.AbsolutePosition + new Vector3(0, 0, spPhysActorSize.Z / 2))); + + m_sp.StandUp(); + + Assert.That(part.SitTargetAvatar, Is.EqualTo(UUID.Zero)); + Assert.That(part.GetSittingAvatarsCount(), Is.EqualTo(0)); + Assert.That(part.GetSittingAvatars(), Is.Null); + Assert.That(m_sp.ParentID, Is.EqualTo(0)); + Assert.That(m_sp.PhysicsActor, Is.Not.Null); + } + + [Test] + public void TestSitAndStandWithSitTarget() + { +/* sit position math as changed, this needs to be fixed later + TestHelpers.InMethod(); +// log4net.Config.XmlConfigurator.Configure(); + + // If a prim has a sit target then we can sit from any distance away + Vector3 startPos = new Vector3(128, 128, 30); + m_sp.AbsolutePosition = startPos; + + SceneObjectPart part = SceneHelpers.AddSceneObject(m_scene).RootPart; + part.SitTargetPosition = new Vector3(0, 0, 1); + + m_sp.HandleAgentRequestSit(m_sp.ControllingClient, m_sp.UUID, part.UUID, Vector3.Zero); + + Assert.That(part.SitTargetAvatar, Is.EqualTo(m_sp.UUID)); + Assert.That(m_sp.ParentID, Is.EqualTo(part.LocalId)); + + // This section is copied from ScenePresence.HandleAgentSit(). Correctness is not guaranteed. + double x, y, z, m1, m2; + + Quaternion r = part.SitTargetOrientation;; + m1 = r.X * r.X + r.Y * r.Y; + m2 = r.Z * r.Z + r.W * r.W; + + // Rotate the vector <0, 0, 1> + x = 2 * (r.X * r.Z + r.Y * r.W); + y = 2 * (-r.X * r.W + r.Y * r.Z); + z = m2 - m1; + + // Set m to be the square of the norm of r. + double m = m1 + m2; + + // This constant is emperically determined to be what is used in SL. + // See also http://opensimulator.org/mantis/view.php?id=7096 + double offset = 0.05; + + Vector3 up = new Vector3((float)x, (float)y, (float)z); + Vector3 sitOffset = up * (float)offset; + // End of copied section. + + Assert.That( + m_sp.AbsolutePosition, + Is.EqualTo(part.AbsolutePosition + part.SitTargetPosition - sitOffset + ScenePresence.SIT_TARGET_ADJUSTMENT)); + Assert.That(m_sp.PhysicsActor, Is.Null); + + Assert.That(part.GetSittingAvatarsCount(), Is.EqualTo(1)); + HashSet sittingAvatars = part.GetSittingAvatars(); + Assert.That(sittingAvatars.Count, Is.EqualTo(1)); + Assert.That(sittingAvatars.Contains(m_sp)); + + m_sp.StandUp(); + + Assert.That(part.SitTargetAvatar, Is.EqualTo(UUID.Zero)); + Assert.That(m_sp.ParentID, Is.EqualTo(0)); + Assert.That(m_sp.PhysicsActor, Is.Not.Null); + + Assert.That(part.SitTargetAvatar, Is.EqualTo(UUID.Zero)); + Assert.That(part.GetSittingAvatarsCount(), Is.EqualTo(0)); + Assert.That(part.GetSittingAvatars(), Is.Null); +*/ + } + + [Test] + public void TestSitAndStandOnGround() + { + TestHelpers.InMethod(); +// log4net.Config.XmlConfigurator.Configure(); + + // If a prim has a sit target then we can sit from any distance away +// Vector3 startPos = new Vector3(128, 128, 30); +// sp.AbsolutePosition = startPos; + + m_sp.HandleAgentSitOnGround(); + + Assert.That(m_sp.SitGround, Is.True); + Assert.That(m_sp.PhysicsActor, Is.Null); + + m_sp.StandUp(); + + Assert.That(m_sp.SitGround, Is.False); + Assert.That(m_sp.PhysicsActor, Is.Not.Null); + } + } +} diff --git a/Tests/OpenSim.Region.Framework.Tests/Scenes/Tests/ScenePresenceTeleportTests.cs b/Tests/OpenSim.Region.Framework.Tests/Scenes/Tests/ScenePresenceTeleportTests.cs new file mode 100644 index 00000000000..4236094ab7e --- /dev/null +++ b/Tests/OpenSim.Region.Framework.Tests/Scenes/Tests/ScenePresenceTeleportTests.cs @@ -0,0 +1,694 @@ +/* + * 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 System.IO; +using System.Net; +using System.Text; +using System.Threading; +using Nini.Config; +using NUnit.Framework; +using OpenMetaverse; +using OpenSim.Framework; +using OpenSim.Framework.Servers; +using OpenSim.Region.Framework.Interfaces; +using OpenSim.Region.CoreModules.Framework; +using OpenSim.Region.CoreModules.Framework.EntityTransfer; +using OpenSim.Region.CoreModules.ServiceConnectorsOut.Simulation; +using OpenSim.Region.CoreModules.World.Permissions; +using OpenSim.Tests.Common; + +namespace OpenSim.Region.Framework.Scenes.Tests +{ + /// + /// Teleport tests in a standalone OpenSim + /// + [TestFixture] + public class ScenePresenceTeleportTests : OpenSimTestCase + { + [OneTimeSetUp] + public void FixtureInit() + { + // Don't allow tests to be bamboozled by asynchronous events. Execute everything on the same thread. + Util.FireAndForgetMethod = FireAndForgetMethod.RegressionTest; + } + + [OneTimeTearDown] + 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] + public void TestSameRegion() + { + TestHelpers.InMethod(); +// log4net.Config.XmlConfigurator.Configure(); + + EntityTransferModule etm = new EntityTransferModule(); + + IConfigSource config = new IniConfigSource(); + config.AddConfig("Modules"); + // Not strictly necessary since FriendsModule assumes it is the default (!) + config.Configs["Modules"].Set("EntityTransferModule", etm.Name); + + TestScene scene = new SceneHelpers().SetupScene("sceneA", TestHelpers.ParseTail(0x100), 1000, 1000); + SceneHelpers.SetupSceneModules(scene, config, etm); + + Vector3 teleportPosition = new Vector3(10, 11, 12); + Vector3 teleportLookAt = new Vector3(20, 21, 22); + + ScenePresence sp = SceneHelpers.AddScenePresence(scene, TestHelpers.ParseTail(0x1)); + sp.AbsolutePosition = new Vector3(30, 31, 32); + scene.RequestTeleportLocation( + sp.ControllingClient, + scene.RegionInfo.RegionHandle, + teleportPosition, + teleportLookAt, + (uint)TeleportFlags.ViaLocation); + + Assert.That(sp.AbsolutePosition, Is.EqualTo(teleportPosition)); + + Assert.That(scene.GetRootAgentCount(), Is.EqualTo(1)); + Assert.That(scene.GetChildAgentCount(), Is.EqualTo(0)); + + // Lookat is sent to the client only - sp.Lookat does not yield the same thing (calculation from camera + // position instead). +// Assert.That(sp.Lookat, Is.EqualTo(teleportLookAt)); + } + +/* + [Test] + public void TestSameSimulatorIsolatedRegionsV1() + { + TestHelpers.InMethod(); +// TestHelpers.EnableLogging(); + + UUID userId = TestHelpers.ParseTail(0x1); + + EntityTransferModule etmA = new EntityTransferModule(); + EntityTransferModule etmB = new EntityTransferModule(); + LocalSimulationConnectorModule lscm = new LocalSimulationConnectorModule(); + + IConfigSource config = new IniConfigSource(); + IConfig modulesConfig = config.AddConfig("Modules"); + modulesConfig.Set("EntityTransferModule", etmA.Name); + modulesConfig.Set("SimulationServices", lscm.Name); + IConfig entityTransferConfig = config.AddConfig("EntityTransfer"); + + // In order to run a single threaded regression test we do not want the entity transfer module waiting + // for a callback from the destination scene before removing its avatar data. + entityTransferConfig.Set("wait_for_callback", false); + + SceneHelpers sh = new SceneHelpers(); + TestScene sceneA = sh.SetupScene("sceneA", TestHelpers.ParseTail(0x100), 1000, 1000); + TestScene sceneB = sh.SetupScene("sceneB", TestHelpers.ParseTail(0x200), 1002, 1000); + + SceneHelpers.SetupSceneModules(sceneA, config, etmA); + SceneHelpers.SetupSceneModules(sceneB, config, etmB); + SceneHelpers.SetupSceneModules(new Scene[] { sceneA, sceneB }, config, lscm); + + // FIXME: Hack - this is here temporarily to revert back to older entity transfer behaviour + lscm.ServiceVersion = 0.1f; + + Vector3 teleportPosition = new Vector3(10, 11, 12); + Vector3 teleportLookAt = new Vector3(20, 21, 22); + + ScenePresence sp = SceneHelpers.AddScenePresence(sceneA, userId); + sp.AbsolutePosition = new Vector3(30, 31, 32); + + List destinationTestClients = new List(); + EntityTransferHelpers.SetupInformClientOfNeighbourTriggersNeighbourClientCreate( + (TestClient)sp.ControllingClient, destinationTestClients); + + sceneA.RequestTeleportLocation( + sp.ControllingClient, + sceneB.RegionInfo.RegionHandle, + teleportPosition, + teleportLookAt, + (uint)TeleportFlags.ViaLocation); + + // SetupInformClientOfNeighbour() will have handled the callback into the target scene to setup the child + // agent. This call will now complete the movement of the user into the destination and upgrade the agent + // from child to root. + destinationTestClients[0].CompleteMovement(); + + Assert.That(sceneA.GetScenePresence(userId), Is.Null); + + ScenePresence sceneBSp = sceneB.GetScenePresence(userId); + Assert.That(sceneBSp, Is.Not.Null); + Assert.That(sceneBSp.Scene.RegionInfo.RegionName, Is.EqualTo(sceneB.RegionInfo.RegionName)); + Assert.That(sceneBSp.AbsolutePosition, Is.EqualTo(teleportPosition)); + + Assert.That(sceneA.GetRootAgentCount(), Is.EqualTo(0)); + Assert.That(sceneA.GetChildAgentCount(), Is.EqualTo(0)); + Assert.That(sceneB.GetRootAgentCount(), Is.EqualTo(1)); + Assert.That(sceneB.GetChildAgentCount(), Is.EqualTo(0)); + + // TODO: Add assertions to check correct circuit details in both scenes. + + // Lookat is sent to the client only - sp.Lookat does not yield the same thing (calculation from camera + // position instead). +// Assert.That(sp.Lookat, Is.EqualTo(teleportLookAt)); + } +*/ + + [Test] + public void TestSameSimulatorIsolatedRegionsV2() + { + TestHelpers.InMethod(); +// TestHelpers.EnableLogging(); + + UUID userId = TestHelpers.ParseTail(0x1); + + EntityTransferModule etmA = new EntityTransferModule(); + EntityTransferModule etmB = new EntityTransferModule(); + LocalSimulationConnectorModule lscm = new LocalSimulationConnectorModule(); + + IConfigSource config = new IniConfigSource(); + IConfig modulesConfig = config.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); + TestScene sceneB = sh.SetupScene("sceneB", TestHelpers.ParseTail(0x200), 1002, 1000); + + SceneHelpers.SetupSceneModules(sceneA, config, etmA); + SceneHelpers.SetupSceneModules(sceneB, config, etmB); + SceneHelpers.SetupSceneModules(new Scene[] { sceneA, sceneB }, config, lscm); + + Vector3 teleportPosition = new Vector3(10, 11, 12); + Vector3 teleportLookAt = new Vector3(20, 21, 22); + + ScenePresence sp = SceneHelpers.AddScenePresence(sceneA, userId); + sp.AbsolutePosition = new Vector3(30, 31, 32); + + sceneA.Update(4); + sceneB.Update(4); + + List destinationTestClients = new List(); + EntityTransferHelpers.SetupSendRegionTeleportTriggersDestinationClientCreateAndCompleteMovement( + (TestClient)sp.ControllingClient, destinationTestClients); + + sceneA.RequestTeleportLocation( + sp.ControllingClient, + sceneB.RegionInfo.RegionHandle, + teleportPosition, + teleportLookAt, + (uint)TeleportFlags.ViaLocation); + + // Assert.That(sceneA.GetScenePresence(userId), Is.Null); + sceneA.Update(4); + sceneB.Update(4); + + ScenePresence sceneBSp = sceneB.GetScenePresence(userId); + Assert.That(sceneBSp, Is.Not.Null); + Assert.That(sceneBSp.Scene.RegionInfo.RegionName, Is.EqualTo(sceneB.RegionInfo.RegionName)); + Assert.That(sceneBSp.AbsolutePosition.X, Is.EqualTo(teleportPosition.X)); + Assert.That(sceneBSp.AbsolutePosition.Y, Is.EqualTo(teleportPosition.Y)); + + //Assert.That(sceneA.GetRootAgentCount(), Is.EqualTo(0)); + //Assert.That(sceneA.GetChildAgentCount(), Is.EqualTo(0)); + //Assert.That(sceneB.GetRootAgentCount(), Is.EqualTo(1)); + //Assert.That(sceneB.GetChildAgentCount(), Is.EqualTo(0)); + + // TODO: Add assertions to check correct circuit details in both scenes. + + // Lookat is sent to the client only - sp.Lookat does not yield the same thing (calculation from camera + // position instead). + // Assert.That(sp.Lookat, Is.EqualTo(teleportLookAt)); + } + + /// + /// Test teleport procedures when the target simulator returns false when queried about access. + /// + [Test] + public void TestSameSimulatorIsolatedRegions_DeniedOnQueryAccess() + { + TestHelpers.InMethod(); +// TestHelpers.EnableLogging(); + + UUID userId = TestHelpers.ParseTail(0x1); + Vector3 preTeleportPosition = new Vector3(30, 31, 32); + + EntityTransferModule etmA = new EntityTransferModule(); + EntityTransferModule etmB = new EntityTransferModule(); + + LocalSimulationConnectorModule lscm = new LocalSimulationConnectorModule(); + + IConfigSource config = new IniConfigSource(); + config.AddConfig("Modules"); + config.Configs["Modules"].Set("EntityTransferModule", etmA.Name); + config.Configs["Modules"].Set("SimulationServices", lscm.Name); + + config.AddConfig("EntityTransfer"); + + // In order to run a single threaded regression test we do not want the entity transfer module waiting + // for a callback from the destination scene before removing its avatar data. + config.Configs["EntityTransfer"].Set("wait_for_callback", false); + + config.AddConfig("Startup"); + config.Configs["Startup"].Set("serverside_object_permissions", true); + + SceneHelpers sh = new SceneHelpers(); + TestScene sceneA = sh.SetupScene("sceneA", TestHelpers.ParseTail(0x100), 1000, 1000); + TestScene sceneB = sh.SetupScene("sceneB", TestHelpers.ParseTail(0x200), 1002, 1000); + + SceneHelpers.SetupSceneModules(sceneA, config, etmA ); + + // We need to set up the permisions module on scene B so that our later use of agent limit to deny + // QueryAccess won't succeed anyway because administrators are always allowed in and the default + // IsAdministrator if no permissions module is present is true. + SceneHelpers.SetupSceneModules(sceneB, config, new object[] { new DefaultPermissionsModule(), etmB }); + + // Shared scene modules + SceneHelpers.SetupSceneModules(new Scene[] { sceneA, sceneB }, config, lscm); + + Vector3 teleportPosition = new Vector3(10, 11, 12); + Vector3 teleportLookAt = new Vector3(20, 21, 22); + + ScenePresence sp = SceneHelpers.AddScenePresence(sceneA, userId); + sp.AbsolutePosition = preTeleportPosition; + + // Make sceneB return false on query access + sceneB.RegionInfo.RegionSettings.AgentLimit = 0; + + sceneA.RequestTeleportLocation( + sp.ControllingClient, + sceneB.RegionInfo.RegionHandle, + teleportPosition, + teleportLookAt, + (uint)TeleportFlags.ViaLocation); + +// ((TestClient)sp.ControllingClient).CompleteTeleportClientSide(); + + Assert.That(sceneB.GetScenePresence(userId), Is.Null); + + ScenePresence sceneASp = sceneA.GetScenePresence(userId); + Assert.That(sceneASp, Is.Not.Null); + Assert.That(sceneASp.Scene.RegionInfo.RegionName, Is.EqualTo(sceneA.RegionInfo.RegionName)); + Assert.That(sceneASp.AbsolutePosition.X, Is.EqualTo(preTeleportPosition.X)); + Assert.That(sceneASp.AbsolutePosition.Y, Is.EqualTo(preTeleportPosition.Y)); + + Assert.That(sceneA.GetRootAgentCount(), Is.EqualTo(1)); + Assert.That(sceneA.GetChildAgentCount(), Is.EqualTo(0)); + Assert.That(sceneB.GetRootAgentCount(), Is.EqualTo(0)); + Assert.That(sceneB.GetChildAgentCount(), Is.EqualTo(0)); + + // TODO: Add assertions to check correct circuit details in both scenes. + + // Lookat is sent to the client only - sp.Lookat does not yield the same thing (calculation from camera + // position instead). +// Assert.That(sp.Lookat, Is.EqualTo(teleportLookAt)); + +// TestHelpers.DisableLogging(); + } + + /// + /// Test teleport procedures when the target simulator create agent step is refused. + /// + [Test] + public void TestSameSimulatorIsolatedRegions_DeniedOnCreateAgent() + { + TestHelpers.InMethod(); +// TestHelpers.EnableLogging(); + + UUID userId = TestHelpers.ParseTail(0x1); + Vector3 preTeleportPosition = new Vector3(30, 31, 32); + + EntityTransferModule etmA = new EntityTransferModule(); + EntityTransferModule etmB = new EntityTransferModule(); + LocalSimulationConnectorModule lscm = new LocalSimulationConnectorModule(); + + IConfigSource config = new IniConfigSource(); + config.AddConfig("Modules"); + config.Configs["Modules"].Set("EntityTransferModule", etmA.Name); + config.Configs["Modules"].Set("SimulationServices", lscm.Name); + + config.AddConfig("EntityTransfer"); + + // In order to run a single threaded regression test we do not want the entity transfer module waiting + // for a callback from the destination scene before removing its avatar data. + config.Configs["EntityTransfer"].Set("wait_for_callback", false); + + SceneHelpers sh = new SceneHelpers(); + TestScene sceneA = sh.SetupScene("sceneA", TestHelpers.ParseTail(0x100), 1000, 1000); + TestScene sceneB = sh.SetupScene("sceneB", TestHelpers.ParseTail(0x200), 1002, 1000); + + SceneHelpers.SetupSceneModules(sceneA, config, etmA); + SceneHelpers.SetupSceneModules(sceneB, config, etmB); + + // Shared scene modules + SceneHelpers.SetupSceneModules(new Scene[] { sceneA, sceneB }, config, lscm); + + Vector3 teleportPosition = new Vector3(10, 11, 12); + Vector3 teleportLookAt = new Vector3(20, 21, 22); + + ScenePresence sp = SceneHelpers.AddScenePresence(sceneA, userId); + sp.AbsolutePosition = preTeleportPosition; + + sceneA.Update(4); + sceneB.Update(4); + + // Make sceneB refuse CreateAgent + sceneB.LoginsEnabled = false; + + sceneA.RequestTeleportLocation( + sp.ControllingClient, + sceneB.RegionInfo.RegionHandle, + teleportPosition, + teleportLookAt, + (uint)TeleportFlags.ViaLocation); + + // ((TestClient)sp.ControllingClient).CompleteTeleportClientSide(); + + sceneA.Update(4); + sceneB.Update(4); + + Assert.That(sceneB.GetScenePresence(userId), Is.Null); + + ScenePresence sceneASp = sceneA.GetScenePresence(userId); + Assert.That(sceneASp, Is.Not.Null); + Assert.That(sceneASp.Scene.RegionInfo.RegionName, Is.EqualTo(sceneA.RegionInfo.RegionName)); + Assert.That(sceneASp.AbsolutePosition.X, Is.EqualTo(preTeleportPosition.X)); + Assert.That(sceneASp.AbsolutePosition.Y, Is.EqualTo(preTeleportPosition.Y)); + + Assert.That(sceneA.GetRootAgentCount(), Is.EqualTo(1)); + Assert.That(sceneA.GetChildAgentCount(), Is.EqualTo(0)); + Assert.That(sceneB.GetRootAgentCount(), Is.EqualTo(0)); + Assert.That(sceneB.GetChildAgentCount(), Is.EqualTo(0)); + + // TODO: Add assertions to check correct circuit details in both scenes. + + // Lookat is sent to the client only - sp.Lookat does not yield the same thing (calculation from camera + // position instead). +// Assert.That(sp.Lookat, Is.EqualTo(teleportLookAt)); + +// TestHelpers.DisableLogging(); + } + + /// + /// Test teleport when the destination region does not process (or does not receive) the connection attempt + /// from the viewer. + /// + /// + /// This could be quite a common case where the source region can connect to a remove destination region + /// (for CreateAgent) but the viewer cannot reach the destination region due to network issues. + /// + [Test] + public void TestSameSimulatorIsolatedRegions_DestinationDidNotProcessViewerConnection() + { + TestHelpers.InMethod(); +// TestHelpers.EnableLogging(); + + UUID userId = TestHelpers.ParseTail(0x1); + Vector3 preTeleportPosition = new Vector3(30, 31, 32); + + EntityTransferModule etmA = new EntityTransferModule(); + EntityTransferModule etmB = new EntityTransferModule(); + + LocalSimulationConnectorModule lscm = new LocalSimulationConnectorModule(); + + IConfigSource config = new IniConfigSource(); + config.AddConfig("Modules"); + config.Configs["Modules"].Set("EntityTransferModule", etmA.Name); + config.Configs["Modules"].Set("SimulationServices", lscm.Name); + + config.AddConfig("EntityTransfer"); + + // In order to run a single threaded regression test we do not want the entity transfer module waiting + // for a callback from the destination scene before removing its avatar data. + config.Configs["EntityTransfer"].Set("wait_for_callback", false); + +// config.AddConfig("Startup"); +// config.Configs["Startup"].Set("serverside_object_permissions", true); + + SceneHelpers sh = new SceneHelpers(); + TestScene sceneA = sh.SetupScene("sceneA", TestHelpers.ParseTail(0x100), 1000, 1000); + TestScene sceneB = sh.SetupScene("sceneB", TestHelpers.ParseTail(0x200), 1002, 1000); + + SceneHelpers.SetupSceneModules(sceneA, config, etmA ); + + // We need to set up the permisions module on scene B so that our later use of agent limit to deny + // QueryAccess won't succeed anyway because administrators are always allowed in and the default + // IsAdministrator if no permissions module is present is true. + SceneHelpers.SetupSceneModules(sceneB, config, new object[] { new DefaultPermissionsModule(), etmB }); + + // Shared scene modules + SceneHelpers.SetupSceneModules(new Scene[] { sceneA, sceneB }, config, lscm); + + Vector3 teleportPosition = new Vector3(10, 11, 12); + Vector3 teleportLookAt = new Vector3(20, 21, 22); + + ScenePresence sp = SceneHelpers.AddScenePresence(sceneA, userId); + sp.AbsolutePosition = preTeleportPosition; + + sceneA.Update(4); + sceneB.Update(4); + + sceneA.RequestTeleportLocation( + sp.ControllingClient, + sceneB.RegionInfo.RegionHandle, + teleportPosition, + teleportLookAt, + (uint)TeleportFlags.ViaLocation); + + // FIXME: Not setting up InformClientOfNeighbour on the TestClient means that it does not initiate + // communication with the destination region. But this is a very non-obvious way of doing it - really we + // should be forced to expicitly set this up. + sceneA.Update(4); + sceneB.Update(4); + + Assert.That(sceneB.GetScenePresence(userId), Is.Null); + + ScenePresence sceneASp = sceneA.GetScenePresence(userId); + Assert.That(sceneASp, Is.Not.Null); + Assert.That(sceneASp.Scene.RegionInfo.RegionName, Is.EqualTo(sceneA.RegionInfo.RegionName)); + Assert.That(sceneASp.AbsolutePosition.X, Is.EqualTo(preTeleportPosition.X)); + Assert.That(sceneASp.AbsolutePosition.Y, Is.EqualTo(preTeleportPosition.Y)); + + sceneA.SceneGraph.RecalculateStats(); + sceneB.SceneGraph.RecalculateStats(); + Assert.That(sceneA.GetRootAgentCount(), Is.EqualTo(1)); + Assert.That(sceneA.GetChildAgentCount(), Is.EqualTo(0)); + Assert.That(sceneB.GetRootAgentCount(), Is.EqualTo(0)); + Assert.That(sceneB.GetChildAgentCount(), Is.EqualTo(0)); + + // TODO: Add assertions to check correct circuit details in both scenes. + + // Lookat is sent to the client only - sp.Lookat does not yield the same thing (calculation from camera + // position instead). +// Assert.That(sp.Lookat, Is.EqualTo(teleportLookAt)); + +// TestHelpers.DisableLogging(); + } + +/* + [Test] + public void TestSameSimulatorNeighbouringRegionsV1() + { + TestHelpers.InMethod(); +// TestHelpers.EnableLogging(); + + UUID userId = TestHelpers.ParseTail(0x1); + + EntityTransferModule etmA = new EntityTransferModule(); + EntityTransferModule etmB = new EntityTransferModule(); + LocalSimulationConnectorModule lscm = new LocalSimulationConnectorModule(); + + IConfigSource config = new IniConfigSource(); + IConfig modulesConfig = config.AddConfig("Modules"); + modulesConfig.Set("EntityTransferModule", etmA.Name); + modulesConfig.Set("SimulationServices", lscm.Name); + IConfig entityTransferConfig = config.AddConfig("EntityTransfer"); + + // In order to run a single threaded regression test we do not want the entity transfer module waiting + // for a callback from the destination scene before removing its avatar data. + entityTransferConfig.Set("wait_for_callback", false); + + SceneHelpers sh = new SceneHelpers(); + TestScene sceneA = sh.SetupScene("sceneA", TestHelpers.ParseTail(0x100), 1000, 1000); + TestScene sceneB = sh.SetupScene("sceneB", TestHelpers.ParseTail(0x200), 1001, 1000); + + SceneHelpers.SetupSceneModules(new Scene[] { sceneA, sceneB }, config, lscm); + SceneHelpers.SetupSceneModules(sceneA, config, new CapabilitiesModule(), etmA); + SceneHelpers.SetupSceneModules(sceneB, config, new CapabilitiesModule(), etmB); + + // FIXME: Hack - this is here temporarily to revert back to older entity transfer behaviour + lscm.ServiceVersion = 0.1f; + + Vector3 teleportPosition = new Vector3(10, 11, 12); + Vector3 teleportLookAt = new Vector3(20, 21, 22); + + AgentCircuitData acd = SceneHelpers.GenerateAgentData(userId); + TestClient tc = new TestClient(acd, sceneA); + List destinationTestClients = new List(); + EntityTransferHelpers.SetupInformClientOfNeighbourTriggersNeighbourClientCreate(tc, destinationTestClients); + + ScenePresence beforeSceneASp = SceneHelpers.AddScenePresence(sceneA, tc, acd); + beforeSceneASp.AbsolutePosition = new Vector3(30, 31, 32); + + Assert.That(beforeSceneASp, Is.Not.Null); + Assert.That(beforeSceneASp.IsChildAgent, Is.False); + + ScenePresence beforeSceneBSp = sceneB.GetScenePresence(userId); + Assert.That(beforeSceneBSp, Is.Not.Null); + Assert.That(beforeSceneBSp.IsChildAgent, Is.True); + + // In this case, we will not receieve a second InformClientOfNeighbour since the viewer already knows + // about the neighbour region it is teleporting to. + sceneA.RequestTeleportLocation( + beforeSceneASp.ControllingClient, + sceneB.RegionInfo.RegionHandle, + teleportPosition, + teleportLookAt, + (uint)TeleportFlags.ViaLocation); + + destinationTestClients[0].CompleteMovement(); + + ScenePresence afterSceneASp = sceneA.GetScenePresence(userId); + Assert.That(afterSceneASp, Is.Not.Null); + Assert.That(afterSceneASp.IsChildAgent, Is.True); + + ScenePresence afterSceneBSp = sceneB.GetScenePresence(userId); + Assert.That(afterSceneBSp, Is.Not.Null); + Assert.That(afterSceneBSp.IsChildAgent, Is.False); + Assert.That(afterSceneBSp.Scene.RegionInfo.RegionName, Is.EqualTo(sceneB.RegionInfo.RegionName)); + Assert.That(afterSceneBSp.AbsolutePosition, Is.EqualTo(teleportPosition)); + + Assert.That(sceneA.GetRootAgentCount(), Is.EqualTo(0)); + Assert.That(sceneA.GetChildAgentCount(), Is.EqualTo(1)); + Assert.That(sceneB.GetRootAgentCount(), Is.EqualTo(1)); + Assert.That(sceneB.GetChildAgentCount(), Is.EqualTo(0)); + + // TODO: Add assertions to check correct circuit details in both scenes. + + // Lookat is sent to the client only - sp.Lookat does not yield the same thing (calculation from camera + // position instead). +// Assert.That(sp.Lookat, Is.EqualTo(teleportLookAt)); + +// TestHelpers.DisableLogging(); + } +*/ + + [Test] + public void TestSameSimulatorNeighbouringRegionsV2() + { + TestHelpers.InMethod(); +// TestHelpers.EnableLogging(); + + UUID userId = TestHelpers.ParseTail(0x1); + + EntityTransferModule etmA = new EntityTransferModule(); + EntityTransferModule etmB = new EntityTransferModule(); + LocalSimulationConnectorModule lscm = new LocalSimulationConnectorModule(); + + IConfigSource config = new IniConfigSource(); + IConfig modulesConfig = config.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); + TestScene sceneB = sh.SetupScene("sceneB", TestHelpers.ParseTail(0x200), 1001, 1000); + + SceneHelpers.SetupSceneModules(new Scene[] { sceneA, sceneB }, config, lscm); + SceneHelpers.SetupSceneModules(sceneA, config, new CapabilitiesModule(), etmA); + SceneHelpers.SetupSceneModules(sceneB, config, new CapabilitiesModule(), etmB); + + Vector3 teleportPosition = new Vector3(10, 11, 12); + Vector3 teleportLookAt = new Vector3(20, 21, 22); + + AgentCircuitData acd = SceneHelpers.GenerateAgentData(userId); + TestClient tc = new TestClient(acd, sceneA); + List destinationTestClients = new List(); + EntityTransferHelpers.SetupInformClientOfNeighbourTriggersNeighbourClientCreate(tc, destinationTestClients); + + ScenePresence beforeSceneASp = SceneHelpers.AddScenePresence(sceneA, tc, acd); + beforeSceneASp.AbsolutePosition = new Vector3(30, 31, 32); + + sceneA.Update(4); + sceneB.Update(4); + + Assert.That(beforeSceneASp, Is.Not.Null); + Assert.That(beforeSceneASp.IsChildAgent, Is.False); + + ScenePresence beforeSceneBSp = sceneB.GetScenePresence(userId); + Assert.That(beforeSceneBSp, Is.Not.Null); + Assert.That(beforeSceneBSp.IsChildAgent, Is.True); + + // Here, we need to make clientA's receipt of SendRegionTeleport trigger clientB's CompleteMovement(). This + // is to operate the teleport V2 mechanism where the EntityTransferModule will first request the client to + // CompleteMovement to the region and then call UpdateAgent to the destination region to confirm the receipt + // Both these operations will occur on different threads and will wait for each other. + // We have to do this via ThreadPool directly since FireAndForget has been switched to sync for the V1 + // test protocol, where we are trying to avoid unpredictable async operations in regression tests. + tc.OnTestClientSendRegionTeleport + += (regionHandle, simAccess, regionExternalEndPoint, locationID, flags, capsURL) + => ThreadPool.UnsafeQueueUserWorkItem(o => destinationTestClients[0].CompleteMovement(), null); + + sceneA.RequestTeleportLocation( + beforeSceneASp.ControllingClient, + sceneB.RegionInfo.RegionHandle, + teleportPosition, + teleportLookAt, + (uint)TeleportFlags.ViaLocation); + + sceneA.Update(4); + sceneB.Update(4); + + ScenePresence afterSceneASp = sceneA.GetScenePresence(userId); + Assert.That(afterSceneASp, Is.Not.Null); + Assert.That(afterSceneASp.IsChildAgent, Is.True); + + ScenePresence afterSceneBSp = sceneB.GetScenePresence(userId); + Assert.That(afterSceneBSp, Is.Not.Null); + Assert.That(afterSceneBSp.IsChildAgent, Is.False); + Assert.That(afterSceneBSp.Scene.RegionInfo.RegionName, Is.EqualTo(sceneB.RegionInfo.RegionName)); + Assert.That(afterSceneBSp.AbsolutePosition.X, Is.EqualTo(teleportPosition.X)); + Assert.That(afterSceneBSp.AbsolutePosition.Y, Is.EqualTo(teleportPosition.Y)); + + Assert.That(sceneA.GetRootAgentCount(), Is.EqualTo(0)); + Assert.That(sceneA.GetChildAgentCount(), Is.EqualTo(1)); + Assert.That(sceneB.GetRootAgentCount(), Is.EqualTo(1)); + Assert.That(sceneB.GetChildAgentCount(), Is.EqualTo(0)); + + // TODO: Add assertions to check correct circuit details in both scenes. + + // Lookat is sent to the client only - sp.Lookat does not yield the same thing (calculation from camera + // position instead). +// Assert.That(sp.Lookat, Is.EqualTo(teleportLookAt)); + +// TestHelpers.DisableLogging(); + } + } +} diff --git a/Tests/OpenSim.Region.Framework.Tests/Scenes/Tests/SceneStatisticsTests.cs b/Tests/OpenSim.Region.Framework.Tests/Scenes/Tests/SceneStatisticsTests.cs new file mode 100644 index 00000000000..4ce6a95f363 --- /dev/null +++ b/Tests/OpenSim.Region.Framework.Tests/Scenes/Tests/SceneStatisticsTests.cs @@ -0,0 +1,69 @@ +/* + * 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 System.Reflection; +using NUnit.Framework; +using OpenMetaverse; +using OpenSim.Framework; +using OpenSim.Region.Framework.Scenes; +using OpenSim.Tests.Common; + +namespace OpenSim.Region.Framework.Scenes.Tests +{ + [TestFixture] + public class SceneStatisticsTests : OpenSimTestCase + { + private TestScene m_scene; + + [SetUp] + public void Init() + { + m_scene = new SceneHelpers().SetupScene(); + } + + [Test] + public void TestAddRemovePhysicalLinkset() + { + Assert.That(m_scene.SceneGraph.GetActiveObjectsCount(), Is.EqualTo(0)); + + UUID ownerId = TestHelpers.ParseTail(0x1); + SceneObjectGroup so1 = SceneHelpers.CreateSceneObject(3, ownerId, "so1", 0x10); + m_scene.AddSceneObject(so1); + so1.ScriptSetPhysicsStatus(true); + + Assert.That(m_scene.SceneGraph.GetTotalObjectsCount(), Is.EqualTo(3)); + Assert.That(m_scene.SceneGraph.GetActiveObjectsCount(), Is.EqualTo(3)); + + m_scene.DeleteSceneObject(so1, false); + + Assert.That(m_scene.SceneGraph.GetTotalObjectsCount(), Is.EqualTo(0)); + Assert.That(m_scene.SceneGraph.GetActiveObjectsCount(), Is.EqualTo(0)); + } + } +} \ No newline at end of file diff --git a/Tests/OpenSim.Region.Framework.Tests/Scenes/Tests/SceneTelehubTests.cs b/Tests/OpenSim.Region.Framework.Tests/Scenes/Tests/SceneTelehubTests.cs new file mode 100644 index 00000000000..dbb6a37e610 --- /dev/null +++ b/Tests/OpenSim.Region.Framework.Tests/Scenes/Tests/SceneTelehubTests.cs @@ -0,0 +1,118 @@ +/* + * 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 Nini.Config; +using NUnit.Framework; +using OpenMetaverse; +using OpenSim.Framework; +using OpenSim.Region.CoreModules.World.Estate; +using OpenSim.Region.Framework.Scenes; +using OpenSim.Region.Framework.Interfaces; +using OpenSim.Services.Interfaces; +using OpenSim.Tests.Common; + +namespace OpenSim.Region.Framework.Scenes.Tests +{ + /// + /// Scene telehub tests + /// + /// + /// TODO: Tests which run through normal functionality. Currently, the only test is one that checks behaviour + /// in the case of an error condition + /// + [TestFixture] + public class SceneTelehubTests : OpenSimTestCase + { + /// + /// Test for desired behaviour when a telehub has no spawn points + /// + [Test] + public void TestNoTelehubSpawnPoints() + { + TestHelpers.InMethod(); +// TestHelpers.EnableLogging(); + + EstateManagementModule emm = new EstateManagementModule(); + + SceneHelpers sh = new SceneHelpers(); + Scene scene = sh.SetupScene(); + SceneHelpers.SetupSceneModules(scene, emm); + + UUID telehubSceneObjectOwner = TestHelpers.ParseTail(0x1); + + SceneObjectGroup telehubSo = SceneHelpers.AddSceneObject(scene, "telehubObject", telehubSceneObjectOwner); + + emm.HandleOnEstateManageTelehub(null, UUID.Zero, UUID.Zero, "connect", telehubSo.LocalId); + scene.RegionInfo.EstateSettings.AllowDirectTeleport = false; + + // Must still be possible to successfully log in + UUID loggingInUserId = TestHelpers.ParseTail(0x2); + + UserAccount ua + = UserAccountHelpers.CreateUserWithInventory(scene, "Test", "User", loggingInUserId, "password"); + + SceneHelpers.AddScenePresence(scene, ua); + + Assert.That(scene.GetScenePresence(loggingInUserId), Is.Not.Null); + } + + /// + /// Test for desired behaviour when the scene object nominated as a telehub object does not exist. + /// + [Test] + public void TestNoTelehubSceneObject() + { + TestHelpers.InMethod(); +// TestHelpers.EnableLogging(); + + EstateManagementModule emm = new EstateManagementModule(); + + SceneHelpers sh = new SceneHelpers(); + Scene scene = sh.SetupScene(); + SceneHelpers.SetupSceneModules(scene, emm); + + UUID telehubSceneObjectOwner = TestHelpers.ParseTail(0x1); + + SceneObjectGroup telehubSo = SceneHelpers.AddSceneObject(scene, "telehubObject", telehubSceneObjectOwner); + SceneObjectGroup spawnPointSo = SceneHelpers.AddSceneObject(scene, "spawnpointObject", telehubSceneObjectOwner); + + emm.HandleOnEstateManageTelehub(null, UUID.Zero, UUID.Zero, "connect", telehubSo.LocalId); + emm.HandleOnEstateManageTelehub(null, UUID.Zero, UUID.Zero, "spawnpoint add", spawnPointSo.LocalId); + scene.RegionInfo.EstateSettings.AllowDirectTeleport = false; + + scene.DeleteSceneObject(telehubSo, false); + + // Must still be possible to successfully log in + UUID loggingInUserId = TestHelpers.ParseTail(0x2); + + UserAccount ua + = UserAccountHelpers.CreateUserWithInventory(scene, "Test", "User", loggingInUserId, "password"); + + SceneHelpers.AddScenePresence(scene, ua); + + Assert.That(scene.GetScenePresence(loggingInUserId), Is.Not.Null); + } + } +} \ No newline at end of file diff --git a/Tests/OpenSim.Region.Framework.Tests/Scenes/Tests/SceneTests.cs b/Tests/OpenSim.Region.Framework.Tests/Scenes/Tests/SceneTests.cs new file mode 100644 index 00000000000..6c0af8f1a00 --- /dev/null +++ b/Tests/OpenSim.Region.Framework.Tests/Scenes/Tests/SceneTests.cs @@ -0,0 +1,107 @@ +/* + * 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 System.Reflection; +using System.Text; +using System.Threading; +using System.Timers; +using Timer=System.Timers.Timer; +using Nini.Config; +using NUnit.Framework; +using OpenMetaverse; +using OpenSim.Framework; +using OpenSim.Region.Framework.Scenes; +using OpenSim.Region.Framework.Interfaces; +using OpenSim.Region.CoreModules.World.Serialiser; +using OpenSim.Region.CoreModules.ServiceConnectorsOut.Simulation; +using OpenSim.Tests.Common; + +namespace OpenSim.Region.Framework.Scenes.Tests +{ + /// + /// Scene presence tests + /// + [TestFixture] + public class SceneTests : OpenSimTestCase + { + [Test] + public void TestCreateScene() + { + TestHelpers.InMethod(); + + new SceneHelpers().SetupScene(); + } + + [Test] + public void TestCreateVarScene() + { + TestHelpers.InMethod(); + UUID regionUuid = TestHelpers.ParseTail(0x1); + uint sizeX = 512; + uint sizeY = 512; + + Scene scene + = new SceneHelpers().SetupScene("scene", regionUuid, 1000, 1000, sizeX, sizeY, new IniConfigSource()); + + Assert.AreEqual(sizeX, scene.RegionInfo.RegionSizeX); + Assert.AreEqual(sizeY, scene.RegionInfo.RegionSizeY); + } + + /// + /// Very basic scene update test. Should become more elaborate with time. + /// + [Test] + public void TestUpdateScene() + { + TestHelpers.InMethod(); + + Scene scene = new SceneHelpers().SetupScene(); + scene.Update(1); + + Assert.That(scene.Frame, Is.EqualTo(1)); + } + + [Test] + public void TestShutdownScene() + { + TestHelpers.InMethod(); + + Scene scene = new SceneHelpers().SetupScene(); + scene.Close(); + + Assert.That(scene.ShuttingDown, Is.True); + Assert.That(scene.Active, Is.False); + + // Trying to update a shutdown scene should result in no update + scene.Update(1); + + Assert.That(scene.Frame, Is.EqualTo(0)); + } + } +} \ No newline at end of file diff --git a/Tests/OpenSim.Region.Framework.Tests/Scenes/Tests/SharedRegionModuleTests.cs b/Tests/OpenSim.Region.Framework.Tests/Scenes/Tests/SharedRegionModuleTests.cs new file mode 100644 index 00000000000..80c11f92db4 --- /dev/null +++ b/Tests/OpenSim.Region.Framework.Tests/Scenes/Tests/SharedRegionModuleTests.cs @@ -0,0 +1,249 @@ +/* + * 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 System.Net; +using Mono.Addins; +using Nini.Config; +using NUnit.Framework; +using OpenMetaverse; +using OpenSim; +using OpenSim.ApplicationPlugins.RegionModulesController; +using OpenSim.Framework; +using OpenSim.Region.CoreModules.ServiceConnectorsOut.Grid; +using OpenSim.Region.Framework.Interfaces; +using OpenSim.Tests.Common; + +namespace OpenSim.Region.Framework.Scenes.Tests +{ + public class SharedRegionModuleTests : OpenSimTestCase + { +// [Test] + public void TestLifecycle() + { + TestHelpers.InMethod(); + TestHelpers.EnableLogging(); + + UUID estateOwnerId = TestHelpers.ParseTail(0x1); + UUID regionId = TestHelpers.ParseTail(0x10); + + IConfigSource configSource = new IniConfigSource(); + configSource.AddConfig("Startup"); + configSource.AddConfig("Modules"); + +// // We use this to skip estate questions + // Turns out not to be needed is estate owner id is pre-set in region information. +// IConfig estateConfig = configSource.AddConfig(OpenSimBase.ESTATE_SECTION_NAME); +// estateConfig.Set("DefaultEstateOwnerName", "Zaphod Beeblebrox"); +// estateConfig.Set("DefaultEstateOwnerUUID", estateOwnerId); +// estateConfig.Set("DefaultEstateOwnerEMail", "zaphod@galaxy.com"); +// estateConfig.Set("DefaultEstateOwnerPassword", "two heads"); + + // For grid servic + configSource.AddConfig("GridService"); + configSource.Configs["Modules"].Set("GridServices", "RegionGridServicesConnector"); + configSource.Configs["GridService"].Set("StorageProvider", "OpenSim.Data.Null.dll:NullRegionData"); + configSource.Configs["GridService"].Set("LocalServiceModule", "OpenSim.Services.GridService.dll:GridService"); + configSource.Configs["GridService"].Set("ConnectionString", "!static"); + + RegionGridServicesConnector gridService = new RegionGridServicesConnector(); +// + OpenSim sim = new OpenSim(configSource); + + sim.SuppressExit = true; + sim.EnableInitialPluginLoad = false; + sim.LoadEstateDataService = false; + sim.NetServersInfo.HttpListenerPort = 0; + + IRegistryCore reg = sim.ApplicationRegistry; + + RegionInfo ri = new RegionInfo(); + ri.RegionID = regionId; + ri.EstateSettings.EstateOwner = estateOwnerId; + ri.InternalEndPoint = new IPEndPoint(0, 0); + + MockRegionModulesControllerPlugin rmcp = new MockRegionModulesControllerPlugin(); + sim.m_plugins = new List() { rmcp }; + reg.RegisterInterface(rmcp); + + // XXX: Have to initialize directly for now + rmcp.Initialise(sim); + + rmcp.AddNode(gridService); + + TestSharedRegion tsr = new TestSharedRegion(); + rmcp.AddNode(tsr); + + // FIXME: Want to use the real one eventually but this is currently directly tied into Mono.Addins + // which has been written in such a way that makes it impossible to use for regression tests. +// RegionModulesControllerPlugin rmcp = new RegionModulesControllerPlugin(); +// rmcp.LoadModulesFromAddins = false; +//// reg.RegisterInterface(rmcp); +// rmcp.Initialise(sim); +// rmcp.PostInitialise(); +// TypeExtensionNode node = new TypeExtensionNode(); +// node. +// rmcp.AddNode(node, configSource.Configs["Modules"], new Dictionary>()); + + sim.Startup(); + IScene scene; + sim.CreateRegion(ri, out scene); + + sim.Shutdown(); + + List co = tsr.CallOrder; + int expectedEventCount = 6; + + Assert.AreEqual( + expectedEventCount, + co.Count, + "Expected {0} events but only got {1} ({2})", + expectedEventCount, co.Count, string.Join(",", co)); + Assert.AreEqual("Initialise", co[0]); + Assert.AreEqual("PostInitialise", co[1]); + Assert.AreEqual("AddRegion", co[2]); + Assert.AreEqual("RegionLoaded", co[3]); + Assert.AreEqual("RemoveRegion", co[4]); + Assert.AreEqual("Close", co[5]); + } + } + + class TestSharedRegion : ISharedRegionModule + { + // FIXME: Should really use MethodInfo + public List CallOrder = new List(); + + public string Name { get { return "TestSharedRegion"; } } + + public Type ReplaceableInterface { get { return null; } } + + public void PostInitialise() + { + CallOrder.Add("PostInitialise"); + } + + public void Initialise(IConfigSource source) + { + CallOrder.Add("Initialise"); + } + + public void Close() + { + CallOrder.Add("Close"); + } + + public void AddRegion(Scene scene) + { + CallOrder.Add("AddRegion"); + } + + public void RemoveRegion(Scene scene) + { + CallOrder.Add("RemoveRegion"); + } + + public void RegionLoaded(Scene scene) + { + CallOrder.Add("RegionLoaded"); + } + } + + class MockRegionModulesControllerPlugin : IRegionModulesController, IApplicationPlugin + { + // List of shared module instances, for adding to Scenes + private List m_sharedInstances = new List(); + + // Config access + private OpenSimBase m_openSim; + + public string Version { get { return "0"; } } + public string Name { get { return "MockRegionModulesControllerPlugin"; } } + + public void Initialise() {} + + public void Initialise(OpenSimBase sim) + { + m_openSim = sim; + } + + /// + /// Called when the application loading is completed + /// + public void PostInitialise() + { + foreach (ISharedRegionModule module in m_sharedInstances) + module.PostInitialise(); + } + + public void AddRegionToModules(Scene scene) + { + List sharedlist = new List(); + + foreach (ISharedRegionModule module in m_sharedInstances) + { + module.AddRegion(scene); + scene.AddRegionModule(module.Name, module); + + sharedlist.Add(module); + } + + foreach (ISharedRegionModule module in sharedlist) + { + module.RegionLoaded(scene); + } + } + + public void RemoveRegionFromModules(Scene scene) + { + foreach (IRegionModuleBase module in scene.RegionModules.Values) + { +// m_log.DebugFormat("[REGIONMODULE]: Removing scene {0} from module {1}", +// scene.RegionInfo.RegionName, module.Name); + module.RemoveRegion(scene); + } + + scene.RegionModules.Clear(); + } + + public void AddNode(ISharedRegionModule module) + { + m_sharedInstances.Add(module); + module.Initialise(m_openSim.ConfigSource.Source); + } + + public void Dispose() + { + // We expect that all regions have been removed already + while (m_sharedInstances.Count > 0) + { + m_sharedInstances[0].Close(); + m_sharedInstances.RemoveAt(0); + } + } + } +} \ No newline at end of file diff --git a/Tests/OpenSim.Region.Framework.Tests/Scenes/Tests/TaskInventoryTests.cs b/Tests/OpenSim.Region.Framework.Tests/Scenes/Tests/TaskInventoryTests.cs new file mode 100644 index 00000000000..3254cc06b9f --- /dev/null +++ b/Tests/OpenSim.Region.Framework.Tests/Scenes/Tests/TaskInventoryTests.cs @@ -0,0 +1,175 @@ +/* + * 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 System.Reflection; +using System.Text; +using System.Threading; +using System.Timers; +using Timer=System.Timers.Timer; +using Nini.Config; +using NUnit.Framework; +using OpenMetaverse; +using OpenMetaverse.Assets; +using OpenSim.Framework; +using OpenSim.Region.Framework.Scenes; +using OpenSim.Region.Framework.Interfaces; +using OpenSim.Region.CoreModules.Avatar.Inventory.Archiver; +using OpenSim.Region.CoreModules.World.Serialiser; +using OpenSim.Region.CoreModules.ServiceConnectorsOut.Simulation; +using OpenSim.Services.Interfaces; +using OpenSim.Tests.Common; + +namespace OpenSim.Region.Framework.Tests +{ + [TestFixture] + public class TaskInventoryTests : OpenSimTestCase + { + [Test] + public void TestAddTaskInventoryItem() + { + TestHelpers.InMethod(); +// log4net.Config.XmlConfigurator.Configure(); + + Scene scene = new SceneHelpers().SetupScene(); + UserAccount user1 = UserAccountHelpers.CreateUserWithInventory(scene); + SceneObjectGroup sog1 = SceneHelpers.CreateSceneObject(1, user1.PrincipalID); + SceneObjectPart sop1 = sog1.RootPart; + + // Create an object embedded inside the first + UUID taskSceneObjectItemId = UUID.Parse("00000000-0000-0000-0000-100000000000"); + TaskInventoryHelpers.AddSceneObject(scene.AssetService, sop1, "tso", taskSceneObjectItemId, user1.PrincipalID); + + TaskInventoryItem addedItem = sop1.Inventory.GetInventoryItem(taskSceneObjectItemId); + Assert.That(addedItem.ItemID, Is.EqualTo(taskSceneObjectItemId)); + Assert.That(addedItem.OwnerID, Is.EqualTo(user1.PrincipalID)); + Assert.That(addedItem.ParentID, Is.EqualTo(sop1.UUID)); + Assert.That(addedItem.InvType, Is.EqualTo((int)InventoryType.Object)); + Assert.That(addedItem.Type, Is.EqualTo((int)AssetType.Object)); + } + + [Test] + public void TestRezObjectFromInventoryItem() + { + TestHelpers.InMethod(); + //log4net.Config.XmlConfigurator.Configure(); + + Scene scene = new SceneHelpers().SetupScene(); + UserAccount user1 = UserAccountHelpers.CreateUserWithInventory(scene); + SceneObjectGroup sog1 = SceneHelpers.CreateSceneObject(1, user1.PrincipalID); + SceneObjectPart sop1 = sog1.RootPart; + + // Create an object embedded inside the first + UUID taskSceneObjectItemId = UUID.Parse("00000000-0000-0000-0000-100000000000"); + TaskInventoryItem taskSceneObjectItem + = TaskInventoryHelpers.AddSceneObject(scene.AssetService, sop1, "tso", taskSceneObjectItemId, user1.PrincipalID); + + scene.AddSceneObject(sog1); + + Vector3 rezPos = new Vector3(10, 10, 10); + Quaternion rezRot = new Quaternion(0.5f, 0.5f, 0.5f, 0.5f); + Vector3 rezVel = new Vector3(2, 2, 2); + + scene.RezObject(sop1, taskSceneObjectItem, rezPos, rezRot, rezVel, 0,false); + + SceneObjectGroup rezzedObject = scene.GetSceneObjectGroup("tso"); + + Assert.That(rezzedObject, Is.Not.Null); + Assert.That(rezzedObject.AbsolutePosition, Is.EqualTo(rezPos)); + + // Velocity doesn't get applied, probably because there is no physics in tests (yet) + //Assert.That(rezzedObject.Velocity, Is.EqualTo(rezVel)); + Assert.That(rezzedObject.Velocity, Is.EqualTo(Vector3.Zero)); + + // Confusingly, this isn't the rezzedObject.Rotation + Assert.That(rezzedObject.RootPart.RotationOffset, Is.EqualTo(rezRot)); + } + + /// + /// Test MoveTaskInventoryItem from a part inventory to a user inventory where the item has no parent folder assigned. + /// + /// + /// This should place it in the most suitable user folder. + /// + [Test] + public void TestMoveTaskInventoryItem() + { + TestHelpers.InMethod(); +// log4net.Config.XmlConfigurator.Configure(); + + Scene scene = new SceneHelpers().SetupScene(); + UserAccount user1 = UserAccountHelpers.CreateUserWithInventory(scene); + SceneObjectGroup sog1 = SceneHelpers.CreateSceneObject(1, user1.PrincipalID); + SceneObjectPart sop1 = sog1.RootPart; + TaskInventoryItem sopItem1 + = TaskInventoryHelpers.AddNotecard( + scene.AssetService, sop1, "ncItem", TestHelpers.ParseTail(0x800), TestHelpers.ParseTail(0x900), "Hello World!"); + + InventoryFolderBase folder + = InventoryArchiveUtils.FindFoldersByPath(scene.InventoryService, user1.PrincipalID, "Objects")[0]; + + // Perform test + string message; + scene.MoveTaskInventoryItem(user1.PrincipalID, folder.ID, sop1, sopItem1.ItemID, out message); + + InventoryItemBase ncUserItem + = InventoryArchiveUtils.FindItemByPath(scene.InventoryService, user1.PrincipalID, "Objects/ncItem"); + Assert.That(ncUserItem, Is.Not.Null, "Objects/ncItem was not found"); + } + + /// + /// Test MoveTaskInventoryItem from a part inventory to a user inventory where the item has no parent folder assigned. + /// + /// + /// This should place it in the most suitable user folder. + /// + [Test] + public void TestMoveTaskInventoryItemNoParent() + { + TestHelpers.InMethod(); +// log4net.Config.XmlConfigurator.Configure(); + + Scene scene = new SceneHelpers().SetupScene(); + UserAccount user1 = UserAccountHelpers.CreateUserWithInventory(scene); + SceneObjectGroup sog1 = SceneHelpers.CreateSceneObject(1, user1.PrincipalID); + + SceneObjectPart sop1 = sog1.RootPart; + TaskInventoryItem sopItem1 + = TaskInventoryHelpers.AddNotecard( + scene.AssetService, sop1, "ncItem", TestHelpers.ParseTail(0x800), TestHelpers.ParseTail(0x900), "Hello World!"); + + // Perform test + string message; + scene.MoveTaskInventoryItem(user1.PrincipalID, UUID.Zero, sop1, sopItem1.ItemID, out message); + + InventoryItemBase ncUserItem + = InventoryArchiveUtils.FindItemByPath(scene.InventoryService, user1.PrincipalID, "Notecards/ncItem"); + Assert.That(ncUserItem, Is.Not.Null, "Notecards/ncItem was not found"); + } + } +} \ No newline at end of file diff --git a/Tests/OpenSim.Region.Framework.Tests/Scenes/Tests/UserInventoryTests.cs b/Tests/OpenSim.Region.Framework.Tests/Scenes/Tests/UserInventoryTests.cs new file mode 100644 index 00000000000..514e4970f14 --- /dev/null +++ b/Tests/OpenSim.Region.Framework.Tests/Scenes/Tests/UserInventoryTests.cs @@ -0,0 +1,200 @@ +/* + * 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 System.Reflection; +using System.Text; +using System.Threading; +using System.Timers; +using Timer=System.Timers.Timer; +using Nini.Config; +using NUnit.Framework; +using OpenMetaverse; +using OpenMetaverse.Assets; +using OpenSim.Framework; +using OpenSim.Region.Framework.Scenes; +using OpenSim.Region.CoreModules.Framework.InventoryAccess; +using OpenSim.Services.Interfaces; +using OpenSim.Tests.Common; + +namespace OpenSim.Region.Framework.Tests +{ + [TestFixture] + public class UserInventoryTests : OpenSimTestCase + { + [Test] + public void TestCreateInventoryFolders() + { + TestHelpers.InMethod(); +// TestHelpers.EnableLogging(); + + // For this test both folders will have the same name which is legal in SL user inventories. + string foldersName = "f1"; + + Scene scene = new SceneHelpers().SetupScene(); + UserAccount user1 = UserAccountHelpers.CreateUserWithInventory(scene, TestHelpers.ParseTail(1001)); + + UserInventoryHelpers.CreateInventoryFolder(scene.InventoryService, user1.PrincipalID, foldersName, false); + + List oneFolder + = UserInventoryHelpers.GetInventoryFolders(scene.InventoryService, user1.PrincipalID, foldersName); + + Assert.That(oneFolder.Count, Is.EqualTo(1)); + InventoryFolderBase firstRetrievedFolder = oneFolder[0]; + Assert.That(firstRetrievedFolder.Name, Is.EqualTo(foldersName)); + + UserInventoryHelpers.CreateInventoryFolder(scene.InventoryService, user1.PrincipalID, foldersName, false); + + List twoFolders + = UserInventoryHelpers.GetInventoryFolders(scene.InventoryService, user1.PrincipalID, foldersName); + + Assert.That(twoFolders.Count, Is.EqualTo(2)); + Assert.That(twoFolders[0].Name, Is.EqualTo(foldersName)); + Assert.That(twoFolders[1].Name, Is.EqualTo(foldersName)); + Assert.That(twoFolders[0].ID, Is.Not.EqualTo(twoFolders[1].ID)); + } + + [Test] + public void TestGiveInventoryItem() + { + TestHelpers.InMethod(); +// log4net.Config.XmlConfigurator.Configure(); + + Scene scene = new SceneHelpers().SetupScene(); + UserAccount user1 = UserAccountHelpers.CreateUserWithInventory(scene, TestHelpers.ParseTail(1001)); + UserAccount user2 = UserAccountHelpers.CreateUserWithInventory(scene, TestHelpers.ParseTail(1002)); + InventoryItemBase item1 = UserInventoryHelpers.CreateInventoryItem(scene, "item1", user1.PrincipalID); + + string message; + + scene.GiveInventoryItem(user2.PrincipalID, user1.PrincipalID, item1.ID, out message); + + InventoryItemBase retrievedItem1 + = UserInventoryHelpers.GetInventoryItem(scene.InventoryService, user2.PrincipalID, "Notecards/item1"); + + Assert.That(retrievedItem1, Is.Not.Null); + + // Try giving back the freshly received item + scene.GiveInventoryItem(user1.PrincipalID, user2.PrincipalID, retrievedItem1.ID, out message); + + List reretrievedItems + = UserInventoryHelpers.GetInventoryItems(scene.InventoryService, user1.PrincipalID, "Notecards/item1"); + + Assert.That(reretrievedItems.Count, Is.EqualTo(2)); + } + + [Test] + public void TestGiveInventoryFolder() + { + TestHelpers.InMethod(); +// TestHelpers.EnableLogging(); + + Scene scene = new SceneHelpers().SetupScene(); + UserAccount user1 = UserAccountHelpers.CreateUserWithInventory(scene, TestHelpers.ParseTail(1001)); + UserAccount user2 = UserAccountHelpers.CreateUserWithInventory(scene, TestHelpers.ParseTail(1002)); + InventoryFolderBase folder1 + = UserInventoryHelpers.CreateInventoryFolder(scene.InventoryService, user1.PrincipalID, "folder1", false); + + scene.GiveInventoryFolder(null, user2.PrincipalID, user1.PrincipalID, folder1.ID, UUID.Zero); + + InventoryFolderBase retrievedFolder1 + = UserInventoryHelpers.GetInventoryFolder(scene.InventoryService, user2.PrincipalID, "folder1"); + + Assert.That(retrievedFolder1, Is.Not.Null); + + // Try giving back the freshly received folder + scene.GiveInventoryFolder(null, user1.PrincipalID, user2.PrincipalID, retrievedFolder1.ID, UUID.Zero); + + List reretrievedFolders + = UserInventoryHelpers.GetInventoryFolders(scene.InventoryService, user1.PrincipalID, "folder1"); + + Assert.That(reretrievedFolders.Count, Is.EqualTo(2)); + } + + // Work in Progress test. All Assertions pertaining permissions are commented for now. + [Test] + public void TestGiveInventoryItemFullPerms() + { + TestHelpers.InMethod(); + + List modules = new List(); + IConfigSource config = DefaultConfig(modules); + Scene scene = new SceneHelpers().SetupScene("Inventory Permissions", UUID.Random(), 1000, 1000, config); + SceneHelpers.SetupSceneModules(scene, config, modules.ToArray()); + + UserAccount user1 = UserAccountHelpers.CreateUserWithInventory(scene, TestHelpers.ParseTail(1001)); + UserAccount user2 = UserAccountHelpers.CreateUserWithInventory(scene, TestHelpers.ParseTail(1002)); + ScenePresence sp1 = SceneHelpers.AddScenePresence(scene, user1.PrincipalID); + ScenePresence sp2 = SceneHelpers.AddScenePresence(scene, user2.PrincipalID); + + InventoryItemBase item1 = UserInventoryHelpers.CreateInventoryItem(scene, "SomeObject", user1.PrincipalID, InventoryType.Object); + // Set All perms in inventory + item1.NextPermissions = (uint)OpenMetaverse.PermissionMask.All; + scene.UpdateInventoryItem(sp1.ControllingClient, UUID.Zero, item1.ID, item1); + //Assert.That((item1.NextPermissions & (uint)OpenMetaverse.PermissionMask.All) == (uint)OpenMetaverse.PermissionMask.All); + + string message; + + InventoryItemBase retrievedItem1 = scene.GiveInventoryItem(user2.PrincipalID, user1.PrincipalID, item1.ID, out message); + Assert.That(retrievedItem1, Is.Not.Null); + //Assert.That((retrievedItem1.CurrentPermissions & (uint)OpenMetaverse.PermissionMask.All) == (uint)OpenMetaverse.PermissionMask.All); + + retrievedItem1 + = UserInventoryHelpers.GetInventoryItem(scene.InventoryService, user2.PrincipalID, "Objects/SomeObject"); + Assert.That(retrievedItem1, Is.Not.Null); + //Assert.That((retrievedItem1.BasePermissions & (uint)OpenMetaverse.PermissionMask.All) == (uint)OpenMetaverse.PermissionMask.All); + //Assert.That((retrievedItem1.CurrentPermissions & (uint)OpenMetaverse.PermissionMask.All) == (uint)OpenMetaverse.PermissionMask.All); + + // Rez the object + scene.RezObject(sp2.ControllingClient, retrievedItem1.ID, UUID.Zero, Vector3.Zero, Vector3.Zero, UUID.Zero, 0, false, false, false, UUID.Zero); + SceneObjectGroup sog = scene.GetSceneObjectGroup("SomeObject"); + Assert.That(sog, Is.Not.Null); + + // This is failing for all sorts of reasons. We'll fix it after perms are fixed. + //Console.WriteLine("Item Perms " + retrievedItem1.CurrentPermissions + " Obj Owner Perms " + sog.RootPart.OwnerMask + " Base Perms " + sog.RootPart.BaseMask + "\n"); + //Assert.True((sog.RootPart.OwnerMask & (uint)OpenMetaverse.PermissionMask.All) == (uint)OpenMetaverse.PermissionMask.All); + + } + + public static IConfigSource DefaultConfig(List modules) + { + IConfigSource config = new IniConfigSource(); + config.AddConfig("Modules"); + config.Configs["Modules"].Set("InventoryAccessModule", "BasicInventoryAccessModule"); + + config.AddConfig("Permissions"); + config.Configs["Permissions"].Set("permissionmodules", "DefaultPermissionsModule"); + config.Configs["Permissions"].Set("serverside_object_permissions", true); + config.Configs["Permissions"].Set("propagate_permissions", true); + + modules.Add(new BasicInventoryAccessModule()); + return config; + } + + } +} \ No newline at end of file diff --git a/Tests/OpenSim.Region.Framework.Tests/Scenes/Tests/UuidGathererTests.cs b/Tests/OpenSim.Region.Framework.Tests/Scenes/Tests/UuidGathererTests.cs new file mode 100644 index 00000000000..efe71e9dcf0 --- /dev/null +++ b/Tests/OpenSim.Region.Framework.Tests/Scenes/Tests/UuidGathererTests.cs @@ -0,0 +1,160 @@ +/* + * 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.Collections.Generic; +using System.Text; +using NUnit.Framework; +using OpenMetaverse; +using OpenSim.Framework; +using OpenSim.Region.Framework.Scenes; +using OpenSim.Services.Interfaces; +using OpenSim.Tests.Common; + +namespace OpenSim.Region.Framework.Scenes.Tests +{ + [TestFixture] + public class UuidGathererTests : OpenSimTestCase + { + protected IAssetService m_assetService; + protected UuidGatherer m_uuidGatherer; + + protected static string noteBase = @"Linden text version 2\n{\nLLEmbeddedItems version 1\n +{\ncount 0\n}\nText length xxx\n"; // len does not matter on this test + [SetUp] + public void Init() + { + // FIXME: We don't need a full scene here - it would be enough to set up the asset service. + Scene scene = new SceneHelpers().SetupScene(); + m_assetService = scene.AssetService; + m_uuidGatherer = new UuidGatherer(m_assetService); + } + + [Test] + public void TestCorruptAsset() + { + TestHelpers.InMethod(); + + UUID corruptAssetUuid = UUID.Parse("00000000-0000-0000-0000-000000000666"); + AssetBase corruptAsset + = AssetHelpers.CreateAsset(corruptAssetUuid, AssetType.Notecard, noteBase + "CORRUPT ASSET", UUID.Zero); + m_assetService.Store(corruptAsset); + + m_uuidGatherer.AddForInspection(corruptAssetUuid); + m_uuidGatherer.GatherAll(); + + // We count the uuid as gathered even if the asset itself is corrupt. + Assert.That(m_uuidGatherer.GatheredUuids.Count, Is.EqualTo(1)); + } + + /// + /// Test requests made for non-existent assets while we're gathering + /// + [Test] + public void TestMissingAsset() + { + TestHelpers.InMethod(); + + UUID missingAssetUuid = UUID.Parse("00000000-0000-0000-0000-000000000666"); + + m_uuidGatherer.AddForInspection(missingAssetUuid); + m_uuidGatherer.GatherAll(); + + Assert.That(m_uuidGatherer.GatheredUuids.Count, Is.EqualTo(0)); + } + + [Test] + public void TestNotecardAsset() + { + TestHelpers.InMethod(); + // TestHelpers.EnableLogging(); + + UUID ownerId = TestHelpers.ParseTail(0x10); + UUID embeddedId = TestHelpers.ParseTail(0x20); + UUID secondLevelEmbeddedId = TestHelpers.ParseTail(0x21); + UUID missingEmbeddedId = TestHelpers.ParseTail(0x22); + UUID ncAssetId = TestHelpers.ParseTail(0x30); + + AssetBase ncAsset + = AssetHelpers.CreateNotecardAsset( + ncAssetId, string.Format("{0}Hello{1}World{2}", noteBase, embeddedId, missingEmbeddedId)); + m_assetService.Store(ncAsset); + + AssetBase embeddedAsset + = AssetHelpers.CreateNotecardAsset(embeddedId, string.Format("{0}{1} We'll meet again.", noteBase, secondLevelEmbeddedId)); + m_assetService.Store(embeddedAsset); + + AssetBase secondLevelEmbeddedAsset + = AssetHelpers.CreateNotecardAsset(secondLevelEmbeddedId, noteBase + "Don't know where, don't know when."); + m_assetService.Store(secondLevelEmbeddedAsset); + + m_uuidGatherer.AddForInspection(ncAssetId); + m_uuidGatherer.GatherAll(); + + // foreach (UUID key in m_uuidGatherer.GatheredUuids.Keys) + // System.Console.WriteLine("key : {0}", key); + + Assert.That(m_uuidGatherer.GatheredUuids.Count, Is.EqualTo(3)); + Assert.That(m_uuidGatherer.GatheredUuids.ContainsKey(ncAssetId)); + Assert.That(m_uuidGatherer.GatheredUuids.ContainsKey(embeddedId)); + Assert.That(m_uuidGatherer.GatheredUuids.ContainsKey(secondLevelEmbeddedId)); + } + + [Test] + public void TestTaskItems() + { + TestHelpers.InMethod(); + // TestHelpers.EnableLogging(); + + UUID ownerId = TestHelpers.ParseTail(0x10); + + SceneObjectGroup soL0 = SceneHelpers.CreateSceneObject(1, ownerId, "l0", 0x20); + SceneObjectGroup soL1 = SceneHelpers.CreateSceneObject(1, ownerId, "l1", 0x21); + SceneObjectGroup soL2 = SceneHelpers.CreateSceneObject(1, ownerId, "l2", 0x22); + + TaskInventoryHelpers.AddScript( + m_assetService, soL2.RootPart, TestHelpers.ParseTail(0x33), TestHelpers.ParseTail(0x43), "l3-script", "gibberish"); + + TaskInventoryHelpers.AddSceneObject( + m_assetService, soL1.RootPart, "l2-item", TestHelpers.ParseTail(0x32), soL2, TestHelpers.ParseTail(0x42)); + TaskInventoryHelpers.AddSceneObject( + m_assetService, soL0.RootPart, "l1-item", TestHelpers.ParseTail(0x31), soL1, TestHelpers.ParseTail(0x41)); + + m_uuidGatherer.AddForInspection(soL0); + m_uuidGatherer.GatherAll(); + +// foreach (UUID key in m_uuidGatherer.GatheredUuids.Keys) +// System.Console.WriteLine("key : {0}", key); + + // We expect to see the default prim texture and the assets of the contained task items + Assert.That(m_uuidGatherer.GatheredUuids.Count, Is.EqualTo(4)); + Assert.That(m_uuidGatherer.GatheredUuids.ContainsKey(new UUID(Constants.DefaultTexture))); + Assert.That(m_uuidGatherer.GatheredUuids.ContainsKey(TestHelpers.ParseTail(0x41))); + Assert.That(m_uuidGatherer.GatheredUuids.ContainsKey(TestHelpers.ParseTail(0x42))); + Assert.That(m_uuidGatherer.GatheredUuids.ContainsKey(TestHelpers.ParseTail(0x43))); + } + } +} \ No newline at end of file diff --git a/Tests/OpenSim.Region.OptionalModules.Tests/Avatar/XmlRpcGroups/Tests/GroupsModuleTests.cs b/Tests/OpenSim.Region.OptionalModules.Tests/Avatar/XmlRpcGroups/Tests/GroupsModuleTests.cs new file mode 100644 index 00000000000..ccfcd8b3540 --- /dev/null +++ b/Tests/OpenSim.Region.OptionalModules.Tests/Avatar/XmlRpcGroups/Tests/GroupsModuleTests.cs @@ -0,0 +1,276 @@ +/* + * 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; +using System.Collections.Generic; +using System.Net; +using System.Reflection; +using Nini.Config; +using NUnit.Framework; +using OpenMetaverse; +using OpenMetaverse.Messages.Linden; +using OpenMetaverse.Packets; +using OpenMetaverse.StructuredData; +using OpenSim.Framework; +using OpenSim.Framework.Servers; +using OpenSim.Framework.Servers.HttpServer; +using OpenSim.Region.ClientStack.Linden; +using OpenSim.Region.CoreModules.Avatar.InstantMessage; +using OpenSim.Region.CoreModules.Framework; +using OpenSim.Region.Framework.Scenes; +using OpenSim.Region.OptionalModules.Avatar.XmlRpcGroups; +using OpenSim.Tests.Common; + +namespace OpenSim.Region.OptionalModules.Avatar.XmlRpcGroups.Tests +{ + /// + /// Basic groups module tests + /// + [TestFixture] + public class GroupsModuleTests : OpenSimTestCase + { + [SetUp] + public override void SetUp() + { + base.SetUp(); + + uint port = 9999; + uint sslPort = 9998; + + // This is an unfortunate bit of clean up we have to do because MainServer manages things through static + // variables and the VM is not restarted between tests. + MainServer.RemoveHttpServer(port); + + BaseHttpServer server = new BaseHttpServer(port, false, sslPort, ""); + MainServer.AddHttpServer(server); + MainServer.Instance = server; + } + + [Test] + public void TestSendAgentGroupDataUpdate() + { +/* AgentGroupDataUpdate is udp + TestHelpers.InMethod(); +// TestHelpers.EnableLogging(); + + TestScene scene = new SceneHelpers().SetupScene(); + IConfigSource configSource = new IniConfigSource(); + IConfig config = configSource.AddConfig("Groups"); + config.Set("Enabled", true); + config.Set("Module", "GroupsModule"); + config.Set("DebugEnabled", true); + + GroupsModule gm = new GroupsModule(); + EventQueueGetModule eqgm = new EventQueueGetModule(); + + // We need a capabilities module active so that adding the scene presence creates an event queue in the + // EventQueueGetModule + SceneHelpers.SetupSceneModules( + scene, configSource, gm, new MockGroupsServicesConnector(), new CapabilitiesModule(), eqgm); + + ScenePresence sp = SceneHelpers.AddScenePresence(scene, TestHelpers.ParseStem("1")); + + gm.SendAgentGroupDataUpdate(sp.ControllingClient); + + Hashtable eventsResponse = eqgm.GetEvents(UUID.Zero, sp.UUID); + + if((int)eventsResponse["int_response_code"] != (int)HttpStatusCode.OK) + { + eventsResponse = eqgm.GetEvents(UUID.Zero, sp.UUID); + if((int)eventsResponse["int_response_code"] != (int)HttpStatusCode.OK) + eventsResponse = eqgm.GetEvents(UUID.Zero, sp.UUID); + } + + Assert.That((int)eventsResponse["int_response_code"], Is.EqualTo((int)HttpStatusCode.OK)); + +// Console.WriteLine("Response [{0}]", (string)eventsResponse["str_response_string"]); + + OSDMap rawOsd = (OSDMap)OSDParser.DeserializeLLSDXml((string)eventsResponse["str_response_string"]); + OSDArray eventsOsd = (OSDArray)rawOsd["events"]; + + bool foundUpdate = false; + foreach (OSD osd in eventsOsd) + { + OSDMap eventOsd = (OSDMap)osd; + + if (eventOsd["message"] == "AgentGroupDataUpdate") + foundUpdate = true; + } + + Assert.That(foundUpdate, Is.True, "Did not find AgentGroupDataUpdate in response"); + + // TODO: More checking of more actual event data. +*/ + } + + [Test] + public void TestSendGroupNotice() + { + TestHelpers.InMethod(); +// TestHelpers.EnableLogging(); + + TestScene scene = new SceneHelpers().SetupScene(); + + MessageTransferModule mtm = new MessageTransferModule(); + GroupsModule gm = new GroupsModule(); + GroupsMessagingModule gmm = new GroupsMessagingModule(); + MockGroupsServicesConnector mgsc = new MockGroupsServicesConnector(); + + IConfigSource configSource = new IniConfigSource(); + + { + IConfig config = configSource.AddConfig("Messaging"); + config.Set("MessageTransferModule", mtm.Name); + } + + { + IConfig config = configSource.AddConfig("Groups"); + config.Set("Enabled", true); + config.Set("Module", gm.Name); + config.Set("DebugEnabled", true); + config.Set("MessagingModule", gmm.Name); + config.Set("MessagingEnabled", true); + } + + SceneHelpers.SetupSceneModules(scene, configSource, mgsc, mtm, gm, gmm); + + UUID userId = TestHelpers.ParseTail(0x1); + string subjectText = "newman"; + string messageText = "Hello"; + string combinedSubjectMessage = string.Format("{0}|{1}", subjectText, messageText); + + ScenePresence sp = SceneHelpers.AddScenePresence(scene, TestHelpers.ParseTail(0x1)); + TestClient tc = (TestClient)sp.ControllingClient; + + UUID groupID = gm.CreateGroup(tc, "group1", null, true, UUID.Zero, 0, true, true, true); + gm.JoinGroupRequest(tc, groupID); + + // Create a second user who doesn't want to receive notices + ScenePresence sp2 = SceneHelpers.AddScenePresence(scene, TestHelpers.ParseTail(0x2)); + TestClient tc2 = (TestClient)sp2.ControllingClient; + gm.JoinGroupRequest(tc2, groupID); + gm.SetGroupAcceptNotices(tc2, groupID, false, true); + + List spReceivedMessages = new List(); + tc.OnReceivedInstantMessage += im => spReceivedMessages.Add(im); + + List sp2ReceivedMessages = new List(); + tc2.OnReceivedInstantMessage += im => sp2ReceivedMessages.Add(im); + + GridInstantMessage noticeIm = new GridInstantMessage(); + noticeIm.fromAgentID = userId.Guid; + noticeIm.toAgentID = groupID.Guid; + noticeIm.message = combinedSubjectMessage; + noticeIm.dialog = (byte)InstantMessageDialog.GroupNotice; + + tc.HandleImprovedInstantMessage(noticeIm); + + Assert.That(spReceivedMessages.Count, Is.EqualTo(1)); + Assert.That(spReceivedMessages[0].message, Is.EqualTo(combinedSubjectMessage)); + + List notices = mgsc.GetGroupNotices(UUID.Zero, groupID); + Assert.AreEqual(1, notices.Count); + + // OpenSimulator (possibly also SL) transport the notice ID as the session ID! + Assert.AreEqual(notices[0].NoticeID.Guid, spReceivedMessages[0].imSessionID); + + Assert.That(sp2ReceivedMessages.Count, Is.EqualTo(0)); + } + + /// + /// Run test with the MessageOnlineUsersOnly flag set. + /// + [Test] + public void TestSendGroupNoticeOnlineOnly() + { + TestHelpers.InMethod(); + // TestHelpers.EnableLogging(); + + TestScene scene = new SceneHelpers().SetupScene(); + + MessageTransferModule mtm = new MessageTransferModule(); + GroupsModule gm = new GroupsModule(); + GroupsMessagingModule gmm = new GroupsMessagingModule(); + + IConfigSource configSource = new IniConfigSource(); + + { + IConfig config = configSource.AddConfig("Messaging"); + config.Set("MessageTransferModule", mtm.Name); + } + + { + IConfig config = configSource.AddConfig("Groups"); + config.Set("Enabled", true); + config.Set("Module", gm.Name); + config.Set("DebugEnabled", true); + config.Set("MessagingModule", gmm.Name); + config.Set("MessagingEnabled", true); + config.Set("MessageOnlineUsersOnly", true); + } + + SceneHelpers.SetupSceneModules(scene, configSource, new MockGroupsServicesConnector(), mtm, gm, gmm); + + UUID userId = TestHelpers.ParseTail(0x1); + string subjectText = "newman"; + string messageText = "Hello"; + string combinedSubjectMessage = string.Format("{0}|{1}", subjectText, messageText); + + ScenePresence sp = SceneHelpers.AddScenePresence(scene, TestHelpers.ParseTail(0x1)); + TestClient tc = (TestClient)sp.ControllingClient; + + UUID groupID = gm.CreateGroup(tc, "group1", null, true, UUID.Zero, 0, true, true, true); + gm.JoinGroupRequest(tc, groupID); + + // Create a second user who doesn't want to receive notices + ScenePresence sp2 = SceneHelpers.AddScenePresence(scene, TestHelpers.ParseTail(0x2)); + TestClient tc2 = (TestClient)sp2.ControllingClient; + gm.JoinGroupRequest(tc2, groupID); + gm.SetGroupAcceptNotices(tc2, groupID, false, true); + + List spReceivedMessages = new List(); + tc.OnReceivedInstantMessage += im => spReceivedMessages.Add(im); + + List sp2ReceivedMessages = new List(); + tc2.OnReceivedInstantMessage += im => sp2ReceivedMessages.Add(im); + + GridInstantMessage noticeIm = new GridInstantMessage(); + noticeIm.fromAgentID = userId.Guid; + noticeIm.toAgentID = groupID.Guid; + noticeIm.message = combinedSubjectMessage; + noticeIm.dialog = (byte)InstantMessageDialog.GroupNotice; + + tc.HandleImprovedInstantMessage(noticeIm); + + Assert.That(spReceivedMessages.Count, Is.EqualTo(1)); + Assert.That(spReceivedMessages[0].message, Is.EqualTo(combinedSubjectMessage)); + + Assert.That(sp2ReceivedMessages.Count, Is.EqualTo(0)); + } + } +} \ No newline at end of file diff --git a/Tests/OpenSim.Region.OptionalModules.Tests/Example/WebSocketEchoTest/WebSocketEchoModule.cs b/Tests/OpenSim.Region.OptionalModules.Tests/Example/WebSocketEchoTest/WebSocketEchoModule.cs new file mode 100644 index 00000000000..0747cc07cba --- /dev/null +++ b/Tests/OpenSim.Region.OptionalModules.Tests/Example/WebSocketEchoTest/WebSocketEchoModule.cs @@ -0,0 +1,175 @@ +/* + * 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 System.Reflection; +using OpenSim.Framework.Servers; +using Mono.Addins; +using log4net; +using Nini.Config; +using OpenSim.Region.Framework.Interfaces; +using OpenSim.Region.Framework.Scenes; + +using OpenSim.Framework.Servers.HttpServer; + + +namespace OpenSim.Region.OptionalModules.WebSocketEchoModule +{ + + [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "WebSocketEchoModule")] + public class WebSocketEchoModule : ISharedRegionModule + { + private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + + private bool enabled; + public string Name { get { return "WebSocketEchoModule"; } } + + public Type ReplaceableInterface { get { return null; } } + + + private HashSet _activeHandlers = new HashSet(); + + public void Initialise(IConfigSource pConfig) + { + enabled = (pConfig.Configs["WebSocketEcho"] != null); +// if (enabled) +// m_log.DebugFormat("[WebSocketEchoModule]: INITIALIZED MODULE"); + } + + /// + /// This method sets up the callback to WebSocketHandlerCallback below when a HTTPRequest comes in for /echo + /// + public void PostInitialise() + { + if (enabled) + MainServer.Instance.AddWebSocketHandler("/echo", WebSocketHandlerCallback); + } + + // This gets called by BaseHttpServer and gives us an opportunity to set things on the WebSocket handler before we turn it on + public void WebSocketHandlerCallback(string path, WebSocketHttpServerHandler handler) + { + SubscribeToEvents(handler); + handler.SetChunksize(8192); + handler.NoDelay_TCP_Nagle = true; + handler.HandshakeAndUpgrade(); + } + + //These are our normal events + public void SubscribeToEvents(WebSocketHttpServerHandler handler) + { + handler.OnClose += HandlerOnOnClose; + handler.OnText += HandlerOnOnText; + handler.OnUpgradeCompleted += HandlerOnOnUpgradeCompleted; + handler.OnData += HandlerOnOnData; + handler.OnPong += HandlerOnOnPong; + } + + public void UnSubscribeToEvents(WebSocketHttpServerHandler handler) + { + handler.OnClose -= HandlerOnOnClose; + handler.OnText -= HandlerOnOnText; + handler.OnUpgradeCompleted -= HandlerOnOnUpgradeCompleted; + handler.OnData -= HandlerOnOnData; + handler.OnPong -= HandlerOnOnPong; + } + + private void HandlerOnOnPong(object sender, PongEventArgs pongdata) + { + m_log.Info("[WebSocketEchoModule]: Got a pong.. ping time: " + pongdata.PingResponseMS); + } + + private void HandlerOnOnData(object sender, WebsocketDataEventArgs data) + { + WebSocketHttpServerHandler obj = sender as WebSocketHttpServerHandler; + obj.SendData(data.Data); + m_log.Info("[WebSocketEchoModule]: We received a bunch of ugly non-printable bytes"); + obj.SendPingCheck(); + } + + + private void HandlerOnOnUpgradeCompleted(object sender, UpgradeCompletedEventArgs completeddata) + { + WebSocketHttpServerHandler obj = sender as WebSocketHttpServerHandler; + _activeHandlers.Add(obj); + } + + private void HandlerOnOnText(object sender, WebsocketTextEventArgs text) + { + WebSocketHttpServerHandler obj = sender as WebSocketHttpServerHandler; + obj.SendMessage(text.Data); + m_log.Info("[WebSocketEchoModule]: We received this: " + text.Data); + } + + // Remove the references to our handler + private void HandlerOnOnClose(object sender, CloseEventArgs closedata) + { + WebSocketHttpServerHandler obj = sender as WebSocketHttpServerHandler; + UnSubscribeToEvents(obj); + + lock (_activeHandlers) + _activeHandlers.Remove(obj); + obj.Dispose(); + } + + // Shutting down.. so shut down all sockets. + // Note.. this should be done outside of an ienumerable if you're also hook to the close event. + public void Close() + { + if (!enabled) + return; + + // We convert this to a for loop so we're not in in an IEnumerable when the close + //call triggers an event which then removes item from _activeHandlers that we're enumerating + WebSocketHttpServerHandler[] items = new WebSocketHttpServerHandler[_activeHandlers.Count]; + _activeHandlers.CopyTo(items); + + for (int i = 0; i < items.Length; i++) + { + items[i].Close(string.Empty); + items[i].Dispose(); + } + _activeHandlers.Clear(); + MainServer.Instance.RemoveWebSocketHandler("/echo"); + } + + public void AddRegion(Scene scene) + { +// m_log.DebugFormat("[WebSocketEchoModule]: REGION {0} ADDED", scene.RegionInfo.RegionName); + } + + public void RemoveRegion(Scene scene) + { +// m_log.DebugFormat("[WebSocketEchoModule]: REGION {0} REMOVED", scene.RegionInfo.RegionName); + } + + public void RegionLoaded(Scene scene) + { +// m_log.DebugFormat("[WebSocketEchoModule]: REGION {0} LOADED", scene.RegionInfo.RegionName); + } + } +} \ No newline at end of file diff --git a/Tests/OpenSim.Region.OptionalModules.Tests/Scripting/JsonStore/Tests/JsonStoreScriptModuleTests.cs b/Tests/OpenSim.Region.OptionalModules.Tests/Scripting/JsonStore/Tests/JsonStoreScriptModuleTests.cs new file mode 100644 index 00000000000..77ee7855a52 --- /dev/null +++ b/Tests/OpenSim.Region.OptionalModules.Tests/Scripting/JsonStore/Tests/JsonStoreScriptModuleTests.cs @@ -0,0 +1,900 @@ +/* + * 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 System.Reflection; +using System.Text; +using log4net; +using Nini.Config; +using NUnit.Framework; +using OpenMetaverse; +using OpenSim.Framework; +using OpenSim.Region.CoreModules.Scripting.ScriptModuleComms; +using OpenSim.Region.Framework.Scenes; +using OpenSim.Region.ScriptEngine.Shared; +using OpenSim.Region.ScriptEngine.Shared.Api; +using OpenSim.Services.Interfaces; +using OpenSim.Tests.Common; + +namespace OpenSim.Region.OptionalModules.Scripting.JsonStore.Tests +{ + /// + /// Tests for inventory functions in LSL + /// + [TestFixture] + public class JsonStoreScriptModuleTests : OpenSimTestCase + { + private Scene m_scene; + private MockScriptEngine m_engine; + private ScriptModuleCommsModule m_smcm; + private JsonStoreScriptModule m_jssm; + + [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; + } + + [SetUp] + public override void SetUp() + { + base.SetUp(); + + IConfigSource configSource = new IniConfigSource(); + IConfig jsonStoreConfig = configSource.AddConfig("JsonStore"); + jsonStoreConfig.Set("Enabled", "true"); + + m_engine = new MockScriptEngine(); + m_smcm = new ScriptModuleCommsModule(); + JsonStoreModule jsm = new JsonStoreModule(); + m_jssm = new JsonStoreScriptModule(); + + m_scene = new SceneHelpers().SetupScene(); + SceneHelpers.SetupSceneModules(m_scene, configSource, m_engine, m_smcm, jsm, m_jssm); + + try + { + m_smcm.RegisterScriptInvocation(this, "DummyTestMethod"); + } + catch (ArgumentException) + { + Assert.Ignore("Ignoring test since running on .NET 3.5 or earlier."); + } + + // XXX: Unfortunately, ICommsModule currently has no way of deregistering methods. + } + + private object InvokeOp(string name, params object[] args) + { + return InvokeOpOnHost(name, UUID.Zero, args); + } + + private object InvokeOpOnHost(string name, UUID hostId, params object[] args) + { + return m_smcm.InvokeOperation(hostId, UUID.Zero, name, args); + } + + [Test] + public void TestJsonCreateStore() + { + TestHelpers.InMethod(); +// TestHelpers.EnableLogging(); + + // Test blank store + { + UUID storeId = (UUID)InvokeOp("JsonCreateStore", "{}"); + Assert.That(storeId, Is.Not.EqualTo(UUID.Zero)); + } + + // Test single element store + { + UUID storeId = (UUID)InvokeOp("JsonCreateStore", "{ 'Hello' : 'World' }"); + Assert.That(storeId, Is.Not.EqualTo(UUID.Zero)); + } + + // Test with an integer value + { + UUID storeId = (UUID)InvokeOp("JsonCreateStore", "{ 'Hello' : 42.15 }"); + Assert.That(storeId, Is.Not.EqualTo(UUID.Zero)); + + string value = (string)InvokeOp("JsonGetValue", storeId, "Hello"); + Assert.That(value, Is.EqualTo("42.15")); + } + + // Test with an array as the root node + { + UUID storeId = (UUID)InvokeOp("JsonCreateStore", "[ 'one', 'two', 'three' ]"); + Assert.That(storeId, Is.Not.EqualTo(UUID.Zero)); + + string value = (string)InvokeOp("JsonGetValue", storeId, "[1]"); + Assert.That(value, Is.EqualTo("two")); + } + } + + [Test] + public void TestJsonDestroyStore() + { + TestHelpers.InMethod(); +// TestHelpers.EnableLogging(); + + UUID storeId = (UUID)InvokeOp("JsonCreateStore", "{ 'Hello' : 'World' }"); + int dsrv = (int)InvokeOp("JsonDestroyStore", storeId); + + Assert.That(dsrv, Is.EqualTo(1)); + + int tprv = (int)InvokeOp("JsonGetNodeType", storeId, "Hello"); + Assert.That(tprv, Is.EqualTo(JsonStoreScriptModule.JSON_NODETYPE_UNDEF)); + } + + [Test] + public void TestJsonDestroyStoreNotExists() + { + TestHelpers.InMethod(); +// TestHelpers.EnableLogging(); + + UUID fakeStoreId = TestHelpers.ParseTail(0x500); + + int dsrv = (int)InvokeOp("JsonDestroyStore", fakeStoreId); + + Assert.That(dsrv, Is.EqualTo(0)); + } + + [Test] + public void TestJsonGetValue() + { + TestHelpers.InMethod(); +// TestHelpers.EnableLogging(); + + UUID storeId = (UUID)InvokeOp("JsonCreateStore", "{ 'Hello' : { 'World' : 'Two' } }"); + + { + string value = (string)InvokeOp("JsonGetValue", storeId, "Hello.World"); + Assert.That(value, Is.EqualTo("Two")); + } + + // Test get of path section instead of leaf + { + string value = (string)InvokeOp("JsonGetValue", storeId, "Hello"); + Assert.That(value, Is.EqualTo("")); + } + + // Test get of non-existing value + { + string fakeValueGet = (string)InvokeOp("JsonGetValue", storeId, "foo"); + Assert.That(fakeValueGet, Is.EqualTo("")); + } + + // Test get from non-existing store + { + UUID fakeStoreId = TestHelpers.ParseTail(0x500); + string fakeStoreValueGet = (string)InvokeOp("JsonGetValue", fakeStoreId, "Hello"); + Assert.That(fakeStoreValueGet, Is.EqualTo("")); + } + } + + [Test] + public void TestJsonGetJson() + { + TestHelpers.InMethod(); +// TestHelpers.EnableLogging(); + + UUID storeId = (UUID)InvokeOp("JsonCreateStore", "{ 'Hello' : { 'World' : 'Two' } }"); + + { + string value = (string)InvokeOp("JsonGetJson", storeId, "Hello.World"); + Assert.That(value, Is.EqualTo("'Two'")); + } + + // Test get of path section instead of leaf + { + string value = (string)InvokeOp("JsonGetJson", storeId, "Hello"); + Assert.That(value, Is.EqualTo("{\"World\":\"Two\"}")); + } + + // Test get of non-existing value + { + string fakeValueGet = (string)InvokeOp("JsonGetJson", storeId, "foo"); + Assert.That(fakeValueGet, Is.EqualTo("")); + } + + // Test get from non-existing store + { + UUID fakeStoreId = TestHelpers.ParseTail(0x500); + string fakeStoreValueGet = (string)InvokeOp("JsonGetJson", fakeStoreId, "Hello"); + Assert.That(fakeStoreValueGet, Is.EqualTo("")); + } + } + +// [Test] +// public void TestJsonTakeValue() +// { +// TestHelpers.InMethod(); +//// TestHelpers.EnableLogging(); +// +// UUID storeId +// = (UUID)m_smcm.InvokeOperation( +// UUID.Zero, UUID.Zero, "JsonCreateStore", new object[] { "{ 'Hello' : 'World' }" }); +// +// string value +// = (string)m_smcm.InvokeOperation( +// UUID.Zero, UUID.Zero, "JsonTakeValue", new object[] { storeId, "Hello" }); +// +// Assert.That(value, Is.EqualTo("World")); +// +// string value2 +// = (string)m_smcm.InvokeOperation( +// UUID.Zero, UUID.Zero, "JsonGetValue", new object[] { storeId, "Hello" }); +// +// Assert.That(value, Is.Null); +// } + + [Test] + public void TestJsonRemoveValue() + { + TestHelpers.InMethod(); +// TestHelpers.EnableLogging(); + + // Test remove of node in object pointing to a string + { + UUID storeId = (UUID)InvokeOp("JsonCreateStore", "{ 'Hello' : 'World' }"); + + int returnValue = (int)InvokeOp( "JsonRemoveValue", storeId, "Hello"); + Assert.That(returnValue, Is.EqualTo(1)); + + int result = (int)InvokeOp("JsonGetNodeType", storeId, "Hello"); + Assert.That(result, Is.EqualTo(JsonStoreScriptModule.JSON_NODETYPE_UNDEF)); + + string returnValue2 = (string)InvokeOp("JsonGetValue", storeId, "Hello"); + Assert.That(returnValue2, Is.EqualTo("")); + } + + // Test remove of node in object pointing to another object + { + UUID storeId = (UUID)InvokeOp("JsonCreateStore", "{ 'Hello' : { 'World' : 'Wally' } }"); + + int returnValue = (int)InvokeOp( "JsonRemoveValue", storeId, "Hello"); + Assert.That(returnValue, Is.EqualTo(1)); + + int result = (int)InvokeOp("JsonGetNodeType", storeId, "Hello"); + Assert.That(result, Is.EqualTo(JsonStoreScriptModule.JSON_NODETYPE_UNDEF)); + + string returnValue2 = (string)InvokeOp("JsonGetJson", storeId, "Hello"); + Assert.That(returnValue2, Is.EqualTo("")); + } + + // Test remove of node in an array + { + UUID storeId + = (UUID)InvokeOp("JsonCreateStore", "{ 'Hello' : [ 'value1', 'value2' ] }"); + + int returnValue = (int)InvokeOp( "JsonRemoveValue", storeId, "Hello[0]"); + Assert.That(returnValue, Is.EqualTo(1)); + + int result = (int)InvokeOp("JsonGetNodeType", storeId, "Hello[0]"); + Assert.That(result, Is.EqualTo(JsonStoreScriptModule.JSON_NODETYPE_VALUE)); + + result = (int)InvokeOp("JsonGetNodeType", storeId, "Hello[1]"); + Assert.That(result, Is.EqualTo(JsonStoreScriptModule.JSON_NODETYPE_UNDEF)); + + string stringReturnValue = (string)InvokeOp("JsonGetValue", storeId, "Hello[0]"); + Assert.That(stringReturnValue, Is.EqualTo("value2")); + + stringReturnValue = (string)InvokeOp("JsonGetJson", storeId, "Hello[1]"); + Assert.That(stringReturnValue, Is.EqualTo("")); + } + + // Test remove of non-existing value + { + UUID storeId = (UUID)InvokeOp("JsonCreateStore", "{ 'Hello' : 'World' }"); + + int fakeValueRemove = (int)InvokeOp("JsonRemoveValue", storeId, "Cheese"); + Assert.That(fakeValueRemove, Is.EqualTo(0)); + } + + { + // Test get from non-existing store + UUID fakeStoreId = TestHelpers.ParseTail(0x500); + int fakeStoreValueRemove = (int)InvokeOp("JsonRemoveValue", fakeStoreId, "Hello"); + Assert.That(fakeStoreValueRemove, Is.EqualTo(0)); + } + } + +// [Test] +// public void TestJsonTestPath() +// { +// TestHelpers.InMethod(); +//// TestHelpers.EnableLogging(); +// +// UUID storeId = (UUID)InvokeOp("JsonCreateStore", "{ 'Hello' : { 'World' : 'One' } }"); +// +// { +// int result = (int)InvokeOp("JsonTestPath", storeId, "Hello.World"); +// Assert.That(result, Is.EqualTo(1)); +// } +// +// // Test for path which does not resolve to a value. +// { +// int result = (int)InvokeOp("JsonTestPath", storeId, "Hello"); +// Assert.That(result, Is.EqualTo(0)); +// } +// +// { +// int result2 = (int)InvokeOp("JsonTestPath", storeId, "foo"); +// Assert.That(result2, Is.EqualTo(0)); +// } +// +// // Test with fake store +// { +// UUID fakeStoreId = TestHelpers.ParseTail(0x500); +// int fakeStoreValueRemove = (int)InvokeOp("JsonTestPath", fakeStoreId, "Hello"); +// Assert.That(fakeStoreValueRemove, Is.EqualTo(0)); +// } +// } + +// [Test] +// public void TestJsonTestPathJson() +// { +// TestHelpers.InMethod(); +//// TestHelpers.EnableLogging(); +// +// UUID storeId = (UUID)InvokeOp("JsonCreateStore", "{ 'Hello' : { 'World' : 'One' } }"); +// +// { +// int result = (int)InvokeOp("JsonTestPathJson", storeId, "Hello.World"); +// Assert.That(result, Is.EqualTo(1)); +// } +// +// // Test for path which does not resolve to a value. +// { +// int result = (int)InvokeOp("JsonTestPathJson", storeId, "Hello"); +// Assert.That(result, Is.EqualTo(1)); +// } +// +// { +// int result2 = (int)InvokeOp("JsonTestPathJson", storeId, "foo"); +// Assert.That(result2, Is.EqualTo(0)); +// } +// +// // Test with fake store +// { +// UUID fakeStoreId = TestHelpers.ParseTail(0x500); +// int fakeStoreValueRemove = (int)InvokeOp("JsonTestPathJson", fakeStoreId, "Hello"); +// Assert.That(fakeStoreValueRemove, Is.EqualTo(0)); +// } +// } + + [Test] + public void TestJsonGetArrayLength() + { + TestHelpers.InMethod(); +// TestHelpers.EnableLogging(); + + UUID storeId = (UUID)InvokeOp("JsonCreateStore", "{ 'Hello' : { 'World' : [ 'one', 2 ] } }"); + + { + int result = (int)InvokeOp("JsonGetArrayLength", storeId, "Hello.World"); + Assert.That(result, Is.EqualTo(2)); + } + + // Test path which is not an array + { + int result = (int)InvokeOp("JsonGetArrayLength", storeId, "Hello"); + Assert.That(result, Is.EqualTo(-1)); + } + + // Test fake path + { + int result = (int)InvokeOp("JsonGetArrayLength", storeId, "foo"); + Assert.That(result, Is.EqualTo(-1)); + } + + // Test fake store + { + UUID fakeStoreId = TestHelpers.ParseTail(0x500); + int result = (int)InvokeOp("JsonGetArrayLength", fakeStoreId, "Hello.World"); + Assert.That(result, Is.EqualTo(-1)); + } + } + + [Test] + public void TestJsonGetNodeType() + { + TestHelpers.InMethod(); +// TestHelpers.EnableLogging(); + + UUID storeId = (UUID)InvokeOp("JsonCreateStore", "{ 'Hello' : { 'World' : [ 'one', 2 ] } }"); + + { + int result = (int)InvokeOp("JsonGetNodeType", storeId, "."); + Assert.That(result, Is.EqualTo(JsonStoreScriptModule.JSON_NODETYPE_OBJECT)); + } + + { + int result = (int)InvokeOp("JsonGetNodeType", storeId, "Hello"); + Assert.That(result, Is.EqualTo(JsonStoreScriptModule.JSON_NODETYPE_OBJECT)); + } + + { + int result = (int)InvokeOp("JsonGetNodeType", storeId, "Hello.World"); + Assert.That(result, Is.EqualTo(JsonStoreScriptModule.JSON_NODETYPE_ARRAY)); + } + + { + int result = (int)InvokeOp("JsonGetNodeType", storeId, "Hello.World[0]"); + Assert.That(result, Is.EqualTo(JsonStoreScriptModule.JSON_NODETYPE_VALUE)); + } + + { + int result = (int)InvokeOp("JsonGetNodeType", storeId, "Hello.World[1]"); + Assert.That(result, Is.EqualTo(JsonStoreScriptModule.JSON_NODETYPE_VALUE)); + } + + // Test for non-existent path + { + int result = (int)InvokeOp("JsonGetNodeType", storeId, "foo"); + Assert.That(result, Is.EqualTo(JsonStoreScriptModule.JSON_NODETYPE_UNDEF)); + } + + // Test for non-existent store + { + UUID fakeStoreId = TestHelpers.ParseTail(0x500); + int result = (int)InvokeOp("JsonGetNodeType", fakeStoreId, "."); + Assert.That(result, Is.EqualTo(JsonStoreScriptModule.JSON_NODETYPE_UNDEF)); + } + } + + [Test] + public void TestJsonList2Path() + { + TestHelpers.InMethod(); +// TestHelpers.EnableLogging(); + + // Invoking these methods directly since I just couldn't get comms module invocation to work for some reason + // - some confusion with the methods that take a params object[] invocation. + { + string result = m_jssm.JsonList2Path(UUID.Zero, UUID.Zero, new object[] { "foo" }); + Assert.That(result, Is.EqualTo("{foo}")); + } + + { + string result = m_jssm.JsonList2Path(UUID.Zero, UUID.Zero, new object[] { "foo", "bar" }); + Assert.That(result, Is.EqualTo("{foo}.{bar}")); + } + + { + string result = m_jssm.JsonList2Path(UUID.Zero, UUID.Zero, new object[] { "foo", 1, "bar" }); + Assert.That(result, Is.EqualTo("{foo}.[1].{bar}")); + } + } + + [Test] + public void TestJsonSetValue() + { + TestHelpers.InMethod(); +// TestHelpers.EnableLogging(); + + { + UUID storeId = (UUID)InvokeOp("JsonCreateStore", "{}"); + + int result = (int)InvokeOp("JsonSetValue", storeId, "Fun", "Times"); + Assert.That(result, Is.EqualTo(1)); + + string value = (string)InvokeOp("JsonGetValue", storeId, "Fun"); + Assert.That(value, Is.EqualTo("Times")); + } + + // Test setting a key containing periods with delineation + { + UUID storeId = (UUID)InvokeOp("JsonCreateStore", "{}"); + + int result = (int)InvokeOp("JsonSetValue", storeId, "{Fun.Circus}", "Times"); + Assert.That(result, Is.EqualTo(1)); + + string value = (string)InvokeOp("JsonGetValue", storeId, "{Fun.Circus}"); + Assert.That(value, Is.EqualTo("Times")); + } + + // *** Test [] *** + + // Test setting a key containing unbalanced ] without delineation. Expecting failure + { + UUID storeId = (UUID)InvokeOp("JsonCreateStore", "{}"); + + int result = (int)InvokeOp("JsonSetValue", storeId, "Fun]Circus", "Times"); + Assert.That(result, Is.EqualTo(0)); + + string value = (string)InvokeOp("JsonGetValue", storeId, "Fun]Circus"); + Assert.That(value, Is.EqualTo("")); + } + + // Test setting a key containing unbalanced [ without delineation. Expecting failure + { + UUID storeId = (UUID)InvokeOp("JsonCreateStore", "{}"); + + int result = (int)InvokeOp("JsonSetValue", storeId, "Fun[Circus", "Times"); + Assert.That(result, Is.EqualTo(0)); + + string value = (string)InvokeOp("JsonGetValue", storeId, "Fun[Circus"); + Assert.That(value, Is.EqualTo("")); + } + + // Test setting a key containing unbalanced [] without delineation. Expecting failure + { + UUID storeId = (UUID)InvokeOp("JsonCreateStore", "{}"); + + int result = (int)InvokeOp("JsonSetValue", storeId, "Fun[]Circus", "Times"); + Assert.That(result, Is.EqualTo(0)); + + string value = (string)InvokeOp("JsonGetValue", storeId, "Fun[]Circus"); + Assert.That(value, Is.EqualTo("")); + } + + // Test setting a key containing unbalanced ] with delineation + { + UUID storeId = (UUID)InvokeOp("JsonCreateStore", "{}"); + + int result = (int)InvokeOp("JsonSetValue", storeId, "{Fun]Circus}", "Times"); + Assert.That(result, Is.EqualTo(1)); + + string value = (string)InvokeOp("JsonGetValue", storeId, "{Fun]Circus}"); + Assert.That(value, Is.EqualTo("Times")); + } + + // Test setting a key containing unbalanced [ with delineation + { + UUID storeId = (UUID)InvokeOp("JsonCreateStore", "{}"); + + int result = (int)InvokeOp("JsonSetValue", storeId, "{Fun[Circus}", "Times"); + Assert.That(result, Is.EqualTo(1)); + + string value = (string)InvokeOp("JsonGetValue", storeId, "{Fun[Circus}"); + Assert.That(value, Is.EqualTo("Times")); + } + + // Test setting a key containing empty balanced [] with delineation + { + UUID storeId = (UUID)InvokeOp("JsonCreateStore", "{}"); + + int result = (int)InvokeOp("JsonSetValue", storeId, "{Fun[]Circus}", "Times"); + Assert.That(result, Is.EqualTo(1)); + + string value = (string)InvokeOp("JsonGetValue", storeId, "{Fun[]Circus}"); + Assert.That(value, Is.EqualTo("Times")); + } + +// // Commented out as this currently unexpectedly fails. +// // Test setting a key containing brackets around an integer with delineation +// { +// UUID storeId = (UUID)InvokeOp("JsonCreateStore", "{}"); +// +// int result = (int)InvokeOp("JsonSetValue", storeId, "{Fun[0]Circus}", "Times"); +// Assert.That(result, Is.EqualTo(1)); +// +// string value = (string)InvokeOp("JsonGetValue", storeId, "{Fun[0]Circus}"); +// Assert.That(value, Is.EqualTo("Times")); +// } + + // *** Test {} *** + + // Test setting a key containing unbalanced } without delineation. Expecting failure (?) + { + UUID storeId = (UUID)InvokeOp("JsonCreateStore", "{}"); + + int result = (int)InvokeOp("JsonSetValue", storeId, "Fun}Circus", "Times"); + Assert.That(result, Is.EqualTo(0)); + + string value = (string)InvokeOp("JsonGetValue", storeId, "Fun}Circus"); + Assert.That(value, Is.EqualTo("")); + } + + // Test setting a key containing unbalanced { without delineation. Expecting failure (?) + { + UUID storeId = (UUID)InvokeOp("JsonCreateStore", "{}"); + + int result = (int)InvokeOp("JsonSetValue", storeId, "Fun{Circus", "Times"); + Assert.That(result, Is.EqualTo(0)); + + string value = (string)InvokeOp("JsonGetValue", storeId, "Fun}Circus"); + Assert.That(value, Is.EqualTo("")); + } + +// // Commented out as this currently unexpectedly fails. +// // Test setting a key containing unbalanced } +// { +// UUID storeId = (UUID)InvokeOp("JsonCreateStore", "{}"); +// +// int result = (int)InvokeOp("JsonSetValue", storeId, "{Fun}Circus}", "Times"); +// Assert.That(result, Is.EqualTo(0)); +// } + + // Test setting a key containing unbalanced { with delineation + { + UUID storeId = (UUID)InvokeOp("JsonCreateStore", "{}"); + + int result = (int)InvokeOp("JsonSetValue", storeId, "{Fun{Circus}", "Times"); + Assert.That(result, Is.EqualTo(1)); + + string value = (string)InvokeOp("JsonGetValue", storeId, "{Fun{Circus}"); + Assert.That(value, Is.EqualTo("Times")); + } + + // Test setting a key containing balanced {} with delineation. This should fail. + { + UUID storeId = (UUID)InvokeOp("JsonCreateStore", "{}"); + + int result = (int)InvokeOp("JsonSetValue", storeId, "{Fun{Filled}Circus}", "Times"); + Assert.That(result, Is.EqualTo(0)); + + string value = (string)InvokeOp("JsonGetValue", storeId, "{Fun{Filled}Circus}"); + Assert.That(value, Is.EqualTo("")); + } + + // Test setting to location that does not exist. This should fail. + { + UUID storeId = (UUID)InvokeOp("JsonCreateStore", "{}"); + + int result = (int)InvokeOp("JsonSetValue", storeId, "Fun.Circus", "Times"); + Assert.That(result, Is.EqualTo(0)); + + string value = (string)InvokeOp("JsonGetValue", storeId, "Fun.Circus"); + Assert.That(value, Is.EqualTo("")); + } + + // Test with fake store + { + UUID fakeStoreId = TestHelpers.ParseTail(0x500); + int fakeStoreValueSet = (int)InvokeOp("JsonSetValue", fakeStoreId, "Hello", "World"); + Assert.That(fakeStoreValueSet, Is.EqualTo(0)); + } + } + + [Test] + public void TestJsonSetJson() + { + TestHelpers.InMethod(); +// TestHelpers.EnableLogging(); + + // Single quoted token case + { + UUID storeId = (UUID)InvokeOp("JsonCreateStore", "{ }"); + + int result = (int)InvokeOp("JsonSetJson", storeId, "Fun", "'Times'"); + Assert.That(result, Is.EqualTo(1)); + + string value = (string)InvokeOp("JsonGetValue", storeId, "Fun"); + Assert.That(value, Is.EqualTo("Times")); + } + + // Sub-tree case + { + UUID storeId = (UUID)InvokeOp("JsonCreateStore", "{ }"); + + int result = (int)InvokeOp("JsonSetJson", storeId, "Fun", "{ 'Filled' : 'Times' }"); + Assert.That(result, Is.EqualTo(1)); + + string value = (string)InvokeOp("JsonGetValue", storeId, "Fun.Filled"); + Assert.That(value, Is.EqualTo("Times")); + } + + // If setting single strings in JsonSetValueJson, these must be single quoted tokens, not bare strings. + { + UUID storeId = (UUID)InvokeOp("JsonCreateStore", "{ }"); + + int result = (int)InvokeOp("JsonSetJson", storeId, "Fun", "Times"); + Assert.That(result, Is.EqualTo(0)); + + string value = (string)InvokeOp("JsonGetValue", storeId, "Fun"); + Assert.That(value, Is.EqualTo("")); + } + + // Test setting to location that does not exist. This should fail. + { + UUID storeId = (UUID)InvokeOp("JsonCreateStore", "{ }"); + + int result = (int)InvokeOp("JsonSetJson", storeId, "Fun.Circus", "'Times'"); + Assert.That(result, Is.EqualTo(0)); + + string value = (string)InvokeOp("JsonGetValue", storeId, "Fun.Circus"); + Assert.That(value, Is.EqualTo("")); + } + + // Test with fake store + { + UUID fakeStoreId = TestHelpers.ParseTail(0x500); + int fakeStoreValueSet = (int)InvokeOp("JsonSetJson", fakeStoreId, "Hello", "'World'"); + Assert.That(fakeStoreValueSet, Is.EqualTo(0)); + } + } + + /// + /// Test for writing json to a notecard + /// + /// + /// TODO: Really needs to test correct receipt of the link_message event. Could do this by directly fetching + /// it via the MockScriptEngine or perhaps by a dummy script instance. + /// + [Test] + public void TestJsonWriteNotecard() + { + TestHelpers.InMethod(); +// TestHelpers.EnableLogging(); + + SceneObjectGroup so = SceneHelpers.CreateSceneObject(1, TestHelpers.ParseTail(0x1)); + m_scene.AddSceneObject(so); + + UUID storeId = (UUID)InvokeOp("JsonCreateStore", "{ 'Hello':'World' }"); + + { + string notecardName = "nc1"; + + // Write notecard + UUID writeNotecardRequestId = (UUID)InvokeOpOnHost("JsonWriteNotecard", so.UUID, storeId, "", notecardName); + Assert.That(writeNotecardRequestId, Is.Not.EqualTo(UUID.Zero)); + + TaskInventoryItem nc1Item = so.RootPart.Inventory.GetInventoryItem(notecardName); + Assert.That(nc1Item, Is.Not.Null); + + // TODO: Should independently check the contents. + } + + // TODO: Write partial test + + { + // Try to write notecard for a bad path + // In this case we do get a request id but no notecard is written. + string badPathNotecardName = "badPathNotecardName"; + + UUID writeNotecardBadPathRequestId + = (UUID)InvokeOpOnHost("JsonWriteNotecard", so.UUID, storeId, "flibble", badPathNotecardName); + Assert.That(writeNotecardBadPathRequestId, Is.Not.EqualTo(UUID.Zero)); + + TaskInventoryItem badPathItem = so.RootPart.Inventory.GetInventoryItem(badPathNotecardName); + Assert.That(badPathItem, Is.Null); + } + + { + // Test with fake store + // In this case we do get a request id but no notecard is written. + string fakeStoreNotecardName = "fakeStoreNotecardName"; + + UUID fakeStoreId = TestHelpers.ParseTail(0x500); + UUID fakeStoreWriteNotecardValue + = (UUID)InvokeOpOnHost("JsonWriteNotecard", so.UUID, fakeStoreId, "", fakeStoreNotecardName); + Assert.That(fakeStoreWriteNotecardValue, Is.Not.EqualTo(UUID.Zero)); + + TaskInventoryItem fakeStoreItem = so.RootPart.Inventory.GetInventoryItem(fakeStoreNotecardName); + Assert.That(fakeStoreItem, Is.Null); + } + } + + /// + /// Test for reading json from a notecard + /// + /// + /// TODO: Really needs to test correct receipt of the link_message event. Could do this by directly fetching + /// it via the MockScriptEngine or perhaps by a dummy script instance. + /// + [Test] + public void TestJsonReadNotecard() + { + TestHelpers.InMethod(); +// TestHelpers.EnableLogging(); + + string notecardName = "nc1"; + + SceneObjectGroup so = SceneHelpers.CreateSceneObject(1, TestHelpers.ParseTail(0x1)); + m_scene.AddSceneObject(so); + + UUID creatingStoreId = (UUID)InvokeOp("JsonCreateStore", "{ 'Hello':'World' }"); + + // Write notecard + InvokeOpOnHost("JsonWriteNotecard", so.UUID, creatingStoreId, "", notecardName); + + { + // Read notecard + UUID receivingStoreId = (UUID)InvokeOp("JsonCreateStore", "{}"); + UUID readNotecardRequestId = (UUID)InvokeOpOnHost("JsonReadNotecard", so.UUID, receivingStoreId, "", notecardName); + Assert.That(readNotecardRequestId, Is.Not.EqualTo(UUID.Zero)); + + string value = (string)InvokeOp("JsonGetValue", receivingStoreId, "Hello"); + Assert.That(value, Is.EqualTo("World")); + } + + { + // Read notecard to new single component path + UUID receivingStoreId = (UUID)InvokeOp("JsonCreateStore", "{}"); + UUID readNotecardRequestId = (UUID)InvokeOpOnHost("JsonReadNotecard", so.UUID, receivingStoreId, "make", notecardName); + Assert.That(readNotecardRequestId, Is.Not.EqualTo(UUID.Zero)); + + string value = (string)InvokeOp("JsonGetValue", receivingStoreId, "Hello"); + Assert.That(value, Is.EqualTo("")); + + value = (string)InvokeOp("JsonGetValue", receivingStoreId, "make.Hello"); + Assert.That(value, Is.EqualTo("World")); + } + + { + // Read notecard to new multi-component path. This should not work. + UUID receivingStoreId = (UUID)InvokeOp("JsonCreateStore", "{}"); + UUID readNotecardRequestId = (UUID)InvokeOpOnHost("JsonReadNotecard", so.UUID, receivingStoreId, "make.it", notecardName); + Assert.That(readNotecardRequestId, Is.Not.EqualTo(UUID.Zero)); + + string value = (string)InvokeOp("JsonGetValue", receivingStoreId, "Hello"); + Assert.That(value, Is.EqualTo("")); + + value = (string)InvokeOp("JsonGetValue", receivingStoreId, "make.it.Hello"); + Assert.That(value, Is.EqualTo("")); + } + + { + // Read notecard to existing multi-component path. This should work + UUID receivingStoreId = (UUID)InvokeOp("JsonCreateStore", "{ 'make' : { 'it' : 'so' } }"); + UUID readNotecardRequestId = (UUID)InvokeOpOnHost("JsonReadNotecard", so.UUID, receivingStoreId, "make.it", notecardName); + Assert.That(readNotecardRequestId, Is.Not.EqualTo(UUID.Zero)); + + string value = (string)InvokeOp("JsonGetValue", receivingStoreId, "Hello"); + Assert.That(value, Is.EqualTo("")); + + value = (string)InvokeOp("JsonGetValue", receivingStoreId, "make.it.Hello"); + Assert.That(value, Is.EqualTo("World")); + } + + { + // Read notecard to invalid path. This should not work. + UUID receivingStoreId = (UUID)InvokeOp("JsonCreateStore", "{ 'make' : { 'it' : 'so' } }"); + UUID readNotecardRequestId = (UUID)InvokeOpOnHost("JsonReadNotecard", so.UUID, receivingStoreId, "/", notecardName); + Assert.That(readNotecardRequestId, Is.Not.EqualTo(UUID.Zero)); + + string value = (string)InvokeOp("JsonGetValue", receivingStoreId, "Hello"); + Assert.That(value, Is.EqualTo("")); + } + + { + // Try read notecard to fake store. + UUID fakeStoreId = TestHelpers.ParseTail(0x500); + UUID readNotecardRequestId = (UUID)InvokeOpOnHost("JsonReadNotecard", so.UUID, fakeStoreId, "", notecardName); + Assert.That(readNotecardRequestId, Is.Not.EqualTo(UUID.Zero)); + + string value = (string)InvokeOp("JsonGetValue", fakeStoreId, "Hello"); + Assert.That(value, Is.EqualTo("")); + } + } + + public object DummyTestMethod(object o1, object o2, object o3, object o4, object o5) { return null; } + } +} diff --git a/Tests/OpenSim.Region.OptionalModules.Tests/World/NPC/Tests/NPCModuleTests.cs b/Tests/OpenSim.Region.OptionalModules.Tests/World/NPC/Tests/NPCModuleTests.cs new file mode 100644 index 00000000000..9a1ea732748 --- /dev/null +++ b/Tests/OpenSim.Region.OptionalModules.Tests/World/NPC/Tests/NPCModuleTests.cs @@ -0,0 +1,486 @@ +/* + * 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 System.Reflection; +using log4net; +using Nini.Config; +using NUnit.Framework; +using OpenMetaverse; +using OpenSim.Framework; +using OpenSim.Region.CoreModules.Avatar.Attachments; +using OpenSim.Region.CoreModules.Avatar.AvatarFactory; +using OpenSim.Region.CoreModules.Framework.InventoryAccess; +using OpenSim.Region.CoreModules.Framework.UserManagement; +using OpenSim.Region.CoreModules.ServiceConnectorsOut.Avatar; +using OpenSim.Region.Framework.Interfaces; +using OpenSim.Region.Framework.Scenes; +using OpenSim.Services.AvatarService; +using OpenSim.Tests.Common; + +namespace OpenSim.Region.OptionalModules.World.NPC.Tests +{ + [TestFixture] + public class NPCModuleTests : OpenSimTestCase + { + private TestScene m_scene; + private AvatarFactoryModule m_afMod; + private UserManagementModule m_umMod; + private AttachmentsModule m_attMod; + private NPCModule m_npcMod; + + [TestFixtureSetUp] + public void FixtureInit() + { + // Don't allow tests to be bamboozled by asynchronous events. Execute everything on the same thread. + Util.FireAndForgetMethod = FireAndForgetMethod.None; + } + + [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 not to worry about such things. + Util.FireAndForgetMethod = Util.DefaultFireAndForgetMethod; + } + + public void SetUpScene() + { + SetUpScene(256, 256); + } + + public void SetUpScene(uint sizeX, uint sizeY) + { + IConfigSource config = new IniConfigSource(); + config.AddConfig("NPC"); + config.Configs["NPC"].Set("Enabled", "true"); + config.AddConfig("Modules"); + config.Configs["Modules"].Set("InventoryAccessModule", "BasicInventoryAccessModule"); + + m_afMod = new AvatarFactoryModule(); + m_umMod = new UserManagementModule(); + m_attMod = new AttachmentsModule(); + m_npcMod = new NPCModule(); + + m_scene = new SceneHelpers().SetupScene("test scene", UUID.Random(), 1000, 1000, sizeX, sizeY, config); + SceneHelpers.SetupSceneModules(m_scene, config, m_afMod, m_umMod, m_attMod, m_npcMod, new BasicInventoryAccessModule()); + } + + [Test] + public void TestCreate() + { + TestHelpers.InMethod(); +// log4net.Config.XmlConfigurator.Configure(); + + SetUpScene(); + + ScenePresence sp = SceneHelpers.AddScenePresence(m_scene, TestHelpers.ParseTail(0x1)); +// ScenePresence originalAvatar = scene.GetScenePresence(originalClient.AgentId); + + // 8 is the index of the first baked texture in AvatarAppearance + UUID originalFace8TextureId = TestHelpers.ParseTail(0x10); + Primitive.TextureEntry originalTe = new Primitive.TextureEntry(UUID.Zero); + Primitive.TextureEntryFace originalTef = originalTe.CreateFace(8); + originalTef.TextureID = originalFace8TextureId; + + // We also need to add the texture to the asset service, otherwise the AvatarFactoryModule will tell + // ScenePresence.SendInitialData() to reset our entire appearance. + m_scene.AssetService.Store(AssetHelpers.CreateNotecardAsset(originalFace8TextureId)); + + m_afMod.SetAppearance(sp, originalTe, null, new WearableCacheItem[0] ); + + UUID npcId = m_npcMod.CreateNPC("John", "Smith", new Vector3(128, 128, 30), UUID.Zero, true, m_scene, sp.Appearance); + + ScenePresence npc = m_scene.GetScenePresence(npcId); + + Assert.That(npc, Is.Not.Null); + Assert.That(npc.Appearance.Texture.FaceTextures[8].TextureID, Is.EqualTo(originalFace8TextureId)); + Assert.That(m_umMod.GetUserName(npc.UUID), Is.EqualTo(string.Format("{0} {1}", npc.Firstname, npc.Lastname))); + + IClientAPI client; + Assert.That(m_scene.TryGetClient(npcId, out client), Is.True); + + // Have to account for both SP and NPC. + Assert.That(m_scene.AuthenticateHandler.GetAgentCircuits().Count, Is.EqualTo(2)); + } + + [Test] + public void TestRemove() + { + TestHelpers.InMethod(); +// log4net.Config.XmlConfigurator.Configure(); + + SetUpScene(); + + ScenePresence sp = SceneHelpers.AddScenePresence(m_scene, TestHelpers.ParseTail(0x1)); +// ScenePresence originalAvatar = scene.GetScenePresence(originalClient.AgentId); + + Vector3 startPos = new Vector3(128, 128, 30); + UUID npcId = m_npcMod.CreateNPC("John", "Smith", startPos, UUID.Zero, true, m_scene, sp.Appearance); + + m_npcMod.DeleteNPC(npcId, m_scene); + + ScenePresence deletedNpc = m_scene.GetScenePresence(npcId); + + Assert.That(deletedNpc, Is.Null); + IClientAPI client; + Assert.That(m_scene.TryGetClient(npcId, out client), Is.False); + + // Have to account for SP still present. + Assert.That(m_scene.AuthenticateHandler.GetAgentCircuits().Count, Is.EqualTo(1)); + } + + [Test] + public void TestCreateWithAttachments() + { + TestHelpers.InMethod(); +// TestHelpers.EnableLogging(); + + SetUpScene(); + + UUID userId = TestHelpers.ParseTail(0x1); + UserAccountHelpers.CreateUserWithInventory(m_scene, userId); + ScenePresence sp = SceneHelpers.AddScenePresence(m_scene, userId); + + UUID attItemId = TestHelpers.ParseTail(0x2); + UUID attAssetId = TestHelpers.ParseTail(0x3); + string attName = "att"; + + UserInventoryHelpers.CreateInventoryItem(m_scene, attName, attItemId, attAssetId, sp.UUID, InventoryType.Object); + + m_attMod.RezSingleAttachmentFromInventory(sp, attItemId, (uint)AttachmentPoint.Chest); + + UUID npcId = m_npcMod.CreateNPC("John", "Smith", new Vector3(128, 128, 30), UUID.Zero, true, m_scene, sp.Appearance); + + ScenePresence npc = m_scene.GetScenePresence(npcId); + + // Check scene presence status + Assert.That(npc.HasAttachments(), Is.True); + List attachments = npc.GetAttachments(); + Assert.That(attachments.Count, Is.EqualTo(1)); + SceneObjectGroup attSo = attachments[0]; + + // Just for now, we won't test the name since this is (wrongly) the asset part name rather than the item + // name. TODO: Do need to fix ultimately since the item may be renamed before being passed on to an NPC. +// Assert.That(attSo.Name, Is.EqualTo(attName)); + + Assert.That(attSo.AttachmentPoint, Is.EqualTo((byte)AttachmentPoint.Chest)); + Assert.That(attSo.IsAttachment); + Assert.That(attSo.UsesPhysics, Is.False); + Assert.That(attSo.IsTemporary, Is.False); + Assert.That(attSo.OwnerID, Is.EqualTo(npc.UUID)); + } + + [Test] + public void TestCreateWithMultiAttachments() + { + TestHelpers.InMethod(); +// TestHelpers.EnableLogging(); + + SetUpScene(); +// m_attMod.DebugLevel = 1; + + UUID userId = TestHelpers.ParseTail(0x1); + UserAccountHelpers.CreateUserWithInventory(m_scene, userId); + ScenePresence sp = SceneHelpers.AddScenePresence(m_scene, userId); + + InventoryItemBase att1Item + = UserInventoryHelpers.CreateInventoryItem( + m_scene, "att1", TestHelpers.ParseTail(0x2), TestHelpers.ParseTail(0x3), sp.UUID, InventoryType.Object); + InventoryItemBase att2Item + = UserInventoryHelpers.CreateInventoryItem( + m_scene, "att2", TestHelpers.ParseTail(0x12), TestHelpers.ParseTail(0x13), sp.UUID, InventoryType.Object); + + m_attMod.RezSingleAttachmentFromInventory(sp, att1Item.ID, (uint)AttachmentPoint.Chest); + m_attMod.RezSingleAttachmentFromInventory(sp, att2Item.ID, (uint)AttachmentPoint.Chest | 0x80); + + UUID npcId = m_npcMod.CreateNPC("John", "Smith", new Vector3(128, 128, 30), UUID.Zero, true, m_scene, sp.Appearance); + + ScenePresence npc = m_scene.GetScenePresence(npcId); + + // Check scene presence status + Assert.That(npc.HasAttachments(), Is.True); + List attachments = npc.GetAttachments(); + Assert.That(attachments.Count, Is.EqualTo(2)); + + // Just for now, we won't test the name since this is (wrongly) the asset part name rather than the item + // name. TODO: Do need to fix ultimately since the item may be renamed before being passed on to an NPC. +// Assert.That(attSo.Name, Is.EqualTo(attName)); + + TestAttachedObject(attachments[0], AttachmentPoint.Chest, npc.UUID); + TestAttachedObject(attachments[1], AttachmentPoint.Chest, npc.UUID); + + // Attached objects on the same point must have different FromItemIDs to be shown to other avatars, at least + // on Singularity 1.8.5. Otherwise, only one (the first ObjectUpdate sent) appears. + Assert.AreNotEqual(attachments[0].FromItemID, attachments[1].FromItemID); + } + + private void TestAttachedObject(SceneObjectGroup attSo, AttachmentPoint attPoint, UUID ownerId) + { + Assert.That(attSo.AttachmentPoint, Is.EqualTo((byte)attPoint)); + Assert.That(attSo.IsAttachment); + Assert.That(attSo.UsesPhysics, Is.False); + Assert.That(attSo.IsTemporary, Is.False); + Assert.That(attSo.OwnerID, Is.EqualTo(ownerId)); + } + + [Test] + public void TestLoadAppearance() + { + TestHelpers.InMethod(); +// log4net.Config.XmlConfigurator.Configure(); + + SetUpScene(); + + UUID userId = TestHelpers.ParseTail(0x1); + UserAccountHelpers.CreateUserWithInventory(m_scene, userId); + ScenePresence sp = SceneHelpers.AddScenePresence(m_scene, userId); + + UUID npcId = m_npcMod.CreateNPC("John", "Smith", new Vector3(128, 128, 30), UUID.Zero, true, m_scene, sp.Appearance); + + // Now add the attachment to the original avatar and use that to load a new appearance + // TODO: Could also run tests loading from a notecard though this isn't much different for our purposes here + UUID attItemId = TestHelpers.ParseTail(0x2); + UUID attAssetId = TestHelpers.ParseTail(0x3); + string attName = "att"; + + UserInventoryHelpers.CreateInventoryItem(m_scene, attName, attItemId, attAssetId, sp.UUID, InventoryType.Object); + + m_attMod.RezSingleAttachmentFromInventory(sp, attItemId, (uint)AttachmentPoint.Chest); + + m_npcMod.SetNPCAppearance(npcId, sp.Appearance, m_scene); + + ScenePresence npc = m_scene.GetScenePresence(npcId); + + // Check scene presence status + Assert.That(npc.HasAttachments(), Is.True); + List attachments = npc.GetAttachments(); + Assert.That(attachments.Count, Is.EqualTo(1)); + SceneObjectGroup attSo = attachments[0]; + + // Just for now, we won't test the name since this is (wrongly) the asset part name rather than the item + // name. TODO: Do need to fix ultimately since the item may be renamed before being passed on to an NPC. +// Assert.That(attSo.Name, Is.EqualTo(attName)); + + Assert.That(attSo.AttachmentPoint, Is.EqualTo((byte)AttachmentPoint.Chest)); + Assert.That(attSo.IsAttachment); + Assert.That(attSo.UsesPhysics, Is.False); + Assert.That(attSo.IsTemporary, Is.False); + Assert.That(attSo.OwnerID, Is.EqualTo(npc.UUID)); + } + + [Test] + public void TestMove() + { + TestHelpers.InMethod(); +// TestHelpers.EnableLogging(); + + SetUpScene(); + + ScenePresence sp = SceneHelpers.AddScenePresence(m_scene, TestHelpers.ParseTail(0x1)); +// ScenePresence originalAvatar = scene.GetScenePresence(originalClient.AgentId); + + Vector3 startPos = new Vector3(128, 128, 30); + UUID npcId = m_npcMod.CreateNPC("John", "Smith", startPos, UUID.Zero, true, m_scene, sp.Appearance); + + ScenePresence npc = m_scene.GetScenePresence(npcId); + Assert.That(npc.AbsolutePosition, Is.EqualTo(startPos)); + + // For now, we'll make the scene presence fly to simplify this test, but this needs to change. + npc.Flying = true; + + m_scene.Update(1); + Assert.That(npc.AbsolutePosition, Is.EqualTo(startPos)); + + Vector3 targetPos = startPos + new Vector3(0, 10, 0); + m_npcMod.MoveToTarget(npc.UUID, m_scene, targetPos, false, false, false); + + Assert.That(npc.AbsolutePosition, Is.EqualTo(startPos)); + //Assert.That(npc.Rotation, Is.EqualTo(new Quaternion(0, 0, 0.7071068f, 0.7071068f))); + Assert.That( + npc.Rotation, new QuaternionToleranceConstraint(new Quaternion(0, 0, 0.7071068f, 0.7071068f), 0.000001)); + + m_scene.Update(1); + + // We should really check the exact figure. + Assert.That(npc.AbsolutePosition.X, Is.EqualTo(startPos.X)); + Assert.That(npc.AbsolutePosition.Y, Is.GreaterThan(startPos.Y)); + Assert.That(npc.AbsolutePosition.Z, Is.EqualTo(startPos.Z)); + Assert.That(npc.AbsolutePosition.Z, Is.LessThan(targetPos.X)); + + m_scene.Update(10); + + double distanceToTarget = Util.GetDistanceTo(npc.AbsolutePosition, targetPos); + Assert.That(distanceToTarget, Is.LessThan(1), "NPC not within 1 unit of target position on first move"); + Assert.That(npc.AbsolutePosition, Is.EqualTo(targetPos)); + Assert.That(npc.AgentControlFlags, Is.EqualTo((uint)AgentManager.ControlFlags.NONE)); + + // Try a second movement + startPos = npc.AbsolutePosition; + targetPos = startPos + new Vector3(10, 0, 0); + m_npcMod.MoveToTarget(npc.UUID, m_scene, targetPos, false, false, false); + + Assert.That(npc.AbsolutePosition, Is.EqualTo(startPos)); +// Assert.That(npc.Rotation, Is.EqualTo(new Quaternion(0, 0, 0, 1))); + Assert.That( + npc.Rotation, new QuaternionToleranceConstraint(new Quaternion(0, 0, 0, 1), 0.000001)); + + m_scene.Update(1); + + // We should really check the exact figure. + Assert.That(npc.AbsolutePosition.X, Is.GreaterThan(startPos.X)); + Assert.That(npc.AbsolutePosition.X, Is.LessThan(targetPos.X)); + Assert.That(npc.AbsolutePosition.Y, Is.EqualTo(startPos.Y)); + Assert.That(npc.AbsolutePosition.Z, Is.EqualTo(startPos.Z)); + + m_scene.Update(10); + + distanceToTarget = Util.GetDistanceTo(npc.AbsolutePosition, targetPos); + Assert.That(distanceToTarget, Is.LessThan(1), "NPC not within 1 unit of target position on second move"); + Assert.That(npc.AbsolutePosition, Is.EqualTo(targetPos)); + } + + [Test] + public void TestMoveInVarRegion() + { + TestHelpers.InMethod(); +// TestHelpers.EnableLogging(); + + SetUpScene(512, 512); + + ScenePresence sp = SceneHelpers.AddScenePresence(m_scene, TestHelpers.ParseTail(0x1)); +// ScenePresence originalAvatar = scene.GetScenePresence(originalClient.AgentId); + + Vector3 startPos = new Vector3(128, 246, 30); + UUID npcId = m_npcMod.CreateNPC("John", "Smith", startPos, UUID.Zero, true, m_scene, sp.Appearance); + + ScenePresence npc = m_scene.GetScenePresence(npcId); + Assert.That(npc.AbsolutePosition, Is.EqualTo(startPos)); + + // For now, we'll make the scene presence fly to simplify this test, but this needs to change. + npc.Flying = true; + + m_scene.Update(1); + Assert.That(npc.AbsolutePosition, Is.EqualTo(startPos)); + + Vector3 targetPos = startPos + new Vector3(0, 20, 0); + m_npcMod.MoveToTarget(npc.UUID, m_scene, targetPos, false, false, false); + + Assert.That(npc.AbsolutePosition, Is.EqualTo(startPos)); + //Assert.That(npc.Rotation, Is.EqualTo(new Quaternion(0, 0, 0.7071068f, 0.7071068f))); + Assert.That( + npc.Rotation, new QuaternionToleranceConstraint(new Quaternion(0, 0, 0.7071068f, 0.7071068f), 0.000001)); + + m_scene.Update(1); + + // We should really check the exact figure. + Assert.That(npc.AbsolutePosition.X, Is.EqualTo(startPos.X)); + Assert.That(npc.AbsolutePosition.Y, Is.GreaterThan(startPos.Y)); + Assert.That(npc.AbsolutePosition.Z, Is.EqualTo(startPos.Z)); + Assert.That(npc.AbsolutePosition.Z, Is.LessThan(targetPos.X)); + + for (int i = 0; i < 20; i++) + { + m_scene.Update(1); +// Console.WriteLine("pos: {0}", npc.AbsolutePosition); + } + + double distanceToTarget = Util.GetDistanceTo(npc.AbsolutePosition, targetPos); + Assert.That(distanceToTarget, Is.LessThan(1), "NPC not within 1 unit of target position on first move"); + Assert.That(npc.AbsolutePosition, Is.EqualTo(targetPos)); + Assert.That(npc.AgentControlFlags, Is.EqualTo((uint)AgentManager.ControlFlags.NONE)); + } + + [Test] + public void TestSitAndStandWithSitTarget() + { + TestHelpers.InMethod(); +// log4net.Config.XmlConfigurator.Configure(); + + SetUpScene(); + + ScenePresence sp = SceneHelpers.AddScenePresence(m_scene, TestHelpers.ParseTail(0x1)); + + Vector3 startPos = new Vector3(128, 128, 30); + UUID npcId = m_npcMod.CreateNPC("John", "Smith", startPos, UUID.Zero, true, m_scene, sp.Appearance); + + ScenePresence npc = m_scene.GetScenePresence(npcId); + SceneObjectPart part = SceneHelpers.AddSceneObject(m_scene).RootPart; + + part.SitTargetPosition = new Vector3(0, 0, 1); + m_npcMod.Sit(npc.UUID, part.UUID, m_scene); + + Assert.That(part.SitTargetAvatar, Is.EqualTo(npcId)); + Assert.That(npc.ParentID, Is.EqualTo(part.LocalId)); +// Assert.That( +// npc.AbsolutePosition, +// Is.EqualTo(part.AbsolutePosition + part.SitTargetPosition + ScenePresence.SIT_TARGET_ADJUSTMENT)); + + m_npcMod.Stand(npc.UUID, m_scene); + + Assert.That(part.SitTargetAvatar, Is.EqualTo(UUID.Zero)); + Assert.That(npc.ParentID, Is.EqualTo(0)); + } + + [Test] + public void TestSitAndStandWithNoSitTarget() + { + TestHelpers.InMethod(); +// TestHelpers.EnableLogging(); + + SetUpScene(); + + ScenePresence sp = SceneHelpers.AddScenePresence(m_scene, TestHelpers.ParseTail(0x1)); + + // FIXME: To get this to work for now, we are going to place the npc right next to the target so that + // the autopilot doesn't trigger + Vector3 startPos = new Vector3(1, 1, 1); + + UUID npcId = m_npcMod.CreateNPC("John", "Smith", startPos, UUID.Zero, true, m_scene, sp.Appearance); + + ScenePresence npc = m_scene.GetScenePresence(npcId); + SceneObjectPart part = SceneHelpers.AddSceneObject(m_scene).RootPart; + + m_npcMod.Sit(npc.UUID, part.UUID, m_scene); + + Assert.That(part.SitTargetAvatar, Is.EqualTo(UUID.Zero)); + Assert.That(npc.ParentID, Is.EqualTo(part.LocalId)); + + // We should really be using the NPC size but this would mean preserving the physics actor since it is + // removed on sit. + Assert.That( + npc.AbsolutePosition, + Is.EqualTo(part.AbsolutePosition + new Vector3(0, 0, sp.PhysicsActor.Size.Z / 2))); + + m_npcMod.Stand(npc.UUID, m_scene); + + Assert.That(part.SitTargetAvatar, Is.EqualTo(UUID.Zero)); + Assert.That(npc.ParentID, Is.EqualTo(0)); + } + } +} diff --git a/Tests/OpenSim.Region.PhysicsModule.Ode.Tests/OpenSim.Region.PhysicsModule.Ode.Tests.csproj b/Tests/OpenSim.Region.PhysicsModule.Ode.Tests/OpenSim.Region.PhysicsModule.Ode.Tests.csproj new file mode 100644 index 00000000000..00263b3409d --- /dev/null +++ b/Tests/OpenSim.Region.PhysicsModule.Ode.Tests/OpenSim.Region.PhysicsModule.Ode.Tests.csproj @@ -0,0 +1,29 @@ + + + net6.0 + + + + + + + + + + ..\..\..\..\..\bin\Nini.dll + False + + + ..\..\..\..\..\bin\OpenMetaverseTypes.dll + False + + + + + + + + + + + \ No newline at end of file diff --git a/Tests/OpenSim.Region.PhysicsModules.BulletS.Tests/BasicVehicles.cs b/Tests/OpenSim.Region.PhysicsModules.BulletS.Tests/BasicVehicles.cs new file mode 100644 index 00000000000..1df209e885a --- /dev/null +++ b/Tests/OpenSim.Region.PhysicsModules.BulletS.Tests/BasicVehicles.cs @@ -0,0 +1,152 @@ +/* + * 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.Collections.Generic; + +using NUnit.Framework; + +using OpenSim.Framework; +using OpenSim.Region.PhysicsModule.BulletS; +using OpenSim.Region.PhysicsModules.SharedBase; +using OpenSim.Tests.Common; + +using OpenMetaverse; + +namespace OpenSim.Region.PhysicsModule.BulletS.Tests +{ + [TestFixture] + public class BasicVehicles : OpenSimTestCase + { + // Documentation on attributes: http://www.nunit.org/index.php?p=attributes&r=2.6.1 + // Documentation on assertions: http://www.nunit.org/index.php?p=assertions&r=2.6.1 + + BSScene PhysicsScene { get; set; } + BSPrim TestVehicle { get; set; } + Vector3 TestVehicleInitPosition { get; set; } + float simulationTimeStep = 0.089f; + + [OneTimeSetUp] + public void Init() + { + Dictionary engineParams = new Dictionary(); + engineParams.Add("VehicleEnableAngularVerticalAttraction", "true"); + engineParams.Add("VehicleAngularVerticalAttractionAlgorithm", "1"); + PhysicsScene = BulletSimTestsUtil.CreateBasicPhysicsEngine(engineParams); + + PrimitiveBaseShape pbs = PrimitiveBaseShape.CreateSphere(); + Vector3 pos = new Vector3(100.0f, 100.0f, 0f); + pos.Z = PhysicsScene.TerrainManager.GetTerrainHeightAtXYZ(pos) + 2f; + TestVehicleInitPosition = pos; + Vector3 size = new Vector3(1f, 1f, 1f); + pbs.Scale = size; + Quaternion rot = Quaternion.Identity; + bool isPhys = false; + uint localID = 123; + + PhysicsScene.AddPrimShape("testPrim", pbs, pos, size, rot, isPhys, localID); + TestVehicle = (BSPrim)PhysicsScene.PhysObjects[localID]; + // The actual prim shape creation happens at taint time + PhysicsScene.ProcessTaints(); + + } + + [OneTimeTearDown] + public void TearDown() + { + if (PhysicsScene != null) + { + // The Dispose() will also free any physical objects in the scene + PhysicsScene.Dispose(); + PhysicsScene = null; + } + } + + [TestCase(2f, 0.2f, 0.25f, 0.25f, 0.25f)] + [TestCase(2f, 0.2f, -0.25f, 0.25f, 0.25f)] + [TestCase(2f, 0.2f, 0.25f, -0.25f, 0.25f)] + [TestCase(2f, 0.2f, -0.25f, -0.25f, 0.25f)] + // [TestCase(2f, 0.2f, 0.785f, 0.0f, 0.25f) /*, "Leaning 45 degrees to the side" */] + // [TestCase(2f, 0.2f, 1.650f, 0.0f, 0.25f) /*, "Leaning more than 90 degrees to the side" */] + // [TestCase(2f, 0.2f, 2.750f, 0.0f, 0.25f) /*, "Almost upside down, tipped right" */] + // [TestCase(2f, 0.2f,-2.750f, 0.0f, 0.25f) /*, "Almost upside down, tipped left" */] + // [TestCase(2f, 0.2f, 0.0f, 0.785f, 0.25f) /*, "Tipped back 45 degrees" */] + // [TestCase(2f, 0.2f, 0.0f, 1.650f, 0.25f) /*, "Tipped back more than 90 degrees" */] + // [TestCase(2f, 0.2f, 0.0f, 2.750f, 0.25f) /*, "Almost upside down, tipped back" */] + // [TestCase(2f, 0.2f, 0.0f,-2.750f, 0.25f) /*, "Almost upside down, tipped forward" */] + public void AngularVerticalAttraction(float timeScale, float efficiency, float initRoll, float initPitch, float initYaw) + { + // Enough simulation steps to cover the timescale the operation should take + int simSteps = (int)(timeScale / simulationTimeStep) + 1; + + // Tip the vehicle + Quaternion initOrientation = Quaternion.CreateFromEulers(initRoll, initPitch, initYaw); + TestVehicle.Orientation = initOrientation; + + TestVehicle.Position = TestVehicleInitPosition; + + // The vehicle controller is not enabled directly (by setting a vehicle type). + // Instead the appropriate values are set and calls are made just the parts of the + // controller we want to exercise. Stepping the physics engine then applies + // the actions of that one feature. + BSDynamics vehicleActor = TestVehicle.GetVehicleActor(true /* createIfNone */); + if (vehicleActor != null) + { + vehicleActor.ProcessFloatVehicleParam(Vehicle.VERTICAL_ATTRACTION_EFFICIENCY, efficiency); + vehicleActor.ProcessFloatVehicleParam(Vehicle.VERTICAL_ATTRACTION_TIMESCALE, timeScale); + // vehicleActor.enableAngularVerticalAttraction = true; + + TestVehicle.IsPhysical = true; + PhysicsScene.ProcessTaints(); + + // Step the simulator a bunch of times and vertical attraction should orient the vehicle up + for (int ii = 0; ii < simSteps; ii++) + { + vehicleActor.ForgetKnownVehicleProperties(); + vehicleActor.ComputeAngularVerticalAttraction(); + vehicleActor.PushKnownChanged(); + + PhysicsScene.Simulate(simulationTimeStep); + } + } + + TestVehicle.IsPhysical = false; + PhysicsScene.ProcessTaints(); + + // After these steps, the vehicle should be upright + /* + float finalRoll, finalPitch, finalYaw; + TestVehicle.Orientation.GetEulerAngles(out finalRoll, out finalPitch, out finalYaw); + Assert.That(finalRoll, Is.InRange(-0.01f, 0.01f)); + Assert.That(finalPitch, Is.InRange(-0.01f, 0.01f)); + Assert.That(finalYaw, Is.InRange(initYaw - 0.1f, initYaw + 0.1f)); + */ + + Vector3 upPointer = Vector3.UnitZ * TestVehicle.Orientation; + Assert.That(upPointer.Z, Is.GreaterThan(0.99f)); + } + } +} \ No newline at end of file diff --git a/Tests/OpenSim.Region.PhysicsModules.BulletS.Tests/BulletSimTests.cs b/Tests/OpenSim.Region.PhysicsModules.BulletS.Tests/BulletSimTests.cs new file mode 100644 index 00000000000..95e53a62858 --- /dev/null +++ b/Tests/OpenSim.Region.PhysicsModules.BulletS.Tests/BulletSimTests.cs @@ -0,0 +1,50 @@ +/* + * 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 NUnit.Framework; + +using OpenSim.Tests.Common; + +namespace OpenSim.Region.PhysicsModule.BulletS.Tests +{ + [TestFixture] + public class BulletSimTests : OpenSimTestCase + { + // Documentation on attributes: http://www.nunit.org/index.php?p=attributes&r=2.6.1 + // Documentation on assertions: http://www.nunit.org/index.php?p=assertions&r=2.6.1 + + [OneTimeSetUp] + public void Init() + { + } + + [OneTimeTearDown] + public void TearDown() + { + } + } +} diff --git a/Tests/OpenSim.Region.PhysicsModules.BulletS.Tests/BulletSimTestsUtil.cs b/Tests/OpenSim.Region.PhysicsModules.BulletS.Tests/BulletSimTestsUtil.cs new file mode 100644 index 00000000000..57abc7fd208 --- /dev/null +++ b/Tests/OpenSim.Region.PhysicsModules.BulletS.Tests/BulletSimTestsUtil.cs @@ -0,0 +1,111 @@ +/* + * 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.IO; +using System.Collections.Generic; +using System.Text; + +using Nini.Config; + +using OpenSim.Framework; +using OpenSim.Region; +using OpenSim.Region.PhysicsModules.SharedBase; +using OpenSim.Region.PhysicsModule.Meshing; +using OpenSim.Region.Framework.Interfaces; + +using OpenMetaverse; +using OpenSim.Region.Framework.Scenes; + +namespace OpenSim.Region.PhysicsModule.BulletS.Tests +{ + // Utility functions for building up and tearing down the sample physics environments + public static class BulletSimTestsUtil + { + // 'engineName' is the Bullet engine to use. Either null (for unmanaged), "BulletUnmanaged" or "BulletXNA" + // 'params' is a set of keyValue pairs to set in the engine's configuration file (override defaults) + // May be 'null' if there are no overrides. + public static BSScene CreateBasicPhysicsEngine(Dictionary paramOverrides) + { + IConfigSource openSimINI = new IniConfigSource(); + IConfig startupConfig = openSimINI.AddConfig("Startup"); + startupConfig.Set("physics", "BulletSim"); + startupConfig.Set("meshing", "Meshmerizer"); + startupConfig.Set("cacheSculptMaps", "false"); // meshmerizer shouldn't save maps + + IConfig bulletSimConfig = openSimINI.AddConfig("BulletSim"); + // If the caller cares, specify the bullet engine otherwise it will default to "BulletUnmanaged". + // bulletSimConfig.Set("BulletEngine", "BulletUnmanaged"); + // bulletSimConfig.Set("BulletEngine", "BulletXNA"); + bulletSimConfig.Set("MeshSculptedPrim", "false"); + bulletSimConfig.Set("ForceSimplePrimMeshing", "true"); + if (paramOverrides != null) + { + foreach (KeyValuePair kvp in paramOverrides) + { + bulletSimConfig.Set(kvp.Key, kvp.Value); + } + } + + // If a special directory exists, put detailed logging therein. + // This allows local testing/debugging without having to worry that the build engine will output logs. + if (Directory.Exists("physlogs")) + { + bulletSimConfig.Set("PhysicsLoggingDir", "./physlogs"); + bulletSimConfig.Set("PhysicsLoggingEnabled", "True"); + bulletSimConfig.Set("PhysicsLoggingDoFlush", "True"); + bulletSimConfig.Set("VehicleLoggingEnabled", "True"); + } + + Vector3 regionExtent = new Vector3(Constants.RegionSize, Constants.RegionSize, Constants.RegionHeight); + + RegionInfo info = new RegionInfo(); + info.RegionName = "BSTestRegion"; + info.RegionSizeX = info.RegionSizeY = info.RegionSizeZ = Constants.RegionSize; + Scene scene = new Scene(info); + + IMesher mesher = new Meshmerizer(); + INonSharedRegionModule mod = mesher as INonSharedRegionModule; + mod.Initialise(openSimINI); + mod.AddRegion(scene); + mod.RegionLoaded(scene); + + BSScene pScene = new BSScene(); + mod = (pScene as INonSharedRegionModule); + mod.Initialise(openSimINI); + mod.AddRegion(scene); + mod.RegionLoaded(scene); + + // Since the asset requestor is not initialized, any mesh or sculptie will be a cube. + // In the future, add a fake asset fetcher to get meshes and sculpts. + // bsScene.RequestAssetMethod = ???; + + return pScene; + } + + } +} diff --git a/Tests/OpenSim.Region.PhysicsModules.BulletS.Tests/HullCreation.cs b/Tests/OpenSim.Region.PhysicsModules.BulletS.Tests/HullCreation.cs new file mode 100644 index 00000000000..83c53ad3b54 --- /dev/null +++ b/Tests/OpenSim.Region.PhysicsModules.BulletS.Tests/HullCreation.cs @@ -0,0 +1,205 @@ +/* + * 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 System.Linq; +using System.Text; + +using NUnit.Framework; +using log4net; + +using OpenSim.Framework; +using OpenSim.Region.PhysicsModule.BulletS; +using OpenSim.Region.PhysicsModules.SharedBase; +using OpenSim.Tests.Common; + +using OpenMetaverse; + +namespace OpenSim.Region.PhysicsModule.BulletS.Tests +{ + [TestFixture] + public class HullCreation : OpenSimTestCase + { + // Documentation on attributes: http://www.nunit.org/index.php?p=attributes&r=2.6.1 + // Documentation on assertions: http://www.nunit.org/index.php?p=assertions&r=2.6.1 + + BSScene PhysicsScene { get; set; } + Vector3 ObjectInitPosition; + + [OneTimeSetUp] + public void Init() + { + + } + + [OneTimeTearDown] + public void TearDown() + { + if (PhysicsScene != null) + { + // The Dispose() will also free any physical objects in the scene + PhysicsScene.Dispose(); + PhysicsScene = null; + } + } + + [TestCase(7, 2, 5f, 5f, 32, 0f)] /* default hull parameters */ + public void GeomHullConvexDecomp(int maxDepthSplit, + int maxDepthSplitForSimpleShapes, + float concavityThresholdPercent, + float volumeConservationThresholdPercent, + int maxVertices, + float maxSkinWidth) + { + // Setup the physics engine to use the C# version of convex decomp + Dictionary engineParams = new Dictionary(); + engineParams.Add("MeshSculptedPrim", "true"); // ShouldMeshSculptedPrim + engineParams.Add("ForceSimplePrimMeshing", "false"); // ShouldForceSimplePrimMeshing + engineParams.Add("UseHullsForPhysicalObjects", "true"); // ShouldUseHullsForPhysicalObjects + engineParams.Add("ShouldRemoveZeroWidthTriangles", "true"); + engineParams.Add("ShouldUseBulletHACD", "false"); + engineParams.Add("ShouldUseSingleConvexHullForPrims", "true"); + engineParams.Add("ShouldUseGImpactShapeForPrims", "false"); + engineParams.Add("ShouldUseAssetHulls", "true"); + + engineParams.Add("CSHullMaxDepthSplit", maxDepthSplit.ToString()); + engineParams.Add("CSHullMaxDepthSplitForSimpleShapes", maxDepthSplitForSimpleShapes.ToString()); + engineParams.Add("CSHullConcavityThresholdPercent", concavityThresholdPercent.ToString()); + engineParams.Add("CSHullVolumeConservationThresholdPercent", volumeConservationThresholdPercent.ToString()); + engineParams.Add("CSHullMaxVertices", maxVertices.ToString()); + engineParams.Add("CSHullMaxSkinWidth", maxSkinWidth.ToString()); + + PhysicsScene = BulletSimTestsUtil.CreateBasicPhysicsEngine(engineParams); + + PrimitiveBaseShape pbs; + Vector3 pos; + Vector3 size; + Quaternion rot; + bool isPhys; + + // Cylinder + pbs = PrimitiveBaseShape.CreateCylinder(); + pos = new Vector3(100.0f, 100.0f, 0f); + pos.Z = PhysicsScene.TerrainManager.GetTerrainHeightAtXYZ(pos) + 10f; + ObjectInitPosition = pos; + size = new Vector3(2f, 2f, 2f); + pbs.Scale = size; + rot = Quaternion.Identity; + isPhys = true; + uint cylinderLocalID = 123; + PhysicsScene.AddPrimShape("testCylinder", pbs, pos, size, rot, isPhys, cylinderLocalID); + BSPrim primTypeCylinder = (BSPrim)PhysicsScene.PhysObjects[cylinderLocalID]; + + // Hollow Cylinder + pbs = PrimitiveBaseShape.CreateCylinder(); + pbs.ProfileHollow = (ushort)(0.70f * 50000); + pos = new Vector3(110.0f, 110.0f, 0f); + pos.Z = PhysicsScene.TerrainManager.GetTerrainHeightAtXYZ(pos) + 10f; + ObjectInitPosition = pos; + size = new Vector3(2f, 2f, 2f); + pbs.Scale = size; + rot = Quaternion.Identity; + isPhys = true; + uint hollowCylinderLocalID = 124; + PhysicsScene.AddPrimShape("testHollowCylinder", pbs, pos, size, rot, isPhys, hollowCylinderLocalID); + BSPrim primTypeHollowCylinder = (BSPrim)PhysicsScene.PhysObjects[hollowCylinderLocalID]; + + // Torus + // ProfileCurve = Circle, PathCurve = Curve1 + pbs = PrimitiveBaseShape.CreateSphere(); + pbs.ProfileShape = (byte)ProfileShape.Circle; + pbs.PathCurve = (byte)Extrusion.Curve1; + pbs.PathScaleX = 100; // default hollow info as set in the viewer + pbs.PathScaleY = (int)(.25f / 0.01f) + 200; + pos = new Vector3(120.0f, 120.0f, 0f); + pos.Z = PhysicsScene.TerrainManager.GetTerrainHeightAtXYZ(pos) + 10f; + ObjectInitPosition = pos; + size = new Vector3(2f, 4f, 4f); + pbs.Scale = size; + rot = Quaternion.Identity; + isPhys = true; + uint torusLocalID = 125; + PhysicsScene.AddPrimShape("testTorus", pbs, pos, size, rot, isPhys, torusLocalID); + BSPrim primTypeTorus = (BSPrim)PhysicsScene.PhysObjects[torusLocalID]; + + // The actual prim shape creation happens at taint time + PhysicsScene.ProcessTaints(); + + // Check out the created hull shapes and report their characteristics + ReportShapeGeom(primTypeCylinder); + ReportShapeGeom(primTypeHollowCylinder); + ReportShapeGeom(primTypeTorus); + } + + [TestCase] + public void GeomHullBulletHACD() + { + // Cylinder + // Hollow Cylinder + // Torus + } + + private void ReportShapeGeom(BSPrim prim) + { + if (prim != null) + { + if (prim.PhysShape.HasPhysicalShape) + { + BSShape physShape = prim.PhysShape; + string shapeType = physShape.GetType().ToString(); + switch (shapeType) + { + case "OpenSim.Region.Physics.BulletSPlugin.BSShapeNative": + BSShapeNative nShape = physShape as BSShapeNative; + prim.PhysScene.DetailLog("{0}, type={1}", prim.Name, shapeType); + break; + case "OpenSim.Region.Physics.BulletSPlugin.BSShapeMesh": + BSShapeMesh mShape = physShape as BSShapeMesh; + prim.PhysScene.DetailLog("{0}, mesh, shapeInfo={1}", prim.Name, mShape.shapeInfo); + break; + case "OpenSim.Region.Physics.BulletSPlugin.BSShapeHull": + // BSShapeHull hShape = physShape as BSShapeHull; + // prim.PhysScene.DetailLog("{0}, hull, shapeInfo={1}", prim.Name, hShape.shapeInfo); + break; + case "OpenSim.Region.Physics.BulletSPlugin.BSShapeConvexHull": + BSShapeConvexHull chShape = physShape as BSShapeConvexHull; + prim.PhysScene.DetailLog("{0}, convexHull, shapeInfo={1}", prim.Name, chShape.shapeInfo); + break; + case "OpenSim.Region.Physics.BulletSPlugin.BSShapeCompound": + BSShapeCompound cShape = physShape as BSShapeCompound; + prim.PhysScene.DetailLog("{0}, type={1}", prim.Name, shapeType); + break; + default: + prim.PhysScene.DetailLog("{0}, type={1}", prim.Name, shapeType); + break; + } + } + } + } + } +} \ No newline at end of file diff --git a/Tests/OpenSim.Region.PhysicsModules.BulletS.Tests/OpenSim.Region.PhysicsModule.BulletS.Tests.csproj b/Tests/OpenSim.Region.PhysicsModules.BulletS.Tests/OpenSim.Region.PhysicsModule.BulletS.Tests.csproj new file mode 100644 index 00000000000..901e2ed5464 --- /dev/null +++ b/Tests/OpenSim.Region.PhysicsModules.BulletS.Tests/OpenSim.Region.PhysicsModule.BulletS.Tests.csproj @@ -0,0 +1,33 @@ + + + net6.0 + + + + + + + + + + ..\..\..\..\..\bin\Nini.dll + False + + + ..\..\..\..\..\bin\OpenMetaverse.dll + False + + + ..\..\..\..\..\bin\OpenMetaverseTypes.dll + False + + + + + + + + + + + \ No newline at end of file diff --git a/Tests/OpenSim.Region.PhysicsModules.BulletS.Tests/Raycast.cs b/Tests/OpenSim.Region.PhysicsModules.BulletS.Tests/Raycast.cs new file mode 100644 index 00000000000..4ba22244510 --- /dev/null +++ b/Tests/OpenSim.Region.PhysicsModules.BulletS.Tests/Raycast.cs @@ -0,0 +1,126 @@ +/* + * 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 System.Linq; +using System.Text; + +using NUnit.Framework; +using log4net; + +using OpenSim.Framework; +using OpenSim.Region.PhysicsModule.BulletS; +using OpenSim.Region.PhysicsModules.SharedBase; +using OpenSim.Tests.Common; + +using OpenMetaverse; + +namespace OpenSim.Region.PhysicsModule.BulletS.Tests +{ + [TestFixture] + public class BulletSimRaycast : OpenSimTestCase + { + // Documentation on attributes: http://www.nunit.org/index.php?p=attributes&r=2.6.1 + // Documentation on assertions: http://www.nunit.org/index.php?p=assertions&r=2.6.1 + + BSScene _physicsScene { get; set; } + BSPrim _targetSphere { get; set; } + Vector3 _targetSpherePosition { get; set; } + // float _simulationTimeStep = 0.089f; + + uint _targetLocalID = 123; + + [OneTimeSetUp] + public void Init() + { + Dictionary engineParams = new Dictionary(); + engineParams.Add("UseBulletRaycast", "true"); + _physicsScene = BulletSimTestsUtil.CreateBasicPhysicsEngine(engineParams); + + PrimitiveBaseShape pbs = PrimitiveBaseShape.CreateSphere(); + Vector3 pos = new Vector3(100.0f, 100.0f, 50f); + _targetSpherePosition = pos; + Vector3 size = new Vector3(10f, 10f, 10f); + pbs.Scale = size; + Quaternion rot = Quaternion.Identity; + bool isPhys = false; + + _physicsScene.AddPrimShape("TargetSphere", pbs, pos, size, rot, isPhys, _targetLocalID); + _targetSphere = (BSPrim)_physicsScene.PhysObjects[_targetLocalID]; + // The actual prim shape creation happens at taint time + _physicsScene.ProcessTaints(); + + } + + [OneTimeTearDown] + public void TearDown() + { + if (_physicsScene != null) + { + // The Dispose() will also free any physical objects in the scene + _physicsScene.Dispose(); + _physicsScene = null; + } + } + + // There is a 10x10x10 sphere at <100,100,50> + // Shoot rays around the sphere and verify it hits and doesn't hit + // TestCase parameters are of start and of end and expected result + [TestCase(100f, 50f, 50f, 100f, 150f, 50f, true, "Pass through sphere from front")] + [TestCase(50f, 100f, 50f, 150f, 100f, 50f, true, "Pass through sphere from side")] + [TestCase(50f, 50f, 50f, 150f, 150f, 50f, true, "Pass through sphere diaginally")] + [TestCase(100f, 100f, 100f, 100f, 100f, 20f, true, "Pass through sphere from above")] + [TestCase(20f, 20f, 50f, 80f, 80f, 50f, false, "Not reach sphere")] + [TestCase(50f, 50f, 65f, 150f, 150f, 65f, false, "Passed over sphere")] + public void RaycastAroundObject(float fromX, float fromY, float fromZ, float toX, float toY, float toZ, bool expected, string msg) + { + Vector3 fromPos = new Vector3(fromX, fromY, fromZ); + Vector3 toPos = new Vector3(toX, toY, toZ); + Vector3 direction = toPos - fromPos; + float len = Vector3.Distance(fromPos, toPos); + + List results = _physicsScene.RaycastWorld(fromPos, direction, len, 1); + + if (expected) + { + // The test coordinates should generate a hit + Assert.True(results.Count != 0, msg + ": Did not return a hit but expected to."); + Assert.True(results.Count == 1, msg + ": Raycast returned not just one hit result."); + Assert.True(results[0].ConsumerID == _targetLocalID, msg + ": Raycast returned a collision object other than the target"); + } + else + { + // The test coordinates should not generate a hit + if (results.Count > 0) + { + Assert.False(results.Count > 0, msg + ": Returned a hit at " + results[0].Pos.ToString()); + } + } + } + } +} \ No newline at end of file diff --git a/Tests/OpenSim.Region.ScriptEngine.Tests/OpenSim.Region.ScriptEngine.Tests.csproj b/Tests/OpenSim.Region.ScriptEngine.Tests/OpenSim.Region.ScriptEngine.Tests.csproj new file mode 100644 index 00000000000..e247e43a7d0 --- /dev/null +++ b/Tests/OpenSim.Region.ScriptEngine.Tests/OpenSim.Region.ScriptEngine.Tests.csproj @@ -0,0 +1,148 @@ + + + net6.0 + + + + ..\..\..\bin\Nini.dll + False + + + ..\..\..\bin\OpenMetaverse.dll + False + + + ..\..\..\bin\OpenMetaverse.StructuredData.dll + False + + + ..\..\..\bin\OpenMetaverseTypes.dll + False + + + ..\..\..\bin\Tools.dll + False + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Tests/OpenSim.Region.ScriptEngine.Tests/Shared/Tests/LSL_ApiAvatarTests.cs b/Tests/OpenSim.Region.ScriptEngine.Tests/Shared/Tests/LSL_ApiAvatarTests.cs new file mode 100644 index 00000000000..a500f10c6c4 --- /dev/null +++ b/Tests/OpenSim.Region.ScriptEngine.Tests/Shared/Tests/LSL_ApiAvatarTests.cs @@ -0,0 +1,165 @@ +/* + * 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 System.Reflection; +using System.Text; +using log4net; +using Nini.Config; +using NUnit.Framework; +using OpenMetaverse; +using OpenMetaverse.Assets; +using OpenMetaverse.StructuredData; +using OpenSim.Framework; +using OpenSim.Region.CoreModules.Avatar.AvatarFactory; +using OpenSim.Region.OptionalModules.World.NPC; +using OpenSim.Region.Framework.Scenes; +using OpenSim.Region.ScriptEngine.Shared; +using OpenSim.Region.ScriptEngine.Shared.Api; +using OpenSim.Region.ScriptEngine.Shared.ScriptBase; +using OpenSim.Services.Interfaces; +using OpenSim.Tests.Common; +using LSL_Integer = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLInteger; +using LSL_List = OpenSim.Region.ScriptEngine.Shared.LSL_Types.list; + +namespace OpenSim.Region.ScriptEngine.Shared.Tests +{ + /// + /// Tests relating directly to avatars + /// + [TestFixture] + public class LSL_ApiAvatarTests : OpenSimTestCase + { + /* + protected Scene m_scene; + + [SetUp] + public override void SetUp() + { + base.SetUp(); + + IConfigSource initConfigSource = new IniConfigSource(); + IConfig config = initConfigSource.AddConfig("XEngine"); + config.Set("Enabled", "true"); + + config = initConfigSource.AddConfig("OSSL"); + config.Set("DebuggerSafe", false); + config.Set("AllowOSFunctions", "true"); + config.Set("OSFunctionThreatLevel", "Severe"); + + m_scene = new SceneHelpers().SetupScene(); + SceneHelpers.SetupSceneModules(m_scene, initConfigSource); + + m_engine = new YEngine.XEngine(); + m_engine.Initialise(initConfigSource); + m_engine.AddRegion(m_scene); + } + + /// + /// Test llSetLinkPrimtiveParams for agents. + /// + /// + /// Also testing entity updates here as well. Possibly that's putting 2 different concerns into one test and + /// this should be separated. + /// + [Test] + public void TestllSetLinkPrimitiveParamsForAgent() + { +/* siting avatars position changed + TestHelpers.InMethod(); +// TestHelpers.EnableLogging(); + + UUID userId = TestHelpers.ParseTail(0x1); + + SceneObjectPart part = SceneHelpers.AddSceneObject(m_scene).RootPart; + part.RotationOffset = new Quaternion(0.7071068f, 0, 0, 0.7071068f); + + LSL_Api apiGrp1 = new LSL_Api(); + apiGrp1.Initialize(m_engine, part, null); + + ScenePresence sp = SceneHelpers.AddScenePresence(m_scene, userId); + + // sp has to be less than 10 meters away from 0, 0, 0 (default part position) + Vector3 startPos = new Vector3(3, 2, 1); + sp.AbsolutePosition = startPos; + + sp.HandleAgentRequestSit(sp.ControllingClient, sp.UUID, part.UUID, Vector3.Zero); + + int entityUpdates = 0; + ((TestClient)sp.ControllingClient).OnReceivedEntityUpdate += (entity, flags) => { if (entity is ScenePresence) { entityUpdates++; }}; + + // Test position + { + Vector3 newPos = new Vector3(1, 2, 3); + apiGrp1.llSetLinkPrimitiveParams(2, new LSL_Types.list(ScriptBaseClass.PRIM_POSITION, newPos)); + + Assert.That(sp.OffsetPosition, Is.EqualTo(newPos)); + + m_scene.Update(1); + Assert.That(entityUpdates, Is.EqualTo(1)); + } + + // Test small reposition + { + Vector3 newPos = new Vector3(1.001f, 2, 3); + apiGrp1.llSetLinkPrimitiveParams(2, new LSL_Types.list(ScriptBaseClass.PRIM_POSITION, newPos)); + + Assert.That(sp.OffsetPosition, Is.EqualTo(newPos)); + + m_scene.Update(1); + Assert.That(entityUpdates, Is.EqualTo(2)); + } + + // Test world rotation + { + Quaternion newRot = new Quaternion(0, 0.7071068f, 0, 0.7071068f); + apiGrp1.llSetLinkPrimitiveParams(2, new LSL_Types.list(ScriptBaseClass.PRIM_ROTATION, newRot)); + + Assert.That( + sp.Rotation, new QuaternionToleranceConstraint(part.GetWorldRotation() * newRot, 0.000001)); + + m_scene.Update(1); + Assert.That(entityUpdates, Is.EqualTo(3)); + } + + // Test local rotation + { + Quaternion newRot = new Quaternion(0, 0.7071068f, 0, 0.7071068f); + apiGrp1.llSetLinkPrimitiveParams(2, new LSL_Types.list(ScriptBaseClass.PRIM_ROT_LOCAL, newRot)); + + Assert.That( + sp.Rotation, new QuaternionToleranceConstraint(newRot, 0.000001)); + + m_scene.Update(1); + Assert.That(entityUpdates, Is.EqualTo(4)); + } + + } + */ + } +} diff --git a/Tests/OpenSim.Region.ScriptEngine.Tests/Shared/Tests/LSL_ApiHttpTests.cs b/Tests/OpenSim.Region.ScriptEngine.Tests/Shared/Tests/LSL_ApiHttpTests.cs new file mode 100644 index 00000000000..7fa2bea0132 --- /dev/null +++ b/Tests/OpenSim.Region.ScriptEngine.Tests/Shared/Tests/LSL_ApiHttpTests.cs @@ -0,0 +1,253 @@ +/* + * 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 System.IO; +using System.Net; +using System.Reflection; +using System.Text; +using log4net; +using Nini.Config; +using NUnit.Framework; +using OpenMetaverse; +using OpenSim.Framework; +using OpenSim.Framework.Servers; +using OpenSim.Framework.Servers.HttpServer; +using OpenSim.Region.CoreModules.Scripting.LSLHttp; +using OpenSim.Region.Framework.Scenes; +using OpenSim.Region.ScriptEngine.Shared; +using OpenSim.Region.ScriptEngine.Shared.Api; +using OpenSim.Region.ScriptEngine.Shared.ScriptBase; +using OpenSim.Services.Interfaces; +using OpenSim.Tests.Common; + +namespace OpenSim.Region.ScriptEngine.Shared.Tests +{ + /// + /// Tests for HTTP related functions in LSL + /// + [TestFixture] + public class LSL_ApiHttpTests : OpenSimTestCase + { + private Scene m_scene; + private MockScriptEngine m_engine; + private UrlModule m_urlModule; + + private TaskInventoryItem m_scriptItem; + private LSL_Api m_lslApi; + + [OneTimeSetUp] + public void TestFixtureSetUp() + { + // Don't allow tests to be bamboozled by asynchronous events. Execute everything on the same thread. + Util.FireAndForgetMethod = FireAndForgetMethod.RegressionTest; + } + + [OneTimeTearDown] + public void TestFixureTearDown() + { + // 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; + } + + [SetUp] + public override void SetUp() + { + base.SetUp(); + + // This is an unfortunate bit of clean up we have to do because MainServer manages things through static + // variables and the VM is not restarted between tests. + uint port = 9999; + MainServer.RemoveHttpServer(port); + + m_engine = new MockScriptEngine(); + m_urlModule = new UrlModule(); + + IConfigSource config = new IniConfigSource(); + config.AddConfig("Network"); + config.Configs["Network"].Set("ExternalHostNameForLSL", "127.0.0.1"); + m_scene = new SceneHelpers().SetupScene(); + + BaseHttpServer server = new BaseHttpServer(port); + MainServer.AddHttpServer(server); + MainServer.Instance = server; + + server.Start(); + + SceneHelpers.SetupSceneModules(m_scene, config, m_engine, m_urlModule); + + SceneObjectGroup so = SceneHelpers.AddSceneObject(m_scene); + m_scriptItem = TaskInventoryHelpers.AddScript(m_scene.AssetService, so.RootPart); + + // This is disconnected from the actual script - the mock engine does not set up any LSL_Api atm. + // Possibly this could be done and we could obtain it directly from the MockScriptEngine. + m_lslApi = new LSL_Api(); + m_lslApi.Initialize(m_engine, so.RootPart, m_scriptItem); + } + + [TearDown] + public void TearDown() + { + MainServer.Instance.Stop(); + } + + [Test] + public void TestLlReleaseUrl() + { + TestHelpers.InMethod(); + + m_lslApi.llRequestURL(); + string returnedUri = m_engine.PostedEvents[m_scriptItem.ItemID][0].Params[2].ToString(); + + { + // Check that the initial number of URLs is correct + Assert.That(m_lslApi.llGetFreeURLs().value, Is.EqualTo(m_urlModule.TotalUrls - 1)); + } + + { + // Check releasing a non-url + m_lslApi.llReleaseURL("GARBAGE"); + Assert.That(m_lslApi.llGetFreeURLs().value, Is.EqualTo(m_urlModule.TotalUrls - 1)); + } + + { + // Check releasing a non-existing url + m_lslApi.llReleaseURL("http://example.com"); + Assert.That(m_lslApi.llGetFreeURLs().value, Is.EqualTo(m_urlModule.TotalUrls - 1)); + } + + { + // Check URL release + m_lslApi.llReleaseURL(returnedUri); + Assert.That(m_lslApi.llGetFreeURLs().value, Is.EqualTo(m_urlModule.TotalUrls)); + + HttpWebRequest webRequest = (HttpWebRequest)WebRequest.Create(returnedUri); + + bool gotExpectedException = false; + + try + { + using (HttpWebResponse webResponse = (HttpWebResponse)webRequest.GetResponse()) + {} + } + catch (WebException) + { +// using (HttpWebResponse response = (HttpWebResponse)e.Response) +// gotExpectedException = response.StatusCode == HttpStatusCode.NotFound; + gotExpectedException = true; + } + + Assert.That(gotExpectedException, Is.True); + } + + { + // Check releasing the same URL again + m_lslApi.llReleaseURL(returnedUri); + Assert.That(m_lslApi.llGetFreeURLs().value, Is.EqualTo(m_urlModule.TotalUrls)); + } + } + + [Test] + public void TestLlRequestUrl() + { + TestHelpers.InMethod(); + + string requestId = m_lslApi.llRequestURL(); + Assert.That(requestId, Is.Not.EqualTo(UUID.Zero.ToString())); + string returnedUri; + + { + // Check that URL is correctly set up + Assert.That(m_lslApi.llGetFreeURLs().value, Is.EqualTo(m_urlModule.TotalUrls - 1)); + + Assert.That(m_engine.PostedEvents.ContainsKey(m_scriptItem.ItemID)); + + List events = m_engine.PostedEvents[m_scriptItem.ItemID]; + Assert.That(events.Count, Is.EqualTo(1)); + EventParams eventParams = events[0]; + Assert.That(eventParams.EventName, Is.EqualTo("http_request")); + + UUID returnKey; + string rawReturnKey = eventParams.Params[0].ToString(); + string method = eventParams.Params[1].ToString(); + returnedUri = eventParams.Params[2].ToString(); + + Assert.That(UUID.TryParse(rawReturnKey, out returnKey), Is.True); + Assert.That(method, Is.EqualTo(ScriptBaseClass.URL_REQUEST_GRANTED)); + Assert.That(Uri.IsWellFormedUriString(returnedUri, UriKind.Absolute), Is.True); + } + + { + // Check that request to URL works. + string testResponse = "Hello World"; + + m_engine.ClearPostedEvents(); + m_engine.PostEventHook + += (itemId, evp) => m_lslApi.llHTTPResponse(evp.Params[0].ToString(), 200, testResponse); + +// Console.WriteLine("Trying {0}", returnedUri); + + AssertHttpResponse(returnedUri, testResponse); + + Assert.That(m_engine.PostedEvents.ContainsKey(m_scriptItem.ItemID)); + + List events = m_engine.PostedEvents[m_scriptItem.ItemID]; + Assert.That(events.Count, Is.EqualTo(1)); + EventParams eventParams = events[0]; + Assert.That(eventParams.EventName, Is.EqualTo("http_request")); + + UUID returnKey; + string rawReturnKey = eventParams.Params[0].ToString(); + string method = eventParams.Params[1].ToString(); + string body = eventParams.Params[2].ToString(); + + Assert.That(UUID.TryParse(rawReturnKey, out returnKey), Is.True); + Assert.That(method, Is.EqualTo("GET")); + Assert.That(body, Is.EqualTo("")); + } + } + + private void AssertHttpResponse(string uri, string expectedResponse) + { + HttpWebRequest webRequest = (HttpWebRequest)WebRequest.Create(uri); + + using (HttpWebResponse webResponse = (HttpWebResponse)webRequest.GetResponse()) + { + using (Stream stream = webResponse.GetResponseStream()) + { + using (StreamReader reader = new StreamReader(stream)) + { + Assert.That(reader.ReadToEnd(), Is.EqualTo(expectedResponse)); + } + } + } + } + } +} diff --git a/Tests/OpenSim.Region.ScriptEngine.Tests/Shared/Tests/LSL_ApiInventoryTests.cs b/Tests/OpenSim.Region.ScriptEngine.Tests/Shared/Tests/LSL_ApiInventoryTests.cs new file mode 100644 index 00000000000..cc5f721bf08 --- /dev/null +++ b/Tests/OpenSim.Region.ScriptEngine.Tests/Shared/Tests/LSL_ApiInventoryTests.cs @@ -0,0 +1,300 @@ +/* + * 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 System.Reflection; +using System.Text; +using log4net; +using Nini.Config; +using NUnit.Framework; +using OpenMetaverse; +using OpenMetaverse.Assets; +using OpenMetaverse.StructuredData; +using OpenSim.Framework; +using OpenSim.Region.CoreModules.Avatar.AvatarFactory; +using OpenSim.Region.OptionalModules.World.NPC; +using OpenSim.Region.Framework.Scenes; +using OpenSim.Region.CoreModules.World.Permissions; +using OpenSim.Region.ScriptEngine.Shared; +using OpenSim.Region.ScriptEngine.Shared.Api; +using OpenSim.Services.Interfaces; +using OpenSim.Tests.Common; +using PermissionMask = OpenSim.Framework.PermissionMask; + +namespace OpenSim.Region.ScriptEngine.Shared.Tests +{ + /// + /// Tests for inventory functions in LSL + /// + [TestFixture] + /* + public class LSL_ApiInventoryTests : OpenSimTestCase + { + protected Scene m_scene; + protected XEngine.XEngine m_engine; + + [SetUp] + public override void SetUp() + { + base.SetUp(); + + IConfigSource initConfigSource = new IniConfigSource(); + IConfig config = initConfigSource.AddConfig("Startup"); + config.Set("serverside_object_permissions", true); + config =initConfigSource.AddConfig("Permissions"); + config.Set("permissionmodules", "DefaultPermissionsModule"); + config.Set("serverside_object_permissions", true); + config.Set("propagate_permissions", true); + + config = initConfigSource.AddConfig("XEngine"); + config.Set("Enabled", "true"); + config = initConfigSource.AddConfig("OSSL"); + config.Set("DebuggerSafe", false); + config.Set("AllowOSFunctions", "true"); + config.Set("OSFunctionThreatLevel", "Severe"); + + m_scene = new SceneHelpers().SetupScene(); + SceneHelpers.SetupSceneModules(m_scene, initConfigSource, new object[] { new DefaultPermissionsModule() }); + m_engine = new XEngine.XEngine(); + m_engine.Initialise(initConfigSource); + m_engine.AddRegion(m_scene); + } + + /// + /// Test giving inventory from an object to an object where both are owned by the same user. + /// + [Test] + public void TestLlGiveInventoryO2OSameOwner() + { + TestHelpers.InMethod(); +// log4net.Config.XmlConfigurator.Configure(); + + UUID userId = TestHelpers.ParseTail(0x1); + string inventoryItemName = "item1"; + + SceneObjectGroup so1 = SceneHelpers.CreateSceneObject(1, userId, "so1", 0x10); + m_scene.AddSceneObject(so1); + + // Create an object embedded inside the first + UUID itemId = TestHelpers.ParseTail(0x20); + TaskInventoryHelpers.AddSceneObject(m_scene.AssetService, so1.RootPart, inventoryItemName, itemId, userId); + + LSL_Api api = new LSL_Api(); + api.Initialize(m_engine, so1.RootPart, null); + + // Create a second object + SceneObjectGroup so2 = SceneHelpers.CreateSceneObject(1, userId, "so2", 0x100); + m_scene.AddSceneObject(so2); + + api.llGiveInventory(so2.UUID.ToString(), inventoryItemName); + + // Item has copy permissions so original should stay intact. + List originalItems = so1.RootPart.Inventory.GetInventoryItems(); + Assert.That(originalItems.Count, Is.EqualTo(1)); + + List copiedItems = so2.RootPart.Inventory.GetInventoryItems(inventoryItemName); + Assert.That(copiedItems.Count, Is.EqualTo(1)); + Assert.That(copiedItems[0].Name, Is.EqualTo(inventoryItemName)); + } + + /// + /// Test giving inventory from an object to an object where they have different owners + /// + [Test] + public void TestLlGiveInventoryO2ODifferentOwners() + { + TestHelpers.InMethod(); +// log4net.Config.XmlConfigurator.Configure(); + + UUID user1Id = TestHelpers.ParseTail(0x1); + UUID user2Id = TestHelpers.ParseTail(0x2); + string inventoryItemName = "item1"; + + SceneObjectGroup so1 = SceneHelpers.CreateSceneObject(1, user1Id, "so1", 0x10); + m_scene.AddSceneObject(so1); + LSL_Api api = new LSL_Api(); + api.Initialize(m_engine, so1.RootPart, null); + + // Create an object embedded inside the first + UUID itemId = TestHelpers.ParseTail(0x20); + TaskInventoryHelpers.AddSceneObject(m_scene.AssetService, so1.RootPart, inventoryItemName, itemId, user1Id); + + // Create a second object + SceneObjectGroup so2 = SceneHelpers.CreateSceneObject(1, user2Id, "so2", 0x100); + m_scene.AddSceneObject(so2); + LSL_Api api2 = new LSL_Api(); + api2.Initialize(m_engine, so2.RootPart, null); + + // *** Firstly, we test where llAllowInventoryDrop() has not been called. *** + api.llGiveInventory(so2.UUID.ToString(), inventoryItemName); + + { + // Item has copy permissions so original should stay intact. + List originalItems = so1.RootPart.Inventory.GetInventoryItems(); + Assert.That(originalItems.Count, Is.EqualTo(1)); + + // Should have not copied + List copiedItems = so2.RootPart.Inventory.GetInventoryItems(inventoryItemName); + Assert.That(copiedItems.Count, Is.EqualTo(0)); + } + + // *** Secondly, we turn on allow inventory drop in the target and retest. *** + api2.llAllowInventoryDrop(1); + api.llGiveInventory(so2.UUID.ToString(), inventoryItemName); + + { + // Item has copy permissions so original should stay intact. + List originalItems = so1.RootPart.Inventory.GetInventoryItems(); + Assert.That(originalItems.Count, Is.EqualTo(1)); + + // Should now have copied. + List copiedItems = so2.RootPart.Inventory.GetInventoryItems(inventoryItemName); + Assert.That(copiedItems.Count, Is.EqualTo(1)); + Assert.That(copiedItems[0].Name, Is.EqualTo(inventoryItemName)); + } + } + + /// + /// Test giving inventory from an object to an avatar that is not the object's owner. + /// + [Test] + public void TestLlGiveInventoryO2DifferentAvatar() + { + TestHelpers.InMethod(); + // TestHelpers.EnableLogging(); + + UUID user1Id = TestHelpers.ParseTail(0x1); + UUID user2Id = TestHelpers.ParseTail(0x2); + string inventoryItemName = "item1"; + + SceneObjectGroup so1 = SceneHelpers.CreateSceneObject(1, user1Id, "so1", 0x10); + m_scene.AddSceneObject(so1); + LSL_Api api = new LSL_Api(); + api.Initialize(m_engine, so1.RootPart, null); + + // Create an object embedded inside the first + UUID itemId = TestHelpers.ParseTail(0x20); + TaskInventoryHelpers.AddSceneObject(m_scene.AssetService, so1.RootPart, inventoryItemName, itemId, user1Id); + + UserAccountHelpers.CreateUserWithInventory(m_scene, user2Id); + + api.llGiveInventory(user2Id.ToString(), inventoryItemName); + + InventoryItemBase receivedItem + = UserInventoryHelpers.GetInventoryItem( + m_scene.InventoryService, user2Id, string.Format("Objects/{0}", inventoryItemName)); + + Assert.IsNotNull(receivedItem); + } + + /// + /// Test giving inventory from an object to an avatar that is not the object's owner and where the next + /// permissions do not include mod. + /// + [Test] + public void TestLlGiveInventoryO2DifferentAvatarNoMod() + { + TestHelpers.InMethod(); +// TestHelpers.EnableLogging(); + + UUID user1Id = TestHelpers.ParseTail(0x1); + UUID user2Id = TestHelpers.ParseTail(0x2); + string inventoryItemName = "item1"; + + SceneObjectGroup so1 = SceneHelpers.CreateSceneObject(1, user1Id, "so1", 0x10); + m_scene.AddSceneObject(so1); + LSL_Api api = new LSL_Api(); + api.Initialize(m_engine, so1.RootPart, null); + + // Create an object embedded inside the first + UUID itemId = TestHelpers.ParseTail(0x20); + TaskInventoryItem tii + = TaskInventoryHelpers.AddSceneObject(m_scene.AssetService, so1.RootPart, inventoryItemName, itemId, user1Id); + tii.NextPermissions &= ~((uint)PermissionMask.Modify); + + UserAccountHelpers.CreateUserWithInventory(m_scene, user2Id); + + api.llGiveInventory(user2Id.ToString(), inventoryItemName); + + InventoryItemBase receivedItem + = UserInventoryHelpers.GetInventoryItem( + m_scene.InventoryService, user2Id, string.Format("Objects/{0}", inventoryItemName)); + + Assert.IsNotNull(receivedItem); + Assert.AreEqual(0, receivedItem.CurrentPermissions & (uint)PermissionMask.Modify); + } + + [Test] + public void TestLlRemoteLoadScriptPin() + { + TestHelpers.InMethod(); +// TestHelpers.EnableLogging(); + + UUID user1Id = TestHelpers.ParseTail(0x1); + UUID user2Id = TestHelpers.ParseTail(0x2); + + SceneObjectGroup sourceSo = SceneHelpers.AddSceneObject(m_scene, "sourceSo", user1Id); + m_scene.AddSceneObject(sourceSo); + LSL_Api api = new LSL_Api(); + api.Initialize(m_engine, sourceSo.RootPart, null); + TaskInventoryHelpers.AddScript(m_scene.AssetService, sourceSo.RootPart, "script", "Hello World"); + + SceneObjectGroup targetSo = SceneHelpers.AddSceneObject(m_scene, "targetSo", user1Id); + SceneObjectGroup otherOwnedTargetSo = SceneHelpers.AddSceneObject(m_scene, "otherOwnedTargetSo", user2Id); + + // Test that we cannot load a script when the target pin has never been set (i.e. it is zero) + api.llRemoteLoadScriptPin(targetSo.UUID.ToString(), "script", 0, 0, 0); + Assert.IsNull(targetSo.RootPart.Inventory.GetInventoryItem("script")); + + // Test that we cannot load a script when the given pin does not match the target + targetSo.RootPart.ScriptAccessPin = 5; + api.llRemoteLoadScriptPin(targetSo.UUID.ToString(), "script", 3, 0, 0); + Assert.IsNull(targetSo.RootPart.Inventory.GetInventoryItem("script")); + + // Test that we cannot load into a prim with a different owner + otherOwnedTargetSo.RootPart.ScriptAccessPin = 3; + api.llRemoteLoadScriptPin(otherOwnedTargetSo.UUID.ToString(), "script", 3, 0, 0); + Assert.IsNull(otherOwnedTargetSo.RootPart.Inventory.GetInventoryItem("script")); + + // Test that we can load a script when given pin and dest pin match. + targetSo.RootPart.ScriptAccessPin = 3; + api.llRemoteLoadScriptPin(targetSo.UUID.ToString(), "script", 3, 0, 0); + TaskInventoryItem insertedItem = targetSo.RootPart.Inventory.GetInventoryItem("script"); + Assert.IsNotNull(insertedItem); + + // Test that we can no longer load if access pin is unset + targetSo.RootPart.Inventory.RemoveInventoryItem(insertedItem.ItemID); + Assert.IsNull(targetSo.RootPart.Inventory.GetInventoryItem("script")); + + targetSo.RootPart.ScriptAccessPin = 0; + api.llRemoteLoadScriptPin(otherOwnedTargetSo.UUID.ToString(), "script", 3, 0, 0); + Assert.IsNull(otherOwnedTargetSo.RootPart.Inventory.GetInventoryItem("script")); + } + } + */ +} diff --git a/Tests/OpenSim.Region.ScriptEngine.Tests/Shared/Tests/LSL_ApiLinkingTests.cs b/Tests/OpenSim.Region.ScriptEngine.Tests/Shared/Tests/LSL_ApiLinkingTests.cs new file mode 100644 index 00000000000..9c262db1244 --- /dev/null +++ b/Tests/OpenSim.Region.ScriptEngine.Tests/Shared/Tests/LSL_ApiLinkingTests.cs @@ -0,0 +1,192 @@ +/* + * 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 System.Reflection; +using System.Text; +using log4net; +using Nini.Config; +using NUnit.Framework; +using OpenMetaverse; +using OpenMetaverse.Assets; +using OpenMetaverse.StructuredData; +using OpenSim.Framework; +using OpenSim.Region.CoreModules.Avatar.AvatarFactory; +using OpenSim.Region.OptionalModules.World.NPC; +using OpenSim.Region.Framework.Scenes; +using OpenSim.Region.ScriptEngine.Shared; +using OpenSim.Region.ScriptEngine.Shared.Api; +using OpenSim.Region.ScriptEngine.Shared.ScriptBase; +using OpenSim.Services.Interfaces; +using OpenSim.Tests.Common; + +namespace OpenSim.Region.ScriptEngine.Shared.Tests +{ + /// + /// Tests for linking functions in LSL + /// + /// + /// This relates to LSL. Actual linking functionality should be tested in the main + /// OpenSim.Region.Framework.Scenes.Tests.SceneObjectLinkingTests. + /// + [TestFixture] + public class LSL_ApiLinkingTests : OpenSimTestCase + { + /* + protected Scene m_scene; + protected XEngine.XEngine m_engine; + + [SetUp] + public override void SetUp() + { + base.SetUp(); + + IConfigSource initConfigSource = new IniConfigSource(); + IConfig config = initConfigSource.AddConfig("XEngine"); + config.Set("Enabled", "true"); + + config = initConfigSource.AddConfig("OSSL"); + config.Set("DebuggerSafe", false); + config.Set("AllowOSFunctions", "true"); + config.Set("OSFunctionThreatLevel", "Severe"); + + m_scene = new SceneHelpers().SetupScene(); + SceneHelpers.SetupSceneModules(m_scene, initConfigSource); + + m_engine = new XEngine.XEngine(); + m_engine.Initialise(initConfigSource); + m_engine.AddRegion(m_scene); + } + + [Test] + public void TestllCreateLink() + { + TestHelpers.InMethod(); + + UUID ownerId = TestHelpers.ParseTail(0x1); + + SceneObjectGroup grp1 = SceneHelpers.CreateSceneObject(2, ownerId, "grp1-", 0x10); + grp1.AbsolutePosition = new Vector3(10, 10, 10); + m_scene.AddSceneObject(grp1); + + // FIXME: This should really be a script item (with accompanying script) + TaskInventoryItem grp1Item + = TaskInventoryHelpers.AddNotecard( + m_scene.AssetService, grp1.RootPart, "ncItem", TestHelpers.ParseTail(0x800), TestHelpers.ParseTail(0x900), "Hello World!"); + grp1Item.PermsMask |= ScriptBaseClass.PERMISSION_CHANGE_LINKS; + + SceneObjectGroup grp2 = SceneHelpers.CreateSceneObject(2, ownerId, "grp2-", 0x20); + grp2.AbsolutePosition = new Vector3(20, 20, 20); + + // <180,0,0> + grp2.UpdateGroupRotationR(Quaternion.CreateFromEulers(180 * Utils.DEG_TO_RAD, 0, 0)); + + m_scene.AddSceneObject(grp2); + + LSL_Api apiGrp1 = new LSL_Api(); + apiGrp1.Initialize(m_engine, grp1.RootPart, grp1Item); + + apiGrp1.llCreateLink(grp2.UUID.ToString(), ScriptBaseClass.TRUE); + + Assert.That(grp1.Parts.Length, Is.EqualTo(4)); + Assert.That(grp2.IsDeleted, Is.True); + } + + [Test] + public void TestllBreakLink() + { + TestHelpers.InMethod(); + + UUID ownerId = TestHelpers.ParseTail(0x1); + + SceneObjectGroup grp1 = SceneHelpers.CreateSceneObject(2, ownerId, "grp1-", 0x10); + grp1.AbsolutePosition = new Vector3(10, 10, 10); + m_scene.AddSceneObject(grp1); + + // FIXME: This should really be a script item (with accompanying script) + TaskInventoryItem grp1Item + = TaskInventoryHelpers.AddNotecard( + m_scene.AssetService, grp1.RootPart, "ncItem", TestHelpers.ParseTail(0x800), TestHelpers.ParseTail(0x900), "Hello World!"); + + grp1Item.PermsMask |= ScriptBaseClass.PERMISSION_CHANGE_LINKS; + + LSL_Api apiGrp1 = new LSL_Api(); + apiGrp1.Initialize(m_engine, grp1.RootPart, grp1Item); + + apiGrp1.llBreakLink(2); + + Assert.That(grp1.Parts.Length, Is.EqualTo(1)); + + SceneObjectGroup grp2 = m_scene.GetSceneObjectGroup("grp1-Part1"); + Assert.That(grp2, Is.Not.Null); + } + + [Test] + public void TestllBreakAllLinks() + { + TestHelpers.InMethod(); + + UUID ownerId = TestHelpers.ParseTail(0x1); + + SceneObjectGroup grp1 = SceneHelpers.CreateSceneObject(3, ownerId, "grp1-", 0x10); + grp1.AbsolutePosition = new Vector3(10, 10, 10); + m_scene.AddSceneObject(grp1); + + // FIXME: This should really be a script item (with accompanying script) + TaskInventoryItem grp1Item + = TaskInventoryHelpers.AddNotecard( + m_scene.AssetService, grp1.RootPart, "ncItem", TestHelpers.ParseTail(0x800), TestHelpers.ParseTail(0x900), "Hello World!"); + + grp1Item.PermsMask |= ScriptBaseClass.PERMISSION_CHANGE_LINKS; + + LSL_Api apiGrp1 = new LSL_Api(); + apiGrp1.Initialize(m_engine, grp1.RootPart, grp1Item); + + apiGrp1.llBreakAllLinks(); + + { + SceneObjectGroup nowGrp = m_scene.GetSceneObjectGroup("grp1-Part1"); + Assert.That(nowGrp, Is.Not.Null); + Assert.That(nowGrp.Parts.Length, Is.EqualTo(1)); + } + + { + SceneObjectGroup nowGrp = m_scene.GetSceneObjectGroup("grp1-Part2"); + Assert.That(nowGrp, Is.Not.Null); + Assert.That(nowGrp.Parts.Length, Is.EqualTo(1)); + } + + { + SceneObjectGroup nowGrp = m_scene.GetSceneObjectGroup("grp1-Part3"); + Assert.That(nowGrp, Is.Not.Null); + Assert.That(nowGrp.Parts.Length, Is.EqualTo(1)); + } + } + } + */ +} diff --git a/Tests/OpenSim.Region.ScriptEngine.Tests/Shared/Tests/LSL_ApiListTests.cs b/Tests/OpenSim.Region.ScriptEngine.Tests/Shared/Tests/LSL_ApiListTests.cs new file mode 100644 index 00000000000..7bc6d91b144 --- /dev/null +++ b/Tests/OpenSim.Region.ScriptEngine.Tests/Shared/Tests/LSL_ApiListTests.cs @@ -0,0 +1,139 @@ +/* + * 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 NUnit.Framework; +using OpenSim.Framework; +using OpenSim.Tests.Common; +using OpenSim.Region.ScriptEngine.Shared; +using OpenSim.Region.Framework.Scenes; +using Nini.Config; +using OpenSim.Region.ScriptEngine.Shared.Api; +using OpenSim.Region.ScriptEngine.Shared.ScriptBase; +using OpenMetaverse; + +using LSL_Float = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLFloat; +using LSL_Integer = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLInteger; +using LSL_List = OpenSim.Region.ScriptEngine.Shared.LSL_Types.list; +using LSL_String = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLString; + +namespace OpenSim.Region.ScriptEngine.Shared.Tests +{ + [TestFixture] + public class LSL_ApiListTests : OpenSimTestCase + { + private LSL_Api m_lslApi; + + [SetUp] + public override void SetUp() + { + base.SetUp(); + + IConfigSource initConfigSource = new IniConfigSource(); + IConfig config = initConfigSource.AddConfig("XEngine"); + config.Set("Enabled", "true"); + + config = initConfigSource.AddConfig("OSSL"); + config.Set("DebuggerSafe", false); + config.Set("AllowOSFunctions", "true"); + config.Set("OSFunctionThreatLevel", "Severe"); + Scene scene = new SceneHelpers().SetupScene(); + SceneObjectPart part = SceneHelpers.AddSceneObject(scene).RootPart; + + XEngine.XEngine engine = new XEngine.XEngine(); + engine.Initialise(initConfigSource); + engine.AddRegion(scene); + + m_lslApi = new LSL_Api(); + m_lslApi.Initialize(engine, part, null); + } + + [Test] + public void TestllListFindList() + { + TestHelpers.InMethod(); + + LSL_List src = new LSL_List(new LSL_Integer(1), new LSL_Integer(2), new LSL_Integer(3)); + + { + // Test for a single item that should be found + int result = m_lslApi.llListFindList(src, new LSL_List(new LSL_Integer(4))); + Assert.That(result, Is.EqualTo(-1)); + } + + { + // Test for a single item that should be found + int result = m_lslApi.llListFindList(src, new LSL_List(new LSL_Integer(2))); + Assert.That(result, Is.EqualTo(1)); + } + + { + // Test for a constant that should be found + int result = m_lslApi.llListFindList(src, new LSL_List(ScriptBaseClass.AGENT)); + Assert.That(result, Is.EqualTo(0)); + } + + { + // Test for a list that should be found + int result = m_lslApi.llListFindList(src, new LSL_List(new LSL_Integer(2), new LSL_Integer(3))); + Assert.That(result, Is.EqualTo(1)); + } + + { + // Test for a single item not in the list + int result = m_lslApi.llListFindList(src, new LSL_List(new LSL_Integer(4))); + Assert.That(result, Is.EqualTo(-1)); + } + + { + // Test for something that should not be cast + int result = m_lslApi.llListFindList(src, new LSL_List(new LSL_String("4"))); + Assert.That(result, Is.EqualTo(-1)); + } + + { + // Test for a list not in the list + int result + = m_lslApi.llListFindList( + src, new LSL_List(new LSL_Integer(2), new LSL_Integer(3), new LSL_Integer(4))); + Assert.That(result, Is.EqualTo(-1)); + } + + { + LSL_List srcWithConstants + = new LSL_List(new LSL_Integer(3), ScriptBaseClass.AGENT, ScriptBaseClass.OS_NPC_LAND_AT_TARGET); + + // Test for constants that appears in the source list that should be found + int result + = m_lslApi.llListFindList(srcWithConstants, new LSL_List(new LSL_Integer(1), new LSL_Integer(2))); + + Assert.That(result, Is.EqualTo(1)); + } + } + } + } diff --git a/Tests/OpenSim.Region.ScriptEngine.Tests/Shared/Tests/LSL_ApiNotecardTests.cs b/Tests/OpenSim.Region.ScriptEngine.Tests/Shared/Tests/LSL_ApiNotecardTests.cs new file mode 100644 index 00000000000..dd60a87c786 --- /dev/null +++ b/Tests/OpenSim.Region.ScriptEngine.Tests/Shared/Tests/LSL_ApiNotecardTests.cs @@ -0,0 +1,269 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Net; +using System.Reflection; +using System.Text; +using log4net; +using Nini.Config; +using NUnit.Framework; +using OpenMetaverse; +using OpenSim.Framework; +using OpenSim.Framework.Servers; +using OpenSim.Framework.Servers.HttpServer; +using OpenSim.Region.CoreModules.Scripting.LSLHttp; +using OpenSim.Region.Framework.Scenes; +using OpenSim.Region.ScriptEngine.Shared; +using OpenSim.Region.ScriptEngine.Shared.Api; +using OpenSim.Region.ScriptEngine.Shared.ScriptBase; +using OpenSim.Services.Interfaces; +using OpenSim.Tests.Common; + +namespace OpenSim.Region.ScriptEngine.Shared.Tests +{ + /// + /// Tests for notecard related functions in LSL + /// + [TestFixture] + public class LSL_ApiNotecardTests : OpenSimTestCase + { + private Scene m_scene; + private MockScriptEngine m_engine; + + private SceneObjectGroup m_so; + private TaskInventoryItem m_scriptItem; + private LSL_Api m_lslApi; + + [OneTimeSetUp] + public void TestFixtureSetUp() + { + // Don't allow tests to be bamboozled by asynchronous events. Execute everything on the same thread. + Util.FireAndForgetMethod = FireAndForgetMethod.RegressionTest; + } + + [OneTimeTearDown] + public void TestFixureTearDown() + { + // 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; + } + + [SetUp] + public override void SetUp() + { + base.SetUp(); + + m_engine = new MockScriptEngine(); + + m_scene = new SceneHelpers().SetupScene(); + SceneHelpers.SetupSceneModules(m_scene, new IniConfigSource(), m_engine); + + m_so = SceneHelpers.AddSceneObject(m_scene); + m_scriptItem = TaskInventoryHelpers.AddScript(m_scene.AssetService, m_so.RootPart); + + // This is disconnected from the actual script - the mock engine does not set up any LSL_Api atm. + // Possibly this could be done and we could obtain it directly from the MockScriptEngine. + m_lslApi = new LSL_Api(); + m_lslApi.Initialize(m_engine, m_so.RootPart, m_scriptItem); + } + + [Test] + public void TestLlGetNotecardLine() + { + TestHelpers.InMethod(); + + string[] ncLines = { "One", "Twoè", "Three" }; + + TaskInventoryItem ncItem + = TaskInventoryHelpers.AddNotecard(m_scene.AssetService, m_so.RootPart, "nc", "1", "10", string.Join("\n", ncLines)); + + AssertValidNotecardLine(ncItem.Name, 0, ncLines[0]); + AssertValidNotecardLine(ncItem.Name, 2, ncLines[2]); + AssertValidNotecardLine(ncItem.Name, 3, ScriptBaseClass.EOF); + AssertValidNotecardLine(ncItem.Name, 4, ScriptBaseClass.EOF); + + // XXX: Is this correct or do we really expect no dataserver event to fire at all? + AssertValidNotecardLine(ncItem.Name, -1, ""); + AssertValidNotecardLine(ncItem.Name, -2, ""); + } + + [Test] + public void TestLlGetNotecardLine_NoNotecard() + { + TestHelpers.InMethod(); + + AssertInValidNotecardLine("nc", 0); + } + + [Test] + public void TestLlGetNotecardLine_NotANotecard() + { + TestHelpers.InMethod(); + + TaskInventoryItem ncItem = TaskInventoryHelpers.AddScript(m_scene.AssetService, m_so.RootPart, "nc1", "Not important"); + + AssertInValidNotecardLine(ncItem.Name, 0); + } + + private void AssertValidNotecardLine(string ncName, int lineNumber, string assertLine) + { + string key = m_lslApi.llGetNotecardLine(ncName, lineNumber); + Assert.That(key, Is.Not.EqualTo(UUID.Zero.ToString())); + + Assert.That(m_engine.PostedEvents.Count, Is.EqualTo(1)); + Assert.That(m_engine.PostedEvents.ContainsKey(m_scriptItem.ItemID)); + + List events = m_engine.PostedEvents[m_scriptItem.ItemID]; + Assert.That(events.Count, Is.EqualTo(1)); + EventParams eventParams = events[0]; + + Assert.That(eventParams.EventName, Is.EqualTo("dataserver")); + Assert.That(eventParams.Params[0].ToString(), Is.EqualTo(key)); + Assert.That(eventParams.Params[1].ToString(), Is.EqualTo(assertLine)); + + m_engine.ClearPostedEvents(); + } + + private void AssertInValidNotecardLine(string ncName, int lineNumber) + { + string key = m_lslApi.llGetNotecardLine(ncName, lineNumber); + Assert.That(key, Is.EqualTo(UUID.Zero.ToString())); + + Assert.That(m_engine.PostedEvents.Count, Is.EqualTo(0)); + } + +// [Test] +// public void TestLlReleaseUrl() +// { +// TestHelpers.InMethod(); +// +// m_lslApi.llRequestURL(); +// string returnedUri = m_engine.PostedEvents[m_scriptItem.ItemID][0].Params[2].ToString(); +// +// { +// // Check that the initial number of URLs is correct +// Assert.That(m_lslApi.llGetFreeURLs().value, Is.EqualTo(m_urlModule.TotalUrls - 1)); +// } +// +// { +// // Check releasing a non-url +// m_lslApi.llReleaseURL("GARBAGE"); +// Assert.That(m_lslApi.llGetFreeURLs().value, Is.EqualTo(m_urlModule.TotalUrls - 1)); +// } +// +// { +// // Check releasing a non-existing url +// m_lslApi.llReleaseURL("http://example.com"); +// Assert.That(m_lslApi.llGetFreeURLs().value, Is.EqualTo(m_urlModule.TotalUrls - 1)); +// } +// +// { +// // Check URL release +// m_lslApi.llReleaseURL(returnedUri); +// Assert.That(m_lslApi.llGetFreeURLs().value, Is.EqualTo(m_urlModule.TotalUrls)); +// +// HttpWebRequest webRequest = (HttpWebRequest)WebRequest.Create(returnedUri); +// +// bool gotExpectedException = false; +// +// try +// { +// using (HttpWebResponse webResponse = (HttpWebResponse)webRequest.GetResponse()) +// {} +// } +// catch (WebException e) +// { +// using (HttpWebResponse response = (HttpWebResponse)e.Response) +// gotExpectedException = response.StatusCode == HttpStatusCode.NotFound; +// } +// +// Assert.That(gotExpectedException, Is.True); +// } +// +// { +// // Check releasing the same URL again +// m_lslApi.llReleaseURL(returnedUri); +// Assert.That(m_lslApi.llGetFreeURLs().value, Is.EqualTo(m_urlModule.TotalUrls)); +// } +// } +// +// [Test] +// public void TestLlRequestUrl() +// { +// TestHelpers.InMethod(); +// +// string requestId = m_lslApi.llRequestURL(); +// Assert.That(requestId, Is.Not.EqualTo(UUID.Zero.ToString())); +// string returnedUri; +// +// { +// // Check that URL is correctly set up +// Assert.That(m_lslApi.llGetFreeURLs().value, Is.EqualTo(m_urlModule.TotalUrls - 1)); +// +// Assert.That(m_engine.PostedEvents.ContainsKey(m_scriptItem.ItemID)); +// +// List events = m_engine.PostedEvents[m_scriptItem.ItemID]; +// Assert.That(events.Count, Is.EqualTo(1)); +// EventParams eventParams = events[0]; +// Assert.That(eventParams.EventName, Is.EqualTo("http_request")); +// +// UUID returnKey; +// string rawReturnKey = eventParams.Params[0].ToString(); +// string method = eventParams.Params[1].ToString(); +// returnedUri = eventParams.Params[2].ToString(); +// +// Assert.That(UUID.TryParse(rawReturnKey, out returnKey), Is.True); +// Assert.That(method, Is.EqualTo(ScriptBaseClass.URL_REQUEST_GRANTED)); +// Assert.That(Uri.IsWellFormedUriString(returnedUri, UriKind.Absolute), Is.True); +// } +// +// { +// // Check that request to URL works. +// string testResponse = "Hello World"; +// +// m_engine.ClearPostedEvents(); +// m_engine.PostEventHook +// += (itemId, evp) => m_lslApi.llHTTPResponse(evp.Params[0].ToString(), 200, testResponse); +// +//// Console.WriteLine("Trying {0}", returnedUri); +// HttpWebRequest webRequest = (HttpWebRequest)WebRequest.Create(returnedUri); +// +// AssertHttpResponse(returnedUri, testResponse); +// +// Assert.That(m_engine.PostedEvents.ContainsKey(m_scriptItem.ItemID)); +// +// List events = m_engine.PostedEvents[m_scriptItem.ItemID]; +// Assert.That(events.Count, Is.EqualTo(1)); +// EventParams eventParams = events[0]; +// Assert.That(eventParams.EventName, Is.EqualTo("http_request")); +// +// UUID returnKey; +// string rawReturnKey = eventParams.Params[0].ToString(); +// string method = eventParams.Params[1].ToString(); +// string body = eventParams.Params[2].ToString(); +// +// Assert.That(UUID.TryParse(rawReturnKey, out returnKey), Is.True); +// Assert.That(method, Is.EqualTo("GET")); +// Assert.That(body, Is.EqualTo("")); +// } +// } +// +// private void AssertHttpResponse(string uri, string expectedResponse) +// { +// HttpWebRequest webRequest = (HttpWebRequest)WebRequest.Create(uri); +// +// using (HttpWebResponse webResponse = (HttpWebResponse)webRequest.GetResponse()) +// { +// using (Stream stream = webResponse.GetResponseStream()) +// { +// using (StreamReader reader = new StreamReader(stream)) +// { +// Assert.That(reader.ReadToEnd(), Is.EqualTo(expectedResponse)); +// } +// } +// } +// } + } +} diff --git a/Tests/OpenSim.Region.ScriptEngine.Tests/Shared/Tests/LSL_ApiObjectTests.cs b/Tests/OpenSim.Region.ScriptEngine.Tests/Shared/Tests/LSL_ApiObjectTests.cs new file mode 100644 index 00000000000..cc550ad5fd8 --- /dev/null +++ b/Tests/OpenSim.Region.ScriptEngine.Tests/Shared/Tests/LSL_ApiObjectTests.cs @@ -0,0 +1,399 @@ +/* + * 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 System.Reflection; +using System.Text; +using log4net; +using Nini.Config; +using NUnit.Framework; +using OpenMetaverse; +using OpenMetaverse.Assets; +using OpenMetaverse.StructuredData; +using OpenSim.Framework; +using OpenSim.Region.CoreModules.Avatar.AvatarFactory; +using OpenSim.Region.OptionalModules.World.NPC; +using OpenSim.Region.Framework.Scenes; +using OpenSim.Region.ScriptEngine.Shared; +using OpenSim.Region.ScriptEngine.Shared.Api; +using OpenSim.Region.ScriptEngine.Shared.ScriptBase; +using OpenSim.Services.Interfaces; +using OpenSim.Tests.Common; +using LSL_Integer = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLInteger; +using LSL_List = OpenSim.Region.ScriptEngine.Shared.LSL_Types.list; + +namespace OpenSim.Region.ScriptEngine.Shared.Tests +{ + [TestFixture] + public class LSL_ApiObjectTests : OpenSimTestCase + { + /* + private const double VECTOR_COMPONENT_ACCURACY = 0.0000005d; + private const float FLOAT_ACCURACY = 0.00005f; + + protected Scene m_scene; + protected XEngine.XEngine m_engine; + + [SetUp] + public override void SetUp() + { + base.SetUp(); + + IConfigSource initConfigSource = new IniConfigSource(); + IConfig config = initConfigSource.AddConfig("XEngine"); + config.Set("Enabled", "true"); + + m_scene = new SceneHelpers().SetupScene(); + SceneHelpers.SetupSceneModules(m_scene, initConfigSource); + + m_engine = new XEngine.XEngine(); + m_engine.Initialise(initConfigSource); + m_engine.AddRegion(m_scene); + } + + [Test] + public void TestllGetLinkPrimitiveParams() + { + TestHelpers.InMethod(); + TestHelpers.EnableLogging(); + + UUID ownerId = TestHelpers.ParseTail(0x1); + + SceneObjectGroup grp1 = SceneHelpers.CreateSceneObject(2, ownerId, "grp1-", 0x10); + grp1.AbsolutePosition = new Vector3(10, 11, 12); + m_scene.AddSceneObject(grp1); + + LSL_Api apiGrp1 = new LSL_Api(); + apiGrp1.Initialize(m_engine, grp1.RootPart, null); + + // Check simple 1 prim case + { + LSL_List resList + = apiGrp1.llGetLinkPrimitiveParams(1, new LSL_List(new LSL_Integer(ScriptBaseClass.PRIM_ROTATION))); + + Assert.That(resList.Length, Is.EqualTo(1)); + } + + // Check 2 prim case + { + LSL_List resList + = apiGrp1.llGetLinkPrimitiveParams( + 1, + new LSL_List( + new LSL_Integer(ScriptBaseClass.PRIM_ROTATION), + new LSL_Integer(ScriptBaseClass.PRIM_LINK_TARGET), + new LSL_Integer(2), + new LSL_Integer(ScriptBaseClass.PRIM_ROTATION))); + + Assert.That(resList.Length, Is.EqualTo(2)); + } + + // Check invalid parameters are ignored + { + LSL_List resList + = apiGrp1.llGetLinkPrimitiveParams(3, new LSL_List(new LSL_Integer(ScriptBaseClass.PRIM_ROTATION))); + + Assert.That(resList.Length, Is.EqualTo(0)); + } + + // Check all parameters are ignored if an initial bad link is given + { + LSL_List resList + = apiGrp1.llGetLinkPrimitiveParams( + 3, + new LSL_List( + new LSL_Integer(ScriptBaseClass.PRIM_ROTATION), + new LSL_Integer(ScriptBaseClass.PRIM_LINK_TARGET), + new LSL_Integer(1), + new LSL_Integer(ScriptBaseClass.PRIM_ROTATION))); + + Assert.That(resList.Length, Is.EqualTo(0)); + } + + // Check only subsequent parameters are ignored when we hit the first bad link number + { + LSL_List resList + = apiGrp1.llGetLinkPrimitiveParams( + 1, + new LSL_List( + new LSL_Integer(ScriptBaseClass.PRIM_ROTATION), + new LSL_Integer(ScriptBaseClass.PRIM_LINK_TARGET), + new LSL_Integer(3), + new LSL_Integer(ScriptBaseClass.PRIM_ROTATION))); + + Assert.That(resList.Length, Is.EqualTo(1)); + } + } + + [Test] + // llSetPrimitiveParams and llGetPrimitiveParams test. + public void TestllSetPrimitiveParams() + { + TestHelpers.InMethod(); + + // Create Prim1. + Scene scene = new SceneHelpers().SetupScene(); + string obj1Name = "Prim1"; + UUID objUuid = new UUID("00000000-0000-0000-0000-000000000001"); + SceneObjectPart part1 = + new SceneObjectPart(UUID.Zero, PrimitiveBaseShape.Default, + Vector3.Zero, Quaternion.Identity, + Vector3.Zero) { Name = obj1Name, UUID = objUuid }; + Assert.That(scene.AddNewSceneObject(new SceneObjectGroup(part1), false), Is.True); + + LSL_Api apiGrp1 = new LSL_Api(); + apiGrp1.Initialize(m_engine, part1, null); + + // Note that prim hollow check is passed with the other prim params in order to allow the + // specification of a different check value from the prim param. A cylinder, prism, sphere, + // torus or ring, with a hole shape of square, is limited to a hollow of 70%. Test 5 below + // specifies a value of 95% and checks to see if 70% was properly returned. + + // Test a sphere. + CheckllSetPrimitiveParams( + apiGrp1, + "test 1", // Prim test identification string + new LSL_Types.Vector3(6.0d, 9.9d, 9.9d), // Prim size + ScriptBaseClass.PRIM_TYPE_SPHERE, // Prim type + ScriptBaseClass.PRIM_HOLE_DEFAULT, // Prim hole type + new LSL_Types.Vector3(0.0d, 0.075d, 0.0d), // Prim cut + 0.80f, // Prim hollow + new LSL_Types.Vector3(0.0d, 0.0d, 0.0d), // Prim twist + new LSL_Types.Vector3(0.32d, 0.76d, 0.0d), // Prim dimple + 0.80f); // Prim hollow check + + // Test a prism. + CheckllSetPrimitiveParams( + apiGrp1, + "test 2", // Prim test identification string + new LSL_Types.Vector3(3.5d, 3.5d, 3.5d), // Prim size + ScriptBaseClass.PRIM_TYPE_PRISM, // Prim type + ScriptBaseClass.PRIM_HOLE_CIRCLE, // Prim hole type + new LSL_Types.Vector3(0.0d, 1.0d, 0.0d), // Prim cut + 0.90f, // Prim hollow + new LSL_Types.Vector3(0.0d, 0.0d, 0.0d), // Prim twist + new LSL_Types.Vector3(2.0d, 1.0d, 0.0d), // Prim taper + new LSL_Types.Vector3(0.0d, 0.0d, 0.0d), // Prim shear + 0.90f); // Prim hollow check + + // Test a box. + CheckllSetPrimitiveParams( + apiGrp1, + "test 3", // Prim test identification string + new LSL_Types.Vector3(3.5d, 3.5d, 3.5d), // Prim size + ScriptBaseClass.PRIM_TYPE_BOX, // Prim type + ScriptBaseClass.PRIM_HOLE_TRIANGLE, // Prim hole type + new LSL_Types.Vector3(0.0d, 1.0d, 0.0d), // Prim cut + 0.99f, // Prim hollow + new LSL_Types.Vector3(1.0d, 0.0d, 0.0d), // Prim twist + new LSL_Types.Vector3(1.0d, 1.0d, 0.0d), // Prim taper + new LSL_Types.Vector3(0.0d, 0.0d, 0.0d), // Prim shear + 0.99f); // Prim hollow check + + // Test a tube. + CheckllSetPrimitiveParams( + apiGrp1, + "test 4", // Prim test identification string + new LSL_Types.Vector3(4.2d, 4.2d, 4.2d), // Prim size + ScriptBaseClass.PRIM_TYPE_TUBE, // Prim type + ScriptBaseClass.PRIM_HOLE_SQUARE, // Prim hole type + new LSL_Types.Vector3(0.0d, 1.0d, 0.0d), // Prim cut + 0.00f, // Prim hollow + new LSL_Types.Vector3(1.0d, -1.0d, 0.0d), // Prim twist + new LSL_Types.Vector3(1.0d, 0.05d, 0.0d), // Prim hole size + // Expression for y selected to test precision problems during byte + // cast in SetPrimitiveShapeParams. + new LSL_Types.Vector3(0.0d, 0.35d + 0.1d, 0.0d), // Prim shear + new LSL_Types.Vector3(0.0d, 1.0d, 0.0d), // Prim profile cut + // Expression for y selected to test precision problems during sbyte + // cast in SetPrimitiveShapeParams. + new LSL_Types.Vector3(-1.0d, 0.70d + 0.1d + 0.1d, 0.0d), // Prim taper + 1.11f, // Prim revolutions + 0.88f, // Prim radius + 0.95f, // Prim skew + 0.00f); // Prim hollow check + + // Test a prism. + CheckllSetPrimitiveParams( + apiGrp1, + "test 5", // Prim test identification string + new LSL_Types.Vector3(3.5d, 3.5d, 3.5d), // Prim size + ScriptBaseClass.PRIM_TYPE_PRISM, // Prim type + ScriptBaseClass.PRIM_HOLE_SQUARE, // Prim hole type + new LSL_Types.Vector3(0.0d, 1.0d, 0.0d), // Prim cut + 0.99f, // Prim hollow + // Expression for x selected to test precision problems during sbyte + // cast in SetPrimitiveShapeBlockParams. + new LSL_Types.Vector3(0.7d + 0.2d, 0.0d, 0.0d), // Prim twist + // Expression for y selected to test precision problems during sbyte + // cast in SetPrimitiveShapeParams. + new LSL_Types.Vector3(2.0d, (1.3d + 0.1d), 0.0d), // Prim taper + new LSL_Types.Vector3(0.0d, 0.0d, 0.0d), // Prim shear + 0.70f); // Prim hollow check + + // Test a sculpted prim. + CheckllSetPrimitiveParams( + apiGrp1, + "test 6", // Prim test identification string + new LSL_Types.Vector3(2.0d, 2.0d, 2.0d), // Prim size + ScriptBaseClass.PRIM_TYPE_SCULPT, // Prim type + "be293869-d0d9-0a69-5989-ad27f1946fd4", // Prim map + ScriptBaseClass.PRIM_SCULPT_TYPE_SPHERE); // Prim sculpt type + } + + // Set prim params for a box, cylinder or prism and check results. + public void CheckllSetPrimitiveParams(LSL_Api api, string primTest, + LSL_Types.Vector3 primSize, int primType, int primHoleType, LSL_Types.Vector3 primCut, + float primHollow, LSL_Types.Vector3 primTwist, LSL_Types.Vector3 primTaper, LSL_Types.Vector3 primShear, + float primHollowCheck) + { + // Set the prim params. + api.llSetPrimitiveParams(new LSL_Types.list(ScriptBaseClass.PRIM_SIZE, primSize, + ScriptBaseClass.PRIM_TYPE, primType, primHoleType, + primCut, primHollow, primTwist, primTaper, primShear)); + + // Get params for prim to validate settings. + LSL_Types.list primParams = + api.llGetPrimitiveParams(new LSL_Types.list(ScriptBaseClass.PRIM_SIZE, ScriptBaseClass.PRIM_TYPE)); + + // Validate settings. + CheckllSetPrimitiveParamsVector(primSize, api.llList2Vector(primParams, 0), primTest + " prim size"); + Assert.AreEqual(primType, api.llList2Integer(primParams, 1), + "TestllSetPrimitiveParams " + primTest + " prim type check fail"); + Assert.AreEqual(primHoleType, api.llList2Integer(primParams, 2), + "TestllSetPrimitiveParams " + primTest + " prim hole default check fail"); + CheckllSetPrimitiveParamsVector(primCut, api.llList2Vector(primParams, 3), primTest + " prim cut"); + Assert.AreEqual(primHollowCheck, api.llList2Float(primParams, 4), FLOAT_ACCURACY, + "TestllSetPrimitiveParams " + primTest + " prim hollow check fail"); + CheckllSetPrimitiveParamsVector(primTwist, api.llList2Vector(primParams, 5), primTest + " prim twist"); + CheckllSetPrimitiveParamsVector(primTaper, api.llList2Vector(primParams, 6), primTest + " prim taper"); + CheckllSetPrimitiveParamsVector(primShear, api.llList2Vector(primParams, 7), primTest + " prim shear"); + } + + // Set prim params for a sphere and check results. + public void CheckllSetPrimitiveParams(LSL_Api api, string primTest, + LSL_Types.Vector3 primSize, int primType, int primHoleType, LSL_Types.Vector3 primCut, + float primHollow, LSL_Types.Vector3 primTwist, LSL_Types.Vector3 primDimple, float primHollowCheck) + { + // Set the prim params. + api.llSetPrimitiveParams(new LSL_Types.list(ScriptBaseClass.PRIM_SIZE, primSize, + ScriptBaseClass.PRIM_TYPE, primType, primHoleType, + primCut, primHollow, primTwist, primDimple)); + + // Get params for prim to validate settings. + LSL_Types.list primParams = + api.llGetPrimitiveParams(new LSL_Types.list(ScriptBaseClass.PRIM_SIZE, ScriptBaseClass.PRIM_TYPE)); + + // Validate settings. + CheckllSetPrimitiveParamsVector(primSize, api.llList2Vector(primParams, 0), primTest + " prim size"); + Assert.AreEqual(primType, api.llList2Integer(primParams, 1), + "TestllSetPrimitiveParams " + primTest + " prim type check fail"); + Assert.AreEqual(primHoleType, api.llList2Integer(primParams, 2), + "TestllSetPrimitiveParams " + primTest + " prim hole default check fail"); + CheckllSetPrimitiveParamsVector(primCut, api.llList2Vector(primParams, 3), primTest + " prim cut"); + Assert.AreEqual(primHollowCheck, api.llList2Float(primParams, 4), FLOAT_ACCURACY, + "TestllSetPrimitiveParams " + primTest + " prim hollow check fail"); + CheckllSetPrimitiveParamsVector(primTwist, api.llList2Vector(primParams, 5), primTest + " prim twist"); + CheckllSetPrimitiveParamsVector(primDimple, api.llList2Vector(primParams, 6), primTest + " prim dimple"); + } + + // Set prim params for a torus, tube or ring and check results. + public void CheckllSetPrimitiveParams(LSL_Api api, string primTest, + LSL_Types.Vector3 primSize, int primType, int primHoleType, LSL_Types.Vector3 primCut, + float primHollow, LSL_Types.Vector3 primTwist, LSL_Types.Vector3 primHoleSize, + LSL_Types.Vector3 primShear, LSL_Types.Vector3 primProfCut, LSL_Types.Vector3 primTaper, + float primRev, float primRadius, float primSkew, float primHollowCheck) + { + // Set the prim params. + api.llSetPrimitiveParams(new LSL_Types.list(ScriptBaseClass.PRIM_SIZE, primSize, + ScriptBaseClass.PRIM_TYPE, primType, primHoleType, + primCut, primHollow, primTwist, primHoleSize, primShear, primProfCut, + primTaper, primRev, primRadius, primSkew)); + + // Get params for prim to validate settings. + LSL_Types.list primParams = + api.llGetPrimitiveParams(new LSL_Types.list(ScriptBaseClass.PRIM_SIZE, ScriptBaseClass.PRIM_TYPE)); + + // Valdate settings. + CheckllSetPrimitiveParamsVector(primSize, api.llList2Vector(primParams, 0), primTest + " prim size"); + Assert.AreEqual(primType, api.llList2Integer(primParams, 1), + "TestllSetPrimitiveParams " + primTest + " prim type check fail"); + Assert.AreEqual(primHoleType, api.llList2Integer(primParams, 2), + "TestllSetPrimitiveParams " + primTest + " prim hole default check fail"); + CheckllSetPrimitiveParamsVector(primCut, api.llList2Vector(primParams, 3), primTest + " prim cut"); + Assert.AreEqual(primHollowCheck, api.llList2Float(primParams, 4), FLOAT_ACCURACY, + "TestllSetPrimitiveParams " + primTest + " prim hollow check fail"); + CheckllSetPrimitiveParamsVector(primTwist, api.llList2Vector(primParams, 5), primTest + " prim twist"); + CheckllSetPrimitiveParamsVector(primHoleSize, api.llList2Vector(primParams, 6), primTest + " prim hole size"); + CheckllSetPrimitiveParamsVector(primShear, api.llList2Vector(primParams, 7), primTest + " prim shear"); + CheckllSetPrimitiveParamsVector(primProfCut, api.llList2Vector(primParams, 8), primTest + " prim profile cut"); + CheckllSetPrimitiveParamsVector(primTaper, api.llList2Vector(primParams, 9), primTest + " prim taper"); + Assert.AreEqual(primRev, api.llList2Float(primParams, 10), FLOAT_ACCURACY, + "TestllSetPrimitiveParams " + primTest + " prim revolutions fail"); + Assert.AreEqual(primRadius, api.llList2Float(primParams, 11), FLOAT_ACCURACY, + "TestllSetPrimitiveParams " + primTest + " prim radius fail"); + Assert.AreEqual(primSkew, api.llList2Float(primParams, 12), FLOAT_ACCURACY, + "TestllSetPrimitiveParams " + primTest + " prim skew fail"); + } + + // Set prim params for a sculpted prim and check results. + public void CheckllSetPrimitiveParams(LSL_Api api, string primTest, + LSL_Types.Vector3 primSize, int primType, string primMap, int primSculptType) + { + // Set the prim params. + api.llSetPrimitiveParams(new LSL_Types.list(ScriptBaseClass.PRIM_SIZE, primSize, + ScriptBaseClass.PRIM_TYPE, primType, primMap, primSculptType)); + + // Get params for prim to validate settings. + LSL_Types.list primParams = + api.llGetPrimitiveParams(new LSL_Types.list(ScriptBaseClass.PRIM_SIZE, ScriptBaseClass.PRIM_TYPE)); + + // Validate settings. + CheckllSetPrimitiveParamsVector(primSize, api.llList2Vector(primParams, 0), primTest + " prim size"); + Assert.AreEqual(primType, api.llList2Integer(primParams, 1), + "TestllSetPrimitiveParams " + primTest + " prim type check fail"); + Assert.AreEqual(primMap, (string)api.llList2String(primParams, 2), + "TestllSetPrimitiveParams " + primTest + " prim map check fail"); + Assert.AreEqual(primSculptType, api.llList2Integer(primParams, 3), + "TestllSetPrimitiveParams " + primTest + " prim type scuplt check fail"); + } + + public void CheckllSetPrimitiveParamsVector(LSL_Types.Vector3 vecCheck, LSL_Types.Vector3 vecReturned, string msg) + { + // Check each vector component against expected result. + Assert.AreEqual(vecCheck.x, vecReturned.x, VECTOR_COMPONENT_ACCURACY, + "TestllSetPrimitiveParams " + msg + " vector check fail on x component"); + Assert.AreEqual(vecCheck.y, vecReturned.y, VECTOR_COMPONENT_ACCURACY, + "TestllSetPrimitiveParams " + msg + " vector check fail on y component"); + Assert.AreEqual(vecCheck.z, vecReturned.z, VECTOR_COMPONENT_ACCURACY, + "TestllSetPrimitiveParams " + msg + " vector check fail on z component"); + } + + } + */ +} diff --git a/Tests/OpenSim.Region.ScriptEngine.Tests/Shared/Tests/LSL_ApiTest.cs b/Tests/OpenSim.Region.ScriptEngine.Tests/Shared/Tests/LSL_ApiTest.cs new file mode 100644 index 00000000000..e10699dcc17 --- /dev/null +++ b/Tests/OpenSim.Region.ScriptEngine.Tests/Shared/Tests/LSL_ApiTest.cs @@ -0,0 +1,278 @@ +/* + * 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.Collections.Generic; +using NUnit.Framework; +using OpenSim.Framework; +using OpenSim.Tests.Common; +using OpenSim.Region.ScriptEngine.Shared; +using OpenSim.Region.Framework.Scenes; +using Nini.Config; +using OpenSim.Region.ScriptEngine.Shared.Api; +using OpenSim.Region.ScriptEngine.Shared.ScriptBase; +using OpenMetaverse; +using System; + +namespace OpenSim.Region.ScriptEngine.Shared.Tests +{ + /// + /// Tests for LSL_Api + /// + [TestFixture, LongRunning] + public class LSL_ApiTest + { + private const double VECTOR_COMPONENT_ACCURACY = 0.0000005d; + private const double ANGLE_ACCURACY_IN_RADIANS = 1E-6; + private LSL_Api m_lslApi; + + [SetUp] + public void SetUp() + { + IConfigSource initConfigSource = new IniConfigSource(); + IConfig config = initConfigSource.AddConfig("XEngine"); + config.Set("Enabled", "true"); + + Scene scene = new SceneHelpers().SetupScene(); + SceneObjectPart part = SceneHelpers.AddSceneObject(scene).RootPart; + + XEngine.XEngine engine = new XEngine.XEngine(); + engine.Initialise(initConfigSource); + engine.AddRegion(scene); + + m_lslApi = new LSL_Api(); + m_lslApi.Initialize(engine, part, null); + } + + [Test] + public void TestllAngleBetween() + { + TestHelpers.InMethod(); + + CheckllAngleBetween(new Vector3(1, 0, 0), 0, 1, 1); + CheckllAngleBetween(new Vector3(1, 0, 0), 90, 1, 1); + CheckllAngleBetween(new Vector3(1, 0, 0), 180, 1, 1); + + CheckllAngleBetween(new Vector3(0, 1, 0), 0, 1, 1); + CheckllAngleBetween(new Vector3(0, 1, 0), 90, 1, 1); + CheckllAngleBetween(new Vector3(0, 1, 0), 180, 1, 1); + + CheckllAngleBetween(new Vector3(0, 0, 1), 0, 1, 1); + CheckllAngleBetween(new Vector3(0, 0, 1), 90, 1, 1); + CheckllAngleBetween(new Vector3(0, 0, 1), 180, 1, 1); + + CheckllAngleBetween(new Vector3(1, 1, 1), 0, 1, 1); + CheckllAngleBetween(new Vector3(1, 1, 1), 90, 1, 1); + CheckllAngleBetween(new Vector3(1, 1, 1), 180, 1, 1); + + CheckllAngleBetween(new Vector3(1, 0, 0), 0, 1.6f, 1.8f); + CheckllAngleBetween(new Vector3(1, 0, 0), 90, 0.3f, 3.9f); + CheckllAngleBetween(new Vector3(1, 0, 0), 180, 8.8f, 7.4f); + + CheckllAngleBetween(new Vector3(0, 1, 0), 0, 9.8f, -9.4f); + CheckllAngleBetween(new Vector3(0, 1, 0), 90, 8.4f, -8.2f); + CheckllAngleBetween(new Vector3(0, 1, 0), 180, 0.4f, -5.8f); + + CheckllAngleBetween(new Vector3(0, 0, 1), 0, -6.8f, 3.4f); + CheckllAngleBetween(new Vector3(0, 0, 1), 90, -3.6f, 5.6f); + CheckllAngleBetween(new Vector3(0, 0, 1), 180, -3.8f, 1.1f); + + CheckllAngleBetween(new Vector3(1, 1, 1), 0, -7.7f, -2.0f); + CheckllAngleBetween(new Vector3(1, 1, 1), 90, -3.0f, -9.1f); + CheckllAngleBetween(new Vector3(1, 1, 1), 180, -7.9f, -8.0f); + } + + private void CheckllAngleBetween(Vector3 axis,float originalAngle, float denorm1, float denorm2) + { + Quaternion rotation1 = Quaternion.CreateFromAxisAngle(axis, 0); + Quaternion rotation2 = Quaternion.CreateFromAxisAngle(axis, ToRadians(originalAngle)); + rotation1 *= denorm1; + rotation2 *= denorm2; + + double deducedAngle = FromLslFloat(m_lslApi.llAngleBetween(ToLslQuaternion(rotation2), ToLslQuaternion(rotation1))); + + Assert.That(deducedAngle, Is.EqualTo(ToRadians(originalAngle)).Within(ANGLE_ACCURACY_IN_RADIANS), "TestllAngleBetween check fail"); + } + + #region Conversions to and from LSL_Types + + private float ToRadians(double degrees) + { + return (float)(Math.PI * degrees / 180); + } + + // private double FromRadians(float radians) + // { + // return radians * 180 / Math.PI; + // } + + private double FromLslFloat(LSL_Types.LSLFloat lslFloat) + { + return lslFloat.value; + } + + // private LSL_Types.LSLFloat ToLslFloat(double value) + // { + // return new LSL_Types.LSLFloat(value); + // } + + // private Quaternion FromLslQuaternion(LSL_Types.Quaternion lslQuaternion) + // { + // return new Quaternion((float)lslQuaternion.x, (float)lslQuaternion.y, (float)lslQuaternion.z, (float)lslQuaternion.s); + // } + + private LSL_Types.Quaternion ToLslQuaternion(Quaternion quaternion) + { + return new LSL_Types.Quaternion(quaternion.X, quaternion.Y, quaternion.Z, quaternion.W); + } + + #endregion + + [Test] + // llRot2Euler test. + public void TestllRot2Euler() + { + TestHelpers.InMethod(); + + // 180, 90 and zero degree rotations. + CheckllRot2Euler(new LSL_Types.Quaternion(0.0f, 0.0f, 0.0f, 1.0f)); + CheckllRot2Euler(new LSL_Types.Quaternion(0.0f, 0.0f, 0.707107f, 0.707107f)); + CheckllRot2Euler(new LSL_Types.Quaternion(0.0f, 0.0f, 1.0f, 0.0f)); + CheckllRot2Euler(new LSL_Types.Quaternion(0.0f, 0.0f, 0.707107f, -0.707107f)); + CheckllRot2Euler(new LSL_Types.Quaternion(0.707107f, 0.0f, 0.0f, 0.707107f)); + CheckllRot2Euler(new LSL_Types.Quaternion(0.5f, -0.5f, 0.5f, 0.5f)); + CheckllRot2Euler(new LSL_Types.Quaternion(0.0f, -0.707107f, 0.707107f, 0.0f)); + CheckllRot2Euler(new LSL_Types.Quaternion(-0.5f, -0.5f, 0.5f, -0.5f)); + CheckllRot2Euler(new LSL_Types.Quaternion(1.0f, 0.0f, 0.0f, 0.0f)); + CheckllRot2Euler(new LSL_Types.Quaternion(0.707107f, -0.707107f, 0.0f, 0.0f)); + CheckllRot2Euler(new LSL_Types.Quaternion(0.0f, -1.0f, 0.0f, 0.0f)); + CheckllRot2Euler(new LSL_Types.Quaternion(-0.707107f, -0.707107f, 0.0f, 0.0f)); + CheckllRot2Euler(new LSL_Types.Quaternion(0.707107f, 0.0f, 0.0f, -0.707107f)); + CheckllRot2Euler(new LSL_Types.Quaternion(0.5f, -0.5f, -0.5f, -0.5f)); + CheckllRot2Euler(new LSL_Types.Quaternion(0.0f, -0.707107f, -0.707107f, 0.0f)); + CheckllRot2Euler(new LSL_Types.Quaternion(-0.5f, -0.5f, -0.5f, 0.5f)); + CheckllRot2Euler(new LSL_Types.Quaternion(0.0f, -0.707107f, 0.0f, 0.707107f)); + CheckllRot2Euler(new LSL_Types.Quaternion(-0.5f, -0.5f, 0.5f, 0.5f)); + CheckllRot2Euler(new LSL_Types.Quaternion(-0.707107f, 0.0f, 0.707107f, 0.0f)); + CheckllRot2Euler(new LSL_Types.Quaternion(-0.5f, 0.5f, 0.5f, -0.5f)); + CheckllRot2Euler(new LSL_Types.Quaternion(0.0f, -0.707107f, 0.0f, -0.707107f)); + CheckllRot2Euler(new LSL_Types.Quaternion(-0.5f, -0.5f, -0.5f, -0.5f)); + CheckllRot2Euler(new LSL_Types.Quaternion(-0.707107f, 0.0f, -0.707107f, 0.0f)); + CheckllRot2Euler(new LSL_Types.Quaternion(-0.5f, 0.5f, -0.5f, 0.5f)); + + // A couple of messy rotations. + CheckllRot2Euler(new LSL_Types.Quaternion(1.0f, 5.651f, -3.1f, 67.023f)); + CheckllRot2Euler(new LSL_Types.Quaternion(0.719188f, -0.408934f, -0.363998f, -0.427841f)); + + // Some deliberately malicious rotations (intended on provoking singularity errors) + // The "f" suffexes are deliberately omitted. + CheckllRot2Euler(new LSL_Types.Quaternion(0.50001f, 0.50001f, 0.50001f, 0.50001f)); + // More malice. The "f" suffixes are deliberately omitted. + CheckllRot2Euler(new LSL_Types.Quaternion(-0.701055, 0.092296, 0.701055, -0.092296)); + CheckllRot2Euler(new LSL_Types.Quaternion(-0.183005, -0.683010, 0.183005, 0.683010)); + CheckllRot2Euler(new LSL_Types.Quaternion(-0.430460, -0.560982, 0.430460, 0.560982)); + CheckllRot2Euler(new LSL_Types.Quaternion(-0.701066, 0.092301, -0.701066, 0.092301)); + CheckllRot2Euler(new LSL_Types.Quaternion(-0.183013, -0.683010, 0.183013, 0.683010)); + CheckllRot2Euler(new LSL_Types.Quaternion(-0.183005, -0.683014, -0.183005, -0.683014)); + CheckllRot2Euler(new LSL_Types.Quaternion(-0.353556, 0.612375, 0.353556, -0.612375)); + CheckllRot2Euler(new LSL_Types.Quaternion(0.353554, -0.612385, -0.353554, 0.612385)); + CheckllRot2Euler(new LSL_Types.Quaternion(-0.560989, 0.430450, 0.560989, -0.430450)); + CheckllRot2Euler(new LSL_Types.Quaternion(-0.183013, 0.683009, -0.183013, 0.683009)); + CheckllRot2Euler(new LSL_Types.Quaternion(0.430457, -0.560985, -0.430457, 0.560985)); + CheckllRot2Euler(new LSL_Types.Quaternion(0.353552, 0.612360, -0.353552, -0.612360)); + CheckllRot2Euler(new LSL_Types.Quaternion(-0.499991, 0.500003, 0.499991, -0.500003)); + CheckllRot2Euler(new LSL_Types.Quaternion(-0.353555, -0.612385, -0.353555, -0.612385)); + CheckllRot2Euler(new LSL_Types.Quaternion(0.701066, -0.092301, -0.701066, 0.092301)); + CheckllRot2Euler(new LSL_Types.Quaternion(-0.499991, 0.500007, 0.499991, -0.500007)); + CheckllRot2Euler(new LSL_Types.Quaternion(-0.683002, 0.183016, -0.683002, 0.183016)); + CheckllRot2Euler(new LSL_Types.Quaternion(0.430458, 0.560982, 0.430458, 0.560982)); + CheckllRot2Euler(new LSL_Types.Quaternion(0.499991, -0.500003, -0.499991, 0.500003)); + CheckllRot2Euler(new LSL_Types.Quaternion(-0.183009, 0.683011, -0.183009, 0.683011)); + CheckllRot2Euler(new LSL_Types.Quaternion(0.560975, -0.430457, 0.560975, -0.430457)); + CheckllRot2Euler(new LSL_Types.Quaternion(0.701055, 0.092300, 0.701055, 0.092300)); + CheckllRot2Euler(new LSL_Types.Quaternion(-0.560990, 0.430459, -0.560990, 0.430459)); + CheckllRot2Euler(new LSL_Types.Quaternion(-0.092302, -0.701059, -0.092302, -0.701059)); + } + + /// + /// Check an llRot2Euler conversion. + /// + /// + /// Testing Rot2Euler this way instead of comparing against expected angles because + /// 1. There are several ways to get to the original Quaternion. For example a rotation + /// of PI and -PI will give the same result. But PI and -PI aren't equal. + /// 2. This method checks to see if the calculated angles from a quaternion can be used + /// to create a new quaternion to produce the same rotation. + /// However, can't compare the newly calculated quaternion against the original because + /// once again, there are multiple quaternions that give the same result. For instance + /// == <-X, -Y, -Z, -S>. Additionally, the magnitude of S can be changed + /// and will still result in the same rotation if the values for X, Y, Z are also changed + /// to compensate. + /// However, if two quaternions represent the same rotation, then multiplying the first + /// quaternion by the conjugate of the second, will give a third quaternion representing + /// a zero rotation. This can be tested for by looking at the X, Y, Z values which should + /// be zero. + /// + /// + private void CheckllRot2Euler(LSL_Types.Quaternion rot) + { + // Call LSL function to convert quaternion rotaion to euler radians. + LSL_Types.Vector3 eulerCalc = m_lslApi.llRot2Euler(rot); + // Now use the euler radians to recalculate a new quaternion rotation + LSL_Types.Quaternion newRot = m_lslApi.llEuler2Rot(eulerCalc); + // Multiple original quaternion by conjugate of quaternion calculated with angles. + LSL_Types.Quaternion check = rot * new LSL_Types.Quaternion(-newRot.x, -newRot.y, -newRot.z, newRot.s); + + Assert.AreEqual(0.0, check.x, VECTOR_COMPONENT_ACCURACY, "TestllRot2Euler X bounds check fail"); + Assert.AreEqual(0.0, check.y, VECTOR_COMPONENT_ACCURACY, "TestllRot2Euler Y bounds check fail"); + Assert.AreEqual(0.0, check.z, VECTOR_COMPONENT_ACCURACY, "TestllRot2Euler Z bounds check fail"); + } + + [Test] + public void TestllVecNorm() + { + TestHelpers.InMethod(); + + // Check special case for normalizing zero vector. + CheckllVecNorm(new LSL_Types.Vector3(0.0d, 0.0d, 0.0d), new LSL_Types.Vector3(0.0d, 0.0d, 0.0d)); + // Check various vectors. + CheckllVecNorm(new LSL_Types.Vector3(10.0d, 25.0d, 0.0d), new LSL_Types.Vector3(0.371391d, 0.928477d, 0.0d)); + CheckllVecNorm(new LSL_Types.Vector3(1.0d, 0.0d, 0.0d), new LSL_Types.Vector3(1.0d, 0.0d, 0.0d)); + CheckllVecNorm(new LSL_Types.Vector3(-90.0d, 55.0d, 2.0d), new LSL_Types.Vector3(-0.853128d, 0.521356d, 0.018958d)); + CheckllVecNorm(new LSL_Types.Vector3(255.0d, 255.0d, 255.0d), new LSL_Types.Vector3(0.577350d, 0.577350d, 0.577350d)); + } + + public void CheckllVecNorm(LSL_Types.Vector3 vec, LSL_Types.Vector3 vecNormCheck) + { + // Call LSL function to normalize the vector. + LSL_Types.Vector3 vecNorm = m_lslApi.llVecNorm(vec); + // Check each vector component against expected result. + Assert.AreEqual(vecNorm.x, vecNormCheck.x, VECTOR_COMPONENT_ACCURACY, "TestllVecNorm vector check fail on x component"); + Assert.AreEqual(vecNorm.y, vecNormCheck.y, VECTOR_COMPONENT_ACCURACY, "TestllVecNorm vector check fail on y component"); + Assert.AreEqual(vecNorm.z, vecNormCheck.z, VECTOR_COMPONENT_ACCURACY, "TestllVecNorm vector check fail on z component"); + } + } +} diff --git a/Tests/OpenSim.Region.ScriptEngine.Tests/Shared/Tests/LSL_ApiUserTests.cs b/Tests/OpenSim.Region.ScriptEngine.Tests/Shared/Tests/LSL_ApiUserTests.cs new file mode 100644 index 00000000000..70a3a9e3daf --- /dev/null +++ b/Tests/OpenSim.Region.ScriptEngine.Tests/Shared/Tests/LSL_ApiUserTests.cs @@ -0,0 +1,157 @@ +/* + * 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 System.Threading; +using Nini.Config; +using NUnit.Framework; +using OpenMetaverse; +using OpenSim.Framework; +using OpenSim.Region.Framework.Scenes; +using OpenSim.Region.ScriptEngine.Shared.Api; +using OpenSim.Region.ScriptEngine.Shared.ScriptBase; +using OpenSim.Services.Interfaces; +using OpenSim.Tests.Common; + +namespace OpenSim.Region.ScriptEngine.Shared.Tests +{ + [TestFixture] + public class LSL_ApiUserTests : OpenSimTestCase + { + private Scene m_scene; + private MockScriptEngine m_engine; + + [SetUp] + public override void SetUp() + { + base.SetUp(); + + m_engine = new MockScriptEngine(); + + m_scene = new SceneHelpers().SetupScene(); + SceneHelpers.SetupSceneModules(m_scene, m_engine); + } + + [Test] + public void TestLlRequestAgentDataOnline() + { + TestHelpers.InMethod(); +// TestHelpers.EnableLogging(); + + UUID userId = TestHelpers.ParseTail(0x1); + + UserAccount ua1 = UserAccountHelpers.CreateUserWithInventory(m_scene, userId); + + SceneObjectPart part = SceneHelpers.AddSceneObject(m_scene).RootPart; + TaskInventoryItem scriptItem = TaskInventoryHelpers.AddScript(m_scene.AssetService, part); + + LSL_Api apiGrp1 = new LSL_Api(); + apiGrp1.Initialize(m_engine, part, scriptItem); + + // Initially long timeout to test cache + apiGrp1.LlRequestAgentDataCacheTimeoutMs = 20000; + + // Offline test + { + apiGrp1.llRequestAgentData(userId.ToString(), ScriptBaseClass.DATA_ONLINE); + + Assert.That(m_engine.PostedEvents.ContainsKey(scriptItem.ItemID)); + + List events = m_engine.PostedEvents[scriptItem.ItemID]; + Assert.That(events.Count, Is.EqualTo(1)); + EventParams eventParams = events[0]; + Assert.That(eventParams.EventName, Is.EqualTo("dataserver")); + + string data = eventParams.Params[1].ToString(); + Assert.AreEqual(0, int.Parse(data)); + + m_engine.PostedEvents.Clear(); + } + + // Online test. Should get the 'wrong' result because of caching. + ScenePresence sp = SceneHelpers.AddScenePresence(m_scene, ua1); + + { + apiGrp1.llRequestAgentData(userId.ToString(), ScriptBaseClass.DATA_ONLINE); + + Assert.That(m_engine.PostedEvents.ContainsKey(scriptItem.ItemID)); + + List events = m_engine.PostedEvents[scriptItem.ItemID]; + Assert.That(events.Count, Is.EqualTo(1)); + EventParams eventParams = events[0]; + Assert.That(eventParams.EventName, Is.EqualTo("dataserver")); + + string data = eventParams.Params[1].ToString(); + Assert.AreEqual(0, int.Parse(data)); + + m_engine.PostedEvents.Clear(); + } + + apiGrp1.LlRequestAgentDataCacheTimeoutMs = 20; + + // Make absolutely sure that we should trigger cache timeout. + Thread.Sleep(apiGrp1.LlRequestAgentDataCacheTimeoutMs + 50); + + { + apiGrp1.llRequestAgentData(userId.ToString(), ScriptBaseClass.DATA_ONLINE); + + Assert.That(m_engine.PostedEvents.ContainsKey(scriptItem.ItemID)); + + List events = m_engine.PostedEvents[scriptItem.ItemID]; + Assert.That(events.Count, Is.EqualTo(1)); + EventParams eventParams = events[0]; + Assert.That(eventParams.EventName, Is.EqualTo("dataserver")); + + string data = eventParams.Params[1].ToString(); + Assert.AreEqual(1, int.Parse(data)); + + m_engine.PostedEvents.Clear(); + } + + m_scene.CloseAgent(userId, false); + + Thread.Sleep(apiGrp1.LlRequestAgentDataCacheTimeoutMs + 50); + + { + apiGrp1.llRequestAgentData(userId.ToString(), ScriptBaseClass.DATA_ONLINE); + + Assert.That(m_engine.PostedEvents.ContainsKey(scriptItem.ItemID)); + + List events = m_engine.PostedEvents[scriptItem.ItemID]; + Assert.That(events.Count, Is.EqualTo(1)); + EventParams eventParams = events[0]; + Assert.That(eventParams.EventName, Is.EqualTo("dataserver")); + + string data = eventParams.Params[1].ToString(); + Assert.AreEqual(0, int.Parse(data)); + + m_engine.PostedEvents.Clear(); + } + } + } +} diff --git a/Tests/OpenSim.Region.ScriptEngine.Tests/Shared/Tests/LSL_TypesTestLSLFloat.cs b/Tests/OpenSim.Region.ScriptEngine.Tests/Shared/Tests/LSL_TypesTestLSLFloat.cs new file mode 100644 index 00000000000..f81e0af04d8 --- /dev/null +++ b/Tests/OpenSim.Region.ScriptEngine.Tests/Shared/Tests/LSL_TypesTestLSLFloat.cs @@ -0,0 +1,661 @@ +/* + * 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.Collections.Generic; +using NUnit.Framework; +using OpenSim.Tests.Common; +using OpenSim.Region.ScriptEngine.Shared; + +namespace OpenSim.Region.ScriptEngine.Shared.Tests +{ + [TestFixture] + public class LSL_TypesTestLSLFloat : OpenSimTestCase + { + // Used for testing equality of two floats. + private double _lowPrecisionTolerance = 0.000001; + + private Dictionary m_intDoubleSet; + private Dictionary m_doubleDoubleSet; + private Dictionary m_doubleIntSet; + private Dictionary m_doubleUintSet; + private Dictionary m_stringDoubleSet; + private Dictionary m_doubleStringSet; + private List m_intList; + private List m_doubleList; + + /// + /// Sets up dictionaries and arrays used in the tests. + /// + [OneTimeSetUp] + public void SetUpDataSets() + { + m_intDoubleSet = new Dictionary(); + m_intDoubleSet.Add(2, 2.0); + m_intDoubleSet.Add(-2, -2.0); + m_intDoubleSet.Add(0, 0.0); + m_intDoubleSet.Add(1, 1.0); + m_intDoubleSet.Add(-1, -1.0); + m_intDoubleSet.Add(999999999, 999999999.0); + m_intDoubleSet.Add(-99999999, -99999999.0); + + m_doubleDoubleSet = new Dictionary(); + m_doubleDoubleSet.Add(2.0, 2.0); + m_doubleDoubleSet.Add(-2.0, -2.0); + m_doubleDoubleSet.Add(0.0, 0.0); + m_doubleDoubleSet.Add(1.0, 1.0); + m_doubleDoubleSet.Add(-1.0, -1.0); + m_doubleDoubleSet.Add(999999999.0, 999999999.0); + m_doubleDoubleSet.Add(-99999999.0, -99999999.0); + m_doubleDoubleSet.Add(0.5, 0.5); + m_doubleDoubleSet.Add(0.0005, 0.0005); + m_doubleDoubleSet.Add(0.6805, 0.6805); + m_doubleDoubleSet.Add(-0.5, -0.5); + m_doubleDoubleSet.Add(-0.0005, -0.0005); + m_doubleDoubleSet.Add(-0.6805, -0.6805); + m_doubleDoubleSet.Add(548.5, 548.5); + m_doubleDoubleSet.Add(2.0005, 2.0005); + m_doubleDoubleSet.Add(349485435.6805, 349485435.6805); + m_doubleDoubleSet.Add(-548.5, -548.5); + m_doubleDoubleSet.Add(-2.0005, -2.0005); + m_doubleDoubleSet.Add(-349485435.6805, -349485435.6805); + + m_doubleIntSet = new Dictionary(); + m_doubleIntSet.Add(2.0, 2); + m_doubleIntSet.Add(-2.0, -2); + m_doubleIntSet.Add(0.0, 0); + m_doubleIntSet.Add(1.0, 1); + m_doubleIntSet.Add(-1.0, -1); + m_doubleIntSet.Add(999999999.0, 999999999); + m_doubleIntSet.Add(-99999999.0, -99999999); + m_doubleIntSet.Add(0.5, 0); + m_doubleIntSet.Add(0.0005, 0); + m_doubleIntSet.Add(0.6805, 0); + m_doubleIntSet.Add(-0.5, 0); + m_doubleIntSet.Add(-0.0005, 0); + m_doubleIntSet.Add(-0.6805, 0); + m_doubleIntSet.Add(548.5, 548); + m_doubleIntSet.Add(2.0005, 2); + m_doubleIntSet.Add(349485435.6805, 349485435); + m_doubleIntSet.Add(-548.5, -548); + m_doubleIntSet.Add(-2.0005, -2); + m_doubleIntSet.Add(-349485435.6805, -349485435); + + m_doubleUintSet = new Dictionary(); + m_doubleUintSet.Add(2.0, 2); + m_doubleUintSet.Add(-2.0, 2); + m_doubleUintSet.Add(0.0, 0); + m_doubleUintSet.Add(1.0, 1); + m_doubleUintSet.Add(-1.0, 1); + m_doubleUintSet.Add(999999999.0, 999999999); + m_doubleUintSet.Add(-99999999.0, 99999999); + m_doubleUintSet.Add(0.5, 0); + m_doubleUintSet.Add(0.0005, 0); + m_doubleUintSet.Add(0.6805, 0); + m_doubleUintSet.Add(-0.5, 0); + m_doubleUintSet.Add(-0.0005, 0); + m_doubleUintSet.Add(-0.6805, 0); + m_doubleUintSet.Add(548.5, 548); + m_doubleUintSet.Add(2.0005, 2); + m_doubleUintSet.Add(349485435.6805, 349485435); + m_doubleUintSet.Add(-548.5, 548); + m_doubleUintSet.Add(-2.0005, 2); + m_doubleUintSet.Add(-349485435.6805, 349485435); + + m_stringDoubleSet = new Dictionary(); + m_stringDoubleSet.Add("2", 2.0); + m_stringDoubleSet.Add("-2", -2.0); + m_stringDoubleSet.Add("1", 1.0); + m_stringDoubleSet.Add("-1", -1.0); + m_stringDoubleSet.Add("0", 0.0); + m_stringDoubleSet.Add("999999999.0", 999999999.0); + m_stringDoubleSet.Add("-99999999.0", -99999999.0); + m_stringDoubleSet.Add("0.5", 0.5); + m_stringDoubleSet.Add("0.0005", 0.0005); + m_stringDoubleSet.Add("0.6805", 0.6805); + m_stringDoubleSet.Add("-0.5", -0.5); + m_stringDoubleSet.Add("-0.0005", -0.0005); + m_stringDoubleSet.Add("-0.6805", -0.6805); + m_stringDoubleSet.Add("548.5", 548.5); + m_stringDoubleSet.Add("2.0005", 2.0005); + m_stringDoubleSet.Add("349485435.6805", 349485435.6805); + m_stringDoubleSet.Add("-548.5", -548.5); + m_stringDoubleSet.Add("-2.0005", -2.0005); + m_stringDoubleSet.Add("-349485435.6805", -349485435.6805); + // some oddball combinations and exponents + m_stringDoubleSet.Add("", 0.0); + m_stringDoubleSet.Add("1.0E+5", 100000.0); + m_stringDoubleSet.Add("-1.0E+5", -100000.0); + m_stringDoubleSet.Add("-1E+5", -100000.0); + m_stringDoubleSet.Add("-1.E+5", -100000.0); + m_stringDoubleSet.Add("-1.E+5.0", -100000.0); + m_stringDoubleSet.Add("1ef", 1.0); + m_stringDoubleSet.Add("e10", 0.0); + m_stringDoubleSet.Add("1.e0.0", 1.0); + + m_doubleStringSet = new Dictionary(); + m_doubleStringSet.Add(2.0, "2.000000"); + m_doubleStringSet.Add(-2.0, "-2.000000"); + m_doubleStringSet.Add(1.0, "1.000000"); + m_doubleStringSet.Add(-1.0, "-1.000000"); + m_doubleStringSet.Add(0.0, "0.000000"); + m_doubleStringSet.Add(999999999.0, "999999999.000000"); + m_doubleStringSet.Add(-99999999.0, "-99999999.000000"); + m_doubleStringSet.Add(0.5, "0.500000"); + m_doubleStringSet.Add(0.0005, "0.000500"); + m_doubleStringSet.Add(0.6805, "0.680500"); + m_doubleStringSet.Add(-0.5, "-0.500000"); + m_doubleStringSet.Add(-0.0005, "-0.000500"); + m_doubleStringSet.Add(-0.6805, "-0.680500"); + m_doubleStringSet.Add(548.5, "548.500000"); + m_doubleStringSet.Add(2.0005, "2.000500"); + m_doubleStringSet.Add(349485435.6805, "349485435.680500"); + m_doubleStringSet.Add(-548.5, "-548.500000"); + m_doubleStringSet.Add(-2.0005, "-2.000500"); + m_doubleStringSet.Add(-349485435.6805, "-349485435.680500"); + + m_doubleList = new List(); + m_doubleList.Add(2.0); + m_doubleList.Add(-2.0); + m_doubleList.Add(1.0); + m_doubleList.Add(-1.0); + m_doubleList.Add(999999999.0); + m_doubleList.Add(-99999999.0); + m_doubleList.Add(0.5); + m_doubleList.Add(0.0005); + m_doubleList.Add(0.6805); + m_doubleList.Add(-0.5); + m_doubleList.Add(-0.0005); + m_doubleList.Add(-0.6805); + m_doubleList.Add(548.5); + m_doubleList.Add(2.0005); + m_doubleList.Add(349485435.6805); + m_doubleList.Add(-548.5); + m_doubleList.Add(-2.0005); + m_doubleList.Add(-349485435.6805); + + m_intList = new List(); + m_intList.Add(2); + m_intList.Add(-2); + m_intList.Add(0); + m_intList.Add(1); + m_intList.Add(-1); + m_intList.Add(999999999); + m_intList.Add(-99999999); + } + + /// + /// Tests constructing a LSLFloat from an integer. + /// + [Test] + public void TestConstructFromInt() + { + TestHelpers.InMethod(); + + LSL_Types.LSLFloat testFloat; + + foreach (KeyValuePair number in m_intDoubleSet) + { + testFloat = new LSL_Types.LSLFloat(number.Key); + Assert.That(testFloat.value, new DoubleToleranceConstraint(number.Value, _lowPrecisionTolerance)); + } + } + + /// + /// Tests constructing a LSLFloat from a double. + /// + [Test] + public void TestConstructFromDouble() + { + TestHelpers.InMethod(); + + LSL_Types.LSLFloat testFloat; + + foreach (KeyValuePair number in m_doubleDoubleSet) + { + testFloat = new LSL_Types.LSLFloat(number.Key); + Assert.That(testFloat.value, new DoubleToleranceConstraint(number.Value, _lowPrecisionTolerance)); + } + } + + /// + /// Tests LSLFloat is correctly cast explicitly to integer. + /// + [Test] + public void TestExplicitCastLSLFloatToInt() + { + TestHelpers.InMethod(); + + int testNumber; + + foreach (KeyValuePair number in m_doubleIntSet) + { + testNumber = (int) new LSL_Types.LSLFloat(number.Key); + Assert.AreEqual(number.Value, testNumber, "Converting double " + number.Key + ", expecting int " + number.Value); + } + } + + /// + /// Tests LSLFloat is correctly cast explicitly to unsigned integer. + /// + [Test] + public void TestExplicitCastLSLFloatToUint() + { + TestHelpers.InMethod(); + + uint testNumber; + + foreach (KeyValuePair number in m_doubleUintSet) + { + testNumber = (uint) new LSL_Types.LSLFloat(number.Key); + Assert.AreEqual(number.Value, testNumber, "Converting double " + number.Key + ", expecting uint " + number.Value); + } + } + + /// + /// Tests LSLFloat is correctly cast implicitly to Boolean if non-zero. + /// + [Test] + public void TestImplicitCastLSLFloatToBooleanTrue() + { + TestHelpers.InMethod(); + + LSL_Types.LSLFloat testFloat; + bool testBool; + + foreach (double number in m_doubleList) + { + testFloat = new LSL_Types.LSLFloat(number); + testBool = testFloat; + + Assert.IsTrue(testBool); + } + } + + /// + /// Tests LSLFloat is correctly cast implicitly to Boolean if zero. + /// + [Test] + public void TestImplicitCastLSLFloatToBooleanFalse() + { + TestHelpers.InMethod(); + + LSL_Types.LSLFloat testFloat = new LSL_Types.LSLFloat(0.0); + bool testBool = testFloat; + + Assert.IsFalse(testBool); + } + + /// + /// Tests integer is correctly cast implicitly to LSLFloat. + /// + [Test] + public void TestImplicitCastIntToLSLFloat() + { + TestHelpers.InMethod(); + + LSL_Types.LSLFloat testFloat; + + foreach (int number in m_intList) + { + testFloat = number; + Assert.That(testFloat.value, new DoubleToleranceConstraint(number, _lowPrecisionTolerance)); + } + } + + /// + /// Tests LSLInteger is correctly cast implicitly to LSLFloat. + /// + [Test] + public void TestImplicitCastLSLIntegerToLSLFloat() + { + TestHelpers.InMethod(); + + LSL_Types.LSLFloat testFloat; + + foreach (int number in m_intList) + { + testFloat = new LSL_Types.LSLInteger(number); + Assert.That(testFloat.value, new DoubleToleranceConstraint(number, _lowPrecisionTolerance)); + } + } + + /// + /// Tests LSLInteger is correctly cast explicitly to LSLFloat. + /// + [Test] + public void TestExplicitCastLSLIntegerToLSLFloat() + { + TestHelpers.InMethod(); + + LSL_Types.LSLFloat testFloat; + + foreach (int number in m_intList) + { + testFloat = (LSL_Types.LSLFloat) new LSL_Types.LSLInteger(number); + Assert.That(testFloat.value, new DoubleToleranceConstraint(number, _lowPrecisionTolerance)); + } + } + + /// + /// Tests string is correctly cast explicitly to LSLFloat. + /// + [Test] + public void TestExplicitCastStringToLSLFloat() + { + TestHelpers.InMethod(); + + LSL_Types.LSLFloat testFloat; + + foreach (KeyValuePair number in m_stringDoubleSet) + { + testFloat = (LSL_Types.LSLFloat) number.Key; + Assert.That(testFloat.value, new DoubleToleranceConstraint(number.Value, _lowPrecisionTolerance)); + } + } + + /// + /// Tests LSLString is correctly cast implicitly to LSLFloat. + /// + [Test] + public void TestExplicitCastLSLStringToLSLFloat() + { + TestHelpers.InMethod(); + + LSL_Types.LSLFloat testFloat; + + foreach (KeyValuePair number in m_stringDoubleSet) + { + testFloat = (LSL_Types.LSLFloat) new LSL_Types.LSLString(number.Key); + Assert.That(testFloat.value, new DoubleToleranceConstraint(number.Value, _lowPrecisionTolerance)); + } + } + + /// + /// Tests double is correctly cast implicitly to LSLFloat. + /// + [Test] + public void TestImplicitCastDoubleToLSLFloat() + { + TestHelpers.InMethod(); + + LSL_Types.LSLFloat testFloat; + + foreach (double number in m_doubleList) + { + testFloat = number; + Assert.That(testFloat.value, new DoubleToleranceConstraint(number, _lowPrecisionTolerance)); + } + } + + /// + /// Tests LSLFloat is correctly cast implicitly to double. + /// + [Test] + public void TestImplicitCastLSLFloatToDouble() + { + TestHelpers.InMethod(); + + double testNumber; + LSL_Types.LSLFloat testFloat; + + foreach (double number in m_doubleList) + { + testFloat = new LSL_Types.LSLFloat(number); + testNumber = testFloat; + + Assert.That(testNumber, new DoubleToleranceConstraint(number, _lowPrecisionTolerance)); + } + } + + /// + /// Tests LSLFloat is correctly cast explicitly to float + /// + [Test] + public void TestExplicitCastLSLFloatToFloat() + { + TestHelpers.InMethod(); + + float testFloat; + float numberAsFloat; + LSL_Types.LSLFloat testLSLFloat; + + foreach (double number in m_doubleList) + { + testLSLFloat = new LSL_Types.LSLFloat(number); + numberAsFloat = (float)number; + testFloat = (float)testLSLFloat; + + Assert.That((double)testFloat, new DoubleToleranceConstraint((double)numberAsFloat, _lowPrecisionTolerance)); + } + } + + /// + /// Tests the equality (==) operator. + /// + [Test] + public void TestEqualsOperator() + { + TestHelpers.InMethod(); + + LSL_Types.LSLFloat testFloatA, testFloatB; + + foreach (double number in m_doubleList) + { + testFloatA = new LSL_Types.LSLFloat(number); + testFloatB = new LSL_Types.LSLFloat(number); + Assert.IsTrue(testFloatA == testFloatB); + + testFloatB = new LSL_Types.LSLFloat(number + 1.0); + Assert.IsFalse(testFloatA == testFloatB); + } + } + + /// + /// Tests the inequality (!=) operator. + /// + [Test] + public void TestNotEqualOperator() + { + TestHelpers.InMethod(); + + LSL_Types.LSLFloat testFloatA, testFloatB; + + foreach (double number in m_doubleList) + { + testFloatA = new LSL_Types.LSLFloat(number); + testFloatB = new LSL_Types.LSLFloat(number + 1.0); + Assert.IsTrue(testFloatA != testFloatB); + + testFloatB = new LSL_Types.LSLFloat(number); + Assert.IsFalse(testFloatA != testFloatB); + } + } + + /// + /// Tests the increment operator. + /// + [Test] + public void TestIncrementOperator() + { + TestHelpers.InMethod(); + + LSL_Types.LSLFloat testFloat; + double testNumber; + + foreach (double number in m_doubleList) + { + testFloat = new LSL_Types.LSLFloat(number); + + testNumber = testFloat++; + Assert.That(testNumber, new DoubleToleranceConstraint(number, _lowPrecisionTolerance)); + + testNumber = testFloat; + Assert.That(testNumber, new DoubleToleranceConstraint(number + 1.0, _lowPrecisionTolerance)); + + testNumber = ++testFloat; + Assert.That(testNumber, new DoubleToleranceConstraint(number + 2.0, _lowPrecisionTolerance)); + } + } + + /// + /// Tests the decrement operator. + /// + [Test] + public void TestDecrementOperator() + { + TestHelpers.InMethod(); + + LSL_Types.LSLFloat testFloat; + double testNumber; + + foreach (double number in m_doubleList) + { + testFloat = new LSL_Types.LSLFloat(number); + + testNumber = testFloat--; + Assert.That(testNumber, new DoubleToleranceConstraint(number, _lowPrecisionTolerance)); + + testNumber = testFloat; + Assert.That(testNumber, new DoubleToleranceConstraint(number - 1.0, _lowPrecisionTolerance)); + + testNumber = --testFloat; + Assert.That(testNumber, new DoubleToleranceConstraint(number - 2.0, _lowPrecisionTolerance)); + } + } + + /// + /// Tests LSLFloat.ToString(). + /// + [Test] + public void TestToString() + { + TestHelpers.InMethod(); + + LSL_Types.LSLFloat testFloat; + + foreach (KeyValuePair number in m_doubleStringSet) + { + testFloat = new LSL_Types.LSLFloat(number.Key); + Assert.AreEqual(number.Value, testFloat.ToString()); + } + } + + /// + /// Tests addition of two LSLFloats. + /// + [Test] + public void TestAddTwoLSLFloats() + { + TestHelpers.InMethod(); + + LSL_Types.LSLFloat testResult; + + foreach (KeyValuePair number in m_doubleDoubleSet) + { + testResult = new LSL_Types.LSLFloat(number.Key) + new LSL_Types.LSLFloat(number.Value); + Assert.That(testResult.value, new DoubleToleranceConstraint(number.Key + number.Value, _lowPrecisionTolerance)); + } + } + + /// + /// Tests subtraction of two LSLFloats. + /// + [Test] + public void TestSubtractTwoLSLFloats() + { + TestHelpers.InMethod(); + + LSL_Types.LSLFloat testResult; + + foreach (KeyValuePair number in m_doubleDoubleSet) + { + testResult = new LSL_Types.LSLFloat(number.Key) - new LSL_Types.LSLFloat(number.Value); + Assert.That(testResult.value, new DoubleToleranceConstraint(number.Key - number.Value, _lowPrecisionTolerance)); + } + } + + /// + /// Tests multiplication of two LSLFloats. + /// + [Test] + public void TestMultiplyTwoLSLFloats() + { + TestHelpers.InMethod(); + + LSL_Types.LSLFloat testResult; + + foreach (KeyValuePair number in m_doubleDoubleSet) + { + testResult = new LSL_Types.LSLFloat(number.Key) * new LSL_Types.LSLFloat(number.Value); + Assert.That(testResult.value, new DoubleToleranceConstraint(number.Key * number.Value, _lowPrecisionTolerance)); + } + } + + /// + /// Tests division of two LSLFloats. + /// + [Test] + public void TestDivideTwoLSLFloats() + { + TestHelpers.InMethod(); + + LSL_Types.LSLFloat testResult; + + foreach (KeyValuePair number in m_doubleDoubleSet) + { + if (number.Value != 0.0) // Let's avoid divide by zero. + { + testResult = new LSL_Types.LSLFloat(number.Key) / new LSL_Types.LSLFloat(number.Value); + Assert.That(testResult.value, new DoubleToleranceConstraint(number.Key / number.Value, _lowPrecisionTolerance)); + } + } + } + + /// + /// Tests boolean correctly cast implicitly to LSLFloat. + /// + [Test] + public void TestImplicitCastBooleanToLSLFloat() + { + TestHelpers.InMethod(); + + LSL_Types.LSLFloat testFloat; + + testFloat = (1 == 0); + Assert.That(testFloat.value, new DoubleToleranceConstraint(0.0, _lowPrecisionTolerance)); + + testFloat = (1 == 1); + Assert.That(testFloat.value, new DoubleToleranceConstraint(1.0, _lowPrecisionTolerance)); + + testFloat = false; + Assert.That(testFloat.value, new DoubleToleranceConstraint(0.0, _lowPrecisionTolerance)); + + testFloat = true; + Assert.That(testFloat.value, new DoubleToleranceConstraint(1.0, _lowPrecisionTolerance)); + } + } +} \ No newline at end of file diff --git a/Tests/OpenSim.Region.ScriptEngine.Tests/Shared/Tests/LSL_TypesTestLSLInteger.cs b/Tests/OpenSim.Region.ScriptEngine.Tests/Shared/Tests/LSL_TypesTestLSLInteger.cs new file mode 100644 index 00000000000..41b5bcc0b8f --- /dev/null +++ b/Tests/OpenSim.Region.ScriptEngine.Tests/Shared/Tests/LSL_TypesTestLSLInteger.cs @@ -0,0 +1,150 @@ +/* + * 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.Collections.Generic; +using NUnit.Framework; +using OpenSim.Tests.Common; +using OpenSim.Region.ScriptEngine.Shared; + +namespace OpenSim.Region.ScriptEngine.Shared.Tests +{ + [TestFixture] + public class LSL_TypesTestLSLInteger : OpenSimTestCase + { + private Dictionary m_doubleIntSet; + private Dictionary m_stringIntSet; + + /// + /// Sets up dictionaries and arrays used in the tests. + /// + [OneTimeSetUp] + public void SetUpDataSets() + { + m_doubleIntSet = new Dictionary(); + m_doubleIntSet.Add(2.0, 2); + m_doubleIntSet.Add(-2.0, -2); + m_doubleIntSet.Add(0.0, 0); + m_doubleIntSet.Add(1.0, 1); + m_doubleIntSet.Add(-1.0, -1); + m_doubleIntSet.Add(999999999.0, 999999999); + m_doubleIntSet.Add(-99999999.0, -99999999); + + m_stringIntSet = new Dictionary(); + m_stringIntSet.Add("2", 2); + m_stringIntSet.Add("-2", -2); + m_stringIntSet.Add("0", 0); + m_stringIntSet.Add("1", 1); + m_stringIntSet.Add("-1", -1); + m_stringIntSet.Add("123.9", 123); + m_stringIntSet.Add("999999999", 999999999); + m_stringIntSet.Add("-99999999", -99999999); + m_stringIntSet.Add("", 0); + m_stringIntSet.Add("aa", 0); + m_stringIntSet.Add("56foo", 56); + m_stringIntSet.Add("42", 42); + m_stringIntSet.Add("42 is the answer", 42); + m_stringIntSet.Add(" 42", 42); + m_stringIntSet.Add("42,123,456", 42); + m_stringIntSet.Add("0xff", 255); + m_stringIntSet.Add("12345678900000", -1); + } + + /// + /// Tests LSLFloat is correctly cast explicitly to LSLInteger. + /// + [Test] + public void TestExplicitCastLSLFloatToLSLInteger() + { + TestHelpers.InMethod(); + + LSL_Types.LSLInteger testInteger; + + foreach (KeyValuePair number in m_doubleIntSet) + { + testInteger = (LSL_Types.LSLInteger) new LSL_Types.LSLFloat(number.Key); + Assert.AreEqual(testInteger.value, number.Value); + } + } + + /// + /// Tests string is correctly cast explicitly to LSLInteger. + /// + [Test] + public void TestExplicitCastStringToLSLInteger() + { + TestHelpers.InMethod(); + + LSL_Types.LSLInteger testInteger; + + foreach (KeyValuePair number in m_stringIntSet) + { + testInteger = (LSL_Types.LSLInteger) number.Key; + Assert.AreEqual(testInteger.value, number.Value); + } + } + + /// + /// Tests LSLString is correctly cast explicitly to LSLInteger. + /// + [Test] + public void TestExplicitCastLSLStringToLSLInteger() + { + TestHelpers.InMethod(); + + LSL_Types.LSLInteger testInteger; + + foreach (KeyValuePair number in m_stringIntSet) + { + testInteger = (LSL_Types.LSLInteger) new LSL_Types.LSLString(number.Key); + Assert.AreEqual(testInteger.value, number.Value); + } + } + + /// + /// Tests boolean correctly cast implicitly to LSLInteger. + /// + [Test] + public void TestImplicitCastBooleanToLSLInteger() + { + TestHelpers.InMethod(); + + LSL_Types.LSLInteger testInteger; + + testInteger = (1 == 0); + Assert.AreEqual(0, testInteger.value); + + testInteger = (1 == 1); + Assert.AreEqual(1, testInteger.value); + + testInteger = false; + Assert.AreEqual(0, testInteger.value); + + testInteger = true; + Assert.AreEqual(1, testInteger.value); + } + } +} diff --git a/Tests/OpenSim.Region.ScriptEngine.Tests/Shared/Tests/LSL_TypesTestLSLString.cs b/Tests/OpenSim.Region.ScriptEngine.Tests/Shared/Tests/LSL_TypesTestLSLString.cs new file mode 100644 index 00000000000..70c1a381c06 --- /dev/null +++ b/Tests/OpenSim.Region.ScriptEngine.Tests/Shared/Tests/LSL_TypesTestLSLString.cs @@ -0,0 +1,144 @@ +/* + * 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.Collections.Generic; +using NUnit.Framework; +using OpenSim.Tests.Common; +using OpenSim.Region.ScriptEngine.Shared; + +namespace OpenSim.Region.ScriptEngine.Shared.Tests +{ + [TestFixture] + public class LSL_TypesTestLSLString : OpenSimTestCase + { + private Dictionary m_doubleStringSet; + + /// + /// Sets up dictionaries and arrays used in the tests. + /// + [OneTimeSetUp] + public void SetUpDataSets() + { + m_doubleStringSet = new Dictionary(); + m_doubleStringSet.Add(2, "2.000000"); + m_doubleStringSet.Add(-2, "-2.000000"); + m_doubleStringSet.Add(0, "0.000000"); + m_doubleStringSet.Add(1, "1.000000"); + m_doubleStringSet.Add(-1, "-1.000000"); + m_doubleStringSet.Add(999999999, "999999999.000000"); + m_doubleStringSet.Add(-99999999, "-99999999.000000"); + m_doubleStringSet.Add(0.5, "0.500000"); + m_doubleStringSet.Add(0.0005, "0.000500"); + m_doubleStringSet.Add(0.6805, "0.680500"); + m_doubleStringSet.Add(-0.5, "-0.500000"); + m_doubleStringSet.Add(-0.0005, "-0.000500"); + m_doubleStringSet.Add(-0.6805, "-0.680500"); + m_doubleStringSet.Add(548.5, "548.500000"); + m_doubleStringSet.Add(2.0005, "2.000500"); + m_doubleStringSet.Add(349485435.6805, "349485435.680500"); + m_doubleStringSet.Add(-548.5, "-548.500000"); + m_doubleStringSet.Add(-2.0005, "-2.000500"); + m_doubleStringSet.Add(-349485435.6805, "-349485435.680500"); + } + + /// + /// Tests constructing a LSLString from an LSLFloat. + /// + [Test] + public void TestConstructFromLSLFloat() + { + TestHelpers.InMethod(); + + LSL_Types.LSLString testString; + + foreach (KeyValuePair number in m_doubleStringSet) + { + testString = new LSL_Types.LSLString(new LSL_Types.LSLFloat(number.Key)); + Assert.AreEqual(number.Value, testString.m_string); + } + } + + /// + /// Tests constructing a LSLString from an LSLFloat. + /// + [Test] + public void TestExplicitCastLSLFloatToLSLString() + { + TestHelpers.InMethod(); + + LSL_Types.LSLString testString; + + foreach (KeyValuePair number in m_doubleStringSet) + { + testString = (LSL_Types.LSLString) new LSL_Types.LSLFloat(number.Key); + Assert.AreEqual(number.Value, testString.m_string); + } + } + + /// + /// Test constructing a Quaternion from a string. + /// + [Test] + public void TestExplicitCastLSLStringToQuaternion() + { + TestHelpers.InMethod(); + + string quaternionString = "<0.00000, 0.70711, 0.00000, 0.70711>"; + LSL_Types.LSLString quaternionLSLString = new LSL_Types.LSLString(quaternionString); + + LSL_Types.Quaternion expectedQuaternion = new LSL_Types.Quaternion(0.0, 0.70711, 0.0, 0.70711); + LSL_Types.Quaternion stringQuaternion = (LSL_Types.Quaternion) quaternionString; + LSL_Types.Quaternion LSLStringQuaternion = (LSL_Types.Quaternion) quaternionLSLString; + + Assert.AreEqual(expectedQuaternion, stringQuaternion); + Assert.AreEqual(expectedQuaternion, LSLStringQuaternion); + } + + /// + /// Tests boolean correctly cast explicitly to LSLString. + /// + [Test] + public void TestImplicitCastBooleanToLSLFloat() + { + TestHelpers.InMethod(); + + LSL_Types.LSLString testString; + + testString = (LSL_Types.LSLString) (1 == 0); + Assert.AreEqual("0", testString.m_string); + + testString = (LSL_Types.LSLString) (1 == 1); + Assert.AreEqual("1", testString.m_string); + + testString = (LSL_Types.LSLString) false; + Assert.AreEqual("0", testString.m_string); + + testString = (LSL_Types.LSLString) true; + Assert.AreEqual("1", testString.m_string); + } + } +} diff --git a/Tests/OpenSim.Region.ScriptEngine.Tests/Shared/Tests/LSL_TypesTestList.cs b/Tests/OpenSim.Region.ScriptEngine.Tests/Shared/Tests/LSL_TypesTestList.cs new file mode 100644 index 00000000000..fe2113bd561 --- /dev/null +++ b/Tests/OpenSim.Region.ScriptEngine.Tests/Shared/Tests/LSL_TypesTestList.cs @@ -0,0 +1,295 @@ +/* + * 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.Collections.Generic; +using NUnit.Framework; +using OpenSim.Tests.Common; +using OpenSim.Region.ScriptEngine.Shared; + +namespace OpenSim.Region.ScriptEngine.Shared.Tests +{ + /// + /// Tests the LSL_Types.list class. + /// + [TestFixture] + public class LSL_TypesTestList : OpenSimTestCase + { + /// + /// Tests concatenating a string to a list. + /// + [Test] + public void TestConcatenateString() + { + TestHelpers.InMethod(); + + LSL_Types.list testList = new LSL_Types.list(new LSL_Types.LSLInteger(1), new LSL_Types.LSLInteger('a'), new LSL_Types.LSLString("test")); + testList += new LSL_Types.LSLString("addition"); + + Assert.AreEqual(4, testList.Length); + Assert.AreEqual(new LSL_Types.LSLString("addition"), testList.Data[3]); + Assert.AreEqual(typeof(LSL_Types.LSLString), testList.Data[3].GetType()); + + LSL_Types.list secondTestList = testList + new LSL_Types.LSLString("more"); + + Assert.AreEqual(5, secondTestList.Length); + Assert.AreEqual(new LSL_Types.LSLString("more"), secondTestList.Data[4]); + Assert.AreEqual(typeof(LSL_Types.LSLString), secondTestList.Data[4].GetType()); + } + + /// + /// Tests concatenating an integer to a list. + /// + [Test] + public void TestConcatenateInteger() + { + TestHelpers.InMethod(); + + LSL_Types.list testList = new LSL_Types.list(new LSL_Types.LSLInteger(1), new LSL_Types.LSLInteger('a'), new LSL_Types.LSLString("test")); + testList += new LSL_Types.LSLInteger(20); + + Assert.AreEqual(4, testList.Length); + Assert.AreEqual(new LSL_Types.LSLInteger(20), testList.Data[3]); + Assert.AreEqual(typeof(LSL_Types.LSLInteger), testList.Data[3].GetType()); + + LSL_Types.list secondTestList = testList + new LSL_Types.LSLInteger(2); + + Assert.AreEqual(5, secondTestList.Length); + Assert.AreEqual(new LSL_Types.LSLInteger(2), secondTestList.Data[4]); + Assert.AreEqual(typeof(LSL_Types.LSLInteger), secondTestList.Data[4].GetType()); + } + + /// + /// Tests concatenating a float to a list. + /// + [Test] + public void TestConcatenateDouble() + { + TestHelpers.InMethod(); + + LSL_Types.list testList = new LSL_Types.list(new LSL_Types.LSLInteger(1), new LSL_Types.LSLInteger('a'), new LSL_Types.LSLString("test")); + testList += new LSL_Types.LSLFloat(2.0f); + + Assert.AreEqual(4, testList.Length); + Assert.AreEqual(new LSL_Types.LSLFloat(2.0f), testList.Data[3]); + Assert.AreEqual(typeof(LSL_Types.LSLFloat), testList.Data[3].GetType()); + + LSL_Types.list secondTestList = testList + new LSL_Types.LSLFloat(0.04f); + + Assert.AreEqual(5, secondTestList.Length); + Assert.AreEqual(new LSL_Types.LSLFloat(0.04f), secondTestList.Data[4]); + Assert.AreEqual(typeof(LSL_Types.LSLFloat), secondTestList.Data[4].GetType()); + } + + /// + /// Tests casting LSLInteger item to LSLInteger. + /// + [Test] + public void TestCastLSLIntegerItemToLSLInteger() + { + TestHelpers.InMethod(); + + LSL_Types.LSLInteger testValue = new LSL_Types.LSLInteger(123); + LSL_Types.list testList = new LSL_Types.list(testValue); + + Assert.AreEqual(testValue, (LSL_Types.LSLInteger)testList.Data[0]); + } + + /// + /// Tests casting LSLFloat item to LSLFloat. + /// + [Test] + public void TestCastLSLFloatItemToLSLFloat() + { + TestHelpers.InMethod(); + + LSL_Types.LSLFloat testValue = new LSL_Types.LSLFloat(123.45678987); + LSL_Types.list testList = new LSL_Types.list(testValue); + + Assert.AreEqual(testValue, (LSL_Types.LSLFloat)testList.Data[0]); + } + + /// + /// Tests casting LSLString item to LSLString. + /// + [Test] + public void TestCastLSLStringItemToLSLString() + { + TestHelpers.InMethod(); + + LSL_Types.LSLString testValue = new LSL_Types.LSLString("hello there"); + LSL_Types.list testList = new LSL_Types.list(testValue); + + Assert.AreEqual(testValue, (LSL_Types.LSLString)testList.Data[0]); + } + + /// + /// Tests casting Vector3 item to Vector3. + /// + [Test] + public void TestCastVector3ItemToVector3() + { + TestHelpers.InMethod(); + + LSL_Types.Vector3 testValue = new LSL_Types.Vector3(12.34, 56.987654, 0.00987); + LSL_Types.list testList = new LSL_Types.list(testValue); + + Assert.AreEqual(testValue, (LSL_Types.Vector3)testList.Data[0]); + } + /// + /// Tests casting Quaternion item to Quaternion. + /// + [Test] + public void TestCastQuaternionItemToQuaternion() + { + TestHelpers.InMethod(); + + LSL_Types.Quaternion testValue = new LSL_Types.Quaternion(12.34, 56.44323, 765.983421, 0.00987); + LSL_Types.list testList = new LSL_Types.list(testValue); + + Assert.AreEqual(testValue, (LSL_Types.Quaternion)testList.Data[0]); + } + +//==================================================================================== + + /// + /// Tests GetLSLIntegerItem for LSLInteger item. + /// + [Test] + public void TestGetLSLIntegerItemForLSLIntegerItem() + { + TestHelpers.InMethod(); + + LSL_Types.LSLInteger testValue = new LSL_Types.LSLInteger(999911); + LSL_Types.list testList = new LSL_Types.list(testValue); + + Assert.AreEqual(testValue, testList.GetLSLIntegerItem(0)); + } + + /// + /// Tests GetLSLFloatItem for LSLFloat item. + /// + [Test] + public void TestGetLSLFloatItemForLSLFloatItem() + { + TestHelpers.InMethod(); + + LSL_Types.LSLFloat testValue = new LSL_Types.LSLFloat(321.45687876); + LSL_Types.list testList = new LSL_Types.list(testValue); + + Assert.AreEqual(testValue, testList.GetLSLFloatItem(0)); + } + + /// + /// Tests GetLSLFloatItem for LSLInteger item. + /// + [Test] + public void TestGetLSLFloatItemForLSLIntegerItem() + { + TestHelpers.InMethod(); + + LSL_Types.LSLInteger testValue = new LSL_Types.LSLInteger(3060987); + LSL_Types.LSLFloat testFloatValue = new LSL_Types.LSLFloat(testValue); + LSL_Types.list testList = new LSL_Types.list(testValue); + + Assert.AreEqual(testFloatValue, testList.GetLSLFloatItem(0)); + } + + /// + /// Tests GetLSLStringItem for LSLString item. + /// + [Test] + public void TestGetLSLStringItemForLSLStringItem() + { + TestHelpers.InMethod(); + + LSL_Types.LSLString testValue = new LSL_Types.LSLString("hello all"); + LSL_Types.list testList = new LSL_Types.list(testValue); + + Assert.AreEqual(testValue, testList.GetLSLStringItem(0)); + } + + /// + /// Tests GetLSLStringItem for key item. + /// + [Test] + public void TestGetLSLStringItemForKeyItem() + { + TestHelpers.InMethod(); + + LSL_Types.key testValue + = new LSL_Types.key("98000000-0000-2222-3333-100000001000"); + LSL_Types.LSLString testStringValue = new LSL_Types.LSLString(testValue); + LSL_Types.list testList = new LSL_Types.list(testValue); + + Assert.AreEqual(testStringValue, testList.GetLSLStringItem(0)); + } + + /// + /// Tests GetVector3Item for Vector3 item. + /// + [Test] + public void TestGetVector3ItemForVector3Item() + { + TestHelpers.InMethod(); + + LSL_Types.Vector3 testValue = new LSL_Types.Vector3(92.34, 58.98754, -0.10987); + LSL_Types.list testList = new LSL_Types.list(testValue); + + Assert.AreEqual(testValue, testList.GetVector3Item(0)); + } + /// + /// Tests GetQuaternionItem for Quaternion item. + /// + [Test] + public void TestGetQuaternionItemForQuaternionItem() + { + TestHelpers.InMethod(); + + LSL_Types.Quaternion testValue = new LSL_Types.Quaternion(12.64, 59.43723, 765.3421, 4.00987); + // make that nonsense a quaternion + testValue.Normalize(); + LSL_Types.list testList = new LSL_Types.list(testValue); + + Assert.AreEqual(testValue, testList.GetQuaternionItem(0)); + } + + /// + /// Tests GetKeyItem for key item. + /// + [Test] + public void TestGetKeyItemForKeyItem() + { + TestHelpers.InMethod(); + + LSL_Types.key testValue + = new LSL_Types.key("00000000-0000-2222-3333-100000001012"); + LSL_Types.list testList = new LSL_Types.list(testValue); + + Assert.AreEqual(testValue, testList.GetKeyItem(0)); + } + } +} \ No newline at end of file diff --git a/Tests/OpenSim.Region.ScriptEngine.Tests/Shared/Tests/LSL_TypesTestVector3.cs b/Tests/OpenSim.Region.ScriptEngine.Tests/Shared/Tests/LSL_TypesTestVector3.cs new file mode 100644 index 00000000000..0c838afa3c7 --- /dev/null +++ b/Tests/OpenSim.Region.ScriptEngine.Tests/Shared/Tests/LSL_TypesTestVector3.cs @@ -0,0 +1,63 @@ +/* + * 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.Collections.Generic; +using NUnit.Framework; +using OpenSim.Tests.Common; +using OpenSim.Region.ScriptEngine.Shared; + +namespace OpenSim.Region.ScriptEngine.Shared.Tests +{ + /// + /// Tests for Vector3 + /// + [TestFixture] + public class LSL_TypesTestVector3 : OpenSimTestCase + { + [Test] + public void TestDotProduct() + { + TestHelpers.InMethod(); + + // The numbers we test for. + Dictionary expectsSet = new Dictionary(); + expectsSet.Add("<1, 2, 3> * <2, 3, 4>", 20.0); + expectsSet.Add("<1, 2, 3> * <0, 0, 0>", 0.0); + + double result; + string[] parts; + string[] delim = { "*" }; + + foreach (KeyValuePair ex in expectsSet) + { + parts = ex.Key.Split(delim, System.StringSplitOptions.None); + result = new LSL_Types.Vector3(parts[0]) * new LSL_Types.Vector3(parts[1]); + Assert.AreEqual(ex.Value, result); + } + } + } +} diff --git a/Tests/OpenSim.Region.ScriptEngine.Tests/Shared/Tests/OSSL_ApiAppearanceTest.cs b/Tests/OpenSim.Region.ScriptEngine.Tests/Shared/Tests/OSSL_ApiAppearanceTest.cs new file mode 100644 index 00000000000..60c78e37194 --- /dev/null +++ b/Tests/OpenSim.Region.ScriptEngine.Tests/Shared/Tests/OSSL_ApiAppearanceTest.cs @@ -0,0 +1,167 @@ +/* + * 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 System.Reflection; +using System.Text; +using log4net; +using Nini.Config; +using NUnit.Framework; +using OpenMetaverse; +using OpenMetaverse.Assets; +using OpenMetaverse.StructuredData; +using OpenSim.Framework; +using OpenSim.Region.CoreModules.Avatar.AvatarFactory; +using OpenSim.Region.OptionalModules.World.NPC; +using OpenSim.Region.Framework.Scenes; +using OpenSim.Region.ScriptEngine.Shared; +using OpenSim.Region.ScriptEngine.Shared.Api; +using OpenSim.Services.Interfaces; +using OpenSim.Tests.Common; + +namespace OpenSim.Region.ScriptEngine.Shared.Tests +{ + /// + /// Tests for OSSL_Api + /// + [TestFixture] + public class OSSL_ApiAppearanceTest : OpenSimTestCase + { + /* + protected Scene m_scene; + protected XEngine.XEngine m_engine; + + [SetUp] + public override void SetUp() + { + base.SetUp(); + + IConfigSource initConfigSource = new IniConfigSource(); + IConfig config = initConfigSource.AddConfig("XEngine"); + config.Set("Enabled", "true"); + + config = initConfigSource.AddConfig("NPC"); + config.Set("Enabled", "true"); + + config = initConfigSource.AddConfig("OSSL"); + config.Set("DebuggerSafe", false); + config.Set("AllowOSFunctions", "true"); + config.Set("OSFunctionThreatLevel", "Severe"); + + + m_scene = new SceneHelpers().SetupScene(); + SceneHelpers.SetupSceneModules(m_scene, initConfigSource, new AvatarFactoryModule(), new NPCModule()); + + m_engine = new XEngine.XEngine(); + m_engine.Initialise(initConfigSource); + m_engine.AddRegion(m_scene); + } + + [Test] + public void TestOsOwnerSaveAppearance() + { + TestHelpers.InMethod(); +// log4net.Config.XmlConfigurator.Configure(); + + UUID userId = TestHelpers.ParseTail(0x1); + float newHeight = 1.9f; + + ScenePresence sp = SceneHelpers.AddScenePresence(m_scene, userId); + sp.Appearance.AvatarHeight = newHeight; + SceneObjectGroup so = SceneHelpers.CreateSceneObject(1, userId, 0x10); + SceneObjectPart part = so.RootPart; + m_scene.AddSceneObject(so); + + OSSL_Api osslApi = new OSSL_Api(); + osslApi.Initialize(m_engine, part, null); + + string notecardName = "appearanceNc"; + + osslApi.osOwnerSaveAppearance(notecardName); + + IList items = part.Inventory.GetInventoryItems(notecardName); + Assert.That(items.Count, Is.EqualTo(1)); + + TaskInventoryItem ncItem = items[0]; + Assert.That(ncItem.Name, Is.EqualTo(notecardName)); + + AssetBase ncAsset = m_scene.AssetService.Get(ncItem.AssetID.ToString()); + Assert.That(ncAsset, Is.Not.Null); + + AssetNotecard anc = new AssetNotecard(UUID.Zero, ncAsset.Data); + anc.Decode(); + OSDMap appearanceOsd = (OSDMap)OSDParser.DeserializeLLSDXml(anc.BodyText); + AvatarAppearance savedAppearance = new AvatarAppearance(); + savedAppearance.Unpack(appearanceOsd); + + Assert.That(savedAppearance.AvatarHeight, Is.EqualTo(sp.Appearance.AvatarHeight)); + } + + [Test] + public void TestOsAgentSaveAppearance() + { + TestHelpers.InMethod(); +// log4net.Config.XmlConfigurator.Configure(); + + UUID ownerId = TestHelpers.ParseTail(0x1); + UUID nonOwnerId = TestHelpers.ParseTail(0x2); + float newHeight = 1.9f; + + ScenePresence sp = SceneHelpers.AddScenePresence(m_scene, nonOwnerId); + sp.Appearance.AvatarHeight = newHeight; + SceneObjectGroup so = SceneHelpers.CreateSceneObject(1, ownerId, 0x10); + SceneObjectPart part = so.RootPart; + m_scene.AddSceneObject(so); + + OSSL_Api osslApi = new OSSL_Api(); + osslApi.Initialize(m_engine, part, null); + + string notecardName = "appearanceNc"; + + osslApi.osAgentSaveAppearance(new LSL_Types.LSLString(nonOwnerId.ToString()), notecardName); + + IList items = part.Inventory.GetInventoryItems(notecardName); + Assert.That(items.Count, Is.EqualTo(1)); + + TaskInventoryItem ncItem = items[0]; + Assert.That(ncItem.Name, Is.EqualTo(notecardName)); + + AssetBase ncAsset = m_scene.AssetService.Get(ncItem.AssetID.ToString()); + Assert.That(ncAsset, Is.Not.Null); + + AssetNotecard anc = new AssetNotecard(UUID.Zero, ncAsset.Data); + anc.Decode(); + OSDMap appearanceOsd = (OSDMap)OSDParser.DeserializeLLSDXml(anc.BodyText); + AvatarAppearance savedAppearance = new AvatarAppearance(); + savedAppearance.Unpack(appearanceOsd); + + Assert.That(savedAppearance.AvatarHeight, Is.EqualTo(sp.Appearance.AvatarHeight)); + } + } + */ +} diff --git a/Tests/OpenSim.Region.ScriptEngine.Tests/Shared/Tests/OSSL_ApiAttachmentTests.cs b/Tests/OpenSim.Region.ScriptEngine.Tests/Shared/Tests/OSSL_ApiAttachmentTests.cs new file mode 100644 index 00000000000..4b13c1c3ea3 --- /dev/null +++ b/Tests/OpenSim.Region.ScriptEngine.Tests/Shared/Tests/OSSL_ApiAttachmentTests.cs @@ -0,0 +1,234 @@ +/* + * 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 System.Reflection; +using System.Text; +using log4net; +using Nini.Config; +using NUnit.Framework; +using OpenMetaverse; +using OpenMetaverse.Assets; +using OpenMetaverse.StructuredData; +using OpenSim.Framework; +using OpenSim.Region.CoreModules.Avatar.Attachments; +using OpenSim.Region.CoreModules.Framework.InventoryAccess; +using OpenSim.Region.Framework.Scenes; +using OpenSim.Region.ScriptEngine.Shared; +using OpenSim.Region.ScriptEngine.Shared.Api; +using OpenSim.Services.Interfaces; +using OpenSim.Tests.Common; + +namespace OpenSim.Region.ScriptEngine.Shared.Tests +{ + /// + /// Tests for OSSL attachment functions + /// + /// + /// TODO: Add tests for all functions + /// + [TestFixture] + public class OSSL_ApiAttachmentTests : OpenSimTestCase + { + protected Scene m_scene; + protected XEngine.XEngine m_engine; + + [SetUp] + public override void SetUp() + { + base.SetUp(); + + IConfigSource initConfigSource = new IniConfigSource(); + + IConfig xengineConfig = initConfigSource.AddConfig("XEngine"); + xengineConfig.Set("Enabled", "true"); + + IConfig oconfig = initConfigSource.AddConfig("OSSL"); + oconfig.Set("DebuggerSafe", false); + oconfig.Set("AllowOSFunctions", "true"); + oconfig.Set("OSFunctionThreatLevel", "Severe"); + + IConfig modulesConfig = initConfigSource.AddConfig("Modules"); + modulesConfig.Set("InventoryAccessModule", "BasicInventoryAccessModule"); + + m_scene = new SceneHelpers().SetupScene(); + SceneHelpers.SetupSceneModules( + m_scene, initConfigSource, new AttachmentsModule(), new BasicInventoryAccessModule()); + + m_engine = new XEngine.XEngine(); + m_engine.Initialise(initConfigSource); + m_engine.AddRegion(m_scene); + } + + [Test] + public void TestOsForceAttachToAvatarFromInventory() + { + TestHelpers.InMethod(); +// TestHelpers.EnableLogging(); + + string taskInvObjItemName = "sphere"; + UUID taskInvObjItemId = UUID.Parse("00000000-0000-0000-0000-100000000000"); + AttachmentPoint attachPoint = AttachmentPoint.Chin; + + UserAccount ua1 = UserAccountHelpers.CreateUserWithInventory(m_scene, 0x1); + ScenePresence sp = SceneHelpers.AddScenePresence(m_scene, ua1.PrincipalID); + SceneObjectGroup inWorldObj = SceneHelpers.AddSceneObject(m_scene, "inWorldObj", ua1.PrincipalID); + TaskInventoryItem scriptItem = TaskInventoryHelpers.AddScript(m_scene.AssetService, inWorldObj.RootPart); + + new LSL_Api().Initialize(m_engine, inWorldObj.RootPart, scriptItem); + OSSL_Api osslApi = new OSSL_Api(); + osslApi.Initialize(m_engine, inWorldObj.RootPart, scriptItem); + +// SceneObjectGroup sog1 = SceneHelpers.CreateSceneObject(1, ua1.PrincipalID); + + // Create an object embedded inside the first + TaskInventoryHelpers.AddSceneObject(m_scene.AssetService, inWorldObj.RootPart, taskInvObjItemName, taskInvObjItemId, ua1.PrincipalID); + + osslApi.osForceAttachToAvatarFromInventory(taskInvObjItemName, (int)attachPoint); + + // Check scene presence status + Assert.That(sp.HasAttachments(), Is.True); + List attachments = sp.GetAttachments(); + Assert.That(attachments.Count, Is.EqualTo(1)); + SceneObjectGroup attSo = attachments[0]; + Assert.That(attSo.Name, Is.EqualTo(taskInvObjItemName)); + Assert.That(attSo.AttachmentPoint, Is.EqualTo((uint)attachPoint)); + Assert.That(attSo.IsAttachment); + Assert.That(attSo.UsesPhysics, Is.False); + Assert.That(attSo.IsTemporary, Is.False); + + // Check appearance status + List attachmentsInAppearance = sp.Appearance.GetAttachments(); + Assert.That(attachmentsInAppearance.Count, Is.EqualTo(1)); + Assert.That(sp.Appearance.GetAttachpoint(attachmentsInAppearance[0].ItemID), Is.EqualTo((uint)attachPoint)); + } + + /// + /// Make sure we can't force attach anything other than objects. + /// + [Test] + public void TestOsForceAttachToAvatarFromInventoryNotObject() + { + TestHelpers.InMethod(); +// TestHelpers.EnableLogging(); + + string taskInvObjItemName = "sphere"; + UUID taskInvObjItemId = UUID.Parse("00000000-0000-0000-0000-100000000000"); + AttachmentPoint attachPoint = AttachmentPoint.Chin; + + UserAccount ua1 = UserAccountHelpers.CreateUserWithInventory(m_scene, 0x1); + ScenePresence sp = SceneHelpers.AddScenePresence(m_scene, ua1.PrincipalID); + SceneObjectGroup inWorldObj = SceneHelpers.AddSceneObject(m_scene, "inWorldObj", ua1.PrincipalID); + TaskInventoryItem scriptItem = TaskInventoryHelpers.AddScript(m_scene.AssetService, inWorldObj.RootPart); + + new LSL_Api().Initialize(m_engine, inWorldObj.RootPart, scriptItem); + OSSL_Api osslApi = new OSSL_Api(); + osslApi.Initialize(m_engine, inWorldObj.RootPart, scriptItem); + + // Create an object embedded inside the first + TaskInventoryHelpers.AddNotecard( + m_scene.AssetService, inWorldObj.RootPart, taskInvObjItemName, taskInvObjItemId, TestHelpers.ParseTail(0x900), "Hello World!"); + + bool exceptionCaught = false; + + try + { + osslApi.osForceAttachToAvatarFromInventory(taskInvObjItemName, (int)attachPoint); + } + catch (Exception) + { + exceptionCaught = true; + } + + Assert.That(exceptionCaught, Is.True); + + // Check scene presence status + Assert.That(sp.HasAttachments(), Is.False); + List attachments = sp.GetAttachments(); + Assert.That(attachments.Count, Is.EqualTo(0)); + + // Check appearance status + List attachmentsInAppearance = sp.Appearance.GetAttachments(); + Assert.That(attachmentsInAppearance.Count, Is.EqualTo(0)); + } + + [Test] + public void TestOsForceAttachToOtherAvatarFromInventory() + { + TestHelpers.InMethod(); +// TestHelpers.EnableLogging(); + + string taskInvObjItemName = "sphere"; + UUID taskInvObjItemId = UUID.Parse("00000000-0000-0000-0000-100000000000"); + AttachmentPoint attachPoint = AttachmentPoint.Chin; + + UserAccount ua1 = UserAccountHelpers.CreateUserWithInventory(m_scene, "user", "one", 0x1, "pass"); + UserAccount ua2 = UserAccountHelpers.CreateUserWithInventory(m_scene, "user", "two", 0x2, "pass"); + + ScenePresence sp = SceneHelpers.AddScenePresence(m_scene, ua1); + SceneObjectGroup inWorldObj = SceneHelpers.AddSceneObject(m_scene, "inWorldObj", ua1.PrincipalID); + TaskInventoryItem scriptItem = TaskInventoryHelpers.AddScript(m_scene.AssetService, inWorldObj.RootPart); + + new LSL_Api().Initialize(m_engine, inWorldObj.RootPart, scriptItem); + OSSL_Api osslApi = new OSSL_Api(); + osslApi.Initialize(m_engine, inWorldObj.RootPart, scriptItem); + + // Create an object embedded inside the first + TaskInventoryHelpers.AddSceneObject( + m_scene.AssetService, inWorldObj.RootPart, taskInvObjItemName, taskInvObjItemId, ua1.PrincipalID); + + ScenePresence sp2 = SceneHelpers.AddScenePresence(m_scene, ua2); + + osslApi.osForceAttachToOtherAvatarFromInventory(sp2.UUID.ToString(), taskInvObjItemName, (int)attachPoint); + + // Check scene presence status + Assert.That(sp.HasAttachments(), Is.False); + List attachments = sp.GetAttachments(); + Assert.That(attachments.Count, Is.EqualTo(0)); + + Assert.That(sp2.HasAttachments(), Is.True); + List attachments2 = sp2.GetAttachments(); + Assert.That(attachments2.Count, Is.EqualTo(1)); + SceneObjectGroup attSo = attachments2[0]; + Assert.That(attSo.Name, Is.EqualTo(taskInvObjItemName)); + Assert.That(attSo.OwnerID, Is.EqualTo(ua2.PrincipalID)); + Assert.That(attSo.AttachmentPoint, Is.EqualTo((uint)attachPoint)); + Assert.That(attSo.IsAttachment); + Assert.That(attSo.UsesPhysics, Is.False); + Assert.That(attSo.IsTemporary, Is.False); + + // Check appearance status + List attachmentsInAppearance = sp.Appearance.GetAttachments(); + Assert.That(attachmentsInAppearance.Count, Is.EqualTo(0)); + + List attachmentsInAppearance2 = sp2.Appearance.GetAttachments(); + Assert.That(attachmentsInAppearance2.Count, Is.EqualTo(1)); + Assert.That(sp2.Appearance.GetAttachpoint(attachmentsInAppearance2[0].ItemID), Is.EqualTo((uint)attachPoint)); + } + } +} diff --git a/Tests/OpenSim.Region.ScriptEngine.Tests/Shared/Tests/OSSL_ApiNpcTests.cs b/Tests/OpenSim.Region.ScriptEngine.Tests/Shared/Tests/OSSL_ApiNpcTests.cs new file mode 100644 index 00000000000..108998ed641 --- /dev/null +++ b/Tests/OpenSim.Region.ScriptEngine.Tests/Shared/Tests/OSSL_ApiNpcTests.cs @@ -0,0 +1,354 @@ +/* + * 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 System.Reflection; +using System.Text; +using log4net; +using Nini.Config; +using NUnit.Framework; +using OpenMetaverse; +using OpenMetaverse.Assets; +using OpenMetaverse.StructuredData; +using OpenSim.Framework; +using OpenSim.Region.CoreModules.Avatar.Attachments; +using OpenSim.Region.CoreModules.Avatar.AvatarFactory; +using OpenSim.Region.OptionalModules.World.NPC; +using OpenSim.Region.Framework.Scenes; +using OpenSim.Region.ScriptEngine.Shared; +using OpenSim.Region.ScriptEngine.Shared.Api; +using OpenSim.Region.ScriptEngine.Shared.ScriptBase; +using OpenSim.Services.Interfaces; +using OpenSim.Tests.Common; + +namespace OpenSim.Region.ScriptEngine.Shared.Tests +{ + /// + /// Tests for OSSL NPC API + /// + [TestFixture] + public class OSSL_NpcApiAppearanceTest : OpenSimTestCase + { + protected Scene m_scene; + protected XEngine.XEngine m_engine; + + [SetUp] + public override void SetUp() + { + base.SetUp(); + + IConfigSource initConfigSource = new IniConfigSource(); + IConfig config = initConfigSource.AddConfig("XEngine"); + config.Set("Enabled", "true"); + + config = initConfigSource.AddConfig("NPC"); + config.Set("Enabled", "true"); + + config = initConfigSource.AddConfig("OSSL"); + config.Set("DebuggerSafe", false); + config.Set("AllowOSFunctions", "true"); + config.Set("OSFunctionThreatLevel", "Severe"); + + m_scene = new SceneHelpers().SetupScene(); + SceneHelpers.SetupSceneModules( + m_scene, initConfigSource, new AvatarFactoryModule(), new AttachmentsModule(), new NPCModule()); + + m_engine = new XEngine.XEngine(); + m_engine.Initialise(initConfigSource); + m_engine.AddRegion(m_scene); + } + + /// + /// Test creation of an NPC where the appearance data comes from a notecard + /// + [Test] + public void TestOsNpcCreateUsingAppearanceFromNotecard() + { + TestHelpers.InMethod(); + + // Store an avatar with a different height from default in a notecard. + UUID userId = TestHelpers.ParseTail(0x1); + float newHeight = 1.9f; + + ScenePresence sp = SceneHelpers.AddScenePresence(m_scene, userId); + sp.Appearance.AvatarHeight = newHeight; + SceneObjectGroup so = SceneHelpers.CreateSceneObject(1, userId, 0x10); + SceneObjectPart part = so.RootPart; + m_scene.AddSceneObject(so); + + OSSL_Api osslApi = new OSSL_Api(); + osslApi.Initialize(m_engine, part, null); + + string notecardName = "appearanceNc"; + osslApi.osOwnerSaveAppearance(notecardName); + + // Try creating a bot using the appearance in the notecard. + string npcRaw = osslApi.osNpcCreate("Jane", "Doe", new LSL_Types.Vector3(128, 128, 128), notecardName); + Assert.That(npcRaw, Is.Not.Null); + + UUID npcId = new UUID(npcRaw); + ScenePresence npc = m_scene.GetScenePresence(npcId); + Assert.That(npc, Is.Not.Null); + Assert.That(npc.Appearance.AvatarHeight, Is.EqualTo(newHeight)); + } + + [Test] + public void TestOsNpcCreateNotExistingNotecard() + { + TestHelpers.InMethod(); + + UUID userId = TestHelpers.ParseTail(0x1); + + SceneObjectGroup so = SceneHelpers.CreateSceneObject(1, userId, 0x10); + m_scene.AddSceneObject(so); + + OSSL_Api osslApi = new OSSL_Api(); + osslApi.Initialize(m_engine, so.RootPart, null); + + bool gotExpectedException = false; + try + { + osslApi.osNpcCreate("Jane", "Doe", new LSL_Types.Vector3(128, 128, 128), "not existing notecard name"); + } + catch (ScriptException) + { + gotExpectedException = true; + } + + Assert.That(gotExpectedException, Is.True); + } + + /// + /// Test creation of an NPC where the appearance data comes from an avatar already in the region. + /// + [Test] + public void TestOsNpcCreateUsingAppearanceFromAvatar() + { + TestHelpers.InMethod(); +// TestHelpers.EnableLogging(); + + // Store an avatar with a different height from default in a notecard. + UUID userId = TestHelpers.ParseTail(0x1); + float newHeight = 1.9f; + + ScenePresence sp = SceneHelpers.AddScenePresence(m_scene, userId); + sp.Appearance.AvatarHeight = newHeight; + SceneObjectGroup so = SceneHelpers.CreateSceneObject(1, userId, 0x10); + SceneObjectPart part = so.RootPart; + m_scene.AddSceneObject(so); + + OSSL_Api osslApi = new OSSL_Api(); + osslApi.Initialize(m_engine, part, null); + + string notecardName = "appearanceNc"; + osslApi.osOwnerSaveAppearance(notecardName); + + // Try creating a bot using the existing avatar's appearance + string npcRaw = osslApi.osNpcCreate("Jane", "Doe", new LSL_Types.Vector3(128, 128, 128), sp.UUID.ToString()); + Assert.That(npcRaw, Is.Not.Null); + + UUID npcId = new UUID(npcRaw); + ScenePresence npc = m_scene.GetScenePresence(npcId); + Assert.That(npc, Is.Not.Null); + Assert.That(npc.Appearance.AvatarHeight, Is.EqualTo(newHeight)); + } + + [Test] + public void TestOsNpcLoadAppearance() + { + TestHelpers.InMethod(); + //TestHelpers.EnableLogging(); + + // Store an avatar with a different height from default in a notecard. + UUID userId = TestHelpers.ParseTail(0x1); + float firstHeight = 1.9f; + float secondHeight = 2.1f; + string firstAppearanceNcName = "appearanceNc1"; + string secondAppearanceNcName = "appearanceNc2"; + + ScenePresence sp = SceneHelpers.AddScenePresence(m_scene, userId); + sp.Appearance.AvatarHeight = firstHeight; + SceneObjectGroup so = SceneHelpers.CreateSceneObject(1, userId, 0x10); + SceneObjectPart part = so.RootPart; + m_scene.AddSceneObject(so); + + OSSL_Api osslApi = new OSSL_Api(); + osslApi.Initialize(m_engine, part, null); + + osslApi.osOwnerSaveAppearance(firstAppearanceNcName); + + string npcRaw + = osslApi.osNpcCreate("Jane", "Doe", new LSL_Types.Vector3(128, 128, 128), firstAppearanceNcName); + + // Create a second appearance notecard with a different height + sp.Appearance.AvatarHeight = secondHeight; + osslApi.osOwnerSaveAppearance(secondAppearanceNcName); + + osslApi.osNpcLoadAppearance(npcRaw, secondAppearanceNcName); + + UUID npcId = new UUID(npcRaw); + ScenePresence npc = m_scene.GetScenePresence(npcId); + Assert.That(npc, Is.Not.Null); + Assert.That(npc.Appearance.AvatarHeight, Is.EqualTo(secondHeight)); + } + + [Test] + public void TestOsNpcLoadAppearanceNotExistingNotecard() + { + TestHelpers.InMethod(); + + // Store an avatar with a different height from default in a notecard. + UUID userId = TestHelpers.ParseTail(0x1); + float firstHeight = 1.9f; +// float secondHeight = 2.1f; + string firstAppearanceNcName = "appearanceNc1"; + string secondAppearanceNcName = "appearanceNc2"; + + ScenePresence sp = SceneHelpers.AddScenePresence(m_scene, userId); + sp.Appearance.AvatarHeight = firstHeight; + SceneObjectGroup so = SceneHelpers.CreateSceneObject(1, userId, 0x10); + SceneObjectPart part = so.RootPart; + m_scene.AddSceneObject(so); + + OSSL_Api osslApi = new OSSL_Api(); + osslApi.Initialize(m_engine, part, null); + + osslApi.osOwnerSaveAppearance(firstAppearanceNcName); + + string npcRaw + = osslApi.osNpcCreate("Jane", "Doe", new LSL_Types.Vector3(128, 128, 128), firstAppearanceNcName); + + bool gotExpectedException = false; + try + { + osslApi.osNpcLoadAppearance(npcRaw, secondAppearanceNcName); + } + catch (ScriptException) + { + gotExpectedException = true; + } + + Assert.That(gotExpectedException, Is.True); + + UUID npcId = new UUID(npcRaw); + ScenePresence npc = m_scene.GetScenePresence(npcId); + Assert.That(npc, Is.Not.Null); + Assert.That(npc.Appearance.AvatarHeight, Is.EqualTo(firstHeight)); + } + + /// + /// Test removal of an owned NPC. + /// + [Test] + public void TestOsNpcRemoveOwned() + { + TestHelpers.InMethod(); + + // Store an avatar with a different height from default in a notecard. + UUID userId = TestHelpers.ParseTail(0x1); + UUID otherUserId = TestHelpers.ParseTail(0x2); + float newHeight = 1.9f; + + SceneHelpers.AddScenePresence(m_scene, otherUserId); + + ScenePresence sp = SceneHelpers.AddScenePresence(m_scene, userId); + sp.Appearance.AvatarHeight = newHeight; + + SceneObjectGroup so = SceneHelpers.CreateSceneObject(1, userId, 0x10); + SceneObjectPart part = so.RootPart; + m_scene.AddSceneObject(so); + + SceneObjectGroup otherSo = SceneHelpers.CreateSceneObject(1, otherUserId, 0x20); + SceneObjectPart otherPart = otherSo.RootPart; + m_scene.AddSceneObject(otherSo); + + OSSL_Api osslApi = new OSSL_Api(); + osslApi.Initialize(m_engine, part, null); + + OSSL_Api otherOsslApi = new OSSL_Api(); + otherOsslApi.Initialize(m_engine, otherPart, null); + + string notecardName = "appearanceNc"; + osslApi.osOwnerSaveAppearance(notecardName); + + string npcRaw + = osslApi.osNpcCreate( + "Jane", "Doe", new LSL_Types.Vector3(128, 128, 128), notecardName, ScriptBaseClass.OS_NPC_CREATOR_OWNED); + + otherOsslApi.osNpcRemove(npcRaw); + + // Should still be around + UUID npcId = new UUID(npcRaw); + ScenePresence npc = m_scene.GetScenePresence(npcId); + Assert.That(npc, Is.Not.Null); + + osslApi.osNpcRemove(npcRaw); + + npc = m_scene.GetScenePresence(npcId); + + // Now the owner deleted it and it's gone + Assert.That(npc, Is.Null); + } + + /// + /// Test removal of an unowned NPC. + /// + [Test] + public void TestOsNpcRemoveUnowned() + { + TestHelpers.InMethod(); +// log4net.Config.XmlConfigurator.Configure(); + + // Store an avatar with a different height from default in a notecard. + UUID userId = TestHelpers.ParseTail(0x1); + float newHeight = 1.9f; + + ScenePresence sp = SceneHelpers.AddScenePresence(m_scene, userId); + sp.Appearance.AvatarHeight = newHeight; + SceneObjectGroup so = SceneHelpers.CreateSceneObject(1, userId, 0x10); + SceneObjectPart part = so.RootPart; + m_scene.AddSceneObject(so); + + OSSL_Api osslApi = new OSSL_Api(); + osslApi.Initialize(m_engine, part, null); + + string notecardName = "appearanceNc"; + osslApi.osOwnerSaveAppearance(notecardName); + + string npcRaw + = osslApi.osNpcCreate( + "Jane", "Doe", new LSL_Types.Vector3(128, 128, 128), notecardName, ScriptBaseClass.OS_NPC_NOT_OWNED); + + osslApi.osNpcRemove(npcRaw); + + UUID npcId = new UUID(npcRaw); + ScenePresence npc = m_scene.GetScenePresence(npcId); + Assert.That(npc, Is.Null); + } + } +} diff --git a/Tests/OpenSim.Region.ScriptEngine.Tests/YEngine/XMREngXmrTestLs.cs b/Tests/OpenSim.Region.ScriptEngine.Tests/YEngine/XMREngXmrTestLs.cs new file mode 100644 index 00000000000..9f23a670630 --- /dev/null +++ b/Tests/OpenSim.Region.ScriptEngine.Tests/YEngine/XMREngXmrTestLs.cs @@ -0,0 +1,549 @@ +/* + * 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 log4net; +using System; +using System.Collections.Generic; +using System.IO; +using System.Reflection; +using System.Text; +using System.Threading; + +using LSL_Float = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLFloat; +using LSL_Integer = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLInteger; +using LSL_Key = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLString; +using LSL_List = OpenSim.Region.ScriptEngine.Shared.LSL_Types.list; +using LSL_Rotation = OpenSim.Region.ScriptEngine.Shared.LSL_Types.Quaternion; +using LSL_String = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLString; +using LSL_Vector = OpenSim.Region.ScriptEngine.Shared.LSL_Types.Vector3; + +using SharedEventParams = OpenSim.Region.ScriptEngine.Shared.EventParams; +using SharedScriptBaseClass = OpenSim.Region.ScriptEngine.Shared.ScriptBase.ScriptBaseClass; + +namespace OpenSim.Region.ScriptEngine.Yengine +{ + public partial class Yengine + { + + private void XmrTestLs(string[] args, int indx) + { + bool flagFull = false; + bool flagQueues = false; + bool flagTopCPU = false; + int maxScripts = 0x7FFFFFFF; + int numScripts = 0; + string outName = null; + XMRInstance[] instances; + + // Decode command line options. + for(int i = indx; i < args.Length; i++) + { + if(args[i] == "-full") + { + flagFull = true; + continue; + } + if(args[i] == "-help") + { + m_log.Info("[YEngine]: yeng ls -full -max= -out= -queues -topcpu"); + return; + } + if(args[i].StartsWith("-max=")) + { + try + { + maxScripts = Convert.ToInt32(args[i].Substring(5)); + } + catch(Exception e) + { + m_log.Error("[YEngine]: bad max " + args[i].Substring(5) + ": " + e.Message); + return; + } + continue; + } + if(args[i].StartsWith("-out=")) + { + outName = args[i].Substring(5); + continue; + } + if(args[i] == "-queues") + { + flagQueues = true; + continue; + } + if(args[i] == "-topcpu") + { + flagTopCPU = true; + continue; + } + if(args[i][0] == '-') + { + m_log.Error("[YEngine]: unknown option " + args[i] + ", try 'yeng ls -help'"); + return; + } + } + + TextWriter outFile = null; + if(outName != null) + { + try + { + outFile = File.CreateText(outName); + } + catch(Exception e) + { + m_log.Error("[YEngine]: error creating " + outName + ": " + e.Message); + return; + } + } + else + { + outFile = new LogInfoTextWriter(m_log); + } + + try + { + // Scan instance list to find those that match selection criteria. + if(!Monitor.TryEnter(m_InstancesDict, 100)) + { + m_log.Error("[YEngine]: deadlock m_LockedDict=" + m_LockedDict); + return; + } + try + { + instances = new XMRInstance[m_InstancesDict.Count]; + foreach(XMRInstance ins in m_InstancesDict.Values) + { + if(InstanceMatchesArgs(ins, args, indx)) + { + instances[numScripts++] = ins; + } + } + } + finally + { + Monitor.Exit(m_InstancesDict); + } + + // Maybe sort by descending CPU time. + if(flagTopCPU) + { + Array.Sort(instances, CompareInstancesByCPUTime); + } + + // Print the entries. + if(!flagFull) + { + outFile.WriteLine(" ItemID" + + " CPU(ms)" + + " NumEvents" + + " Status " + + " World Position " + + " :"); + } + for(int i = 0; (i < numScripts) && (i < maxScripts); i++) + { + outFile.WriteLine(instances[i].RunTestLs(flagFull)); + } + + // Print number of scripts that match selection criteria, + // even if we were told to print fewer. + outFile.WriteLine("total of {0} script(s)", numScripts); + + // If -queues given, print out queue contents too. + if(flagQueues) + { + LsQueue(outFile, "start", m_StartQueue, args, indx); + LsQueue(outFile, "sleep", m_SleepQueue, args, indx); + LsQueue(outFile, "yield", m_YieldQueue, args, indx); + } + } + finally + { + outFile.Close(); + } + } + + private void XmrTestPev(string[] args, int indx) + { + bool flagAll = false; + int numScripts = 0; + XMRInstance[] instances; + + // Decode command line options. + int i, j; + List selargs = new List(args.Length); + MethodInfo[] eventmethods = typeof(IEventHandlers).GetMethods(); + MethodInfo eventmethod; + for(i = indx; i < args.Length; i++) + { + string arg = args[i]; + if(arg == "-all") + { + flagAll = true; + continue; + } + if(arg == "-help") + { + m_log.Info("[YEngine]: yeng pev -all | "); + return; + } + if(arg[0] == '-') + { + m_log.Error("[YEngine]: unknown option " + arg + ", try 'yeng pev -help'"); + return; + } + for(j = 0; j < eventmethods.Length; j++) + { + eventmethod = eventmethods[j]; + if(eventmethod.Name == arg) + goto gotevent; + } + selargs.Add(arg); + } + m_log.Error("[YEngine]: missing , try 'yeng pev -help'"); + return; + gotevent: + string eventname = eventmethod.Name; + StringBuilder sourcesb = new StringBuilder(); + while(++i < args.Length) + { + sourcesb.Append(' '); + sourcesb.Append(args[i]); + } + string sourcest = sourcesb.ToString(); + string sourcehash; + youveanerror = false; + Token t = TokenBegin.Construct("", null, ErrorMsg, sourcest, out sourcehash); + if(youveanerror) + return; + ParameterInfo[] paraminfos = eventmethod.GetParameters(); + object[] paramvalues = new object[paraminfos.Length]; + i = 0; + while(!((t = t.nextToken) is TokenEnd)) + { + if(i >= paramvalues.Length) + { + ErrorMsg(t, "extra parameter(s)"); + return; + } + paramvalues[i] = ParseParamValue(ref t); + if(paramvalues[i] == null) + return; + i++; + } + SharedEventParams eps = new SharedEventParams(eventname, paramvalues, zeroDetectParams); + + // Scan instance list to find those that match selection criteria. + if(!Monitor.TryEnter(m_InstancesDict, 100)) + { + m_log.Error("[YEngine]: deadlock m_LockedDict=" + m_LockedDict); + return; + } + + try + { + instances = new XMRInstance[m_InstancesDict.Count]; + foreach(XMRInstance ins in m_InstancesDict.Values) + { + if(flagAll || InstanceMatchesArgs(ins, selargs.ToArray(), 0)) + { + instances[numScripts++] = ins; + } + } + } + finally + { + Monitor.Exit(m_InstancesDict); + } + + // Post event to the matching instances. + for(i = 0; i < numScripts; i++) + { + XMRInstance inst = instances[i]; + m_log.Info("[YEngine]: post " + eventname + " to " + inst.m_DescName); + inst.PostEvent(eps); + } + } + + private object ParseParamValue(ref Token token) + { + if(token is TokenFloat) + { + return new LSL_Float(((TokenFloat)token).val); + } + if(token is TokenInt) + { + return new LSL_Integer(((TokenInt)token).val); + } + if(token is TokenStr) + { + return new LSL_String(((TokenStr)token).val); + } + if(token is TokenKwCmpLT) + { + List valuelist = new List(); + while(!((token = token.nextToken) is TokenKwCmpGT)) + { + if(!(token is TokenKwComma)) + { + object value = ParseParamValue(ref token); + if(value == null) + return null; + if(value is int) + value = (double)(int)value; + if(!(value is double)) + { + ErrorMsg(token, "must be float or integer constant"); + return null; + } + valuelist.Add((double)value); + } + else if(token.prevToken is TokenKwComma) + { + ErrorMsg(token, "missing constant"); + return null; + } + } + double[] values = valuelist.ToArray(); + switch(values.Length) + { + case 3: + { + return new LSL_Vector(values[0], values[1], values[2]); + } + case 4: + { + return new LSL_Rotation(values[0], values[1], values[2], values[3]); + } + default: + { + ErrorMsg(token, "not rotation or vector"); + return null; + } + } + } + if(token is TokenKwBrkOpen) + { + List valuelist = new List(); + while(!((token = token.nextToken) is TokenKwBrkClose)) + { + if(!(token is TokenKwComma)) + { + object value = ParseParamValue(ref token); + if(value == null) + return null; + valuelist.Add(value); + } + else if(token.prevToken is TokenKwComma) + { + ErrorMsg(token, "missing constant"); + return null; + } + } + return new LSL_List(valuelist.ToArray()); + } + if(token is TokenName) + { + FieldInfo field = typeof(SharedScriptBaseClass).GetField(((TokenName)token).val); + if((field != null) && field.IsPublic && (field.IsLiteral || (field.IsStatic && field.IsInitOnly))) + { + return field.GetValue(null); + } + } + ErrorMsg(token, "invalid constant"); + return null; + } + + private bool youveanerror; + private void ErrorMsg(Token token, string message) + { + youveanerror = true; + m_log.Info("[YEngine]: " + token.posn + " " + message); + } + + private void XmrTestReset(string[] args, int indx) + { + bool flagAll = false; + int numScripts = 0; + XMRInstance[] instances; + + if(args.Length <= indx) + { + m_log.Error("[YEngine]: must specify part of script name or -all for all scripts"); + return; + } + + // Decode command line options. + for(int i = indx; i < args.Length; i++) + { + if(args[i] == "-all") + { + flagAll = true; + continue; + } + if(args[i] == "-help") + { + m_log.Info("[YEngine]: yeng reset -all | "); + return; + } + if(args[i][0] == '-') + { + m_log.Error("[YEngine]: unknown option " + args[i] + ", try 'yeng reset -help'"); + return; + } + } + + // Scan instance list to find those that match selection criteria. + if(!Monitor.TryEnter(m_InstancesDict, 100)) + { + m_log.Error("[YEngine]: deadlock m_LockedDict=" + m_LockedDict); + return; + } + + try + { + instances = new XMRInstance[m_InstancesDict.Count]; + foreach(XMRInstance ins in m_InstancesDict.Values) + { + if(flagAll || InstanceMatchesArgs(ins, args, indx)) + { + instances[numScripts++] = ins; + } + } + } + finally + { + Monitor.Exit(m_InstancesDict); + } + + // Reset the instances as if someone clicked their "Reset" button. + for(int i = 0; i < numScripts; i++) + { + XMRInstance inst = instances[i]; + m_log.Info("[YEngine]: resetting " + inst.m_DescName); + inst.Reset(); + } + } + + private static int CompareInstancesByCPUTime(XMRInstance a, XMRInstance b) + { + if(a == null) + { + return (b == null) ? 0 : 1; + } + if(b == null) + { + return -1; + } + if(b.m_CPUTime < a.m_CPUTime) + return -1; + if(b.m_CPUTime > a.m_CPUTime) + return 1; + return 0; + } + + private void LsQueue(TextWriter outFile, string name, XMRInstQueue queue, string[] args, int indx) + { + outFile.WriteLine("Queue " + name + ":"); + lock(queue) + { + for(XMRInstance inst = queue.PeekHead(); inst != null; inst = inst.m_NextInst) + { + try + { + // Try to print instance name. + if(InstanceMatchesArgs(inst, args, indx)) + { + outFile.WriteLine(" " + inst.ItemID.ToString() + " " + inst.m_DescName); + } + } + catch(Exception e) + { + // Sometimes there are instances in the queue that are disposed. + outFile.WriteLine(" " + inst.ItemID.ToString() + " " + inst.m_DescName + ": " + e.Message); + } + } + } + } + + private bool InstanceMatchesArgs(XMRInstance ins, string[] args, int indx) + { + bool hadSomethingToCompare = false; + + for(int i = indx; i < args.Length; i++) + { + if(args[i][0] != '-') + { + hadSomethingToCompare = true; + if(ins.m_DescName.Contains(args[i])) + return true; + if(ins.ItemID.ToString().Contains(args[i])) + return true; + if(ins.AssetID.ToString().Contains(args[i])) + return true; + } + } + return !hadSomethingToCompare; + } + } + + /** + * @brief Make m_log.Info look like a text writer. + */ + public class LogInfoTextWriter: TextWriter + { + private StringBuilder sb = new StringBuilder(); + private ILog m_log; + public LogInfoTextWriter(ILog m_log) + { + this.m_log = m_log; + } + public override void Write(char c) + { + if(c == '\n') + { + m_log.Info("[YEngine]: " + sb.ToString()); + sb.Remove(0, sb.Length); + } + else + { + sb.Append(c); + } + } + public override void Close() + { + } + public override Encoding Encoding + { + get + { + return Encoding.UTF8; + } + } + } +} diff --git a/Tests/OpenSim.Robust.Tests/Clients/Grid/GridClient.cs b/Tests/OpenSim.Robust.Tests/Clients/Grid/GridClient.cs new file mode 100644 index 00000000000..15498517eb1 --- /dev/null +++ b/Tests/OpenSim.Robust.Tests/Clients/Grid/GridClient.cs @@ -0,0 +1,133 @@ +/* + * 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 System.Text; +using System.Reflection; + +using OpenMetaverse; +using NUnit.Framework; + +using OpenSim.Framework; +using OpenSim.Services.Interfaces; +using GridRegion = OpenSim.Services.Interfaces.GridRegion; +using OpenSim.Services.Connectors; + +namespace Robust.Tests +{ + [TestFixture] + public class GridClient + { +// private static readonly ILog m_log = +// LogManager.GetLogger( +// MethodBase.GetCurrentMethod().DeclaringType); + + [Test] + public void Grid_001() + { + GridServicesConnector m_Connector = new GridServicesConnector(DemonServer.Address); + + GridRegion r1 = CreateRegion("Test Region 1", 1000, 1000); + GridRegion r2 = CreateRegion("Test Region 2", 1001, 1000); + GridRegion r3 = CreateRegion("Test Region 3", 1005, 1000); + + string msg = m_Connector.RegisterRegion(UUID.Zero, r1); + Assert.AreEqual(msg, string.Empty, "Region 1 failed to register"); + + msg = m_Connector.RegisterRegion(UUID.Zero, r2); + Assert.AreEqual(msg, string.Empty, "Region 2 failed to register"); + + msg = m_Connector.RegisterRegion(UUID.Zero, r3); + Assert.AreEqual(msg, string.Empty, "Region 3 failed to register"); + + bool success; + success = m_Connector.DeregisterRegion(r3.RegionID); + Assert.AreEqual(success, true, "Region 3 failed to deregister"); + + msg = m_Connector.RegisterRegion(UUID.Zero, r3); + Assert.AreEqual(msg, string.Empty, "Region 3 failed to re-register"); + + List regions = m_Connector.GetNeighbours(UUID.Zero, r1.RegionID); + Assert.AreNotEqual(regions, null, "GetNeighbours of region 1 failed"); + Assert.AreEqual(regions.Count, 1, "Region 1 should have 1 neighbor"); + Assert.AreEqual(regions[0].RegionName, "Test Region 2", "Region 1 has the wrong neighbor"); + + GridRegion region = m_Connector.GetRegionByUUID(UUID.Zero, r2.RegionID); + Assert.AreNotEqual(region, null, "GetRegionByUUID for region 2 failed"); + Assert.AreEqual(region.RegionName, "Test Region 2", "GetRegionByUUID of region 2 returned wrong region"); + + region = m_Connector.GetRegionByUUID(UUID.Zero, UUID.Random()); + Assert.AreEqual(region, null, "Region with randon id should not exist"); + + region = m_Connector.GetRegionByName(UUID.Zero, r3.RegionName); + Assert.AreNotEqual(region, null, "GetRegionByUUID for region 3 failed"); + Assert.AreEqual(region.RegionName, "Test Region 3", "GetRegionByUUID of region 3 returned wrong region"); + + region = m_Connector.GetRegionByName(UUID.Zero, "Foo"); + Assert.AreEqual(region, null, "Region Foo should not exist"); + + regions = m_Connector.GetRegionsByName(UUID.Zero, "Test", 10); + Assert.AreNotEqual(regions, null, "GetRegionsByName failed"); + Assert.AreEqual(regions.Count, 3, "GetRegionsByName should return 3"); + + regions = m_Connector.GetRegionRange(UUID.Zero, + (int)Util.RegionToWorldLoc(900), (int)Util.RegionToWorldLoc(1002), + (int)Util.RegionToWorldLoc(900), (int)Util.RegionToWorldLoc(1002) ); + Assert.AreNotEqual(regions, null, "GetRegionRange failed"); + Assert.AreEqual(regions.Count, 2, "GetRegionRange should return 2"); + + regions = m_Connector.GetRegionRange(UUID.Zero, + (int)Util.RegionToWorldLoc(900), (int)Util.RegionToWorldLoc(950), + (int)Util.RegionToWorldLoc(900), (int)Util.RegionToWorldLoc(950) ); + Assert.AreNotEqual(regions, null, "GetRegionRange (bis) failed"); + Assert.AreEqual(regions.Count, 0, "GetRegionRange (bis) should return 0"); + + // Deregister them all + success = m_Connector.DeregisterRegion(r1.RegionID); + Assert.AreEqual(success, true, "Region 1 failed to deregister"); + + success = m_Connector.DeregisterRegion(r2.RegionID); + Assert.AreEqual(success, true, "Region 2 failed to deregister"); + + success = m_Connector.DeregisterRegion(r3.RegionID); + Assert.AreEqual(success, true, "Region 3 failed to deregister"); + } + + private static GridRegion CreateRegion(string name, uint xcell, uint ycell) + { + GridRegion region = new GridRegion(xcell, ycell); + region.RegionName = name; + region.RegionID = UUID.Random(); + region.ExternalHostName = "127.0.0.1"; + region.HttpPort = 9000; + region.InternalEndPoint = new System.Net.IPEndPoint(System.Net.IPAddress.Parse("0.0.0.0"), 9000); + + return region; + } + } +} diff --git a/Tests/OpenSim.Robust.Tests/Clients/Grid/GridForm.html b/Tests/OpenSim.Robust.Tests/Clients/Grid/GridForm.html new file mode 100644 index 00000000000..252920f38d3 --- /dev/null +++ b/Tests/OpenSim.Robust.Tests/Clients/Grid/GridForm.html @@ -0,0 +1,11 @@ + + +
+xmin: +xmax: +ymin: +ymax: + + +
+ diff --git a/Tests/OpenSim.Robust.Tests/Clients/InstantMessage/IMClient.cs b/Tests/OpenSim.Robust.Tests/Clients/InstantMessage/IMClient.cs new file mode 100644 index 00000000000..4eba7b90847 --- /dev/null +++ b/Tests/OpenSim.Robust.Tests/Clients/InstantMessage/IMClient.cs @@ -0,0 +1,58 @@ +/* + * 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 System.Text; + +using OpenMetaverse; +using NUnit.Framework; + +using OpenSim.Framework; +using OpenSim.Services.Interfaces; +using OpenSim.Services.Connectors.InstantMessage; + +namespace Robust.Tests +{ + [TestFixture] + public class IMClient + { + [Test] + public void HGIM_001() + { + GridInstantMessage im = new GridInstantMessage(); + im.fromAgentID = new Guid(); + im.toAgentID = new Guid(); + im.message = "Hello"; + im.imSessionID = new Guid(); + + bool success = InstantMessageServiceConnector.SendInstantMessage(DemonServer.Address, im, String.Empty); + Assert.IsFalse(success, "Sending of IM succeeded, but it should have failed"); + } + + } +} diff --git a/Tests/OpenSim.Robust.Tests/Clients/Inventory/InventoryClient.cs b/Tests/OpenSim.Robust.Tests/Clients/Inventory/InventoryClient.cs new file mode 100644 index 00000000000..fe46a4f523c --- /dev/null +++ b/Tests/OpenSim.Robust.Tests/Clients/Inventory/InventoryClient.cs @@ -0,0 +1,205 @@ +/* + * 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 System.Text; +using System.Reflection; + +using OpenMetaverse; +using NUnit.Framework; + +using OpenSim.Framework; +using OpenSim.Services.Interfaces; +using OpenSim.Services.Connectors; + +using OpenSim.Tests.Common; + +namespace Robust.Tests +{ + [TestFixture] + public class InventoryClient + { +// private static readonly ILog m_log = +// LogManager.GetLogger( +// MethodBase.GetCurrentMethod().DeclaringType); + + private UUID m_userID = new UUID("00000000-0000-0000-0000-333333333333"); + private UUID m_rootFolderID; + private UUID m_notecardsFolder; + private UUID m_objectsFolder; + + [Test] + public void Inventory_001_CreateInventory() + { + TestHelpers.InMethod(); + XInventoryServicesConnector m_Connector = new XInventoryServicesConnector(DemonServer.Address); + + // Create an inventory that looks like this: + // + // /My Inventory + // + // /Objects + // Some Object + // /Notecards + // Notecard 1 + // Notecard 2 + // /Test Folder + // Link to notecard -> /Notecards/Notecard 2 + // Link to Objects folder -> /Objects + + bool success = m_Connector.CreateUserInventory(m_userID); + Assert.IsTrue(success, "Failed to create user inventory"); + + m_rootFolderID = m_Connector.GetRootFolder(m_userID).ID; + Assert.AreNotEqual(m_rootFolderID, UUID.Zero, "Root folder ID must not be UUID.Zero"); + + InventoryFolderBase of = m_Connector.GetFolderForType(m_userID, FolderType.Object); + Assert.IsNotNull(of, "Failed to retrieve Objects folder"); + m_objectsFolder = of.ID; + Assert.AreNotEqual(m_objectsFolder, UUID.Zero, "Objects folder ID must not be UUID.Zero"); + + // Add an object + InventoryItemBase item = new InventoryItemBase(new UUID("b0000000-0000-0000-0000-00000000000b"), m_userID); + item.AssetID = UUID.Random(); + item.AssetType = (int)AssetType.Object; + item.Folder = m_objectsFolder; + item.Name = "Some Object"; + item.Description = string.Empty; + success = m_Connector.AddItem(item); + Assert.IsTrue(success, "Failed to add object to inventory"); + + InventoryFolderBase ncf = m_Connector.GetFolderForType(m_userID, FolderType.Notecard); + Assert.IsNotNull(of, "Failed to retrieve Notecards folder"); + m_notecardsFolder = ncf.ID; + Assert.AreNotEqual(m_notecardsFolder, UUID.Zero, "Notecards folder ID must not be UUID.Zero"); + m_notecardsFolder = ncf.ID; + + // Add a notecard + item = new InventoryItemBase(new UUID("10000000-0000-0000-0000-000000000001"), m_userID); + item.AssetID = UUID.Random(); + item.AssetType = (int)AssetType.Notecard; + item.Folder = m_notecardsFolder; + item.Name = "Test Notecard 1"; + item.Description = string.Empty; + success = m_Connector.AddItem(item); + Assert.IsTrue(success, "Failed to add Notecard 1 to inventory"); + // Add another notecard + item.ID = new UUID("20000000-0000-0000-0000-000000000002"); + item.AssetID = new UUID("a0000000-0000-0000-0000-00000000000a"); + item.Name = "Test Notecard 2"; + item.Description = string.Empty; + success = m_Connector.AddItem(item); + Assert.IsTrue(success, "Failed to add Notecard 2 to inventory"); + + // Add a folder + InventoryFolderBase folder = new InventoryFolderBase(new UUID("f0000000-0000-0000-0000-00000000000f"), "Test Folder", m_userID, m_rootFolderID); + folder.Type = (int)FolderType.None; + success = m_Connector.AddFolder(folder); + Assert.IsTrue(success, "Failed to add Test Folder to inventory"); + + // Add a link to notecard 2 in Test Folder + item.AssetID = item.ID; // use item ID of notecard 2 + item.ID = new UUID("40000000-0000-0000-0000-000000000004"); + item.AssetType = (int)AssetType.Link; + item.Folder = folder.ID; + item.Name = "Link to notecard"; + item.Description = string.Empty; + success = m_Connector.AddItem(item); + Assert.IsTrue(success, "Failed to add link to notecard to inventory"); + + // Add a link to the Objects folder in Test Folder + item.AssetID = m_Connector.GetFolderForType(m_userID, FolderType.Object).ID; // use item ID of Objects folder + item.ID = new UUID("50000000-0000-0000-0000-000000000005"); + item.AssetType = (int)AssetType.LinkFolder; + item.Folder = folder.ID; + item.Name = "Link to Objects folder"; + item.Description = string.Empty; + success = m_Connector.AddItem(item); + Assert.IsTrue(success, "Failed to add link to objects folder to inventory"); + + InventoryCollection coll = m_Connector.GetFolderContent(m_userID, m_rootFolderID); + Assert.IsNotNull(coll, "Failed to retrieve contents of root folder"); + Assert.Greater(coll.Folders.Count, 0, "Root folder does not have any subfolders"); + + coll = m_Connector.GetFolderContent(m_userID, folder.ID); + Assert.IsNotNull(coll, "Failed to retrieve contents of Test Folder"); + Assert.AreEqual(coll.Items.Count + coll.Folders.Count, 2, "Test Folder is expected to have exactly 2 things inside"); + + } + + [Test] + public void Inventory_002_MultipleItemsRequest() + { + TestHelpers.InMethod(); + XInventoryServicesConnector m_Connector = new XInventoryServicesConnector(DemonServer.Address); + + // Prefetch Notecard 1, will be cached from here on + InventoryItemBase item = m_Connector.GetItem(m_userID, new UUID("10000000-0000-0000-0000-000000000001")); + Assert.NotNull(item, "Failed to get Notecard 1"); + Assert.AreEqual("Test Notecard 1", item.Name, "Wrong name for Notecard 1"); + + UUID[] uuids = new UUID[2]; + uuids[0] = item.ID; + uuids[1] = new UUID("20000000-0000-0000-0000-000000000002"); + + InventoryItemBase[] items = m_Connector.GetMultipleItems(m_userID, uuids); + Assert.NotNull(items, "Failed to get multiple items"); + Assert.IsTrue(items.Length == 2, "Requested 2 items, but didn't receive 2 items"); + + // Now they should both be cached + items = m_Connector.GetMultipleItems(m_userID, uuids); + Assert.NotNull(items, "(Repeat) Failed to get multiple items"); + Assert.IsTrue(items.Length == 2, "(Repeat) Requested 2 items, but didn't receive 2 items"); + + // This item doesn't exist, but [0] does, and it's cached. + uuids[1] = new UUID("bb000000-0000-0000-0000-0000000000bb"); + // Fetching should return 2 items, but [1] should be null + items = m_Connector.GetMultipleItems(m_userID, uuids); + Assert.NotNull(items, "(Three times) Failed to get multiple items"); + Assert.IsTrue(items.Length == 2, "(Three times) Requested 2 items, but didn't receive 2 items"); + Assert.AreEqual("Test Notecard 1", items[0].Name, "(Three times) Wrong name for Notecard 1"); + Assert.IsNull(items[1], "(Three times) Expecting 2nd item to be null"); + + // Now both don't exist + uuids[0] = new UUID("aa000000-0000-0000-0000-0000000000aa"); + items = m_Connector.GetMultipleItems(m_userID, uuids); + Assert.Null(items[0], "Request to multiple non-existent items is supposed to return null [0]"); + Assert.Null(items[1], "Request to multiple non-existent items is supposed to return null [1]"); + + // This item exists, and it's not cached + uuids[1] = new UUID("b0000000-0000-0000-0000-00000000000b"); + // Fetching should return 2 items, but [0] should be null + items = m_Connector.GetMultipleItems(m_userID, uuids); + Assert.NotNull(items, "(Four times) Failed to get multiple items"); + Assert.IsTrue(items.Length == 2, "(Four times) Requested 2 items, but didn't receive 2 items"); + Assert.AreEqual("Some Object", items[1].Name, "(Four times) Wrong name for Some Object"); + Assert.IsNull(items[0], "(Four times) Expecting 1st item to be null"); + + } + } +} diff --git a/Tests/OpenSim.Robust.Tests/Clients/Presence/PresenceClient.cs b/Tests/OpenSim.Robust.Tests/Clients/Presence/PresenceClient.cs new file mode 100644 index 00000000000..31c8ee96ef2 --- /dev/null +++ b/Tests/OpenSim.Robust.Tests/Clients/Presence/PresenceClient.cs @@ -0,0 +1,81 @@ +/* + * 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 System.Text; +using System.Reflection; + +using OpenMetaverse; +using NUnit.Framework; + +using OpenSim.Framework; +using OpenSim.Services.Interfaces; +using OpenSim.Services.Connectors; + +namespace Robust.Tests +{ + [TestFixture] + public class PresenceClient + { + [Test] + public void Presence_001() + { + PresenceServicesConnector m_Connector = new PresenceServicesConnector(DemonServer.Address); + + UUID user1 = UUID.Random(); + UUID session1 = UUID.Random(); + UUID region1 = UUID.Random(); + + bool success = m_Connector.LoginAgent(user1.ToString(), session1, UUID.Zero); + Assert.AreEqual(success, true, "Failed to add user session"); + + PresenceInfo pinfo = m_Connector.GetAgent(session1); + Assert.AreNotEqual(pinfo, null, "Unable to retrieve session"); + Assert.AreEqual(pinfo.UserID, user1.ToString(), "Retrieved session does not match expected userID"); + Assert.AreNotEqual(pinfo.RegionID, region1, "Retrieved session is unexpectedly in region"); + + success = m_Connector.ReportAgent(session1, region1); + Assert.AreEqual(success, true, "Failed to report session in region 1"); + + pinfo = m_Connector.GetAgent(session1); + Assert.AreNotEqual(pinfo, null, "Unable to session presence"); + Assert.AreEqual(pinfo.UserID, user1.ToString(), "Retrieved session does not match expected userID"); + Assert.AreEqual(pinfo.RegionID, region1, "Retrieved session is not in expected region"); + + success = m_Connector.LogoutAgent(session1); + Assert.AreEqual(success, true, "Failed to remove session"); + + pinfo = m_Connector.GetAgent(session1); + Assert.AreEqual(pinfo, null, "Session is still there, even though it shouldn't"); + + success = m_Connector.ReportAgent(session1, UUID.Random()); + Assert.AreEqual(success, false, "Remove non-existing session should fail"); + } + + } +} diff --git a/Tests/OpenSim.Robust.Tests/Clients/UserAccounts/UserAccountsClient.cs b/Tests/OpenSim.Robust.Tests/Clients/UserAccounts/UserAccountsClient.cs new file mode 100644 index 00000000000..3238dc9a31c --- /dev/null +++ b/Tests/OpenSim.Robust.Tests/Clients/UserAccounts/UserAccountsClient.cs @@ -0,0 +1,86 @@ +/* + * 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 System.Text; +using System.Reflection; + +using OpenMetaverse; +using NUnit.Framework; + +using OpenSim.Framework; +using OpenSim.Services.Interfaces; +using OpenSim.Services.Connectors; + +namespace Robust.Tests +{ + [TestFixture] + public class UserAccountsClient + { + [Test] + public void UserAccounts_001() + { + UserAccountServicesConnector m_Connector = new UserAccountServicesConnector(DemonServer.Address); + + string first = "Completely"; + string last = "Clueless"; + string email = "foo@bar.com"; + + UserAccount account = m_Connector.CreateUser(first, last, "123", email, UUID.Zero); + Assert.IsNotNull(account, "Failed to create account " + first + " " + last); + UUID user1 = account.PrincipalID; + + account = m_Connector.GetUserAccount(UUID.Zero, user1); + Assert.NotNull(account, "Failed to retrieve account for user id " + user1); + Assert.AreEqual(account.FirstName, first, "First name does not match"); + Assert.AreEqual(account.LastName, last, "Last name does not match"); + + account = m_Connector.GetUserAccount(UUID.Zero, first, last); + Assert.IsNotNull(account, "Failed to retrieve account for user " + first + " " + last); + Assert.AreEqual(account.FirstName, first, "First name does not match (bis)"); + Assert.AreEqual(account.LastName, last, "Last name does not match (bis)"); + + account.Email = "user@example.com"; + bool success = m_Connector.StoreUserAccount(account); + Assert.IsTrue(success, "Failed to store existing account"); + + account = m_Connector.GetUserAccount(UUID.Zero, user1); + Assert.NotNull(account, "Failed to retrieve account for user id " + user1); + Assert.AreEqual(account.Email, "user@example.com", "Incorrect email"); + + account = new UserAccount(UUID.Zero, "DoesNot", "Exist", "xxx@xxx.com"); + success = m_Connector.StoreUserAccount(account); + Assert.IsFalse(success, "Storing a non-existing account must fail"); + + account = m_Connector.GetUserAccount(UUID.Zero, "DoesNot", "Exist"); + Assert.IsNull(account, "Account DoesNot Exist must not be there"); + + } + + } +} diff --git a/Tests/OpenSim.Robust.Tests/Robust.Tests.csproj b/Tests/OpenSim.Robust.Tests/Robust.Tests.csproj new file mode 100644 index 00000000000..3d2a835db14 --- /dev/null +++ b/Tests/OpenSim.Robust.Tests/Robust.Tests.csproj @@ -0,0 +1,37 @@ + + + net6.0 + + + + + + + + + + ..\..\..\bin\Nini.dll + False + + + ..\..\..\bin\OpenMetaverse.dll + False + + + ..\..\..\bin\OpenMetaverseTypes.dll + False + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Tests/OpenSim.Robust.Tests/Server/DemonServer.cs b/Tests/OpenSim.Robust.Tests/Server/DemonServer.cs new file mode 100644 index 00000000000..1e0797e1ac9 --- /dev/null +++ b/Tests/OpenSim.Robust.Tests/Server/DemonServer.cs @@ -0,0 +1,69 @@ +/* + * 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 System.IO; +using System.Threading; + +using Nini.Config; +using log4net; +using NUnit.Framework; + +using OpenSim.Server; + +namespace Robust.Tests +{ + [SetUpFixture] + public class DemonServer : OpenSimServer + { + private Thread m_demon; + + public static string Address = "http://localhost:8888"; + + [SetUp] + public void StartDemon() + { + if (File.Exists("Robust.Tests.log")) + File.Delete("Robust.Tests.log"); + + Console.WriteLine("**** Starting demon Robust server ****"); + m_demon = new Thread( () => Main(new string[] {"-inifile=Robust.Tests.ini"})); + m_demon.Start(); + // Give some time for the server to instantiate all services + Thread.Sleep(3000); + Console.WriteLine("**** Setup Finished ****"); + } + + [TearDown] + public void StopDemon() + { + Console.WriteLine("**** Killing demon Robust Server ****"); + m_Server.Shutdown(); + } + } +} diff --git a/Tests/OpenSim.Server.Handlers.Tests/Asset/Tests/AssetServerPostHandlerTests.cs b/Tests/OpenSim.Server.Handlers.Tests/Asset/Tests/AssetServerPostHandlerTests.cs new file mode 100644 index 00000000000..4d2228a025f --- /dev/null +++ b/Tests/OpenSim.Server.Handlers.Tests/Asset/Tests/AssetServerPostHandlerTests.cs @@ -0,0 +1,109 @@ +/* + * 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.IO; +using System.Net; +using System.Text; +using System.Xml; +using System.Xml.Serialization; +using Nini.Config; +using NUnit.Framework; +using OpenMetaverse; +using OpenSim.Framework; +using OpenSim.Server.Handlers.Asset; +using OpenSim.Services.AssetService; +using OpenSim.Services.Interfaces; +using OpenSim.Tests.Common; + +namespace OpenSim.Server.Handlers.Asset.Test +{ + [TestFixture] + public class AssetServerPostHandlerTests : OpenSimTestCase + { + [Test] + public void TestGoodAssetStoreRequest() + { + TestHelpers.InMethod(); + + UUID assetId = TestHelpers.ParseTail(0x1); + + IConfigSource config = new IniConfigSource(); + config.AddConfig("AssetService"); + config.Configs["AssetService"].Set("StorageProvider", "OpenSim.Tests.Common.dll"); + + AssetService assetService = new AssetService(config); + + AssetServerPostHandler asph = new AssetServerPostHandler(assetService); + + AssetBase asset = AssetHelpers.CreateNotecardAsset(assetId, "Hello World"); + + MemoryStream buffer = new MemoryStream(); + + XmlWriterSettings settings = new XmlWriterSettings(); + settings.Encoding = Encoding.UTF8; + + using (XmlWriter writer = XmlWriter.Create(buffer, settings)) + { + XmlSerializer serializer = new XmlSerializer(typeof(AssetBase)); + serializer.Serialize(writer, asset); + writer.Flush(); + } + + buffer.Position = 0; + asph.Handle(null, buffer, null, null); + + AssetBase retrievedAsset = assetService.Get(assetId.ToString()); + + Assert.That(retrievedAsset, Is.Not.Null); + } + + [Test] + public void TestBadXmlAssetStoreRequest() + { + TestHelpers.InMethod(); + + IConfigSource config = new IniConfigSource(); + config.AddConfig("AssetService"); + config.Configs["AssetService"].Set("StorageProvider", "OpenSim.Tests.Common.dll"); + + AssetService assetService = new AssetService(config); + + AssetServerPostHandler asph = new AssetServerPostHandler(assetService); + + MemoryStream buffer = new MemoryStream(); + byte[] badData = new byte[] { 0x48, 0x65, 0x6c, 0x6c, 0x6f }; + buffer.Write(badData, 0, badData.Length); + buffer.Position = 0; + + TestOSHttpResponse response = new TestOSHttpResponse(); + asph.Handle(null, buffer, null, response); + + Assert.That(response.StatusCode, Is.EqualTo((int)HttpStatusCode.BadRequest)); + } + } +} \ No newline at end of file diff --git a/Tests/OpenSim.Server.Handlers.Tests/OpenSim.Server.Handlers.Tests.csproj b/Tests/OpenSim.Server.Handlers.Tests/OpenSim.Server.Handlers.Tests.csproj new file mode 100644 index 00000000000..81138d14868 --- /dev/null +++ b/Tests/OpenSim.Server.Handlers.Tests/OpenSim.Server.Handlers.Tests.csproj @@ -0,0 +1,115 @@ + + + net6.0 + + + + ..\..\..\bin\Nini.dll + False + + + ..\..\..\bin\OpenMetaverse.dll + False + + + ..\..\..\bin\OpenMetaverse.StructuredData.dll + False + + + ..\..\..\bin\OpenMetaverseTypes.dll + False + + + False + + + ..\..\..\bin\XMLRPC.dll + False + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Tests/OpenSim.Services.InventoryService.Tests/OpenSim.Services.InventoryService.Tests.csproj b/Tests/OpenSim.Services.InventoryService.Tests/OpenSim.Services.InventoryService.Tests.csproj new file mode 100644 index 00000000000..87b101a2094 --- /dev/null +++ b/Tests/OpenSim.Services.InventoryService.Tests/OpenSim.Services.InventoryService.Tests.csproj @@ -0,0 +1,50 @@ + + + net6.0 + + + + + + + + ..\..\..\..\bin\Nini.dll + False + + + ..\..\..\..\bin\nunit.framework.dll + False + + + ..\..\..\..\bin\OpenMetaverse.dll + False + + + ..\..\..\..\bin\OpenMetaverse.StructuredData.dll + False + + + ..\..\..\..\bin\OpenMetaverseTypes.dll + False + + + False + + + False + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Tests/OpenSim.Services.InventoryService.Tests/XInventoryServiceTests.cs b/Tests/OpenSim.Services.InventoryService.Tests/XInventoryServiceTests.cs new file mode 100644 index 00000000000..cf23f6147d4 --- /dev/null +++ b/Tests/OpenSim.Services.InventoryService.Tests/XInventoryServiceTests.cs @@ -0,0 +1,175 @@ +/* + * 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 Nini.Config; +using NUnit.Framework; +using OpenMetaverse; +using OpenSim.Framework; +using OpenSim.Server.Base; +using OpenSim.Services.Interfaces; +using OpenSim.Tests.Common; + +namespace OpenSim.Services.InventoryService.Tests +{ + /// + /// Tests for the XInventoryService + /// + /// + /// TODO: Fill out more tests. + /// + [TestFixture] + public class XInventoryServiceTests : OpenSimTestCase + { + private IInventoryService CreateXInventoryService() + { + IConfigSource config = new IniConfigSource(); + config.AddConfig("InventoryService"); + config.Configs["InventoryService"].Set("StorageProvider", "OpenSim.Tests.Common.dll"); + + return ServerUtils.LoadPlugin( + "OpenSim.Services.InventoryService.dll:XInventoryService", new Object[] { config }); + } + + /// + /// Tests add item operation. + /// + /// + /// TODO: Test all operations. + /// + [Test] + public void TestAddItem() + { + TestHelpers.InMethod(); + + string creatorId = TestHelpers.ParseTail(0x1).ToString(); + UUID ownerId = TestHelpers.ParseTail(0x2); + UUID itemId = TestHelpers.ParseTail(0x10); + UUID assetId = TestHelpers.ParseTail(0x20); + UUID folderId = TestHelpers.ParseTail(0x30); + int invType = (int)InventoryType.Animation; + int assetType = (int)AssetType.Animation; + string itemName = "item1"; + + IInventoryService xis = CreateXInventoryService(); + + InventoryItemBase itemToStore + = new InventoryItemBase(itemId, ownerId) + { + CreatorIdentification = creatorId.ToString(), + AssetID = assetId, + Name = itemName, + Folder = folderId, + InvType = invType, + AssetType = assetType + }; + + Assert.That(xis.AddItem(itemToStore), Is.True); + + InventoryItemBase itemRetrieved = xis.GetItem(UUID.Zero, itemId); + + Assert.That(itemRetrieved, Is.Not.Null); + Assert.That(itemRetrieved.CreatorId, Is.EqualTo(creatorId)); + Assert.That(itemRetrieved.Owner, Is.EqualTo(ownerId)); + Assert.That(itemRetrieved.AssetID, Is.EqualTo(assetId)); + Assert.That(itemRetrieved.Folder, Is.EqualTo(folderId)); + Assert.That(itemRetrieved.InvType, Is.EqualTo(invType)); + Assert.That(itemRetrieved.AssetType, Is.EqualTo(assetType)); + Assert.That(itemRetrieved.Name, Is.EqualTo(itemName)); + } + + [Test] + public void TestUpdateItem() + { + TestHelpers.InMethod(); +// TestHelpers.EnableLogging(); + + string creatorId = TestHelpers.ParseTail(0x1).ToString(); + UUID ownerId = TestHelpers.ParseTail(0x2); + UUID itemId = TestHelpers.ParseTail(0x10); + UUID assetId = TestHelpers.ParseTail(0x20); + UUID folderId = TestHelpers.ParseTail(0x30); + int invType = (int)InventoryType.Animation; + int assetType = (int)AssetType.Animation; + string itemName = "item1"; + string itemName2 = "item2"; + + IInventoryService xis = CreateXInventoryService(); + + InventoryItemBase itemToStore + = new InventoryItemBase(itemId, ownerId) + { + CreatorIdentification = creatorId.ToString(), + AssetID = assetId, + Name = itemName, + Folder = folderId, + InvType = invType, + AssetType = assetType + }; + + Assert.That(xis.AddItem(itemToStore), Is.True); + + // Normal update + itemToStore.Name = itemName2; + + Assert.That(xis.UpdateItem(itemToStore), Is.True); + + InventoryItemBase itemRetrieved = xis.GetItem(UUID.Zero, itemId); + + Assert.That(itemRetrieved, Is.Not.Null); + Assert.That(itemRetrieved.Name, Is.EqualTo(itemName2)); + + // Attempt to update properties that should never change + string creatorId2 = TestHelpers.ParseTail(0x7).ToString(); + UUID ownerId2 = TestHelpers.ParseTail(0x8); + UUID folderId2 = TestHelpers.ParseTail(0x70); + int invType2 = (int)InventoryType.CallingCard; + int assetType2 = (int)AssetType.CallingCard; + string itemName3 = "item3"; + + itemToStore.CreatorIdentification = creatorId2.ToString(); + //itemToStore.Owner = ownerId2; this cant be done + itemToStore.Folder = folderId2; + itemToStore.InvType = invType2; + itemToStore.AssetType = assetType2; + itemToStore.Name = itemName3; + + Assert.That(xis.UpdateItem(itemToStore), Is.True); + + itemRetrieved = xis.GetItem(itemRetrieved.Owner, itemRetrieved.ID); + + Assert.That(itemRetrieved, Is.Not.Null); + Assert.That(itemRetrieved.CreatorId, Is.EqualTo(creatorId)); + Assert.That(itemRetrieved.Owner, Is.EqualTo(ownerId)); + Assert.That(itemRetrieved.AssetID, Is.EqualTo(assetId)); + Assert.That(itemRetrieved.Folder, Is.EqualTo(folderId)); + Assert.That(itemRetrieved.InvType, Is.EqualTo(invType)); + Assert.That(itemRetrieved.AssetType, Is.EqualTo(assetType)); + Assert.That(itemRetrieved.Name, Is.EqualTo(itemName3)); + } + } +} diff --git a/Tests/OpenSim.Stress.Tests/OpenSim.Tests.Stress.csproj b/Tests/OpenSim.Stress.Tests/OpenSim.Tests.Stress.csproj new file mode 100644 index 00000000000..b393c77af9d --- /dev/null +++ b/Tests/OpenSim.Stress.Tests/OpenSim.Tests.Stress.csproj @@ -0,0 +1,45 @@ + + + net6.0 + + + + + + + + + + ..\..\..\bin\Nini.dll + False + + + ..\..\..\bin\OpenMetaverse.dll + False + + + ..\..\..\bin\OpenMetaverse.StructuredData.dll + False + + + ..\..\..\bin\OpenMetaverseTypes.dll + False + + + ..\..\..\bin\XMLRPC.dll + False + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Tests/OpenSim.Stress.Tests/VectorRenderModuleStressTests.cs b/Tests/OpenSim.Stress.Tests/VectorRenderModuleStressTests.cs new file mode 100644 index 00000000000..e9767f3e84a --- /dev/null +++ b/Tests/OpenSim.Stress.Tests/VectorRenderModuleStressTests.cs @@ -0,0 +1,130 @@ +/* + * 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 System.IO; +using System.Linq; +using System.Reflection; +using System.Threading; +using log4net.Config; +using NUnit.Framework; +using OpenMetaverse; +using OpenMetaverse.Assets; +using OpenSim.Framework; +using OpenSim.Region.CoreModules.Scripting.DynamicTexture; +using OpenSim.Region.CoreModules.Scripting.VectorRender; +using OpenSim.Region.Framework.Scenes; +using OpenSim.Region.Framework.Scenes.Serialization; +using OpenSim.Tests.Common; + +namespace OpenSim.Tests.Stress +{ + [TestFixture] + public class VectorRenderModuleStressTests : OpenSimTestCase + { + public Scene Scene { get; private set; } + public DynamicTextureModule Dtm { get; private set; } + public VectorRenderModule Vrm { get; private set; } + + private void SetupScene(bool reuseTextures) + { + Scene = new SceneHelpers().SetupScene(); + + Dtm = new DynamicTextureModule(); + Dtm.ReuseTextures = reuseTextures; + + Vrm = new VectorRenderModule(); + + SceneHelpers.SetupSceneModules(Scene, Dtm, Vrm); + } + + [Test] + public void TestConcurrentRepeatedDraw() + { + int threads = 4; + TestHelpers.InMethod(); + + SetupScene(false); + + List drawers = new List(); + + for (int i = 0; i < threads; i++) + { + Drawer d = new Drawer(this, i); + drawers.Add(d); + Console.WriteLine("Starting drawer {0}", i); + Util.FireAndForget(o => d.Draw(), null, "VectorRenderModuleStressTests.TestConcurrentRepeatedDraw"); + } + + Thread.Sleep(10 * 60 * 1000); + + drawers.ForEach(d => d.Ready = false); + drawers.ForEach(d => Console.WriteLine("Drawer {0} drew {1} textures", d.Number, d.Pass + 1)); + } + + class Drawer + { + public int Number { get; private set; } + public int Pass { get; private set; } + public bool Ready { get; set; } + + private VectorRenderModuleStressTests m_tests; + + public Drawer(VectorRenderModuleStressTests tests, int number) + { + m_tests = tests; + Number = number; + Ready = true; + } + + public void Draw() + { + SceneObjectGroup so = SceneHelpers.AddSceneObject(m_tests.Scene); + + while (Ready) + { + UUID originalTextureID = so.RootPart.Shape.Textures.GetFace(0).TextureID; + + // Ensure unique text + string text = string.Format("{0:D2}{1}", Number, Pass); + + m_tests.Dtm.AddDynamicTextureData( + m_tests.Scene.RegionInfo.RegionID, + so.UUID, + m_tests.Vrm.GetContentType(), + string.Format("PenColour BLACK; MoveTo 40,220; FontSize 32; Text {0};", text), + ""); + + Assert.That(originalTextureID, Is.Not.EqualTo(so.RootPart.Shape.Textures.GetFace(0).TextureID)); + + Pass++; + } + } + } + } +} \ No newline at end of file diff --git a/Tests/OpenSim.Tests/Clients/Grid/GridClient.cs b/Tests/OpenSim.Tests/Clients/Grid/GridClient.cs new file mode 100644 index 00000000000..7d3aee31380 --- /dev/null +++ b/Tests/OpenSim.Tests/Clients/Grid/GridClient.cs @@ -0,0 +1,205 @@ +/* + * 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 System.Text; +using System.Reflection; + +using OpenMetaverse; +using log4net; +using log4net.Appender; +using log4net.Layout; + +using OpenSim.Framework; +using OpenSim.Services.Interfaces; +using GridRegion = OpenSim.Services.Interfaces.GridRegion; +using OpenSim.Services.Connectors; + +namespace OpenSim.Tests.Clients.GridClient +{ + public class GridClient + { +// private static readonly ILog m_log = +// LogManager.GetLogger( +// MethodBase.GetCurrentMethod().DeclaringType); + + public static void Main(string[] args) + { + ConsoleAppender consoleAppender = new ConsoleAppender(); + consoleAppender.Layout = + new PatternLayout("%date [%thread] %-5level %logger [%property{NDC}] - %message%newline"); + log4net.Config.BasicConfigurator.Configure(consoleAppender); + + string serverURI = "http://127.0.0.1:8001"; + GridServicesConnector m_Connector = new GridServicesConnector(serverURI); + + GridRegion r1 = CreateRegion("Test Region 1", 1000, 1000); + GridRegion r2 = CreateRegion("Test Region 2", 1001, 1000); + GridRegion r3 = CreateRegion("Test Region 3", 1005, 1000); + + Console.WriteLine("[GRID CLIENT]: *** Registering region 1"); + string msg = m_Connector.RegisterRegion(UUID.Zero, r1); + if (msg == String.Empty) + Console.WriteLine("[GRID CLIENT]: Successfully registered region 1"); + else + Console.WriteLine("[GRID CLIENT]: region 1 failed to register"); + + Console.WriteLine("[GRID CLIENT]: *** Registering region 2"); + msg = m_Connector.RegisterRegion(UUID.Zero, r2); + if (msg == String.Empty) + Console.WriteLine("[GRID CLIENT]: Successfully registered region 2"); + else + Console.WriteLine("[GRID CLIENT]: region 2 failed to register"); + + Console.WriteLine("[GRID CLIENT]: *** Registering region 3"); + msg = m_Connector.RegisterRegion(UUID.Zero, r3); + if (msg == String.Empty) + Console.WriteLine("[GRID CLIENT]: Successfully registered region 3"); + else + Console.WriteLine("[GRID CLIENT]: region 3 failed to register"); + + + bool success; + Console.WriteLine("[GRID CLIENT]: *** Deregistering region 3"); + success = m_Connector.DeregisterRegion(r3.RegionID); + if (success) + Console.WriteLine("[GRID CLIENT]: Successfully deregistered region 3"); + else + Console.WriteLine("[GRID CLIENT]: region 3 failed to deregister"); + Console.WriteLine("[GRID CLIENT]: *** Registering region 3 again"); + msg = m_Connector.RegisterRegion(UUID.Zero, r3); + if (msg == String.Empty) + Console.WriteLine("[GRID CLIENT]: Successfully registered region 3"); + else + Console.WriteLine("[GRID CLIENT]: region 3 failed to register"); + + Console.WriteLine("[GRID CLIENT]: *** GetNeighbours of region 1"); + List regions = m_Connector.GetNeighbours(UUID.Zero, r1.RegionID); + if (regions == null) + Console.WriteLine("[GRID CLIENT]: GetNeighbours of region 1 failed"); + else if (regions.Count > 0) + { + if (regions.Count != 1) + Console.WriteLine("[GRID CLIENT]: GetNeighbours of region 1 returned more neighbours than expected: " + regions.Count); + else + Console.WriteLine("[GRID CLIENT]: GetNeighbours of region 1 returned the right neighbour " + regions[0].RegionName); + } + else + Console.WriteLine("[GRID CLIENT]: GetNeighbours of region 1 returned 0 neighbours"); + + + Console.WriteLine("[GRID CLIENT]: *** GetRegionByUUID of region 2 (this should succeed)"); + GridRegion region = m_Connector.GetRegionByUUID(UUID.Zero, r2.RegionID); + if (region == null) + Console.WriteLine("[GRID CLIENT]: GetRegionByUUID returned null"); + else + Console.WriteLine("[GRID CLIENT]: GetRegionByUUID returned region " + region.RegionName); + + Console.WriteLine("[GRID CLIENT]: *** GetRegionByUUID of non-existent region (this should fail)"); + region = m_Connector.GetRegionByUUID(UUID.Zero, UUID.Random()); + if (region == null) + Console.WriteLine("[GRID CLIENT]: GetRegionByUUID returned null"); + else + Console.WriteLine("[GRID CLIENT]: GetRegionByUUID returned region " + region.RegionName); + + Console.WriteLine("[GRID CLIENT]: *** GetRegionByName of region 3 (this should succeed)"); + region = m_Connector.GetRegionByName(UUID.Zero, r3.RegionName); + if (region == null) + Console.WriteLine("[GRID CLIENT]: GetRegionByName returned null"); + else + Console.WriteLine("[GRID CLIENT]: GetRegionByName returned region " + region.RegionName); + + Console.WriteLine("[GRID CLIENT]: *** GetRegionByName of non-existent region (this should fail)"); + region = m_Connector.GetRegionByName(UUID.Zero, "Foo"); + if (region == null) + Console.WriteLine("[GRID CLIENT]: GetRegionByName returned null"); + else + Console.WriteLine("[GRID CLIENT]: GetRegionByName returned region " + region.RegionName); + + Console.WriteLine("[GRID CLIENT]: *** GetRegionsByName (this should return 3 regions)"); + regions = m_Connector.GetRegionsByName(UUID.Zero, "Test", 10); + if (regions == null) + Console.WriteLine("[GRID CLIENT]: GetRegionsByName returned null"); + else + Console.WriteLine("[GRID CLIENT]: GetRegionsByName returned " + regions.Count + " regions"); + + Console.WriteLine("[GRID CLIENT]: *** GetRegionRange (this should return 2 regions)"); + regions = m_Connector.GetRegionRange(UUID.Zero, + (int)Util.RegionToWorldLoc(900), (int)Util.RegionToWorldLoc(1002), + (int)Util.RegionToWorldLoc(900), (int)Util.RegionToWorldLoc(1002) ); + if (regions == null) + Console.WriteLine("[GRID CLIENT]: GetRegionRange returned null"); + else + Console.WriteLine("[GRID CLIENT]: GetRegionRange returned " + regions.Count + " regions"); + Console.WriteLine("[GRID CLIENT]: *** GetRegionRange (this should return 0 regions)"); + regions = m_Connector.GetRegionRange(UUID.Zero, + (int)Util.RegionToWorldLoc(900), (int)Util.RegionToWorldLoc(950), + (int)Util.RegionToWorldLoc(900), (int)Util.RegionToWorldLoc(950) ); + if (regions == null) + Console.WriteLine("[GRID CLIENT]: GetRegionRange returned null"); + else + Console.WriteLine("[GRID CLIENT]: GetRegionRange returned " + regions.Count + " regions"); + + Console.Write("Proceed to deregister? Press enter..."); + Console.ReadLine(); + + // Deregister them all + Console.WriteLine("[GRID CLIENT]: *** Deregistering region 1"); + success = m_Connector.DeregisterRegion(r1.RegionID); + if (success) + Console.WriteLine("[GRID CLIENT]: Successfully deregistered region 1"); + else + Console.WriteLine("[GRID CLIENT]: region 1 failed to deregister"); + Console.WriteLine("[GRID CLIENT]: *** Deregistering region 2"); + success = m_Connector.DeregisterRegion(r2.RegionID); + if (success) + Console.WriteLine("[GRID CLIENT]: Successfully deregistered region 2"); + else + Console.WriteLine("[GRID CLIENT]: region 2 failed to deregister"); + Console.WriteLine("[GRID CLIENT]: *** Deregistering region 3"); + success = m_Connector.DeregisterRegion(r3.RegionID); + if (success) + Console.WriteLine("[GRID CLIENT]: Successfully deregistered region 3"); + else + Console.WriteLine("[GRID CLIENT]: region 3 failed to deregister"); + + } + + private static GridRegion CreateRegion(string name, uint xcell, uint ycell) + { + GridRegion region = new GridRegion(xcell, ycell); + region.RegionName = name; + region.RegionID = UUID.Random(); + region.ExternalHostName = "127.0.0.1"; + region.HttpPort = 9000; + region.InternalEndPoint = new System.Net.IPEndPoint(System.Net.IPAddress.Parse("0.0.0.0"), 9000); + + return region; + } + } +} diff --git a/Tests/OpenSim.Tests/ConfigurationLoaderTest.cs b/Tests/OpenSim.Tests/ConfigurationLoaderTest.cs new file mode 100644 index 00000000000..a14f1672c8f --- /dev/null +++ b/Tests/OpenSim.Tests/ConfigurationLoaderTest.cs @@ -0,0 +1,150 @@ +/* + * 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.IO; +using Nini.Config; +using NUnit.Framework; +using OpenSim.Framework; +using OpenSim.Tests.Common; + +namespace OpenSim.Tests +{ + [TestFixture] + public class ConfigurationLoaderTests : OpenSimTestCase + { + private const string m_testSubdirectory = "test"; + private string m_basePath; + private string m_workingDirectory; + private IConfigSource m_config; + + /// + /// Set up a test directory. + /// + [SetUp] + public override void SetUp() + { + base.SetUp(); + + m_basePath = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName()); + string path = Path.Combine(m_basePath, m_testSubdirectory); + Directory.CreateDirectory(path); + m_workingDirectory = Directory.GetCurrentDirectory(); + Directory.SetCurrentDirectory(path); + } + + /// + /// Remove the test directory. + /// + [TearDown] + public void TearDown() + { + Directory.SetCurrentDirectory(m_workingDirectory); + Directory.Delete(m_basePath, true); + } + + /// + /// Test the including of ini files with absolute and relative paths. + /// + [Test] + public void IncludeTests() + { + const string mainIniFile = "OpenSimDefaults.ini"; + m_config = new IniConfigSource(); + + // Create ini files in a directory structure + IniConfigSource ini; + IConfig config; + + ini = new IniConfigSource(); + config = ini.AddConfig("IncludeTest"); + config.Set("Include-absolute", "absolute/one/config/setting.ini"); + config.Set("Include-absolute1", "absolute/two/config/setting1.ini"); + config.Set("Include-absolute2", "absolute/two/config/setting2.ini"); + config.Set("Include-relative", "../" + m_testSubdirectory + "/relative/one/config/setting.ini"); + config.Set("Include-relative1", "../" + m_testSubdirectory + "/relative/two/config/setting1.ini"); + config.Set("Include-relative2", "../" + m_testSubdirectory + "/relative/two/config/setting2.ini"); + CreateIni(mainIniFile, ini); + + ini = new IniConfigSource(); + ini.AddConfig("Absolute1").Set("name1", "value1"); + CreateIni("absolute/one/config/setting.ini", ini); + + ini = new IniConfigSource(); + ini.AddConfig("Absolute2").Set("name2", 2.3); + CreateIni("absolute/two/config/setting1.ini", ini); + + ini = new IniConfigSource(); + ini.AddConfig("Absolute2").Set("name3", "value3"); + CreateIni("absolute/two/config/setting2.ini", ini); + + ini = new IniConfigSource(); + ini.AddConfig("Relative1").Set("name4", "value4"); + CreateIni("relative/one/config/setting.ini", ini); + + ini = new IniConfigSource(); + ini.AddConfig("Relative2").Set("name5", true); + CreateIni("relative/two/config/setting1.ini", ini); + + ini = new IniConfigSource(); + ini.AddConfig("Relative2").Set("name6", 6); + CreateIni("relative/two/config/setting2.ini", ini); + + // Prepare call to ConfigurationLoader.LoadConfigSettings() + ConfigurationLoader cl = new ConfigurationLoader(); + IConfigSource argvSource = new IniConfigSource(); + EnvConfigSource envConfigSource = new EnvConfigSource(); + argvSource.AddConfig("Startup").Set("inifile", mainIniFile); + argvSource.AddConfig("Network"); + ConfigSettings configSettings; + NetworkServersInfo networkInfo; + + OpenSimConfigSource source = cl.LoadConfigSettings(argvSource, envConfigSource, + out configSettings, out networkInfo); + + // Remove default config + config = source.Source.Configs["Startup"]; + source.Source.Configs.Remove(config); + config = source.Source.Configs["Network"]; + source.Source.Configs.Remove(config); + + // Finally, we are able to check the result + Assert.AreEqual(m_config.ToString(), source.Source.ToString(), + "Configuration with includes does not contain all settings."); + } + + private void CreateIni(string filepath, IniConfigSource source) + { + string path = Path.GetDirectoryName(filepath); + if (path != string.Empty) + { + Directory.CreateDirectory(path); + } + source.Save(filepath); + m_config.Merge(source); + } + } +} diff --git a/Tests/OpenSim.Tests/OpenSim.Tests.csproj b/Tests/OpenSim.Tests/OpenSim.Tests.csproj new file mode 100644 index 00000000000..aa0baa7d080 --- /dev/null +++ b/Tests/OpenSim.Tests/OpenSim.Tests.csproj @@ -0,0 +1,81 @@ + + + net6.0 + + + + ..\..\bin\Nini.dll + False + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file