DataTransferSessionTest.cpp 51.8 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
#include "common/exception/Exception.hpp"
44
#include "common/utils/Utils.hpp"
45
#include "scheduler/Scheduler.hpp"
46
#include "smc_struct.h"
47
48
#include "nameserver/mockNS/MockNameServer.hpp"
#include "remotens/MockRemoteNS.hpp"
49
#include "remotens/MockRemoteFullFS.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;
Eric Cano's avatar
Eric Cano committed
69
namespace unitTests {
70

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

  void SetUp() {
76
77
    strncpy(m_tmpDir, "/tmp/DataTransferSessionTestXXXXXX", sizeof(m_tmpDir));
    if(!mkdtemp(m_tmpDir)) {
78
      const std::string errMsg = cta::utils::errnoToString(errno);
79
80
81
82
83
84
85
86
87
88
      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)) {
89
      const std::string errMsg = cta::utils::errnoToString(errno);
90
91
92
93
94
95
96
97
      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
    // 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()) {
108
        const std::string errMsg = cta::utils::errnoToString(errno);
109
110
111
112
113
114
115
116
117
118
119
120
        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())) {
121
            const std::string errMsg = cta::utils::errnoToString(errno);
122
123
124
125
126
127
128
129
130
            std::ostringstream msg;
            msg << "Failed to unlink " << entryPath;
            throw cta::exception::Exception(msg.str());
          }
        }
      }

      // Delete the now empty directory
      if(rmdir(m_tmpDir)) {
131
        const std::string errMsg = cta::utils::errnoToString(errno);
132
133
134
135
136
        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
156
  // cta::MountType::Enum mountType = cta::MountType::RETRIEVE;

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

  // 4) Create the scheduler
  cta::MockNameServer ns;
  cta::MockRemoteNS rns;
170
  cta::OStoreDBWrapper<cta::objectstore::BackendVFS> db("Unittest");
171
172
173
174
175
176
177
178
  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;
179
  
180
181
182
183
184
185
186
187
188
189
190
191
  // 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", ""));
192
  ASSERT_NO_THROW(scheduler.createTape(requester, "V12345", "T10KD6", "TapePool", 10*1000*1000, ""));
193
  
194
  // 5) Prepare files for reading by writing them to the mock system
195
196
197
  {
    // Label the tape
    castor::tape::tapeFile::LabelSession ls(*mockSys.fake.m_pathToDrive["/dev/nst0"], 
198
        "V12345", false);
199
200
    mockSys.fake.m_pathToDrive["/dev/nst0"]->rewind();
    // And write to it
201
    castor::tape::tapeserver::daemon::VolumeInfo volInfo;
202
    volInfo.vid="V12345";
203
    castor::tape::tapeFile::WriteSession ws(*mockSys.fake.m_pathToDrive["/dev/nst0"],
204
       volInfo , 0, true);
205
206
207

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

216
      // Create an archive file entry in the archive namespace
217
218
219
220
      std::ostringstream archiveFilePath;
      archiveFilePath << "/test" << fseq;
      const mode_t archiveFileMode = 0655;
      const uint64_t archiveFileSize = 256*1024;
221
      ASSERT_NO_THROW(ns.createFile(
222
223
224
        requester,
        archiveFilePath.str(),
        archiveFileMode,
225
        cta::Checksum(cta::Checksum::CHECKSUMTYPE_ADLER32, cta::utils::getAdler32(data, sizeof data)),
226
        archiveFileSize));
227
      std::unique_ptr<cta::common::archiveNS::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
      tapeFile.tapeFileLocation.vid = volInfo.vid;
      tapeFile.tapeFileLocation.copyNb = 1;
      tapeFile.size = archiveFileSize;
      tapeFile.compressedSize = archiveFileSize; // No compression
256
      cta::Checksum tapeFileChecksum(cta::Checksum::CHECKSUMTYPE_ADLER32, cta::utils::getAdler32(data, sizeof data));
257
258
259
260
261
262
      tapeFile.checksum = tapeFileChecksum;
      ASSERT_NO_THROW(ns.addTapeFile(
        requester,
        archiveFilePath.str(),
        tapeFile));

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

  // 6) Create the data transfer session
274
  DriveConfig driveConfig("T10D6116", "T10KD6", "/dev/tape_T10D6116", "manual");
275
276
277
278
279
280
  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;
281
282
283
284
  castor::messages::AcsProxyDummy acs;
  castor::mediachanger::MmcProxyDummy mmc;
  castor::legacymsg::RmcProxyDummy rmc;
  castor::mediachanger::MediaChangerFacade mc(acs, mmc, rmc);
285
  castor::server::ProcessCap capUtils;
286
  castor::messages::TapeserverProxyDummy initialProcess;
287
  DataTransferSession sess("tapeHost", logger, mockSys,
288
    driveConfig, mc, initialProcess, capUtils, castorConf, scheduler);
289
290

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

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

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

307
TEST_F(castor_tape_tapeserver_daemon_DataTransferSessionTest, DataTransferSessionWrongRecall) {
308
309
310
  // 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.
311
312

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

319
320
321
322
323
324
325
326
  // 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 
327
  mockSys.fake.m_pathToDrive["/dev/nst0"] = new castor::tape::tapeserver::drive::FakeDrive;
328
329
330
331

  // 4) Create the scheduler
  cta::MockNameServer ns;
  cta::MockRemoteNS rns;
332
  cta::OStoreDBWrapper<cta::objectstore::BackendVFS> db("Unittest");
333
334
335
336
337
338
339
340
  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;
341
  
342
343
344
345
346
347
348
349
350
351
352
353
  // 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", ""));
354
  ASSERT_NO_THROW(scheduler.createTape(requester, "V12345", "T10KD6", "TapePool", 10*1000*1000, ""));
355
  
356
  // 5) Prepare files for reading by writing them to the mock system
357
358
359
  {
    // Label the tape
    castor::tape::tapeFile::LabelSession ls(*mockSys.fake.m_pathToDrive["/dev/nst0"], 
360
        "V12345", false);
361
362
    mockSys.fake.m_pathToDrive["/dev/nst0"]->rewind();
    // And write to it
363
    castor::tape::tapeserver::daemon::VolumeInfo volInfo;
364
365
366
    volInfo.vid="V12345";
    castor::tape::tapeFile::WriteSession ws(*mockSys.fake.m_pathToDrive["/dev/nst0"],
       volInfo , 0, true);
367
368
369

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

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

      // Write the file to tape
392
393
394
395
396
      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));
397
      ftr->nameServerTapeFile.tapeFileLocation.fSeq = fseq;
398
      ftm_temp->nameServerTapeFile.tapeFileLocation.fSeq = fseq;
399
400
      ftr->archiveFile.fileId = 1000 + fseq;
      ftm_temp->archiveFile.fileId = 1000 + fseq;
401
      castor::tape::tapeFile::WriteFile wf(&ws, *ftm_temp, archiveFileSize);
402
      ftr->nameServerTapeFile.tapeFileLocation.blockId = wf.getBlockId();
403
      ftr->remotePath = remoteFilePath.str();
404
405
406
407
      // Write the data (one block)
      wf.write(data, sizeof(data));
      // Close the file
      wf.close();
408

409
410
411
412
413
      // 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;
414
      tapeFile.tapeFileLocation.blockId = wf.getBlockId() + 10000;
415
416
417
418
      tapeFile.tapeFileLocation.vid = volInfo.vid;
      tapeFile.tapeFileLocation.copyNb = 1;
      tapeFile.size = archiveFileSize;
      tapeFile.compressedSize = archiveFileSize; // No compression
419
      cta::Checksum tapeFileChecksum(cta::Checksum::CHECKSUMTYPE_ADLER32, cta::utils::getAdler32(data, sizeof data));
420
421
422
423
424
425
      tapeFile.checksum = tapeFileChecksum;
      ASSERT_NO_THROW(ns.addTapeFile(
        requester,
        archiveFilePath.str(),
        tapeFile));

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

  // 6) Create the data transfer session
437
  DriveConfig driveConfig("T10D6116", "T10KD6", "/dev/tape_T10D6116", "manual");
438
439
440
441
442
443
  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;
444
445
446
447
  castor::messages::AcsProxyDummy acs;
  castor::mediachanger::MmcProxyDummy mmc;
  castor::legacymsg::RmcProxyDummy rmc;
  castor::mediachanger::MediaChangerFacade mc(acs, mmc, rmc);
448
449
  castor::server::ProcessCap capUtils;
  castor::messages::TapeserverProxyDummy initialProcess;
450
  DataTransferSession sess("tapeHost", logger, mockSys,
451
    driveConfig, mc, initialProcess, capUtils, castorConf, scheduler);
452
453
454
455
456

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

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

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

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

473
474
475
476
477
  // 3) Prepare the necessary environment (logger, plus system wrapper), 
  castor::tape::System::mockWrapper mockSys;
  mockSys.delegateToFake();
  mockSys.disableGMockCallsCounting();
  mockSys.fake.setupForVirtualDriveSLC6();
478
479
480
481
482
483
484
485
  //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;
486
  cta::OStoreDBWrapper<cta::objectstore::BackendVFS> db("Unittest");
487
488
489
490
491
  cta::Scheduler scheduler(ns, db, rns);

  // Always use the same requester
  const cta::SecurityIdentity requester;
  
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
  // 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", ""));
508
  ASSERT_NO_THROW(scheduler.createTape(requester, "V12345", "T10KD6", "TapePool", 10*1000*1000, ""));
509
510
511
512
513
  
  // 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"], 
514
        "V12345", false);
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
    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,
542
        cta::Checksum(cta::Checksum::CHECKSUMTYPE_ADLER32, cta::utils::getAdler32(data, sizeof data)),
543
544
545
        archiveFileSize));

      // Write the file to tape
