DataTransferSessionTest.cpp 31.9 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
/******************************************************************************
 *
 * This file is part of the Castor project.
 * See http://castor.web.cern.ch/castor
 *
 * Copyright (C) 2003  CERN
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 *
 * 
 *
 * @author Castor Dev team, castor-dev@cern.ch
 *****************************************************************************/

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

30
#include "castor/legacymsg/RmcProxyDummy.hpp"
31
#include "castor/log/StringLogger.hpp"
32
33
34
#include "castor/mediachanger/MediaChangerFacade.hpp"
#include "castor/mediachanger/MmcProxyDummy.hpp"
#include "castor/messages/AcsProxyDummy.hpp"
35
#include "castor/messages/TapeserverProxyDummy.hpp"
36
#include "castor/server/ProcessCapDummy.hpp"
37
38
39
40
41
42
43
44
45
46
#include "castor/tape/tapegateway/EndNotificationErrorReport.hpp"
#include "castor/tape/tapegateway/NoMoreFiles.hpp"
#include "castor/tape/tapegateway/NotificationAcknowledge.hpp"
#include "castor/tape/tapegateway/RetryPolicyElement.hpp"
#include "castor/tape/tapegateway/Volume.hpp"
#include "castor/tape/tapeserver/client/ClientSimulator.hpp"
#include "castor/tape/tapeserver/client/ClientSimSingleReply.hpp"
#include "castor/tape/tapeserver/client/ClientProxy.hpp"
#include "castor/tape/tapeserver/daemon/DataTransferSession.hpp"
#include "castor/tape/tapeserver/system/Wrapper.hpp"
47
#include "castor/server/Threading.hpp"
48
#include "castor/tape/tapeserver/file/File.hpp"
49
#include "castor/tape/tapeserver/drive/FakeDrive.hpp"
50
51
#include "Ctape.h"
#include "smc_struct.h"
52
53

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

60

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

65
class clientRunner: public castor::server::Thread {
66
public:
67
  clientRunner(client::ClientSimulator &client): m_sim(client) {}
68
69
70
71
private:
  void run() {
    m_sim.sessionLoop();
  }
72
  client::ClientSimulator & m_sim;
73
74
};

75
TEST(tapeServer, DataTransferSessionGooddayRecall) {
76
77
78
79
  // 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
80
81
82
  // 0) Prepare the logger for everyone
  castor::log::StringLogger logger("tapeServerUnitTest");
  
83
  // 1) prepare the client and run it in another thread
84
85
  uint32_t volReq = 0xBEEF;
  std::string vid = "V12345";
86
  std::string density = "8000GC";
87
88
  client::ClientSimulator sim(volReq, vid, density,
    castor::tape::tapegateway::READ_TP, castor::tape::tapegateway::READ);
89
  client::ClientSimulator::ipPort clientAddr = sim.getCallbackAddress();
90
91
  clientRunner simRun(sim);
  simRun.start();
92
  
93
94
95
  // 3) Prepare the necessary environment (logger, plus system wrapper), 
  // construct and run the session.
  castor::tape::System::mockWrapper mockSys;
96
97
  mockSys.delegateToFake();
  mockSys.disableGMockCallsCounting();
98
  mockSys.fake.setupForVirtualDriveSLC6();
99
100
101
102

  //delete is unnecessary
  //pointer with ownership will be passed to the application,
  //which will do the delete 
103
  mockSys.fake.m_pathToDrive["/dev/nst0"] = new castor::tape::tapeserver::drive::FakeDrive;
104
  
105
106
107
108
  // We can prepare files for reading on the drive
  {
    // Label the tape
    castor::tape::tapeFile::LabelSession ls(*mockSys.fake.m_pathToDrive["/dev/nst0"], 
109
        "V12345");
110
111
    mockSys.fake.m_pathToDrive["/dev/nst0"]->rewind();
    // And write to it
112
113
114
    castor::tape::tapeserver::client::ClientInterface::VolumeInfo volInfo;
    volInfo.vid="V12345";
    volInfo.clientType=castor::tape::tapegateway::READ_TP;
115
    castor::tape::tapeFile::WriteSession ws(*mockSys.fake.m_pathToDrive["/dev/nst0"],
116
       volInfo , 0, true);
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
    // 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 ++) {
      castor::tape::tapegateway::FileToRecallStruct ftr;
      castor::tape::tapegateway::FileToMigrateStruct ftm_temp;
      ftr.setFseq(fseq);
      ftm_temp.setFseq(fseq);
      ftr.setFileid(1000 + fseq);
      ftm_temp.setFileid(1000 + fseq);
      castor::tape::tapeFile::WriteFile wf(&ws, ftm_temp, 256*1024);
      // Cut up the position into the old-style BlockId0-3
      ftr.setBlockId0(wf.getPosition() >> 24);
      ftr.setBlockId1( (wf.getPosition() >> 16) & 0xFF);
      ftr.setBlockId2( (wf.getPosition() >> 8) & 0xFF);
      ftr.setBlockId3(wf.getPosition() & 0xFF);
Eric Cano's avatar
Eric Cano committed
134
135
      // Set the recall destination (/dev/null)
      ftr.setPath("/dev/null");
136
137
138
139
140
141
142
143
      // Write the data (one block)
      wf.write(data, sizeof(data));
      // Close the file
      wf.close();
      // Record the file for recall
      sim.addFileToRecall(ftr, sizeof(data));
    }
  }
