StructuresTest.cpp 51 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
/******************************************************************************
 *
 * 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
 *****************************************************************************/
21
22
23

#include <gtest/gtest.h>
#include <gmock/gmock-cardinalities.h>
24
25
#include "Device.hpp"
#include "Structures.hpp"
26
#include "../system/Wrapper.hpp"
27
#include "Exception.hpp"
28
29
30
31
32

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

33
namespace unitTests {
34
  TEST(castor_tape_SCSI_Structures, inquiryData_t_multi_byte_numbers_strings) {
35
36
37
38
39
    /* 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
40
41
42
    castor::tape::SCSI::Structures::inquiryData_t inq;
    unsigned char *inqBuff = (unsigned char*)&inq;
    memset(inqBuff, 0, sizeof(inq));
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
    /* 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);
    
63
    /* Test of strings: empty/full/boundary effect with next record */
64
    ASSERT_EQ("", castor::tape::SCSI::Structures::toString(inq.T10Vendor));
65
66
67
68
69
70
71
    inqBuff[8] = 'V';
    inqBuff[9] = 'i';
    inqBuff[10] = 'r';
    inqBuff[11] = 't';
    inqBuff[12] = 'u';
    inqBuff[13] = 'a';
    inqBuff[14] = 'l';
72
    inqBuff[15] = 's';
73
    ASSERT_EQ("Virtuals", castor::tape::SCSI::Structures::toString(inq.T10Vendor));
74
    
75
76
    /* Check there is no side effect from next record */
    inqBuff[16] = 'X';
77
78
    inqBuff[17] = 'Y';
    inqBuff[18] = 'Z';
79
    ASSERT_EQ("Virtuals", castor::tape::SCSI::Structures::toString(inq.T10Vendor));
80
    ASSERT_EQ("XYZ", castor::tape::SCSI::Structures::toString(inq.prodId));
81
82
83
84
85
86
87
88
89
90
            
    /* 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';
91
    ASSERT_EQ("Tapes", castor::tape::SCSI::Structures::toString(inq.T10Vendor));
92

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

105
  TEST(castor_tape_SCSI_Structures, inquiryCDB_t) {
106
    castor::tape::SCSI::Structures::inquiryCDB_t inqCDB;
107
108
    unsigned char *buff = (unsigned char *)&inqCDB;
    
109
110
111
112
    /*
     * Make sure this struct is a POD (plain old data without virtual table)
     * (and has the right size).
     */
113
    ASSERT_EQ(6U, sizeof(inqCDB));
114
    
115
    ASSERT_EQ(castor::tape::SCSI::Commands::INQUIRY, inqCDB.opCode);
116
117
    buff[0] = 0;
    ASSERT_EQ(0, inqCDB.opCode);
118
119
120
121
122
123
124
125
126
    
    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);
  }
127
  
128
    TEST(castor_tape_SCSI_Structures, inquiryUnitSerialNumberData_t) {
129
    castor::tape::SCSI::Structures::inquiryUnitSerialNumberData_t inqSerialNumber;
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
    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);
    
155
    ASSERT_EQ("", castor::tape::SCSI::Structures::toString(inqSerialNumber.productSerialNumber));
156
157
    const char serialNumber[13] = "XYZZY_A2    ";
    memcpy(&buff[4],serialNumber,12);
158
    ASSERT_EQ("XYZZY_A2    ", castor::tape::SCSI::Structures::toString(inqSerialNumber.productSerialNumber));
159
160
  }
  
161
  TEST(castor_tape_SCSI_Structures, logSelectCDB_t) {
162
    castor::tape::SCSI::Structures::logSelectCDB_t logSelectCDB;
163
164
165
166
167
168
    unsigned char *buff = (unsigned char *)&logSelectCDB;
    
    /*
     * Make sure this struct is a POD (plain old data without virtual table)
     * (and has the right size).
     */
169
    ASSERT_EQ(10U, sizeof(logSelectCDB));
170
    
171
    ASSERT_EQ(castor::tape::SCSI::Commands::LOG_SELECT, logSelectCDB.opCode);
172
173
174
175
176
177
178
179
180
181
182
183
184
185
    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;
186
    ASSERT_EQ(0xABCD, castor::tape::SCSI::Structures::toU16(logSelectCDB.parameterListLength));
187
188
189
    buff[9] |= 0xBC;
    ASSERT_EQ(0xBC, logSelectCDB.control);
  }
190

191
  TEST(castor_tape_SCSI_Structures, LinuxSGIO_t) {
192
193
    ASSERT_EQ(sizeof(sg_io_hdr_t), sizeof(castor::tape::SCSI::Structures::LinuxSGIO_t));
    castor::tape::SCSI::Structures::LinuxSGIO_t lsg;
194
195
196
197
    /* 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 */
198
    ASSERT_EQ(900000U, sgio_hdr.timeout);
199
200
201
202
    ASSERT_EQ('S', sgio_hdr.interface_id);
    /* The rest is safe. It's just a struct with added functions */
  }

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

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

664
  TEST(castor_tape_SCSI_Structures, toU64) {
Eric Cano's avatar
Eric Cano committed
665
    unsigned char num[8] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xCA, 0xFE, 0xFA, 0xDE };
666
    ASSERT_EQ ( 0xDEADBEEFCAFEFADEULL, castor::tape::SCSI::Structures::toU64(num));
Eric Cano's avatar
Eric Cano committed
667
  }
668
  
669
  TEST(castor_tape_SCSI_Structures, Exception) {
670
671
    castor::tape::SCSI::Structures::senseData_t<255> sense;
    castor::tape::SCSI::Structures::LinuxSGIO_t sgio;
672
    sgio.setSenseBuffer(&sense);
673
674
675
    sgio.status = castor::tape::SCSI::Status::GOOD;
    ASSERT_NO_THROW(castor::tape::SCSI::ExceptionLauncher(sgio));
    sgio.status = castor::tape::SCSI::Status::CHECK_CONDITION;
676
677
678
679
    /* fill up the ASC part of the */
    sense.responseCode = 0x70;
    sense.fixedFormat.ASC = 0x14;
    sense.fixedFormat.ASCQ = 0x04;
680
681
682
    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) {
683
      std::string what(ex.getMessageValue());
684
685
686
687
688
689
      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: "));
    }
  }
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
827
828
829
830
 
  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: "));
    }
  }
 
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
878
879
880
881
  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());
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
  }
  
  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);
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
953
954
955
956
  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
957
    buff[2] = 0xFF; buff[3] = 0xFF;
958
959

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

  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
970
    ASSERT_EQ(4+(12*castor::tape::SCSI::maxLTOTapeWraps), sizeof(readEndOfWrapPositionDataLongForm));
971
972
973
974
975
976

    // 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));
    buff[0] = 0x0A; buff[1] = 0xB0;
    ASSERT_EQ(0xAB0, castor::tape::SCSI::Structures::toU16(readEndOfWrapPositionDataLongForm.responseDataLength));

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

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

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

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

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