546
547
548
549
550
      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));
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
      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
573
      cta::Checksum tapeFileChecksum(cta::Checksum::CHECKSUMTYPE_ADLER32, cta::utils::getAdler32(data, sizeof data));
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
      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");
591
592
593
  DataTransferConfig castorConf;
  castorConf.bufsz = 1024;
  castorConf.nbBufs = 10;
594
595
596
597
  castor::messages::AcsProxyDummy acs;
  castor::mediachanger::MmcProxyDummy mmc;
  castor::legacymsg::RmcProxyDummy rmc;
  castor::mediachanger::MediaChangerFacade mc(acs, mmc, rmc);
598
  castor::messages::TapeserverProxyDummy initialProcess;
599
  castor::server::ProcessCapDummy capUtils;
600
  DataTransferSession sess("tapeHost", logger, mockSys,
601
    driveConfig, mc, initialProcess, capUtils, castorConf, scheduler);
602
  ASSERT_NO_THROW(sess.execute());
603
  std::string temp = logger.getLog();
604
  ASSERT_NE(std::string::npos, logger.getLog().find("Could not stat path: /dev/noSuchDrive"));
605
606
}

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

616
617
618
619
620
  // 3) Prepare the necessary environment (logger, plus system wrapper), 
  castor::tape::System::mockWrapper mockSys;
  mockSys.delegateToFake();
  mockSys.disableGMockCallsCounting();
  mockSys.fake.setupForVirtualDriveSLC6();
