SchedulerTest.cpp 22.7 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
/*
 * The CERN Tape Archive (CTA) project
 * Copyright (C) 2015  CERN
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU 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 General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

19
20
#include "catalogue/InMemoryCatalogue.hpp"
#include "catalogue/SchemaCreatingSqliteCatalogue.hpp"
21
22
23
#include "common/admin/AdminUser.hpp"
#include "common/admin/AdminHost.hpp"
#include "common/archiveRoutes/ArchiveRoute.hpp"
24
#include "common/make_unique.hpp"
25
#include "scheduler/ArchiveMount.hpp"
26
27
#include "scheduler/LogicalLibrary.hpp"
#include "scheduler/MountRequest.hpp"
28
#include "scheduler/OStoreDB/OStoreDBFactory.hpp"
29
#include "scheduler/RetrieveMount.hpp"
30
31
#include "scheduler/Scheduler.hpp"
#include "scheduler/SchedulerDatabase.hpp"
32
#include "scheduler/SchedulerDatabaseFactory.hpp"
33
#include "scheduler/TapeMount.hpp"
34
#include "tests/TempFile.hpp"
35
#include "common/log/DummyLogger.hpp"
36
#include "objectstore/BackendRadosTestSwitch.hpp"
37
38
39
40
#include "tests/TestsCompileTimeSwitches.hpp"
#ifdef STDOUT_LOGGING
#include "common/log/StdoutLogger.hpp"
#endif
41
42
43
44
45
46
47
48

#include <exception>
#include <gtest/gtest.h>
#include <memory>
#include <utility>

namespace unitTests {

49
50
namespace {

51
52
53
54
55
56
57
58
59
60
61
62
/**
 * This structure is used to parameterize scheduler tests.
 */
struct SchedulerTestParam {
  cta::SchedulerDatabaseFactory &dbFactory;

  SchedulerTestParam(
    cta::SchedulerDatabaseFactory &dbFactory):
    dbFactory(dbFactory) {
 }
}; // struct SchedulerTestParam

63
64
}

65
66
67
68
69
70
71
/**
 * The scheduler test is a parameterized test.  It takes a pair of name server
 * and scheduler database factories as a parameter.
 */
class SchedulerTest: public ::testing::TestWithParam<SchedulerTestParam> {
public:

72
  SchedulerTest() {
73
74
  }

75
76
77
78
79
80
81
  class FailedToGetCatalogue: public std::exception {
  public:
    const char *what() const throw() {
      return "Failed to get catalogue";
    }
  };

82
83
84
85
86
87
  class FailedToGetScheduler: public std::exception {
  public:
    const char *what() const throw() {
      return "Failed to get scheduler";
    }
  };
88
89
90
91
92
93
94
  
  class FailedToGetSchedulerDB: public std::exception {
  public:
    const char *what() const throw() {
      return "Failed to get object store db.";
    }
  };
95
96
97
98
99
100

  virtual void SetUp() {
    using namespace cta;

    const SchedulerTestParam &param = GetParam();
    m_db = param.dbFactory.create();
101
    const uint64_t nbConns = 1;
102
103
104
    //m_catalogue = cta::make_unique<catalogue::SchemaCreatingSqliteCatalogue>(m_tempSqliteFile.path(), nbConns);
    m_catalogue = cta::make_unique<catalogue::InMemoryCatalogue>(nbConns);
    m_scheduler = cta::make_unique<Scheduler>(*m_catalogue, *m_db, 5, 2*1000*1000);
105
106
107
108
  }

