Mercurial > hg > orthanc-databases
diff Framework/Plugins/IndexUnitTests.h @ 0:7cea966b6829
initial commit
author | Sebastien Jodogne <s.jodogne@gmail.com> |
---|---|
date | Wed, 04 Jul 2018 08:16:29 +0200 |
parents | |
children | 19eec364236b |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Framework/Plugins/IndexUnitTests.h Wed Jul 04 08:16:29 2018 +0200 @@ -0,0 +1,416 @@ +/** + * Orthanc - A Lightweight, RESTful DICOM Store + * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics + * Department, University Hospital of Liege, Belgium + * Copyright (C) 2017-2018 Osimis S.A., Belgium + * + * This program is free software: you can redistribute it and/or + * modify it under the terms of the GNU Affero General Public License + * as published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + **/ + + +#pragma once + +#include <orthanc/OrthancCDatabasePlugin.h> +#include <OrthancServer/ServerEnumerations.h> + +#include <gtest/gtest.h> +#include <list> + + +static std::auto_ptr<OrthancPluginAttachment> expectedAttachment; +static std::list<OrthancPluginDicomTag> expectedDicomTags; +static std::auto_ptr<OrthancPluginExportedResource> expectedExported; + +static void CheckAttachment(const OrthancPluginAttachment& attachment) +{ + ASSERT_STREQ(expectedAttachment->uuid, attachment.uuid); + ASSERT_EQ(expectedAttachment->contentType, attachment.contentType); + ASSERT_EQ(expectedAttachment->uncompressedSize, attachment.uncompressedSize); + ASSERT_STREQ(expectedAttachment->uncompressedHash, attachment.uncompressedHash); + ASSERT_EQ(expectedAttachment->compressionType, attachment.compressionType); + ASSERT_EQ(expectedAttachment->compressedSize, attachment.compressedSize); + ASSERT_STREQ(expectedAttachment->compressedHash, attachment.compressedHash); +} + +static void CheckExportedResource(const OrthancPluginExportedResource& exported) +{ + ASSERT_EQ(expectedExported->seq, exported.seq); + ASSERT_EQ(expectedExported->resourceType, exported.resourceType); + ASSERT_STREQ(expectedExported->publicId, exported.publicId); + ASSERT_STREQ(expectedExported->modality, exported.modality); + ASSERT_STREQ(expectedExported->date, exported.date); + ASSERT_STREQ(expectedExported->patientId, exported.patientId); + ASSERT_STREQ(expectedExported->studyInstanceUid, exported.studyInstanceUid); + ASSERT_STREQ(expectedExported->seriesInstanceUid, exported.seriesInstanceUid); + ASSERT_STREQ(expectedExported->sopInstanceUid, exported.sopInstanceUid); +} + +static void CheckDicomTag(const OrthancPluginDicomTag& tag) +{ + for (std::list<OrthancPluginDicomTag>::const_iterator + it = expectedDicomTags.begin(); it != expectedDicomTags.end(); ++it) + { + if (it->group == tag.group && + it->element == tag.element && + !strcmp(it->value, tag.value)) + { + // OK, match + return; + } + } + + ASSERT_TRUE(0); // Error +} + + + +static OrthancPluginErrorCode InvokeService(struct _OrthancPluginContext_t* context, + _OrthancPluginService service, + const void* params) +{ + if (service == _OrthancPluginService_DatabaseAnswer) + { + const _OrthancPluginDatabaseAnswer& answer = + *reinterpret_cast<const _OrthancPluginDatabaseAnswer*>(params); + + switch (answer.type) + { + case _OrthancPluginDatabaseAnswerType_Attachment: + { + const OrthancPluginAttachment& attachment = + *reinterpret_cast<const OrthancPluginAttachment*>(answer.valueGeneric); + CheckAttachment(attachment); + break; + } + + case _OrthancPluginDatabaseAnswerType_ExportedResource: + { + const OrthancPluginExportedResource& attachment = + *reinterpret_cast<const OrthancPluginExportedResource*>(answer.valueGeneric); + CheckExportedResource(attachment); + break; + } + + case _OrthancPluginDatabaseAnswerType_DicomTag: + { + const OrthancPluginDicomTag& tag = + *reinterpret_cast<const OrthancPluginDicomTag*>(answer.valueGeneric); + CheckDicomTag(tag); + break; + } + + default: + printf("Unhandled message: %d\n", answer.type); + break; + } + } + + return OrthancPluginErrorCode_Success; +} + + +TEST(IndexBackend, Basic) +{ + using namespace OrthancDatabases; + + OrthancPluginContext context; + context.pluginsManager = NULL; + context.orthancVersion = "mainline"; + context.Free = ::free; + context.InvokeService = InvokeService; + +#if ORTHANC_ENABLE_POSTGRESQL == 1 + PostgreSQLIndex db(globalParameters_); + db.SetClearAll(true); +#elif ORTHANC_ENABLE_MYSQL == 1 + MySQLIndex db(globalParameters_); + db.SetClearAll(true); +#elif ORTHANC_ENABLE_SQLITE == 1 + SQLiteIndex db; // Open in memory +#else +# error Unsupported database backend +#endif + + db.RegisterOutput(new OrthancPlugins::DatabaseBackendOutput(&context, NULL)); + db.Open(); + + std::string s; + ASSERT_TRUE(db.LookupGlobalProperty(s, Orthanc::GlobalProperty_DatabaseSchemaVersion)); + ASSERT_EQ("6", s); + + ASSERT_FALSE(db.LookupGlobalProperty(s, Orthanc::GlobalProperty_AnonymizationSequence)); + db.SetGlobalProperty(Orthanc::GlobalProperty_AnonymizationSequence, "Hello"); + ASSERT_TRUE(db.LookupGlobalProperty(s, Orthanc::GlobalProperty_AnonymizationSequence)); + ASSERT_EQ("Hello", s); + db.SetGlobalProperty(Orthanc::GlobalProperty_AnonymizationSequence, "HelloWorld"); + ASSERT_TRUE(db.LookupGlobalProperty(s, Orthanc::GlobalProperty_AnonymizationSequence)); + ASSERT_EQ("HelloWorld", s); + + int64_t a = db.CreateResource("study", OrthancPluginResourceType_Study); + ASSERT_TRUE(db.IsExistingResource(a)); + ASSERT_FALSE(db.IsExistingResource(a + 1)); + + int64_t b; + OrthancPluginResourceType t; + ASSERT_FALSE(db.LookupResource(b, t, "world")); + ASSERT_TRUE(db.LookupResource(b, t, "study")); + ASSERT_EQ(a, b); + ASSERT_EQ(OrthancPluginResourceType_Study, t); + + b = db.CreateResource("series", OrthancPluginResourceType_Series); + ASSERT_NE(a, b); + + ASSERT_EQ("study", db.GetPublicId(a)); + ASSERT_EQ("series", db.GetPublicId(b)); + ASSERT_EQ(OrthancPluginResourceType_Study, db.GetResourceType(a)); + ASSERT_EQ(OrthancPluginResourceType_Series, db.GetResourceType(b)); + + db.AttachChild(a, b); + + int64_t c; + ASSERT_FALSE(db.LookupParent(c, a)); + ASSERT_TRUE(db.LookupParent(c, b)); + ASSERT_EQ(a, c); + + c = db.CreateResource("series2", OrthancPluginResourceType_Series); + db.AttachChild(a, c); + + ASSERT_EQ(3u, db.GetResourcesCount()); + ASSERT_EQ(0u, db.GetResourceCount(OrthancPluginResourceType_Patient)); + ASSERT_EQ(1u, db.GetResourceCount(OrthancPluginResourceType_Study)); + ASSERT_EQ(2u, db.GetResourceCount(OrthancPluginResourceType_Series)); + + ASSERT_FALSE(db.GetParentPublicId(s, a)); + ASSERT_TRUE(db.GetParentPublicId(s, b)); ASSERT_EQ("study", s); + ASSERT_TRUE(db.GetParentPublicId(s, c)); ASSERT_EQ("study", s); + + std::list<std::string> children; + db.GetChildren(children, a); + ASSERT_EQ(2u, children.size()); + db.GetChildren(children, b); + ASSERT_EQ(0u, children.size()); + db.GetChildren(children, c); + ASSERT_EQ(0u, children.size()); + + std::list<std::string> cp; + db.GetChildrenPublicId(cp, a); + ASSERT_EQ(2u, cp.size()); + ASSERT_TRUE(cp.front() == "series" || cp.front() == "series2"); + ASSERT_TRUE(cp.back() == "series" || cp.back() == "series2"); + ASSERT_NE(cp.front(), cp.back()); + + std::list<std::string> pub; + db.GetAllPublicIds(pub, OrthancPluginResourceType_Patient); + ASSERT_EQ(0u, pub.size()); + db.GetAllPublicIds(pub, OrthancPluginResourceType_Study); + ASSERT_EQ(1u, pub.size()); + ASSERT_EQ("study", pub.front()); + db.GetAllPublicIds(pub, OrthancPluginResourceType_Series); + ASSERT_EQ(2u, pub.size()); + ASSERT_TRUE(pub.front() == "series" || pub.front() == "series2"); + ASSERT_TRUE(pub.back() == "series" || pub.back() == "series2"); + ASSERT_NE(pub.front(), pub.back()); + + std::list<int64_t> ci; + db.GetChildrenInternalId(ci, a); + ASSERT_EQ(2u, ci.size()); + ASSERT_TRUE(ci.front() == b || ci.front() == c); + ASSERT_TRUE(ci.back() == b || ci.back() == c); + ASSERT_NE(ci.front(), ci.back()); + + db.SetMetadata(a, Orthanc::MetadataType_ModifiedFrom, "modified"); + db.SetMetadata(a, Orthanc::MetadataType_LastUpdate, "update2"); + ASSERT_FALSE(db.LookupMetadata(s, b, Orthanc::MetadataType_LastUpdate)); + ASSERT_TRUE(db.LookupMetadata(s, a, Orthanc::MetadataType_LastUpdate)); + ASSERT_EQ("update2", s); + db.SetMetadata(a, Orthanc::MetadataType_LastUpdate, "update"); + ASSERT_TRUE(db.LookupMetadata(s, a, Orthanc::MetadataType_LastUpdate)); + ASSERT_EQ("update", s); + + std::list<int32_t> md; + db.ListAvailableMetadata(md, a); + ASSERT_EQ(2u, md.size()); + ASSERT_TRUE(md.front() == Orthanc::MetadataType_ModifiedFrom || md.back() == Orthanc::MetadataType_ModifiedFrom); + ASSERT_TRUE(md.front() == Orthanc::MetadataType_LastUpdate || md.back() == Orthanc::MetadataType_LastUpdate); + std::string mdd; + ASSERT_TRUE(db.LookupMetadata(mdd, a, Orthanc::MetadataType_ModifiedFrom)); + ASSERT_EQ("modified", mdd); + ASSERT_TRUE(db.LookupMetadata(mdd, a, Orthanc::MetadataType_LastUpdate)); + ASSERT_EQ("update", mdd); + + db.ListAvailableMetadata(md, b); + ASSERT_EQ(0u, md.size()); + + db.DeleteMetadata(a, Orthanc::MetadataType_LastUpdate); + db.DeleteMetadata(b, Orthanc::MetadataType_LastUpdate); + ASSERT_FALSE(db.LookupMetadata(s, a, Orthanc::MetadataType_LastUpdate)); + + db.ListAvailableMetadata(md, a); + ASSERT_EQ(1u, md.size()); + ASSERT_EQ(Orthanc::MetadataType_ModifiedFrom, md.front()); + + ASSERT_EQ(0u, db.GetTotalCompressedSize()); + ASSERT_EQ(0u, db.GetTotalUncompressedSize()); + + + std::list<int32_t> fc; + + OrthancPluginAttachment a1; + a1.uuid = "uuid1"; + a1.contentType = Orthanc::FileContentType_Dicom; + a1.uncompressedSize = 42; + a1.uncompressedHash = "md5_1"; + a1.compressionType = Orthanc::CompressionType_None; + a1.compressedSize = 42; + a1.compressedHash = "md5_1"; + + OrthancPluginAttachment a2; + a2.uuid = "uuid2"; + a2.contentType = Orthanc::FileContentType_DicomAsJson; + a2.uncompressedSize = 4242; + a2.uncompressedHash = "md5_2"; + a2.compressionType = Orthanc::CompressionType_None; + a2.compressedSize = 4242; + a2.compressedHash = "md5_2"; + + db.AddAttachment(a, a1); + db.ListAvailableAttachments(fc, a); + ASSERT_EQ(1u, fc.size()); + ASSERT_EQ(Orthanc::FileContentType_Dicom, fc.front()); + db.AddAttachment(a, a2); + db.ListAvailableAttachments(fc, a); + ASSERT_EQ(2u, fc.size()); + ASSERT_FALSE(db.LookupAttachment(b, Orthanc::FileContentType_Dicom)); + + ASSERT_EQ(4284u, db.GetTotalCompressedSize()); + ASSERT_EQ(4284u, db.GetTotalUncompressedSize()); + + expectedAttachment.reset(new OrthancPluginAttachment); + expectedAttachment->uuid = "uuid1"; + expectedAttachment->contentType = Orthanc::FileContentType_Dicom; + expectedAttachment->uncompressedSize = 42; + expectedAttachment->uncompressedHash = "md5_1"; + expectedAttachment->compressionType = Orthanc::CompressionType_None; + expectedAttachment->compressedSize = 42; + expectedAttachment->compressedHash = "md5_1"; + ASSERT_TRUE(db.LookupAttachment(a, Orthanc::FileContentType_Dicom)); + + expectedAttachment.reset(new OrthancPluginAttachment); + expectedAttachment->uuid = "uuid2"; + expectedAttachment->contentType = Orthanc::FileContentType_DicomAsJson; + expectedAttachment->uncompressedSize = 4242; + expectedAttachment->uncompressedHash = "md5_2"; + expectedAttachment->compressionType = Orthanc::CompressionType_None; + expectedAttachment->compressedSize = 4242; + expectedAttachment->compressedHash = "md5_2"; + ASSERT_TRUE(db.LookupAttachment(a, Orthanc::FileContentType_DicomAsJson)); + + db.ListAvailableAttachments(fc, b); + ASSERT_EQ(0u, fc.size()); + db.DeleteAttachment(a, Orthanc::FileContentType_Dicom); + db.ListAvailableAttachments(fc, a); + ASSERT_EQ(1u, fc.size()); + ASSERT_EQ(Orthanc::FileContentType_DicomAsJson, fc.front()); + db.DeleteAttachment(a, Orthanc::FileContentType_DicomAsJson); + db.ListAvailableAttachments(fc, a); + ASSERT_EQ(0u, fc.size()); + + + db.SetIdentifierTag(a, 0x0010, 0x0020, "patient"); + db.SetIdentifierTag(a, 0x0020, 0x000d, "study"); + + expectedDicomTags.clear(); + expectedDicomTags.push_back(OrthancPluginDicomTag()); + expectedDicomTags.push_back(OrthancPluginDicomTag()); + expectedDicomTags.front().group = 0x0010; + expectedDicomTags.front().element = 0x0020; + expectedDicomTags.front().value = "patient"; + expectedDicomTags.back().group = 0x0020; + expectedDicomTags.back().element = 0x000d; + expectedDicomTags.back().value = "study"; + db.GetMainDicomTags(a); + + + db.LookupIdentifier(ci, OrthancPluginResourceType_Study, 0x0010, 0x0020, + OrthancPluginIdentifierConstraint_Equal, "patient"); + ASSERT_EQ(1u, ci.size()); + ASSERT_EQ(a, ci.front()); + db.LookupIdentifier(ci, OrthancPluginResourceType_Study, 0x0010, 0x0020, + OrthancPluginIdentifierConstraint_Equal, "study"); + ASSERT_EQ(0u, ci.size()); + + + OrthancPluginExportedResource exp; + exp.seq = -1; + exp.resourceType = OrthancPluginResourceType_Study; + exp.publicId = "id"; + exp.modality = "remote"; + exp.date = "date"; + exp.patientId = "patient"; + exp.studyInstanceUid = "study"; + exp.seriesInstanceUid = "series"; + exp.sopInstanceUid = "instance"; + db.LogExportedResource(exp); + + expectedExported.reset(new OrthancPluginExportedResource()); + *expectedExported = exp; + expectedExported->seq = 1; + + bool done; + db.GetExportedResources(done, 0, 10); + + + db.GetAllPublicIds(pub, OrthancPluginResourceType_Patient); ASSERT_EQ(0u, pub.size()); + db.GetAllPublicIds(pub, OrthancPluginResourceType_Study); ASSERT_EQ(1u, pub.size()); + db.GetAllPublicIds(pub, OrthancPluginResourceType_Series); ASSERT_EQ(2u, pub.size()); + db.GetAllPublicIds(pub, OrthancPluginResourceType_Instance); ASSERT_EQ(0u, pub.size()); + ASSERT_EQ(3u, db.GetResourcesCount()); + + ASSERT_EQ(0u, db.GetUnprotectedPatientsCount()); // No patient was inserted + ASSERT_TRUE(db.IsExistingResource(c)); + db.DeleteResource(c); + ASSERT_FALSE(db.IsExistingResource(c)); + ASSERT_TRUE(db.IsExistingResource(a)); + ASSERT_TRUE(db.IsExistingResource(b)); + ASSERT_EQ(2u, db.GetResourcesCount()); + db.DeleteResource(a); + ASSERT_EQ(0u, db.GetResourcesCount()); + ASSERT_FALSE(db.IsExistingResource(a)); + ASSERT_FALSE(db.IsExistingResource(b)); + ASSERT_FALSE(db.IsExistingResource(c)); + + ASSERT_EQ(0u, db.GetResourcesCount()); + ASSERT_EQ(0u, db.GetUnprotectedPatientsCount()); + int64_t p1 = db.CreateResource("patient1", OrthancPluginResourceType_Patient); + int64_t p2 = db.CreateResource("patient2", OrthancPluginResourceType_Patient); + int64_t p3 = db.CreateResource("patient3", OrthancPluginResourceType_Patient); + ASSERT_EQ(3u, db.GetUnprotectedPatientsCount()); + int64_t r; + ASSERT_TRUE(db.SelectPatientToRecycle(r)); + ASSERT_EQ(p1, r); + ASSERT_TRUE(db.SelectPatientToRecycle(r, p1)); + ASSERT_EQ(p2, r); + ASSERT_FALSE(db.IsProtectedPatient(p1)); + db.SetProtectedPatient(p1, true); + ASSERT_TRUE(db.IsProtectedPatient(p1)); + ASSERT_TRUE(db.SelectPatientToRecycle(r)); + ASSERT_EQ(p2, r); + db.SetProtectedPatient(p1, false); + ASSERT_FALSE(db.IsProtectedPatient(p1)); + ASSERT_TRUE(db.SelectPatientToRecycle(r)); + ASSERT_EQ(p2, r); + db.DeleteResource(p2); + ASSERT_TRUE(db.SelectPatientToRecycle(r, p3)); + ASSERT_EQ(p1, r); +}