621
622
623
624

  // 4) Create the scheduler
  cta::MockNameServer ns;
  cta::MockRemoteNS rns;
625
  cta::OStoreDBWrapper<cta::objectstore::BackendVFS> db("Unittest");
626
627
628
629
630
631
632
633
  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;
634
635
636
637
638
639
640
641
642
643
644
645
646
  
  // 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", ""));
647
  ASSERT_NO_THROW(scheduler.createTape(requester, "V12345", "T10KD6", "TapePool", 10*1000*1000, ""));
648
649
650
651
652
653
654
655
656

  //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
  {
657
    
658
659
    // Label the tape
    castor::tape::tapeFile::LabelSession ls(*mockSys.fake.m_pathToDrive["/dev/nst0"], 
660
        "V12345");
661
662
    mockSys.fake.m_pathToDrive["/dev/nst0"]->rewind();
    // And write to it
663
    castor::tape::tapeserver::daemon::VolumeInfo volInfo;
664
    volInfo.vid="V12345";
665
666
667
668
669
670
671
    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);
672
    for (int fseq=1; fseq <= 10 ; fseq ++) {
673
674
      // Create a path to a remote destination file
      std::ostringstream remoteFilePath;
675
      remoteFilePath << "file://" << m_tmpDir << "/test" << fseq;
676
677
      remoteFilePaths.push_back(remoteFilePath.str());

678
      // Create an archive file entry in the archive namespace
679
680
681
      std::ostringstream archiveFilePath;
      archiveFilePath << "/test" << fseq;
      const mode_t archiveFileMode = 0655;
682
      const uint64_t archiveFileSize = 1000;
683
      ASSERT_NO_THROW(ns.createFile(
684
685
686
        requester,
        archiveFilePath.str(),
        archiveFileMode,
687
        cta::Checksum(),
688
        archiveFileSize));
689
690

      // Write the file to tape
691
692
693
694
695
      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));
