1 /**
2 * Orthanc - A Lightweight, RESTful DICOM Store
3 * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
4 * Department, University Hospital of Liege, Belgium
5 * Copyright (C) 2017-2021 Osimis S.A., Belgium
6 *
7 * This program is free software: you can redistribute it and/or
8 * modify it under the terms of the GNU Affero General Public License
9 * as published by the Free Software Foundation, either version 3 of
10 * the License, or (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Affero General Public License for more details.
16 *
17 * You should have received a copy of the GNU Affero General Public License
18 * along with this program. If not, see <http://www.gnu.org/licenses/>.
19 **/
20
21
22 #include <gtest/gtest.h>
23
24 #if defined(_WIN32)
25 // Fix redefinition of symbols on MinGW (these symbols are manually
26 // defined both by PostgreSQL and Google Test)
27 # undef S_IRGRP
28 # undef S_IROTH
29 # undef S_IRWXG
30 # undef S_IRWXO
31 # undef S_IWGRP
32 # undef S_IWOTH
33 # undef S_IXGRP
34 # undef S_IXOTH
35 #endif
36
37 #include "../../Framework/Plugins/GlobalProperties.h"
38 #include "../../Framework/PostgreSQL/PostgreSQLLargeObject.h"
39 #include "../../Framework/PostgreSQL/PostgreSQLResult.h"
40 #include "../../Framework/PostgreSQL/PostgreSQLTransaction.h"
41 #include "../Plugins/PostgreSQLIndex.h"
42 #include "../Plugins/PostgreSQLStorageArea.h"
43
44 #include <Compatibility.h> // For std::unique_ptr<>
45 #include <OrthancException.h>
46
47 #include <boost/lexical_cast.hpp>
48
49 using namespace OrthancDatabases;
50
51 extern PostgreSQLParameters globalParameters_;
52
53
CreateTestDatabase()54 static PostgreSQLDatabase* CreateTestDatabase()
55 {
56 std::unique_ptr<PostgreSQLDatabase> pg
57 (new PostgreSQLDatabase(globalParameters_));
58
59 pg->Open();
60 pg->ClearAll();
61
62 return pg.release();
63 }
64
65
CountLargeObjects(PostgreSQLDatabase & db)66 static int64_t CountLargeObjects(PostgreSQLDatabase& db)
67 {
68 PostgreSQLTransaction transaction(db, TransactionType_ReadOnly);
69
70 int64_t count;
71
72 {
73 // Count the number of large objects in the DB
74 PostgreSQLStatement s(db, "SELECT COUNT(*) FROM pg_catalog.pg_largeobject");
75 PostgreSQLResult r(s);
76 count = r.GetInteger64(0);
77 }
78
79 transaction.Commit();
80 return count;
81 }
82
83
TEST(PostgreSQL,Basic)84 TEST(PostgreSQL, Basic)
85 {
86 std::unique_ptr<PostgreSQLDatabase> pg(CreateTestDatabase());
87
88 ASSERT_FALSE(pg->DoesTableExist("Test"));
89 ASSERT_FALSE(pg->DoesColumnExist("Test", "value"));
90 ASSERT_FALSE(pg->DoesTableExist("TEST"));
91 ASSERT_FALSE(pg->DoesTableExist("test"));
92 pg->ExecuteMultiLines("CREATE TABLE Test(name INTEGER, value BIGINT)");
93 ASSERT_TRUE(pg->DoesTableExist("Test"));
94 ASSERT_TRUE(pg->DoesTableExist("TEST"));
95 ASSERT_TRUE(pg->DoesTableExist("test"));
96
97 ASSERT_TRUE(pg->DoesColumnExist("Test", "Value"));
98 ASSERT_TRUE(pg->DoesColumnExist("TEST", "VALUE"));
99 ASSERT_TRUE(pg->DoesColumnExist("test", "value"));
100
101 PostgreSQLStatement s(*pg, "INSERT INTO Test VALUES ($1,$2)");
102 s.DeclareInputInteger(0);
103 s.DeclareInputInteger64(1);
104
105 s.BindInteger(0, 43);
106 s.BindNull(0);
107 s.BindInteger(0, 42);
108 s.BindInteger64(1, -4242);
109 s.Run();
110
111 s.BindInteger(0, 43);
112 s.BindNull(1);
113 s.Run();
114
115 s.BindNull(0);
116 s.BindInteger64(1, 4444);
117 s.Run();
118
119 {
120 PostgreSQLStatement t(*pg, "SELECT name, value FROM Test ORDER BY name");
121 PostgreSQLResult r(t);
122
123 ASSERT_FALSE(r.IsDone());
124 ASSERT_FALSE(r.IsNull(0)); ASSERT_EQ(42, r.GetInteger(0));
125 ASSERT_FALSE(r.IsNull(1)); ASSERT_EQ(-4242, r.GetInteger64(1));
126
127 r.Next();
128 ASSERT_FALSE(r.IsDone());
129 ASSERT_FALSE(r.IsNull(0)); ASSERT_EQ(43, r.GetInteger(0));
130 ASSERT_TRUE(r.IsNull(1));
131
132 r.Next();
133 ASSERT_FALSE(r.IsDone());
134 ASSERT_TRUE(r.IsNull(0));
135 ASSERT_FALSE(r.IsNull(1)); ASSERT_EQ(4444, r.GetInteger64(1));
136
137 r.Next();
138 ASSERT_TRUE(r.IsDone());
139 }
140
141 {
142 PostgreSQLStatement t(*pg, "SELECT name, value FROM Test WHERE name=$1");
143 t.DeclareInputInteger(0);
144
145 {
146 t.BindInteger(0, 42);
147 PostgreSQLResult r(t);
148 ASSERT_FALSE(r.IsDone());
149 ASSERT_FALSE(r.IsNull(0)); ASSERT_EQ(42, r.GetInteger(0));
150 ASSERT_FALSE(r.IsNull(1)); ASSERT_EQ(-4242, r.GetInteger64(1));
151
152 r.Next();
153 ASSERT_TRUE(r.IsDone());
154 }
155
156 {
157 t.BindInteger(0, 40);
158 PostgreSQLResult r(t);
159 ASSERT_TRUE(r.IsDone());
160 }
161 }
162
163 }
164
165
TEST(PostgreSQL,String)166 TEST(PostgreSQL, String)
167 {
168 std::unique_ptr<PostgreSQLDatabase> pg(CreateTestDatabase());
169
170 pg->ExecuteMultiLines("CREATE TABLE Test(name INTEGER, value VARCHAR(40))");
171
172 PostgreSQLStatement s(*pg, "INSERT INTO Test VALUES ($1,$2)");
173 s.DeclareInputInteger(0);
174 s.DeclareInputString(1);
175
176 s.BindInteger(0, 42);
177 s.BindString(1, "Hello");
178 s.Run();
179
180 s.BindInteger(0, 43);
181 s.BindNull(1);
182 s.Run();
183
184 s.BindNull(0);
185 s.BindString(1, "");
186 s.Run();
187
188 {
189 PostgreSQLStatement t(*pg, "SELECT name, value FROM Test ORDER BY name");
190 PostgreSQLResult r(t);
191
192 ASSERT_FALSE(r.IsDone());
193 ASSERT_FALSE(r.IsNull(0)); ASSERT_EQ(42, r.GetInteger(0));
194 ASSERT_FALSE(r.IsNull(1)); ASSERT_EQ("Hello", r.GetString(1));
195
196 r.Next();
197 ASSERT_FALSE(r.IsDone());
198 ASSERT_FALSE(r.IsNull(0)); ASSERT_EQ(43, r.GetInteger(0));
199 ASSERT_TRUE(r.IsNull(1));
200
201 r.Next();
202 ASSERT_FALSE(r.IsDone());
203 ASSERT_TRUE(r.IsNull(0));
204 ASSERT_FALSE(r.IsNull(1)); ASSERT_EQ("", r.GetString(1));
205
206 r.Next();
207 ASSERT_TRUE(r.IsDone());
208 }
209 }
210
211
TEST(PostgreSQL,Transaction)212 TEST(PostgreSQL, Transaction)
213 {
214 std::unique_ptr<PostgreSQLDatabase> pg(CreateTestDatabase());
215
216 pg->ExecuteMultiLines("CREATE TABLE Test(name INTEGER, value INTEGER)");
217
218 {
219 PostgreSQLStatement s(*pg, "INSERT INTO Test VALUES ($1,$2)");
220 s.DeclareInputInteger(0);
221 s.DeclareInputInteger(1);
222 s.BindInteger(0, 42);
223 s.BindInteger(1, 4242);
224 s.Run();
225
226 {
227 PostgreSQLTransaction t(*pg, TransactionType_ReadOnly);
228 s.BindInteger(0, 0);
229 s.BindInteger(1, 1);
230 // Failure, as INSERT in a read-only transaction
231 ASSERT_THROW(s.Run(), Orthanc::OrthancException);
232 }
233
234 {
235 PostgreSQLTransaction t(*pg, TransactionType_ReadWrite);
236 s.BindInteger(0, 43);
237 s.BindInteger(1, 4343);
238 s.Run();
239 s.BindInteger(0, 44);
240 s.BindInteger(1, 4444);
241 s.Run();
242
243 PostgreSQLStatement u(*pg, "SELECT COUNT(*) FROM Test");
244 PostgreSQLResult r(u);
245 ASSERT_EQ(3, r.GetInteger64(0));
246
247 // No commit
248 }
249
250 {
251 // Implicit transaction
252 PostgreSQLStatement u(*pg, "SELECT COUNT(*) FROM Test");
253 PostgreSQLResult r(u);
254 ASSERT_EQ(1, r.GetInteger64(0)); // Just "1" because of implicit rollback
255 }
256
257 {
258 PostgreSQLTransaction t(*pg, TransactionType_ReadWrite);
259 s.BindInteger(0, 43);
260 s.BindInteger(1, 4343);
261 s.Run();
262 s.BindInteger(0, 44);
263 s.BindInteger(1, 4444);
264 s.Run();
265
266 {
267 PostgreSQLStatement u(*pg, "SELECT COUNT(*) FROM Test");
268 PostgreSQLResult r(u);
269 ASSERT_EQ(3, r.GetInteger64(0));
270
271 t.Commit();
272 ASSERT_THROW(t.Rollback(), Orthanc::OrthancException);
273 ASSERT_THROW(t.Commit(), Orthanc::OrthancException);
274 }
275 }
276
277 {
278 PostgreSQLTransaction t(*pg, TransactionType_ReadOnly);
279 PostgreSQLStatement u(*pg, "SELECT COUNT(*) FROM Test");
280 PostgreSQLResult r(u);
281 ASSERT_EQ(3, r.GetInteger64(0));
282 }
283 }
284 }
285
286
287
288
289
TEST(PostgreSQL,LargeObject)290 TEST(PostgreSQL, LargeObject)
291 {
292 std::unique_ptr<PostgreSQLDatabase> pg(CreateTestDatabase());
293 ASSERT_EQ(0, CountLargeObjects(*pg));
294
295 pg->ExecuteMultiLines("CREATE TABLE Test(name VARCHAR, value OID)");
296
297 // Automatically remove the large objects associated with the table
298 pg->ExecuteMultiLines("CREATE RULE TestDelete AS ON DELETE TO Test DO SELECT lo_unlink(old.value);");
299
300 {
301 PostgreSQLStatement s(*pg, "INSERT INTO Test VALUES ($1,$2)");
302 s.DeclareInputString(0);
303 s.DeclareInputLargeObject(1);
304
305 for (int i = 0; i < 10; i++)
306 {
307 PostgreSQLTransaction t(*pg, TransactionType_ReadWrite);
308
309 std::string value = "Value " + boost::lexical_cast<std::string>(i * 2);
310 PostgreSQLLargeObject obj(*pg, value);
311
312 s.BindString(0, "Index " + boost::lexical_cast<std::string>(i));
313 s.BindLargeObject(1, obj);
314 s.Run();
315
316 std::string tmp;
317 PostgreSQLLargeObject::ReadWhole(tmp, *pg, obj.GetOid());
318 ASSERT_EQ(value, tmp);
319
320 t.Commit();
321 }
322 }
323
324
325 ASSERT_EQ(10, CountLargeObjects(*pg));
326
327 {
328 PostgreSQLTransaction t(*pg, TransactionType_ReadOnly);
329 PostgreSQLStatement s(*pg, "SELECT * FROM Test ORDER BY name DESC");
330 PostgreSQLResult r(s);
331
332 ASSERT_FALSE(r.IsDone());
333
334 ASSERT_FALSE(r.IsNull(0));
335 ASSERT_EQ("Index 9", r.GetString(0));
336
337 std::string data;
338 r.GetLargeObjectContent(data, 1);
339 ASSERT_EQ("Value 18", data);
340
341 r.Next();
342 ASSERT_FALSE(r.IsDone());
343
344 //ASSERT_TRUE(r.IsString(0));
345 }
346
347
348 {
349 PostgreSQLTransaction t(*pg, TransactionType_ReadWrite);
350 PostgreSQLStatement s(*pg, "DELETE FROM Test WHERE name='Index 9'");
351 s.Run();
352 t.Commit();
353 }
354
355
356 {
357 // Count the number of items in the DB
358 PostgreSQLTransaction t(*pg, TransactionType_ReadOnly);
359 PostgreSQLStatement s(*pg, "SELECT COUNT(*) FROM Test");
360 PostgreSQLResult r(s);
361 ASSERT_EQ(9, r.GetInteger64(0));
362 }
363
364 ASSERT_EQ(9, CountLargeObjects(*pg));
365 }
366
367
TEST(PostgreSQL,StorageArea)368 TEST(PostgreSQL, StorageArea)
369 {
370 std::unique_ptr<PostgreSQLDatabase> database(PostgreSQLDatabase::CreateDatabaseConnection(globalParameters_));
371
372 PostgreSQLStorageArea storageArea(globalParameters_, true /* clear database */);
373
374 {
375 std::unique_ptr<OrthancDatabases::StorageBackend::IAccessor> accessor(storageArea.CreateAccessor());
376
377 ASSERT_EQ(0, CountLargeObjects(*database));
378
379 for (int i = 0; i < 10; i++)
380 {
381 std::string uuid = boost::lexical_cast<std::string>(i);
382 std::string value = "Value " + boost::lexical_cast<std::string>(i * 2);
383 accessor->Create(uuid, value.c_str(), value.size(), OrthancPluginContentType_Unknown);
384 }
385
386 std::string buffer;
387 ASSERT_THROW(OrthancDatabases::StorageBackend::ReadWholeToString(buffer, *accessor, "nope", OrthancPluginContentType_Unknown),
388 Orthanc::OrthancException);
389
390 ASSERT_EQ(10, CountLargeObjects(*database));
391 accessor->Remove("5", OrthancPluginContentType_Unknown);
392
393 ASSERT_EQ(9, CountLargeObjects(*database));
394
395 for (int i = 0; i < 10; i++)
396 {
397 std::string uuid = boost::lexical_cast<std::string>(i);
398 std::string expected = "Value " + boost::lexical_cast<std::string>(i * 2);
399
400 if (i == 5)
401 {
402 ASSERT_THROW(OrthancDatabases::StorageBackend::ReadWholeToString(buffer, *accessor, uuid, OrthancPluginContentType_Unknown),
403 Orthanc::OrthancException);
404 }
405 else
406 {
407 OrthancDatabases::StorageBackend::ReadWholeToString(buffer, *accessor, uuid, OrthancPluginContentType_Unknown);
408 ASSERT_EQ(expected, buffer);
409 }
410 }
411
412 for (int i = 0; i < 10; i++)
413 {
414 accessor->Remove(boost::lexical_cast<std::string>(i), OrthancPluginContentType_Unknown);
415 }
416
417 ASSERT_EQ(0, CountLargeObjects(*database));
418 }
419 }
420
421
TEST(PostgreSQL,StorageReadRange)422 TEST(PostgreSQL, StorageReadRange)
423 {
424 std::unique_ptr<OrthancDatabases::PostgreSQLDatabase> database(
425 OrthancDatabases::PostgreSQLDatabase::CreateDatabaseConnection(globalParameters_));
426
427 OrthancDatabases::PostgreSQLStorageArea storageArea(globalParameters_, true /* clear database */);
428
429 {
430 std::unique_ptr<OrthancDatabases::StorageBackend::IAccessor> accessor(storageArea.CreateAccessor());
431 ASSERT_EQ(0, CountLargeObjects(*database));
432 accessor->Create("uuid", "abcd\0\1\2\3\4\5", 10, OrthancPluginContentType_Unknown);
433 ASSERT_EQ(1u, CountLargeObjects(*database));
434 }
435
436 {
437 std::unique_ptr<OrthancDatabases::StorageBackend::IAccessor> accessor(storageArea.CreateAccessor());
438 ASSERT_EQ(1u, CountLargeObjects(*database));
439
440 std::string s;
441 OrthancDatabases::StorageBackend::ReadWholeToString(s, *accessor, "uuid", OrthancPluginContentType_Unknown);
442 ASSERT_EQ(10u, s.size());
443 ASSERT_EQ('a', s[0]);
444 ASSERT_EQ('d', s[3]);
445 ASSERT_EQ('\0', s[4]);
446 ASSERT_EQ('\5', s[9]);
447
448 OrthancDatabases::StorageBackend::ReadRangeToString(s, *accessor, "uuid", OrthancPluginContentType_Unknown, 0, 0);
449 ASSERT_TRUE(s.empty());
450
451 OrthancDatabases::StorageBackend::ReadRangeToString(s, *accessor, "uuid", OrthancPluginContentType_Unknown, 0, 1);
452 ASSERT_EQ(1u, s.size());
453 ASSERT_EQ('a', s[0]);
454
455 OrthancDatabases::StorageBackend::ReadRangeToString(s, *accessor, "uuid", OrthancPluginContentType_Unknown, 4, 1);
456 ASSERT_EQ(1u, s.size());
457 ASSERT_EQ('\0', s[0]);
458
459 OrthancDatabases::StorageBackend::ReadRangeToString(s, *accessor, "uuid", OrthancPluginContentType_Unknown, 9, 1);
460 ASSERT_EQ(1u, s.size());
461 ASSERT_EQ('\5', s[0]);
462
463 // Cannot read non-empty range after the end of the string. NB:
464 // The behavior on range (10, 0) is different than in MySQL!
465 ASSERT_THROW(OrthancDatabases::StorageBackend::ReadRangeToString(
466 s, *accessor, "uuid", OrthancPluginContentType_Unknown, 10, 0), Orthanc::OrthancException);
467
468 ASSERT_THROW(OrthancDatabases::StorageBackend::ReadRangeToString(
469 s, *accessor, "uuid", OrthancPluginContentType_Unknown, 10, 1), Orthanc::OrthancException);
470
471 OrthancDatabases::StorageBackend::ReadRangeToString(s, *accessor, "uuid", OrthancPluginContentType_Unknown, 0, 4);
472 ASSERT_EQ(4u, s.size());
473 ASSERT_EQ('a', s[0]);
474 ASSERT_EQ('b', s[1]);
475 ASSERT_EQ('c', s[2]);
476 ASSERT_EQ('d', s[3]);
477
478 OrthancDatabases::StorageBackend::ReadRangeToString(s, *accessor, "uuid", OrthancPluginContentType_Unknown, 4, 6);
479 ASSERT_EQ(6u, s.size());
480 ASSERT_EQ('\0', s[0]);
481 ASSERT_EQ('\1', s[1]);
482 ASSERT_EQ('\2', s[2]);
483 ASSERT_EQ('\3', s[3]);
484 ASSERT_EQ('\4', s[4]);
485 ASSERT_EQ('\5', s[5]);
486
487 ASSERT_THROW(OrthancDatabases::StorageBackend::ReadRangeToString(
488 s, *accessor, "uuid", OrthancPluginContentType_Unknown, 4, 7), Orthanc::OrthancException);
489 }
490 }
491
492
TEST(PostgreSQL,ImplicitTransaction)493 TEST(PostgreSQL, ImplicitTransaction)
494 {
495 std::unique_ptr<PostgreSQLDatabase> db(CreateTestDatabase());
496
497 ASSERT_FALSE(db->DoesTableExist("test"));
498 ASSERT_FALSE(db->DoesTableExist("test2"));
499
500 {
501 std::unique_ptr<OrthancDatabases::ITransaction> t(db->CreateTransaction(TransactionType_ReadWrite));
502 ASSERT_FALSE(t->IsImplicit());
503 }
504
505 {
506 Query query("CREATE TABLE test(id INT)", false);
507 std::unique_ptr<IPrecompiledStatement> s(db->Compile(query));
508
509 std::unique_ptr<ITransaction> t(db->CreateTransaction(TransactionType_Implicit));
510 ASSERT_TRUE(t->IsImplicit());
511 ASSERT_THROW(t->Commit(), Orthanc::OrthancException);
512 ASSERT_THROW(t->Rollback(), Orthanc::OrthancException);
513
514 Dictionary args;
515 t->ExecuteWithoutResult(*s, args);
516 ASSERT_THROW(t->Rollback(), Orthanc::OrthancException);
517 t->Commit();
518
519 ASSERT_THROW(t->Commit(), Orthanc::OrthancException);
520 }
521
522 {
523 // An implicit transaction does not need to be explicitely committed
524 Query query("CREATE TABLE test2(id INT)", false);
525 std::unique_ptr<IPrecompiledStatement> s(db->Compile(query));
526
527 std::unique_ptr<ITransaction> t(db->CreateTransaction(TransactionType_Implicit));
528
529 Dictionary args;
530 t->ExecuteWithoutResult(*s, args);
531 }
532
533 ASSERT_TRUE(db->DoesTableExist("test"));
534 ASSERT_TRUE(db->DoesTableExist("test2"));
535 }
536
537
538 #if ORTHANC_PLUGINS_HAS_DATABASE_CONSTRAINT == 1
TEST(PostgreSQLIndex,CreateInstance)539 TEST(PostgreSQLIndex, CreateInstance)
540 {
541 OrthancDatabases::PostgreSQLIndex db(NULL, globalParameters_);
542 db.SetClearAll(true);
543
544 std::unique_ptr<OrthancDatabases::DatabaseManager> manager(OrthancDatabases::IndexBackend::CreateSingleDatabaseManager(db));
545
546 std::string s;
547 ASSERT_TRUE(db.LookupGlobalProperty(s, *manager, MISSING_SERVER_IDENTIFIER, Orthanc::GlobalProperty_DatabaseInternal1));
548 ASSERT_EQ("2", s);
549
550 OrthancPluginCreateInstanceResult r1, r2;
551
552 memset(&r1, 0, sizeof(r1));
553 db.CreateInstance(r1, *manager, "a", "b", "c", "d");
554 ASSERT_TRUE(r1.isNewInstance);
555 ASSERT_TRUE(r1.isNewSeries);
556 ASSERT_TRUE(r1.isNewStudy);
557 ASSERT_TRUE(r1.isNewPatient);
558
559 memset(&r2, 0, sizeof(r2));
560 db.CreateInstance(r2, *manager, "a", "b", "c", "d");
561 ASSERT_FALSE(r2.isNewInstance);
562 ASSERT_EQ(r1.instanceId, r2.instanceId);
563
564 // Breaking the hierarchy
565 memset(&r2, 0, sizeof(r2));
566 ASSERT_THROW(db.CreateInstance(r2, *manager, "a", "e", "c", "f"), Orthanc::OrthancException);
567
568 memset(&r2, 0, sizeof(r2));
569 db.CreateInstance(r2, *manager, "a", "b", "c", "e");
570 ASSERT_TRUE(r2.isNewInstance);
571 ASSERT_FALSE(r2.isNewSeries);
572 ASSERT_FALSE(r2.isNewStudy);
573 ASSERT_FALSE(r2.isNewPatient);
574 ASSERT_EQ(r1.patientId, r2.patientId);
575 ASSERT_EQ(r1.studyId, r2.studyId);
576 ASSERT_EQ(r1.seriesId, r2.seriesId);
577 ASSERT_NE(r1.instanceId, r2.instanceId);
578
579 memset(&r2, 0, sizeof(r2));
580 db.CreateInstance(r2, *manager, "a", "b", "f", "g");
581 ASSERT_TRUE(r2.isNewInstance);
582 ASSERT_TRUE(r2.isNewSeries);
583 ASSERT_FALSE(r2.isNewStudy);
584 ASSERT_FALSE(r2.isNewPatient);
585 ASSERT_EQ(r1.patientId, r2.patientId);
586 ASSERT_EQ(r1.studyId, r2.studyId);
587 ASSERT_NE(r1.seriesId, r2.seriesId);
588 ASSERT_NE(r1.instanceId, r2.instanceId);
589
590 memset(&r2, 0, sizeof(r2));
591 db.CreateInstance(r2, *manager, "a", "h", "i", "j");
592 ASSERT_TRUE(r2.isNewInstance);
593 ASSERT_TRUE(r2.isNewSeries);
594 ASSERT_TRUE(r2.isNewStudy);
595 ASSERT_FALSE(r2.isNewPatient);
596 ASSERT_EQ(r1.patientId, r2.patientId);
597 ASSERT_NE(r1.studyId, r2.studyId);
598 ASSERT_NE(r1.seriesId, r2.seriesId);
599 ASSERT_NE(r1.instanceId, r2.instanceId);
600
601 memset(&r2, 0, sizeof(r2));
602 db.CreateInstance(r2, *manager, "k", "l", "m", "n");
603 ASSERT_TRUE(r2.isNewInstance);
604 ASSERT_TRUE(r2.isNewSeries);
605 ASSERT_TRUE(r2.isNewStudy);
606 ASSERT_TRUE(r2.isNewPatient);
607 ASSERT_NE(r1.patientId, r2.patientId);
608 ASSERT_NE(r1.studyId, r2.studyId);
609 ASSERT_NE(r1.seriesId, r2.seriesId);
610 ASSERT_NE(r1.instanceId, r2.instanceId);
611 }
612 #endif
613
614
TEST(PostgreSQL,Lock2)615 TEST(PostgreSQL, Lock2)
616 {
617 std::unique_ptr<PostgreSQLDatabase> db1(CreateTestDatabase());
618
619 ASSERT_FALSE(db1->ReleaseAdvisoryLock(43)); // lock counter = 0
620 ASSERT_TRUE(db1->AcquireAdvisoryLock(43)); // lock counter = 1
621
622 // OK, as this is the same connection
623 ASSERT_TRUE(db1->AcquireAdvisoryLock(43)); // lock counter = 2
624 ASSERT_TRUE(db1->ReleaseAdvisoryLock(43)); // lock counter = 1
625
626 // Try and release twice the lock
627 ASSERT_TRUE(db1->ReleaseAdvisoryLock(43)); // lock counter = 0
628 ASSERT_FALSE(db1->ReleaseAdvisoryLock(43)); // cannot unlock
629 ASSERT_TRUE(db1->AcquireAdvisoryLock(43)); // lock counter = 1
630
631 {
632 std::unique_ptr<PostgreSQLDatabase> db2(CreateTestDatabase());
633
634 // The "db1" is still actively locking
635 ASSERT_FALSE(db2->AcquireAdvisoryLock(43));
636
637 // Release the "db1" lock
638 ASSERT_TRUE(db1->ReleaseAdvisoryLock(43));
639 ASSERT_FALSE(db1->ReleaseAdvisoryLock(43));
640
641 // "db2" can now acquire the lock, but not "db1"
642 ASSERT_TRUE(db2->AcquireAdvisoryLock(43));
643 ASSERT_FALSE(db1->AcquireAdvisoryLock(43));
644 }
645
646 // "db2" is closed, "db1" can now acquire the lock
647 ASSERT_TRUE(db1->AcquireAdvisoryLock(43));
648 }
649