StructuresTest.cpp 51.1 KB
Newer Older
1
2
/*
 * @project        The CERN Tape Archive (CTA)
3
 * @copyright      Copyright(C) 2003-2021 CERN
4
5
6
7
 * @license        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 3 of the License, or
 *                 (at your option) any later version.
8
 *
9
10
11
12
 *                 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.
13
 *
14
15
16
 *                 You should have received a copy of the GNU General Public License
 *                 along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
17
18
19

#include <gtest/gtest.h>
#include <gmock/gmock-cardinalities.h>
20
21
#include "Device.hpp"
#include "Structures.hpp"
22
#include "../system/Wrapper.hpp"
23
#include "Exception.hpp"
24
25
26
27
28

using ::testing::AtLeast;
using ::testing::Return;
using ::testing::_;

29
namespace unitTests {
30
  TEST(castor_tape_SCSI_Structures, inquiryData_t_multi_byte_numbers_strings) {
31
32
33
34
35
    /* Validate the bit field behavior of the struct inquiryData_t,
     which represents the standard INQUIRY data format as defined in 
     SPC-4. This test also validates the handling of multi-bytes numbers,
     as SCSI structures are big endian (and main development target is 
     little endian.  */
sponcec3's avatar
sponcec3 committed
36
37
38
    castor::tape::SCSI::Structures::inquiryData_t inq;
    unsigned char *inqBuff = (unsigned char*)&inq;
    memset(inqBuff, 0, sizeof(inq));
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
    /* Peripheral device type */
    ASSERT_EQ(0, inq.perifDevType);
    inqBuff[0] |= (0x1A & 0x1F) << 0;
    ASSERT_EQ(0x1A, inq.perifDevType);
    
    /* Peripheral qualifier */
    ASSERT_EQ(0, inq.perifQualifyer);
    inqBuff[0] |= (0x5 & 0x7) << 5;
    ASSERT_EQ(0x5, inq.perifQualifyer);
    
    /* ... */
    /* sampling of bits */
    ASSERT_EQ(0, inq.VS1);
    inqBuff[6] |= (0x1 & 0x1) << 5;
    ASSERT_EQ(1, inq.VS1);
    
    ASSERT_EQ(0, inq.sync);
    inqBuff[7] |= (0x1 & 0x1) << 4;
    ASSERT_EQ(1, inq.sync);
    
59
    /* Test of strings: empty/full/boundary effect with next record */
60
    ASSERT_EQ("", castor::tape::SCSI::Structures::toString(inq.T10Vendor));
61
62
63
64
65
66
67
    inqBuff[8] = 'V';
    inqBuff[9] = 'i';
    inqBuff[10] = 'r';
    inqBuff[11] = 't';
    inqBuff[12] = 'u';
    inqBuff[13] = 'a';
    inqBuff[14] = 'l';
68
    inqBuff[15] = 's';
69
    ASSERT_EQ("Virtuals", castor::tape::SCSI::Structures::toString(inq.T10Vendor));
70
    
71
72
    /* Check there is no side effect from next record */
    inqBuff[16] = 'X';
73
74
    inqBuff[17] = 'Y';
    inqBuff[18] = 'Z';
75
    ASSERT_EQ("Virtuals", castor::tape::SCSI::Structures::toString(inq.T10Vendor));
76
    ASSERT_EQ("XYZ", castor::tape::SCSI::Structures::toString(inq.prodId));
77
78
79
80
81
82
83
84
85
86
            
    /* Check that non-full record does not yield too long a string */
    inqBuff[8] = 'T';
    inqBuff[9] = 'a';
    inqBuff[10] = 'p';
    inqBuff[11] = 'e';
    inqBuff[12] = 's';
    inqBuff[13] = '\0';
    inqBuff[14] = '\0';
    inqBuff[15] = '\0';
87
    ASSERT_EQ("Tapes", castor::tape::SCSI::Structures::toString(inq.T10Vendor));
88

89
    /* Test of endian conversion */
90
    ASSERT_EQ(0, castor::tape::SCSI::Structures::toU16(inq.versionDescriptor[7]));
91
92
    inqBuff[72] = 0xCA;
    inqBuff[73] = 0xFE;
93
    ASSERT_EQ(0xCAFE, castor::tape::SCSI::Structures::toU16(inq.versionDescriptor[7]));
94
95
96
97
98
99
100
    
    /* Test last element */
    ASSERT_EQ(0, *inq.vendorSpecific2);
    inqBuff[96] = 0x12;
    ASSERT_EQ(0x12, *inq.vendorSpecific2);
  }

101
  TEST(castor_tape_SCSI_Structures, inquiryCDB_t) {
102
    castor::tape::SCSI::Structures::inquiryCDB_t inqCDB;
103
104
    unsigned char *buff = (unsigned char *)&inqCDB;
    
105
106
107
108
    /*
     * Make sure this struct is a POD (plain old data without virtual table)
     * (and has the right size).
     */
109
    ASSERT_EQ(6U, sizeof(inqCDB));
110
    
111
    ASSERT_EQ(castor::tape::SCSI::Commands::INQUIRY, inqCDB.opCode);
112
113
    buff[0] = 0;
    ASSERT_EQ(0, inqCDB.opCode);
114
115
116
117
118
119
120
121
122
    
    ASSERT_EQ(0, inqCDB.EVPD);
    buff[1] = 0x1;
    ASSERT_EQ(1, inqCDB.EVPD);
    
    ASSERT_EQ(0, inqCDB.control);
    buff[5] = 0xCA;
    ASSERT_EQ(0xCA, inqCDB.control);
  }
123
  
124
    TEST(castor_tape_SCSI_Structures, inquiryUnitSerialNumberData_t) {
125
    castor::tape::SCSI::Structures::inquiryUnitSerialNumberData_t inqSerialNumber;
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
    unsigned char *buff = (unsigned char *)&inqSerialNumber;
    
    /*
     * Make sure this struct is a POD (plain old data without virtual table)
     * (and has the right size).
     */
    ASSERT_EQ(16U, sizeof(inqSerialNumber));
       
    ASSERT_EQ(0, inqSerialNumber.peripheralDeviceType);
    buff[0] |= (0x15 & 0x1F) << 0;
    ASSERT_EQ(0x15, inqSerialNumber.peripheralDeviceType);
    
    ASSERT_EQ(0, inqSerialNumber.peripheralQualifier);
    buff[0] |= (0x5 & 0x7) <<5;
    ASSERT_EQ(0x5,inqSerialNumber.peripheralQualifier);
    
    ASSERT_EQ(0, inqSerialNumber.pageCode);
    buff[1] |= 0xAB ;
    ASSERT_EQ(0xAB, inqSerialNumber.pageCode);
    
    buff[2] |= 0xFF;
    ASSERT_EQ(0, inqSerialNumber.pageLength);
    buff[3] |= 0xCD ;
    ASSERT_EQ(0xCD, inqSerialNumber.pageLength);
    
151
    ASSERT_EQ("", castor::tape::SCSI::Structures::toString(inqSerialNumber.productSerialNumber));
152
153
    const char serialNumber[13] = "XYZZY_A2    ";
    memcpy(&buff[4],serialNumber,12);
154
    ASSERT_EQ("XYZZY_A2    ", castor::tape::SCSI::Structures::toString(inqSerialNumber.productSerialNumber));
155
156
  }
  