  virtual void TearDown() {
    m_scheduler.reset();
109
    m_catalogue.reset();
110
111
112
    m_db.reset();
  }

113
114
115
116
117
118
119
120
  cta::catalogue::Catalogue &getCatalogue() {
    cta::catalogue::Catalogue *const ptr = m_catalogue.get();
    if(NULL == ptr) {
      throw FailedToGetCatalogue();
    }
    return *ptr;
  }
    
121
122
123
124
125
126
127
  cta::Scheduler &getScheduler() {
    cta::Scheduler *const ptr = m_scheduler.get();
    if(NULL == ptr) {
      throw FailedToGetScheduler();
    }
    return *ptr;
  }
128
  
129
130
131
132
133
134
135
136
  cta::SchedulerDatabase &getSchedulerDB() {
    cta::SchedulerDatabase *const ptr = m_db.get();
    if(NULL == ptr) {
      throw FailedToGetSchedulerDB();
    }
    return *ptr;
  }
  
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
  void setupDefaultCatalogue() {
    using namespace cta;
    auto & catalogue=getCatalogue();

    const std::string mountPolicyName = "mount_group";
    const uint64_t archivePriority = 1;
    const uint64_t minArchiveRequestAge = 2;
    const uint64_t retrievePriority = 3;
    const uint64_t minRetrieveRequestAge = 4;
    const uint64_t maxDrivesAllowed = 5;
    const std::string mountPolicyComment = "create mount group";

    ASSERT_TRUE(catalogue.getMountPolicies().empty());

    catalogue.createMountPolicy(
      s_adminOnAdminHost,
      mountPolicyName,
      archivePriority,
      minArchiveRequestAge,
      retrievePriority,
      minRetrieveRequestAge,
      maxDrivesAllowed,
      mountPolicyComment);

161
    const std::list<common::dataStructures::MountPolicy> groups = catalogue.getMountPolicies();
162
163
164
165
166
167
168
169
170
171
    ASSERT_EQ(1, groups.size());
    const common::dataStructures::MountPolicy group = groups.front();
    ASSERT_EQ(mountPolicyName, group.name);
    ASSERT_EQ(archivePriority, group.archivePriority);
    ASSERT_EQ(minArchiveRequestAge, group.archiveMinRequestAge);
    ASSERT_EQ(retrievePriority, group.retrievePriority);
    ASSERT_EQ(minRetrieveRequestAge, group.retrieveMinRequestAge);
    ASSERT_EQ(maxDrivesAllowed, group.maxDrivesAllowed);
    ASSERT_EQ(mountPolicyComment, group.comment);

172
    const std::string ruleComment = "create requester mount-rule";
173
    cta::common::dataStructures::UserIdentity userIdentity;
174
    catalogue.createRequesterMountRule(s_adminOnAdminHost, mountPolicyName, s_diskInstance, s_userName, ruleComment);
175

176
177
    const std::list<common::dataStructures::RequesterMountRule> rules = catalogue.getRequesterMountRules();
    ASSERT_EQ(1, rules.size());
178

179
    const common::dataStructures::RequesterMountRule rule = rules.front();
180

181
182
183
184
185
186
    ASSERT_EQ(s_userName, rule.name);
    ASSERT_EQ(mountPolicyName, rule.mountPolicy);
    ASSERT_EQ(ruleComment, rule.comment);
    ASSERT_EQ(s_adminOnAdminHost.username, rule.creationLog.username);
    ASSERT_EQ(s_adminOnAdminHost.host, rule.creationLog.host);
    ASSERT_EQ(rule.creationLog, rule.lastModificationLog);
187

188
189
190
191
192
193
    common::dataStructures::StorageClass storageClass;
    storageClass.diskInstance = s_diskInstance;
    storageClass.name = s_storageClassName;
    storageClass.nbCopies = 1;
    storageClass.comment = "create storage class";
    m_catalogue->createStorageClass(s_adminOnAdminHost, storageClass);
194
195
196
197

    const uint16_t nbPartialTapes = 1;
    const std::string tapePoolComment = "Tape-pool comment";
    const bool tapePoolEncryption = false;
198
199
    catalogue.createTapePool(s_adminOnAdminHost, s_tapePoolName,
      nbPartialTapes, tapePoolEncryption, tapePoolComment);
200
201
    const uint16_t copyNb = 1;
    const std::string archiveRouteComment = "Archive-route comment";
202
203
    catalogue.createArchiveRoute(s_adminOnAdminHost, s_diskInstance, s_storageClassName, copyNb, s_tapePoolName,
      archiveRouteComment);
204
  }
205

206
private:
207

208
209
  // Prevent copying
  SchedulerTest(const SchedulerTest &) = delete;
210

211
212
  // Prevent assignment
  SchedulerTest & operator= (const SchedulerTest &) = delete;
213

214
215
216
217
218
219
220
  std::unique_ptr<cta::SchedulerDatabase> m_db;
  std::unique_ptr<cta::catalogue::Catalogue> m_catalogue;
  std::unique_ptr<cta::Scheduler> m_scheduler;
  
protected:
  // Default parameters for storage classes, etc...
  const std::string s_userName = "user_name";
221
  const std::string s_diskInstance = "disk_instance";
222
223
224
225
226
  const std::string s_storageClassName = "TestStorageClass";
  const cta::common::dataStructures::SecurityIdentity s_adminOnAdminHost = { "admin1", "host1" };
  const std::string s_tapePoolName = "TestTapePool";
  const std::string s_libraryName = "TestLogicalLibrary";
  const std::string s_vid = "TestVid";
227
  //TempFile m_tempSqliteFile;
228

229
}; // class SchedulerTest
230

