| /* |
| * 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; |
| char* m_filename; |
| String8 mKey1; |
| String8 mKey2; |
| String8 mKey3; |
| String8 mKey4; |
| |
| virtual void SetUp() { |
| m_external_storage = getenv("EXTERNAL_STORAGE"); |
| |
| const int totalLen = strlen(m_external_storage) + strlen(TEST_FILENAME) + 1; |
| m_filename = new char[totalLen]; |
| snprintf(m_filename, totalLen, "%s%s", m_external_storage, TEST_FILENAME); |
| |
| ::unlink(m_filename); |
| int fd = ::open(m_filename, O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR); |
| if (fd < 0) { |
| FAIL() << "Couldn't create " << m_filename << " for writing"; |
| } |
| mKey1 = String8(KEY1); |
| mKey2 = String8(KEY2); |
| mKey3 = String8(KEY3); |
| mKey4 = String8(KEY4); |
| } |
| |
| virtual void TearDown() { |
| } |
| }; |
| |
| TEST_F(BackupDataTest, WriteAndReadSingle) { |
| int fd = ::open(m_filename, 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(m_filename, 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(m_filename, 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(m_filename, 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(m_filename, 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(m_filename, 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(m_filename, 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(m_filename, 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(m_filename, 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(m_filename, 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(m_filename, 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(m_filename, 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(m_filename, O_WRONLY); |
| BackupDataWriter* writer = new BackupDataWriter(fd); |
| writer->WriteEntityHeader(mKey1, -1); |
| writer->WriteEntityHeader(mKey2, -1); |
| |
| ::close(fd); |
| fd = ::open(m_filename, 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 writer; |
| delete reader; |
| } |
| |
| } |