StructuresTest.cpp 27.9 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
/******************************************************************************
 *
 * 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
  TEST(castor_tape_SCSI_Structures, tapeAlertLogPage_t_and_parameters) {
479
    castor::tape::SCSI::Structures::tapeAlertLogPage_t<12> tal;
480
481
482
483
    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 */
484
    ASSERT_EQ(4U + 12U*5U, sizeof(tal));
485
    
486
    ASSERT_EQ(0U, tal.pageCode);
487
    buff[0] |= (0x12 & 0x3F) << 0;
488
    ASSERT_EQ(0x12U, tal.pageCode);
489
    
490
    ASSERT_EQ(0U,tal.subPageCode);
491
    buff[1] = 0x34;
492
    ASSERT_EQ(0x34U, tal.subPageCode);
493
494
    
    /* Simulate 123 records = 600 bytes = 0x267 */
495
    ASSERT_EQ(0U, castor::tape::SCSI::Structures::toU16(tal.pageLength));
496
    buff[2] = 0x2; buff[3]= 0x67;
497
    ASSERT_EQ(0x267U, castor::tape::SCSI::Structures::toU16(tal.pageLength));
498
    /* The page length is counted in bytes. We are interested in the number of parameters*/
499
    ASSERT_EQ(123U, tal.parameterNumber());
500
    
501
    ASSERT_EQ(0U, castor::tape::SCSI::Structures::toU16(tal.parameters[0].parameterCode));
502
    buff [4] = 0xCA; buff[5] = 0xFE;
503
    ASSERT_EQ(0xCAFEU, castor::tape::SCSI::Structures::toU16(tal.parameters[0].parameterCode));
504
    
505
    ASSERT_EQ(0U, tal.parameters[11].flag);
506
    buff[3+12*5] |= (0x1) << 0;
507
    ASSERT_EQ(1U, tal.parameters[11].flag);
508
509
  }
  
510
  TEST(castor_tape_SCSI_Structures, senseBuffer_t) {
511
    castor::tape::SCSI::Structures::senseData_t<255> sense;
Eric Cano's avatar
Eric Cano committed
512
513
514
515
    unsigned char * buff = (unsigned char *) & sense;
    
    /* Check the total size of the structure, plus the one of each of the members
     of the union */
516
517
518
    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
519
520
    
    buff[0] = 0x70;
521
    buff[2] = 0xFE;
Eric Cano's avatar
Eric Cano committed
522
523
524
    buff[12] = 0x12;
    buff[13] = 0x34;
    ASSERT_EQ(true, sense.isCurrent());
525
    ASSERT_EQ(false, sense.isDeferred());
Eric Cano's avatar
Eric Cano committed
526
527
528
529
    ASSERT_EQ(true, sense.isFixedFormat());
    ASSERT_EQ(false, sense.isDescriptorFormat());
    ASSERT_EQ(0x12, sense.getASC());
    ASSERT_EQ(0x34, sense.getASCQ());
530
531
    ASSERT_EQ(0xE, sense.getSenseKey());
    ASSERT_EQ("Miscompare", sense.getSenseKeyString());
Eric Cano's avatar
Eric Cano committed
532
533
    
    buff[0] = 0x71;
534
    buff[2] = 0xFA;
Eric Cano's avatar
Eric Cano committed
535
536
537
    buff[12] = 0x12;
    buff[13] = 0x34;
    ASSERT_EQ(false, sense.isCurrent());
538
    ASSERT_EQ(true, sense.isDeferred());
Eric Cano's avatar
Eric Cano committed
539
540
541
542
    ASSERT_EQ(true, sense.isFixedFormat());
    ASSERT_EQ(false, sense.isDescriptorFormat());
    ASSERT_EQ(0x12, sense.getASC());
    ASSERT_EQ(0x34, sense.getASCQ());
543
544
    ASSERT_EQ(0xA, sense.getSenseKey());
    ASSERT_EQ("Copy Aborted", sense.getSenseKeyString());
Eric Cano's avatar
Eric Cano committed
545
546
    
    buff[0] = 0x72;
547
    buff[1] = 0xFB;
Eric Cano's avatar
Eric Cano committed
548
549
550
    buff[2] = 0x56;
    buff[3] = 0x78;
    ASSERT_EQ(true, sense.isCurrent());
551
    ASSERT_EQ(false, sense.isDeferred());
Eric Cano's avatar
Eric Cano committed
552
553
554
555
    ASSERT_EQ(false, sense.isFixedFormat());
    ASSERT_EQ(true, sense.isDescriptorFormat());
    ASSERT_EQ(0x56, sense.getASC());
    ASSERT_EQ(0x78, sense.getASCQ());
556
557
    ASSERT_EQ(0xB, sense.getSenseKey());
    ASSERT_EQ("Aborted Command", sense.getSenseKeyString());
Eric Cano's avatar
Eric Cano committed
558
559
    
    buff[0] = 0x73;
560
    buff[1] = 0xFC;
561
562
    buff[2] = 0x0b;
    buff[3] = 0x08;
Eric Cano's avatar
Eric Cano committed
563
    ASSERT_EQ(false, sense.isCurrent());
564
    ASSERT_EQ(true, sense.isDeferred());
Eric Cano's avatar
Eric Cano committed
565
566
    ASSERT_EQ(false, sense.isFixedFormat());
    ASSERT_EQ(true, sense.isDescriptorFormat());
567
568
    ASSERT_EQ(0x0b, sense.getASC());
    ASSERT_EQ(0x08, sense.getASCQ());
569
    ASSERT_EQ(0xC, sense.getSenseKey());
570
    ASSERT_EQ("Warning - power loss expected", sense.getACSString());
571
    ASSERT_EQ("Equal", sense.getSenseKeyString());
572
573
574
575
576
577
578
579
    
    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
580
    
581
582
583
    buff[1] = 0xF;
    ASSERT_THROW(sense.getSenseKeyString(), castor::exception::Exception);
    
Eric Cano's avatar
Eric Cano committed
584
    buff[0] = 0x74;
585
    ASSERT_THROW(sense.getASC(), castor::exception::Exception);
586
    
587
    ASSERT_THROW(sense.getACSString(), castor::exception::Exception);
588
589
    
    try { sense.getACSString(); ASSERT_TRUE(false); }
590
    catch (castor::exception::Exception & ex) {
591
      std::string what(ex.getMessageValue());
592
593
      ASSERT_NE(std::string::npos, what.find("response code not supported (0x74)"));
    }
594
595
596
597
598
599
600
601
602
603
604
605
606
607
    
    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
608
  }