231
232
TEST_P(SchedulerTest, archive_to_new_file) {
  using namespace cta;
233

234
235
236
237
238
239
240
  setupDefaultCatalogue();
  Scheduler &scheduler = getScheduler();
  
  cta::common::dataStructures::EntryLog creationLog;
  creationLog.host="host2";
  creationLog.time=0;
  creationLog.username="admin1";
241
242
243
244
245
  cta::common::dataStructures::DiskFileInfo diskFileInfo;
  diskFileInfo.recoveryBlob="blob";
  diskFileInfo.group="group2";
  diskFileInfo.owner="cms_user";
  diskFileInfo.path="path/to/file";
246
  cta::common::dataStructures::ArchiveRequest request;
247
  request.checksumType="ADLER32";
248
249
  request.checksumValue="1111";
  request.creationLog=creationLog;
250
  request.diskFileInfo=diskFileInfo;
251
252
253
254
255
256
257
258
  request.diskFileID="diskFileID";
  request.fileSize=100*1000*1000;
  cta::common::dataStructures::UserIdentity requester;
  requester.name = s_userName;
  requester.group = "userGroup";
  request.requester = requester;
  request.srcURL="srcURL";
  request.storageClass=s_storageClassName;
259

260
261
262
  log::DummyLogger dl("");
  log::LogContext lc(dl);
  scheduler.queueArchive(s_diskInstance, request, lc);
263
264

  {
265
    auto rqsts = scheduler.getPendingArchiveJobs();
266
267
268
    ASSERT_EQ(1, rqsts.size());
    auto poolItor = rqsts.cbegin();
    ASSERT_FALSE(poolItor == rqsts.cend());
269
270
271
272
    const std::string pool = poolItor->first;
    ASSERT_TRUE(s_tapePoolName == pool);
    auto poolRqsts = poolItor->second;
    ASSERT_EQ(1, poolRqsts.size());
273
274
275
276
    std::set<std::string> remoteFiles;
    std::set<std::string> archiveFiles;
    for(auto rqstItor = poolRqsts.cbegin();
      rqstItor != poolRqsts.cend(); rqstItor++) {
277
      remoteFiles.insert(rqstItor->request.diskFileInfo.path);
278
    }
279
    ASSERT_EQ(1, remoteFiles.size());
280
    ASSERT_FALSE(remoteFiles.find(request.diskFileInfo.path) == remoteFiles.end());
281
282
283
  }
}

