/* * 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; [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"); Monitor.PulseAll(this); } } private void SaveCompleted(Guid requestId, string errorMessage) { lock (this) { m_lastRequestId = requestId; m_lastErrorMessage = errorMessage; Console.WriteLine("About to pulse ArchiverTests on SaveCompleted"); Monitor.PulseAll(this); } } 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); // 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); 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"); lock (this) { m_archiverModule.ArchiveRegion(archiveWriteStream, requestId); //AssetServerBase assetServer = (AssetServerBase)scene.CommsManager.AssetCache.AssetServer; //while (assetServer.HasWaitingRequests()) // assetServer.ProcessNextRequest(); 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); 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()); lock (this) { m_scene.EventManager.OnOarFileLoaded += LoadCompleted; m_archiverModule.DearchiveRegion(archiveReadStream); } 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()); lock (this) { m_scene.EventManager.OnOarFileLoaded += LoadCompleted; m_archiverModule.DearchiveRegion(archiveReadStream); } 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"); lock (this) { m_archiverModule.ArchiveRegion( archiveWriteStream, requestId, new Dictionary() { { "wipe-owners", Boolean.TrueString } }); Monitor.Wait(this, 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; lock (this) { scene2.EventManager.OnOarFileLoaded += LoadCompleted; archiverModule.DearchiveRegion(archiveReadStream); } 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 lock (this) { m_scene.EventManager.OnOarFileLoaded += LoadCompleted; m_archiverModule.DearchiveRegion(oarStream); } 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 = 0.4; 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)); tar.Close(); MemoryStream archiveReadStream = new MemoryStream(archiveWriteStream.ToArray()); lock (this) { m_scene.EventManager.OnOarFileLoaded += LoadCompleted; m_archiverModule.DearchiveRegion(archiveReadStream); } 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.FixedSun, Is.True); Assert.AreEqual(12.0, loadedRs.SunPosition); Assert.That(loadedRs.ObjectBonus, Is.EqualTo(1.4)); Assert.That(loadedRs.RestrictPushing, Is.True); Assert.That(loadedRs.TerrainLowerLimit, Is.EqualTo(0.4)); 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.UseEstateSun, Is.True); 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; lock (this) { m_archiverModule.ArchiveRegion(archiveWriteStream); Monitor.Wait(this, 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); Dictionary archiveOptions = new Dictionary(); archiveOptions.Add("merge", null); m_archiverModule.DearchiveRegion(archiveReadStream, Guid.Empty, archiveOptions); 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(); m_scene.EventManager.OnOarFileSaved += SaveCompleted; Guid requestId = new Guid("00000000-0000-0000-0000-808080808080"); Dictionary options = new Dictionary(); options.Add("all", true); lock (this) { m_archiverModule.ArchiveRegion(archiveWriteStream, requestId, options); Monitor.Wait(this, 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()); lock (this) { m_scene.EventManager.OnOarFileLoaded += LoadCompleted; m_archiverModule.DearchiveRegion(archiveReadStream); } 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"); Assert.That( object1PartLoaded.RotationOffset, Is.EqualTo(part1.RotationOffset), "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"); } } }