/*
* Copyright (C) 2010 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#define LOG_TAG "ObbFile_test"
#include <androidfw/BackupHelpers.h>
#include <utils/Log.h>
#include <utils/String8.h>
#include <gtest/gtest.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
namespace android {
#define TEST_FILENAME "/test.bd"
// keys of different lengths to test padding
#define KEY1 "key1"
#define KEY2 "key2a"
#define KEY3 "key3bc"
#define KEY4 "key4def"
// payloads of different lengths to test padding
#define DATA1 "abcdefg"
#define DATA2 "hijklmnopq"
#define DATA3 "rstuvwxyz"
// KEY4 is only ever deleted
class BackupDataTest : public testing::Test {
protected:
char* m_external_storage;
String8 mFilename;
String8 mKey1;
String8 mKey2;
String8 mKey3;
String8 mKey4;
virtual void SetUp() {
m_external_storage = getenv("EXTERNAL_STORAGE");
mFilename.append(m_external_storage);
mFilename.append(TEST_FILENAME);
::unlink(mFilename.string());
int fd = ::open(mFilename.string(), O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR);
if (fd < 0) {
FAIL() << "Couldn't create " << mFilename.string() << " for writing";
}
mKey1 = String8(KEY1);
mKey2 = String8(KEY2);
mKey3 = String8(KEY3);
mKey4 = String8(KEY4);
}
virtual void TearDown() {
}
};
TEST_F(BackupDataTest, WriteAndReadSingle) {
int fd = ::open(mFilename.string(), O_WRONLY);
BackupDataWriter* writer = new BackupDataWriter(fd);
EXPECT_EQ(NO_ERROR, writer->WriteEntityHeader(mKey1, sizeof(DATA1)))
<< "WriteEntityHeader returned an error";
EXPECT_EQ(NO_ERROR, writer->WriteEntityData(DATA1, sizeof(DATA1)))
<< "WriteEntityData returned an error";
::close(fd);
fd = ::open(mFilename.string(), O_RDONLY);
BackupDataReader* reader = new BackupDataReader(fd);
EXPECT_EQ(NO_ERROR, reader->Status())
<< "Reader ctor failed";
bool done;
int type;
reader->ReadNextHeader(&done, &type);
EXPECT_EQ(BACKUP_HEADER_ENTITY_V1, type)
<< "wrong type from ReadNextHeader";
String8 key;
size_t dataSize;
EXPECT_EQ(NO_ERROR, reader->ReadEntityHeader(&key, &dataSize))
<< "ReadEntityHeader returned an error";
EXPECT_EQ(mKey1, key)
<< "wrong key from ReadEntityHeader";
EXPECT_EQ(sizeof(DATA1), dataSize)
<< "wrong size from ReadEntityHeader";
char* dataBytes = new char[dataSize];
EXPECT_EQ((int) dataSize, reader->ReadEntityData(dataBytes, dataSize))
<< "ReadEntityData returned an error";
for (unsigned int i = 0; i < sizeof(DATA1); i++) {
EXPECT_EQ(DATA1[i], dataBytes[i])
<< "data character " << i << " should be equal";
}
delete[] dataBytes;
delete writer;
delete reader;
}
TEST_F(BackupDataTest, WriteAndReadMultiple) {
int fd = ::open(mFilename.string(), O_WRONLY);
BackupDataWriter* writer = new BackupDataWriter(fd);
writer->WriteEntityHeader(mKey1, sizeof(DATA1));
writer->WriteEntityData(DATA1, sizeof(DATA1));
writer->WriteEntityHeader(mKey2, sizeof(DATA2));
writer->WriteEntityData(DATA2, sizeof(DATA2));
::close(fd);
fd = ::open(mFilename.string(), O_RDONLY);
BackupDataReader* reader = new BackupDataReader(fd);
bool done;
int type;
String8 key;
size_t dataSize;
char* dataBytes;
// read first entity
reader->ReadNextHeader(&done, &type);
reader->ReadEntityHeader(&key, &dataSize);
dataBytes = new char[dataSize];
reader->ReadEntityData(dataBytes, dataSize);
delete dataBytes;
// read and verify second entity
reader->ReadNextHeader(&done, &type);
EXPECT_EQ(BACKUP_HEADER_ENTITY_V1, type)
<< "wrong type from ReadNextHeader";
EXPECT_EQ(NO_ERROR, reader->ReadEntityHeader(&key, &dataSize))
<< "ReadEntityHeader returned an error on second entity";
EXPECT_EQ(mKey2, key)
<< "wrong key from ReadEntityHeader on second entity";
EXPECT_EQ(sizeof(DATA2), dataSize)
<< "wrong size from ReadEntityHeader on second entity";
dataBytes = new char[dataSize];
EXPECT_EQ((int)dataSize, reader->ReadEntityData(dataBytes, dataSize))
<< "ReadEntityData returned an error on second entity";
for (unsigned int i = 0; i < sizeof(DATA2); i++) {
EXPECT_EQ(DATA2[i], dataBytes[i])
<< "data character " << i << " should be equal";
}
delete dataBytes;
delete writer;
delete reader;
}
TEST_F(BackupDataTest, SkipEntity) {
int fd = ::open(mFilename.string(), O_WRONLY);
BackupDataWriter* writer = new BackupDataWriter(fd);
writer->WriteEntityHeader(mKey1, sizeof(DATA1));
writer->WriteEntityData(DATA1, sizeof(DATA1));
writer->WriteEntityHeader(mKey2, sizeof(DATA2));
writer->WriteEntityData(DATA2, sizeof(DATA2));
writer->WriteEntityHeader(mKey3, sizeof(DATA3));
writer->WriteEntityData(DATA3, sizeof(DATA3));
::close(fd);
fd = ::open(mFilename.string(), O_RDONLY);
BackupDataReader* reader = new BackupDataReader(fd);
bool done;
int type;
String8 key;
size_t dataSize;
char* dataBytes;
// read first entity
reader->ReadNextHeader(&done, &type);
reader->ReadEntityHeader(&key, &dataSize);
dataBytes = new char[dataSize];
reader->ReadEntityData(dataBytes, dataSize);
delete dataBytes;
// skip second entity
reader->ReadNextHeader(&done, &type);
reader->ReadEntityHeader(&key, &dataSize);
reader->SkipEntityData();
// read and verify third entity
reader->ReadNextHeader(&done, &type);
EXPECT_EQ(BACKUP_HEADER_ENTITY_V1, type)
<< "wrong type from ReadNextHeader after skip";
EXPECT_EQ(NO_ERROR, reader->ReadEntityHeader(&key, &dataSize))
<< "ReadEntityHeader returned an error on third entity";
EXPECT_EQ(mKey3, key)
<< "wrong key from ReadEntityHeader on third entity";
EXPECT_EQ(sizeof(DATA3), dataSize)
<< "wrong size from ReadEntityHeader on third entity";
dataBytes = new char[dataSize];
EXPECT_EQ((int) dataSize, reader->ReadEntityData(dataBytes, dataSize))
<< "ReadEntityData returned an error on third entity";
for (unsigned int i = 0; i < sizeof(DATA3); i++) {
EXPECT_EQ(DATA3[i], dataBytes[i])
<< "data character " << i << " should be equal";
}
delete dataBytes;
delete writer;
delete reader;
}
TEST_F(BackupDataTest, DeleteEntity) {
int fd = ::open(mFilename.string(), O_WRONLY);
BackupDataWriter* writer = new BackupDataWriter(fd);
writer->WriteEntityHeader(mKey1, sizeof(DATA1));
writer->WriteEntityData(DATA1, sizeof(DATA1));
writer->WriteEntityHeader(mKey2, -1);
::close(fd);
fd = ::open(mFilename.string(), O_RDONLY);
BackupDataReader* reader = new BackupDataReader(fd);
bool done;
int type;
String8 key;
size_t dataSize;
char* dataBytes;
// read first entity
reader->ReadNextHeader(&done, &type);
reader->ReadEntityHeader(&key, &dataSize);
dataBytes = new char[dataSize];
reader->ReadEntityData(dataBytes, dataSize);
delete dataBytes;
// read and verify deletion
reader->ReadNextHeader(&done, &type);
EXPECT_EQ(BACKUP_HEADER_ENTITY_V1, type)
<< "wrong type from ReadNextHeader on deletion";
EXPECT_EQ(NO_ERROR, reader->ReadEntityHeader(&key, &dataSize))
<< "ReadEntityHeader returned an error on second entity";
EXPECT_EQ(mKey2, key)
<< "wrong key from ReadEntityHeader on second entity";
EXPECT_EQ(-1, (int) dataSize)
<< "not recognizing deletion on second entity";
delete writer;
delete reader;
}
TEST_F(BackupDataTest, EneityAfterDelete) {
int fd = ::open(mFilename.string(), O_WRONLY);
BackupDataWriter* writer = new BackupDataWriter(fd);
writer->WriteEntityHeader(mKey1, sizeof(DATA1));
writer->WriteEntityData(DATA1, sizeof(DATA1));
writer->WriteEntityHeader(mKey2, -1);
writer->WriteEntityHeader(mKey3, sizeof(DATA3));
writer->WriteEntityData(DATA3, sizeof(DATA3));
::close(fd);
fd = ::open(mFilename.string(), O_RDONLY);
BackupDataReader* reader = new BackupDataReader(fd);
bool done;
int type;
String8 key;
size_t dataSize;
char* dataBytes;
// read first entity
reader->ReadNextHeader(&done, &type);
reader->ReadEntityHeader(&key, &dataSize);
dataBytes = new char[dataSize];
reader->ReadEntityData(dataBytes, dataSize);
delete dataBytes;
// read and verify deletion
reader->ReadNextHeader(&done, &type);
EXPECT_EQ(BACKUP_HEADER_ENTITY_V1, type)
<< "wrong type from ReadNextHeader on deletion";
EXPECT_EQ(NO_ERROR, reader->ReadEntityHeader(&key, &dataSize))
<< "ReadEntityHeader returned an error on second entity";
EXPECT_EQ(mKey2, key)
<< "wrong key from ReadEntityHeader on second entity";
EXPECT_EQ(-1, (int)dataSize)
<< "not recognizing deletion on second entity";
// read and verify third entity
reader->ReadNextHeader(&done, &type);
EXPECT_EQ(BACKUP_HEADER_ENTITY_V1, type)
<< "wrong type from ReadNextHeader after deletion";
EXPECT_EQ(NO_ERROR, reader->ReadEntityHeader(&key, &dataSize))
<< "ReadEntityHeader returned an error on third entity";
EXPECT_EQ(mKey3, key)
<< "wrong key from ReadEntityHeader on third entity";
EXPECT_EQ(sizeof(DATA3), dataSize)
<< "wrong size from ReadEntityHeader on third entity";
dataBytes = new char[dataSize];
EXPECT_EQ((int) dataSize, reader->ReadEntityData(dataBytes, dataSize))
<< "ReadEntityData returned an error on third entity";
for (unsigned int i = 0; i < sizeof(DATA3); i++) {
EXPECT_EQ(DATA3[i], dataBytes[i])
<< "data character " << i << " should be equal";
}
delete dataBytes;
delete writer;
delete reader;
}
TEST_F(BackupDataTest, OnlyDeleteEntities) {
int fd = ::open(mFilename.string(), O_WRONLY);
BackupDataWriter* writer = new BackupDataWriter(fd);
writer->WriteEntityHeader(mKey1, -1);
writer->WriteEntityHeader(mKey2, -1);
writer->WriteEntityHeader(mKey3, -1);
writer->WriteEntityHeader(mKey4, -1);
::close(fd);
fd = ::open(mFilename.string(), O_RDONLY);
BackupDataReader* reader = new BackupDataReader(fd);
bool done;
int type;
String8 key;
size_t dataSize;
// read and verify first deletion
reader->ReadNextHeader(&done, &type);
EXPECT_EQ(BACKUP_HEADER_ENTITY_V1, type)
<< "wrong type from ReadNextHeader first deletion";
EXPECT_EQ(NO_ERROR, reader->ReadEntityHeader(&key, &dataSize))
<< "ReadEntityHeader returned an error on first entity";
EXPECT_EQ(mKey1, key)
<< "wrong key from ReadEntityHeader on first entity";
EXPECT_EQ(-1, (int) dataSize)
<< "not recognizing deletion on first entity";
// read and verify second deletion
reader->ReadNextHeader(&done, &type);
EXPECT_EQ(BACKUP_HEADER_ENTITY_V1, type)
<< "wrong type from ReadNextHeader second deletion";
EXPECT_EQ(NO_ERROR, reader->ReadEntityHeader(&key, &dataSize))
<< "ReadEntityHeader returned an error on second entity";
EXPECT_EQ(mKey2, key)
<< "wrong key from ReadEntityHeader on second entity";
EXPECT_EQ(-1, (int) dataSize)
<< "not recognizing deletion on second entity";
// read and verify third deletion
reader->ReadNextHeader(&done, &type);
EXPECT_EQ(BACKUP_HEADER_ENTITY_V1, type)
<< "wrong type from ReadNextHeader third deletion";
EXPECT_EQ(NO_ERROR, reader->ReadEntityHeader(&key, &dataSize))
<< "ReadEntityHeader returned an error on third entity";
EXPECT_EQ(mKey3, key)
<< "wrong key from ReadEntityHeader on third entity";
EXPECT_EQ(-1, (int) dataSize)
<< "not recognizing deletion on third entity";
// read and verify fourth deletion
reader->ReadNextHeader(&done, &type);
EXPECT_EQ(BACKUP_HEADER_ENTITY_V1, type)
<< "wrong type from ReadNextHeader fourth deletion";
EXPECT_EQ(NO_ERROR, reader->ReadEntityHeader(&key, &dataSize))
<< "ReadEntityHeader returned an error on fourth entity";
EXPECT_EQ(mKey4, key)
<< "wrong key from ReadEntityHeader on fourth entity";
EXPECT_EQ(-1, (int) dataSize)
<< "not recognizing deletion on fourth entity";
delete writer;
delete reader;
}
TEST_F(BackupDataTest, ReadDeletedEntityData) {
int fd = ::open(mFilename.string(), O_WRONLY);
BackupDataWriter* writer = new BackupDataWriter(fd);
writer->WriteEntityHeader(mKey1, -1);
writer->WriteEntityHeader(mKey2, -1);
::close(fd);
fd = ::open(mFilename.string(), O_RDONLY);
BackupDataReader* reader = new BackupDataReader(fd);
bool done;
int type;
String8 key;
size_t dataSize;
// read and verify first deletion
reader->ReadNextHeader(&done, &type);
EXPECT_EQ(BACKUP_HEADER_ENTITY_V1, type)
<< "wrong type from ReadNextHeader first deletion";
EXPECT_EQ(NO_ERROR, reader->ReadEntityHeader(&key, &dataSize))
<< "ReadEntityHeader returned an error on first entity";
EXPECT_EQ(mKey1, key)
<< "wrong key from ReadEntityHeader on first entity";
EXPECT_EQ(-1, (int) dataSize)
<< "not recognizing deletion on first entity";
// erroneously try to read first entity data
char* dataBytes = new char[10];
dataBytes[0] = 'A';
EXPECT_EQ(NO_ERROR, reader->ReadEntityData(dataBytes, dataSize));
// expect dataBytes to be unmodofied
EXPECT_EQ('A', dataBytes[0]);
// read and verify second deletion
reader->ReadNextHeader(&done, &type);
EXPECT_EQ(BACKUP_HEADER_ENTITY_V1, type)
<< "wrong type from ReadNextHeader second deletion";
EXPECT_EQ(NO_ERROR, reader->ReadEntityHeader(&key, &dataSize))
<< "ReadEntityHeader returned an error on second entity";
EXPECT_EQ(mKey2, key)
<< "wrong key from ReadEntityHeader on second entity";
EXPECT_EQ(-1, (int) dataSize)
<< "not recognizing deletion on second entity";
delete[] dataBytes;
delete writer;
delete reader;
}
}