144
  DriveConfig driveConfig("T10D6116", "T10KD6", "/dev/tape_T10D6116", "manual");
145
146
147
148
149
150
  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;
151
152
153
154
  castor::messages::AcsProxyDummy acs;
  castor::mediachanger::MmcProxyDummy mmc;
  castor::legacymsg::RmcProxyDummy rmc;
  castor::mediachanger::MediaChangerFacade mc(acs, mmc, rmc);
155
  castor::server::ProcessCap capUtils;
156
  castor::messages::TapeserverProxyDummy initialProcess;
157
  DataTransferSession sess("tapeHost", logger, mockSys,
158
    driveConfig, mc, initialProcess, capUtils, castorConf);
Eric Cano's avatar
Eric Cano committed
159
  sess.execute();
160
  simRun.wait();
Eric Cano's avatar
Eric Cano committed
161
162
  std::string temp = logger.getLog();
  temp += "";
163
  ASSERT_EQ("V12345", sess.getVid());
164
  ASSERT_EQ(0, sim.m_sessionErrorCode);
165
}
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193

TEST(tapeServer, DataTransferSessionWrongRecall) {
  // 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 
194
  mockSys.fake.m_pathToDrive["/dev/nst0"] = new castor::tape::tapeserver::drive::FakeDrive;
195
196
197
198
199
  
  // We can prepare files for reading on the drive
  {
    // Label the tape
    castor::tape::tapeFile::LabelSession ls(*mockSys.fake.m_pathToDrive["/dev/nst0"], 
200
        "V12345");
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
    mockSys.fake.m_pathToDrive["/dev/nst0"]->rewind();
    // And write to it
    castor::tape::tapeserver::client::ClientInterface::VolumeInfo volInfo;
    volInfo.vid="V12345";
    volInfo.clientType=castor::tape::tapegateway::READ_TP;
    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 ++) {
      castor::tape::tapegateway::FileToRecallStruct ftr;
      castor::tape::tapegateway::FileToMigrateStruct ftm_temp;
      ftr.setFseq(fseq);
      ftm_temp.setFseq(fseq);
      ftr.setFileid(1000 + fseq);
      ftm_temp.setFileid(1000 + fseq);
      castor::tape::tapeFile::WriteFile wf(&ws, ftm_temp, 256*1024);
      // Cut up the position into the old-style BlockId0-3
      ftr.setBlockId0(wf.getPosition() >> 24);
      ftr.setBlockId1( (wf.getPosition() >> 16) & 0xFF);
      ftr.setBlockId2( (wf.getPosition() >> 8) & 0xFF);
      ftr.setBlockId3(wf.getPosition() & 0xFF);
      // Set the recall destination (/dev/null)
      ftr.setPath("/dev/null");
      // 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
      ftr.setFseq(ftr.fseq() + 1000);
      sim.addFileToRecall(ftr, sizeof(data));
    }
  }
236
  DriveConfig driveConfig("T10D6116", "T10KD6", "/dev/tape_T10D6116", "manual");
237
238
239
240
241
242
  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;
243
244
245
246
  castor::messages::AcsProxyDummy acs;
  castor::mediachanger::MmcProxyDummy mmc;
  castor::legacymsg::RmcProxyDummy rmc;
  castor::mediachanger::MediaChangerFacade mc(acs, mmc, rmc);
247
248
  castor::server::ProcessCap capUtils;
  castor::messages::TapeserverProxyDummy initialProcess;