696
      ftr->nameServerTapeFile.tapeFileLocation.fSeq = fseq;
697
      ftm_temp->nameServerTapeFile.tapeFileLocation.fSeq = fseq;
698
      ftr->archiveFile.fileId = 1000 + fseq;
699
700
      ftm_temp->archiveFile.fileId = 1000 + fseq;
      castor::tape::tapeFile::WriteFile wf(&ws, *ftm_temp, archiveFileSize);
701
702
      ftr->nameServerTapeFile.tapeFileLocation.blockId = wf.getPosition();
      ftr->remotePath = remoteFilePath.str();
703
704
705
706
707
      // Write the data (one block)
      wf.write(data, sizeof(data));
      // Close the file
      wf.close();

708
709
710
711
712
713
714
715
716
      // 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
717
      cta::Checksum tapeFileChecksum(cta::Checksum::CHECKSUMTYPE_ADLER32, cta::utils::getAdler32(data, sizeof data));
718
719
720
721
722
723
      tapeFile.checksum = tapeFileChecksum;
      ASSERT_NO_THROW(ns.addTapeFile(
        requester,
        archiveFilePath.str(),
        tapeFile));

724
725
726
      // Schedule the retrieval of the file
      std::list<std::string> archiveFilePaths;
      archiveFilePaths.push_back(archiveFilePath.str());
727
      ASSERT_NO_THROW(scheduler.queueRetrieveRequest(
728
729
        requester,
        archiveFilePaths,
730
        remoteFilePath.str()));
731
732
    }
  }
733
  DriveConfig driveConfig("T10D6116", "T10KD6", "/dev/tape_T10D6116", "manual");
734
735
736
737
738
739
740
741
742
743
744
745
  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;
746
  DataTransferSession sess("tapeHost", logger, mockSys,
747
    driveConfig, mc, initialProcess, capUtils, castorConf, scheduler);
748
  ASSERT_NO_THROW(sess.execute());
749
  std::string temp = logger.getLog();
750
  ASSERT_NE(std::string::npos, logger.getLog().find("Failed to mount the tape"));
751
752
}

753
TEST_F(castor_tape_tapeserver_daemon_DataTransferSessionTest, DataTransferSessionEmptyOnVolReq) {
754
755
  
  // 0) Prepare the logger for everyone
756
757
  castor::log::StringLogger logger("tapeServerUnitTest");
  
758
  // 1) prepare the fake scheduler
759
  std::string vid = "V12345";
760
761
  // cta::MountType::Enum mountType = cta::MountType::RETRIEVE;

762
763
764
765
766
  // 3) Prepare the necessary environment (logger, plus system wrapper), 
  castor::tape::System::mockWrapper mockSys;
  mockSys.delegateToFake();
  mockSys.disableGMockCallsCounting();
  mockSys.fake.setupForVirtualDriveSLC6();
767
  
768
769
770
  // The drive will not even be opened. so no need for one.
  mockSys.fake.m_pathToDrive["/dev/nst0"] = NULL;
  
771
772
773
  // 4) Create the scheduler
  cta::MockNameServer ns;
  cta::MockRemoteNS rns;
774
  cta::OStoreDBWrapper<cta::objectstore::BackendVFS> db("Unittest");
775
776
777
778
779
  cta::Scheduler scheduler(ns, db, rns);

  // Always use the same requester
  const cta::SecurityIdentity requester;
  
780
  DriveConfig driveConfig("T10D6116", "T10KD6", "/dev/tape_T10D6116", "manual");
781
782
783
784
785
786
787
788
789
790
791
792
  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;
793
  DataTransferSession sess("tapeHost", logger, mockSys,
794
    driveConfig, mc, initialProcess, capUtils, castorConf, scheduler);
795
  ASSERT_NO_THROW(sess.execute());
796
797
798
799
800
801
  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"));
}
802

