// 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/consensus/log_anchor_registry.h"

#include <cstdint>
#include <string>

#include <gtest/gtest.h>

#include "kudu/gutil/ref_counted.h"
#include "kudu/gutil/strings/substitute.h"
#include "kudu/util/monotime.h"
#include "kudu/util/scoped_cleanup.h"
#include "kudu/util/status.h"
#include "kudu/util/test_macros.h"
#include "kudu/util/test_util.h"

using std::string;
using strings::Substitute;

namespace kudu {
namespace log {

class LogAnchorRegistryTest : public KuduTest {
};

TEST_F(LogAnchorRegistryTest, TestUpdateRegistration) {
  const string test_name = CURRENT_TEST_NAME();
  scoped_refptr<LogAnchorRegistry> reg(new LogAnchorRegistry());

  LogAnchor anchor;
  const int64_t kInitialIndex = 12345;

  ASSERT_FALSE(anchor.is_registered);
  ASSERT_FALSE(anchor.when_registered.Initialized());
  reg->Register(kInitialIndex, test_name, &anchor);
  SCOPED_CLEANUP({
    ASSERT_OK(reg->Unregister(&anchor));
    ASSERT_FALSE(anchor.is_registered);
  });
  ASSERT_TRUE(anchor.is_registered);
  ASSERT_TRUE(anchor.when_registered.Initialized());
  ASSERT_OK(reg->RegisterOrUpdate(kInitialIndex + 1, test_name, &anchor));
  ASSERT_EQ(kInitialIndex + 1, anchor.log_index);
  ASSERT_OK(reg->Unregister(&anchor));
  ASSERT_FALSE(anchor.is_registered);

  ASSERT_OK(reg->RegisterOrUpdate(kInitialIndex + 2, test_name, &anchor));
  ASSERT_TRUE(anchor.is_registered);
  ASSERT_EQ(kInitialIndex + 2, anchor.log_index);

  ASSERT_OK(reg->RegisterOrUpdate(kInitialIndex + 3, test_name, &anchor));
  ASSERT_TRUE(anchor.is_registered);
  ASSERT_EQ(kInitialIndex + 3, anchor.log_index);
}

TEST_F(LogAnchorRegistryTest, TestDuplicateInserts) {
  const string test_name = CURRENT_TEST_NAME();
  scoped_refptr<LogAnchorRegistry> reg(new LogAnchorRegistry());

  // Register a bunch of anchors at log index 1.
  const int num_anchors = 10;
  LogAnchor anchors[num_anchors];
  for (auto& anchor : anchors) {
    reg->Register(1, test_name, &anchor);
  }

  // We should see index 1 as the earliest registered.
  int64_t first_index = -1;
  ASSERT_OK(reg->GetEarliestRegisteredLogIndex(&first_index));
  ASSERT_EQ(1, first_index);

  // Unregister them all.
  for (auto& anchor : anchors) {
    ASSERT_OK(reg->Unregister(&anchor));
  }

  // We should see none registered.
  Status s = reg->GetEarliestRegisteredLogIndex(&first_index);
  ASSERT_TRUE(s.IsNotFound())
      << Substitute("Should have empty OpId registry. Status: $0, anchor: $1, Num anchors: $2",
                    s.ToString(), first_index, reg->GetAnchorCountForTests());

  ASSERT_EQ(0, reg->GetAnchorCountForTests());
}

// Ensure that the correct results are returned when anchors are added/removed
// out of order.
TEST_F(LogAnchorRegistryTest, TestOrderedEarliestOpId) {
  scoped_refptr<LogAnchorRegistry> reg(new LogAnchorRegistry());
  const int kNumAnchors = 4;
  const string test_name = CURRENT_TEST_NAME();

  LogAnchor anchors[kNumAnchors];

  reg->Register(2, test_name, &anchors[0]);
  reg->Register(3, test_name, &anchors[1]);
  reg->Register(1, test_name, &anchors[2]);
  reg->Register(4, test_name, &anchors[3]);

  ASSERT_STR_CONTAINS(reg->DumpAnchorInfo(), "LogAnchor[index=1");

  int64_t anchor_idx = -1;
  ASSERT_OK(reg->GetEarliestRegisteredLogIndex(&anchor_idx));
  ASSERT_EQ(1, anchor_idx);

  ASSERT_OK(reg->Unregister(&anchors[2]));
  ASSERT_OK(reg->GetEarliestRegisteredLogIndex(&anchor_idx));
  ASSERT_EQ(2, anchor_idx);

  ASSERT_OK(reg->Unregister(&anchors[3]));
  ASSERT_OK(reg->GetEarliestRegisteredLogIndex(&anchor_idx));
  ASSERT_EQ(2, anchor_idx);

  ASSERT_OK(reg->Unregister(&anchors[0]));
  ASSERT_OK(reg->GetEarliestRegisteredLogIndex(&anchor_idx));
  ASSERT_EQ(3, anchor_idx);

  ASSERT_OK(reg->Unregister(&anchors[1]));
  Status s = reg->GetEarliestRegisteredLogIndex(&anchor_idx);
  ASSERT_TRUE(s.IsNotFound()) << s.ToString();
}

} // namespace log
} // namespace kudu