157
  TEST(castor_tape_SCSI_Structures, logSelectCDB_t) {
158
    castor::tape::SCSI::Structures::logSelectCDB_t logSelectCDB;
159
160
161
162
163
164
    unsigned char *buff = (unsigned char *)&logSelectCDB;
    
    /*
     * Make sure this struct is a POD (plain old data without virtual table)
     * (and has the right size).
     */
165
    ASSERT_EQ(10U, sizeof(logSelectCDB));
166
    
167
    ASSERT_EQ(castor::tape::SCSI::Commands::LOG_SELECT, logSelectCDB.opCode);
168
169
170
171
172
173
174
175
176
177
178
179
180
181
    buff[0] = 0xAB;
    ASSERT_EQ(0xAB, logSelectCDB.opCode);
    buff[1] |= (0x1 & 0x7) << 0;
    ASSERT_EQ(1, logSelectCDB.SP);
    buff[1] |= (0x1 & 0xF) << 1;
    ASSERT_EQ(1, logSelectCDB.PCR);
    buff[2] |= 0xAB << 2 >> 2;  
    ASSERT_EQ(0x2B, logSelectCDB.pageCode);
    buff[2] |= 0x70 << 1;
    ASSERT_EQ(0x3, logSelectCDB.PC);
    buff[3] |= 0xBC;
    ASSERT_EQ(0xBC, logSelectCDB.subPageCode);
    /* ... */
    buff[7] |= 0xAB; buff[8] |= 0xCD;
182
    ASSERT_EQ(0xABCD, castor::tape::SCSI::Structures::toU16(logSelectCDB.parameterListLength));
183
184
185
    buff[9] |= 0xBC;
    ASSERT_EQ(0xBC, logSelectCDB.control);
  }
186

187
  TEST(castor_tape_SCSI_Structures, LinuxSGIO_t) {
188
189
    ASSERT_EQ(sizeof(sg_io_hdr_t), sizeof(castor::tape::SCSI::Structures::LinuxSGIO_t));
    castor::tape::SCSI::Structures::LinuxSGIO_t lsg;
190
191
192
193
    /* Most important part: check that the class does not add data
     to the original structure (virtual table, for example)*/
    sg_io_hdr_t & sgio_hdr = *(sg_io_hdr_t *)&lsg;
    /* Also make sure the constructor does its initialization job */
194
    ASSERT_EQ(900000U, sgio_hdr.timeout);
195
196
197
198
    ASSERT_EQ('S', sgio_hdr.interface_id);
    /* The rest is safe. It's just a struct with added functions */
  }

199
  TEST(castor_tape_SCSI_Structures, logSenseCDB_t) {
200
    castor::tape::SCSI::Structures::logSenseCDB_t logSenseCDB;
201
202
203
204
205
206
    unsigned char *buff = (unsigned char *)&logSenseCDB;
    
    /*
     * Make sure this struct is a POD (plain old data without virtual table)
     * (and has the right size).
     */
207
    ASSERT_EQ(10U, sizeof(logSenseCDB));
208
209
210
    
    /* Check proper initialization an location of struct members match
     the bit/byte locations defined in SPC-4 */
211
    ASSERT_EQ(castor::tape::SCSI::Commands::LOG_SENSE, logSenseCDB.opCode);
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
    buff[0] = 0xAB;
    ASSERT_EQ(0xAB, logSenseCDB.opCode);
    
    ASSERT_EQ(0, logSenseCDB.SP);
    buff[1] |= (0x1 &   0x7) << 0;
    ASSERT_EQ(1, logSenseCDB.SP);
    
    ASSERT_EQ(0, logSenseCDB.PPC);
    buff[1] |= (0x1 &   0xF) << 1;
    ASSERT_EQ(1, logSenseCDB.PPC);
    
    ASSERT_EQ(0, logSenseCDB.pageCode);
    buff[2] |= (0xAB & 0x3F) << 0;  
    ASSERT_EQ(0x2B, logSenseCDB.pageCode);
    
    ASSERT_EQ(0, logSenseCDB.PC);
    buff[2] |= (0x2 &   0x3) << 6;
    ASSERT_EQ(0x2, logSenseCDB.PC);
    
    ASSERT_EQ(0, logSenseCDB.subPageCode);
    buff[3] = 0xBC;
    ASSERT_EQ(0xBC, logSenseCDB.subPageCode);
    
235
    ASSERT_EQ(0, castor::tape::SCSI::Structures::toU16(logSenseCDB.parameterPointer));
236
    buff[5] = 0x12; buff[6] = 0x34;
237
    ASSERT_EQ(0x1234, castor::tape::SCSI::Structures::toU16(logSenseCDB.parameterPointer));
238
    
239
    ASSERT_EQ(0, castor::tape::SCSI::Structures::toU16(logSenseCDB.allocationLength));
240
    buff[7] |= 0xAB; buff[8] |= 0xCD;
241
    ASSERT_EQ(0xABCD, castor::tape::SCSI::Structures::toU16(logSenseCDB.allocationLength));
242
243
244
245
246
247
    
    ASSERT_EQ(0, logSenseCDB.control);
    buff[9] |= 0xBC;
    ASSERT_EQ(0xBC, logSenseCDB.control);
  }
  
248
  TEST(castor_tape_SCSI_Structures, locate10CDB_t) {
249
    castor::tape::SCSI::Structures::locate10CDB_t locate10CDB;
250
251
252
253
254
255
    unsigned char *buff = (unsigned char *)&locate10CDB;
    
    /*
     * Make sure this struct is a POD (plain old data without virtual table)
     * (and has the right size).
     */
256
    ASSERT_EQ(10U, sizeof(locate10CDB));  // that is why it called locate 10
257
258
259
    
    /* Check proper initialization an location of struct members match
     the bit/byte locations defined in SPC-4 */
260
    ASSERT_EQ(castor::tape::SCSI::Commands::LOCATE_10, locate10CDB.opCode);
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
    buff[0] = 0xAB;
    ASSERT_EQ(0xAB, locate10CDB.opCode);
    
    ASSERT_EQ(0, locate10CDB.IMMED);
    buff[1] |= (0x1 &   0x7) << 0;
    ASSERT_EQ(1, locate10CDB.IMMED);
    
    ASSERT_EQ(0, locate10CDB.CP);
    buff[1] |= (0x1 &   0xF) << 1;
    ASSERT_EQ(1, locate10CDB.CP);
    
    ASSERT_EQ(0, locate10CDB.BT);
    buff[1] |= (0x1 &   0xF) << 2;  
    ASSERT_EQ(1, locate10CDB.BT);
    
276
    ASSERT_EQ(0U, castor::tape::SCSI::Structures::toU32(locate10CDB.logicalObjectID));
277
    buff[3] |= 0x0A;buff[4] |= 0xBC;buff[5] |= 0xDE;buff[6] |= 0xF0;
278
    ASSERT_EQ(0x0ABCDEF0U, castor::tape::SCSI::Structures::toU32(locate10CDB.logicalObjectID));
279
280
281
282
283
284
285
286
287
288
    
    ASSERT_EQ(0, locate10CDB.partition);
    buff[8] = 0xAB;
    ASSERT_EQ(0xAB, locate10CDB.partition);
       
    ASSERT_EQ(0, locate10CDB.control);
    buff[9] |= 0xBC;
    ASSERT_EQ(0xBC, locate10CDB.control);
  }
  
289
  TEST(castor_tape_SCSI_Structures, readPositionCDB_t) {
290
    castor::tape::SCSI::Structures::readPositionCDB_t readPositionCDB;
291
292
293
294
295
    unsigned char *buff = (unsigned char *)&readPositionCDB;  
    /*
     * Make sure this struct is a POD (plain old data without virtual table)
     * (and has the right size).
     */
296
    ASSERT_EQ(10U, sizeof(readPositionCDB)); 
297
298
299
    
    /* Check proper initialization an location of struct members match
     the bit/byte locations defined in SPC-4 */
300
    ASSERT_EQ(castor::tape::SCSI::Commands::READ_POSITION, readPositionCDB.opCode);
301
302
303
304
305
306
307
308
309
    buff[0] = 0xAB;
    ASSERT_EQ(0xAB, readPositionCDB.opCode);
    
    ASSERT_EQ(0, readPositionCDB.serviceAction);
    buff[1] |= (0x15 &   0xFF) << 0;
    ASSERT_EQ(0x15, readPositionCDB.serviceAction);
    
    buff[2] |= 0xFF; buff[3] = 0xFF; buff[4] = 0xFF; buff[5] = 0xFF; buff[6] = 0xFF;
    
Eric Cano's avatar
Eric Cano committed
310
    ASSERT_EQ(0, castor::tape::SCSI::Structures::toU16(readPositionCDB.allocationLength));
311
    buff[7] |= 0x0A;buff[8] |= 0xBC;
Eric Cano's avatar
Eric Cano committed
312
    ASSERT_EQ(0x0ABC, castor::tape::SCSI::Structures::toU16(readPositionCDB.allocationLength));
313
314
315
316
317
318
           
    ASSERT_EQ(0, readPositionCDB.control);
    buff[9] |= 0xBC;
    ASSERT_EQ(0xBC, readPositionCDB.control);
  }
  