249
  DataTransferSession sess("tapeHost", logger, mockSys,
250
    driveConfig, mc, initialProcess, capUtils, castorConf);
251
252
253
254
255
  sess.execute();
  simRun.wait();
  std::string temp = logger.getLog();
  temp += "";
  ASSERT_EQ("V12345", sess.getVid());
256
  ASSERT_EQ(SEINTERNAL, sim.m_sessionErrorCode);
257
}
258

259
TEST(tapeServer, DataTransferSessionNoSuchDrive) {
260
261
262
263
264
265
266
267
  // 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";
268
269
  client::ClientSimulator sim(volReq, vid, density,
    castor::tape::tapegateway::READ_TP, castor::tape::tapegateway::READ);
270
  client::ClientSimulator::ipPort clientAddr = sim.getCallbackAddress();
271
272
273
274
275
276
277
278
279
280
  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();
281
  DriveConfig driveConfig("T10D6116", "T10KD6", "/dev/noSuchTape", "manual");
282
283
284
  DataTransferConfig castorConf;
  castorConf.bufsz = 1024;
  castorConf.nbBufs = 10;
285
286
287
288
  castor::messages::AcsProxyDummy acs;
  castor::mediachanger::MmcProxyDummy mmc;
  castor::legacymsg::RmcProxyDummy rmc;
  castor::mediachanger::MediaChangerFacade mc(acs, mmc, rmc);
289
  castor::messages::TapeserverProxyDummy initialProcess;
290
  castor::server::ProcessCapDummy capUtils;
291
  DataTransferSession sess("tapeHost", logger, mockSys,
292
    driveConfig, mc, initialProcess, capUtils, castorConf);
293
294
295
296
297
  sess.execute();
  simRun.wait();
  std::string temp = logger.getLog();
  temp += "";
  ASSERT_NE(std::string::npos, logger.getLog().find("Drive not found on this path"));
298
  ASSERT_EQ(SEINTERNAL, sim.m_sessionErrorCode);
299
300
}

301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
TEST(tapeServer, DataTransferSessionFailtoMount) {
  // 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"], 
335
        "V12345");
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
    mockSys.fake.m_pathToDrive["/dev/nst0"]->rewind();
    // And write to it
    castor::tape::tapeserver::client::ClientInterface::VolumeInfo volInfo;
    volInfo.vid="V12345";
    volInfo.clientType=castor::tape::tapegateway::READ_TP;
    // Prepare a non-empty files to recall list to pass the empty session
    // detection
    for (int fseq=1; fseq <= 10 ; fseq ++) {
      castor::tape::tapegateway::FileToRecallStruct ftr;
      ftr.setFseq(fseq);
      ftr.setFileid(1000 + fseq);
      // Set the recall destination (/dev/null)
      ftr.setPath("/dev/null");
      // Record the file for recall, with an out of tape fSeq
      ftr.setFseq(ftr.fseq() + 1000);
      sim.addFileToRecall(ftr, 1000);
    }
  }
354
  DriveConfig driveConfig("T10D6116", "T10KD6", "/dev/tape_T10D6116", "manual");
355
356
357
358
359
360
361
362
363
364
365
366
  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;
367
  DataTransferSession sess("tapeHost", logger, mockSys,
368
369
370
371
372
373
    driveConfig, mc, initialProcess, capUtils, castorConf);
  sess.execute();
  simRun.wait();
  std::string temp = logger.getLog();
  temp += "";
  ASSERT_EQ("V12345", sess.getVid());
374
375
  // The session is now failing (internal error is reported)
  ASSERT_EQ(1015, sim.m_sessionErrorCode);
376
377
}

378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
TEST(tapeServer, DataTransferSessionEmptyOnVolReq) {
  // 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;
  
405
  DriveConfig driveConfig("T10D6116", "T10KD6", "/dev/tape_T10D6116", "manual");
406
407
408
409
410
411
412
413
414
415
416
417
  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;
418
  DataTransferSession sess("tapeHost", logger, mockSys,
419
420
421
422
423
424
425
426
427
428
429
430
    driveConfig, mc, initialProcess, capUtils, castorConf);
  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"));
}

431
class TempFileForData {
Eric Cano's avatar
Eric Cano committed
432
public:
433
  TempFileForData(size_t size): m_size(size) {
Eric Cano's avatar
Eric Cano committed
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
    // 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
452
      delete[] buff;
Eric Cano's avatar
Eric Cano committed
453
454
455
456
457
458
459
    } catch (...) {
      delete[] buff;
      unlink(m_path.c_str());
      throw;
    }
  }
  
