DataTransferSessionTest.cpp 51.9 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
/******************************************************************************
 *
 * This file is part of the Castor project.
 * See http://castor.web.cern.ch/castor
 *
 * Copyright (C) 2003  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 2
 * 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, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 *
 * 
 *
 * @author Castor Dev team, castor-dev@cern.ch
 *****************************************************************************/

24
25
26
27
#define __STDC_CONSTANT_MACROS // For using stdint macros (stdint is included
// by inttypes.h, so we shoot first)
#include <stdint.h>
#include <inttypes.h>
28
#include <gtest/gtest.h>
29

30
#include "castor/legacymsg/RmcProxyDummy.hpp"
31
#include "castor/log/StringLogger.hpp"
32
33
34
#include "castor/mediachanger/MediaChangerFacade.hpp"
#include "castor/mediachanger/MmcProxyDummy.hpp"
#include "castor/messages/AcsProxyDummy.hpp"
35
#include "castor/messages/TapeserverProxyDummy.hpp"
36
#include "castor/server/ProcessCapDummy.hpp"
37
#include "castor/server/Threading.hpp"
38
#include "castor/tape/tapeserver/daemon/DataTransferSession.hpp"
39
#include "castor/tape/tapeserver/daemon/VolumeInfo.hpp"
40
41
#include "castor/tape/tapeserver/system/Wrapper.hpp"
#include "castor/tape/tapeserver/file/File.hpp"
42
#include "castor/tape/tapeserver/drive/FakeDrive.hpp"
43
44
#include "common/exception/Exception.hpp"
#include "common/Utils.hpp"
45
#include "Ctape.h"
46
#include "scheduler/Scheduler.hpp"
47
#include "smc_struct.h"
48
49
#include "nameserver/mockNS/MockNameServer.hpp"
#include "remotens/MockRemoteNS.hpp"
50
#include "scheduler/DummyScheduler.hpp"
51
#include "scheduler/OStoreDB/OStoreDBFactory.hpp"
52
#include "scheduler/MountType.hpp"
53
54
55
56
#include "nameserver/NameServer.hpp"
#include "scheduler/testingMocks/MockRetrieveMount.hpp"
#include "scheduler/testingMocks/MockArchiveJob.hpp"
#include "scheduler/testingMocks/MockArchiveMount.hpp"
57

58
#include <dirent.h>
59
#include <fcntl.h>
60
#include <stdexcept>
Eric Cano's avatar
Eric Cano committed
61
62
63
#include <sys/mman.h>
#include <sys/types.h>
#include <sys/stat.h>
64
65
#include <unistd.h>
#include <zlib.h>
Eric Cano's avatar
Eric Cano committed
66