319
   TEST(castor_tape_SCSI_Structures, readPositionDataShortForm_t) {
320
    castor::tape::SCSI::Structures::readPositionDataShortForm_t readPositionData;
321
322
    unsigned char *buff = (unsigned char *)&readPositionData;  

323
    ASSERT_EQ(20U, sizeof(readPositionData)); 
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
352
    
    ASSERT_EQ(0, readPositionData.BPEW);
    buff[0] |= (0x1 &   0xFF) << 0;
    ASSERT_EQ(0x1, readPositionData.BPEW);
    ASSERT_EQ(0, readPositionData.PERR);
    buff[0] |= (0x2 &   0xFF) << 0;
    ASSERT_EQ(0x1, readPositionData.PERR);
    ASSERT_EQ(0, readPositionData.LOLU);
    buff[0] |= (0x4 &   0xFF) << 0;
    ASSERT_EQ(0x1, readPositionData.LOLU);
    ASSERT_EQ(0, readPositionData.BYCU);
    buff[0] |= (0x10 &   0xFF) << 0;
    ASSERT_EQ(0x1, readPositionData.BYCU);
    ASSERT_EQ(0, readPositionData.LOCU);
    buff[0] |= (0x20 &   0xFF) << 0;
    ASSERT_EQ(0x1, readPositionData.LOCU);
    ASSERT_EQ(0, readPositionData.EOP);
    buff[0] |= (0x40 &   0xFF) << 0;
    ASSERT_EQ(0x1, readPositionData.EOP);
    ASSERT_EQ(0, readPositionData.BOP);
    buff[0] |= (0x80 &   0xFF) << 0;
    ASSERT_EQ(0x1, readPositionData.BOP);
    
    ASSERT_EQ(0, readPositionData.partitionNumber);
    buff[1] |= 0xBC;
    ASSERT_EQ(0xBC, readPositionData.partitionNumber);
        
    buff[2] |= 0xFF; buff[3] = 0xFF;
    
353
    ASSERT_EQ(0U, castor::tape::SCSI::Structures::toU32(readPositionData.firstBlockLocation));
354
    buff[4] |= 0x0A;buff[5] |= 0xBC;buff[6] |= 0xDE;buff[7] |= 0xF0;
355
    ASSERT_EQ(0x0ABCDEF0U, castor::tape::SCSI::Structures::toU32(readPositionData.firstBlockLocation));
356
    
357
    ASSERT_EQ(0U, castor::tape::SCSI::Structures::toU32(readPositionData.lastBlockLocation));
358
    buff[8] |= 0x9A;buff[9] |= 0xBC;buff[10] |= 0xDE;buff[11] |= 0xF9;
359
    ASSERT_EQ(0x9ABCDEF9U, castor::tape::SCSI::Structures::toU32(readPositionData.lastBlockLocation));
360
    buff[12] |= 0xFF;
361
    ASSERT_EQ(0U, castor::tape::SCSI::Structures::toU32(readPositionData.blocksInBuffer));
362
    buff[13] |= 0x9A;buff[14] |= 0xBC;buff[15] |= 0xDE;
363
    ASSERT_EQ(0x009ABCDEU, castor::tape::SCSI::Structures::toU32(readPositionData.blocksInBuffer));
364
           
365
    ASSERT_EQ(0U, castor::tape::SCSI::Structures::toU32(readPositionData.bytesInBuffer));
366
    buff[16] |= 0x7A;buff[17] |= 0xBC;buff[18] |= 0xDE;buff[19] |= 0xF7;
367
    ASSERT_EQ(0x7ABCDEF7U, castor::tape::SCSI::Structures::toU32(readPositionData.bytesInBuffer));
368
369
  }
  
370
  TEST(castor_tape_SCSI_Structures, modeSelect6CDB_t) {
371
    castor::tape::SCSI::Structures::modeSelect6CDB_t modeSelect6CDB;
372
373
374
375
376
    unsigned char *buff = (unsigned char *)&modeSelect6CDB;  
    /*
     * Make sure this struct is a POD (plain old data without virtual table)
     * (and has the right size).
     */
377
    ASSERT_EQ(6U, sizeof(modeSelect6CDB)); 
378
379
380
    
    /* Check proper initialization an location of struct members match
     the bit/byte locations defined in SPC-4 */
381
    ASSERT_EQ(castor::tape::SCSI::Commands::MODE_SELECT_6, modeSelect6CDB.opCode);
382
    buff[0] = 0xAB;
383
    ASSERT_EQ(0xABU, modeSelect6CDB.opCode);
384
385
386
    
    ASSERT_EQ(0, modeSelect6CDB.SP);
    buff[1] |= (0x1 &   0xFF) << 0;
387
    ASSERT_EQ(0x1U, modeSelect6CDB.SP);
388
    
389
    ASSERT_EQ(0U, modeSelect6CDB.PF);
390
    buff[1] |= (0x10 &   0xFF) << 0;
391
    ASSERT_EQ(0x1U, modeSelect6CDB.PF);
392
393
394
    
    buff[2] |= 0xFF; buff[3] = 0xFF; 
    
395
    ASSERT_EQ(0U, modeSelect6CDB.paramListLength);
396
    buff[4] |= 0xBC;
397
    ASSERT_EQ(0xBCU, modeSelect6CDB.paramListLength);
398
399
400
401
402
403
           
    ASSERT_EQ(0, modeSelect6CDB.control);
    buff[5] |= 0xAB;
    ASSERT_EQ(0xAB, modeSelect6CDB.control);
  }
  
404
  TEST(castor_tape_SCSI_Structures, modeSense6CDB_t) {
405
    castor::tape::SCSI::Structures::modeSense6CDB_t modeSense6CDB;
406
407
408
409
410
    unsigned char *buff = (unsigned char *)&modeSense6CDB;  
    /*
     * Make sure this struct is a POD (plain old data without virtual table)
     * (and has the right size).
     */
411
    ASSERT_EQ(6U, sizeof(modeSense6CDB)); 
412
413
414
    
    /* Check proper initialization an location of struct members match
     the bit/byte locations defined in SPC-4 */
415
    ASSERT_EQ(castor::tape::SCSI::Commands::MODE_SENSE_6, modeSense6CDB.opCode);
416
    buff[0] = 0xAB;
417
    ASSERT_EQ(0xABU, modeSense6CDB.opCode);
418
419
420
    
    ASSERT_EQ(0, modeSense6CDB.DBD);
    buff[1] |= (0x8 &   0xFF) << 0;
421
    ASSERT_EQ(0x1U, modeSense6CDB.DBD);
422
    
423
    ASSERT_EQ(0U, modeSense6CDB.pageCode);
424
    buff[2] |= (0x2A &   0xFF) << 0;
425
    ASSERT_EQ(0x2AU,  modeSense6CDB.pageCode);
426
    
427
    ASSERT_EQ(0u, modeSense6CDB.PC);
428
    buff[2] |= (0x8B &   0xFF) << 0;
429
    ASSERT_EQ(0x2U,  modeSense6CDB.PC);
430
    
431
    ASSERT_EQ(0U,  modeSense6CDB.subPageCode);
432
    buff[3] |= 0xBC;
433
    ASSERT_EQ(0xBCU, modeSense6CDB.subPageCode);
434
           
435
    ASSERT_EQ(0U, modeSense6CDB.allocationLength);
436
    buff[4] |= 0xAB;
437
    ASSERT_EQ(0xABU, modeSense6CDB.allocationLength);
438
    
439
    ASSERT_EQ(0U, modeSense6CDB.control);
440
    buff[5] |= 0xCD;
441
    ASSERT_EQ(0xCDU, modeSense6CDB.control);
442
443
  }  
  
