Home | History | Annotate | Download | only in io
      1 /* Copyright 2016 The TensorFlow Authors. All Rights Reserved.
      2 
      3 Licensed under the Apache License, Version 2.0 (the "License");
      4 you may not use this file except in compliance with the License.
      5 You may obtain a copy of the License at
      6 
      7     http://www.apache.org/licenses/LICENSE-2.0
      8 
      9 Unless required by applicable law or agreed to in writing, software
     10 distributed under the License is distributed on an "AS IS" BASIS,
     11 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     12 See the License for the specific language governing permissions and
     13 limitations under the License.
     14 ==============================================================================*/
     15 
     16 #include "tensorflow/core/lib/core/status_test_util.h"
     17 #include "tensorflow/core/lib/io/random_inputstream.h"
     18 #include "tensorflow/core/lib/io/zlib_compression_options.h"
     19 #include "tensorflow/core/lib/io/zlib_inputstream.h"
     20 #include "tensorflow/core/lib/io/zlib_outputbuffer.h"
     21 #include "tensorflow/core/lib/strings/strcat.h"
     22 
     23 namespace tensorflow {
     24 namespace io {
     25 
     26 static std::vector<int> InputBufferSizes() {
     27   return {10, 100, 200, 500, 1000, 10000};
     28 }
     29 
     30 static std::vector<int> OutputBufferSizes() { return {100, 200, 500, 1000}; }
     31 
     32 static std::vector<int> NumCopies() { return {1, 50, 500}; }
     33 
     34 static string GetRecord() {
     35   static const string lorem_ipsum =
     36       "Lorem ipsum dolor sit amet, consectetur adipiscing elit."
     37       " Fusce vehicula tincidunt libero sit amet ultrices. Vestibulum non "
     38       "felis augue. Duis vitae augue id lectus lacinia congue et ut purus. "
     39       "Donec auctor, nisl at dapibus volutpat, diam ante lacinia dolor, vel"
     40       "dignissim lacus nisi sed purus. Duis fringilla nunc ac lacus sagittis"
     41       " efficitur. Praesent tincidunt egestas eros, eu vehicula urna ultrices"
     42       " et. Aliquam erat volutpat. Maecenas vehicula risus consequat risus"
     43       " dictum, luctus tincidunt nibh imperdiet. Aenean bibendum ac erat"
     44       " cursus scelerisque. Cras lacinia in enim dapibus iaculis. Nunc porta"
     45       " felis lectus, ac tincidunt massa pharetra quis. Fusce feugiat dolor"
     46       " vel ligula rutrum egestas. Donec vulputate quam eros, et commodo"
     47       " purus lobortis sed.";
     48   return lorem_ipsum;
     49 }
     50 
     51 static string GenTestString(int copies = 1) {
     52   string result = "";
     53   for (int i = 0; i < copies; i++) {
     54     result += GetRecord();
     55   }
     56   return result;
     57 }
     58 
     59 typedef io::ZlibCompressionOptions CompressionOptions;
     60 
     61 void TestAllCombinations(CompressionOptions input_options,
     62                          CompressionOptions output_options) {
     63   Env* env = Env::Default();
     64   string fname = testing::TmpDir() + "/zlib_buffers_test";
     65   for (auto file_size : NumCopies()) {
     66     // Write to compressed file
     67     string data = GenTestString(file_size);
     68     for (auto input_buf_size : InputBufferSizes()) {
     69       for (auto output_buf_size : OutputBufferSizes()) {
     70         std::unique_ptr<WritableFile> file_writer;
     71         TF_ASSERT_OK(env->NewWritableFile(fname, &file_writer));
     72         string result;
     73 
     74         ZlibOutputBuffer out(file_writer.get(), input_buf_size, output_buf_size,
     75                              output_options);
     76         TF_ASSERT_OK(out.Init());
     77 
     78         TF_ASSERT_OK(out.Append(StringPiece(data)));
     79         TF_ASSERT_OK(out.Close());
     80         TF_ASSERT_OK(file_writer->Flush());
     81         TF_ASSERT_OK(file_writer->Close());
     82 
     83         std::unique_ptr<RandomAccessFile> file_reader;
     84         TF_ASSERT_OK(env->NewRandomAccessFile(fname, &file_reader));
     85         std::unique_ptr<RandomAccessInputStream> input_stream(
     86             new RandomAccessInputStream(file_reader.get()));
     87         ZlibInputStream in(input_stream.get(), input_buf_size, output_buf_size,
     88                            input_options);
     89         TF_ASSERT_OK(in.ReadNBytes(data.size(), &result));
     90         EXPECT_EQ(result, data);
     91       }
     92     }
     93   }
     94 }
     95 
     96 TEST(ZlibBuffers, DefaultOptions) {
     97   TestAllCombinations(CompressionOptions::DEFAULT(),
     98                       CompressionOptions::DEFAULT());
     99 }
    100 
    101 TEST(ZlibBuffers, RawDeflate) {
    102   TestAllCombinations(CompressionOptions::RAW(), CompressionOptions::RAW());
    103 }
    104 
    105 TEST(ZlibBuffers, Gzip) {
    106   TestAllCombinations(CompressionOptions::GZIP(), CompressionOptions::GZIP());
    107 }
    108 
    109 void TestMultipleWrites(uint8 input_buf_size, uint8 output_buf_size,
    110                         int num_writes, bool with_flush = false) {
    111   Env* env = Env::Default();
    112   CompressionOptions input_options = CompressionOptions::DEFAULT();
    113   CompressionOptions output_options = CompressionOptions::DEFAULT();
    114 
    115   string fname = testing::TmpDir() + "/zlib_buffers_test";
    116   string data = GenTestString();
    117   std::unique_ptr<WritableFile> file_writer;
    118   string actual_result;
    119   string expected_result;
    120 
    121   TF_ASSERT_OK(env->NewWritableFile(fname, &file_writer));
    122   ZlibOutputBuffer out(file_writer.get(), input_buf_size, output_buf_size,
    123                        output_options);
    124   TF_ASSERT_OK(out.Init());
    125 
    126   for (int i = 0; i < num_writes; i++) {
    127     TF_ASSERT_OK(out.Append(StringPiece(data)));
    128     if (with_flush) {
    129       TF_ASSERT_OK(out.Flush());
    130     }
    131     strings::StrAppend(&expected_result, data);
    132   }
    133   TF_ASSERT_OK(out.Close());
    134   TF_ASSERT_OK(file_writer->Flush());
    135   TF_ASSERT_OK(file_writer->Close());
    136 
    137   std::unique_ptr<RandomAccessFile> file_reader;
    138   TF_ASSERT_OK(env->NewRandomAccessFile(fname, &file_reader));
    139   std::unique_ptr<RandomAccessInputStream> input_stream(
    140       new RandomAccessInputStream(file_reader.get()));
    141   ZlibInputStream in(input_stream.get(), input_buf_size, output_buf_size,
    142                      input_options);
    143 
    144   for (int i = 0; i < num_writes; i++) {
    145     string decompressed_output;
    146     TF_ASSERT_OK(in.ReadNBytes(data.size(), &decompressed_output));
    147     strings::StrAppend(&actual_result, decompressed_output);
    148   }
    149 
    150   EXPECT_EQ(actual_result, expected_result);
    151 }
    152 
    153 TEST(ZlibBuffers, MultipleWritesWithoutFlush) {
    154   TestMultipleWrites(200, 200, 10);
    155 }
    156 
    157 TEST(ZlibBuffers, MultipleWriteCallsWithFlush) {
    158   TestMultipleWrites(200, 200, 10, true);
    159 }
    160 
    161 TEST(ZlibInputStream, FailsToReadIfWindowBitsAreIncompatible) {
    162   Env* env = Env::Default();
    163   string fname = testing::TmpDir() + "/zlib_buffers_test";
    164   CompressionOptions output_options = CompressionOptions::DEFAULT();
    165   CompressionOptions input_options = CompressionOptions::DEFAULT();
    166   int input_buf_size = 200, output_buf_size = 200;
    167   output_options.window_bits = MAX_WBITS;
    168   // inflate() has smaller history buffer.
    169   input_options.window_bits = output_options.window_bits - 1;
    170 
    171   string data = GenTestString(10);
    172   std::unique_ptr<WritableFile> file_writer;
    173   TF_ASSERT_OK(env->NewWritableFile(fname, &file_writer));
    174   string result;
    175   ZlibOutputBuffer out(file_writer.get(), input_buf_size, output_buf_size,
    176                        output_options);
    177   TF_ASSERT_OK(out.Init());
    178 
    179   TF_ASSERT_OK(out.Append(StringPiece(data)));
    180   TF_ASSERT_OK(out.Close());
    181   TF_ASSERT_OK(file_writer->Flush());
    182   TF_ASSERT_OK(file_writer->Close());
    183 
    184   std::unique_ptr<RandomAccessFile> file_reader;
    185   TF_ASSERT_OK(env->NewRandomAccessFile(fname, &file_reader));
    186   std::unique_ptr<RandomAccessInputStream> input_stream(
    187       new RandomAccessInputStream(file_reader.get()));
    188   ZlibInputStream in(input_stream.get(), input_buf_size, output_buf_size,
    189                      input_options);
    190   Status read_status = in.ReadNBytes(data.size(), &result);
    191   CHECK_EQ(read_status.code(), error::DATA_LOSS);
    192   CHECK(read_status.error_message().find("inflate() failed") != string::npos);
    193 }
    194 
    195 void WriteCompressedFile(Env* env, const string& fname, int input_buf_size,
    196                          int output_buf_size,
    197                          const CompressionOptions& output_options,
    198                          const string& data) {
    199   std::unique_ptr<WritableFile> file_writer;
    200   TF_ASSERT_OK(env->NewWritableFile(fname, &file_writer));
    201 
    202   ZlibOutputBuffer out(file_writer.get(), input_buf_size, output_buf_size,
    203                        output_options);
    204   TF_ASSERT_OK(out.Init());
    205 
    206   TF_ASSERT_OK(out.Append(StringPiece(data)));
    207   TF_ASSERT_OK(out.Close());
    208   TF_ASSERT_OK(file_writer->Flush());
    209   TF_ASSERT_OK(file_writer->Close());
    210 }
    211 
    212 void TestTell(CompressionOptions input_options,
    213               CompressionOptions output_options) {
    214   Env* env = Env::Default();
    215   string fname = testing::TmpDir() + "/zlib_buffers_test";
    216   for (auto file_size : NumCopies()) {
    217     string data = GenTestString(file_size);
    218     for (auto input_buf_size : InputBufferSizes()) {
    219       for (auto output_buf_size : OutputBufferSizes()) {
    220         // Write the compressed file.
    221         WriteCompressedFile(env, fname, input_buf_size, output_buf_size,
    222                             output_options, data);
    223 
    224         // Boiler-plate to set up ZlibInputStream.
    225         std::unique_ptr<RandomAccessFile> file_reader;
    226         TF_ASSERT_OK(env->NewRandomAccessFile(fname, &file_reader));
    227         std::unique_ptr<RandomAccessInputStream> input_stream(
    228             new RandomAccessInputStream(file_reader.get()));
    229         ZlibInputStream in(input_stream.get(), input_buf_size, output_buf_size,
    230                            input_options);
    231 
    232         string first_half(data, 0, data.size() / 2);
    233         string bytes_read;
    234 
    235         // Read the first half of the uncompressed file and expect that Tell()
    236         // returns half the uncompressed length of the file.
    237         TF_ASSERT_OK(in.ReadNBytes(first_half.size(), &bytes_read));
    238         EXPECT_EQ(in.Tell(), first_half.size());
    239         EXPECT_EQ(bytes_read, first_half);
    240 
    241         // Read the remaining half of the uncompressed file and expect that
    242         // Tell() points past the end of file.
    243         string second_half;
    244         TF_ASSERT_OK(
    245             in.ReadNBytes(data.size() - first_half.size(), &second_half));
    246         EXPECT_EQ(in.Tell(), data.size());
    247         bytes_read.append(second_half);
    248 
    249         // Expect that the file is correctly read.
    250         EXPECT_EQ(bytes_read, data);
    251       }
    252     }
    253   }
    254 }
    255 
    256 void TestSkipNBytes(CompressionOptions input_options,
    257                     CompressionOptions output_options) {
    258   Env* env = Env::Default();
    259   string fname = testing::TmpDir() + "/zlib_buffers_test";
    260   for (auto file_size : NumCopies()) {
    261     string data = GenTestString(file_size);
    262     for (auto input_buf_size : InputBufferSizes()) {
    263       for (auto output_buf_size : OutputBufferSizes()) {
    264         // Write the compressed file.
    265         WriteCompressedFile(env, fname, input_buf_size, output_buf_size,
    266                             output_options, data);
    267 
    268         // Boiler-plate to set up ZlibInputStream.
    269         std::unique_ptr<RandomAccessFile> file_reader;
    270         TF_ASSERT_OK(env->NewRandomAccessFile(fname, &file_reader));
    271         std::unique_ptr<RandomAccessInputStream> input_stream(
    272             new RandomAccessInputStream(file_reader.get()));
    273         ZlibInputStream in(input_stream.get(), input_buf_size, output_buf_size,
    274                            input_options);
    275 
    276         size_t data_half_size = data.size() / 2;
    277         string second_half(data, data_half_size, data.size() - data_half_size);
    278 
    279         // Skip past the first half of the file and expect Tell() returns
    280         // correctly.
    281         TF_ASSERT_OK(in.SkipNBytes(data_half_size));
    282         EXPECT_EQ(in.Tell(), data_half_size);
    283 
    284         // Expect that second half is read correctly and Tell() returns past
    285         // end of file after reading complete file.
    286         string bytes_read;
    287         TF_ASSERT_OK(in.ReadNBytes(second_half.size(), &bytes_read));
    288         EXPECT_EQ(bytes_read, second_half);
    289         EXPECT_EQ(in.Tell(), data.size());
    290       }
    291     }
    292   }
    293 }
    294 
    295 TEST(ZlibInputStream, TellDefaultOptions) {
    296   TestTell(CompressionOptions::DEFAULT(), CompressionOptions::DEFAULT());
    297 }
    298 
    299 TEST(ZlibInputStream, TellRawDeflate) {
    300   TestTell(CompressionOptions::RAW(), CompressionOptions::RAW());
    301 }
    302 
    303 TEST(ZlibInputStream, TellGzip) {
    304   TestTell(CompressionOptions::GZIP(), CompressionOptions::GZIP());
    305 }
    306 
    307 TEST(ZlibInputStream, SkipNBytesDefaultOptions) {
    308   TestSkipNBytes(CompressionOptions::DEFAULT(), CompressionOptions::DEFAULT());
    309 }
    310 
    311 TEST(ZlibInputStream, SkipNBytesRawDeflate) {
    312   TestSkipNBytes(CompressionOptions::RAW(), CompressionOptions::RAW());
    313 }
    314 
    315 TEST(ZlibInputStream, SkipNBytesGzip) {
    316   TestSkipNBytes(CompressionOptions::GZIP(), CompressionOptions::GZIP());
    317 }
    318 
    319 }  // namespace io
    320 }  // namespace tensorflow
    321