| #include "gpreader.cpp" |
| #include "gmock/gmock.h" |
| #include "gtest/gtest.h" |
| #include "mock_classes.h" |
| |
| using ::testing::_; |
| using ::testing::AtLeast; |
| using ::testing::Invoke; |
| using ::testing::Return; |
| using ::testing::Throw; |
| |
| class MockGPReader : public GPReader { |
| public: |
| MockGPReader(const S3Params& params, S3RESTfulService* mockRESTfulService) : GPReader(params) { |
| restfulServicePtr = mockRESTfulService; |
| } |
| |
| S3BucketReader& getBucketReader() { |
| return this->bucketReader; |
| } |
| }; |
| |
| class GPReaderTest : public testing::Test { |
| protected: |
| virtual void SetUp() { |
| eolString[0] = '\0'; |
| } |
| virtual void TearDown() { |
| eolString[0] = '\n'; |
| eolString[1] = '\0'; |
| } |
| }; |
| |
| TEST_F(GPReaderTest, Construct) { |
| string url = "s3://s3-us-west-2.amazonaws.com/s3test.pivotal.io/dataset1/normal"; |
| |
| S3Params p = InitConfig(url + " config=data/s3test.conf"); |
| |
| EXPECT_EQ("secret_test", p.getCred().secret); |
| EXPECT_EQ("accessid_test", p.getCred().accessID); |
| EXPECT_EQ("ABCDEFGabcdefg", p.getCred().token); |
| } |
| |
| TEST_F(GPReaderTest, Open) { |
| string url = "s3://s3-us-west-2.amazonaws.com/s3test.pivotal.io/dataset1/normal"; |
| |
| S3Params p(url); |
| MockS3RESTfulService mockRESTfulService(p); |
| MockGPReader gpreader(p, &mockRESTfulService); |
| |
| XMLGenerator generator; |
| XMLGenerator* gen = &generator; |
| gen->setName("s3test.pivotal.io") |
| ->setPrefix("threebytes/") |
| ->setIsTruncated(false) |
| ->pushBuckentContent(BucketContent("threebytes/", 0)) |
| ->pushBuckentContent(BucketContent("threebytes/threebytes", 3)); |
| |
| Response response(RESPONSE_OK, gen->toXML()); |
| |
| EXPECT_CALL(mockRESTfulService, get(_, _)).WillOnce(Return(response)); |
| |
| gpreader.open(p); |
| |
| const ListBucketResult& keyList = gpreader.getBucketReader().getKeyList(); |
| EXPECT_EQ((uint64_t)1, keyList.contents.size()); |
| EXPECT_EQ("threebytes/threebytes", keyList.contents[0].getName()); |
| EXPECT_EQ((uint64_t)3, keyList.contents[0].getSize()); |
| } |
| |
| TEST_F(GPReaderTest, Close) { |
| string url = "s3://s3-us-west-2.amazonaws.com/s3test.pivotal.io/dataset1/normal"; |
| S3Params p(url); |
| |
| MockS3RESTfulService mockRESTfulService(p); |
| MockGPReader gpreader(p, &mockRESTfulService); |
| |
| XMLGenerator generator; |
| XMLGenerator* gen = &generator; |
| gen->setName("s3test.pivotal.io") |
| ->setPrefix("threebytes/") |
| ->setIsTruncated(false) |
| ->pushBuckentContent(BucketContent("threebytes/", 0)) |
| ->pushBuckentContent(BucketContent("threebytes/threebytes", 3)); |
| |
| Response response(RESPONSE_OK, gen->toXML()); |
| |
| EXPECT_CALL(mockRESTfulService, get(_, _)).WillOnce(Return(response)); |
| |
| gpreader.open(p); |
| |
| const ListBucketResult& keyList = gpreader.getBucketReader().getKeyList(); |
| EXPECT_EQ((uint64_t)1, keyList.contents.size()); |
| |
| gpreader.close(); |
| EXPECT_TRUE(keyList.contents.empty()); |
| } |
| |
| TEST_F(GPReaderTest, ReadSmallData) { |
| string url = "s3://s3-us-west-2.amazonaws.com/s3test.pivotal.io/dataset1/normal"; |
| S3Params p = InitConfig(url + " config=data/s3test.conf"); |
| |
| MockS3RESTfulService mockRESTfulService(p); |
| MockGPReader gpreader(p, &mockRESTfulService); |
| |
| XMLGenerator generator; |
| XMLGenerator* gen = &generator; |
| gen->setName("s3test.pivotal.io") |
| ->setPrefix("threebytes/") |
| ->setIsTruncated(false) |
| ->pushBuckentContent(BucketContent("threebytes/", 0)) |
| ->pushBuckentContent(BucketContent("threebytes/threebytes", 3)); |
| |
| Response listBucketResponse(RESPONSE_OK, gen->toXML()); |
| |
| vector<uint8_t> keyContent; |
| |
| // generate 3 bytes in random way |
| srand(time(NULL)); |
| keyContent.push_back(rand() & 0xFF); |
| keyContent.push_back(rand() & 0xFF); |
| keyContent.push_back(rand() & 0xFF); |
| |
| Response keyReaderResponse(RESPONSE_OK, keyContent); |
| |
| EXPECT_CALL(mockRESTfulService, get(_, _)) |
| .WillOnce(Return(listBucketResponse)) |
| // first 4 bytes is retrieved once for format detection. |
| .WillOnce(Return(keyReaderResponse)) |
| // whole file content |
| .WillOnce(Return(keyReaderResponse)); |
| |
| gpreader.open(p); |
| |
| const ListBucketResult& keyList = gpreader.getBucketReader().getKeyList(); |
| printf("Size: %lu\n", keyList.contents.size()); |
| |
| EXPECT_EQ((uint64_t)1, keyList.contents.size()); |
| EXPECT_EQ("threebytes/threebytes", keyList.contents[0].getName()); |
| EXPECT_EQ((uint64_t)3, keyList.contents[0].getSize()); |
| |
| char buffer[64]; |
| EXPECT_EQ((uint64_t)3, gpreader.read(buffer, sizeof(buffer))); |
| EXPECT_EQ(0, memcmp(buffer, keyContent.data(), 3)); |
| |
| EXPECT_EQ((uint64_t)0, gpreader.read(buffer, sizeof(buffer))); |
| } |
| |
| // We need to mock the Get() to fulfill unordered GET request. |
| class MockS3RESTfulServiceForMultiThreads : public MockS3RESTfulService { |
| public: |
| MockS3RESTfulServiceForMultiThreads(const S3Params& params, uint64_t dataSize) |
| : MockS3RESTfulService(params) { |
| srand(time(NULL)); |
| data.reserve(dataSize); |
| for (uint64_t i = 0; i < dataSize; i++) { |
| data.push_back(rand() & 0xFF); |
| } |
| } |
| |
| Response mockGet(const string& url, HTTPHeaders& headers) { |
| string range = headers.Get(RANGE); |
| size_t index = range.find("="); |
| string rangeNumber = range.substr(index + 1); |
| index = rangeNumber.find("-"); |
| |
| // stoi is not available in C++98, use sscanf as workaround. |
| int begin, end; |
| if (index > 0) { |
| sscanf(rangeNumber.substr(0, index).c_str(), "%d", &begin); |
| } else { |
| begin = 0; |
| } |
| |
| if (rangeNumber.empty()) { |
| end = data.size(); |
| } else { |
| sscanf(rangeNumber.substr(index + 1).c_str(), "%d", &end); |
| } |
| |
| vector<uint8_t> responseData(data.begin() + begin, data.begin() + end + 1); |
| |
| return Response(RESPONSE_OK, responseData); |
| } |
| |
| const uint8_t* getData() { |
| return data.data(); |
| } |
| |
| private: |
| vector<uint8_t> data; |
| }; |
| |
| TEST_F(GPReaderTest, ReadHugeData) { |
| string url = "s3://s3-us-west-2.amazonaws.com/s3test.pivotal.io/dataset1/normal"; |
| S3Params p = InitConfig(url + " config=data/s3test.conf section=smallchunk"); |
| |
| // We don't know the chunksize before we load_config() |
| // so we create a big enough data (128M), to force |
| // multiple-threads to be constructed and loop-read to be triggered. |
| uint64_t totalData = 1024 * 1024 * 128; |
| |
| MockS3RESTfulServiceForMultiThreads mockRESTfulService(p, totalData); |
| MockGPReader gpreader(p, &mockRESTfulService); |
| |
| XMLGenerator generator; |
| XMLGenerator* gen = &generator; |
| gen->setName("s3test.pivotal.io") |
| ->setPrefix("bigdata/") |
| ->setIsTruncated(false) |
| ->pushBuckentContent(BucketContent("bigdata/", 0)) |
| ->pushBuckentContent(BucketContent("bigdata/bigdata", totalData)); |
| |
| Response listBucketResponse(RESPONSE_OK, gen->toXML()); |
| |
| // call mockGet() instead of simply return a Response. |
| EXPECT_CALL(mockRESTfulService, get(_, _)) |
| .WillOnce(Return(listBucketResponse)) |
| .WillRepeatedly(Invoke(&mockRESTfulService, &MockS3RESTfulServiceForMultiThreads::mockGet)); |
| |
| gpreader.open(p); |
| |
| // compare the data size |
| const ListBucketResult& keyList = gpreader.getBucketReader().getKeyList(); |
| EXPECT_EQ((uint64_t)1, keyList.contents.size()); |
| EXPECT_EQ("bigdata/bigdata", keyList.contents[0].getName()); |
| EXPECT_EQ(totalData, keyList.contents[0].getSize()); |
| |
| // compare the data content |
| static char buffer[1024 * 1024]; |
| uint64_t size = sizeof(buffer); |
| for (uint64_t i = 0; i < totalData; i += size) { |
| EXPECT_EQ(size, gpreader.read(buffer, size)); |
| ASSERT_EQ(0, memcmp(buffer, mockRESTfulService.getData() + i, size)); |
| } |
| |
| // Guarantee the last call |
| EXPECT_EQ((uint64_t)0, gpreader.read(buffer, sizeof(buffer))); |
| } |
| |
| TEST_F(GPReaderTest, ReadFromEmptyURL) { |
| string url; |
| S3Params p(url); |
| MockS3RESTfulService mockRESTfulService(p); |
| MockGPReader gpreader(p, &mockRESTfulService); |
| |
| // an exception should be throwed in parseURL() |
| // with message "'' is not valid" |
| EXPECT_THROW(gpreader.open(p), S3Exception); |
| } |
| |
| /* |
| TEST_F(GPReaderTest, ReadFromInvalidURL) { |
| string baseUrl = "s3://"; |
| |
| S3Params p(baseUrl); |
| MockS3RESTfulService mockRESTfulService(p); |
| MockGPReader gpreader(p, &mockRESTfulService); |
| |
| // an exception should be throwed in parseURL() |
| // with message "'s3://' is not valid," |
| EXPECT_THROW(gpreader.open(p), S3Exception); |
| }*/ |
| |
| TEST_F(GPReaderTest, ReadAndGetFailedListBucketResponse) { |
| string url = "s3://s3-us-west-2.amazonaws.com/s3test.pivotal.io/dataset1/normal"; |
| S3Params p(url); |
| MockS3RESTfulService mockRESTfulService(p); |
| MockGPReader gpreader(p, &mockRESTfulService); |
| |
| EXPECT_CALL(mockRESTfulService, get(_, _)).WillRepeatedly(Throw(S3FailedAfterRetry("", 3, ""))); |
| |
| EXPECT_THROW(gpreader.open(p), S3FailedAfterRetry); |
| } |
| |
| TEST_F(GPReaderTest, ReadAndGetFailedKeyReaderResponse) { |
| string url = "s3://s3-us-west-2.amazonaws.com/s3test.pivotal.io/dataset1/normal"; |
| S3Params p(url); |
| MockS3RESTfulService mockRESTfulService(p); |
| MockGPReader gpreader(p, &mockRESTfulService); |
| |
| XMLGenerator generator; |
| XMLGenerator* gen = &generator; |
| gen->setName("s3test.pivotal.io") |
| ->setPrefix("threebytes/") |
| ->setIsTruncated(false) |
| ->pushBuckentContent(BucketContent("threebytes/", 0)) |
| ->pushBuckentContent(BucketContent("threebytes/threebytes", 3)); |
| |
| Response listBucketResponse(RESPONSE_OK, gen->toXML()); |
| |
| EXPECT_CALL(mockRESTfulService, get(_, _)) |
| .WillOnce(Return(listBucketResponse)) |
| .WillRepeatedly(Throw(S3FailedAfterRetry("", 3, ""))); |
| |
| gpreader.open(p); |
| |
| const ListBucketResult& keyList = gpreader.getBucketReader().getKeyList(); |
| EXPECT_EQ((uint64_t)1, keyList.contents.size()); |
| EXPECT_EQ("threebytes/threebytes", keyList.contents[0].getName()); |
| EXPECT_EQ((uint64_t)3, keyList.contents[0].getSize()); |
| |
| char buffer[64]; |
| EXPECT_THROW(gpreader.read(buffer, sizeof(buffer)), S3FailedAfterRetry); |
| } |
| |
| // thread functions test with local variables |
| TEST(Common, ThreadFunctions) { |
| // just to test if these two are functional |
| thread_setup(); |
| EXPECT_NE((void*)NULL, mutex_buf); |
| |
| thread_cleanup(); |
| EXPECT_EQ((void*)NULL, mutex_buf); |
| |
| EXPECT_NE((uint64_t)0, gpcloud_id_function()); |
| } |