DataTransferSessionTest.cpp 32.6 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 "Ctape.h"
44
#include "scheduler/Scheduler.hpp"
45
#include "smc_struct.h"
46
47
48
#include "nameserver/mockNS/MockNameServer.hpp"
#include "remotens/MockRemoteNS.hpp"
#include "scheduler/mockDB/MockSchedulerDatabase.hpp"
49
#include "scheduler/MountType.hpp"
50
51

#include <fcntl.h>
Eric Cano's avatar
Eric Cano committed
52
53
54
#include <sys/mman.h>
#include <sys/types.h>
#include <sys/stat.h>
55
56
#include <unistd.h>
#include <zlib.h>
Eric Cano's avatar
Eric Cano committed
57

58

59
using namespace castor::tape::tapeserver;
60
using namespace castor::tape::tapeserver::daemon;
61
62
namespace unitTest {

63
64
65
66
67
68
69
class tapeServer: public ::testing::Test {
protected:

  void SetUp() {
  }

  void TearDown() {
70
  }
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91

  class MockArchiveJob: public cta::ArchiveJob {
  public:
    MockArchiveJob() {
    } 
      
    ~MockArchiveJob() throw() {
    } 
  };

  class MockRetrieveJob: public cta::RetrieveJob {
  public:
    MockRetrieveJob() {
    } 
      
    ~MockRetrieveJob() throw() {
    } 
  };