803
TEST_F(castor_tape_tapeserver_daemon_DataTransferSessionTest, DataTransferSessionGooddayMigration) {
804
  
Eric Cano's avatar
Eric Cano committed
805
806
807
  // 0) Prepare the logger for everyone
  castor::log::StringLogger logger("tapeServerUnitTest");
  
808
  // 1) prepare the fake scheduler
Eric Cano's avatar
Eric Cano committed
809
  std::string vid = "V12345";
810

Eric Cano's avatar
Eric Cano committed
811
812
813
814
815
  // 3) Prepare the necessary environment (logger, plus system wrapper), 
  castor::tape::System::mockWrapper mockSys;
  mockSys.delegateToFake();
  mockSys.disableGMockCallsCounting();
  mockSys.fake.setupForVirtualDriveSLC6();
816
817
818

  // 4) Create the scheduler
  cta::MockNameServer ns;
819
  cta::MockRemoteFullFS rns;
820
821
822
823
824
825
826
827
828
  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
829
  
830
831
  // create a single copy storage class
  ASSERT_NO_THROW(scheduler.createStorageClass(requester, "SINGLE", 1, 1, "comment"));
Eric Cano's avatar
Eric Cano committed
832
  
833
834
835
836
  // assign it to the root directory
  ASSERT_NO_THROW(scheduler.setDirStorageClass(requester, "/", "SINGLE"));
  
  // create the logical library
837
  ASSERT_NO_THROW(scheduler.createLogicalLibrary(requester, "T10KD6", "the illogical library"));
838
839
840
841
  
  // create the tape pool
  ASSERT_NO_THROW(scheduler.createTapePool(requester, "swimmingpool", 2, "the swimming pool"));
  
842
843
844
845
846
847
848
  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)));
  
849
850
851
852
  // create the route
  ASSERT_NO_THROW(scheduler.createArchiveRoute(requester, "SINGLE", 1, "swimmingpool", "iArchive"));
  
  // create the tape
853
  std::string comment = "the magic tape";
854
  ASSERT_NO_THROW(scheduler.createTape(requester, "V12345", "T10KD6", "swimmingpool", 100000, comment));
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
  
  // 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
872
    for(int fseq=1; fseq <= 10 ; fseq ++) { 
873
      // Create a path to a remote source file
874
875
876
      std::ostringstream fileName;
      fileName << "/test" << fseq;
      remoteFilePaths.push_back(fileName.str());
877
      
878
879
880
      // Create the file to be migrated in the fake remote NS
      cta::RemotePath rpath(rns.createFullURL(fileName.str()));
      rns.createFile(rpath.getRaw(), 1000);
881
882
883

      // Schedule the archival of the file
      std::list<std::string> remoteFilePathList;
884
885
      remoteFilePathList.push_back(rns.createFullURL(fileName.str()));
      ASSERT_NO_THROW(scheduler.queueArchiveRequest(requester, remoteFilePathList, fileName.str()));
886
    }
Eric Cano's avatar
Eric Cano committed
887
  }
888
  DriveConfig driveConfig("T10D6116", "T10KD6", "/dev/tape_T10D6116", "manual");
889
890
891
  DataTransferConfig castorConf;
  castorConf.bufsz = 1024*1024; // 1 MB memory buffers
  castorConf.nbBufs = 10;
892
893
  castorConf.bulkRequestRecallMaxBytes = UINT64_C(100)*1000*1000*1000;
  castorConf.bulkRequestRecallMaxFiles = 1000;
894
  castorConf.nbDiskThreads = 1;
895
896
897
898
  castor::messages::AcsProxyDummy acs;
  castor::mediachanger::MmcProxyDummy mmc;
  castor::legacymsg::RmcProxyDummy rmc;
  castor::mediachanger::MediaChangerFacade mc(acs, mmc, rmc);