444
  TEST(castor_tape_SCSI_Structures, modeSenseDeviceConfiguration_t) {
445
    castor::tape::SCSI::Structures::modeSenseDeviceConfiguration_t devConfig;
446
447
448
449
450
    unsigned char *buff = (unsigned char *)&devConfig;  
    /*
     * Make sure this struct is a POD (plain old data without virtual table)
     * (and has the right size).
     */
451
452
453
454
    ASSERT_EQ(28U, sizeof(devConfig));
    ASSERT_EQ(4U, sizeof(devConfig.header));
    ASSERT_EQ(8U, sizeof(devConfig.blockDescriptor));
    ASSERT_EQ(16U, sizeof(devConfig.modePage));
455
456
    
    /* We will only check used by us parameters */
457
    ASSERT_EQ(0U, devConfig.header.modeDataLength);
458
    buff[0] |= 0xAB;
459
    ASSERT_EQ(0xABU, devConfig.header.modeDataLength);
460
461
    
    buff[1] = buff[2] = buff[3] = 0xFF;
462
    ASSERT_EQ(0U, devConfig.blockDescriptor.densityCode);
463
    buff[4] |= 0xCD;
464
    ASSERT_EQ(0xCDU, devConfig.blockDescriptor.densityCode);
465
466
    
    for(int i=5;i<26;i++) buff[i] = 0xFF; // fill the space
467
    ASSERT_EQ(0U, devConfig.modePage.selectDataComprAlgorithm );
468
    buff[26] |= 0xEF;
469
    ASSERT_EQ(0xEFU, devConfig.modePage.selectDataComprAlgorithm);
470
  }  
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
  TEST(castor_tape_SCSI_Structures, modeSenseControlDataProtection_t) {
    castor::tape::SCSI::Structures::modeSenseControlDataProtection_t dataProt;
    unsigned char *buff = (unsigned char *)&dataProt;  
    /*
     * Make sure this struct is a POD (plain old data without virtual table)
     * (and has the right size).
     */
    ASSERT_EQ(44U, sizeof(dataProt));
    ASSERT_EQ(4U, sizeof(dataProt.header));
    ASSERT_EQ(8U, sizeof(dataProt.blockDescriptor));
    ASSERT_EQ(32U, sizeof(dataProt.modePage));
    
    /* We will only check used by us parameters */
    ASSERT_EQ(0U, dataProt.header.modeDataLength);
    buff[0] |= 0xAC;
    ASSERT_EQ(0xACU, dataProt.header.modeDataLength);
    
    for(int i=1;i<=15;i++) buff[i] = 0xFF; // fill the space
    ASSERT_EQ(0U, dataProt.modePage.LBPMethod );
    buff[16] |= 0xEF;
    ASSERT_EQ(0xEFU, dataProt.modePage.LBPMethod );
    ASSERT_EQ(0U, dataProt.modePage.LBPInformationLength );
    buff[17] |= 0xDF;
    ASSERT_EQ(0x1FU, dataProt.modePage.LBPInformationLength );
    ASSERT_EQ(0U, dataProt.modePage.LBP_W );
    buff[18] |= 0x8F;
    ASSERT_EQ(0x1U, dataProt.modePage.LBP_W );
    ASSERT_EQ(0U, dataProt.modePage.LBP_R );
    buff[18] |= 0x4F;
    ASSERT_EQ(0x1U, dataProt.modePage.LBP_R );
  }  
    
503
  TEST(castor_tape_SCSI_Structures, tapeAlertLogPage_t_and_parameters) {
504
    castor::tape::SCSI::Structures::tapeAlertLogPage_t<12> tal;
505
506
507
508
    unsigned char * buff = (unsigned char *) & tal;
    
    /* Check the size of the structure (header is 4 bytes, array elements, 5.*/
    /* As usual, this ensures we have POD */
509
    ASSERT_EQ(4U + 12U*5U, sizeof(tal));
510
    
511
    ASSERT_EQ(0U, tal.pageCode);
512
    buff[0] |= (0x12 & 0x3F) << 0;
513
    ASSERT_EQ(0x12U, tal.pageCode);
514
    
515
    ASSERT_EQ(0U,tal.subPageCode);
516
    buff[1] = 0x34;
517
    ASSERT_EQ(0x34U, tal.subPageCode);
518
519
    
    /* Simulate 123 records = 600 bytes = 0x267 */
520
    ASSERT_EQ(0U, castor::tape::SCSI::Structures::toU16(tal.pageLength));
521
    buff[2] = 0x2; buff[3]= 0x67;
522
    ASSERT_EQ(0x267U, castor::tape::SCSI::Structures::toU16(tal.pageLength));
523
    /* The page length is counted in bytes. We are interested in the number of parameters*/
524
    ASSERT_EQ(123U, tal.parameterNumber());
525
    
526
    ASSERT_EQ(0U, castor::tape::SCSI::Structures::toU16(tal.parameters[0].parameterCode));
527
    buff [4] = 0xCA; buff[5] = 0xFE;
528
    ASSERT_EQ(0xCAFEU, castor::tape::SCSI::Structures::toU16(tal.parameters[0].parameterCode));
529
    
530
    ASSERT_EQ(0U, tal.parameters[11].flag);
531
    buff[3+12*5] |= (0x1) << 0;
532
    ASSERT_EQ(1U, tal.parameters[11].flag);
533
534
  }
  
