Exemplo n.º 1
0
        public void TestImportThenReimportAfterMissingFiles()
        {
            RunTestWithRealmAsync(async(realmFactory, storage) =>
            {
                using var importer = new BeatmapModelManager(realmFactory, storage);
                using var store    = new RealmRulesetStore(realmFactory, storage);

                var imported = await LoadOszIntoStore(importer, realmFactory.Realm);

                deleteBeatmapSet(imported, realmFactory.Realm);

                Assert.IsTrue(imported.DeletePending);

                // intentionally nuke all files
                storage.DeleteDirectory("files");

                Assert.That(imported.Files.All(f => !storage.GetStorageForDirectory("files").Exists(f.File.GetStoragePath())));

                var importedSecondTime = await LoadOszIntoStore(importer, realmFactory.Realm);

                // check the newly "imported" beatmap is actually just the restored previous import. since it matches hash.
                Assert.IsTrue(imported.ID == importedSecondTime.ID);
                Assert.IsTrue(imported.Beatmaps.First().ID == importedSecondTime.Beatmaps.First().ID);
                Assert.IsFalse(imported.DeletePending);
                Assert.IsFalse(importedSecondTime.DeletePending);

                // check that the files now exist, even though they were deleted above.
                Assert.That(importedSecondTime.Files.All(f => storage.GetStorageForDirectory("files").Exists(f.File.GetStoragePath())));
            });
        }
Exemplo n.º 2
0
        public void TestImportThenDeleteThenImportNonOptimisedPath()
        {
            RunTestWithRealmAsync(async(realm, storage) =>
            {
                using var importer = new NonOptimisedBeatmapImporter(realm, storage);
                using var store    = new RealmRulesetStore(realm, storage);

                var imported = await LoadOszIntoStore(importer, realm.Realm);

                deleteBeatmapSet(imported, realm.Realm);

                Assert.IsTrue(imported.DeletePending);

                var originalAddedDate = imported.DateAdded;

                var importedSecondTime = await LoadOszIntoStore(importer, realm.Realm);

                // check the newly "imported" beatmap is actually just the restored previous import. since it matches hash.
                Assert.IsTrue(imported.ID == importedSecondTime.ID);
                Assert.IsTrue(imported.Beatmaps.First().ID == importedSecondTime.Beatmaps.First().ID);
                Assert.IsFalse(imported.DeletePending);
                Assert.IsFalse(importedSecondTime.DeletePending);
                Assert.That(importedSecondTime.DateAdded, Is.GreaterThan(originalAddedDate));
            });
        }
Exemplo n.º 3
0
        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);
            });
        }
Exemplo n.º 4
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 BeatmapModelManager(realm, storage);
                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);
            });
        }
Exemplo n.º 5
0
        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);
                }
            });
        }
Exemplo n.º 6
0
        public void TestImportThenDeleteThenImportWithOnlineIDsMissing()
        {
            RunTestWithRealmAsync(async(realmFactory, storage) =>
            {
                using var importer = new BeatmapImporter(realmFactory, storage);
                using var store    = new RealmRulesetStore(realmFactory, storage);

                var imported = await LoadOszIntoStore(importer, realmFactory.Context);

                realmFactory.Context.Write(() =>
                {
                    foreach (var b in imported.Beatmaps)
                    {
                        b.OnlineID = -1;
                    }
                });

                deleteBeatmapSet(imported, realmFactory.Context);

                var importedSecondTime = await LoadOszIntoStore(importer, realmFactory.Context);

                // check the newly "imported" beatmap has been reimported due to mismatch (even though hashes matched)
                Assert.IsTrue(imported.ID != importedSecondTime.ID);
                Assert.IsTrue(imported.Beatmaps.First().ID != importedSecondTime.Beatmaps.First().ID);
            });
        }
Exemplo n.º 7
0
        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);
                }
            });
        }