899
  castor::server::ProcessCap capUtils;
900
  castor::messages::TapeserverProxyDummy initialProcess;
901
  DataTransferSession sess("tapeHost", logger, mockSys, driveConfig, mc, initialProcess, capUtils, castorConf, scheduler);
902
  ASSERT_NO_THROW(sess.execute());
903
904
905
906
  std::string temp = logger.getLog();
  temp += "";
  ASSERT_EQ("V12345", sess.getVid());
  for(auto i=remoteFilePaths.begin(); i!=remoteFilePaths.end(); i++) {
907
    ASSERT_NO_THROW(ns.statFile(requester, *i));
908
    std::unique_ptr<cta::common::archiveNS::ArchiveFileStatus> stat(ns.statFile(requester, *i));
909
910
911
    ASSERT_NE(NULL, (uint64_t)(stat.get()));
    ASSERT_EQ(0100777, stat->mode);
    ASSERT_EQ(1000, stat->size);
912
  }
Eric Cano's avatar
Eric Cano committed
913
914
}

915
916
917
918
//
// 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.
///
919
TEST_F(castor_tape_tapeserver_daemon_DataTransferSessionTest, DataTransferSessionMissingFilesMigration) {
920
  
921
922
923
  // 0) Prepare the logger for everyone
  castor::log::StringLogger logger("tapeServerUnitTest");
  
924
  // 1) prepare the fake scheduler
925
  std::string vid = "V12345";
926

927
928
929
930
931
  // 3) Prepare the necessary environment (logger, plus system wrapper), 
  castor::tape::System::mockWrapper mockSys;
  mockSys.delegateToFake();
  mockSys.disableGMockCallsCounting();
  mockSys.fake.setupForVirtualDriveSLC6();
932
933
934

  // 4) Create the scheduler
  cta::MockNameServer ns;
935
  cta::MockRemoteFullFS rns;
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
  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
953
  ASSERT_NO_THROW(scheduler.createLogicalLibrary(requester, "T10KD6", "the illogical library"));
954
955
956
  
  // create the tape pool
  ASSERT_NO_THROW(scheduler.createTapePool(requester, "swimmingpool", 2, "the swimming pool"));
957
958
959
960
961
962
963
964

  // Make the pool mount immediately
  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)));
965
966
967
  
  // create the route
  ASSERT_NO_THROW(scheduler.createArchiveRoute(requester, "SINGLE", 1, "swimmingpool", "iArchive"));
968
  
969
  // create the tape
970
  std::string comment = "the magic tape";
971
  ASSERT_NO_THROW(scheduler.createTape(requester, "V12345", "T10KD6", "swimmingpool", 100000, comment));
972
  
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
  // 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 ++) {      
      // Create a path to a remote destination file
991
992
993
      std::ostringstream fileName;
      fileName << "/test" << fseq;
      remoteFilePaths.push_back(fileName.str());
994
      
995
996
997
998
      // create the file in the remote file system (to be deleted after queueing
      // the request)
      cta::RemotePath rpath(rns.createFullURL(fileName.str()));
      rns.createFile(rpath.getRaw(), 1000);
999
1000
1001

      // Schedule the archival of the file
      std::list<std::string> remoteFilePathList;
1002
1003
1004
1005
1006
      remoteFilePathList.push_back(rns.createFullURL(fileName.str()));
      ASSERT_NO_THROW(scheduler.queueArchiveRequest(requester, remoteFilePathList, fileName.str()));
      
      // Delete the file
      rns.deleteFile(rpath.getRaw());
1007
    }
1008
  }
1009
  DriveConfig driveConfig("T10D6116", "T10KD6", "/dev/tape_T10D6116", "manual");
1010
1011
1012
  DataTransferConfig castorConf;
  castorConf.bufsz = 1024*1024; // 1 MB memory buffers
  castorConf.nbBufs = 10;
1013
1014
  castorConf.bulkRequestRecallMaxBytes = UINT64_C(100)*1000*1000*1000;
  castorConf.bulkRequestRecallMaxFiles = 1000;
1015
  castorConf.nbDiskThreads = 1;