From 82690e138448ebac6456ab03dcca4b0a8a1cc57a Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Sat, 24 Nov 2012 02:43:31 +0000 Subject: Fix bug where loading an OAR with a deeded parcel would always set the parcel owner ID to the estate owner even if the group UUID was present. Aims to address http://opensimulator.org/mantis/view.php?id=6355 As part of this work, an incomplete IXGroupsData was added which currently only allows store/fetch/delete of group records (i.e. no membership data etc) This is subject to change and currently only an in-memory storage implementation exists for regression test purposes. --- .../World/Archiver/ArchiveReadRequest.cs | 30 +- .../World/Archiver/ArchiveWriteRequest.cs | 11 +- .../World/Archiver/Tests/ArchiverTests.cs | 312 +++++++++++++-------- 3 files changed, 213 insertions(+), 140 deletions(-) (limited to 'OpenSim/Region/CoreModules/World/Archiver') diff --git a/OpenSim/Region/CoreModules/World/Archiver/ArchiveReadRequest.cs b/OpenSim/Region/CoreModules/World/Archiver/ArchiveReadRequest.cs index 60bbf9b..c810242 100644 --- a/OpenSim/Region/CoreModules/World/Archiver/ArchiveReadRequest.cs +++ b/OpenSim/Region/CoreModules/World/Archiver/ArchiveReadRequest.cs @@ -552,19 +552,23 @@ namespace OpenSim.Region.CoreModules.World.Archiver // Validate User and Group UUID's - if (!ResolveUserUuid(scene, parcel.OwnerID)) - parcel.OwnerID = m_rootScene.RegionInfo.EstateSettings.EstateOwner; - - if (!ResolveGroupUuid(parcel.GroupID)) + if (parcel.IsGroupOwned) { -// m_log.DebugFormat("[ARCHIVE READ REQUEST]: Could not find group {0}", parcel.GroupID); - parcel.GroupID = UUID.Zero; - parcel.IsGroupOwned = false; + if (!ResolveGroupUuid(parcel.GroupID)) + { + parcel.OwnerID = m_rootScene.RegionInfo.EstateSettings.EstateOwner; + parcel.GroupID = UUID.Zero; + parcel.IsGroupOwned = false; + } + } + else + { + if (!ResolveUserUuid(scene, parcel.OwnerID)) + parcel.OwnerID = m_rootScene.RegionInfo.EstateSettings.EstateOwner; + + if (!ResolveGroupUuid(parcel.GroupID)) + parcel.GroupID = UUID.Zero; } -// else -// { -// m_log.DebugFormat("[ARCHIVE READ REQUEST]: Found group {0}", parcel.GroupID); -// } List accessList = new List(); foreach (LandAccessEntry entry in parcel.ParcelAccessList) @@ -576,8 +580,8 @@ namespace OpenSim.Region.CoreModules.World.Archiver parcel.ParcelAccessList = accessList; // m_log.DebugFormat( -// "[ARCHIVER]: Adding parcel {0}, local id {1}, area {2}", -// parcel.Name, parcel.LocalID, parcel.Area); +// "[ARCHIVER]: Adding parcel {0}, local id {1}, owner {2}, group {3}, isGroupOwned {4}, area {5}", +// parcel.Name, parcel.LocalID, parcel.OwnerID, parcel.GroupID, parcel.IsGroupOwned, parcel.Area); landData.Add(parcel); } diff --git a/OpenSim/Region/CoreModules/World/Archiver/ArchiveWriteRequest.cs b/OpenSim/Region/CoreModules/World/Archiver/ArchiveWriteRequest.cs index d751b1c..7bdd65c 100644 --- a/OpenSim/Region/CoreModules/World/Archiver/ArchiveWriteRequest.cs +++ b/OpenSim/Region/CoreModules/World/Archiver/ArchiveWriteRequest.cs @@ -167,7 +167,6 @@ namespace OpenSim.Region.CoreModules.World.Archiver } scenesGroup.CalcSceneLocations(); - m_archiveWriter = new TarArchiveWriter(m_saveStream); try @@ -216,7 +215,6 @@ namespace OpenSim.Region.CoreModules.World.Archiver } } - private void ArchiveOneRegion(Scene scene, string regionDir, Dictionary assetUuids) { m_log.InfoFormat("[ARCHIVER]: Writing region {0}", scene.RegionInfo.RegionName); @@ -540,7 +538,6 @@ namespace OpenSim.Region.CoreModules.World.Archiver xtw.WriteElementString("size_in_meters", string.Format("{0},{1}", size.X, size.Y)); } - protected void Save(Scene scene, List sceneObjects, string regionDir) { if (regionDir != string.Empty) @@ -560,8 +557,8 @@ namespace OpenSim.Region.CoreModules.World.Archiver foreach (ILandObject lo in landObjects) { LandData landData = lo.LandData; - string landDataPath = String.Format("{0}{1}{2}.xml", - regionDir, ArchiveConstants.LANDDATA_PATH, landData.GlobalID.ToString()); + string landDataPath + = String.Format("{0}{1}", regionDir, ArchiveConstants.CreateOarLandDataPath(landData)); m_archiveWriter.WriteFile(landDataPath, LandDataSerializer.Serialize(landData, m_options)); } @@ -604,7 +601,6 @@ namespace OpenSim.Region.CoreModules.World.Archiver CloseArchive(String.Empty); } - /// /// Closes the archive and notifies that we're done. @@ -629,6 +625,5 @@ namespace OpenSim.Region.CoreModules.World.Archiver m_rootScene.EventManager.TriggerOarFileSaved(m_requestId, errorMessage); } - } -} +} \ No newline at end of file diff --git a/OpenSim/Region/CoreModules/World/Archiver/Tests/ArchiverTests.cs b/OpenSim/Region/CoreModules/World/Archiver/Tests/ArchiverTests.cs index 82f49b0..7cc3519 100644 --- a/OpenSim/Region/CoreModules/World/Archiver/Tests/ArchiverTests.cs +++ b/OpenSim/Region/CoreModules/World/Archiver/Tests/ArchiverTests.cs @@ -31,16 +31,19 @@ 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 OpenSim.Tests.Common.Mock; using ArchiveConstants = OpenSim.Framework.Serialization.ArchiveConstants; @@ -127,6 +130,53 @@ namespace OpenSim.Region.CoreModules.World.Archiver.Tests 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. @@ -204,30 +254,6 @@ namespace OpenSim.Region.CoreModules.World.Archiver.Tests // TODO: Test presence of more files and contents of files. } - 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); - } - /// /// Test saving an OpenSim Region Archive with the no assets option /// @@ -309,59 +335,6 @@ namespace OpenSim.Region.CoreModules.World.Archiver.Tests } /// - /// 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. /// [Test] @@ -435,50 +408,57 @@ namespace OpenSim.Region.CoreModules.World.Archiver.Tests TestLoadedRegion(part1, soundItemName, soundData); } - private static void CreateSoundAsset(TarArchiveWriter tar, Assembly assembly, string soundDataResourceName, out byte[] soundData, out UUID soundUuid) + /// + /// 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() { - 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); + TestHelpers.InMethod(); - /* - AssetBase soundAsset = AssetHelpers.CreateAsset(soundUuid, soundData); - scene.AssetService.Store(soundAsset); - asset1FileName = ArchiveConstants.ASSETS_PATH + soundUuid + ".wav"; - */ - } - } - } + UUID ownerId = TestHelpers.ParseTail(0xaaaa); - private void TestLoadedRegion(SceneObjectPart part1, string soundItemName, byte[] soundData) - { - SceneObjectPart object1PartLoaded = m_scene.GetSceneObjectPart(part1.Name); + MemoryStream archiveWriteStream = new MemoryStream(); + TarArchiveWriter tar = new TarArchiveWriter(archiveWriteStream); - 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)); + tar.WriteFile( + ArchiveConstants.CONTROL_FILE_PATH, + new ArchiveWriteRequest(m_scene, (Stream)null, Guid.Empty).CreateControlFile(new ArchiveScenesGroup())); - 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"); + 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); - Assert.Greater(m_scene.LandChannel.AllParcels().Count, 0, "incorrect number of parcels"); + // 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)); } /// @@ -563,6 +543,81 @@ namespace OpenSim.Region.CoreModules.World.Archiver.Tests } /// + /// 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, null); + + // FIXME: We set directly rather than call SetLandBitmap in order not to do an AABB value update, which + // requests the terrain heightmap from an active scene. This is confusing and not a long-term solution. + //lo.LandBitmap = lo.BasicFullRegionLandBitmap(); + lo.SetLandBitmap(lo.BasicFullRegionLandBitmap()); + + // FIXME: We have to make a separate call to update the LandData's copy of the land bitmap, even though this is + // identical to the LandObject copy. This should be changed so there's only one copy of the data if at all + // possible + //lo.UpdateLandBitmapByteArray(); + + LandData ld = lo.LandData; + ld.GlobalID = landID; + + string ldPath = ArchiveConstants.CreateOarLandDataPath(ld); + tar.WriteFile(ldPath, LandDataSerializer.Serialize(ld, null)); + 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] @@ -781,9 +836,7 @@ namespace OpenSim.Region.CoreModules.World.Archiver.Tests } } - // Save OAR - MemoryStream archiveWriteStream = new MemoryStream(); m_scene.EventManager.OnOarFileSaved += SaveCompleted; @@ -800,7 +853,6 @@ namespace OpenSim.Region.CoreModules.World.Archiver.Tests // Check that the OAR contains the expected data - Assert.That(m_lastRequestId, Is.EqualTo(requestId)); byte[] archive = archiveWriteStream.ToArray(); @@ -976,5 +1028,27 @@ namespace OpenSim.Region.CoreModules.World.Archiver.Tests 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"); + } } -} +} \ No newline at end of file -- cgit v1.1