284
TEST_P(SchedulerTest, delete_archive_request) {
285
286
287
  using namespace cta;

  Scheduler &scheduler = getScheduler();
288
289
  
  setupDefaultCatalogue();
290

291
292
293
294
  cta::common::dataStructures::EntryLog creationLog;
  creationLog.host="host2";
  creationLog.time=0;
  creationLog.username="admin1";
295
296
297
298
299
  cta::common::dataStructures::DiskFileInfo diskFileInfo;
  diskFileInfo.recoveryBlob="blob";
  diskFileInfo.group="group2";
  diskFileInfo.owner="cms_user";
  diskFileInfo.path="path/to/file";
300
  cta::common::dataStructures::ArchiveRequest request;
301
  request.checksumType="ADLER32";
302
303
  request.checksumValue="1111";
  request.creationLog=creationLog;
304
  request.diskFileInfo=diskFileInfo;
305
306
307
308
309
310
311
312
  request.diskFileID="diskFileID";
  request.fileSize=100*1000*1000;
  cta::common::dataStructures::UserIdentity requester;
  requester.name = s_userName;
  requester.group = "userGroup";
  request.requester = requester;
  request.srcURL="srcURL";
  request.storageClass=s_storageClassName;
313

314
315
316
  log::DummyLogger dl("");
  log::LogContext lc(dl);
  auto archiveFileId = scheduler.queueArchive(s_diskInstance, request, lc);
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
  
  // Check that we have the file in the queues
  // TODO: for this to work all the time, we need an index of all requests
  // (otherwise we miss the selected ones).
  // Could also be limited to querying by ID (global index needed)
  bool found=false;
  for (auto & tp: scheduler.getPendingArchiveJobs()) {
    for (auto & req: tp.second) {
      if (req.archiveFileID == archiveFileId)
        found = true;
    }
  }
  ASSERT_TRUE(found);
  
  // Remove the request
  cta::common::dataStructures::DeleteArchiveRequest dar;
  dar.archiveFileID = archiveFileId;
  dar.requester.group = "group1";
  dar.requester.name = "user1";
336
  scheduler.deleteArchive("disk_instance", dar);
337
338
339
340
341
342
343
344
345
346
  
  // Validate that the request is gone.
  found=false;
  for (auto & tp: scheduler.getPendingArchiveJobs()) {
    for (auto & req: tp.second) {
      if (req.archiveFileID == archiveFileId)
        found = true;
    }
  }
  ASSERT_FALSE(found);
347
348
}