535
  TEST(castor_tape_SCSI_Structures, senseBuffer_t) {
536
    castor::tape::SCSI::Structures::senseData_t<255> sense;
Eric Cano's avatar
Eric Cano committed
537
538
539
540
    unsigned char * buff = (unsigned char *) & sense;
    
    /* Check the total size of the structure, plus the one of each of the members
     of the union */
541
542
543
    ASSERT_EQ(255U, sizeof(sense));
    ASSERT_EQ(255U - 1U, sizeof(sense.descriptorFormat));
    ASSERT_EQ(255U - 1U, sizeof(sense.fixedFormat));
Eric Cano's avatar
Eric Cano committed
544
545
    
    buff[0] = 0x70;
546
    buff[2] = 0xFE;
Eric Cano's avatar
Eric Cano committed
547
548
549
    buff[12] = 0x12;
    buff[13] = 0x34;
    ASSERT_EQ(true, sense.isCurrent());
Steven Murray's avatar
Steven Murray committed
550
    ASSERT_FALSE(sense.isDeferred());
Eric Cano's avatar
Eric Cano committed
551
    ASSERT_EQ(true, sense.isFixedFormat());
Steven Murray's avatar
Steven Murray committed
552
    ASSERT_FALSE(sense.isDescriptorFormat());
Eric Cano's avatar
Eric Cano committed
553
554
    ASSERT_EQ(0x12, sense.getASC());
    ASSERT_EQ(0x34, sense.getASCQ());
555
556
    ASSERT_EQ(0xE, sense.getSenseKey());
    ASSERT_EQ("Miscompare", sense.getSenseKeyString());
Eric Cano's avatar
Eric Cano committed
557
558
    
    buff[0] = 0x71;
559
    buff[2] = 0xFA;
Eric Cano's avatar
Eric Cano committed
560
561
    buff[12] = 0x12;
    buff[13] = 0x34;
Steven Murray's avatar
Steven Murray committed
562
    ASSERT_FALSE(sense.isCurrent());
563
    ASSERT_EQ(true, sense.isDeferred());
Eric Cano's avatar
Eric Cano committed
564
    ASSERT_EQ(true, sense.isFixedFormat());
Steven Murray's avatar
Steven Murray committed
565
    ASSERT_FALSE(sense.isDescriptorFormat());
Eric Cano's avatar
Eric Cano committed
566
567
    ASSERT_EQ(0x12, sense.getASC());
    ASSERT_EQ(0x34, sense.getASCQ());
568
569
    ASSERT_EQ(0xA, sense.getSenseKey());
    ASSERT_EQ("Copy Aborted", sense.getSenseKeyString());
Eric Cano's avatar
Eric Cano committed
570
571
    
    buff[0] = 0x72;
572
    buff[1] = 0xFB;
Eric Cano's avatar
Eric Cano committed
573
574
575
    buff[2] = 0x56;
    buff[3] = 0x78;
    ASSERT_EQ(true, sense.isCurrent());
Steven Murray's avatar
Steven Murray committed
576
577
    ASSERT_FALSE(sense.isDeferred());
    ASSERT_FALSE(sense.isFixedFormat());
Eric Cano's avatar
Eric Cano committed
578
579
580
    ASSERT_EQ(true, sense.isDescriptorFormat());
    ASSERT_EQ(0x56, sense.getASC());
    ASSERT_EQ(0x78, sense.getASCQ());
581
582
    ASSERT_EQ(0xB, sense.getSenseKey());
    ASSERT_EQ("Aborted Command", sense.getSenseKeyString());
Eric Cano's avatar
Eric Cano committed
583
584
    
    buff[0] = 0x73;
585
    buff[1] = 0xFC;
586
587
    buff[2] = 0x0b;
    buff[3] = 0x08;
Steven Murray's avatar
Steven Murray committed
588
    ASSERT_FALSE(sense.isCurrent());
589
    ASSERT_EQ(true, sense.isDeferred());
Steven Murray's avatar
Steven Murray committed
590
    ASSERT_FALSE(sense.isFixedFormat());
Eric Cano's avatar
Eric Cano committed
591
    ASSERT_EQ(true, sense.isDescriptorFormat());
592
593
    ASSERT_EQ(0x0b, sense.getASC());
    ASSERT_EQ(0x08, sense.getASCQ());
594
    ASSERT_EQ(0xC, sense.getSenseKey());
595
    ASSERT_EQ("Warning - power loss expected", sense.getACSString());
596
    ASSERT_EQ("Equal", sense.getSenseKeyString());
597
598
599
600
601
602
603
604
    
    buff[2] = 0x40;
    buff[3] = 0xab;
    ASSERT_EQ("Diagnostic failure on component (ab)", sense.getACSString());
    
    buff[2] = 0x00;
    buff[3] = 0x1F;
    ASSERT_EQ("Unknown ASC/ASCQ:00/1f", sense.getACSString());
Eric Cano's avatar
Eric Cano committed
605
    
606
    buff[1] = 0xF;
607
    ASSERT_THROW(sense.getSenseKeyString(), cta::exception::Exception);
608
    
Eric Cano's avatar
Eric Cano committed
609
    buff[0] = 0x74;
610
    ASSERT_THROW(sense.getASC(), cta::exception::Exception);
611
    
612
    ASSERT_THROW(sense.getACSString(), cta::exception::Exception);
613
614
    
    try { sense.getACSString(); ASSERT_TRUE(false); }
615
    catch (cta::exception::Exception & ex) {
616
      std::string what(ex.getMessageValue());
617
618
      ASSERT_NE(std::string::npos, what.find("response code not supported (0x74)"));
    }
619
620
    
    buff[1] = 0xA;
621
622
    ASSERT_THROW(sense.getSenseKey(), cta::exception::Exception);
    ASSERT_THROW(sense.getSenseKeyString(), cta::exception::Exception);
623
    try { sense.getSenseKey(); ASSERT_TRUE(false); }
624
    catch (cta::exception::Exception & ex) {
625
626
627
628
      std::string what(ex.getMessageValue());
      ASSERT_NE(std::string::npos, what.find("response code not supported (0x74)"));
    }
    try { sense.getSenseKeyString(); ASSERT_TRUE(false); }
629
    catch (cta::exception::Exception & ex) {
630
631
632
      std::string what(ex.getMessageValue());
      ASSERT_NE(std::string::npos, what.find("response code not supported (0x74)"));
    }
Eric Cano's avatar
Eric Cano committed
633
  }
634
  
635
  TEST(castor_tape_SCSI_Structures, toU16) {
636
    unsigned char num[2] = { 0x1, 0x2 };
637
    ASSERT_EQ( 0x102, castor::tape::SCSI::Structures::toU16(num));
638
639
  }
  
640
  TEST(castor_tape_SCSI_Structures, toU32) {
641
    unsigned char num[4] = { 0x1, 0x2, 0x3, 0x4 };
642
    ASSERT_EQ( 0x1020304U, castor::tape::SCSI::Structures::toU32(num));
643
  }
Eric Cano's avatar
Eric Cano committed
644
  
645
  TEST(castor_tape_SCSI_Structures, toU32_3byte) {
646
    unsigned char num[3] = { 0xAA, 0xBB, 0xCC };
647
    ASSERT_EQ( 0x00AABBCCU, castor::tape::SCSI::Structures::toU32(num));
648
649
  }
  
650
  TEST(castor_tape_SCSI_Structures, toS32) {
651
    unsigned char num[4] = { 0xE6, 0x29, 0x66, 0x5B };
652
    ASSERT_EQ( -433494437, castor::tape::SCSI::Structures::toS32(num));
653
654
  }
  
655
656
657
658
659
  TEST(castor_tape_SCSI_Structures, toU64_6byte) {
    unsigned char num[6] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xCA, 0xFE };
    ASSERT_EQ ( 0xDEADBEEFCAFEULL, castor::tape::SCSI::Structures::toU64(num));
  }

660
  TEST(castor_tape_SCSI_Structures, toU64) {
Eric Cano's avatar
Eric Cano committed
661
    unsigned char num[8] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xCA, 0xFE, 0xFA, 0xDE };
662
    ASSERT_EQ ( 0xDEADBEEFCAFEFADEULL, castor::tape::SCSI::Structures::toU64(num));
Eric Cano's avatar
Eric Cano committed
663
  }
664
  