Exemplo n.º 8
0
        public void TestImportCorruptThenImport()
        {
            RunTestWithRealmAsync(async(realmFactory, storage) =>
            {
                using var importer = new BeatmapImporter(realmFactory, storage);
                using var store    = new RealmRulesetStore(realmFactory, storage);

                var imported = await LoadOszIntoStore(importer, realmFactory.Context);

                var firstFile = imported.Files.First();

                long originalLength;
                using (var stream = storage.GetStream(firstFile.File.StoragePath))
                    originalLength = stream.Length;

                using (var stream = storage.GetStream(firstFile.File.StoragePath, FileAccess.Write, FileMode.Create))
                    stream.WriteByte(0);

                var importedSecondTime = await LoadOszIntoStore(importer, realmFactory.Context);

                using (var stream = storage.GetStream(firstFile.File.StoragePath))
                    Assert.AreEqual(stream.Length, originalLength, "Corruption was not fixed on second import");

                // check the newly "imported" beatmap is actually just the restored previous import. since it matches hash.
                Assert.IsTrue(imported.ID == importedSecondTime.ID);
                Assert.IsTrue(imported.Beatmaps.First().ID == importedSecondTime.Beatmaps.First().ID);

                checkBeatmapSetCount(realmFactory.Context, 1);
                checkSingleReferencedFileCount(realmFactory.Context, 18);
            });
        }
Exemplo n.º 9
0
        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);
            });
        }
Exemplo n.º 10
0
        public void TestImportWhenClosed()
        {
            RunTestWithRealmAsync(async(realm, storage) =>
            {
                using var importer = new BeatmapModelManager(realm, storage);
                using var store    = new RealmRulesetStore(realm, storage);

                await LoadOszIntoStore(importer, realm.Realm);
            });
        }
Exemplo n.º 11
0
        public void TestCreateStore()
        {
            RunTestWithRealm((realm, storage) =>
            {
                var rulesets = new RealmRulesetStore(realm, storage);

                Assert.AreEqual(4, rulesets.AvailableRulesets.Count());
                Assert.AreEqual(4, realm.Realm.All <RulesetInfo>().Count());
            });
        }
Exemplo n.º 12
0
        public void TestImportWhenClosed()
        {
            RunTestWithRealmAsync(async(realmFactory, storage) =>
            {
                using var importer = new BeatmapImporter(realmFactory, storage);
                using var store    = new RealmRulesetStore(realmFactory, storage);

                await LoadOszIntoStore(importer, realmFactory.Context);
            });
        }
Exemplo n.º 13
0
        public void TestRetrievedRulesetsAreDetached()
        {
            RunTestWithRealm((realm, storage) =>
            {
                var rulesets = new RealmRulesetStore(realm, storage);

                Assert.IsFalse(rulesets.AvailableRulesets.First().IsManaged);
                Assert.IsFalse(rulesets.GetRuleset(0)?.IsManaged);
                Assert.IsFalse(rulesets.GetRuleset("mania")?.IsManaged);
            });
        }
Exemplo n.º 14
0
        public void TestRetrievedRulesetsAreDetached()
        {
            RunTestWithRealm((realmFactory, storage) =>
            {
                var rulesets = new RealmRulesetStore(realmFactory, storage);

                Assert.IsTrue((rulesets.AvailableRulesets.First() as RealmRuleset)?.IsManaged == false);
                Assert.IsTrue((rulesets.GetRuleset(0) as RealmRuleset)?.IsManaged == false);
                Assert.IsTrue((rulesets.GetRuleset("mania") as RealmRuleset)?.IsManaged == false);
            });
        }
Exemplo n.º 15
0
        public void TestImportThenDelete()
        {
            RunTestWithRealmAsync(async(realmFactory, storage) =>
            {
                using var importer = new BeatmapImporter(realmFactory, storage);
                using var store    = new RealmRulesetStore(realmFactory, storage);

                var imported = await LoadOszIntoStore(importer, realmFactory.Context);

                deleteBeatmapSet(imported, realmFactory.Context);
            });
        }
