text: // Licensed to the Apache Software Foundation (ASF) under one
  // or more contributor license agreements.  See the NOTICE file
  // distributed with this work for additional information
  // regarding copyright ownership.  The ASF licenses this file
  // to you 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.
  
  #include "kudu/util/rolling_log.h"
  
  #include <unistd.h>
  
  #include <algorithm>
  #include <cstdint>
  #include <string>
  #include <vector>
  
  #include <glog/stl_logging.h>
  #include <gtest/gtest.h>
  
  #include "kudu/gutil/port.h"
  #include "kudu/gutil/strings/stringpiece.h"
  #include "kudu/gutil/strings/substitute.h"
  #include "kudu/gutil/strings/util.h"
  #include "kudu/util/env.h"
  #include "kudu/util/faststring.h"
  #include "kudu/util/path_util.h"
  #include "kudu/util/test_macros.h"
  #include "kudu/util/test_util.h"
  
  using std::string;
  using std::vector;
  using strings::Substitute;
  
  namespace kudu {
  
  class RollingLogTest : public KuduTest {
   public:
    RollingLogTest()
      : log_dir_(GetTestPath("log_dir")) {
    }
  
    virtual void SetUp() OVERRIDE {
      ASSERT_OK(env_->CreateDir(log_dir_));
    }
  
   protected:
    void AssertLogCount(int expected_count, vector<string>* children) {
      vector<string> dir_entries;
      ASSERT_OK(env_->GetChildren(log_dir_, &dir_entries));
      children->clear();
  
      for (const string& child : dir_entries) {
        if (child == "." || child == "..") continue;
        children->push_back(child);
        ASSERT_TRUE(HasPrefixString(child, "rolling_log-test."));
        ASSERT_STR_CONTAINS(child, ".mylog.");
  
        string pid_suffix = Substitute("$0", getpid());
        ASSERT_TRUE(HasSuffixString(child, pid_suffix) ||
                    HasSuffixString(child, pid_suffix + ".gz")) << "bad child: " << child;
      }
      std::sort(children->begin(), children->end());
      ASSERT_EQ(children->size(), expected_count) << *children;
    }
  
    const string log_dir_;
  };
  
  // Test with compression off.
  TEST_F(RollingLogTest, TestLog) {
    RollingLog log(env_, log_dir_, "rolling_log-test", "mylog");
    log.SetCompressionEnabled(false);
    log.SetRollThresholdBytes(100);
  
    // Before writing anything, we shouldn't open a log file.
    vector<string> children;
    NO_FATALS(AssertLogCount(0, &children));
  
    // Appending some data should write a new segment.
    const string kTestString = "Hello world\n";
    ASSERT_OK(log.Append(kTestString));
    NO_FATALS(AssertLogCount(1, &children));
  
    for (int i = 0; i < 10; i++) {
      ASSERT_OK(log.Append(kTestString));
    }
    NO_FATALS(AssertLogCount(2, &children));
  
    faststring data;
    string path = JoinPathSegments(log_dir_, children[0]);
    ASSERT_OK(ReadFileToString(env_, path, &data));
    ASSERT_TRUE(HasPrefixString(data.ToString(), kTestString))
      << "Data missing";
    ASSERT_LE(data.size(), 100 + kTestString.length())
        << "Roll threshold not respected";
  }
  
  // Test with compression on.
  TEST_F(RollingLogTest, TestCompression) {
    RollingLog log(env_, log_dir_, "rolling_log-test", "mylog");
    ASSERT_OK(log.Open());
  
    StringPiece data = "Hello world\n";
    int raw_size = 0;
    for (int i = 0; i < 1000; i++) {
      ASSERT_OK(log.Append(data));
      raw_size += data.size();
    }
    ASSERT_OK(log.Close());
  
    vector<string> children;
    NO_FATALS(AssertLogCount(1, &children));
    ASSERT_TRUE(HasSuffixString(children[0], ".gz"));
  
    // Ensure that the output is actually gzipped.
    uint64_t size;
    ASSERT_OK(env_->GetFileSize(JoinPathSegments(log_dir_, children[0]), &size));
    ASSERT_LT(size, raw_size / 10);
    ASSERT_GT(size, 0);
  }
  
  TEST_F(RollingLogTest, TestFileCountLimit) {
    RollingLog log(env_, log_dir_, "rolling_log-test", "mylog");
    ASSERT_OK(log.Open());
    log.SetRollThresholdBytes(100);
    log.SetMaxNumSegments(3);
  
    for (int i = 0; i < 100; i++) {
      ASSERT_OK(log.Append("hello world\n"));
    }
    ASSERT_OK(log.Close());
  
    vector<string> children;
    NO_FATALS(AssertLogCount(3, &children));
  }
  
  } // namespace kudu
  