67
using namespace castor::tape::tapeserver;
68
using namespace castor::tape::tapeserver::daemon;
69
70
namespace unitTest {

71
72
class castor_tape_tapeserver_daemon_DataTransferSessionTest: public
  ::testing::Test {
73
74
75
protected:

  void SetUp() {
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
    strncpy(m_tmpDir, "/tmp/DataTransferSessionTestXXXXXX", sizeof(m_tmpDir));
    if(!mkdtemp(m_tmpDir)) {
      const std::string errMsg = cta::Utils::errnoToString(errno);
      std::ostringstream msg;
      msg << "Failed to create directory with template"
        " /tmp/DataTransferSessionTestXXXXXX: " << errMsg;
      bzero(m_tmpDir, sizeof(m_tmpDir));
      throw cta::exception::Exception(msg.str());
    }

    struct stat statBuf;
    bzero(&statBuf, sizeof(statBuf));
    if(stat(m_tmpDir, &statBuf)) {
      const std::string errMsg = cta::Utils::errnoToString(errno);
      std::ostringstream msg;
      msg << "Failed to stat directory " << m_tmpDir << ": " << errMsg;
      throw cta::exception::Exception(msg.str());
    }

    std::ostringstream cmd;
    cmd << "touch " << m_tmpDir << "/hello";
    system(cmd.str().c_str());
98
99
100
  }

  void TearDown() {
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
    // If Setup() created a temporary directory
    if(m_tmpDir) {

      // Openn the directory
      std::unique_ptr<DIR, std::function<int(DIR*)>>
        dir(opendir(m_tmpDir), closedir);
      if(NULL == dir.get()) {
        const std::string errMsg = cta::Utils::errnoToString(errno);
        std::ostringstream msg;
        msg << "Failed to open directory " << m_tmpDir << ": " << errMsg;
        throw cta::exception::Exception(msg.str());
      }

      // Delete each of the files within the directory
      struct dirent *entry = NULL;
      while((entry = readdir(dir.get()))) {
        const std::string entryName(entry->d_name);
        if(entryName != "." && entryName != "..") {
          const std::string entryPath = std::string(m_tmpDir) + "/" + entryName;
          if(unlink(entryPath.c_str())) {
            const std::string errMsg = cta::Utils::errnoToString(errno);
            std::ostringstream msg;
            msg << "Failed to unlink " << entryPath;
            throw cta::exception::Exception(msg.str());
          }
        }
      }

      // Delete the now empty directory
      if(rmdir(m_tmpDir)) {
        const std::string errMsg = cta::Utils::errnoToString(errno);
        std::ostringstream msg;
        msg << "Failed to delete directory " << m_tmpDir << ": " << errMsg;
        throw cta::exception::Exception(msg.str());
      }
    }
137
  }
138

139
140
141
142
143
144
145
  /**
   * Temporary directory created with mkdtemp that will be used to contain the
   * destination remote files of the tests that need to create them.
   *
   * Please note that a new temporary directory is created and deleted for each
   * test by the Setup() and TearDown() methods.
   */
146
  char m_tmpDir[100];
147
148
};

149
TEST_F(castor_tape_tapeserver_daemon_DataTransferSessionTest, DataTransferSessionGooddayRecall) {
Eric Cano's avatar
Eric Cano committed
150
151
152
  // 0) Prepare the logger for everyone
  castor::log::StringLogger logger("tapeServerUnitTest");
  
153
  // 1) prepare the fake scheduler
154
  std::string vid = "V12345";
155
  // cta::MountType::Enum mountType = cta::MountType::RETRIEVE;
156
  std::string density = "8000GC";
157

158
159
  // 3) Prepare the necessary environment (logger, plus system wrapper), 
  castor::tape::System::mockWrapper mockSys;
160
161
  mockSys.delegateToFake();
  mockSys.disableGMockCallsCounting();
162
  mockSys.fake.setupForVirtualDriveSLC6();
163
164
165
  //delete is unnecessary
  //pointer with ownership will be passed to the application,
  //which will do the delete 
166
  mockSys.fake.m_pathToDrive["/dev/nst0"] = new castor::tape::tapeserver::drive::FakeDrive;
167
168
169
170

  // 4) Create the scheduler
  cta::MockNameServer ns;
  cta::MockRemoteNS rns;
171
  cta::OStoreDBWrapper<cta::objectstore::BackendVFS> db("Unittest");
172
173
174
175
176
177
178
179
  cta::Scheduler scheduler(ns, db, rns);

  // Always use the same requester
  const cta::SecurityIdentity requester;

  // List to remember the path of each remote file so that the existance of the
  // files can be tested for at the end of the test
  std::list<std::string> remoteFilePaths;
180
  
181
182
183
184
185
186
187
188
189
190
191
192
193
194
  // 5) Create the tapepool, library and tape for the scheduler.
  // Make mounts immediate.
  ASSERT_NO_THROW(scheduler.createAdminUserWithoutAuthorizingRequester(requester, requester.getUser(), ""));
  ASSERT_NO_THROW(scheduler.createAdminHostWithoutAuthorizingRequester(requester, requester.getHost(), ""));
  ASSERT_NO_THROW(scheduler.createTapePool(requester, "TapePool", 1, ""));
  cta::MountCriteria immediateMount;
  immediateMount.maxAge = 0;
  immediateMount.maxBytesQueued = 1;
  immediateMount.maxFilesQueued = 1;
  immediateMount.quota = 10;
  ASSERT_NO_THROW(scheduler.setTapePoolMountCriteria("TapePool", cta::MountCriteriaByDirection(immediateMount, immediateMount)));                   
  ASSERT_NO_THROW(scheduler.createLogicalLibrary(requester, "T10KD6", ""));
  ASSERT_NO_THROW(scheduler.createTape(requester, "V12345", "T10KD6", "TapePool", 10*1000*1000, "8000GC", ""));
  
195
  // 5) Prepare files for reading by writing them to the mock system
196
197
198
  {
    // Label the tape
    castor::tape::tapeFile::LabelSession ls(*mockSys.fake.m_pathToDrive["/dev/nst0"], 
199
        "V12345");
200
201
    mockSys.fake.m_pathToDrive["/dev/nst0"]->rewind();
    // And write to it
202
    castor::tape::tapeserver::daemon::VolumeInfo volInfo;
203
    volInfo.vid="V12345";
204
    castor::tape::tapeFile::WriteSession ws(*mockSys.fake.m_pathToDrive["/dev/nst0"],
205
       volInfo , 0, true);
206
207
208

    // Write a few files on the virtual tape and modify the archive name space
    // so that it is in sync
209
210
211
    uint8_t data[1000];
    castor::tape::SCSI::Structures::zeroStruct(&data);
    for (int fseq=1; fseq <= 10 ; fseq ++) {
212
213
      // Create a path to a remote destination file
      std::ostringstream remoteFilePath;
214
      remoteFilePath << "file://" << m_tmpDir << "/test" << fseq;
215
216
      remoteFilePaths.push_back(remoteFilePath.str());

217
      // Create an archive file entry in the archive namespace
218
219
220
221
      std::ostringstream archiveFilePath;
      archiveFilePath << "/test" << fseq;
      const mode_t archiveFileMode = 0655;
      const uint64_t archiveFileSize = 256*1024;
222
      ASSERT_NO_THROW(ns.createFile(
223
224
225
        requester,
        archiveFilePath.str(),
        archiveFileMode,
226
        archiveFileSize));
227
      std::unique_ptr<cta::ArchiveFileStatus> status = ns.statFile(requester, archiveFilePath.str());
228
      
229
      // Write the file to tape
230
231
232
233
234
      cta::MockRetrieveMount mrm;
      cta::MockNameServer mns;
      cta::MockArchiveMount mam(mns);
      std::unique_ptr<cta::RetrieveJob> ftr(new cta::MockRetrieveJob(mrm));
      std::unique_ptr<cta::ArchiveJob> ftm(new cta::MockArchiveJob(mam, mns));
235
      ftr->nameServerTapeFile.tapeFileLocation.fSeq = fseq;
236
      ftm->nameServerTapeFile.tapeFileLocation.fSeq = fseq;
237
238
      ftr->archiveFile.fileId = status->fileId;
      ftm->archiveFile.fileId = status->fileId;
239
      castor::tape::tapeFile::WriteFile wf(&ws, *ftm, archiveFileSize);
240
      ftr->nameServerTapeFile.tapeFileLocation.blockId = wf.getBlockId();
241
      ftr->remotePath = remoteFilePath.str();
242
243
244
245
      // Write the data (one block)
      wf.write(data, sizeof(data));
      // Close the file
      wf.close();
246

247
248
249
250
      // Create tape file entry in the archive namespace
      cta::NameServerTapeFile tapeFile;
      tapeFile.copyNb = 1;
      tapeFile.tapeFileLocation.fSeq = fseq;
251
      tapeFile.tapeFileLocation.blockId = wf.getBlockId();
252
253
254
255
256
257
258
259
260
261
262
263
      tapeFile.tapeFileLocation.vid = volInfo.vid;
      tapeFile.tapeFileLocation.copyNb = 1;
      tapeFile.size = archiveFileSize;
      tapeFile.compressedSize = archiveFileSize; // No compression
      cta::Checksum tapeFileChecksum(cta::Checksum::CHECKSUMTYPE_ADLER32,
        cta::ByteArray(cta::Utils::getAdler32(data, sizeof data)));
      tapeFile.checksum = tapeFileChecksum;
      ASSERT_NO_THROW(ns.addTapeFile(
        requester,
        archiveFilePath.str(),
        tapeFile));

264
265
266
      // Schedule the retrieval of the file
      std::list<std::string> archiveFilePaths;
      archiveFilePaths.push_back(archiveFilePath.str());
267
      ASSERT_NO_THROW(scheduler.queueRetrieveRequest(
268
269
        requester,
        archiveFilePaths,
270
        remoteFilePath.str()));
271
272
    }
  }
273
274

  // 6) Create the data transfer session
275
  DriveConfig driveConfig("T10D6116", "T10KD6", "/dev/tape_T10D6116", "manual");
276
277
278
279
280
281
  DataTransferConfig castorConf;
  castorConf.bufsz = 1024*1024; // 1 MB memory buffers
  castorConf.nbBufs = 10;
  castorConf.bulkRequestRecallMaxBytes = UINT64_C(100)*1000*1000*1000;
  castorConf.bulkRequestRecallMaxFiles = 1000;
  castorConf.nbDiskThreads = 1;
282
283
284
285
  castor::messages::AcsProxyDummy acs;
  castor::mediachanger::MmcProxyDummy mmc;
  castor::legacymsg::RmcProxyDummy rmc;
  castor::mediachanger::MediaChangerFacade mc(acs, mmc, rmc);
286
  castor::server::ProcessCap capUtils;
287
  castor::messages::TapeserverProxyDummy initialProcess;
288
  DataTransferSession sess("tapeHost", logger, mockSys,
289
    driveConfig, mc, initialProcess, capUtils, castorConf, scheduler);
290
291

  // 7) Run the data transfer session
292
  ASSERT_NO_THROW(sess.execute());
293
294

  // 8) Check the session git the correct VID
295
  ASSERT_EQ("V12345", sess.getVid());
296

297
  // 9) Check the remote files exist and have the correct size
298
299
300
301
  for(auto pathItor = remoteFilePaths.cbegin(); pathItor !=
    remoteFilePaths.cend(); pathItor++) {
    struct stat statBuf;
    bzero(&statBuf, sizeof(statBuf));
302
    const int statRc = stat(pathItor->substr(7).c_str(), &statBuf); //remove the "file://" for stat-ing
303
    ASSERT_EQ(0, statRc);
304
    ASSERT_EQ(1000, statBuf.st_size); //same size of data
305
  }
306
}
307

308
TEST_F(castor_tape_tapeserver_daemon_DataTransferSessionTest, DataTransferSessionWrongRecall) {
309
310
311
  // This test is the same as the previous one, with 
  // wrong parameters set for the recall, so that we fail 
  // to recall the first file and cancel the second.
312
313

  // 0) Prepare the logger for everyone
314
315
  castor::log::StringLogger logger("tapeServerUnitTest");
  
316
  // 1) prepare the fake scheduler
317
  std::string vid = "V12345";
318
  // cta::MountType::Enum mountType = cta::MountType::RETRIEVE;
319
  std::string density = "8000GC";
320

321
322
323
324
325
326
327
328
  // 3) Prepare the necessary environment (logger, plus system wrapper), 
  castor::tape::System::mockWrapper mockSys;
  mockSys.delegateToFake();
  mockSys.disableGMockCallsCounting();
  mockSys.fake.setupForVirtualDriveSLC6();
  //delete is unnecessary
  //pointer with ownership will be passed to the application,
  //which will do the delete 
329
  mockSys.fake.m_pathToDrive["/dev/nst0"] = new castor::tape::tapeserver::drive::FakeDrive;
330
331
332
333

  // 4) Create the scheduler
  cta::MockNameServer ns;
  cta::MockRemoteNS rns;
334
  cta::OStoreDBWrapper<cta::objectstore::BackendVFS> db("Unittest");
335
336
337
338
339
340
341
342
  cta::Scheduler scheduler(ns, db, rns);

  // Always use the same requester
  const cta::SecurityIdentity requester;

  // List to remember the path of each remote file so that the existance of the
  // files can be tested for at the end of the test
  std::list<std::string> remoteFilePaths;
343
  
344
345
346
347
348
349
350
351
352
353
354
355
356
357
  // 5) Create the tapepool, library and tape for the scheduler.
  // Make mounts immediate.
  ASSERT_NO_THROW(scheduler.createAdminUserWithoutAuthorizingRequester(requester, requester.getUser(), ""));
  ASSERT_NO_THROW(scheduler.createAdminHostWithoutAuthorizingRequester(requester, requester.getHost(), ""));
  ASSERT_NO_THROW(scheduler.createTapePool(requester, "TapePool", 1, ""));
  cta::MountCriteria immediateMount;
  immediateMount.maxAge = 0;
  immediateMount.maxBytesQueued = 1;
  immediateMount.maxFilesQueued = 1;
  immediateMount.quota = 10;
  ASSERT_NO_THROW(scheduler.setTapePoolMountCriteria("TapePool", cta::MountCriteriaByDirection(immediateMount, immediateMount)));                   
  ASSERT_NO_THROW(scheduler.createLogicalLibrary(requester, "T10KD6", ""));
  ASSERT_NO_THROW(scheduler.createTape(requester, "V12345", "T10KD6", "TapePool", 10*1000*1000, "8000GC", ""));
  
358
  // 5) Prepare files for reading by writing them to the mock system
359
360
361
  {
    // Label the tape
    castor::tape::tapeFile::LabelSession ls(*mockSys.fake.m_pathToDrive["/dev/nst0"], 
362
        "V12345");
363
364
    mockSys.fake.m_pathToDrive["/dev/nst0"]->rewind();
    // And write to it
365
    castor::tape::tapeserver::daemon::VolumeInfo volInfo;
366
367
368
    volInfo.vid="V12345";
    castor::tape::tapeFile::WriteSession ws(*mockSys.fake.m_pathToDrive["/dev/nst0"],
       volInfo , 0, true);
369
370
371

    // Write a few files on the virtual tape and modify the archive name space
    // so that it is in sync
372
373
    uint8_t data[1000];
    castor::tape::SCSI::Structures::zeroStruct(&data);
374
375
    int fseq=1;
    {
376
377
      // Create a path to a remote destination file
      std::ostringstream remoteFilePath;
378
      remoteFilePath << "file://" << m_tmpDir << "/test" << fseq;
379
380
      remoteFilePaths.push_back(remoteFilePath.str());

381
      // Create an archive file entry in the archive namespace
382
383
384
      std::ostringstream archiveFilePath;
      archiveFilePath << "/test" << fseq;
      const mode_t archiveFileMode = 0655;
385
      const uint64_t archiveFileSize = 1000;
386
      ASSERT_NO_THROW(ns.createFile(
387
388
389
        requester,
        archiveFilePath.str(),
        archiveFileMode,
390
        archiveFileSize));
391
392

      // Write the file to tape
393
394
395
396
397
      cta::MockNameServer mns;
      cta::MockArchiveMount mam(mns);
      cta::MockRetrieveMount mrm;
      std::unique_ptr<cta::RetrieveJob> ftr(new cta::MockRetrieveJob(mrm));
      std::unique_ptr<cta::ArchiveJob> ftm_temp(new cta::MockArchiveJob(mam, mns));
398
      ftr->nameServerTapeFile.tapeFileLocation.fSeq = fseq;
399
      ftm_temp->nameServerTapeFile.tapeFileLocation.fSeq = fseq;
400
401
      ftr->archiveFile.fileId = 1000 + fseq;
      ftm_temp->archiveFile.fileId = 1000 + fseq;
402
      castor::tape::tapeFile::WriteFile wf(&ws, *ftm_temp, archiveFileSize);
403
      ftr->nameServerTapeFile.tapeFileLocation.blockId = wf.getBlockId();
404
      ftr->remotePath = remoteFilePath.str();
405
406
407
408
      // Write the data (one block)
      wf.write(data, sizeof(data));
      // Close the file
      wf.close();
409

410
411
412
413
414
      // Create tape file entry in the archive namespace that is beyond the end
      // of data
      cta::NameServerTapeFile tapeFile;
      tapeFile.copyNb = 1;
      tapeFile.tapeFileLocation.fSeq = fseq + 10000;
415
      tapeFile.tapeFileLocation.blockId = wf.getBlockId() + 10000;
416
417
418
419
420
421
422
423
424
425
426
427
      tapeFile.tapeFileLocation.vid = volInfo.vid;
      tapeFile.tapeFileLocation.copyNb = 1;
      tapeFile.size = archiveFileSize;
      tapeFile.compressedSize = archiveFileSize; // No compression
      cta::Checksum tapeFileChecksum(cta::Checksum::CHECKSUMTYPE_ADLER32,
        cta::ByteArray(cta::Utils::getAdler32(data, sizeof data)));
      tapeFile.checksum = tapeFileChecksum;
      ASSERT_NO_THROW(ns.addTapeFile(
        requester,
        archiveFilePath.str(),
        tapeFile));

428
429
430
      // Schedule the retrieval of the file
      std::list<std::string> archiveFilePaths;
      archiveFilePaths.push_back(archiveFilePath.str());
431
      ASSERT_NO_THROW(scheduler.queueRetrieveRequest(
432
433
        requester,
        archiveFilePaths,
434
        remoteFilePath.str()));
435
436
    }
  }
437
438

  // 6) Create the data transfer session
439
  DriveConfig driveConfig("T10D6116", "T10KD6", "/dev/tape_T10D6116", "manual");
440
441
442
443
444
445
  DataTransferConfig castorConf;
  castorConf.bufsz = 1024*1024; // 1 MB memory buffers
  castorConf.nbBufs = 10;
  castorConf.bulkRequestRecallMaxBytes = UINT64_C(100)*1000*1000*1000;
  castorConf.bulkRequestRecallMaxFiles = 1000;
  castorConf.nbDiskThreads = 1;
446
447
448
449
  castor::messages::AcsProxyDummy acs;
  castor::mediachanger::MmcProxyDummy mmc;
  castor::legacymsg::RmcProxyDummy rmc;
  castor::mediachanger::MediaChangerFacade mc(acs, mmc, rmc);
450
451
  castor::server::ProcessCap capUtils;
  castor::messages::TapeserverProxyDummy initialProcess;
452
  DataTransferSession sess("tapeHost", logger, mockSys,
453
    driveConfig, mc, initialProcess, capUtils, castorConf, scheduler);
454
455
456
457
458

  // 7) Run the data transfer session
  ASSERT_NO_THROW(sess.execute());

  // 8) Check the session git the correct VID
459
  ASSERT_EQ("V12345", sess.getVid());
460
461

  // 9) Check the remote files exist and have the correct size
462
463
  std::string temp = logger.getLog();
  ASSERT_NE(std::string::npos, logger.getLog().find("trying to position beyond the end of data"));
464
}
465

466
TEST_F(castor_tape_tapeserver_daemon_DataTransferSessionTest, DataTransferSessionNoSuchDrive) {
467
468
469
470
471
  
  // 0) Prepare the logger for everyone
  castor::log::StringLogger logger("tapeServerUnitTest");
  
  // 1) prepare the fake scheduler
472
  std::string vid = "V12345";
473
  // cta::MountType::Enum mountType = cta::MountType::RETRIEVE;
474
  std::string density = "8000GC";
475

476
477
478
479
480
  // 3) Prepare the necessary environment (logger, plus system wrapper), 
  castor::tape::System::mockWrapper mockSys;
  mockSys.delegateToFake();
  mockSys.disableGMockCallsCounting();
  mockSys.fake.setupForVirtualDriveSLC6();
481
482
483
484
485
486
487
488
  //delete is unnecessary
  //pointer with ownership will be passed to the application,
  //which will do the delete 
  mockSys.fake.m_pathToDrive["/dev/nst0"] = new castor::tape::tapeserver::drive::FakeDrive;

  // 4) Create the scheduler
  cta::MockNameServer ns;
  cta::MockRemoteNS rns;
489
  cta::OStoreDBWrapper<cta::objectstore::BackendVFS> db("Unittest");
490
491
492
493
494
  cta::Scheduler scheduler(ns, db, rns);

  // Always use the same requester
  const cta::SecurityIdentity requester;
  
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
  // List to remember the path of each remote file so that the existance of the
  // files can be tested for at the end of the test
  std::list<std::string> remoteFilePaths;
  
  // 5) Create the tapepool, library and tape for the scheduler.
  // Make mounts immediate.
  ASSERT_NO_THROW(scheduler.createAdminUserWithoutAuthorizingRequester(requester, requester.getUser(), ""));
  ASSERT_NO_THROW(scheduler.createAdminHostWithoutAuthorizingRequester(requester, requester.getHost(), ""));
  ASSERT_NO_THROW(scheduler.createTapePool(requester, "TapePool", 1, ""));
  cta::MountCriteria immediateMount;
  immediateMount.maxAge = 0;
  immediateMount.maxBytesQueued = 1;
  immediateMount.maxFilesQueued = 1;
  immediateMount.quota = 10;
  ASSERT_NO_THROW(scheduler.setTapePoolMountCriteria("TapePool", cta::MountCriteriaByDirection(immediateMount, immediateMount)));                   
  ASSERT_NO_THROW(scheduler.createLogicalLibrary(requester, "T10KD6", ""));
  ASSERT_NO_THROW(scheduler.createTape(requester, "V12345", "T10KD6", "TapePool", 10*1000*1000, "8000GC", ""));
  
  // 5) Prepare files for reading by writing them to the mock system
  {
    // Label the tape
    castor::tape::tapeFile::LabelSession ls(*mockSys.fake.m_pathToDrive["/dev/nst0"], 
        "V12345");
    mockSys.fake.m_pathToDrive["/dev/nst0"]->rewind();
    // And write to it
    castor::tape::tapeserver::daemon::VolumeInfo volInfo;
    volInfo.vid="V12345";
    castor::tape::tapeFile::WriteSession ws(*mockSys.fake.m_pathToDrive["/dev/nst0"],
       volInfo , 0, true);

    // Write a few files on the virtual tape and modify the archive name space
    // so that it is in sync
    uint8_t data[1000];
    castor::tape::SCSI::Structures::zeroStruct(&data);
    int fseq=1;
    {
      // Create a path to a remote destination file
      std::ostringstream remoteFilePath;
      remoteFilePath << "file://" << m_tmpDir << "/test" << fseq;
      remoteFilePaths.push_back(remoteFilePath.str());

      // Create an archive file entry in the archive namespace
      std::ostringstream archiveFilePath;
      archiveFilePath << "/test" << fseq;
      const mode_t archiveFileMode = 0655;
      const uint64_t archiveFileSize = 1000;
      ASSERT_NO_THROW(ns.createFile(
        requester,
        archiveFilePath.str(),
        archiveFileMode,
        archiveFileSize));

      // Write the file to tape
548
549
550
551
552
      cta::MockNameServer mns;
      cta::MockArchiveMount mam(mns);
      cta::MockRetrieveMount mrm;
      std::unique_ptr<cta::RetrieveJob> ftr(new cta::MockRetrieveJob(mrm));
      std::unique_ptr<cta::ArchiveJob> ftm_temp(new cta::MockArchiveJob(mam, mns));
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
      ftr->nameServerTapeFile.tapeFileLocation.fSeq = fseq;
      ftm_temp->nameServerTapeFile.tapeFileLocation.fSeq = fseq;
      ftr->archiveFile.fileId = 1000 + fseq;
      ftm_temp->archiveFile.fileId = 1000 + fseq;
      castor::tape::tapeFile::WriteFile wf(&ws, *ftm_temp, archiveFileSize);
      ftr->nameServerTapeFile.tapeFileLocation.blockId = wf.getBlockId();
      ftr->remotePath = remoteFilePath.str();
      // Write the data (one block)
      wf.write(data, sizeof(data));
      // Close the file
      wf.close();

      // Create tape file entry in the archive namespace that is beyond the end
      // of data
      cta::NameServerTapeFile tapeFile;
      tapeFile.copyNb = 1;
      tapeFile.tapeFileLocation.fSeq = fseq + 1000;
      tapeFile.tapeFileLocation.blockId = wf.getBlockId();
      tapeFile.tapeFileLocation.vid = volInfo.vid;
      tapeFile.tapeFileLocation.copyNb = 1;
      tapeFile.size = archiveFileSize;
      tapeFile.compressedSize = archiveFileSize; // No compression
      cta::Checksum tapeFileChecksum(cta::Checksum::CHECKSUMTYPE_ADLER32,
        cta::ByteArray(cta::Utils::getAdler32(data, sizeof data)));
      tapeFile.checksum = tapeFileChecksum;
      ASSERT_NO_THROW(ns.addTapeFile(
        requester,
        archiveFilePath.str(),
        tapeFile));

      // Schedule the retrieval of the file
      std::list<std::string> archiveFilePaths;
      archiveFilePaths.push_back(archiveFilePath.str());
      ASSERT_NO_THROW(scheduler.queueRetrieveRequest(
        requester,
        archiveFilePaths,
        remoteFilePath.str()));
    }
  }
  
  DriveConfig driveConfig("T10D6116", "T10KD6", "/dev/noSuchDrive", "manual");
594
595
596
  DataTransferConfig castorConf;
  castorConf.bufsz = 1024;
  castorConf.nbBufs = 10;
597
598
599
600
  castor::messages::AcsProxyDummy acs;
  castor::mediachanger::MmcProxyDummy mmc;
  castor::legacymsg::RmcProxyDummy rmc;
  castor::mediachanger::MediaChangerFacade mc(acs, mmc, rmc);
601
  castor::messages::TapeserverProxyDummy initialProcess;
602
  castor::server::ProcessCapDummy capUtils;
603
  DataTransferSession sess("tapeHost", logger, mockSys,
604
    driveConfig, mc, initialProcess, capUtils, castorConf, scheduler);
605
  ASSERT_NO_THROW(sess.execute());
606
  std::string temp = logger.getLog();
607
  ASSERT_NE(std::string::npos, logger.getLog().find("Could not stat path: /dev/noSuchDrive"));
608
609
}

610
TEST_F(castor_tape_tapeserver_daemon_DataTransferSessionTest, DataTransferSessionFailtoMount) {
611
612
  
  // 0) Prepare the logger for everyone
613
614
  castor::log::StringLogger logger("tapeServerUnitTest");
  
615
  // 1) prepare the fake scheduler
616
  std::string vid = "V12345";
617
  // cta::MountType::Enum mountType = cta::MountType::RETRIEVE;
618
  std::string density = "8000GC";
619

620
621
622
623
624
  // 3) Prepare the necessary environment (logger, plus system wrapper), 
  castor::tape::System::mockWrapper mockSys;
  mockSys.delegateToFake();
  mockSys.disableGMockCallsCounting();
  mockSys.fake.setupForVirtualDriveSLC6();
625
626
627
628
629
630
631
632
  //delete is unnecessary
  //pointer with ownership will be passed to the application,
  //which will do the delete 
  mockSys.fake.m_pathToDrive["/dev/nst0"] = new castor::tape::tapeserver::drive::FakeDrive;

  // 4) Create the scheduler
  cta::MockNameServer ns;
  cta::MockRemoteNS rns;
633
  cta::OStoreDBWrapper<cta::objectstore::BackendVFS> db("Unittest");
634
635
636
637
638
639
640
641
  cta::Scheduler scheduler(ns, db, rns);

  // Always use the same requester
  const cta::SecurityIdentity requester;
  
  // List to remember the path of each remote file so that the existance of the
  // files can be tested for at the end of the test
  std::list<std::string> remoteFilePaths;
642
643
644
645
646
647
648
649
650
651
652
653
654
655
  
  // 5) Create the tapepool, library and tape for the scheduler.
  // Make mounts immediate.
  ASSERT_NO_THROW(scheduler.createAdminUserWithoutAuthorizingRequester(requester, requester.getUser(), ""));
  ASSERT_NO_THROW(scheduler.createAdminHostWithoutAuthorizingRequester(requester, requester.getHost(), ""));
  ASSERT_NO_THROW(scheduler.createTapePool(requester, "TapePool", 1, ""));
  cta::MountCriteria immediateMount;
  immediateMount.maxAge = 0;
  immediateMount.maxBytesQueued = 1;
  immediateMount.maxFilesQueued = 1;
  immediateMount.quota = 10;
  ASSERT_NO_THROW(scheduler.setTapePoolMountCriteria("TapePool", cta::MountCriteriaByDirection(immediateMount, immediateMount)));                   
  ASSERT_NO_THROW(scheduler.createLogicalLibrary(requester, "T10KD6", ""));
  ASSERT_NO_THROW(scheduler.createTape(requester, "V12345", "T10KD6", "TapePool", 10*1000*1000, "8000GC", ""));
656
657
658
659
660
661
662
663
664

  //delete is unnecessary
  //pointer with ownership will be passed to the application,
  //which will do the delete 
  const bool failOnMount=true;
  mockSys.fake.m_pathToDrive["/dev/nst0"] = new castor::tape::tapeserver::drive::FakeDrive(failOnMount);
  
  // We can prepare files for reading on the drive
  {
665
    
666
667
    // Label the tape
    castor::tape::tapeFile::LabelSession ls(*mockSys.fake.m_pathToDrive["/dev/nst0"], 
668
        "V12345");
669
670
    mockSys.fake.m_pathToDrive["/dev/nst0"]->rewind();
    // And write to it
671
    castor::tape::tapeserver::daemon::VolumeInfo volInfo;
672
    volInfo.vid="V12345";
673
674
675
676
677
678
679
    castor::tape::tapeFile::WriteSession ws(*mockSys.fake.m_pathToDrive["/dev/nst0"],
       volInfo , 0, true);

    // Write a few files on the virtual tape and modify the archive name space
    // so that it is in sync
    uint8_t data[1000];
    castor::tape::SCSI::Structures::zeroStruct(&data);
680
    for (int fseq=1; fseq <= 10 ; fseq ++) {
681
682
      // Create a path to a remote destination file
      std::ostringstream remoteFilePath;
683
      remoteFilePath << "file://" << m_tmpDir << "/test" << fseq;
684
685
      remoteFilePaths.push_back(remoteFilePath.str());

686
      // Create an archive file entry in the archive namespace
687
688
689
      std::ostringstream archiveFilePath;
      archiveFilePath << "/test" << fseq;
      const mode_t archiveFileMode = 0655;
690
      const uint64_t archiveFileSize = 1000;
691
      ASSERT_NO_THROW(ns.createFile(
692
693
694
        requester,
        archiveFilePath.str(),
        archiveFileMode,
695
        archiveFileSize));
696
697

      // Write the file to tape
698
699
700
701
702
      cta::MockNameServer  mns;
      cta::MockArchiveMount mam(mns);
      cta::MockRetrieveMount mrm;
      std::unique_ptr<cta::RetrieveJob> ftr(new cta::MockRetrieveJob(mrm));
      std::unique_ptr<cta::ArchiveJob> ftm_temp(new cta::MockArchiveJob(mam, mns));
703
      ftr->nameServerTapeFile.tapeFileLocation.fSeq = fseq;
704
      ftm_temp->nameServerTapeFile.tapeFileLocation.fSeq = fseq;
705
      ftr->archiveFile.fileId = 1000 + fseq;
706
707
      ftm_temp->archiveFile.fileId = 1000 + fseq;
      castor::tape::tapeFile::WriteFile wf(&ws, *ftm_temp, archiveFileSize);
708
709
      ftr->nameServerTapeFile.tapeFileLocation.blockId = wf.getPosition();
      ftr->remotePath = remoteFilePath.str();
710
711
712
713
714
      // Write the data (one block)
      wf.write(data, sizeof(data));
      // Close the file
      wf.close();

715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
      // Create tape file entry in the archive namespace
      cta::NameServerTapeFile tapeFile;
      tapeFile.copyNb = 1;
      tapeFile.tapeFileLocation.fSeq = fseq;
      tapeFile.tapeFileLocation.blockId = wf.getPosition();
      tapeFile.tapeFileLocation.vid = volInfo.vid;
      tapeFile.tapeFileLocation.copyNb = 1;
      tapeFile.size = archiveFileSize;
      tapeFile.compressedSize = archiveFileSize; // No compression
      cta::Checksum tapeFileChecksum(cta::Checksum::CHECKSUMTYPE_ADLER32,
        cta::ByteArray(cta::Utils::getAdler32(data, sizeof data)));
      tapeFile.checksum = tapeFileChecksum;
      ASSERT_NO_THROW(ns.addTapeFile(
        requester,
        archiveFilePath.str(),
        tapeFile));

732
733
734
      // Schedule the retrieval of the file
      std::list<std::string> archiveFilePaths;
      archiveFilePaths.push_back(archiveFilePath.str());
735
      ASSERT_NO_THROW(scheduler.queueRetrieveRequest(
736
737
        requester,
        archiveFilePaths,
738
        remoteFilePath.str()));
739
740
    }
  }
741
  DriveConfig driveConfig("T10D6116", "T10KD6", "/dev/tape_T10D6116", "manual");
742
743
744
745
746
747
748
749
750
751
752
753
  DataTransferConfig castorConf;
  castorConf.bufsz = 1024*1024; // 1 MB memory buffers
  castorConf.nbBufs = 10;
  castorConf.bulkRequestRecallMaxBytes = UINT64_C(100)*1000*1000*1000;
  castorConf.bulkRequestRecallMaxFiles = 1000;
  castorConf.nbDiskThreads = 3;
  castor::messages::AcsProxyDummy acs;
  castor::mediachanger::MmcProxyDummy mmc;
  castor::legacymsg::RmcProxyDummy rmc;
  castor::mediachanger::MediaChangerFacade mc(acs, mmc, rmc);
  castor::server::ProcessCap capUtils;
  castor::messages::TapeserverProxyDummy initialProcess;
754
  DataTransferSession sess("tapeHost", logger, mockSys,
755
    driveConfig, mc, initialProcess, capUtils, castorConf, scheduler);
756
  ASSERT_NO_THROW(sess.execute());
757
  std::string temp = logger.getLog();
758
  ASSERT_NE(std::string::npos, logger.getLog().find("Failed to mount the tape"));
759
760
}

761
TEST_F(castor_tape_tapeserver_daemon_DataTransferSessionTest, DataTransferSessionEmptyOnVolReq) {
762
763
  
  // 0) Prepare the logger for everyone
764
765
  castor::log::StringLogger logger("tapeServerUnitTest");
  
766
  // 1) prepare the fake scheduler
767
  std::string vid = "V12345";
768
  // cta::MountType::Enum mountType = cta::MountType::RETRIEVE;
769
  std::string density = "8000GC";
770

771
772
773
774
775
  // 3) Prepare the necessary environment (logger, plus system wrapper), 
  castor::tape::System::mockWrapper mockSys;
  mockSys.delegateToFake();
  mockSys.disableGMockCallsCounting();
  mockSys.fake.setupForVirtualDriveSLC6();
776
  
777
778
779
  // The drive will not even be opened. so no need for one.
  mockSys.fake.m_pathToDrive["/dev/nst0"] = NULL;
  
780
781
782
  // 4) Create the scheduler
  cta::MockNameServer ns;
  cta::MockRemoteNS rns;
783
  cta::OStoreDBWrapper<cta::objectstore::BackendVFS> db("Unittest");
784
785
786
787
788
  cta::Scheduler scheduler(ns, db, rns);

  // Always use the same requester
  const cta::SecurityIdentity requester;
  
789
  DriveConfig driveConfig("T10D6116", "T10KD6", "/dev/tape_T10D6116", "manual");
790
791
792
793
794
795
796
797
798
799
800
801
  DataTransferConfig castorConf;
  castorConf.bufsz = 1024*1024; // 1 MB memory buffers
  castorConf.nbBufs = 10;
  castorConf.bulkRequestRecallMaxBytes = UINT64_C(100)*1000*1000*1000;
  castorConf.bulkRequestRecallMaxFiles = 1000;
  castorConf.nbDiskThreads = 3;
  castor::messages::AcsProxyDummy acs;
  castor::mediachanger::MmcProxyDummy mmc;
  castor::legacymsg::RmcProxyDummy rmc;
  castor::mediachanger::MediaChangerFacade mc(acs, mmc, rmc);
  castor::server::ProcessCap capUtils;
  castor::messages::TapeserverProxyDummy initialProcess;
802
  DataTransferSession sess("tapeHost", logger, mockSys,
803
    driveConfig, mc, initialProcess, capUtils, castorConf, scheduler);
804
  ASSERT_NO_THROW(sess.execute());
805
806
807
808
809
810
  std::string temp = logger.getLog();
  temp += "";
  ASSERT_EQ("", sess.getVid());
  // We should not have logged any error
  ASSERT_EQ(std::string::npos, logger.getLog().find("LVL=E"));
}
811

812
TEST_F(castor_tape_tapeserver_daemon_DataTransferSessionTest, DataTransferSessionGooddayMigration) {
813
  
Eric Cano's avatar
Eric Cano committed
814
815
816
  // 0) Prepare the logger for everyone
  castor::log::StringLogger logger("tapeServerUnitTest");
  
817
  // 1) prepare the fake scheduler
Eric Cano's avatar
Eric Cano committed
818
819
  std::string vid = "V12345";
  std::string density = "8000GC";
820

Eric Cano's avatar
Eric Cano committed
821
822
823
824
825
826
827
828
  // 3) Prepare the necessary environment (logger, plus system wrapper), 
  castor::tape::System::mockWrapper mockSys;
  mockSys.delegateToFake();
  mockSys.disableGMockCallsCounting();
  mockSys.fake.setupForVirtualDriveSLC6();
  //delete is unnecessary
  //pointer with ownership will be passed to the application,
  //which will do the delete 
829
  mockSys.fake.m_pathToDrive["/dev/nst0"] = new castor::tape::tapeserver::drive::FakeDrive;
830
831
832
833
834
835
836
837
838
839
840
841
842

  // 4) Create the scheduler
  cta::MockNameServer ns;
  cta::MockRemoteNS rns;
  cta::OStoreDBWrapper<cta::objectstore::BackendVFS> db("Unittest");
  cta::Scheduler scheduler(ns, db, rns);

  // Always use the same requester
  const cta::SecurityIdentity requester;
  
  // Create the bootstrap admin user and host
  ASSERT_NO_THROW(scheduler.createAdminUserWithoutAuthorizingRequester(requester, requester.getUser(), "admin user"));
  ASSERT_NO_THROW(scheduler.createAdminHostWithoutAuthorizingRequester(requester, requester.getHost(), "admin host"));
Eric Cano's avatar
Eric Cano committed
843
  
844
845
  // create a single copy storage class
  ASSERT_NO_THROW(scheduler.createStorageClass(requester, "SINGLE", 1, 1, "comment"));
Eric Cano's avatar
Eric Cano committed
846
  
847
848
849
850
  // assign it to the root directory
  ASSERT_NO_THROW(scheduler.setDirStorageClass(requester, "/", "SINGLE"));
  
  // create the logical library
851
  ASSERT_NO_THROW(scheduler.createLogicalLibrary(requester, "T10KD6", "the illogical library"));
852
853
854
855
  
  // create the tape pool
  ASSERT_NO_THROW(scheduler.createTapePool(requester, "swimmingpool", 2, "the swimming pool"));
  
856
857
858
859
860
861
862
  cta::MountCriteria immediateMount;
  immediateMount.maxAge = 0;
  immediateMount.maxBytesQueued = 1;
  immediateMount.maxFilesQueued = 1;
  immediateMount.quota = 10;
  ASSERT_NO_THROW(scheduler.setTapePoolMountCriteria("swimmingpool", cta::MountCriteriaByDirection(immediateMount, immediateMount)));
  
863
864
865
866
  // create the route
  ASSERT_NO_THROW(scheduler.createArchiveRoute(requester, "SINGLE", 1, "swimmingpool", "iArchive"));
  
  // create the tape
867
  std::string comment = "the magic tape";
868
  ASSERT_NO_THROW(scheduler.createTape(requester, "V12345", "T10KD6", "swimmingpool", 100000, "8000GC", comment));
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
  
  // List to remember the path of each remote file so that the existence of the
  // files can be tested for at the end of the test
  std::list<std::string> remoteFilePaths;

  //delete is unnecessary
  //pointer with ownership will be passed to the application,
  //which will do the delete
  mockSys.fake.m_pathToDrive["/dev/nst0"] = new castor::tape::tapeserver::drive::FakeDrive();
  
  // We can prepare files for writing on the drive
  {    
    // Label the tape
    castor::tape::tapeFile::LabelSession ls(*mockSys.fake.m_pathToDrive["/dev/nst0"], "V12345");
    mockSys.fake.m_pathToDrive["/dev/nst0"]->rewind();
    
    // schedule the archivals
    for(int fseq=1; fseq <= 10 ; fseq ++) {      
887
      // Create a path to a remote source file
888
      std::ostringstream remoteFilePath;
889
//      remoteFilePath << "file:" << "/test" << fseq;
890
891
892
893
894
895
896
897
898
899
900
901
902
      remoteFilePath << "file:" << "/test" << fseq;
      remoteFilePaths.push_back(remoteFilePath.str());
      
      // Create the entry in the remote namespace (same user id of the requester)
      cta::RemotePath rpath(remoteFilePath.str());
      cta::RemoteFileStatus rstatus(requester.getUser(), 0777, 1000);
      rns.createEntry(rpath, rstatus);

      // Schedule the archival of the file
      std::list<std::string> remoteFilePathList;
      remoteFilePathList.push_back(remoteFilePath.str());
      ASSERT_NO_THROW(scheduler.queueArchiveRequest(requester, remoteFilePathList, rpath.getAfterScheme()));
    }
Eric Cano's avatar
Eric Cano committed
903
  }
904
  DriveConfig driveConfig("T10D6116", "T10KD6", "/dev/tape_T10D6116", "manual");
905
906
907
  DataTransferConfig castorConf;
  castorConf.bufsz = 1024*1024; // 1 MB memory buffers
  castorConf.nbBufs = 10;
908
909
  castorConf.bulkRequestRecallMaxBytes = UINT64_C(100)*1000*1000*1000;
  castorConf.bulkRequestRecallMaxFiles = 1000;
910
  castorConf.nbDiskThreads = 1;
911
912
913
914
  castor::messages::AcsProxyDummy acs;
  castor::mediachanger::MmcProxyDummy mmc;
  castor::legacymsg::RmcProxyDummy rmc;
  castor::mediachanger::MediaChangerFacade mc(acs, mmc, rmc);
915
  castor::server::ProcessCap capUtils;
916
  castor::messages::TapeserverProxyDummy initialProcess;
917
  DataTransferSession sess("tapeHost", logger, mockSys, driveConfig, mc, initialProcess, capUtils, castorConf, scheduler);
918
  /*ASSERT_NO_THROW*/(sess.execute());
919
920
921
922
923
924
925
926
927
928
  std::string temp = logger.getLog();
  temp += "";
  ASSERT_EQ("V12345", sess.getVid());
  for(auto i=remoteFilePaths.begin(); i!=remoteFilePaths.end(); i++) {
    cta::RemotePath rpath(*i);
    ASSERT_NO_THROW(ns.statFile(requester, rpath.getAfterScheme()));
    std::unique_ptr<cta::ArchiveFileStatus> stat(ns.statFile(requester, rpath.getAfterScheme()));
    ASSERT_NE((uint64_t)(stat.get()), NULL);
    ASSERT_EQ(stat->mode, 0777);
    ASSERT_EQ(stat->size, 1000);
929
  }
Eric Cano's avatar
Eric Cano committed
930
931
}

932
933
934
935
//
// This test is the same as the previous one, except that the files are deleted
// from filesystem immediately. The disk tasks will then fail on open.
///
936
TEST_F(castor_tape_tapeserver_daemon_DataTransferSessionTest, DataTransferSessionMissingFilesMigration) {
937
  
938
939
940
  // 0) Prepare the logger for everyone
  castor::log::StringLogger logger("tapeServerUnitTest");
  
941
  // 1) prepare the fake scheduler
942
943
  std::string vid = "V12345";
  std::string density = "8000GC";
944

945
946
947
948
949
950
951
952
  // 3) Prepare the necessary environment (logger, plus system wrapper), 
  castor::tape::System::mockWrapper mockSys;
  mockSys.delegateToFake();
  mockSys.disableGMockCallsCounting();
  mockSys.fake.setupForVirtualDriveSLC6();
  //delete is unnecessary
  //pointer with ownership will be passed to the application,
  //which will do the delete 
953
  mockSys.fake.m_pathToDrive["/dev/nst0"] = new castor::tape::tapeserver::drive::FakeDrive;
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974

  // 4) Create the scheduler
  cta::MockNameServer ns;
  cta::MockRemoteNS rns;
  cta::OStoreDBWrapper<cta::objectstore::BackendVFS> db("Unittest");
  cta::Scheduler scheduler(ns, db, rns);

  // Always use the same requester
  const cta::SecurityIdentity requester;
  
  // Create the bootstrap admin user and host
  ASSERT_NO_THROW(scheduler.createAdminUserWithoutAuthorizingRequester(requester, requester.getUser(), "admin user"));
  ASSERT_NO_THROW(scheduler.createAdminHostWithoutAuthorizingRequester(requester, requester.getHost(), "admin host"));
  
  // create a single copy storage class
  ASSERT_NO_THROW(scheduler.createStorageClass(requester, "SINGLE", 1, 1, "comment"));
  
  // assign it to the root directory
  ASSERT_NO_THROW(scheduler.setDirStorageClass(requester, "/", "SINGLE"));
  
  // create the logical library
975
  ASSERT_NO_THROW(scheduler.createLogicalLibrary(requester, "T10KD6", "the illogical library"));
976
977
978
979
980
981
  
  // create the tape pool
  ASSERT_NO_THROW(scheduler.createTapePool(requester, "swimmingpool", 2, "the swimming pool"));
  
  // create the route
  ASSERT_NO_THROW(scheduler.createArchiveRoute(requester, "SINGLE", 1, "swimmingpool", "iArchive"));
982
  
983
  // create the tape
984
  std::string comment = "the magic tape";
985
  ASSERT_NO_THROW(scheduler.createTape(requester, "V12345", "T10KD6", "swimmingpool", 100000, "8000GC", comment));
986
  
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
  // List to remember the path of each remote file so that the existence of the
  // files can be tested for at the end of the test
  std::list<std::string> remoteFilePaths;

  //delete is unnecessary
  //pointer with ownership will be passed to the application,
  //which will do the delete
  mockSys.fake.m_pathToDrive["/dev/nst0"] = new castor::tape::tapeserver::drive::FakeDrive();
  
  // We can prepare files for writing on the drive
  {    
    // Label the tape
    castor::tape::tapeFile::LabelSession ls(*mockSys.fake.m_pathToDrive["/dev/nst0"], "V12345");
    mockSys.fake.m_pathToDrive["/dev/nst0"]->rewind();