  std::list<std::unique_ptr<cta::RetrieveJob>> m_retrieveJobs;

92
93
};

94
TEST_F(tapeServer, DataTransferSessionGooddayRecall) {
95
96
97
98
  // TpcpClients only supports 32 bits session number
  // This number has to be less than 2^31 as in addition there is a mix
  // of signed and unsigned numbers
  // As the current ids in prod are ~30M, we are far from overflow (Feb 2013)
Eric Cano's avatar
Eric Cano committed
99
100
101
  // 0) Prepare the logger for everyone
  castor::log::StringLogger logger("tapeServerUnitTest");
  
102
  // 1) prepare the fake scheduler
103
  std::string vid = "V12345";
104
  // cta::MountType::Enum mountType = cta::MountType::RETRIEVE;
105
  std::string density = "8000GC";
106

107
108
109
  // 3) Prepare the necessary environment (logger, plus system wrapper), 
  // construct and run the session.
  castor::tape::System::mockWrapper mockSys;
110
111
  mockSys.delegateToFake();
  mockSys.disableGMockCallsCounting();
112
  mockSys.fake.setupForVirtualDriveSLC6();
113
114
115
116

  //delete is unnecessary
  //pointer with ownership will be passed to the application,
  //which will do the delete 
117
  mockSys.fake.m_pathToDrive["/dev/nst0"] = new castor::tape::tapeserver::drive::FakeDrive;
118
  
119
120
121
122
  // We can prepare files for reading on the drive
  {
    // Label the tape
    castor::tape::tapeFile::LabelSession ls(*mockSys.fake.m_pathToDrive["/dev/nst0"], 
123
        "V12345");
124
125
    mockSys.fake.m_pathToDrive["/dev/nst0"]->rewind();
    // And write to it
126
    castor::tape::tapeserver::daemon::VolumeInfo volInfo;
127
    volInfo.vid="V12345";
128
    castor::tape::tapeFile::WriteSession ws(*mockSys.fake.m_pathToDrive["/dev/nst0"],
129
       volInfo , 0, true);
130
131
132
133
134
    // Write a few files on the virtual tape
    // Prepare the data
    uint8_t data[1000];
    castor::tape::SCSI::Structures::zeroStruct(&data);
    for (int fseq=1; fseq <= 10 ; fseq ++) {
135
136
137
138
139
140
141
142
      std::unique_ptr<cta::RetrieveJob> ftr(new MockRetrieveJob());
      std::unique_ptr<cta::ArchiveJob> ftm_temp(new MockArchiveJob());
      ftr->tapeFileLocation.fSeq = fseq;
      ftm_temp->tapeFileLocation.fSeq = fseq;
      ftr->archiveFile.fileId = 1000 + fseq;
      ftm_temp->archiveFile.fileId = 1000 + fseq;
      castor::tape::tapeFile::WriteFile wf(&ws, *ftm_temp, 256*1024);
      ftr->tapeFileLocation.blockId = wf.getPosition();
Eric Cano's avatar
Eric Cano committed
143
      // Set the recall destination (/dev/null)
144
      ftr->archiveFile.path = "/dev/null";
145
146
147
148
149
      // Write the data (one block)
      wf.write(data, sizeof(data));
      // Close the file
      wf.close();
      // Record the file for recall
150
      // TODO sim.addFileToRecall(ftr, sizeof(data));
151
152
    }
  }
153
  DriveConfig driveConfig("T10D6116", "T10KD6", "/dev/tape_T10D6116", "manual");
154
155
156
157
158
159
  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;
160
161
162
163
  castor::messages::AcsProxyDummy acs;
  castor::mediachanger::MmcProxyDummy mmc;
  castor::legacymsg::RmcProxyDummy rmc;
  castor::mediachanger::MediaChangerFacade mc(acs, mmc, rmc);
164
  castor::server::ProcessCap capUtils;
165
  castor::messages::TapeserverProxyDummy initialProcess;
166
167
168
169
  cta::MockNameServer ns;
  cta::MockRemoteNS rns;
  cta::MockSchedulerDatabase db;
  cta::Scheduler scheduler(ns, db, rns);
170
  DataTransferSession sess("tapeHost", logger, mockSys,
171
    driveConfig, mc, initialProcess, capUtils, castorConf, scheduler);
172
  ASSERT_NO_THROW(sess.execute());
Eric Cano's avatar
Eric Cano committed
173
174
  std::string temp = logger.getLog();
  temp += "";
175
  ASSERT_EQ("V12345", sess.getVid());
176
177
// TODO  ASSERT(The state of the session is NOT error);
// ASSERT_EQ(0, sim.m_sessionErrorCode);
178
}
179

180
181
/*
TEST_F(tapeServer, DataTransferSessionWrongRecall) {
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
  // 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.
  castor::log::StringLogger logger("tapeServerUnitTest");
  
  // 1) prepare the client and run it in another thread
  uint32_t volReq = 0xBEEF;
  std::string vid = "V12345";
  std::string density = "8000GC";
  client::ClientSimulator sim(volReq, vid, density,
    castor::tape::tapegateway::TAPE_GATEWAY,
    castor::tape::tapegateway::READ);
  client::ClientSimulator::ipPort clientAddr = sim.getCallbackAddress();
  clientRunner simRun(sim);
  simRun.start();
  
  // 3) Prepare the necessary environment (logger, plus system wrapper), 
  // construct and run the session.
  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 
208
  mockSys.fake.m_pathToDrive["/dev/nst0"] = new castor::tape::tapeserver::drive::FakeDrive;
209
210
211
212
213
  
  // We can prepare files for reading on the drive
  {
    // Label the tape
    castor::tape::tapeFile::LabelSession ls(*mockSys.fake.m_pathToDrive["/dev/nst0"], 
214
        "V12345");
215
216
217
218
219
220
221
222
223
224
225
    mockSys.fake.m_pathToDrive["/dev/nst0"]->rewind();
    // And write to it
    castor::tape::tapeserver::client::ClientInterface::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
    // Prepare the data
    uint8_t data[1000];
    castor::tape::SCSI::Structures::zeroStruct(&data);
    for (int fseq=1; fseq <= 10 ; fseq ++) {
226
227
228
229
230
231
232
233
      std::unique_ptr<cta::RetrieveJob> ftr(new MockRetrieveJob());
      std::unique_ptr<cta::ArchiveJob> ftm_temp(new MockArchiveJob());
      ftr->tapeFileLocation.fSeq = fseq;
      ftm_temp->tapeFileLocation.fSeq = fseq;
      ftr->archiveFile.fileId = 1000 + fseq;
      ftm_temp->archiveFile.fileId = 1000 + fseq;
      castor::tape::tapeFile::WriteFile wf(&ws, *ftm_temp, 256*1024);
      ftr->tapeFileLocation.blockId = wf.getPosition();
234
      // Set the recall destination (/dev/null)
235
      ftr->archiveFile.path = "/dev/null";
236
237
238
239
240
      // Write the data (one block)
      wf.write(data, sizeof(data));
      // Close the file
      wf.close();
      // Record the file for recall, with an out of tape fSeq
241
      ftr->setFseq(ftr->fseq() + 1000);
242
243
244
      sim.addFileToRecall(ftr, sizeof(data));
    }
  }
245
  DriveConfig driveConfig("T10D6116", "T10KD6", "/dev/tape_T10D6116", "manual");
246
247
248
249
250
251
  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;
252
253
254
255
  castor::messages::AcsProxyDummy acs;
  castor::mediachanger::MmcProxyDummy mmc;
  castor::legacymsg::RmcProxyDummy rmc;
  castor::mediachanger::MediaChangerFacade mc(acs, mmc, rmc);
256
257
  castor::server::ProcessCap capUtils;
  castor::messages::TapeserverProxyDummy initialProcess;
258
259
260
261
  cta::MockNameServer ns;
  cta::MockRemoteNS rns;
  cta::MockSchedulerDatabase db;
  cta::Scheduler scheduler(ns, db, rns);
262
  DataTransferSession sess("tapeHost", logger, mockSys,
263
    driveConfig, mc, initialProcess, capUtils, castorConf, scheduler);
264
265
266
267
268
  sess.execute();
  simRun.wait();
  std::string temp = logger.getLog();
  temp += "";
  ASSERT_EQ("V12345", sess.getVid());
269
  ASSERT_EQ(SEINTERNAL, sim.m_sessionErrorCode);
270
}
271

272
TEST_F(tapeServer, DataTransferSessionNoSuchDrive) {
273
274
275
276
277
278
279
280
  // TpcpClients only supports 32 bits session number
  // This number has to be less than 2^31 as in addition there is a mix
  // of signed and unsigned numbers
  // As the current ids in prod are ~30M, we are far from overflow (Feb 2013)
  // 1) prepare the client and run it in another thread
  uint32_t volReq = 0xBEEF;
  std::string vid = "V12345";
  std::string density = "8000GC";
281
282
  client::ClientSimulator sim(volReq, vid, density,
    castor::tape::tapegateway::READ_TP, castor::tape::tapegateway::READ);
283
  client::ClientSimulator::ipPort clientAddr = sim.getCallbackAddress();
284
285
286
287
288
289
290
291
292
293
  clientRunner simRun(sim);
  simRun.start();
  
  // 3) Prepare the necessary environment (logger, plus system wrapper), 
  // construct and run the session.
  castor::log::StringLogger logger("tapeServerUnitTest");
  castor::tape::System::mockWrapper mockSys;
  mockSys.delegateToFake();
  mockSys.disableGMockCallsCounting();
  mockSys.fake.setupForVirtualDriveSLC6();
294
  DriveConfig driveConfig("T10D6116", "T10KD6", "/dev/noSuchTape", "manual");
295
296
297
  DataTransferConfig castorConf;
  castorConf.bufsz = 1024;
  castorConf.nbBufs = 10;
298
299
300
301
  castor::messages::AcsProxyDummy acs;
  castor::mediachanger::MmcProxyDummy mmc;
  castor::legacymsg::RmcProxyDummy rmc;
  castor::mediachanger::MediaChangerFacade mc(acs, mmc, rmc);
302
  castor::messages::TapeserverProxyDummy initialProcess;
303
  castor::server::ProcessCapDummy capUtils;
304
305
306
307
  cta::MockNameServer ns;
  cta::MockRemoteNS rns;
  cta::MockSchedulerDatabase db;
  cta::Scheduler scheduler(ns, db, rns);
308
  DataTransferSession sess("tapeHost", logger, mockSys,
309
    driveConfig, mc, initialProcess, capUtils, castorConf, scheduler);
310
311
312
313
314
  sess.execute();
  simRun.wait();
  std::string temp = logger.getLog();
  temp += "";
  ASSERT_NE(std::string::npos, logger.getLog().find("Drive not found on this path"));
315
  ASSERT_EQ(SEINTERNAL, sim.m_sessionErrorCode);
316
317
}

318
TEST_F(tapeServer, DataTransferSessionFailtoMount) {
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
  // 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.
  castor::log::StringLogger logger("tapeServerUnitTest");
  
  // 1) prepare the client and run it in another thread
  uint32_t volReq = 0xBEEF;
  std::string vid = "V12345";
  std::string density = "8000GC";
  client::ClientSimulator sim(volReq, vid, density,
    castor::tape::tapegateway::TAPE_GATEWAY,
    castor::tape::tapegateway::READ);
  client::ClientSimulator::ipPort clientAddr = sim.getCallbackAddress();
  clientRunner simRun(sim);
  simRun.start();
  
  // 3) Prepare the necessary environment (logger, plus system wrapper), 
  // construct and run the session.
  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 
  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
  {
    // Label the tape
    castor::tape::tapeFile::LabelSession ls(*mockSys.fake.m_pathToDrive["/dev/nst0"], 
352
        "V12345");
353
354
355
356
357
358
359
    mockSys.fake.m_pathToDrive["/dev/nst0"]->rewind();
    // And write to it
    castor::tape::tapeserver::client::ClientInterface::VolumeInfo volInfo;
    volInfo.vid="V12345";
    // Prepare a non-empty files to recall list to pass the empty session
    // detection
    for (int fseq=1; fseq <= 10 ; fseq ++) {
360
361
362
      std::unique_ptr<cta::RetrieveJob> ftr(new MockRetrieveJob());
      ftr->tapeFileLocation.fSeq = fseq;
      ftr->archiveFile.fileId = 1000 + fseq;
363
      // Set the recall destination (/dev/null)
364
      ftr->archiveFile.path = "/dev/null";
365
      // Record the file for recall, with an out of tape fSeq
366
      ftr->setFseq(ftr->fseq() + 1000);
367
368
369
      sim.addFileToRecall(ftr, 1000);
    }
  }
370
  DriveConfig driveConfig("T10D6116", "T10KD6", "/dev/tape_T10D6116", "manual");
371
372
373
374
375
376
377
378
379
380
381
382
  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;
383
384
385
386
  cta::MockNameServer ns;
  cta::MockRemoteNS rns;
  cta::MockSchedulerDatabase db;
  cta::Scheduler scheduler(ns, db, rns);
387
  DataTransferSession sess("tapeHost", logger, mockSys,
388
    driveConfig, mc, initialProcess, capUtils, castorConf, scheduler);
389
390
391
392
393
  sess.execute();
  simRun.wait();
  std::string temp = logger.getLog();
  temp += "";
  ASSERT_EQ("V12345", sess.getVid());
394
395
  // The session is now failing (internal error is reported)
  ASSERT_EQ(1015, sim.m_sessionErrorCode);
396
397
}

398
TEST_F(tapeServer, DataTransferSessionEmptyOnVolReq) {
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
  // 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.
  castor::log::StringLogger logger("tapeServerUnitTest");
  
  // 1) prepare the client and run it in another thread
  uint32_t volReq = 0xBEEF;
  std::string vid = "V12345";
  std::string density = "8000GC";
  client::ClientSimulator sim(volReq, vid, density,
    castor::tape::tapegateway::TAPE_GATEWAY,
    castor::tape::tapegateway::READ, client::ClientSimulator::EmptyOnVolReq);
  client::ClientSimulator::ipPort clientAddr = sim.getCallbackAddress();
  clientRunner simRun(sim);
  simRun.start();
  
  // 3) Prepare the necessary environment (logger, plus system wrapper), 
  // construct and run the session.
  castor::tape::System::mockWrapper mockSys;
  mockSys.delegateToFake();
  mockSys.disableGMockCallsCounting();
  mockSys.fake.setupForVirtualDriveSLC6();

  // The drive will not even be opened. so no need for one.
  mockSys.fake.m_pathToDrive["/dev/nst0"] = NULL;
  
425
  DriveConfig driveConfig("T10D6116", "T10KD6", "/dev/tape_T10D6116", "manual");
426
427
428
429
430
431
432
433
434
435
436
437
  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;
438
439
440
441
  cta::MockNameServer ns;
  cta::MockRemoteNS rns;
  cta::MockSchedulerDatabase db;
  cta::Scheduler scheduler(ns, db, rns);
442
  DataTransferSession sess("tapeHost", logger, mockSys,
443
    driveConfig, mc, initialProcess, capUtils, castorConf, scheduler);
444
445
446
447
448
449
450
451
452
453
454
  sess.execute();
  simRun.wait();
  std::string temp = logger.getLog();
  temp += "";
  ASSERT_EQ("", sess.getVid());
  // Currently, failures are reported by files and recall sessions do not fail.
  ASSERT_EQ(0, sim.m_sessionErrorCode);
  // We should not have logged any error
  ASSERT_EQ(std::string::npos, logger.getLog().find("LVL=E"));
}

455
class TempFileForData {
Eric Cano's avatar
Eric Cano committed
456
public:
457
  TempFileForData(size_t size): m_size(size) {
Eric Cano's avatar
Eric Cano committed
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
    // Create a temporary file
    int randomFd = open("/dev/urandom", 0);
    castor::exception::Errnum::throwOnMinusOne(randomFd, "Error opening /dev/urandom");
    char path[100];
    strncpy(path, "/tmp/castorUnitTestMigrationSourceXXXXXX", 100);
    int tmpFileFd = mkstemp(path);
    castor::exception::Errnum::throwOnMinusOne(tmpFileFd, "Error creating a temporary file");
    m_path = path;
    char * buff = NULL;
    try {
      buff = new char[size];
      if(!buff) { throw castor::exception::Exception("Failed to allocate memory to read /dev/urandom"); }
      castor::exception::Errnum::throwOnMinusOne(read(randomFd, buff, size));
      castor::exception::Errnum::throwOnMinusOne(write(tmpFileFd, buff, size));
      m_checksum = adler32(0L, Z_NULL, 0);
      m_checksum = adler32(m_checksum, (const Bytef *)buff, size);
      close(randomFd);
      close(tmpFileFd);
Eric Cano's avatar
Eric Cano committed
476
      delete[] buff;
Eric Cano's avatar
Eric Cano committed
477
478
479
480
481
482
483
    } catch (...) {
      delete[] buff;
      unlink(m_path.c_str());
      throw;
    }
  }
  
484
  ~TempFileForData() {
Eric Cano's avatar
Eric Cano committed
485
486
487
488
489
490
491
492
493
494
    unlink(m_path.c_str());
  }
  const size_t m_size;
  const std::string path() const { return m_path; }
  uint32_t checksum() const { return m_checksum; }
private:
  std::string m_path;
  uint32_t m_checksum;
};

495
class tempFileVector: public std::vector<TempFileForData *> {
Eric Cano's avatar
Eric Cano committed
496
497
498
499
500
501
502
503
504
505
public:
  ~tempFileVector() {
    while(size()) {
      delete back();
      pop_back();
    }
  }
};

struct expectedResult {
506
507
  expectedResult(int fs, uint32_t cs, int eCode = 0):
    fSeq(fs), checksum(cs), errorCode(eCode) {}
Eric Cano's avatar
Eric Cano committed
508
509
  int fSeq;
  uint32_t checksum;
510
  int errorCode;
Eric Cano's avatar
Eric Cano committed
511
512
};

513
TEST_F(tapeServer, DataTransferSessionGooddayMigration) {
Eric Cano's avatar
Eric Cano committed
514
515
516
517
518
519
520
521
522
523
524
  // TpcpClients only supports 32 bits session number
  // This number has to be less than 2^31 as in addition there is a mix
  // of signed and unsigned numbers
  // As the current ids in prod are ~30M, we are far from overflow (Feb 2013)
  // 0) Prepare the logger for everyone
  castor::log::StringLogger logger("tapeServerUnitTest");
  
  // 1) prepare the client and run it in another thread
  uint32_t volReq = 0xBEEF;
  std::string vid = "V12345";
  std::string density = "8000GC";
525
526
  client::ClientSimulator sim(volReq, vid, density,
    castor::tape::tapegateway::WRITE_TP, castor::tape::tapegateway::WRITE);
Eric Cano's avatar
Eric Cano committed
527
528
529
530
531
532
533
534
535
536
537
538
539
540
  client::ClientSimulator::ipPort clientAddr = sim.getCallbackAddress();
  clientRunner simRun(sim);
  simRun.start();
  
  // 3) Prepare the necessary environment (logger, plus system wrapper), 
  // construct and run the session.
  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 
541
  mockSys.fake.m_pathToDrive["/dev/nst0"] = new castor::tape::tapeserver::drive::FakeDrive;
Eric Cano's avatar
Eric Cano committed
542
543
544
  
  // Just label the tape
  castor::tape::tapeFile::LabelSession ls(*mockSys.fake.m_pathToDrive["/dev/nst0"], 
545
      "V12345");
Eric Cano's avatar
Eric Cano committed
546
547
548
549
550
551
552
  mockSys.fake.m_pathToDrive["/dev/nst0"]->rewind();
  
  tempFileVector tempFiles;
  std::vector<expectedResult> expected;
  // Prepare the files (in real filesystem as they will be opened by the rfio client)
  for (int fseq=1; fseq<=10; fseq++) {
    // Create the file from which we will recall
553
    std::unique_ptr<TempFileForData> tf(new TempFileForData(1000));
Eric Cano's avatar
Eric Cano committed
554
    // Prepare the migrationRequest
555
    MockArchiveJob ftm;
Eric Cano's avatar
Eric Cano committed
556
    ftm.setFileSize(tf->m_size);
557
558
    ftm.archiveFile.fileId = 1000 + fseq;
    ftm.tapeFileLocation.fSeq = fseq;
Eric Cano's avatar
Eric Cano committed
559
560
561
562
563
    ftm.setPath(tf->path());
    sim.addFileToMigrate(ftm);
    expected.push_back(expectedResult(fseq, tf->checksum()));
    tempFiles.push_back(tf.release());
  }
564
  DriveConfig driveConfig("T10D6116", "T10KD6", "/dev/tape_T10D6116", "manual");
565
566
567
568
569
570
  DataTransferConfig castorConf;
  castorConf.bufsz = 1024*1024; // 1 MB memory buffers
  castorConf.nbBufs = 10;
  castorConf.bulkRequestMigrationMaxBytes = UINT64_C(100)*1000*1000*1000;
  castorConf.bulkRequestMigrationMaxFiles = 1000;
  castorConf.nbDiskThreads = 1;
571
572
573
574
  castor::messages::AcsProxyDummy acs;
  castor::mediachanger::MmcProxyDummy mmc;
  castor::legacymsg::RmcProxyDummy rmc;
  castor::mediachanger::MediaChangerFacade mc(acs, mmc, rmc);
575
  castor::messages::TapeserverProxyDummy initialProcess;
576
  castor::server::ProcessCapDummy capUtils;
577
578
579
580
  cta::MockNameServer ns;
  cta::MockRemoteNS rns;
  cta::MockSchedulerDatabase db;
  cta::Scheduler scheduler(ns, db, rns);
581
  DataTransferSession sess("tapeHost", logger, mockSys,
582
    driveConfig, mc, initialProcess, capUtils, castorConf, scheduler);
Eric Cano's avatar
Eric Cano committed
583
584
  sess.execute();
  simRun.wait();
585
586
587
588
  for (std::vector<struct expectedResult>::iterator i = expected.begin();
      i != expected.end(); i++) {
    ASSERT_EQ(i->checksum, sim.m_receivedChecksums[i->fSeq]);
  }
589
  ASSERT_EQ(0, sim.m_sessionErrorCode);
Eric Cano's avatar
Eric Cano committed
590
591
}

592
593
594
595
596
//
// 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.
///
TEST_F(tapeServer, DataTransferSessionMissingFilesMigration) {
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
  // TpcpClients only supports 32 bits session number
  // This number has to be less than 2^31 as in addition there is a mix
  // of signed and unsigned numbers
  // As the current ids in prod are ~30M, we are far from overflow (Feb 2013)
  // 0) Prepare the logger for everyone
  castor::log::StringLogger logger("tapeServerUnitTest");
  
  // 1) prepare the client and run it in another thread
  uint32_t volReq = 0xBEEF;
  std::string vid = "V12345";
  std::string density = "8000GC";
  client::ClientSimulator sim(volReq, vid, density,
    castor::tape::tapegateway::WRITE_TP, castor::tape::tapegateway::WRITE);
  client::ClientSimulator::ipPort clientAddr = sim.getCallbackAddress();
  clientRunner simRun(sim);
  simRun.start();
  
  // 3) Prepare the necessary environment (logger, plus system wrapper), 
  // construct and run the session.
  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 
624
  mockSys.fake.m_pathToDrive["/dev/nst0"] = new castor::tape::tapeserver::drive::FakeDrive;
625
626
627
  
  // Just label the tape
  castor::tape::tapeFile::LabelSession ls(*mockSys.fake.m_pathToDrive["/dev/nst0"], 
628
      "V12345");
629
630
631
632
633
  mockSys.fake.m_pathToDrive["/dev/nst0"]->rewind();
  
  // Prepare the files, but delete them immediately. The migration will fail.
  for (int fseq=1; fseq<=10; fseq++) {
    // Create the file from which we will recall
634
    std::unique_ptr<TempFileForData> tf(new TempFileForData(1000));
635
    // Prepare the migrationRequest
636
    MockArchiveJob ftm;
637
    ftm.setFileSize(tf->m_size);
638
639
    ftm.archiveFile.fileId = 1000 + fseq;
    ftm.tapeFileLocation.fSeq = fseq;
640
641
642
    ftm.setPath(tf->path());
    sim.addFileToMigrate(ftm);
  }
643
  DriveConfig driveConfig("T10D6116", "T10KD6", "/dev/tape_T10D6116", "manual");
644
645
646
647
648
649
  DataTransferConfig castorConf;
  castorConf.bufsz = 1024*1024; // 1 MB memory buffers
  castorConf.nbBufs = 10;
  castorConf.bulkRequestMigrationMaxBytes = UINT64_C(100)*1000*1000*1000;
  castorConf.bulkRequestMigrationMaxFiles = 1000;
  castorConf.nbDiskThreads = 1;
650
651
652
653
  castor::messages::AcsProxyDummy acs;
  castor::mediachanger::MmcProxyDummy mmc;
  castor::legacymsg::RmcProxyDummy rmc;
  castor::mediachanger::MediaChangerFacade mc(acs, mmc, rmc);
654
655
  castor::messages::TapeserverProxyDummy initialProcess;
  castor::server::ProcessCapDummy capUtils;
656
657
658
659
  cta::MockNameServer ns;
  cta::MockRemoteNS rns;
  cta::MockSchedulerDatabase db;
  cta::Scheduler scheduler(ns, db, rns);
660
  DataTransferSession sess("tapeHost", logger, mockSys,
661
    driveConfig, mc, initialProcess, capUtils, castorConf, scheduler);
662
663
  sess.execute();
  simRun.wait();
664
  ASSERT_EQ(SEINTERNAL, sim.m_sessionErrorCode);
665
}
666

667
668
669
670
671
672
//
// This test is identical to the good day migration, but the tape will accept
// only a finite number of bytes and hence we will report a full tape skip the
// last migrations
//
TEST_F(tapeServer, DataTransferSessionTapeFullMigration) {
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
  // TpcpClients only supports 32 bits session number
  // This number has to be less than 2^31 as in addition there is a mix
  // of signed and unsigned numbers
  // As the current ids in prod are ~30M, we are far from overflow (Feb 2013)
  // 0) Prepare the logger for everyone
  castor::log::StringLogger logger("tapeServerUnitTest");
  
  // 1) prepare the client and run it in another thread
  uint32_t volReq = 0xBEEF;
  std::string vid = "V12345";
  std::string density = "8000GC";
  client::ClientSimulator sim(volReq, vid, density,
    castor::tape::tapegateway::WRITE_TP, castor::tape::tapegateway::WRITE);
  client::ClientSimulator::ipPort clientAddr = sim.getCallbackAddress();
  clientRunner simRun(sim);
  simRun.start();
  
  // 3) Prepare the necessary environment (logger, plus system wrapper), 
  // construct and run the session.
  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 
  const uint64_t tapeSize = 5000;
701
  mockSys.fake.m_pathToDrive["/dev/nst0"] = new castor::tape::tapeserver::drive::FakeDrive(tapeSize);
702
703
704
  
  // Just label the tape
  castor::tape::tapeFile::LabelSession ls(*mockSys.fake.m_pathToDrive["/dev/nst0"], 
705
      "V12345");
706
707
708
709
710
711
712
713
714
715
  mockSys.fake.m_pathToDrive["/dev/nst0"]->rewind();
  
  tempFileVector tempFiles;
  std::vector<expectedResult> expected;
  uint64_t remainingSpace = tapeSize;
  bool failedFileDone = false;
  // Prepare the files (in real filesystem as they will be opened by the rfio client)
  for (int fseq=1; fseq<=10; fseq++) {
    // Create the file from which we will recall
    const size_t fileSize = 1000;
716
    std::unique_ptr<TempFileForData> tf(new TempFileForData(fileSize));
717
    // Prepare the migrationRequest
718
    MockArchiveJob ftm;
719
    ftm.setFileSize(tf->m_size);
720
721
    ftm.archiveFile.fileId = 1000 + fseq;
    ftm.tapeFileLocation.fSeq = fseq;
722
723
724
725
726
727
728
729
730
731
732
733
    ftm.setPath(tf->path());
    sim.addFileToMigrate(ftm);
    if (fileSize + 6 * 80 < remainingSpace) {
      expected.push_back(expectedResult(fseq, tf->checksum()));
      remainingSpace -= fileSize + 6 * 80;
    } else if (!failedFileDone) {
      // We add also the report for the first file (which will come in error)
      expected.push_back(expectedResult(fseq, 0, ENOSPC));
      failedFileDone = true;
    }
    tempFiles.push_back(tf.release());
  }
734
  DriveConfig driveConfig("T10D6116", "T10KD6", "/dev/tape_T10D6116", "manual");
735
736
737
738
739
740
  DataTransferConfig castorConf;
  castorConf.bufsz = 1024*1024; // 1 MB memory buffers
  castorConf.nbBufs = 10;
  castorConf.bulkRequestMigrationMaxBytes = UINT64_C(100)*1000*1000*1000;
  castorConf.bulkRequestMigrationMaxFiles = 1000;
  castorConf.nbDiskThreads = 1;
741
742
743
744
  castor::messages::AcsProxyDummy acs;
  castor::mediachanger::MmcProxyDummy mmc;
  castor::legacymsg::RmcProxyDummy rmc;
  castor::mediachanger::MediaChangerFacade mc(acs, mmc, rmc);
745
746
  castor::messages::TapeserverProxyDummy initialProcess;
  castor::server::ProcessCapDummy capUtils;
747
748
749
750
  cta::MockNameServer ns;
  cta::MockRemoteNS rns;
  cta::MockSchedulerDatabase db;
  cta::Scheduler scheduler(ns, db, rns);
751
  DataTransferSession sess("tapeHost", logger, mockSys,
752
    driveConfig, mc, initialProcess, capUtils, castorConf, scheduler);
753
754
755
756
757
758
759
760
761
762
  sess.execute();
  simRun.wait();
  for (std::vector<struct expectedResult>::iterator i = expected.begin();
      i != expected.end(); i++) {
    if (!i->errorCode) {
      ASSERT_EQ(i->checksum, sim.m_receivedChecksums[i->fSeq]);
    } else {
      ASSERT_EQ(i->errorCode, sim.m_receivedErrorCodes[i->fSeq]);
    }
  }
763
764
765
  ASSERT_EQ(ENOSPC, sim.m_sessionErrorCode);
}

766
TEST_F(tapeServer, DataTransferSessionTapeFullOnFlushMigration) {
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
  // TpcpClients only supports 32 bits session number
  // This number has to be less than 2^31 as in addition there is a mix
  // of signed and unsigned numbers
  // As the current ids in prod are ~30M, we are far from overflow (Feb 2013)
  // 0) Prepare the logger for everyone
  castor::log::StringLogger logger("tapeServerUnitTest");
  
  // 1) prepare the client and run it in another thread
  uint32_t volReq = 0xBEEF;
  std::string vid = "V12345";
  std::string density = "8000GC";
  client::ClientSimulator sim(volReq, vid, density,
    castor::tape::tapegateway::WRITE_TP, castor::tape::tapegateway::WRITE);
  client::ClientSimulator::ipPort clientAddr = sim.getCallbackAddress();
  clientRunner simRun(sim);
  simRun.start();
  
  // 3) Prepare the necessary environment (logger, plus system wrapper), 
  // construct and run the session.
  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 
  const uint64_t tapeSize = 5000;
  mockSys.fake.m_pathToDrive["/dev/nst0"] =
796
797
      new castor::tape::tapeserver::drive::FakeDrive(tapeSize,
        castor::tape::tapeserver::drive::FakeDrive::OnFlush);
798
799
800
  
  // Just label the tape
  castor::tape::tapeFile::LabelSession ls(*mockSys.fake.m_pathToDrive["/dev/nst0"], 
801
      "V12345");
802
803
804
805
806
807
808
809
810
811
  mockSys.fake.m_pathToDrive["/dev/nst0"]->rewind();
  
  tempFileVector tempFiles;
  std::vector<expectedResult> expected;
  uint64_t remainingSpace = tapeSize;
  bool failedFileDone = false;
  // Prepare the files (in real filesystem as they will be opened by the rfio client)
  for (int fseq=1; fseq<=10; fseq++) {
    // Create the file from which we will recall
    const size_t fileSize = 1000;
812
    std::unique_ptr<TempFileForData> tf(new TempFileForData(fileSize));
813
    // Prepare the migrationRequest
814
    MockArchiveJob ftm;
815
    ftm.setFileSize(tf->m_size);
816
817
    ftm.archiveFile.fileId = 1000 + fseq;
    ftm.tapeFileLocation.fSeq = fseq;
818
819
820
821
822
823
824
825
826
827
828
829
    ftm.setPath(tf->path());
    sim.addFileToMigrate(ftm);
    if (fileSize + 6 * 80 < remainingSpace) {
      expected.push_back(expectedResult(fseq, tf->checksum()));
      remainingSpace -= fileSize + 6 * 80;
    } else if (!failedFileDone) {
      // We expect no report for this file anymore (but the report for the 
      // session)
      failedFileDone = true;
    }
    tempFiles.push_back(tf.release());
  }
830
  DriveConfig driveConfig("T10D6116", "T10KD6", "/dev/tape_T10D6116", "manual");
831
832
833
834
835
836
  DataTransferConfig castorConf;
  castorConf.bufsz = 1024*1024; // 1 MB memory buffers
  castorConf.nbBufs = 10;
  castorConf.bulkRequestMigrationMaxBytes = UINT64_C(100)*1000*1000*1000;
  castorConf.bulkRequestMigrationMaxFiles = 1000;
  castorConf.nbDiskThreads = 1;
837
838
839
840
  castor::messages::AcsProxyDummy acs;
  castor::mediachanger::MmcProxyDummy mmc;
  castor::legacymsg::RmcProxyDummy rmc;
  castor::mediachanger::MediaChangerFacade mc(acs, mmc, rmc);
841
842
  castor::messages::TapeserverProxyDummy initialProcess;
  castor::server::ProcessCapDummy capUtils;
843
844
845
846
  cta::MockNameServer ns;
  cta::MockRemoteNS rns;
  cta::MockSchedulerDatabase db;
  cta::Scheduler scheduler(ns, db, rns);
847
  DataTransferSession sess("tapeHost", logger, mockSys,
848
    driveConfig, mc, initialProcess, capUtils, castorConf, scheduler);
849
850
851
852
853
854
855
856
857
858
859
  sess.execute();
  simRun.wait();
  for (std::vector<struct expectedResult>::iterator i = expected.begin();
      i != expected.end(); i++) {
    if (!i->errorCode) {
      ASSERT_EQ(i->checksum, sim.m_receivedChecksums[i->fSeq]);
    } else {
      ASSERT_EQ(i->errorCode, sim.m_receivedErrorCodes[i->fSeq]);
    }
  }
  ASSERT_EQ(ENOSPC, sim.m_sessionErrorCode);
860
}
861
*/
862

863
} // namespace unitTest