665
  TEST(castor_tape_SCSI_Structures, Exception) {
666
667
    castor::tape::SCSI::Structures::senseData_t<255> sense;
    castor::tape::SCSI::Structures::LinuxSGIO_t sgio;
668
    sgio.setSenseBuffer(&sense);
669
670
671
    sgio.status = castor::tape::SCSI::Status::GOOD;
    ASSERT_NO_THROW(castor::tape::SCSI::ExceptionLauncher(sgio));
    sgio.status = castor::tape::SCSI::Status::CHECK_CONDITION;
672
673
674
675
    /* fill up the ASC part of the */
    sense.responseCode = 0x70;
    sense.fixedFormat.ASC = 0x14;
    sense.fixedFormat.ASCQ = 0x04;
676
677
678
    ASSERT_THROW(castor::tape::SCSI::ExceptionLauncher(sgio), castor::tape::SCSI::Exception);
    try { castor::tape::SCSI::ExceptionLauncher(sgio, "In exception validation:"); ASSERT_TRUE(false); }
    catch (castor::tape::SCSI::Exception & ex) {
679
      std::string what(ex.getMessageValue());
680
681
682
683
684
685
      ASSERT_NE(std::string::npos, what.find("Block sequence error"));
      /* We check here that the formatting is also done correctly (space added when context
       not empty */
      ASSERT_NE(std::string::npos, what.find("In exception validation: "));
    }
  }
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
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
760
761
762
763
764
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
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
 
  TEST(castor_tape_SCSI_Structures, HostException) {
    castor::tape::SCSI::Structures::LinuxSGIO_t sgio;
    sgio.status = castor::tape::SCSI::Status::GOOD;
    sgio.host_status = castor::tape::SCSI::HostStatus::OK;
    ASSERT_NO_THROW(castor::tape::SCSI::ExceptionLauncher(sgio));

    sgio.host_status = castor::tape::SCSI::HostStatus::NO_CONNECT;
    ASSERT_THROW(castor::tape::SCSI::ExceptionLauncher(sgio),
      castor::tape::SCSI::HostException);
    sgio.host_status = castor::tape::SCSI::HostStatus::BUS_BUSY;
    ASSERT_THROW(castor::tape::SCSI::ExceptionLauncher(sgio),
      castor::tape::SCSI::HostException);
    sgio.host_status = castor::tape::SCSI::HostStatus::TIME_OUT;
    ASSERT_THROW(castor::tape::SCSI::ExceptionLauncher(sgio),
      castor::tape::SCSI::HostException);
    sgio.host_status = castor::tape::SCSI::HostStatus::BAD_TARGET;
    ASSERT_THROW(castor::tape::SCSI::ExceptionLauncher(sgio),
      castor::tape::SCSI::HostException);
    sgio.host_status = castor::tape::SCSI::HostStatus::ABORT;
    ASSERT_THROW(castor::tape::SCSI::ExceptionLauncher(sgio),
      castor::tape::SCSI::HostException);
    sgio.host_status = castor::tape::SCSI::HostStatus::PARITY;
    ASSERT_THROW(castor::tape::SCSI::ExceptionLauncher(sgio),
      castor::tape::SCSI::HostException);
    sgio.host_status = castor::tape::SCSI::HostStatus::ERROR;
    ASSERT_THROW(castor::tape::SCSI::ExceptionLauncher(sgio),
      castor::tape::SCSI::HostException);
    sgio.host_status = castor::tape::SCSI::HostStatus::RESET;
    ASSERT_THROW(castor::tape::SCSI::ExceptionLauncher(sgio),
      castor::tape::SCSI::HostException);
    sgio.host_status = castor::tape::SCSI::HostStatus::BAD_INTR;
    ASSERT_THROW(castor::tape::SCSI::ExceptionLauncher(sgio),
      castor::tape::SCSI::HostException);
    sgio.host_status = castor::tape::SCSI::HostStatus::PASSTHROUGH;
    ASSERT_THROW(castor::tape::SCSI::ExceptionLauncher(sgio),
      castor::tape::SCSI::HostException);
    sgio.host_status = castor::tape::SCSI::HostStatus::SOFT_ERROR;
    ASSERT_THROW(castor::tape::SCSI::ExceptionLauncher(sgio),
      castor::tape::SCSI::HostException);

    try {
      castor::tape::SCSI::ExceptionLauncher(sgio, "In exception validation:");
      ASSERT_TRUE(false);
    }
    catch (castor::tape::SCSI::HostException & ex) {
      std::string what(ex.getMessageValue());
      ASSERT_NE(std::string::npos, what.find("SOFT ERROR"));
      /* We check here that the formatting is also done correctly (space added
       *  when context not empty */
      ASSERT_NE(std::string::npos, what.find("In exception validation: "));
    }
  }

  TEST(castor_tape_SCSI_Structures, DriverException) {
    castor::tape::SCSI::Structures::LinuxSGIO_t sgio;
    sgio.status = castor::tape::SCSI::Status::GOOD;
    sgio.driver_status = castor::tape::SCSI::DriverStatus::OK;
    ASSERT_NO_THROW(castor::tape::SCSI::ExceptionLauncher(sgio));

    sgio.driver_status = castor::tape::SCSI::DriverStatus::BUSY;
    ASSERT_THROW(castor::tape::SCSI::ExceptionLauncher(sgio),
      castor::tape::SCSI::DriverException);
    sgio.driver_status = castor::tape::SCSI::DriverStatus::SOFT;
    ASSERT_THROW(castor::tape::SCSI::ExceptionLauncher(sgio),
      castor::tape::SCSI::DriverException);
    sgio.driver_status = castor::tape::SCSI::DriverStatus::MEDIA;
    ASSERT_THROW(castor::tape::SCSI::ExceptionLauncher(sgio),
      castor::tape::SCSI::DriverException);
    sgio.driver_status = castor::tape::SCSI::DriverStatus::ERROR;
    ASSERT_THROW(castor::tape::SCSI::ExceptionLauncher(sgio),
      castor::tape::SCSI::DriverException);
    sgio.driver_status = castor::tape::SCSI::DriverStatus::INVALID;
    ASSERT_THROW(castor::tape::SCSI::ExceptionLauncher(sgio),
      castor::tape::SCSI::DriverException);
    sgio.driver_status = castor::tape::SCSI::DriverStatus::TIMEOUT;
    ASSERT_THROW(castor::tape::SCSI::ExceptionLauncher(sgio),
      castor::tape::SCSI::DriverException);
    sgio.driver_status = castor::tape::SCSI::DriverStatus::HARD;
    ASSERT_THROW(castor::tape::SCSI::ExceptionLauncher(sgio),
      castor::tape::SCSI::DriverException);

    /* sense is a special case*/
    castor::tape::SCSI::Structures::senseData_t<255> sense;
    sgio.setSenseBuffer(&sense);
    /* fill up the ASC part of the */
    sense.responseCode = 0x70;
    sense.fixedFormat.ASC = 0x14;
    sense.fixedFormat.ASCQ = 0x04;
    sgio.driver_status = castor::tape::SCSI::DriverStatus::SENSE;
    ASSERT_THROW(castor::tape::SCSI::ExceptionLauncher(sgio),
      castor::tape::SCSI::DriverException);
    /* add suggestions*/
    sgio.driver_status |= castor::tape::SCSI::DriverStatusSuggest::RETRY;
    ASSERT_THROW(castor::tape::SCSI::ExceptionLauncher(sgio),
      castor::tape::SCSI::DriverException);
    sgio.driver_status |= castor::tape::SCSI::DriverStatusSuggest::ABORT;
    ASSERT_THROW(castor::tape::SCSI::ExceptionLauncher(sgio),
      castor::tape::SCSI::DriverException);
    sgio.driver_status |= castor::tape::SCSI::DriverStatusSuggest::REMAP;
    ASSERT_THROW(castor::tape::SCSI::ExceptionLauncher(sgio),
      castor::tape::SCSI::DriverException);
    sgio.driver_status |= castor::tape::SCSI::DriverStatusSuggest::DIE;
    ASSERT_THROW(castor::tape::SCSI::ExceptionLauncher(sgio),
      castor::tape::SCSI::DriverException);
    sgio.driver_status |= castor::tape::SCSI::DriverStatusSuggest::SENSE;
    ASSERT_THROW(castor::tape::SCSI::ExceptionLauncher(sgio),
      castor::tape::SCSI::DriverException);

    try {
      castor::tape::SCSI::ExceptionLauncher(sgio, "In exception validation:");
      ASSERT_TRUE(false);
    }
    catch (castor::tape::SCSI::DriverException & ex) {
      std::string what(ex.getMessageValue());
      ASSERT_NE(std::string::npos, what.find(": SENSE"));
      ASSERT_NE(std::string::npos, what.find("Driver suggestions:"));
      ASSERT_NE(std::string::npos, what.find(" RETRY ABORT REMAP DIE SENSE"));
      ASSERT_NE(std::string::npos, what.find("Block sequence error"));
      /* We check here that the formatting is also done correctly (space added
       *  when context not empty */
      ASSERT_NE(std::string::npos, what.find("In exception validation: "));
    }

    try {
      sgio.driver_status = castor::tape::SCSI::DriverStatus::TIMEOUT;
      castor::tape::SCSI::ExceptionLauncher(sgio, "In exception validation:");
      ASSERT_TRUE(false);
    }
    catch (castor::tape::SCSI::DriverException & ex) {
      std::string what(ex.getMessageValue());
      ASSERT_NE(std::string::npos, what.find(": TIMEOUT"));
      ASSERT_EQ(std::string::npos, what.find("Driver suggestions:"));
      ASSERT_EQ(std::string::npos, what.find(" RETRY ABORT REMAP DIE SENSE"));
      ASSERT_EQ(std::string::npos, what.find("Block sequence error"));
      /* We check here that the formatting is also done correctly (space added
       *  when context not empty */
      ASSERT_NE(std::string::npos, what.find("In exception validation: "));
    }
  }
 
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
  TEST(castor_tape_SCSI_Structures, logSenseParameter_t) {  
    unsigned char dataBuff[128];
    memset(dataBuff, random(), sizeof (dataBuff));
     
    castor::tape::SCSI::Structures::logSenseParameter_t &logParam=
            *(castor::tape::SCSI::Structures::logSenseParameter_t *) dataBuff;
          
    ASSERT_EQ(4U, sizeof(logParam.header));
    ASSERT_LE(sizeof(castor::tape::SCSI::Structures::logSenseParameterHeader_t), sizeof(logParam));
    
    unsigned char test1[] = {0x00, 0x08, 0x43, 0x04, 0x11, 0x22, 0x33, 0x44, 0x55};
    memcpy(dataBuff,test1,sizeof(test1));
    ASSERT_EQ(0x08U,castor::tape::SCSI::Structures::toU16(logParam.header.parameterCode));
    ASSERT_EQ(0x04U,logParam.header.parameterLength);
    ASSERT_EQ(0x11223344ULL,logParam.getU64Value());
    ASSERT_EQ(0x11223344LL,logParam.getS64Value());
    
    unsigned char test2[] = {0x00, 0x00, 0x43, 0x06, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77};
    memcpy(dataBuff,test2,sizeof(test2));
    ASSERT_EQ(0x00U,castor::tape::SCSI::Structures::toU16(logParam.header.parameterCode));
    ASSERT_EQ(0x06U,logParam.header.parameterLength);
    ASSERT_EQ(0x112233445566ULL,logParam.getU64Value());
    ASSERT_EQ(0x112233445566LL,logParam.getS64Value());
    
    unsigned char test3[] = {0x0A, 0x0F, 0x43, 0x08, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99};
    memcpy(dataBuff,test3,sizeof(test3));
    ASSERT_EQ(0xA0FU,castor::tape::SCSI::Structures::toU16(logParam.header.parameterCode));
    ASSERT_EQ(0x08U,logParam.header.parameterLength);
    ASSERT_EQ(0x1122334455667788ULL,logParam.getU64Value());
    ASSERT_EQ(0x1122334455667788LL,logParam.getS64Value());
    
    unsigned char test4[] = {0x0A, 0x0F, 0x43, 0x09, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99};
    memcpy(dataBuff,test4,sizeof(test4));
    ASSERT_EQ(0xA0FU,castor::tape::SCSI::Structures::toU16(logParam.header.parameterCode));
    ASSERT_EQ(0x09U,logParam.header.parameterLength);
    ASSERT_NE(0x1122334455667788ULL,logParam.getU64Value());
    ASSERT_NE(0x1122334455667788LL,logParam.getS64Value());
    
    unsigned char test5[] = {0xBB, 0xEE, 0x43, 0x00, 0x11, 0x22};
    memcpy(dataBuff,test5,sizeof(test5));
    ASSERT_EQ(0xBBEEU,castor::tape::SCSI::Structures::toU16(logParam.header.parameterCode));
    ASSERT_EQ(0x00U,logParam.header.parameterLength);
    ASSERT_EQ(0ULL,logParam.getU64Value());
    ASSERT_EQ(0LL,logParam.getS64Value());
    
    unsigned char test6[] = {0xDD, 0xCC, 0x43, 0x04, 0xFF, 0x22, 0x33, 0x44, 0x55};
    memcpy(dataBuff,test6,sizeof(test6));
    ASSERT_EQ(0xDDCCU,castor::tape::SCSI::Structures::toU16(logParam.header.parameterCode));
    ASSERT_EQ(0x04U,logParam.header.parameterLength);
    ASSERT_EQ(4280431428ULL,logParam.getU64Value());
    ASSERT_EQ(-14535868LL,logParam.getS64Value());
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
  }
  
  TEST(castor_tape_SCSI_Structures, testUnitReadyCDB_t) {
    castor::tape::SCSI::Structures::testUnitReadyCDB_t testUnitReadyCDB;
    unsigned char *buff = (unsigned char *)&testUnitReadyCDB;  
    /*
     * Make sure this struct is a POD (plain old data without virtual table)
     * (and has the right size).
     */
    ASSERT_EQ(6U, sizeof(testUnitReadyCDB)); 
    
    /* Check proper initialization an location of struct members match
     the bit/byte locations defined in SPC-4 */
    ASSERT_EQ(castor::tape::SCSI::Commands::TEST_UNIT_READY, testUnitReadyCDB.opCode);
    buff[0] = 0xAB;
    ASSERT_EQ(0xABU, testUnitReadyCDB.opCode);
    
    buff[1] = 0xFF;
    
    ASSERT_EQ(0, testUnitReadyCDB.EDCC);
    buff[2] |= (0x01 &   0xFF) << 0;
    ASSERT_EQ(0x1U, testUnitReadyCDB.EDCC);
        
    buff[3] = buff[4] = 0xFF;
    
    ASSERT_EQ(0U, testUnitReadyCDB.control);
    buff[5] |= 0xCD;
    ASSERT_EQ(0xCDU, testUnitReadyCDB.control);
906
  }  