609
  
610
  TEST(castor_tape_SCSI_Structures, toU16) {
611
    unsigned char num[2] = { 0x1, 0x2 };
612
    ASSERT_EQ( 0x102, castor::tape::SCSI::Structures::toU16(num));
613
614
  }
  
615
  TEST(castor_tape_SCSI_Structures, toU32) {
616
    unsigned char num[4] = { 0x1, 0x2, 0x3, 0x4 };
617
    ASSERT_EQ( 0x1020304U, castor::tape::SCSI::Structures::toU32(num));
618
  }
Eric Cano's avatar
Eric Cano committed
619
  
620
  TEST(castor_tape_SCSI_Structures, toU32_3byte) {
621
    unsigned char num[3] = { 0xAA, 0xBB, 0xCC };
622
    ASSERT_EQ( 0x00AABBCCU, castor::tape::SCSI::Structures::toU32(num));
623
624
  }
  
625
  TEST(castor_tape_SCSI_Structures, toS32) {
626
    unsigned char num[4] = { 0xE6, 0x29, 0x66, 0x5B };
627
    ASSERT_EQ( -433494437, castor::tape::SCSI::Structures::toS32(num));
628
629
  }
  
630
  TEST(castor_tape_SCSI_Structures, toU64) {
Eric Cano's avatar
Eric Cano committed
631
    unsigned char num[8] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xCA, 0xFE, 0xFA, 0xDE };
632
    ASSERT_EQ ( 0xDEADBEEFCAFEFADEULL, castor::tape::SCSI::Structures::toU64(num));
Eric Cano's avatar
Eric Cano committed
633
  }
634
  
635
  TEST(castor_tape_SCSI_Structures, Exception) {
636
637
    castor::tape::SCSI::Structures::senseData_t<255> sense;
    castor::tape::SCSI::Structures::LinuxSGIO_t sgio;
638
    sgio.setSenseBuffer(&sense);
639
640
641
    sgio.status = castor::tape::SCSI::Status::GOOD;
    ASSERT_NO_THROW(castor::tape::SCSI::ExceptionLauncher(sgio));
    sgio.status = castor::tape::SCSI::Status::CHECK_CONDITION;
642
643
644
645
    /* fill up the ASC part of the */
    sense.responseCode = 0x70;
    sense.fixedFormat.ASC = 0x14;
    sense.fixedFormat.ASCQ = 0x04;
646
647
648
    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) {
649
      std::string what(ex.getMessageValue());
650
651
652
653
654
655
      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: "));
    }
  }
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
  
  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());
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
  }
  
  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);
736
  }  
737
}