349
TEST_P(SchedulerTest, archive_and_retrieve_new_file) {
350
351
352
  using namespace cta;

  Scheduler &scheduler = getScheduler();
353
354
  auto &catalogue = getCatalogue();
  
355
  setupDefaultCatalogue();
356
357
358
#ifdef STDOUT_LOGGING
  log::StdoutLogger dl("unitTest");
#else
359
  log::DummyLogger dl("");
360
#endif
361
362
  log::LogContext lc(dl);
  
363
364
365
366
367
368
369
  uint64_t archiveFileId;
  {
    // Queue an archive request.
    cta::common::dataStructures::EntryLog creationLog;
    creationLog.host="host2";
    creationLog.time=0;
    creationLog.username="admin1";
370
371
372
373
374
    cta::common::dataStructures::DiskFileInfo diskFileInfo;
    diskFileInfo.recoveryBlob="blob";
    diskFileInfo.group="group2";
    diskFileInfo.owner="cms_user";
    diskFileInfo.path="path/to/file";
375
    cta::common::dataStructures::ArchiveRequest request;
376
    request.checksumType="ADLER32";
377
    request.checksumValue="1234abcd";
378
    request.creationLog=creationLog;
379
    request.diskFileInfo=diskFileInfo;
380
381
382
383
384
385
386
387
    request.diskFileID="diskFileID";
    request.fileSize=100*1000*1000;
    cta::common::dataStructures::UserIdentity requester;
    requester.name = s_userName;
    requester.group = "userGroup";
    request.requester = requester;
    request.srcURL="srcURL";
    request.storageClass=s_storageClassName;
388
    archiveFileId = scheduler.queueArchive(s_diskInstance, request, lc);
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
  }
  
  // Check that we have the file in the queues
  // TODO: for this to work all the time, we need an index of all requests
  // (otherwise we miss the selected ones).
  // Could also be limited to querying by ID (global index needed)
  bool found=false;
  for (auto & tp: scheduler.getPendingArchiveJobs()) {
    for (auto & req: tp.second) {
      if (req.archiveFileID == archiveFileId)
        found = true;
    }
  }
  ASSERT_TRUE(found);

  // Create the environment for the migration to happen (library + tape) 
405
  const std::string libraryComment = "Library comment";
406
407
  catalogue.createLogicalLibrary(s_adminOnAdminHost, s_libraryName,
    libraryComment);
408
  {
409
    auto libraries = catalogue.getLogicalLibraries();
410
    ASSERT_EQ(1, libraries.size());
411
412
    ASSERT_EQ(s_libraryName, libraries.front().name);
    ASSERT_EQ(libraryComment, libraries.front().comment);
413
414
  }
  const uint64_t capacityInBytes = 12345678;
415
416
417
  const std::string tapeComment = "Tape comment";
  bool notDisabled = false;
  bool notFull = false;
418
  catalogue.createTape(s_adminOnAdminHost, s_vid, s_libraryName, s_tapePoolName, capacityInBytes,
419
    notDisabled, notFull, tapeComment);
420

421
  const bool lbpIsOn = true;
422
423
  const std::string driveName = "tape_drive";

424
  catalogue.tapeLabelled(s_vid, "tape_drive", lbpIsOn);
425

426
427
428
429
  {
    // Emulate a tape server by asking for a mount and then a file (and succeed
    // the transfer)
    std::unique_ptr<cta::TapeMount> mount;
430
431
432
433
    // This first initialization is normally done by the dataSession function.
    cta::common::dataStructures::DriveInfo driveInfo = { driveName, "myHost", s_libraryName };
    scheduler.reportDriveStatus(driveInfo, cta::common::dataStructures::MountType::NoMount, cta::common::dataStructures::DriveStatus::Down);
    scheduler.reportDriveStatus(driveInfo, cta::common::dataStructures::MountType::NoMount, cta::common::dataStructures::DriveStatus::Up);
434
    mount.reset(scheduler.getNextMount(s_libraryName, "drive0", lc).release());
435
    ASSERT_NE((cta::TapeMount*)NULL, mount.get());
436
    ASSERT_EQ(cta::common::dataStructures::MountType::Archive, mount.get()->getMountType());
437
438
439
440
441
    auto & osdb=getSchedulerDB();
    auto mi=osdb.getMountInfo();
    ASSERT_EQ(1, mi->existingOrNextMounts.size());
    ASSERT_EQ("TestTapePool", mi->existingOrNextMounts.front().tapePool);
    ASSERT_EQ("TestVid", mi->existingOrNextMounts.front().vid);
442
    std::unique_ptr<cta::ArchiveMount> archiveMount;
443
    archiveMount.reset(dynamic_cast<cta::ArchiveMount*>(mount.release()));
444
445
    ASSERT_NE((cta::ArchiveMount*)NULL, archiveMount.get());
    std::unique_ptr<cta::ArchiveJob> archiveJob;
446
    archiveJob.reset(archiveMount->getNextJob(lc).release());
447
    ASSERT_NE((cta::ArchiveJob*)NULL, archiveJob.get());
448
449
    archiveJob->tapeFile.blockId = 1;
    archiveJob->tapeFile.fSeq = 1;
450
    archiveJob->tapeFile.checksumType = "ADLER32";
451
    archiveJob->tapeFile.checksumValue = "1234abcd";
452
453
    archiveJob->tapeFile.compressedSize = archiveJob->archiveFile.fileSize;
    archiveJob->tapeFile.copyNb = 1;
454
    archiveJob->complete();
455
    archiveJob.reset(archiveMount->getNextJob(lc).release());
456
    ASSERT_EQ((cta::ArchiveJob*)NULL, archiveJob.get());
457
    archiveMount->complete();
458
459
460
  }

  {
461
462
463
464
    cta::common::dataStructures::EntryLog creationLog;
    creationLog.host="host2";
    creationLog.time=0;
    creationLog.username="admin1";
465
466
467
468
469
    cta::common::dataStructures::DiskFileInfo diskFileInfo;
    diskFileInfo.recoveryBlob="blob";
    diskFileInfo.group="group2";
    diskFileInfo.owner="cms_user";
    diskFileInfo.path="path/to/file";
470
471
    cta::common::dataStructures::RetrieveRequest request;
    request.archiveFileID = archiveFileId;
472
    request.entryLog = creationLog;
473
    request.diskFileInfo = diskFileInfo;
474
475
476
    request.dstURL = "dstURL";
    request.requester.name = s_userName;
    request.requester.group = "userGroup";
477
    scheduler.queueRetrieve("disk_instance", request, lc);
478
479
  }

480
  // Check that the retrieve request is queued
481
  {
482
483
    auto rqsts = scheduler.getPendingRetrieveJobs();
    // We expect 1 tape with queued jobs
484
    ASSERT_EQ(1, rqsts.size());
485
486
487
488
489
490
491
492
493
494
495
    // We expect the queue to contain 1 job
    ASSERT_EQ(1, rqsts.cbegin()->second.size());
    // We expect the job to be single copy
    auto & job = rqsts.cbegin()->second.back();
    ASSERT_EQ(1, job.tapeCopies.size());
    // We expect the copy to be on the provided tape.
    ASSERT_TRUE(s_vid == job.tapeCopies.cbegin()->first);
    // Check the remote target
    ASSERT_EQ("dstURL", job.request.dstURL);
    // Check the archive file ID
    ASSERT_EQ(archiveFileId, job.request.archiveFileID);
496
497
498
499
500
501
  }
  
  {
    // Emulate a tape server by asking for a mount and then a file (and succeed
    // the transfer)
    std::unique_ptr<cta::TapeMount> mount;
502
    mount.reset(scheduler.getNextMount(s_libraryName, "drive0", lc).release());
503
    ASSERT_NE((cta::TapeMount*)NULL, mount.get());
504
    ASSERT_EQ(cta::common::dataStructures::MountType::Retrieve, mount.get()->getMountType());
505
    std::unique_ptr<cta::RetrieveMount> retrieveMount;
506
    retrieveMount.reset(dynamic_cast<cta::RetrieveMount*>(mount.release()));
507
508
    ASSERT_NE((cta::RetrieveMount*)NULL, retrieveMount.get());
    std::unique_ptr<cta::RetrieveJob> retrieveJob;
509
    retrieveJob.reset(retrieveMount->getNextJob().release());
510
    ASSERT_NE((cta::RetrieveJob*)NULL, retrieveJob.get());
511
512
    retrieveJob->complete();
    retrieveJob.reset(retrieveMount->getNextJob().release());
513
514
515
    ASSERT_EQ((cta::RetrieveJob*)NULL, retrieveJob.get());
  }
}
516

