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
#include "nameserver/mockNS/MockNameServer.hpp"
#include "remotens/MockRemoteNS.hpp"
48
#include "scheduler/DummyScheduler.hpp"
49
#include "scheduler/mockDB/MockSchedulerDatabase.hpp"
50
#include "scheduler/MountType.hpp"
51
52

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

59

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

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

  void SetUp() {
  }

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

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

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

92
TEST_F(tapeServer, DataTransferSessionGooddayRecall) {
93
94
95
96
  // 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
97
98
99
  // 0) Prepare the logger for everyone
  castor::log::StringLogger logger("tapeServerUnitTest");
  
100
  // 1) prepare the fake scheduler
101
  std::string vid = "V12345";
102
  // cta::MountType::Enum mountType = cta::MountType::RETRIEVE;
103
  std::string density = "8000GC";
104

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

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

178
179
/*
TEST_F(tapeServer, DataTransferSessionWrongRecall) {
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
  // 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 
206
  mockSys.fake.m_pathToDrive["/dev/nst0"] = new castor::tape::tapeserver::drive::FakeDrive;
207
208
209
210
211
  
  // We can prepare files for reading on the drive
  {
    // Label the tape
    castor::tape::tapeFile::LabelSession ls(*mockSys.fake.m_pathToDrive["/dev/nst0"], 
212
        "V12345");
213
214
215
216
217
218
219
220
221
222
223
    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 ++) {
224
225
226
227
228
229
230
231
      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();
232
      // Set the recall destination (/dev/null)
233
      ftr->archiveFile.path = "/dev/null";
234
235
236
237
238
      // 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
239
      ftr->setFseq(ftr->fseq() + 1000);
240
241
242
      sim.addFileToRecall(ftr, sizeof(data));
    }
  }
243
  DriveConfig driveConfig("T10D6116", "T10KD6", "/dev/tape_T10D6116", "manual");
244
245
246
247
248
249
  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;
250
251
252
253
  castor::messages::AcsProxyDummy acs;
  castor::mediachanger::MmcProxyDummy mmc;
  castor::legacymsg::RmcProxyDummy rmc;
  castor::mediachanger::MediaChangerFacade mc(acs, mmc, rmc);
254
255
  castor::server::ProcessCap capUtils;
  castor::messages::TapeserverProxyDummy initialProcess;
256
257
258
259
  cta::MockNameServer ns;
  cta::MockRemoteNS rns;
  cta::MockSchedulerDatabase db;
  cta::Scheduler scheduler(ns, db, rns);
260
  DataTransferSession sess("tapeHost", logger, mockSys,
261
    driveConfig, mc, initialProcess, capUtils, castorConf, scheduler);
262
263
264
265
266
  sess.execute();
  simRun.wait();
  std::string temp = logger.getLog();
  temp += "";
  ASSERT_EQ("V12345", sess.getVid());
267
  ASSERT_EQ(SEINTERNAL, sim.m_sessionErrorCode);
268
}
269

270
TEST_F(tapeServer, DataTransferSessionNoSuchDrive) {
271
272
273
274
275
276
277
278
  // 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";
279
280
  client::ClientSimulator sim(volReq, vid, density,
    castor::tape::tapegateway::READ_TP, castor::tape::tapegateway::READ);
281
  client::ClientSimulator::ipPort clientAddr = sim.getCallbackAddress();
282
283
284
285
286
287
288
289
290
291
  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();
292
  DriveConfig driveConfig("T10D6116", "T10KD6", "/dev/noSuchTape", "manual");
293
294
295
  DataTransferConfig castorConf;
  castorConf.bufsz = 1024;
  castorConf.nbBufs = 10;
296
297
298
299
  castor::messages::AcsProxyDummy acs;
  castor::mediachanger::MmcProxyDummy mmc;
  castor::legacymsg::RmcProxyDummy rmc;
  castor::mediachanger::MediaChangerFacade mc(acs, mmc, rmc);
300
  castor::messages::TapeserverProxyDummy initialProcess;
301
  castor::server::ProcessCapDummy capUtils;
302
303
304
305
  cta::MockNameServer ns;
  cta::MockRemoteNS rns;
  cta::MockSchedulerDatabase db;
  cta::Scheduler scheduler(ns, db, rns);
306
  DataTransferSession sess("tapeHost", logger, mockSys,
307
    driveConfig, mc, initialProcess, capUtils, castorConf, scheduler);
308
309
310
311
312
  sess.execute();
  simRun.wait();
  std::string temp = logger.getLog();
  temp += "";
  ASSERT_NE(std::string::npos, logger.getLog().find("Drive not found on this path"));
313
  ASSERT_EQ(SEINTERNAL, sim.m_sessionErrorCode);
314
315
}

316
TEST_F(tapeServer, DataTransferSessionFailtoMount) {
317
318
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
  // 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"], 
350
        "V12345");
351
352
353
354
355
356
357
    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 ++) {
358
359
360
      std::unique_ptr<cta::RetrieveJob> ftr(new MockRetrieveJob());
      ftr->tapeFileLocation.fSeq = fseq;
      ftr->archiveFile.fileId = 1000 + fseq;
361
      // Set the recall destination (/dev/null)
362
      ftr->archiveFile.path = "/dev/null";
363
      // Record the file for recall, with an out of tape fSeq
364
      ftr->setFseq(ftr->fseq() + 1000);
365
366
367
      sim.addFileToRecall(ftr, 1000);
    }
  }
368
  DriveConfig driveConfig("T10D6116", "T10KD6", "/dev/tape_T10D6116", "manual");
369
370
371
372
373
374
375
376
377
378
379
380
  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;
381
382
383
384
  cta::MockNameServer ns;
  cta::MockRemoteNS rns;
  cta::MockSchedulerDatabase db;
  cta::Scheduler scheduler(ns, db, rns);
385
  DataTransferSession sess("tapeHost", logger, mockSys,
386
    driveConfig, mc, initialProcess, capUtils, castorConf, scheduler);
387
388
389
390
391
  sess.execute();
  simRun.wait();
  std::string temp = logger.getLog();
  temp += "";
  ASSERT_EQ("V12345", sess.getVid());
392
393
  // The session is now failing (internal error is reported)
  ASSERT_EQ(1015, sim.m_sessionErrorCode);
394
395
}

396
TEST_F(tapeServer, DataTransferSessionEmptyOnVolReq) {
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
  // 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;
  
423
  DriveConfig driveConfig("T10D6116", "T10KD6", "/dev/tape_T10D6116", "manual");
424
425
426
427
428
429
430
431
432
433
434
435
  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;
436
437
438
439
  cta::MockNameServer ns;
  cta::MockRemoteNS rns;
  cta::MockSchedulerDatabase db;
  cta::Scheduler scheduler(ns, db, rns);
440
  DataTransferSession sess("tapeHost", logger, mockSys,
441
    driveConfig, mc, initialProcess, capUtils, castorConf, scheduler);
442
443
444
445
446
447
448
449
450
451
452
  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"));
}

453
class TempFileForData {
Eric Cano's avatar
Eric Cano committed
454
public:
455
  TempFileForData(size_t size): m_size(size) {
Eric Cano's avatar
Eric Cano committed
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
    // 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
474
      delete[] buff;
Eric Cano's avatar
Eric Cano committed
475
476
477
478
479
480
481
    } catch (...) {
      delete[] buff;
      unlink(m_path.c_str());
      throw;
    }
  }
  
482
  ~TempFileForData() {
Eric Cano's avatar
Eric Cano committed
483
484
485
486
487
488
489
490
491
492
    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;
};

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

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

511
TEST_F(tapeServer, DataTransferSessionGooddayMigration) {
Eric Cano's avatar
Eric Cano committed
512
513
514
515
516
517
518
519
520
521
522
  // 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";
523
524
  client::ClientSimulator sim(volReq, vid, density,
    castor::tape::tapegateway::WRITE_TP, castor::tape::tapegateway::WRITE);
Eric Cano's avatar
Eric Cano committed
525
526
527
528
529
530
531
532
533
534
535
536
537
538
  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 
539
  mockSys.fake.m_pathToDrive["/dev/nst0"] = new castor::tape::tapeserver::drive::FakeDrive;
Eric Cano's avatar
Eric Cano committed
540
541
542
  
  // Just label the tape
  castor::tape::tapeFile::LabelSession ls(*mockSys.fake.m_pathToDrive["/dev/nst0"], 
543
      "V12345");
Eric Cano's avatar
Eric Cano committed
544
545
546
547
548
549
550
  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
551
    std::unique_ptr<TempFileForData> tf(new TempFileForData(1000));
Eric Cano's avatar
Eric Cano committed
552
    // Prepare the migrationRequest
553
    MockArchiveJob ftm;
Eric Cano's avatar
Eric Cano committed
554
    ftm.setFileSize(tf->m_size);
555
556
    ftm.archiveFile.fileId = 1000 + fseq;
    ftm.tapeFileLocation.fSeq = fseq;
Eric Cano's avatar
Eric Cano committed
557
558
559
560
561
    ftm.setPath(tf->path());
    sim.addFileToMigrate(ftm);
    expected.push_back(expectedResult(fseq, tf->checksum()));
    tempFiles.push_back(tf.release());
  }
562
  DriveConfig driveConfig("T10D6116", "T10KD6", "/dev/tape_T10D6116", "manual");
563
564
565
566
567
568
  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;
569
570
571
572
  castor::messages::AcsProxyDummy acs;
  castor::mediachanger::MmcProxyDummy mmc;
  castor::legacymsg::RmcProxyDummy rmc;
  castor::mediachanger::MediaChangerFacade mc(acs, mmc, rmc);
573
  castor::messages::TapeserverProxyDummy initialProcess;
574
  castor::server::ProcessCapDummy capUtils;
575
576
577
578
  cta::MockNameServer ns;
  cta::MockRemoteNS rns;
  cta::MockSchedulerDatabase db;
  cta::Scheduler scheduler(ns, db, rns);
579
  DataTransferSession sess("tapeHost", logger, mockSys,
580
    driveConfig, mc, initialProcess, capUtils, castorConf, scheduler);
Eric Cano's avatar
Eric Cano committed
581
582
  sess.execute();
  simRun.wait();
583
584
585
586
  for (std::vector<struct expectedResult>::iterator i = expected.begin();
      i != expected.end(); i++) {
    ASSERT_EQ(i->checksum, sim.m_receivedChecksums[i->fSeq]);
  }
587
  ASSERT_EQ(0, sim.m_sessionErrorCode);
Eric Cano's avatar
Eric Cano committed
588
589
}

590
591
592
593
594
//
// 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) {
595
596
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
  // 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 
622
  mockSys.fake.m_pathToDrive["/dev/nst0"] = new castor::tape::tapeserver::drive::FakeDrive;
623
624
625
  
  // Just label the tape
  castor::tape::tapeFile::LabelSession ls(*mockSys.fake.m_pathToDrive["/dev/nst0"], 
626
      "V12345");
627
628
629
630
631
  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
632
    std::unique_ptr<TempFileForData> tf(new TempFileForData(1000));
633
    // Prepare the migrationRequest
634
    MockArchiveJob ftm;
635
    ftm.setFileSize(tf->m_size);
636
637
    ftm.archiveFile.fileId = 1000 + fseq;
    ftm.tapeFileLocation.fSeq = fseq;
638
639
640
    ftm.setPath(tf->path());
    sim.addFileToMigrate(ftm);
  }
641
  DriveConfig driveConfig("T10D6116", "T10KD6", "/dev/tape_T10D6116", "manual");
642
643
644
645
646
647
  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;
648
649
650
651
  castor::messages::AcsProxyDummy acs;
  castor::mediachanger::MmcProxyDummy mmc;
  castor::legacymsg::RmcProxyDummy rmc;
  castor::mediachanger::MediaChangerFacade mc(acs, mmc, rmc);
652
653
  castor::messages::TapeserverProxyDummy initialProcess;
  castor::server::ProcessCapDummy capUtils;
654
655
656
657
  cta::MockNameServer ns;
  cta::MockRemoteNS rns;
  cta::MockSchedulerDatabase db;
  cta::Scheduler scheduler(ns, db, rns);
658
  DataTransferSession sess("tapeHost", logger, mockSys,
659
    driveConfig, mc, initialProcess, capUtils, castorConf, scheduler);
660
661
  sess.execute();
  simRun.wait();
662
  ASSERT_EQ(SEINTERNAL, sim.m_sessionErrorCode);
663
}
664

665
666
667
668
669
670
//
// 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) {
671
672
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
  // 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;
699
  mockSys.fake.m_pathToDrive["/dev/nst0"] = new castor::tape::tapeserver::drive::FakeDrive(tapeSize);
700
701
702
  
  // Just label the tape
  castor::tape::tapeFile::LabelSession ls(*mockSys.fake.m_pathToDrive["/dev/nst0"], 
703
      "V12345");
704
705
706
707
708
709
710
711
712
713
  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;
714
    std::unique_ptr<TempFileForData> tf(new TempFileForData(fileSize));
715
    // Prepare the migrationRequest
716
    MockArchiveJob ftm;
717
    ftm.setFileSize(tf->m_size);
718
719
    ftm.archiveFile.fileId = 1000 + fseq;
    ftm.tapeFileLocation.fSeq = fseq;
720
721
722
723
724
725
726
727
728
729
730
731
    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());
  }
732
  DriveConfig driveConfig("T10D6116", "T10KD6", "/dev/tape_T10D6116", "manual");
733
734
735
736
737
738
  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;
739
740
741
742
  castor::messages::AcsProxyDummy acs;
  castor::mediachanger::MmcProxyDummy mmc;
  castor::legacymsg::RmcProxyDummy rmc;
  castor::mediachanger::MediaChangerFacade mc(acs, mmc, rmc);
743
744
  castor::messages::TapeserverProxyDummy initialProcess;
  castor::server::ProcessCapDummy capUtils;
745
746
747
748
  cta::MockNameServer ns;
  cta::MockRemoteNS rns;
  cta::MockSchedulerDatabase db;
  cta::Scheduler scheduler(ns, db, rns);
749
  DataTransferSession sess("tapeHost", logger, mockSys,
750
    driveConfig, mc, initialProcess, capUtils, castorConf, scheduler);
751
752
753
754
755
756
757
758
759
760
  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]);
    }
  }
761
762
763
  ASSERT_EQ(ENOSPC, sim.m_sessionErrorCode);
}

764
TEST_F(tapeServer, DataTransferSessionTapeFullOnFlushMigration) {
765
766
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
  // 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"] =
794
795
      new castor::tape::tapeserver::drive::FakeDrive(tapeSize,
        castor::tape::tapeserver::drive::FakeDrive::OnFlush);
796
797
798
  
  // Just label the tape
  castor::tape::tapeFile::LabelSession ls(*mockSys.fake.m_pathToDrive["/dev/nst0"], 
799
      "V12345");
800
801
802
803
804
805
806
807
808
809
  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;
810
    std::unique_ptr<TempFileForData> tf(new TempFileForData(fileSize));
811
    // Prepare the migrationRequest
812
    MockArchiveJob ftm;
813
    ftm.setFileSize(tf->m_size);
814
815
    ftm.archiveFile.fileId = 1000 + fseq;
    ftm.tapeFileLocation.fSeq = fseq;
816
817
818
819
820
821
822
823
824
825
826
827
    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());
  }
828
  DriveConfig driveConfig("T10D6116", "T10KD6", "/dev/tape_T10D6116", "manual");
829
830
831
832
833
834
  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;
835
836
837
838
  castor::messages::AcsProxyDummy acs;
  castor::mediachanger::MmcProxyDummy mmc;
  castor::legacymsg::RmcProxyDummy rmc;
  castor::mediachanger::MediaChangerFacade mc(acs, mmc, rmc);
839
840
  castor::messages::TapeserverProxyDummy initialProcess;
  castor::server::ProcessCapDummy capUtils;
841
842
843
844
  cta::MockNameServer ns;
  cta::MockRemoteNS rns;
  cta::MockSchedulerDatabase db;
  cta::Scheduler scheduler(ns, db, rns);
845
  DataTransferSession sess("tapeHost", logger, mockSys,
846
    driveConfig, mc, initialProcess, capUtils, castorConf, scheduler);
847
848
849
850
851
852
853
854
855
856
857
  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);
858
}
859
*/
860

861
} // namespace unitTest