907

908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
  TEST(castor_tape_SCSI_Structures, readEndOfWrapPositionCDB_t) {
    castor::tape::SCSI::Structures::readEndOfWrapPositionCDB_t readEndOfWrapPositionCDB;
    unsigned char *buff = reinterpret_cast<unsigned char*>(&readEndOfWrapPositionCDB);

    // Make sure this struct is a POD (plain old data without virtual table) and has the right size
    ASSERT_EQ(12U, sizeof(readEndOfWrapPositionCDB));

    // Check proper initialization and location of struct members match the bit/byte locations defined in LTO-8 reference
    ASSERT_EQ(buff[0], 0xA3);
    ASSERT_EQ(buff[1], 0x1F);
    ASSERT_EQ(buff[2], 0x45);

    ASSERT_EQ(0U, readEndOfWrapPositionCDB.WNV);
    buff[3] = 0x01;
    ASSERT_EQ(1U, readEndOfWrapPositionCDB.WNV);
    ASSERT_EQ(0U, readEndOfWrapPositionCDB.RA);
    buff[3] = 0x02;
    ASSERT_EQ(1U, readEndOfWrapPositionCDB.RA);

    ASSERT_EQ(0U, readEndOfWrapPositionCDB.wrapNumber);
    buff[5] = 0xAB;
    ASSERT_EQ(0xAB, readEndOfWrapPositionCDB.wrapNumber);

    ASSERT_EQ(0U, castor::tape::SCSI::Structures::toU32(readEndOfWrapPositionCDB.allocationLength));
    buff[6] = 0x0A; buff[7] = 0xBC; buff[8] = 0xDE; buff[9] = 0xF0;
    ASSERT_EQ(0xABCDEF0, castor::tape::SCSI::Structures::toU32(readEndOfWrapPositionCDB.allocationLength));

    ASSERT_EQ(0U, readEndOfWrapPositionCDB.control);
    buff[11] = 0xBC;
    ASSERT_EQ(0xBC, readEndOfWrapPositionCDB.control);
  }

  TEST(castor_tape_SCSI_Structures, readEndOfWrapPositionDataShortForm_t) {
    castor::tape::SCSI::Structures::readEndOfWrapPositionDataShortForm_t readEndOfWrapPositionDataShortForm;
    unsigned char *buff = reinterpret_cast<unsigned char*>(&readEndOfWrapPositionDataShortForm);

    // Make sure this struct is a POD (plain old data without virtual table) and has the right size
    ASSERT_EQ(10U, sizeof(readEndOfWrapPositionDataShortForm));

    // Check proper initialization and location of struct members match the bit/byte locations defined in LTO-8 reference
    ASSERT_EQ(0U, castor::tape::SCSI::Structures::toU16(readEndOfWrapPositionDataShortForm.responseDataLength));
    buff[0] = 0x0A; buff[1] = 0xB0;
    ASSERT_EQ(0xAB0, castor::tape::SCSI::Structures::toU16(readEndOfWrapPositionDataShortForm.responseDataLength));

    // Reserved
Michael Davis's avatar
Michael Davis committed
953
    buff[2] = 0xFF; buff[3] = 0xFF;
954
955

    // In this record, the logical object identifier is 6 bytes (48 bits).
956
    ASSERT_EQ(0U, castor::tape::SCSI::Structures::toU64(readEndOfWrapPositionDataShortForm.logicalObjectIdentifier));
957
    buff[4] = 0xAB; buff[5] = 0xCD; buff[6] = 0xEF; buff[7] = 0x12; buff[8] = 0x34; buff[9] = 0x56;
958
    ASSERT_EQ(0xABCDEF123456, castor::tape::SCSI::Structures::toU64(readEndOfWrapPositionDataShortForm.logicalObjectIdentifier));
959
960
961
962
963
964
965
  }

  TEST(castor_tape_SCSI_Structures, readEndOfWrapPositionDataLongForm_t) {
    castor::tape::SCSI::Structures::readEndOfWrapPositionDataLongForm_t readEndOfWrapPositionDataLongForm;
    unsigned char *buff = reinterpret_cast<unsigned char*>(&readEndOfWrapPositionDataLongForm);

    // Make sure this struct is a POD (plain old data without virtual table) and has the right size
Michael Davis's avatar
Michael Davis committed
966
    ASSERT_EQ(4+(12*castor::tape::SCSI::maxLTOTapeWraps), sizeof(readEndOfWrapPositionDataLongForm));
967
968
969

    // Check proper initialization and location of struct members match the bit/byte locations defined in LTO-8 reference
    ASSERT_EQ(0U, castor::tape::SCSI::Structures::toU16(readEndOfWrapPositionDataLongForm.responseDataLength));
970
971
972
    //Assume we have maxLTOTapeWraps returned * 12 bytes = 3362 = 0x0D22
    buff[0] = 0x0D; buff[1] = 0x22;
    ASSERT_EQ(0x0D22, castor::tape::SCSI::Structures::toU16(readEndOfWrapPositionDataLongForm.responseDataLength));
973

Michael Davis's avatar
Michael Davis committed
974
    for(unsigned int wrap = 0; wrap < castor::tape::SCSI::maxLTOTapeWraps; ++wrap) {
975
976
        int offset = 4 + (wrap * 12);

Michael Davis's avatar
Michael Davis committed
977
        ASSERT_EQ(0U, castor::tape::SCSI::Structures::toU16(readEndOfWrapPositionDataLongForm.wrapDescriptor[wrap].wrapNumber));
978
979
        buff[offset + 0] = 0xAB;
        buff[offset + 1] = 0xCD;
Michael Davis's avatar
Michael Davis committed
980
        ASSERT_EQ(0xABCD, castor::tape::SCSI::Structures::toU16(readEndOfWrapPositionDataLongForm.wrapDescriptor[wrap].wrapNumber));
981

Michael Davis's avatar
Michael Davis committed
982
        ASSERT_EQ(0U, castor::tape::SCSI::Structures::toU16(readEndOfWrapPositionDataLongForm.wrapDescriptor[wrap].partition));
983
984
        buff[offset + 2] = 0xEF;
        buff[offset + 3] = 0x01;
Michael Davis's avatar
Michael Davis committed
985
        ASSERT_EQ(0xEF01, castor::tape::SCSI::Structures::toU16(readEndOfWrapPositionDataLongForm.wrapDescriptor[wrap].partition));
986
987
988
989
990

        // Reserved
        buff[offset + 4] = 0xFF; buff[offset + 5] = 0xFF;

        // In this record, the logical object identifier is 6 bytes (48 bits).
991
        ASSERT_EQ(0U, castor::tape::SCSI::Structures::toU64(readEndOfWrapPositionDataLongForm.wrapDescriptor[wrap].logicalObjectIdentifier));
992
993
        buff[offset + 6] = 0xAB; buff[offset + 7] = 0xCD; buff[offset + 8] = 0xEF;
        buff[offset + 9] = 0x12; buff[offset + 10] = 0x34; buff[offset + 11] = 0x56;
994
        ASSERT_EQ(0xABCDEF123456, castor::tape::SCSI::Structures::toU64(readEndOfWrapPositionDataLongForm.wrapDescriptor[wrap].logicalObjectIdentifier));
995
    }
996
997
    
    ASSERT_EQ(castor::tape::SCSI::maxLTOTapeWraps,readEndOfWrapPositionDataLongForm.getNbWrapsReturned());
998
999
  }

