public void TestImportBeatmapThenCleanup() { RunTestWithRealmAsync(async(realm, storage) => { using (var importer = new BeatmapImporter(storage, realm)) using (new RealmRulesetStore(realm, storage)) { var imported = await importer.Import(new ImportTask(TestResources.GetTestBeatmapStream(), "renatus.osz")); EnsureLoaded(realm.Realm); Assert.AreEqual(1, realm.Realm.All <BeatmapSetInfo>().Count()); Assert.NotNull(imported); Debug.Assert(imported != null); imported.PerformWrite(s => s.DeletePending = true); Assert.AreEqual(1, realm.Realm.All <BeatmapSetInfo>().Count(s => s.DeletePending)); } }); Logger.Log("Running with no work to purge pending deletions"); RunTestWithRealm((realm, _) => { Assert.AreEqual(0, realm.Realm.All <BeatmapSetInfo>().Count()); }); }
public void TestImportDirectoryWithEmptyOsuFiles() { RunTestWithRealmAsync(async(realm, storage) => { using var importer = new BeatmapImporter(storage, realm); using var store = new RealmRulesetStore(realm, storage); string?temp = TestResources.GetTestBeatmapForImport(); string extractedFolder = $"{temp}_extracted"; Directory.CreateDirectory(extractedFolder); try { using (var zip = ZipArchive.Open(temp)) zip.WriteToDirectory(extractedFolder); foreach (var file in new DirectoryInfo(extractedFolder).GetFiles("*.osu")) { using (file.Open(FileMode.Create)) { // empty file. } } var imported = await importer.Import(new ImportTask(extractedFolder)); Assert.IsNull(imported); } finally { Directory.Delete(extractedFolder, true); } }); }
public void TestAddFileToAsyncImportedBeatmap() { RunTestWithRealm((realm, storage) => { BeatmapSetInfo?detachedSet = null; var manager = new ModelManager <BeatmapSetInfo>(storage, realm); using (var importer = new BeatmapImporter(storage, realm)) using (new RealmRulesetStore(realm, storage)) { Task.Run(async() => { // ReSharper disable once AccessToDisposedClosure var beatmapSet = await importer.Import(new ImportTask(TestResources.GetTestBeatmapStream(), "renatus.osz")); Assert.NotNull(beatmapSet); Debug.Assert(beatmapSet != null); // Intentionally detach on async thread as to not trigger a refresh on the main thread. beatmapSet.PerformRead(s => detachedSet = s.Detach()); }).WaitSafely(); Debug.Assert(detachedSet != null); manager.AddFile(detachedSet, new MemoryStream(), "test"); } }); }
public void TestImportThenDeleteFromStream() { RunTestWithRealmAsync(async(realmFactory, storage) => { using var importer = new BeatmapImporter(realmFactory, storage); using var store = new RealmRulesetStore(realmFactory, storage); string?tempPath = TestResources.GetTestBeatmapForImport(); ILive <RealmBeatmapSet>?importedSet; using (var stream = File.OpenRead(tempPath)) { importedSet = await importer.Import(new ImportTask(stream, Path.GetFileName(tempPath))); ensureLoaded(realmFactory.Context); } Assert.NotNull(importedSet); Debug.Assert(importedSet != null); Assert.IsTrue(File.Exists(tempPath), "Stream source file somehow went missing"); File.Delete(tempPath); var imported = realmFactory.Context.All <RealmBeatmapSet>().First(beatmapSet => beatmapSet.ID == importedSet.ID); deleteBeatmapSet(imported, realmFactory.Context); }); }
public static int Main(string[] args) { LegacyFilesystemReader.Register(); using (DesktopGameHost host = Host.GetSuitableHost(@"osu", true)) { if (!host.IsPrimaryInstance) { var importer = new BeatmapImporter(host); foreach (var file in args) { if (!importer.Import(file).Wait(1000)) { throw new TimeoutException(@"IPC took too long to send"); } } Console.WriteLine(@"Sent import requests to running instance"); } else { Ruleset.Register(new OsuRuleset()); Ruleset.Register(new TaikoRuleset()); Ruleset.Register(new ManiaRuleset()); Ruleset.Register(new CatchRuleset()); BaseGame osu = new OsuGame(args); host.Add(osu); host.Run(); } return(0); } }
public void TestRollbackOnFailure() { RunTestWithRealmAsync(async(realm, storage) => { int loggedExceptionCount = 0; Logger.NewEntry += l => { if (l.Target == LoggingTarget.Database && l.Exception != null) { Interlocked.Increment(ref loggedExceptionCount); } }; using var importer = new BeatmapImporter(storage, realm); using var store = new RealmRulesetStore(realm, storage); var imported = await LoadOszIntoStore(importer, realm.Realm); realm.Realm.Write(() => imported.Hash += "-changed"); checkBeatmapSetCount(realm.Realm, 1); checkBeatmapCount(realm.Realm, 12); checkSingleReferencedFileCount(realm.Realm, 18); string?brokenTempFilename = TestResources.GetTestBeatmapForImport(); MemoryStream brokenOsu = new MemoryStream(); MemoryStream brokenOsz = new MemoryStream(await File.ReadAllBytesAsync(brokenTempFilename)); File.Delete(brokenTempFilename); using (var outStream = File.Open(brokenTempFilename, FileMode.CreateNew)) using (var zip = ZipArchive.Open(brokenOsz)) { zip.AddEntry("broken.osu", brokenOsu, false); zip.SaveTo(outStream, CompressionType.Deflate); } // this will trigger purging of the existing beatmap (online set id match) but should rollback due to broken osu. try { await importer.Import(new ImportTask(brokenTempFilename)); } catch { } EnsureLoaded(realm.Realm); checkBeatmapSetCount(realm.Realm, 1); checkBeatmapCount(realm.Realm, 12); checkSingleReferencedFileCount(realm.Realm, 18); Assert.AreEqual(1, loggedExceptionCount); File.Delete(brokenTempFilename); }); }
public static int Main(string[] args) { DesktopGameHost host = Host.GetSuitableHost(@"osu", true); if (!host.IsPrimaryInstance) { var importer = new BeatmapImporter(host); foreach (var file in args) { if (!importer.Import(file).Wait(1000)) { throw new TimeoutException(@"IPC took too long to send"); } } Console.WriteLine(@"Sent import requests to running instance"); } else { BaseGame osu = new OsuGame(args); host.Add(osu); host.Run(); } return(0); }
public void TestImportBeatmapThenCleanup() { RunTestWithRealmAsync(async(realmFactory, storage) => { using (var importer = new BeatmapImporter(realmFactory, storage)) using (new RealmRulesetStore(realmFactory, storage)) { ILive <RealmBeatmapSet>?imported; using (var reader = new ZipArchiveReader(TestResources.GetTestBeatmapStream())) imported = await importer.Import(reader); Assert.AreEqual(1, realmFactory.Context.All <RealmBeatmapSet>().Count()); Assert.NotNull(imported); Debug.Assert(imported != null); imported.PerformWrite(s => s.DeletePending = true); Assert.AreEqual(1, realmFactory.Context.All <RealmBeatmapSet>().Count(s => s.DeletePending)); } }); Logger.Log("Running with no work to purge pending deletions"); RunTestWithRealm((realmFactory, _) => { Assert.AreEqual(0, realmFactory.Context.All <RealmBeatmapSet>().Count()); }); }
public void TestImportWithDuplicateHashes() { RunTestWithRealmAsync(async(realmFactory, storage) => { using var importer = new BeatmapImporter(realmFactory, storage); using var store = new RealmRulesetStore(realmFactory, storage); string?temp = TestResources.GetTestBeatmapForImport(); string extractedFolder = $"{temp}_extracted"; Directory.CreateDirectory(extractedFolder); try { using (var zip = ZipArchive.Open(temp)) zip.WriteToDirectory(extractedFolder); using (var zip = ZipArchive.Create()) { zip.AddAllFromDirectory(extractedFolder); zip.AddEntry("duplicate.osu", Directory.GetFiles(extractedFolder, "*.osu").First()); zip.SaveTo(temp, new ZipWriterOptions(CompressionType.Deflate)); } await importer.Import(temp); ensureLoaded(realmFactory.Context); } finally { Directory.Delete(extractedFolder, true); } }); }
public void TestModelCreationFailureDoesntReturn() { RunTestWithRealmAsync(async(realmFactory, storage) => { using var importer = new BeatmapImporter(realmFactory, storage); using var store = new RealmRulesetStore(realmFactory, storage); var progressNotification = new ImportProgressNotification(); var zipStream = new MemoryStream(); using (var zip = ZipArchive.Create()) zip.SaveTo(zipStream, new ZipWriterOptions(CompressionType.Deflate)); var imported = await importer.Import( progressNotification, new ImportTask(zipStream, string.Empty) ); checkBeatmapSetCount(realmFactory.Context, 0); checkBeatmapCount(realmFactory.Context, 0); Assert.IsEmpty(imported); Assert.AreEqual(ProgressNotificationState.Cancelled, progressNotification.State); }); }
public void TestUpdateDetachedBeatmapSet() { RunTestWithRealmAsync(async(realm, storage) => { using (var importer = new BeatmapImporter(storage, realm)) using (new RealmRulesetStore(realm, storage)) { var beatmapSet = await importer.Import(new ImportTask(TestResources.GetTestBeatmapStream(), "renatus.osz")); Assert.NotNull(beatmapSet); Debug.Assert(beatmapSet != null); // Detach at the BeatmapInfo point, similar to what GetWorkingBeatmap does. BeatmapInfo?detachedBeatmap = null; beatmapSet.PerformRead(s => detachedBeatmap = s.Beatmaps.First().Detach()); BeatmapSetInfo?detachedBeatmapSet = detachedBeatmap?.BeatmapSet; Debug.Assert(detachedBeatmapSet != null); var newUser = new RealmUser { Username = "******", OnlineID = 2 }; detachedBeatmapSet.Beatmaps.First().Metadata.Artist = "New Artist"; detachedBeatmapSet.Beatmaps.First().Metadata.Author = newUser; Assert.AreNotEqual(detachedBeatmapSet.Status, BeatmapOnlineStatus.Ranked); detachedBeatmapSet.Status = BeatmapOnlineStatus.Ranked; beatmapSet.PerformWrite(s => { detachedBeatmapSet.CopyChangesToRealm(s); }); beatmapSet.PerformRead(s => { // Check above changes explicitly. Assert.AreEqual(BeatmapOnlineStatus.Ranked, s.Status); Assert.AreEqual("New Artist", s.Beatmaps.First().Metadata.Artist); Assert.AreEqual(newUser, s.Beatmaps.First().Metadata.Author); Assert.NotZero(s.Files.Count); // Check nothing was lost in the copy operation. Assert.AreEqual(s.Files.Count, detachedBeatmapSet.Files.Count); Assert.AreEqual(s.Files.Select(f => f.File).Count(), detachedBeatmapSet.Files.Select(f => f.File).Count()); Assert.AreEqual(s.Beatmaps.Count, detachedBeatmapSet.Beatmaps.Count); Assert.AreEqual(s.Beatmaps.Select(f => f.Difficulty).Count(), detachedBeatmapSet.Beatmaps.Select(f => f.Difficulty).Count()); Assert.AreEqual(s.Metadata, detachedBeatmapSet.Metadata); }); } }); }
public static async Task <RealmBeatmapSet?> LoadQuickOszIntoOsu(BeatmapImporter importer, Realm realm) { string?temp = TestResources.GetQuickTestBeatmapForImport(); var importedSet = await importer.Import(new ImportTask(temp)); Assert.NotNull(importedSet); ensureLoaded(realm); waitForOrAssert(() => !File.Exists(temp), "Temporary file still exists after standard import", 5000); return(realm.All <RealmBeatmapSet>().FirstOrDefault(beatmapSet => beatmapSet.ID == importedSet !.ID)); }
public void TestImportWithIgnoredDirectoryInArchive() { RunTestWithRealmAsync(async(realmFactory, storage) => { using var importer = new BeatmapImporter(realmFactory, storage); using var store = new RealmRulesetStore(realmFactory, storage); string?temp = TestResources.GetTestBeatmapForImport(); string extractedFolder = $"{temp}_extracted"; string dataFolder = Path.Combine(extractedFolder, "actual_data"); string resourceForkFolder = Path.Combine(extractedFolder, "__MACOSX"); string resourceForkFilePath = Path.Combine(resourceForkFolder, ".extracted"); Directory.CreateDirectory(dataFolder); Directory.CreateDirectory(resourceForkFolder); using (var resourceForkFile = File.CreateText(resourceForkFilePath)) { await resourceForkFile.WriteLineAsync("adding content so that it's not empty"); } try { using (var zip = ZipArchive.Open(temp)) zip.WriteToDirectory(dataFolder); using (var zip = ZipArchive.Create()) { zip.AddAllFromDirectory(extractedFolder); zip.SaveTo(temp, new ZipWriterOptions(CompressionType.Deflate)); } var imported = await importer.Import(new ImportTask(temp)); Assert.NotNull(imported); Debug.Assert(imported != null); ensureLoaded(realmFactory.Context); Assert.IsFalse(imported.PerformRead(s => s.Files.Any(f => f.Filename.Contains("__MACOSX"))), "Files contain resource fork folder, which should be ignored"); Assert.IsFalse(imported.PerformRead(s => s.Files.Any(f => f.Filename.Contains("actual_data"))), "Files contain common subfolder"); } finally { Directory.Delete(extractedFolder, true); } }); }
public void TestImportThenImportWithChangedHashedFile() { RunTestWithRealmAsync(async(realmFactory, storage) => { using var importer = new BeatmapImporter(realmFactory, storage); using var store = new RealmRulesetStore(realmFactory, storage); string?temp = TestResources.GetTestBeatmapForImport(); string extractedFolder = $"{temp}_extracted"; Directory.CreateDirectory(extractedFolder); try { var imported = await LoadOszIntoStore(importer, realmFactory.Context); await createScoreForBeatmap(realmFactory.Context, imported.Beatmaps.First()); using (var zip = ZipArchive.Open(temp)) zip.WriteToDirectory(extractedFolder); // arbitrary write to hashed file // this triggers the special BeatmapManager.PreImport deletion/replacement flow. using (var sw = new FileInfo(Directory.GetFiles(extractedFolder, "*.osu").First()).AppendText()) await sw.WriteLineAsync("// changed"); using (var zip = ZipArchive.Create()) { zip.AddAllFromDirectory(extractedFolder); zip.SaveTo(temp, new ZipWriterOptions(CompressionType.Deflate)); } var importedSecondTime = await importer.Import(new ImportTask(temp)); ensureLoaded(realmFactory.Context); // check the newly "imported" beatmap is not the original. Assert.NotNull(importedSecondTime); Debug.Assert(importedSecondTime != null); Assert.IsTrue(imported.ID != importedSecondTime.ID); Assert.IsTrue(imported.Beatmaps.First().ID != importedSecondTime.PerformRead(s => s.Beatmaps.First().ID)); } finally { Directory.Delete(extractedFolder, true); } }); }
public void TestImportWhenFileOpen() { RunTestWithRealmAsync(async(realmFactory, storage) => { using var importer = new BeatmapImporter(realmFactory, storage); using var store = new RealmRulesetStore(realmFactory, storage); string?temp = TestResources.GetTestBeatmapForImport(); using (File.OpenRead(temp)) await importer.Import(temp); ensureLoaded(realmFactory.Context); File.Delete(temp); Assert.IsFalse(File.Exists(temp), "We likely held a read lock on the file when we shouldn't"); }); }
public static async Task <RealmBeatmapSet> LoadOszIntoStore(BeatmapImporter importer, Realm realm, string?path = null, bool virtualTrack = false) { string?temp = path ?? TestResources.GetTestBeatmapForImport(virtualTrack); var importedSet = await importer.Import(new ImportTask(temp)); Assert.NotNull(importedSet); Debug.Assert(importedSet != null); ensureLoaded(realm); waitForOrAssert(() => !File.Exists(temp), "Temporary file still exists after standard import", 5000); return(realm.All <RealmBeatmapSet>().First(beatmapSet => beatmapSet.ID == importedSet.ID)); }
public void TestImportThenImportWithReZip() { RunTestWithRealmAsync(async(realmFactory, storage) => { using var importer = new BeatmapImporter(realmFactory, storage); using var store = new RealmRulesetStore(realmFactory, storage); string?temp = TestResources.GetTestBeatmapForImport(); string extractedFolder = $"{temp}_extracted"; Directory.CreateDirectory(extractedFolder); try { var imported = await LoadOszIntoStore(importer, realmFactory.Context); string hashBefore = hashFile(temp); using (var zip = ZipArchive.Open(temp)) zip.WriteToDirectory(extractedFolder); using (var zip = ZipArchive.Create()) { zip.AddAllFromDirectory(extractedFolder); zip.SaveTo(temp, new ZipWriterOptions(CompressionType.Deflate)); } // zip files differ because different compression or encoder. Assert.AreNotEqual(hashBefore, hashFile(temp)); var importedSecondTime = await importer.Import(new ImportTask(temp)); ensureLoaded(realmFactory.Context); Assert.NotNull(importedSecondTime); Debug.Assert(importedSecondTime != null); // but contents doesn't, so existing should still be used. Assert.IsTrue(imported.ID == importedSecondTime.ID); Assert.IsTrue(imported.Beatmaps.First().ID == importedSecondTime.PerformRead(s => s.Beatmaps.First().ID)); } finally { Directory.Delete(extractedFolder, true); } }); }
public void TestImportThenImportWithDifferentFilename() { RunTestWithRealmAsync(async(realmFactory, storage) => { using var importer = new BeatmapImporter(realmFactory, storage); using var store = new RealmRulesetStore(realmFactory, storage); string?temp = TestResources.GetTestBeatmapForImport(); string extractedFolder = $"{temp}_extracted"; Directory.CreateDirectory(extractedFolder); try { var imported = await LoadOszIntoStore(importer, realmFactory.Context); using (var zip = ZipArchive.Open(temp)) zip.WriteToDirectory(extractedFolder); // change filename var firstFile = new FileInfo(Directory.GetFiles(extractedFolder).First()); firstFile.MoveTo(Path.Combine(firstFile.DirectoryName.AsNonNull(), $"{firstFile.Name}-changed{firstFile.Extension}")); using (var zip = ZipArchive.Create()) { zip.AddAllFromDirectory(extractedFolder); zip.SaveTo(temp, new ZipWriterOptions(CompressionType.Deflate)); } var importedSecondTime = await importer.Import(new ImportTask(temp)); ensureLoaded(realmFactory.Context); Assert.NotNull(importedSecondTime); Debug.Assert(importedSecondTime != null); // check the newly "imported" beatmap is not the original. Assert.IsTrue(imported.ID != importedSecondTime.ID); Assert.IsTrue(imported.Beatmaps.First().ID != importedSecondTime.PerformRead(s => s.Beatmaps.First().ID)); } finally { Directory.Delete(extractedFolder, true); } }); }
public void TestImportWithDuplicateBeatmapIDs() { RunTestWithRealmAsync(async(realmFactory, storage) => { using var importer = new BeatmapImporter(realmFactory, storage); using var store = new RealmRulesetStore(realmFactory, storage); var metadata = new RealmBeatmapMetadata { Artist = "SomeArtist", Author = { Username = "******" } }; var ruleset = realmFactory.Context.All <RealmRuleset>().First(); var toImport = new RealmBeatmapSet { OnlineID = 1, Beatmaps = { new RealmBeatmap(ruleset, new RealmBeatmapDifficulty(), metadata) { OnlineID = 2, }, new RealmBeatmap(ruleset, new RealmBeatmapDifficulty(), metadata) { OnlineID = 2, Status = BeatmapSetOnlineStatus.Loved, } } }; var imported = await importer.Import(toImport); Assert.NotNull(imported); Debug.Assert(imported != null); Assert.AreEqual(-1, imported.PerformRead(s => s.Beatmaps[0].OnlineID)); Assert.AreEqual(-1, imported.PerformRead(s => s.Beatmaps[1].OnlineID)); }); }
public void TestImportOverIPC() { HeadlessGameHost host = new HeadlessGameHost("host", true); HeadlessGameHost client = new HeadlessGameHost("client", true); Assert.IsTrue(host.IsPrimaryInstance); Assert.IsTrue(!client.IsPrimaryInstance); var osu = loadOsu(host); var importer = new BeatmapImporter(client); if (!importer.Import(osz_path).Wait(1000)) { Assert.Fail(@"IPC took too long to send"); } ensureLoaded(osu, 10000); }
public void TestUpdateBeatmapInfo() { RunTestWithRealmAsync(async(realmFactory, storage) => { using var importer = new BeatmapImporter(realmFactory, storage); using var store = new RealmRulesetStore(realmFactory, storage); string?temp = TestResources.GetTestBeatmapForImport(); await importer.Import(temp); // Update via the beatmap, not the beatmap info, to ensure correct linking RealmBeatmapSet setToUpdate = realmFactory.Context.All <RealmBeatmapSet>().First(); var beatmapToUpdate = setToUpdate.Beatmaps.First(); realmFactory.Context.Write(() => beatmapToUpdate.DifficultyName = "updated"); RealmBeatmap updatedInfo = realmFactory.Context.All <RealmBeatmap>().First(b => b.ID == beatmapToUpdate.ID); Assert.That(updatedInfo.DifficultyName, Is.EqualTo("updated")); }); }
public void TestImportNestedStructure() { RunTestWithRealmAsync(async(realmFactory, storage) => { using var importer = new BeatmapImporter(realmFactory, storage); using var store = new RealmRulesetStore(realmFactory, storage); string?temp = TestResources.GetTestBeatmapForImport(); string extractedFolder = $"{temp}_extracted"; string subfolder = Path.Combine(extractedFolder, "subfolder"); Directory.CreateDirectory(subfolder); try { using (var zip = ZipArchive.Open(temp)) zip.WriteToDirectory(subfolder); using (var zip = ZipArchive.Create()) { zip.AddAllFromDirectory(extractedFolder); zip.SaveTo(temp, new ZipWriterOptions(CompressionType.Deflate)); } var imported = await importer.Import(new ImportTask(temp)); Assert.NotNull(imported); Debug.Assert(imported != null); ensureLoaded(realmFactory.Context); Assert.IsFalse(imported.PerformRead(s => s.Files.Any(f => f.Filename.Contains("subfolder"))), "Files contain common subfolder"); } finally { Directory.Delete(extractedFolder, true); } }); }
public void TestDetachBeatmapSet() { RunTestWithRealmAsync(async(realm, storage) => { using (var importer = new BeatmapImporter(storage, realm)) using (new RealmRulesetStore(realm, storage)) { var beatmapSet = await importer.Import(new ImportTask(TestResources.GetTestBeatmapStream(), "renatus.osz")); Assert.NotNull(beatmapSet); Debug.Assert(beatmapSet != null); BeatmapSetInfo?detachedBeatmapSet = null; beatmapSet.PerformRead(live => { detachedBeatmapSet = live.Detach(); // files are omitted Assert.AreEqual(0, detachedBeatmapSet.Files.Count); Assert.AreEqual(live.Beatmaps.Count, detachedBeatmapSet.Beatmaps.Count); Assert.AreEqual(live.Beatmaps.Select(f => f.Difficulty).Count(), detachedBeatmapSet.Beatmaps.Select(f => f.Difficulty).Count()); Assert.AreEqual(live.Metadata, detachedBeatmapSet.Metadata); }); Debug.Assert(detachedBeatmapSet != null); // Check detached instances can all be accessed without throwing. Assert.AreEqual(0, detachedBeatmapSet.Files.Count); Assert.NotNull(detachedBeatmapSet.Beatmaps.Count); Assert.NotZero(detachedBeatmapSet.Beatmaps.Select(f => f.Difficulty).Count()); Assert.NotNull(detachedBeatmapSet.Metadata); // Check cyclic reference to beatmap set Assert.AreEqual(detachedBeatmapSet, detachedBeatmapSet.Beatmaps.First().BeatmapSet); } }); }
public static int Main(string[] args) { LegacyFilesystemReader.Register(); // Back up the cwd before DesktopGameHost changes it var cwd = Environment.CurrentDirectory; using (DesktopGameHost host = Host.GetSuitableHost(@"osu", true)) { if (!host.IsPrimaryInstance) { var importer = new BeatmapImporter(host); // Restore the cwd so relative paths given at the command line work correctly Directory.SetCurrentDirectory(cwd); foreach (var file in args) { Console.WriteLine(@"Importing {0}", file); if (!importer.Import(Path.GetFullPath(file)).Wait(3000)) { throw new TimeoutException(@"IPC took too long to send"); } } } else { Ruleset.Register(new OsuRuleset()); Ruleset.Register(new TaikoRuleset()); Ruleset.Register(new ManiaRuleset()); Ruleset.Register(new CatchRuleset()); BaseGame osu = new OsuGameDesktop(args); host.Add(osu); host.Run(); } return(0); } }