517
TEST_P(SchedulerTest, retry_archive_until_max_reached) {
518
  using namespace cta;
519
520
  
  setupDefaultCatalogue();
521

522
  auto &scheduler = getScheduler();
523
  auto &catalogue = getCatalogue();
524
  
525
526
527
#ifdef STDOUT_LOGGING
  log::StdoutLogger dl("unitTest");
#else
528
  log::DummyLogger dl("");
529
#endif
530
531
  log::LogContext lc(dl);
  
532
533
534
535
536
537
538
  uint64_t archiveFileId;
  {
    // Queue an archive request.
    cta::common::dataStructures::EntryLog creationLog;
    creationLog.host="host2";
    creationLog.time=0;
    creationLog.username="admin1";
539
540
541
542
543
    cta::common::dataStructures::DiskFileInfo diskFileInfo;
    diskFileInfo.recoveryBlob="blob";
    diskFileInfo.group="group2";
    diskFileInfo.owner="cms_user";
    diskFileInfo.path="path/to/file";
544
    cta::common::dataStructures::ArchiveRequest request;
545
    request.checksumType="ADLER32";
546
547
    request.checksumValue="1111";
    request.creationLog=creationLog;
548
    request.diskFileInfo=diskFileInfo;
549
550
551
552
553
554
555
556
    request.diskFileID="diskFileID";
    request.fileSize=100*1000*1000;
    cta::common::dataStructures::UserIdentity requester;
    requester.name = s_userName;
    requester.group = "userGroup";
    request.requester = requester;
    request.srcURL="srcURL";
    request.storageClass=s_storageClassName;
557
    archiveFileId = scheduler.queueArchive(s_diskInstance, request, lc);
558
559
  }
  
560
561
562
563
564
565
566
567
568
569
570
571
572
573
  // Create the environment for the migration to happen (library + tape) 
    const std::string libraryComment = "Library comment";
  catalogue.createLogicalLibrary(s_adminOnAdminHost, s_libraryName,
    libraryComment);
  {
    auto libraries = catalogue.getLogicalLibraries();
    ASSERT_EQ(1, libraries.size());
    ASSERT_EQ(s_libraryName, libraries.front().name);
    ASSERT_EQ(libraryComment, libraries.front().comment);
  }
  const uint64_t capacityInBytes = 12345678;
  const std::string tapeComment = "Tape comment";
  bool notDisabled = false;
  bool notFull = false;
574
  catalogue.createTape(s_adminOnAdminHost, s_vid, s_libraryName, s_tapePoolName, capacityInBytes, notDisabled,
575
    notFull, tapeComment);
576

577
578
  const bool lbpIsOn = true;
  catalogue.tapeLabelled(s_vid, "tape_drive", lbpIsOn);
579

580
581
582
  {
    // Emulate a tape server by asking for a mount and then a file
    std::unique_ptr<cta::TapeMount> mount;
583
    mount.reset(scheduler.getNextMount(s_libraryName, "drive0", lc).release());
584
    ASSERT_NE((cta::TapeMount*)NULL, mount.get());
585
    ASSERT_EQ(cta::common::dataStructures::MountType::Archive, mount.get()->getMountType());
586
    std::unique_ptr<cta::ArchiveMount> archiveMount;
587
    archiveMount.reset(dynamic_cast<cta::ArchiveMount*>(mount.release()));
588
589
    ASSERT_NE((cta::ArchiveMount*)NULL, archiveMount.get());
    // The file should be retried 10 times
590
    for (int i=0; i<=5; i++) {
591
      std::unique_ptr<cta::ArchiveJob> archiveJob(archiveMount->getNextJob(lc));
592
593
594
595
      if (!archiveJob.get()) {
        int __attribute__((__unused__)) debugI=i;
      }
      ASSERT_NE((cta::ArchiveJob*)NULL, archiveJob.get());
596
      // Validate we got the right file
597
      ASSERT_EQ(archiveFileId, archiveJob->archiveFile.archiveFileID);
598
      archiveJob->failed(cta::exception::Exception("Archive failed"));
599
600
601
    }
    // Then the request should be gone
    std::unique_ptr<cta::ArchiveJob> archiveJob;
602
    archiveJob.reset(archiveMount->getNextJob(lc).release());
603
604
605
    ASSERT_EQ((cta::ArchiveJob*)NULL, archiveJob.get());
  }
}
606

