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

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

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

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

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

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

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

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

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