1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
  TEST(castor_tape_SCSI_Structures, requestSenseCDB_t) {
    castor::tape::SCSI::Structures::requestSenseCDB_t requestSenseCDB;
    unsigned char *buff = reinterpret_cast<unsigned char*>(&requestSenseCDB);

    // Make sure this struct is a POD (plain old data without virtual table) and has the right size
    ASSERT_EQ(6U, sizeof(requestSenseCDB));

    // Check proper initialization and location of struct members match the bit/byte locations defined in LTO-8 reference
    buff[1] = 0xFF; buff[2] = 0xFF; buff[3] = 0xFF;

    ASSERT_EQ(castor::tape::SCSI::Commands::REQUEST_SENSE, requestSenseCDB.opCode);

    buff[0] = 0xAB;
    ASSERT_EQ(0xAB, requestSenseCDB.opCode);

    ASSERT_EQ(0, requestSenseCDB.allocationLength);
    buff[4] = 0x58;
    ASSERT_EQ(0x58, requestSenseCDB.allocationLength);

    ASSERT_EQ(0, requestSenseCDB.control);
    buff[5] = 0xBC;
    ASSERT_EQ(0xBC, requestSenseCDB.control);
  }

  TEST(castor_tape_SCSI_Structures, requestSenseData_t) {
    castor::tape::SCSI::Structures::requestSenseData_t requestSenseData;
    unsigned char *buff = reinterpret_cast<unsigned char*>(&requestSenseData);

    // Make sure this struct is a POD (plain old data without virtual table) and has the right size
    ASSERT_EQ(96U, sizeof(requestSenseData));

    // Check proper location of struct members match the bit/byte locations defined in LTO-8 reference
    buff[1] = 0xFF;
    buff[20] = 0xFF;

    ASSERT_EQ(0, requestSenseData.RESPONSE_CODE);
    buff[0] = 0x71;
    ASSERT_EQ(0x71, requestSenseData.RESPONSE_CODE);
    ASSERT_EQ(0, requestSenseData.VALID);
    buff[0] |= 1 << 7;
    ASSERT_EQ(0x1, requestSenseData.VALID);

    ASSERT_EQ(0, requestSenseData.SENSE_KEY);
    buff[2] = 0xA;
    ASSERT_EQ(0xA, requestSenseData.SENSE_KEY);
    ASSERT_EQ(0, requestSenseData.ILI);
    buff[2] |= 1 << 5;
    ASSERT_EQ(0x1, requestSenseData.ILI);
    ASSERT_EQ(0, requestSenseData.EOM);
    buff[2] |= 1 << 6;
    ASSERT_EQ(0x1, requestSenseData.EOM);
    ASSERT_EQ(0, requestSenseData.FILEMARK);
    buff[2] |= 1 << 7;
    ASSERT_EQ(0x1, requestSenseData.FILEMARK);

    ASSERT_EQ(0U, castor::tape::SCSI::Structures::toU32(requestSenseData.information));
    buff[3] = 0x0A; buff[4] = 0xBC; buff[5] = 0xDE; buff[6] = 0xF0;
    ASSERT_EQ(0x0ABCDEF0U, castor::tape::SCSI::Structures::toU32(requestSenseData.information));

    ASSERT_EQ(0, requestSenseData.additionalSenseLength);
    buff[7] = 0x58;
    ASSERT_EQ(0x58, requestSenseData.additionalSenseLength);