607
608
TEST_P(SchedulerTest, retrieve_non_existing_file) {
  using namespace cta;
609
610
611
  
  setupDefaultCatalogue();
  
612
  Scheduler &scheduler = getScheduler();
613
614
615
  
  log::DummyLogger dl("");
  log::LogContext lc(dl);
616
617

  {
618
619
620
621
    cta::common::dataStructures::EntryLog creationLog;
    creationLog.host="host2";
    creationLog.time=0;
    creationLog.username="admin1";
622
623
624
625
626
    cta::common::dataStructures::DiskFileInfo diskFileInfo;
    diskFileInfo.recoveryBlob="blob";
    diskFileInfo.group="group2";
    diskFileInfo.owner="cms_user";
    diskFileInfo.path="path/to/file";
627
628
    cta::common::dataStructures::RetrieveRequest request;
    request.archiveFileID = 12345;
629
    request.entryLog = creationLog;
630
    request.diskFileInfo = diskFileInfo;
631
632
633
    request.dstURL = "dstURL";
    request.requester.name = s_userName;
    request.requester.group = "userGroup";
634
    ASSERT_THROW(scheduler.queueRetrieve("disk_instance", request, lc), cta::exception::Exception);
635
636
  }
}
637

638
639
640
641
#undef TEST_MOCK_DB
#ifdef TEST_MOCK_DB
static cta::MockSchedulerDatabaseFactory mockDbFactory;
INSTANTIATE_TEST_CASE_P(MockSchedulerTest, SchedulerTest,
642
  ::testing::Values(SchedulerTestParam(mockDbFactory)));
643
644
645
646
647
648
649
#endif

#define TEST_VFS
#ifdef TEST_VFS
static cta::OStoreDBFactory<cta::objectstore::BackendVFS> OStoreDBFactoryVFS;

INSTANTIATE_TEST_CASE_P(OStoreDBPlusMockSchedulerTestVFS, SchedulerTest,
650
  ::testing::Values(SchedulerTestParam(OStoreDBFactoryVFS)));
651
652
653
654
655
656
#endif

#ifdef TEST_RADOS
static cta::OStoreDBFactory<cta::objectstore::BackendRados> OStoreDBFactoryRados("rados://tapetest@tapetest");

INSTANTIATE_TEST_CASE_P(OStoreDBPlusMockSchedulerTestRados, SchedulerTest,
657
  ::testing::Values(SchedulerTestParam(OStoreDBFactoryRados)));
658
659
660
#endif
} // namespace unitTests