460
  ~TempFileForData() {
Eric Cano's avatar
Eric Cano committed
461
462
463
464
465
466
467
468
469
470
    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;
};

471
class tempFileVector: public std::vector<TempFileForData *> {
Eric Cano's avatar
Eric Cano committed
472
473
474
475
476
477
478
479
480
481
public:
  ~tempFileVector() {
    while(size()) {
      delete back();
      pop_back();
    }
  }
};

struct expectedResult {
482
483
  expectedResult(int fs, uint32_t cs, int eCode = 0):
    fSeq(fs), checksum(cs), errorCode(eCode) {}
Eric Cano's avatar
Eric Cano committed
484
485
  int fSeq;
  uint32_t checksum;
486
  int errorCode;
Eric Cano's avatar
Eric Cano committed
487
488
};

489
TEST(tapeServer, DataTransferSessionGooddayMigration) {
Eric Cano's avatar
Eric Cano committed
490
491
492
493
494
495
496
497
498
499
500
  // 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";
501
502
  client::ClientSimulator sim(volReq, vid, density,
    castor::tape::tapegateway::WRITE_TP, castor::tape::tapegateway::WRITE);
Eric Cano's avatar
Eric Cano committed
503
504
505
506
507
508
509
510
511
512
513
514
515
516
  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 
517
  mockSys.fake.m_pathToDrive["/dev/nst0"] = new castor::tape::tapeserver::drive::FakeDrive;
Eric Cano's avatar
Eric Cano committed
518
519
520
  
  // Just label the tape
  castor::tape::tapeFile::LabelSession ls(*mockSys.fake.m_pathToDrive["/dev/nst0"], 
521
      "V12345");
Eric Cano's avatar
Eric Cano committed
522
523
524
525
526
527
528
  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
529
    std::unique_ptr<TempFileForData> tf(new TempFileForData(1000));
Eric Cano's avatar
Eric Cano committed
530
531
532
533
534
535
536
537
538
539
    // Prepare the migrationRequest
    castor::tape::tapegateway::FileToMigrateStruct ftm;
    ftm.setFileSize(tf->m_size);
    ftm.setFileid(1000 + fseq);
    ftm.setFseq(fseq);
    ftm.setPath(tf->path());
    sim.addFileToMigrate(ftm);
    expected.push_back(expectedResult(fseq, tf->checksum()));
    tempFiles.push_back(tf.release());
  }
540
  DriveConfig driveConfig("T10D6116", "T10KD6", "/dev/tape_T10D6116", "manual");
541
542
543
544
545
546
  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;
547
548
549
550
  castor::messages::AcsProxyDummy acs;
  castor::mediachanger::MmcProxyDummy mmc;
  castor::legacymsg::RmcProxyDummy rmc;
  castor::mediachanger::MediaChangerFacade mc(acs, mmc, rmc);
551
  castor::messages::TapeserverProxyDummy initialProcess;
552
  castor::server::ProcessCapDummy capUtils;
553
  DataTransferSession sess("tapeHost", logger, mockSys,
554
    driveConfig, mc, initialProcess, capUtils, castorConf);
Eric Cano's avatar
Eric Cano committed
555
556
  sess.execute();
  simRun.wait();
557
558
559
560
  for (std::vector<struct expectedResult>::iterator i = expected.begin();
      i != expected.end(); i++) {
    ASSERT_EQ(i->checksum, sim.m_receivedChecksums[i->fSeq]);
  }
561
  ASSERT_EQ(0, sim.m_sessionErrorCode);
Eric Cano's avatar
Eric Cano committed
562
563
}

564
565
566
567
/**
 * 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.
 */
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
TEST(tapeServer, DataTransferSessionMissingFilesMigration) {
  // 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 
596
  mockSys.fake.m_pathToDrive["/dev/nst0"] = new castor::tape::tapeserver::drive::FakeDrive;
597
598
599
  
  // Just label the tape
  castor::tape::tapeFile::LabelSession ls(*mockSys.fake.m_pathToDrive["/dev/nst0"], 
600
      "V12345");
601
602
603
604
605
  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
606
    std::unique_ptr<TempFileForData> tf(new TempFileForData(1000));
607
608
609
610
611
612
613
614
    // Prepare the migrationRequest
    castor::tape::tapegateway::FileToMigrateStruct ftm;
    ftm.setFileSize(tf->m_size);
    ftm.setFileid(1000 + fseq);
    ftm.setFseq(fseq);
    ftm.setPath(tf->path());
    sim.addFileToMigrate(ftm);
  }