Exemplo n.º 16
0
        public void TestCreateStoreTwiceDoesntAddRulesetsAgain()
        {
            RunTestWithRealm((realm, storage) =>
            {
                var rulesets  = new RealmRulesetStore(realm, storage);
                var rulesets2 = new RealmRulesetStore(realm, storage);

                Assert.AreEqual(4, rulesets.AvailableRulesets.Count());
                Assert.AreEqual(4, rulesets2.AvailableRulesets.Count());

                Assert.AreEqual(rulesets.AvailableRulesets.First(), rulesets2.AvailableRulesets.First());
                Assert.AreEqual(4, realm.Realm.All <RulesetInfo>().Count());
            });
        }
Exemplo n.º 17
0
        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);
                }
            });
        }
Exemplo n.º 18
0
        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);
                }
            });
        }
Exemplo n.º 19
0
        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");
            });
        }
Exemplo n.º 20
0
        public void TestAccessFileAfterImport()
        {
            RunTestWithRealmAsync(async(realm, storage) =>
            {
                using var importer = new BeatmapModelManager(realm, storage);
                using var store    = new RealmRulesetStore(realm, storage);

                var imported = await LoadOszIntoStore(importer, realm.Realm);

                var beatmap = imported.Beatmaps.First();
                var file    = beatmap.File;

                Assert.NotNull(file);
                Assert.AreEqual(beatmap.Hash, file !.File.Hash);
            });
        }
Exemplo n.º 21
0
        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);
                }
            });
        }
Exemplo n.º 22
0
        public void TestImportWithDuplicateBeatmapIDs()
        {
            RunTestWithRealm((realm, storage) =>
            {
                using var importer = new BeatmapModelManager(realm, storage);
                using var store    = new RealmRulesetStore(realm, storage);

                var metadata = new BeatmapMetadata
                {
                    Artist = "SomeArtist",
                    Author =
                    {
                        Username = "******"
                    }
                };

                var ruleset = realm.Realm.All <RulesetInfo>().First();

                var toImport = new BeatmapSetInfo
                {
                    OnlineID = 1,
                    Beatmaps =
                    {
                        new BeatmapInfo(ruleset, new BeatmapDifficulty(), metadata)
                        {
                            OnlineID = 2,
                        },
                        new BeatmapInfo(ruleset, new BeatmapDifficulty(), metadata)
                        {
                            OnlineID = 2,
                            Status   = BeatmapOnlineStatus.Loved,
                        }
                    }
                };

                var imported = importer.Import(toImport);

                realm.Run(r => r.Refresh());

                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));
            });
        }
Exemplo n.º 23
0
        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);
                }
            });
        }
Exemplo n.º 24
0
        public void TestImportThenDeleteThenImport()
        {
            RunTestWithRealmAsync(async(realmFactory, storage) =>
            {
                using var importer = new BeatmapImporter(realmFactory, storage);
                using var store    = new RealmRulesetStore(realmFactory, storage);

                var imported = await LoadOszIntoStore(importer, realmFactory.Context);

                deleteBeatmapSet(imported, realmFactory.Context);

                var importedSecondTime = await LoadOszIntoStore(importer, realmFactory.Context);

                // check the newly "imported" beatmap is actually just the restored previous import. since it matches hash.
                Assert.IsTrue(imported.ID == importedSecondTime.ID);
                Assert.IsTrue(imported.Beatmaps.First().ID == importedSecondTime.Beatmaps.First().ID);
            });
        }