615
  DriveConfig driveConfig("T10D6116", "T10KD6", "/dev/tape_T10D6116", "manual");
616
617
618
619
620
621
  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;
622
623
624
625
  castor::messages::AcsProxyDummy acs;
  castor::mediachanger::MmcProxyDummy mmc;
  castor::legacymsg::RmcProxyDummy rmc;
  castor::mediachanger::MediaChangerFacade mc(acs, mmc, rmc);
626
627
  castor::messages::TapeserverProxyDummy initialProcess;
  castor::server::ProcessCapDummy capUtils;
628
  DataTransferSession sess("tapeHost", logger, mockSys,
629
    driveConfig, mc, initialProcess, capUtils, castorConf);
630
631
  sess.execute();
  simRun.wait();
632
  ASSERT_EQ(SEINTERNAL, sim.m_sessionErrorCode);
633
}
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668

/**
 * 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(tapeServer, DataTransferSessionTapeFullMigration) {
  // 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;
669
  mockSys.fake.m_pathToDrive["/dev/nst0"] = new castor::tape::tapeserver::drive::FakeDrive(tapeSize);
670
671
672
  
  // Just label the tape
  castor::tape::tapeFile::LabelSession ls(*mockSys.fake.m_pathToDrive["/dev/nst0"], 
673
      "V12345");
674
675
676
677
678
679
680
681
682
683
  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;
684
    std::unique_ptr<TempFileForData> tf(new TempFileForData(fileSize));
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
    // Prepare the migrationRequest
    castor::tape::tapegateway::FileToMigrateStruct ftm;
    ftm.setFileSize(tf->m_size);
    ftm.setFileid(1000 + fseq);
    ftm.setFseq(fseq);
    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());
  }
702
  DriveConfig driveConfig("T10D6116", "T10KD6", "/dev/tape_T10D6116", "manual");
703
704
705
706
707
708
  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;
709
710
711
712
  castor::messages::AcsProxyDummy acs;
  castor::mediachanger::MmcProxyDummy mmc;
  castor::legacymsg::RmcProxyDummy rmc;
  castor::mediachanger::MediaChangerFacade mc(acs, mmc, rmc);
713
714
  castor::messages::TapeserverProxyDummy initialProcess;
  castor::server::ProcessCapDummy capUtils;
715
  DataTransferSession sess("tapeHost", logger, mockSys,
716
    driveConfig, mc, initialProcess, capUtils, castorConf);
717
718
719
720
721
722
723
724
725
726
  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]);
    }
  }
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
  ASSERT_EQ(ENOSPC, sim.m_sessionErrorCode);
}

TEST(tapeServer, DataTransferSessionTapeFullOnFlushMigration) {
  // 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"] =
760
761
      new castor::tape::tapeserver::drive::FakeDrive(tapeSize,
        castor::tape::tapeserver::drive::FakeDrive::OnFlush);
762
763
764
  
  // Just label the tape
  castor::tape::tapeFile::LabelSession ls(*mockSys.fake.m_pathToDrive["/dev/nst0"], 
765
      "V12345");
766
767
768
769
770
771
772
773
774
775
  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;
776
    std::unique_ptr<TempFileForData> tf(new TempFileForData(fileSize));
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
    // Prepare the migrationRequest
    castor::tape::tapegateway::FileToMigrateStruct ftm;
    ftm.setFileSize(tf->m_size);
    ftm.setFileid(1000 + fseq);
    ftm.setFseq(fseq);
    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());
  }
794
  DriveConfig driveConfig("T10D6116", "T10KD6", "/dev/tape_T10D6116", "manual");
795
796
797
798
799
800
  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;
801
802
803
804
  castor::messages::AcsProxyDummy acs;
  castor::mediachanger::MmcProxyDummy mmc;
  castor::legacymsg::RmcProxyDummy rmc;
  castor::mediachanger::MediaChangerFacade mc(acs, mmc, rmc);
805
806
  castor::messages::TapeserverProxyDummy initialProcess;
  castor::server::ProcessCapDummy capUtils;
807
  DataTransferSession sess("tapeHost", logger, mockSys,
808
    driveConfig, mc, initialProcess, capUtils, castorConf);
809
810
811
812
813
814
815
816
817
818
819
  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);
820
821
}

822
} // namespace unitTest