Exemplo n.º 25
0
        public void TestImportThenImport()
        {
            RunTestWithRealmAsync(async(realm, storage) =>
            {
                using var importer = new BeatmapModelManager(realm, storage);
                using var store    = new RealmRulesetStore(realm, storage);

                var imported           = await LoadOszIntoStore(importer, realm.Realm);
                var importedSecondTime = await LoadOszIntoStore(importer, realm.Realm);

                // check the newly "imported" beatmap is actually just the restored previous import. since it matches hash.
                Assert.IsTrue(imported.ID == importedSecondTime.ID);
                Assert.IsTrue(imported.Beatmaps.First().ID == importedSecondTime.Beatmaps.First().ID);

                checkBeatmapSetCount(realm.Realm, 1);
                checkSingleReferencedFileCount(realm.Realm, 18);
            });
        }
Exemplo n.º 26
0
        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));
            });
        }
Exemplo n.º 27
0
        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"));
            });
        }
Exemplo n.º 28
0
        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);
                }
            });
        }
Exemplo n.º 29
0
        private void load(ReadableKeyCombinationProvider keyCombinationProvider)
        {
            try
            {
                using (var str = File.OpenRead(typeof(OsuGameBase).Assembly.Location))
                    VersionHash = str.ComputeMD5Hash();
            }
            catch
            {
                // special case for android builds, which can't read DLLs from a packed apk.
                // should eventually be handled in a better way.
                VersionHash = $"{Version}-{RuntimeInfo.OS}".ComputeMD5Hash();
            }

            Resources.AddStore(new DllResourceStore(OsuResources.ResourceAssembly));

            if (Storage.Exists(DatabaseContextFactory.DATABASE_NAME))
            {
                dependencies.Cache(EFContextFactory = new DatabaseContextFactory(Storage));
            }

            dependencies.Cache(realm = new RealmAccess(Storage, "client", EFContextFactory));

            dependencies.CacheAs <RulesetStore>(RulesetStore = new RealmRulesetStore(realm, Storage));
            dependencies.CacheAs <IRulesetStore>(RulesetStore);

            Decoder.RegisterDependencies(RulesetStore);

            // Backup is taken here rather than in EFToRealmMigrator to avoid recycling realm contexts
            // after initial usages below. It can be moved once a direction is established for handling re-subscription.
            // See https://github.com/ppy/osu/pull/16547 for more discussion.
            if (EFContextFactory != null)
            {
                const string backup_folder = "backups";

                string migration = $"before_final_migration_{DateTimeOffset.UtcNow.ToUnixTimeSeconds()}";

                EFContextFactory.CreateBackup(Path.Combine(backup_folder, $"client.{migration}.db"));
                realm.CreateBackup(Path.Combine(backup_folder, $"client.{migration}.realm"));

                using (var source = Storage.GetStream("collection.db"))
                {
                    if (source != null)
                    {
                        using (var destination = Storage.GetStream(Path.Combine(backup_folder, $"collection.{migration}.db"), FileAccess.Write, FileMode.CreateNew))
                            source.CopyTo(destination);
                    }
                }
            }

            dependencies.CacheAs(Storage);

            var largeStore = new LargeTextureStore(Host.CreateTextureLoaderStore(new NamespacedResourceStore <byte[]>(Resources, @"Textures")));

            largeStore.AddStore(Host.CreateTextureLoaderStore(new OnlineStore()));
            dependencies.Cache(largeStore);

            dependencies.CacheAs(this);
            dependencies.CacheAs(LocalConfig);

            InitialiseFonts();

            Audio.Samples.PlaybackConcurrency = SAMPLE_CONCURRENCY;

            dependencies.Cache(SkinManager = new SkinManager(Storage, realm, Host, Resources, Audio, Scheduler));
            dependencies.CacheAs <ISkinSource>(SkinManager);

            EndpointConfiguration endpoints = UseDevelopmentServer ? (EndpointConfiguration) new DevelopmentEndpointConfiguration() : new ProductionEndpointConfiguration();

            MessageFormatter.WebsiteRootUrl = endpoints.WebsiteRootUrl;

            dependencies.CacheAs(API ??= new APIAccess(LocalConfig, endpoints, VersionHash));

            dependencies.CacheAs(spectatorClient   = new OnlineSpectatorClient(endpoints));
            dependencies.CacheAs(multiplayerClient = new OnlineMultiplayerClient(endpoints));

            var defaultBeatmap = new DummyWorkingBeatmap(Audio, Textures);

            // ordering is important here to ensure foreign keys rules are not broken in ModelStore.Cleanup()
            dependencies.Cache(ScoreManager   = new ScoreManager(RulesetStore, () => BeatmapManager, Storage, realm, Scheduler, () => difficultyCache, LocalConfig));
            dependencies.Cache(BeatmapManager = new BeatmapManager(Storage, realm, RulesetStore, API, Audio, Resources, Host, defaultBeatmap, performOnlineLookups: true));

            dependencies.Cache(BeatmapDownloader = new BeatmapModelDownloader(BeatmapManager, API));
            dependencies.Cache(ScoreDownloader   = new ScoreModelDownloader(ScoreManager, API));

            dependencies.Cache(difficultyCache = new BeatmapDifficultyCache());
            AddInternal(difficultyCache);

            dependencies.Cache(userCache = new UserLookupCache());
            AddInternal(userCache);

            dependencies.Cache(beatmapCache = new BeatmapLookupCache());
            AddInternal(beatmapCache);

            var scorePerformanceManager = new ScorePerformanceCache();

            dependencies.Cache(scorePerformanceManager);
            AddInternal(scorePerformanceManager);

            dependencies.CacheAs <IRulesetConfigCache>(rulesetConfigCache = new RulesetConfigCache(realm, RulesetStore));

            var powerStatus = CreateBatteryInfo();

            if (powerStatus != null)
            {
                dependencies.CacheAs(powerStatus);
            }

            dependencies.Cache(SessionStatics = new SessionStatics());
            dependencies.Cache(new OsuColour());

            RegisterImportHandler(BeatmapManager);
            RegisterImportHandler(ScoreManager);
            RegisterImportHandler(SkinManager);

            // drop track volume game-wide to leave some head-room for UI effects / samples.
            // this means that for the time being, gameplay sample playback is louder relative to the audio track, compared to stable.
            // we may want to revisit this if users notice or complain about the difference (consider this a bit of a trial).
            Audio.Tracks.AddAdjustment(AdjustableProperty.Volume, globalTrackVolumeAdjust);

            Beatmap = new NonNullableBindable <WorkingBeatmap>(defaultBeatmap);

            dependencies.CacheAs <IBindable <WorkingBeatmap> >(Beatmap);
            dependencies.CacheAs(Beatmap);

            // add api components to hierarchy.
            if (API is APIAccess apiAccess)
            {
                AddInternal(apiAccess);
            }
            AddInternal(spectatorClient);
            AddInternal(multiplayerClient);

            AddInternal(rulesetConfigCache);

            GlobalActionContainer globalBindings;

            base.Content.Add(new SafeAreaContainer
            {
                SafeAreaOverrideEdges = SafeAreaOverrideEdges,
                RelativeSizeAxes      = Axes.Both,
                Child = CreateScalingContainer().WithChildren(new Drawable[]
                {
                    (MenuCursorContainer = new MenuCursorContainer
                    {
                        RelativeSizeAxes = Axes.Both
                    }).WithChild(content = new OsuTooltipContainer(MenuCursorContainer.Cursor)
                    {
                        RelativeSizeAxes = Axes.Both
                    }),
                    // to avoid positional input being blocked by children, ensure the GlobalActionContainer is above everything.
                    globalBindings = new GlobalActionContainer(this)
                })
            });

            KeyBindingStore = new RealmKeyBindingStore(realm, keyCombinationProvider);
            KeyBindingStore.Register(globalBindings, RulesetStore.AvailableRulesets);

            dependencies.Cache(globalBindings);

            PreviewTrackManager previewTrackManager;

            dependencies.Cache(previewTrackManager = new PreviewTrackManager(BeatmapManager.BeatmapTrackStore));
            Add(previewTrackManager);

            AddInternal(MusicController = new MusicController());
            dependencies.CacheAs(MusicController);

            Ruleset.BindValueChanged(onRulesetChanged);
            Beatmap.BindValueChanged(onBeatmapChanged);
        }
Exemplo n.º 30
0
        private void load(ReadableKeyCombinationProvider keyCombinationProvider)
        {
            try
            {
                using (var str = File.OpenRead(typeof(OsuGameBase).Assembly.Location))
                    VersionHash = str.ComputeMD5Hash();
            }
            catch
            {
                // special case for android builds, which can't read DLLs from a packed apk.
                // should eventually be handled in a better way.
                VersionHash = $"{Version}-{RuntimeInfo.OS}".ComputeMD5Hash();
            }

            Resources.AddStore(new DllResourceStore(OsuResources.ResourceAssembly));

            dependencies.Cache(contextFactory = new DatabaseContextFactory(Storage));

            dependencies.Cache(realmFactory = new RealmContextFactory(Storage, "client"));

            dependencies.CacheAs(Storage);

            var largeStore = new LargeTextureStore(Host.CreateTextureLoaderStore(new NamespacedResourceStore <byte[]>(Resources, @"Textures")));

            largeStore.AddStore(Host.CreateTextureLoaderStore(new OnlineStore()));
            dependencies.Cache(largeStore);

            dependencies.CacheAs(this);
            dependencies.CacheAs(LocalConfig);

            InitialiseFonts();

            Audio.Samples.PlaybackConcurrency = SAMPLE_CONCURRENCY;

            runMigrations();

            dependencies.Cache(SkinManager = new SkinManager(Storage, contextFactory, Host, Resources, Audio));
            dependencies.CacheAs <ISkinSource>(SkinManager);

            // needs to be done here rather than inside SkinManager to ensure thread safety of CurrentSkinInfo.
            SkinManager.ItemRemoved += item => Schedule(() =>
            {
                // check the removed skin is not the current user choice. if it is, switch back to default.
                if (item.ID == SkinManager.CurrentSkinInfo.Value.ID)
                {
                    SkinManager.CurrentSkinInfo.Value = SkinInfo.Default;
                }
            });

            EndpointConfiguration endpoints = UseDevelopmentServer ? (EndpointConfiguration) new DevelopmentEndpointConfiguration() : new ProductionEndpointConfiguration();

            MessageFormatter.WebsiteRootUrl = endpoints.WebsiteRootUrl;

            dependencies.CacheAs(API ??= new APIAccess(LocalConfig, endpoints, VersionHash));

            dependencies.CacheAs(spectatorClient   = new OnlineSpectatorClient(endpoints));
            dependencies.CacheAs(multiplayerClient = new OnlineMultiplayerClient(endpoints));

            var defaultBeatmap = new DummyWorkingBeatmap(Audio, Textures);

            dependencies.Cache(RulesetStore = new RulesetStore(contextFactory, Storage));
            dependencies.Cache(fileStore    = new FileStore(contextFactory, Storage));

            // ordering is important here to ensure foreign keys rules are not broken in ModelStore.Cleanup()
            dependencies.Cache(ScoreManager   = new ScoreManager(RulesetStore, () => BeatmapManager, Storage, API, contextFactory, Scheduler, Host, () => difficultyCache, LocalConfig));
            dependencies.Cache(BeatmapManager = new BeatmapManager(Storage, contextFactory, RulesetStore, API, Audio, Resources, Host, defaultBeatmap, performOnlineLookups: true));

            // the following realm components are not actively used yet, but initialised and kept up to date for initial testing.
            realmRulesetStore = new RealmRulesetStore(realmFactory, Storage);

            dependencies.Cache(realmRulesetStore);

            // this should likely be moved to ArchiveModelManager when another case appears where it is necessary
            // to have inter-dependent model managers. this could be obtained with an IHasForeign<T> interface to
            // allow lookups to be done on the child (ScoreManager in this case) to perform the cascading delete.
            List <ScoreInfo> getBeatmapScores(BeatmapSetInfo set)
            {
                var beatmapIds = BeatmapManager.QueryBeatmaps(b => b.BeatmapSetInfoID == set.ID).Select(b => b.ID).ToList();

                return(ScoreManager.QueryScores(s => beatmapIds.Contains(s.BeatmapInfo.ID)).ToList());
            }

            BeatmapManager.ItemRemoved += item => ScoreManager.Delete(getBeatmapScores(item), true);
            BeatmapManager.ItemUpdated += item => ScoreManager.Undelete(getBeatmapScores(item), true);

            dependencies.Cache(difficultyCache = new BeatmapDifficultyCache());
            AddInternal(difficultyCache);

            dependencies.Cache(userCache = new UserLookupCache());
            AddInternal(userCache);

            var scorePerformanceManager = new ScorePerformanceCache();

            dependencies.Cache(scorePerformanceManager);
            AddInternal(scorePerformanceManager);

            migrateDataToRealm();

            dependencies.Cache(rulesetConfigCache = new RulesetConfigCache(realmFactory, RulesetStore));

            var powerStatus = CreateBatteryInfo();

            if (powerStatus != null)
            {
                dependencies.CacheAs(powerStatus);
            }

            dependencies.Cache(SessionStatics = new SessionStatics());
            dependencies.Cache(new OsuColour());

            RegisterImportHandler(BeatmapManager);
            RegisterImportHandler(ScoreManager);
            RegisterImportHandler(SkinManager);

            // drop track volume game-wide to leave some head-room for UI effects / samples.
            // this means that for the time being, gameplay sample playback is louder relative to the audio track, compared to stable.
            // we may want to revisit this if users notice or complain about the difference (consider this a bit of a trial).
            Audio.Tracks.AddAdjustment(AdjustableProperty.Volume, globalTrackVolumeAdjust);

            Beatmap = new NonNullableBindable <WorkingBeatmap>(defaultBeatmap);

            dependencies.CacheAs <IBindable <WorkingBeatmap> >(Beatmap);
            dependencies.CacheAs(Beatmap);

            fileStore.Cleanup();

            // add api components to hierarchy.
            if (API is APIAccess apiAccess)
            {
                AddInternal(apiAccess);
            }
            AddInternal(spectatorClient);
            AddInternal(multiplayerClient);

            AddInternal(rulesetConfigCache);

            GlobalActionContainer globalBindings;

            var mainContent = new Drawable[]
            {
                MenuCursorContainer = new MenuCursorContainer {
                    RelativeSizeAxes = Axes.Both
                },
                // to avoid positional input being blocked by children, ensure the GlobalActionContainer is above everything.
                globalBindings = new GlobalActionContainer(this)
            };

            MenuCursorContainer.Child = content = new OsuTooltipContainer(MenuCursorContainer.Cursor)
            {
                RelativeSizeAxes = Axes.Both
            };

            base.Content.Add(CreateScalingContainer().WithChildren(mainContent));

            KeyBindingStore = new RealmKeyBindingStore(realmFactory, keyCombinationProvider);
            KeyBindingStore.Register(globalBindings, RulesetStore.AvailableRulesets);

            dependencies.Cache(globalBindings);

            PreviewTrackManager previewTrackManager;

            dependencies.Cache(previewTrackManager = new PreviewTrackManager(BeatmapManager.BeatmapTrackStore));
            Add(previewTrackManager);

            AddInternal(MusicController = new MusicController());
            dependencies.CacheAs(MusicController);

            Ruleset.BindValueChanged(onRulesetChanged);
        }