]> git-server-git.apps.pok.os.sepia.ceph.com Git - ceph.git/commitdiff
Refactor: Extract mock classes from TestPeeringState into separate header files
authorAlex Ainscow <aainscow@uk.ibm.com>
Sat, 28 Feb 2026 23:58:51 +0000 (23:58 +0000)
committerAlex Ainscow <aainscow@uk.ibm.com>
Tue, 24 Mar 2026 13:29:53 +0000 (13:29 +0000)
Move the following mock classes out of TestPeeringState.cc into their own
header files. The code is identical - this is a pure refactor with no
functional changes:

- MockConnection -> MockConnection.h
- MockLog -> MockLog.h
- MockECRecPred -> MockECRecPred.h
- MockECReadPred -> MockECReadPred.h
- MockPGBackendListener -> MockPGBackendListener.h
- MockPGBackend -> MockPGBackend.h
- MockPGLogEntryHandler -> MockPGLogEntryHandler.h
- MockPeeringListener -> MockPeeringListener.h

TestPeeringState.cc is updated to include the new headers instead of
defining the classes inline.

Signed-off-by: Alex Ainscow <aainscow@uk.ibm.com>
src/test/osd/MockConnection.h [new file with mode: 0644]
src/test/osd/MockECReadPred.h [new file with mode: 0644]
src/test/osd/MockECRecPred.h [new file with mode: 0644]
src/test/osd/MockLog.h [new file with mode: 0644]
src/test/osd/MockPGBackend.h [new file with mode: 0644]
src/test/osd/MockPGBackendListener.h [new file with mode: 0644]
src/test/osd/MockPGLogEntryHandler.h [new file with mode: 0644]
src/test/osd/MockPeeringListener.h [new file with mode: 0644]
src/test/osd/TestPeeringState.cc

diff --git a/src/test/osd/MockConnection.h b/src/test/osd/MockConnection.h
new file mode 100644 (file)
index 0000000..a0785c2
--- /dev/null
@@ -0,0 +1,51 @@
+// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:nil -*-
+// vim: ts=8 sw=2 sts=2 expandtab
+/*
+ * Ceph - scalable distributed file system
+ *
+ * Copyright (C) 2026 IBM
+ *
+ * This is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2.1, as published by the Free Software
+ * Foundation.  See file COPYING.
+ *
+ */
+
+#pragma once
+
+#include "msg/Connection.h"
+#include "msg/Message.h"
+#include "global/global_context.h"
+
+//MockConnection - simple stub. Required because PeeringState needs
+//to know the features of the peer OSD which sent a peering message
+class MockConnection : public Connection {
+ public:
+  MockConnection() : Connection(g_ceph_context, nullptr) {
+    set_features(CEPH_FEATURES_ALL);
+  }
+
+  bool is_connected() override {
+    return true;
+  }
+
+  int send_message(Message *m) override {
+    m->put();
+    return 0;
+  }
+
+  void send_keepalive() override {
+  }
+
+  void mark_down() override {
+  }
+
+  void mark_disposable() override {
+  }
+
+  entity_addr_t get_peer_socket_addr() const override {
+    return entity_addr_t();
+  }
+};
+
diff --git a/src/test/osd/MockECReadPred.h b/src/test/osd/MockECReadPred.h
new file mode 100644 (file)
index 0000000..cff7b35
--- /dev/null
@@ -0,0 +1,30 @@
+// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:nil -*-
+// vim: ts=8 sw=2 sts=2 expandtab
+/*
+ * Ceph - scalable distributed file system
+ *
+ * Copyright (C) 2026 IBM
+ *
+ * This is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2.1, as published by the Free Software
+ * Foundation.  See file COPYING.
+ *
+ */
+
+#pragma once
+
+#include <set>
+#include "osd/PGBackend.h"
+
+// MockECReadPred - simple stub for IsPGReadablePredicate
+// Warning - this always returns true. This means we cannot test scenarios
+// where there are too many OSDs down and the PG should be incomplete
+class MockECReadPred : public IsPGReadablePredicate {
+ public:
+  MockECReadPred() {}
+  bool operator()(const std::set<pg_shard_t> &_have) const override {
+    return true;
+  }
+};
+
diff --git a/src/test/osd/MockECRecPred.h b/src/test/osd/MockECRecPred.h
new file mode 100644 (file)
index 0000000..1b60335
--- /dev/null
@@ -0,0 +1,31 @@
+// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:nil -*-
+// vim: ts=8 sw=2 sts=2 expandtab
+/*
+ * Ceph - scalable distributed file system
+ *
+ * Copyright (C) 2026 IBM
+ *
+ * This is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2.1, as published by the Free Software
+ * Foundation.  See file COPYING.
+ *
+ */
+
+#pragma once
+
+#include <set>
+#include "osd/PGBackend.h"
+
+// MockECRecPred - simple stub for IsPGRecoverablePredicate
+// Warning - this always returns true. This means we cannot test scenarios
+// where there are too many OSDs down and the PG should be incomplete
+class MockECRecPred : public IsPGRecoverablePredicate {
+ public:
+  MockECRecPred() {}
+
+  bool operator()(const std::set<pg_shard_t> &_have) const override {
+    return true;
+  }
+};
+
diff --git a/src/test/osd/MockLog.h b/src/test/osd/MockLog.h
new file mode 100644 (file)
index 0000000..e3ee9cf
--- /dev/null
@@ -0,0 +1,107 @@
+// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:nil -*-
+// vim: ts=8 sw=2 sts=2 expandtab
+/*
+ * Ceph - scalable distributed file system
+ *
+ * Copyright (C) 2026 IBM
+ *
+ * This is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2.1, as published by the Free Software
+ * Foundation.  See file COPYING.
+ *
+ */
+
+#pragma once
+
+#include <iostream>
+#include <sstream>
+#include <string>
+#include "common/ostream_temp.h"
+
+//MockLog - simple stub
+class MockLog : public LoggerSinkSet {
+ public:
+  void debug(std::stringstream& s) final
+  {
+    std::cout << "\n<<debug>> " << s.str() << std::endl;
+  }
+
+  void info(std::stringstream& s) final
+  {
+    std::cout << "\n<<info>> " << s.str() << std::endl;
+  }
+
+  void sec(std::stringstream& s) final
+  {
+    std::cout << "\n<<sec>> " << s.str() << std::endl;
+  }
+
+  void warn(std::stringstream& s) final
+  {
+    std::cout << "\n<<warn>> " << s.str() << std::endl;
+  }
+
+  void error(std::stringstream& s) final
+  {
+    err_count++;
+    std::cout << "\n<<error>> " << s.str() << std::endl;
+  }
+
+  OstreamTemp info() final { return OstreamTemp(CLOG_INFO, this); }
+  OstreamTemp warn() final { return OstreamTemp(CLOG_WARN, this); }
+  OstreamTemp error() final { return OstreamTemp(CLOG_ERROR, this); }
+  OstreamTemp sec() final { return OstreamTemp(CLOG_ERROR, this); }
+  OstreamTemp debug() final { return OstreamTemp(CLOG_DEBUG, this); }
+
+  void do_log(clog_type prio, std::stringstream& ss) final
+  {
+    switch (prio) {
+      case CLOG_DEBUG:
+        debug(ss);
+        break;
+      case CLOG_INFO:
+        info(ss);
+        break;
+      case CLOG_SEC:
+        sec(ss);
+        break;
+      case CLOG_WARN:
+        warn(ss);
+        break;
+      case CLOG_ERROR:
+      default:
+        error(ss);
+        break;
+    }
+  }
+
+  void do_log(clog_type prio, const std::string& ss) final
+  {
+    switch (prio) {
+      case CLOG_DEBUG:
+        debug() << ss;
+        break;
+      case CLOG_INFO:
+        info() << ss;
+        break;
+      case CLOG_SEC:
+        sec() << ss;
+        break;
+      case CLOG_WARN:
+        warn() << ss;
+        break;
+      case CLOG_ERROR:
+      default:
+        error() << ss;
+        break;
+    }
+  }
+
+  virtual ~MockLog() {}
+
+  int err_count{0};
+  int expected_err_count{0};
+  void set_expected_err_count(int c) { expected_err_count = c; }
+};
+
diff --git a/src/test/osd/MockPGBackend.h b/src/test/osd/MockPGBackend.h
new file mode 100644 (file)
index 0000000..5be8a21
--- /dev/null
@@ -0,0 +1,159 @@
+// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:nil -*-
+// vim: ts=8 sw=2 sts=2 expandtab
+/*
+ * Ceph - scalable distributed file system
+ *
+ * Copyright (C) 2026 IBM
+ *
+ * This is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2.1, as published by the Free Software
+ * Foundation.  See file COPYING.
+ *
+ */
+
+#pragma once
+
+#include <functional>
+#include <list>
+#include <optional>
+#include <vector>
+#include "osd/PGBackend.h"
+#include "osd/ECUtil.h"
+#include "os/ObjectStore.h"
+
+// MockPGBackend - simple stub for PGBackend
+class MockPGBackend : public PGBackend {
+public:
+  MockPGBackend(CephContext* cct, Listener *l, ObjectStore *store,
+                const coll_t &coll, ObjectStore::CollectionHandle &ch)
+    : PGBackend(cct, l, store, coll, ch) {}
+
+  // Recovery operations
+  RecoveryHandle *open_recovery_op() override {
+    return nullptr;
+  }
+
+  void run_recovery_op(RecoveryHandle *h, int priority) override {
+  }
+
+  int recover_object(
+    const hobject_t &hoid,
+    eversion_t v,
+    ObjectContextRef head,
+    ObjectContextRef obc,
+    RecoveryHandle *h) override {
+    return 0;
+  }
+
+  // Message handling
+  bool can_handle_while_inactive(OpRequestRef op) override {
+    return false;
+  }
+
+  bool _handle_message(OpRequestRef op) override {
+    return false;
+  }
+
+  void check_recovery_sources(const OSDMapRef& osdmap) override {
+  }
+
+  // State management
+  void on_change() override {
+  }
+
+  void clear_recovery_state() override {
+  }
+
+  // Predicates
+  IsPGRecoverablePredicate *get_is_recoverable_predicate() const override {
+    return nullptr;
+  }
+
+  IsPGReadablePredicate *get_is_readable_predicate() const override {
+    return nullptr;
+  }
+
+  bool get_ec_supports_crc_encode_decode() const override {
+    return false;
+  }
+
+  void dump_recovery_info(ceph::Formatter *f) const override {
+  }
+
+  bool ec_can_decode(const shard_id_set &available_shards) const override {
+    return false;
+  }
+
+  shard_id_map<bufferlist> ec_encode_acting_set(
+    const bufferlist &in_bl) const override {
+    return {0};
+  }
+
+  shard_id_map<bufferlist> ec_decode_acting_set(
+    const shard_id_map<bufferlist> &shard_map, int chunk_size) const override {
+    return {0};
+  }
+
+  ECUtil::stripe_info_t ec_get_sinfo() const override {
+    return {0, 0, 0};
+  }
+
+  // Transaction submission
+  void submit_transaction(
+    const hobject_t &hoid,
+    const object_stat_sum_t &delta_stats,
+    const eversion_t &at_version,
+    PGTransactionUPtr &&t,
+    const eversion_t &trim_to,
+    const eversion_t &pg_committed_to,
+    std::vector<pg_log_entry_t>&& log_entries,
+    std::optional<pg_hit_set_history_t> &hset_history,
+    Context *on_all_commit,
+    ceph_tid_t tid,
+    osd_reqid_t reqid,
+    OpRequestRef op) override {
+  }
+
+  void call_write_ordered(std::function<void(void)> &&cb) override {
+    cb();
+  }
+
+  // Object operations
+  int objects_read_sync(
+    const hobject_t &hoid,
+    uint64_t off,
+    uint64_t len,
+    uint32_t op_flags,
+    ceph::buffer::list *bl) override {
+    return 0;
+  }
+
+  void objects_read_async(
+    const hobject_t &hoid,
+    uint64_t object_size,
+    const std::list<std::pair<ec_align_t,
+      std::pair<ceph::buffer::list*, Context*>>> &to_read,
+    Context *on_complete, bool fast_read = false) override {
+  }
+
+  bool auto_repair_supported() const override {
+    return false;
+  }
+
+  uint64_t be_get_ondisk_size(uint64_t logical_size,
+                              shard_id_t shard_id,
+                              bool object_is_legacy_ec) const override {
+    return logical_size;
+  }
+
+  int be_deep_scrub(
+    const Scrub::ScrubCounterSet& io_counters,
+    const hobject_t &oid,
+    ScrubMap &map,
+    ScrubMapBuilder &pos,
+    ScrubMap::object &o) override {
+    return 0;
+  }
+};
+
diff --git a/src/test/osd/MockPGBackendListener.h b/src/test/osd/MockPGBackendListener.h
new file mode 100644 (file)
index 0000000..219e529
--- /dev/null
@@ -0,0 +1,401 @@
+// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:nil -*-
+// vim: ts=8 sw=2 sts=2 expandtab
+/*
+ * Ceph - scalable distributed file system
+ *
+ * Copyright (C) 2026 IBM
+ *
+ * This is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2.1, as published by the Free Software
+ * Foundation.  See file COPYING.
+ *
+ */
+
+#pragma once
+
+#include <map>
+#include <set>
+#include <optional>
+#include "osd/PGBackend.h"
+#include "osd/OSDMap.h"
+#include "osd/osd_types.h"
+#include "osd/PGLog.h"
+#include "common/intrusive_timer.h"
+#include "common/ostream_temp.h"
+#include "global/global_context.h"
+#include "os/ObjectStore.h"
+
+// MockPGBackendListener - simple stub for PGBackend::Listener
+class MockPGBackendListener : public PGBackend::Listener {
+public:
+  pg_info_t info;
+  OSDMapRef osdmap;
+  const pg_pool_t pool;
+  PGLog log;
+  DoutPrefixProvider *dpp;
+  pg_shard_t pg_whoami;
+  std::set<pg_shard_t> shardset;
+  std::map<pg_shard_t, pg_info_t> shard_info;
+  std::map<pg_shard_t, pg_missing_t> shard_missing;
+  std::map<hobject_t, std::set<pg_shard_t>> missing_loc_shards;
+  pg_missing_tracker_t local_missing;
+
+  MockPGBackendListener(OSDMapRef osdmap, const pg_pool_t pi, DoutPrefixProvider *dpp, pg_shard_t pg_whoami) :
+    osdmap(osdmap), pool(pi), log(g_ceph_context), dpp(dpp), pg_whoami(pg_whoami) {}
+
+  // Debugging
+  DoutPrefixProvider *get_dpp() override {
+    return dpp;
+  }
+
+  // Recovery callbacks
+  void on_local_recover(
+    const hobject_t &oid,
+    const ObjectRecoveryInfo &recovery_info,
+    ObjectContextRef obc,
+    bool is_delete,
+    ObjectStore::Transaction *t) override {
+  }
+
+  void on_global_recover(
+    const hobject_t &oid,
+    const object_stat_sum_t &stat_diff,
+    bool is_delete) override {
+  }
+
+  void on_peer_recover(
+    pg_shard_t peer,
+    const hobject_t &oid,
+    const ObjectRecoveryInfo &recovery_info) override {
+  }
+
+  void begin_peer_recover(
+    pg_shard_t peer,
+    const hobject_t oid) override {
+  }
+
+  void apply_stats(
+    const hobject_t &soid,
+    const object_stat_sum_t &delta_stats) override {
+  }
+
+  void on_failed_pull(
+    const std::set<pg_shard_t> &from,
+    const hobject_t &soid,
+    const eversion_t &v) override {
+  }
+
+  void cancel_pull(const hobject_t &soid) override {
+  }
+
+  void remove_missing_object(
+    const hobject_t &oid,
+    eversion_t v,
+    Context *on_complete) override {
+  }
+
+  // Locking
+  void pg_lock() override {}
+  void pg_unlock() override {}
+  void pg_add_ref() override {}
+  void pg_dec_ref() override {}
+
+  // Context wrapping
+  Context *bless_context(Context *c) override {
+    return c;
+  }
+
+  GenContext<ThreadPool::TPHandle&> *bless_gencontext(
+    GenContext<ThreadPool::TPHandle&> *c) override {
+    return c;
+  }
+
+  GenContext<ThreadPool::TPHandle&> *bless_unlocked_gencontext(
+    GenContext<ThreadPool::TPHandle&> *c) override {
+    return c;
+  }
+
+  // Messaging
+  void send_message(int to_osd, Message *m) override {
+  }
+
+  void queue_transaction(
+    ObjectStore::Transaction&& t,
+    OpRequestRef op = OpRequestRef()) override {
+  }
+
+  void queue_transactions(
+    std::vector<ObjectStore::Transaction>& tls,
+    OpRequestRef op = OpRequestRef()) override {
+  }
+
+  epoch_t get_interval_start_epoch() const override {
+    return 1;
+  }
+
+  epoch_t get_last_peering_reset_epoch() const override {
+    return 1;
+  }
+
+  // Shard information
+  const std::set<pg_shard_t> &get_acting_recovery_backfill_shards() const override {
+    return shardset;
+  }
+
+  const std::set<pg_shard_t> &get_acting_shards() const override {
+    return shardset;
+  }
+
+  const std::set<pg_shard_t> &get_backfill_shards() const override {
+    return shardset;
+  }
+
+  std::ostream& gen_dbg_prefix(std::ostream& out) const override {
+    return out << "MockPGBackend ";
+  }
+
+  const std::map<hobject_t, std::set<pg_shard_t>> &get_missing_loc_shards() const override {
+    return missing_loc_shards;
+  }
+
+  const pg_missing_tracker_t &get_local_missing() const override {
+    return local_missing;
+  }
+
+  void add_local_next_event(const pg_log_entry_t& e) override {
+  }
+
+  const std::map<pg_shard_t, pg_missing_t> &get_shard_missing() const override {
+    return shard_missing;
+  }
+
+  const pg_missing_const_i &get_shard_missing(pg_shard_t peer) const override {
+    return local_missing;
+  }
+
+  const std::map<pg_shard_t, pg_info_t> &get_shard_info() const override {
+    return shard_info;
+  }
+
+  const PGLog &get_log() const override {
+    return log;
+  }
+
+  bool pgb_is_primary() const override {
+    return true;
+  }
+
+  const OSDMapRef& pgb_get_osdmap() const override {
+    return osdmap;
+  }
+
+  epoch_t pgb_get_osdmap_epoch() const override {
+    return osdmap->get_epoch();
+  }
+
+  const pg_info_t &get_info() const override {
+    return info;
+  }
+
+  const pg_pool_t &get_pool() const override {
+    return pool;
+  }
+
+  eversion_t get_pg_committed_to() const override {
+    return eversion_t();
+  }
+
+  ObjectContextRef get_obc(
+    const hobject_t &hoid,
+    const std::map<std::string, ceph::buffer::list, std::less<>> &attrs) override {
+    return ObjectContextRef();
+  }
+
+  bool try_lock_for_read(
+    const hobject_t &hoid,
+    ObcLockManager &manager) override {
+    return true;
+  }
+
+  void release_locks(ObcLockManager &manager) override {
+  }
+
+  void op_applied(const eversion_t &applied_version) override {
+  }
+
+  bool should_send_op(pg_shard_t peer, const hobject_t &hoid) override {
+    return true;
+  }
+
+  bool pg_is_undersized() const override {
+    return false;
+  }
+
+  bool pg_is_repair() const override {
+    return false;
+  }
+
+#if POOL_MIGRATION
+  void update_migration_watermark(const hobject_t &watermark) override {
+  }
+#endif
+
+#if POOL_MIGRATION
+  std::optional<hobject_t> consider_updating_migration_watermark(
+    std::set<hobject_t> &deleted) override {
+    return std::nullopt;
+  }
+#endif
+
+  void log_operation(
+    std::vector<pg_log_entry_t>&& logv,
+    const std::optional<pg_hit_set_history_t> &hset_history,
+    const eversion_t &trim_to,
+    const eversion_t &roll_forward_to,
+    const eversion_t &pg_committed_to,
+    bool transaction_applied,
+    ObjectStore::Transaction &t,
+    bool async = false) override {
+  }
+
+  void pgb_set_object_snap_mapping(
+    const hobject_t &soid,
+    const std::set<snapid_t> &snaps,
+    ObjectStore::Transaction *t) override {
+  }
+
+  void pgb_clear_object_snap_mapping(
+    const hobject_t &soid,
+    ObjectStore::Transaction *t) override {
+  }
+
+  void update_peer_last_complete_ondisk(
+    pg_shard_t fromosd,
+    eversion_t lcod) override {
+  }
+
+  void update_last_complete_ondisk(eversion_t lcod) override {
+  }
+
+  void update_pct(eversion_t pct) override {
+  }
+
+  void update_stats(const pg_stat_t &stat) override {
+  }
+
+  void schedule_recovery_work(
+    GenContext<ThreadPool::TPHandle&> *c,
+    uint64_t cost) override {
+  }
+
+  common::intrusive_timer &get_pg_timer() override {
+    ceph_abort("Not supported");
+  }
+
+  pg_shard_t whoami_shard() const override {
+    return pg_whoami;
+  }
+
+  spg_t primary_spg_t() const override {
+    return spg_t();
+  }
+
+  pg_shard_t primary_shard() const override {
+    return pg_shard_t();
+  }
+
+  uint64_t min_peer_features() const override {
+    return CEPH_FEATURES_ALL;
+  }
+
+  uint64_t min_upacting_features() const override {
+    return CEPH_FEATURES_ALL;
+  }
+
+  pg_feature_vec_t get_pg_acting_features() const override {
+    return pg_feature_vec_t();
+  }
+
+  hobject_t get_temp_recovery_object(
+    const hobject_t& target,
+    eversion_t version) override {
+    return hobject_t();
+  }
+
+  void send_message_osd_cluster(
+    int peer, Message *m, epoch_t from_epoch) override {
+  }
+
+  void send_message_osd_cluster(
+    std::vector<std::pair<int, Message*>>& messages, epoch_t from_epoch) override {
+  }
+
+  void send_message_osd_cluster(MessageRef, Connection *con) override {
+  }
+
+  void send_message_osd_cluster(Message *m, const ConnectionRef& con) override {
+  }
+
+  void start_mon_command(
+    std::vector<std::string>&& cmd, bufferlist&& inbl,
+    bufferlist *outbl, std::string *outs,
+    Context *onfinish) override {
+  }
+
+  ConnectionRef get_con_osd_cluster(int peer, epoch_t from_epoch) override {
+    return nullptr;
+  }
+
+  entity_name_t get_cluster_msgr_name() override {
+    return entity_name_t();
+  }
+
+  PerfCounters *get_logger() override {
+    return nullptr;
+  }
+
+  ceph_tid_t get_tid() override {
+    return 0;
+  }
+
+  OstreamTemp clog_error() override {
+    return OstreamTemp(CLOG_ERROR, nullptr);
+  }
+
+  OstreamTemp clog_warn() override {
+    return OstreamTemp(CLOG_WARN, nullptr);
+  }
+
+  bool check_failsafe_full() override {
+    return false;
+  }
+
+  void inc_osd_stat_repaired() override {
+  }
+
+  bool pg_is_remote_backfilling() override {
+    return false;
+  }
+
+  void pg_add_local_num_bytes(int64_t num_bytes) override {
+  }
+
+  void pg_sub_local_num_bytes(int64_t num_bytes) override {
+  }
+
+  void pg_add_num_bytes(int64_t num_bytes) override {
+  }
+
+  void pg_sub_num_bytes(int64_t num_bytes) override {
+  }
+
+  bool maybe_preempt_replica_scrub(const hobject_t& oid) override {
+    return false;
+  }
+
+  struct ECListener *get_eclistener() override {
+    return nullptr;
+  }
+};
+
diff --git a/src/test/osd/MockPGLogEntryHandler.h b/src/test/osd/MockPGLogEntryHandler.h
new file mode 100644 (file)
index 0000000..629d335
--- /dev/null
@@ -0,0 +1,71 @@
+// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:nil -*-
+// vim: ts=8 sw=2 sts=2 expandtab
+/*
+ * Ceph - scalable distributed file system
+ *
+ * Copyright (C) 2026 IBM
+ *
+ * This is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2.1, as published by the Free Software
+ * Foundation.  See file COPYING.
+ *
+ */
+
+#pragma once
+
+#include "osd/PGLog.h"
+#include "os/ObjectStore.h"
+#include "test/osd/MockPGBackend.h"
+
+// dout using global context and OSD subsystem
+#define dout_context g_ceph_context
+#define dout_subsys ceph_subsys_osd
+
+// MockPGLogEntryHandler
+//
+// This is a fully functional implementation of the PGLog::LogEntryHandler
+// interface. It calls code in PGBackend to perform the requested operations
+// although some of the stubs in MockPGBackend return questionable information
+// about the object size so the generated ObjectStore::Transaction is probably
+// not correct. The main purpose is to use partial_write to update the PWLC
+// information when appending entries to the log
+class MockPGLogEntryHandler : public PGLog::LogEntryHandler {
+ public:
+  MockPGBackend *backend;
+  ObjectStore::Transaction *t;
+  MockPGLogEntryHandler(MockPGBackend *backend, ObjectStore::Transaction *t) : backend(backend), t(t) {}
+
+  // LogEntryHandler
+  void remove(const hobject_t &hoid) override {
+    dout(0) << "MockPGLogEntryHandler::remove " << hoid << dendl;
+    backend->remove(hoid, t);
+  }
+  void try_stash(const hobject_t &hoid, version_t v) override {
+    dout(0) << "MockPGLogEntryHandler::try_stash " << hoid << " " << v << dendl;
+    backend->try_stash(hoid, v, t);
+  }
+  void rollback(const pg_log_entry_t &entry) override {
+    dout(0) << "MockPGLogEntryHandler::rollback " << entry << dendl;
+    ceph_assert(entry.can_rollback());
+    backend->rollback(entry, t);
+  }
+  void rollforward(const pg_log_entry_t &entry) override {
+    dout(0) << "MockPGLogEntryHandler::rollforward " << entry << dendl;
+    backend->rollforward(entry, t);
+  }
+  void trim(const pg_log_entry_t &entry) override {
+    dout(0) << "MockPGLogEntryHandler::trim " << entry << dendl;
+    backend->trim(entry, t);
+  }
+  void partial_write(pg_info_t *info, eversion_t previous_version,
+                      const pg_log_entry_t &entry
+    ) override {
+    dout(0) << "MockPGLogEntryHandler::partial_write " << entry << dendl;
+    backend->partial_write(info, previous_version, entry);
+  }
+};
+
+#undef dout_context
+#undef dout_subsys
+
diff --git a/src/test/osd/MockPeeringListener.h b/src/test/osd/MockPeeringListener.h
new file mode 100644 (file)
index 0000000..d2e9140
--- /dev/null
@@ -0,0 +1,572 @@
+// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:nil -*-
+// vim: ts=8 sw=2 sts=2 expandtab
+/*
+ * Ceph - scalable distributed file system
+ *
+ * Copyright (C) 2026 IBM
+ *
+ * This is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2.1, as published by the Free Software
+ * Foundation.  See file COPYING.
+ *
+ */
+
+#pragma once
+
+#include <list>
+#include <map>
+#include <memory>
+#include <set>
+#include <string>
+#include <vector>
+#include "osd/PeeringState.h"
+#include "osd/osd_perf_counters.h"
+#include "common/perf_counters_collection.h"
+#include "global/global_context.h"
+#include "os/ObjectStore.h"
+#include "test/osd/MockLog.h"
+#include "test/osd/MockPGBackend.h"
+#include "test/osd/MockPGBackendListener.h"
+#include "test/osd/MockPGLogEntryHandler.h"
+
+// dout using global context and OSD subsystem
+#define dout_context g_ceph_context
+#define dout_subsys ceph_subsys_osd
+
+using namespace std;
+
+// Mock PeeringListener - stub of PeeringState::PeeringListener
+// to help with testing of PeeringState. Keep track of calls
+// from PeeringState and emulate some of PrimaryLogPG/PG
+// functionality for testing purposes.
+//
+// There are some inject_* variables that can be used to help
+// tests create race hazards or test failure paths
+class MockPeeringListener : public PeeringState::PeeringListener {
+ public:
+  pg_shard_t pg_whoami;
+  MockLog logger;
+  PeeringState *ps;
+  unique_ptr<MockPGBackendListener> backend_listener;
+  coll_t coll;
+  ObjectStore::CollectionHandle ch;
+  unique_ptr<MockPGBackend> backend;
+  PerfCounters* recoverystate_perf;
+  PerfCounters* logger_perf;
+  std::vector<int> next_acting;
+
+#ifdef WITH_CRIMSON
+  // Per OSD state
+  std::map<int,std::list<MessageURef>> messages;
+#else
+  // Per OSD state
+  std::map<int,std::list<MessageRef>> messages;
+#endif
+  std::vector<HeartbeatStampsRef> hb_stamps;
+  std::list<PGPeeringEventRef> events;
+  std::list<PGPeeringEventRef> stalled_events;
+
+  // By default MockPeeringListener will add events to the event queue immediately
+  // simulating the responses that PrimaryLogPG normally generates. These inject
+  // booleans can change the behavior to test other code paths
+
+  // If inject_event_stall is true then events are added to the stalled_events list
+  // and the test case must manually dispatch the event
+  bool inject_event_stall = false;
+
+  // If inject_keep_preempt is true then the preempt event for a local/remote
+  // reservation is added to the stalled_events list so the test case can later
+  // dispatch this event to test a preempted reservation
+  bool inject_keep_preempt = false;
+
+  // If inject_fail_reserve_recovery_space is true then reject backfill/pool
+  // migration requests with too full
+  bool inject_fail_reserve_recovery_space = false;
+
+  MockPeeringListener(OSDMapRef osdmap,
+                      const pg_pool_t pi,
+                      DoutPrefixProvider *dpp,
+                      pg_shard_t pg_whoami) : pg_whoami(pg_whoami) {
+    backend_listener = make_unique<MockPGBackendListener>(osdmap, pi, dpp, pg_whoami);
+    backend = make_unique<MockPGBackend>(g_ceph_context, backend_listener.get(), nullptr, coll, ch);
+    recoverystate_perf = build_recoverystate_perf(g_ceph_context);
+    g_ceph_context->get_perfcounters_collection()->add(recoverystate_perf);
+    logger_perf = build_osd_logger(g_ceph_context);
+    g_ceph_context->get_perfcounters_collection()->add(logger_perf);
+  }
+
+  // EpochSource interface
+  epoch_t get_osdmap_epoch() const override {
+    return current_epoch;
+  }
+
+  // PeeringListener interface
+  void prepare_write(
+    pg_info_t &info,
+    pg_info_t &last_written_info,
+    PastIntervals &past_intervals,
+    PGLog &pglog,
+    bool dirty_info,
+    bool dirty_big_info,
+    bool need_write_epoch,
+    ObjectStore::Transaction &t) override {
+    prepare_write_called = true;
+  }
+
+  void scrub_requested(scrub_level_t scrub_level, scrub_type_t scrub_type) override {
+    scrub_requested_called = true;
+  }
+
+  uint64_t get_snap_trimq_size() const override {
+    return snap_trimq_size;
+  }
+
+#ifdef WITH_CRIMSON
+  void send_cluster_message(
+    int osd, MessageURef m, epoch_t epoch, bool share_map_update=false) override {
+    dout(0) << "send_cluster_message to " << osd << " " << m << dendl;
+    messages[osd].push_back(m);
+    messages_sent++;
+  }
+#else
+  void send_cluster_message(
+    int osd, MessageRef m, epoch_t epoch, bool share_map_update=false) override {
+    dout(0) << "send_cluster_message to " << osd << " " << m << dendl;
+    messages[osd].push_back(m);
+    messages_sent++;
+  }
+#endif
+
+  void send_pg_created(pg_t pgid) override {
+    pg_created_sent = true;
+  }
+  ceph::signedspan get_mnow() const override {
+    return ceph::signedspan::zero();
+  }
+
+  HeartbeatStampsRef get_hb_stamps(int peer) override {
+    if (peer >= (int)hb_stamps.size()) {
+      hb_stamps.resize(peer + 1);
+    }
+    if (!hb_stamps[peer]) {
+      hb_stamps[peer] = ceph::make_ref<HeartbeatStamps>(peer);
+    }
+    return hb_stamps[peer];
+  }
+
+  void schedule_renew_lease(epoch_t plr, ceph::timespan delay) override {
+    renew_lease_scheduled = true;
+  }
+
+  void queue_check_readable(epoch_t lpr, ceph::timespan delay) override {
+    check_readable_queued = true;
+  }
+
+  void recheck_readable() override {
+    readable_rechecked = true;
+  }
+
+  unsigned get_target_pg_log_entries() const override {
+    return target_pg_log_entries;
+  }
+
+
+  bool try_flush_or_schedule_async() override {
+    return true;
+  }
+
+  void start_flush_on_transaction(ObjectStore::Transaction &t) override {
+    flush_started = true;
+  }
+
+  void on_flushed() override {
+    flushed = true;
+  }
+
+  void schedule_event_after(
+    PGPeeringEventRef event,
+    float delay) override {
+    stalled_events.push_back(std::move(event));
+    events_scheduled++;
+  }
+
+  void request_local_background_io_reservation(
+    unsigned priority,
+    PGPeeringEventURef on_grant,
+    PGPeeringEventURef on_preempt) override {
+    if (inject_event_stall) {
+      stalled_events.push_back(std::move(on_grant));
+    } else {
+      events.push_back(std::move(on_grant));
+    }
+    if (inject_keep_preempt) {
+      stalled_events.push_back(std::move(on_preempt));
+    }
+    io_reservations_requested++;
+  }
+
+  void update_local_background_io_priority(
+    unsigned priority) override {
+    io_priority_updated = true;
+  }
+
+  void cancel_local_background_io_reservation() override {
+    io_reservation_cancelled = true;
+  }
+
+  void request_remote_recovery_reservation(
+    unsigned priority,
+    PGPeeringEventURef on_grant,
+    PGPeeringEventURef on_preempt) override {
+    if (inject_event_stall) {
+      stalled_events.push_back(std::move(on_grant));
+    } else {
+      events.push_back(std::move(on_grant));
+    }
+    if (inject_keep_preempt) {
+      stalled_events.push_back(std::move(on_preempt));
+    }
+    remote_recovery_reservations_requested++;
+  }
+
+  void cancel_remote_recovery_reservation() override {
+    remote_recovery_reservation_cancelled = true;
+  }
+
+  void schedule_event_on_commit(
+    ObjectStore::Transaction &t,
+    PGPeeringEventRef on_commit) override {
+    if (inject_event_stall) {
+      stalled_events.push_back(std::move(on_commit));
+    } else {
+      events.push_back(std::move(on_commit));
+    }
+    events_on_commit_scheduled++;
+  }
+
+  void update_heartbeat_peers(std::set<int> peers) override {
+    heartbeat_peers_updated = true;
+  }
+
+  void set_probe_targets(const std::set<pg_shard_t> &probe_set) override {
+    probe_targets_set = true;
+  }
+
+  void clear_probe_targets() override {
+    probe_targets_cleared = true;
+  }
+
+  void queue_want_pg_temp(const std::vector<int> &wanted) override {
+    pg_temp_wanted = true;
+    next_acting = wanted;
+  }
+
+  void clear_want_pg_temp() override {
+    pg_temp_cleared = true;
+  }
+
+#if POOL_MIGRATION
+  void send_pg_migrated_pool() override {
+    pg_migrated_pool_sent = true;
+  }
+#endif
+
+  void publish_stats_to_osd() override {
+    stats_published = true;
+  }
+
+  void clear_publish_stats() override {
+    stats_cleared = true;
+  }
+
+  void check_recovery_sources(const OSDMapRef& newmap) override {
+    recovery_sources_checked = true;
+  }
+
+  void check_blocklisted_watchers() override {
+    blocklisted_watchers_checked = true;
+  }
+
+  void clear_primary_state() override {
+    primary_state_cleared = true;
+  }
+
+  void on_active_exit() override {
+    active_exited = true;
+  }
+
+  void on_active_actmap() override {
+    active_actmap_called = true;
+  }
+
+  void on_active_advmap(const OSDMapRef &osdmap) override {
+    active_advmap_called = true;
+  }
+
+  void on_backfill_reserved() override {
+    backfill_reserved = true;
+  }
+
+  void on_recovery_reserved() override {
+    recovery_reserved = true;
+  }
+
+  Context *on_clean() override {
+    clean_called = true;
+    return nullptr;
+  }
+
+  void on_activate(interval_set<snapid_t> snaps) override {
+    activate_called = true;
+  }
+
+  void on_change(ObjectStore::Transaction &t) override {
+    first_write_in_interval = true;
+    change_called = true;
+  }
+
+  std::pair<ghobject_t, bool> do_delete_work(
+    ObjectStore::Transaction &t, ghobject_t _next) override {
+    delete_work_done = true;
+    return std::make_pair(ghobject_t(), true);
+  }
+
+  void clear_ready_to_merge() override {
+    ready_to_merge_cleared = true;
+  }
+
+  void set_not_ready_to_merge_target(pg_t pgid, pg_t src) override {
+    not_ready_to_merge_target_set = true;
+  }
+
+  void set_not_ready_to_merge_source(pg_t pgid) override {
+    not_ready_to_merge_source_set = true;
+  }
+
+  void set_ready_to_merge_target(eversion_t lu, epoch_t les, epoch_t lec) override {
+    ready_to_merge_target_set = true;
+  }
+
+  void set_ready_to_merge_source(eversion_t lu) override {
+    ready_to_merge_source_set = true;
+  }
+
+  epoch_t cluster_osdmap_trim_lower_bound() override {
+    return 1;
+  }
+
+  void on_backfill_suspended() override {
+    backfill_suspended = true;
+  }
+
+  void on_recovery_cancelled() override {
+    recovery_cancelled = true;
+  }
+
+#if POOL_MIGRATION
+  void on_pool_migration_reserved() override {
+    pool_migration_reserved = true;
+  }
+#endif
+
+#if POOL_MIGRATION
+  void on_pool_migration_suspended() override {
+    pool_migration_suspended = true;
+  }
+#endif
+
+  bool try_reserve_recovery_space(
+    int64_t primary_num_bytes,
+    int64_t local_num_bytes) override {
+    recovery_space_reserved = true;
+    if (inject_fail_reserve_recovery_space) {
+      return false;
+    }
+    return true;
+  }
+
+  void unreserve_recovery_space() override {
+    recovery_space_unreserved = true;
+  }
+
+  PGLog::LogEntryHandlerRef get_log_handler(
+    ObjectStore::Transaction &t) override {
+    return std::make_unique<MockPGLogEntryHandler>(backend.get(), &t);
+  }
+
+  void rebuild_missing_set_with_deletes(PGLog &pglog) override {
+    missing_set_rebuilt = true;
+  }
+
+  PerfCounters &get_peering_perf() override {
+    return *recoverystate_perf;
+  }
+
+  PerfCounters &get_perf_logger() override {
+    return *logger_perf;
+  }
+
+  void log_state_enter(const char *state) override {
+    last_state_entered = string(state);
+    state_entered = true;
+  }
+
+  void log_state_exit(
+    const char *state_name, utime_t enter_time,
+    uint64_t events, utime_t event_dur) override {
+    last_state_exited = string(state_name);
+    state_exited = true;
+  }
+
+  void dump_recovery_info(ceph::Formatter *f) const override {
+    recovery_info_dumped = true;
+  }
+
+  OstreamTemp get_clog_info() override {
+    return logger.info();
+  }
+
+  OstreamTemp get_clog_error() override {
+    return logger.error();
+  }
+
+  OstreamTemp get_clog_debug() override {
+    return logger.debug();
+  }
+
+  void on_activate_complete() override {
+    dout(0) << __func__ << dendl;
+    std::list<PGPeeringEventRef> *event_queue;
+    if (inject_event_stall) {
+      event_queue = &stalled_events;
+    } else {
+      event_queue = &events;
+    }
+
+    if (ps->needs_recovery()) {
+      dout(10) << "activate not all replicas are up-to-date, queueing recovery" << dendl;
+      event_queue->push_back(
+          std::make_shared<PGPeeringEvent>(
+            get_osdmap_epoch(),
+            get_osdmap_epoch(),
+            PeeringState::DoRecovery()));
+    } else if (ps->needs_backfill()) {
+      dout(10) << "activate queueing backfill" << dendl;
+      event_queue->push_back(
+          std::make_shared<PGPeeringEvent>(
+            get_osdmap_epoch(),
+            get_osdmap_epoch(),
+            PeeringState::RequestBackfill()));
+#if POOL_MIGRATION
+    } else if (ps->needs_pool_migration()) {
+      dout(10) << "activate queueing pool migration" << dendl;
+      event_queue->push_back(
+          std::make_shared<PGPeeringEvent>(
+            get_osdmap_epoch(),
+            get_osdmap_epoch(),
+            PeeringState::DoPoolMigration()));
+#endif
+    } else {
+      dout(10) << "activate all replicas clean, no recovery" << dendl;
+      event_queue->push_back(
+          std::make_shared<PGPeeringEvent>(
+            get_osdmap_epoch(),
+            get_osdmap_epoch(),
+            PeeringState::AllReplicasRecovered()));
+    }
+    activate_complete_called = true;
+  }
+
+  void on_activate_committed() override {
+    activate_committed_called = true;
+  }
+
+  void on_new_interval() override {
+    new_interval_called = true;
+  }
+
+  void on_pool_change() override {
+    pool_changed = true;
+  }
+
+  void on_role_change() override {
+    role_changed = true;
+  }
+
+  void on_removal(ObjectStore::Transaction &t) override {
+    removal_called = true;
+  }
+
+  // Test state tracking
+  unsigned target_pg_log_entries = 100;
+  bool renew_lease_scheduled = false;
+  bool check_readable_queued = false;
+  bool readable_rechecked = false;
+  bool heartbeat_peers_updated = false;
+  bool probe_targets_set = false;
+  bool probe_targets_cleared = false;
+  bool pg_temp_wanted = false;
+  bool pg_temp_cleared = false;
+  bool pg_migrated_pool_sent = false;
+  bool stats_published = false;
+  bool stats_cleared = false;
+  bool recovery_sources_checked = false;
+  bool blocklisted_watchers_checked = false;
+  bool primary_state_cleared = false;
+  bool delete_work_done = false;
+  bool ready_to_merge_cleared = false;
+  bool not_ready_to_merge_target_set = false;
+  bool not_ready_to_merge_source_set = false;
+  bool ready_to_merge_target_set = false;
+  bool ready_to_merge_source_set = false;
+  bool backfill_suspended = false;
+  bool recovery_cancelled = false;
+  bool pool_migration_reserved = false;
+  bool pool_migration_suspended = false;
+  bool recovery_space_reserved = false;
+  bool recovery_space_unreserved = false;
+  bool missing_set_rebuilt = false;
+  string last_state_entered;
+  bool state_entered = false;
+  string last_state_exited;
+  bool state_exited = false;
+  mutable bool recovery_info_dumped = false;
+  epoch_t current_epoch = 1;
+  uint64_t snap_trimq_size = 0;
+  bool prepare_write_called = false;
+  bool scrub_requested_called = false;
+  bool pg_created_sent = false;
+  bool flush_started = false;
+  bool flushed = false;
+  bool io_priority_updated = false;
+  bool io_reservation_cancelled = false;
+  bool remote_recovery_reservation_cancelled = false;
+  bool active_exited = false;
+  bool active_actmap_called = false;
+  bool active_advmap_called = false;
+  bool backfill_reserved = false;
+  bool backfill_cancelled = false;
+  bool recovery_reserved = false;
+  bool clean_called = false;
+  bool activate_called = false;
+  bool activate_complete_called = false;
+  bool change_called = false;
+  bool activate_committed_called = false;
+  bool new_interval_called = false;
+  bool primary_status_changed = false;
+  bool pool_changed = false;
+  bool role_changed = false;
+  bool removal_called = false;
+  bool shutdown_called = false;
+  int messages_sent = 0;
+  int events_scheduled = 0;
+  int io_reservations_requested = 0;
+  int remote_recovery_reservations_requested = 0;
+  int events_on_commit_scheduled = 0;
+  bool first_write_in_interval = false;
+};
+
+#undef dout_context
+#undef dout_subsys
+
index 7552304842b2dd99e7251a145526f2be7479f04a..1013cc30e3b6c73f89a188d7d98ad1f69342ed96 100644 (file)
 
 #include <memory>
 #include <gtest/gtest.h>
-#include "osd/PeeringState.h"
-#include "osd/PGBackend.h"
-#include "osd/ReplicatedBackend.h"
-#include "osd/ECBackend.h"
-#include "osd/OSDMap.h"
-#include "osd/osd_types.h"
-#include "osd/osd_perf_counters.h"
-#include "common/ceph_context.h"
-#include "common/ostream_temp.h"
-#include "common/perf_counters_collection.h"
-#include "common/WorkQueue.h"
-#include "common/intrusive_timer.h"
-#include "global/global_context.h"
+#include "test/osd/MockConnection.h"
+#include "test/osd/MockECRecPred.h"
+#include "test/osd/MockECReadPred.h"
+#include "test/osd/MockPeeringListener.h"
 #include "global/global_init.h"
 #include "messages/MOSDPeeringOp.h"
 #include "msg/Connection.h"
 
 using namespace std;
 
-//MockConnection - simple stub. Required because PeeringState needs
-//to know the features of the peer OSD which sent a peering message
-class MockConnection : public Connection {
- public:
-  MockConnection() : Connection(g_ceph_context, nullptr) {
-    set_features(CEPH_FEATURES_ALL);
-  }
-
-  bool is_connected() override {
-    return true;
-  }
-
-  int send_message(Message *m) override {
-    m->put();
-    return 0;
-  }
-
-  void send_keepalive() override {
-  }
-
-  void mark_down() override {
-  }
-
-  void mark_disposable() override {
-  }
-
-  entity_addr_t get_peer_socket_addr() const override {
-    return entity_addr_t();
-  }
-};
-
-//MockLog - simple stub
-class MockLog : public LoggerSinkSet {
- public:
-  void debug(std::stringstream& s) final
-  {
-    std::cout << "\n<<debug>> " << s.str() << std::endl;
-  }
-
-  void info(std::stringstream& s) final
-  {
-    std::cout << "\n<<info>> " << s.str() << std::endl;
-  }
-
-  void sec(std::stringstream& s) final
-  {
-    std::cout << "\n<<sec>> " << s.str() << std::endl;
-  }
-
-  void warn(std::stringstream& s) final
-  {
-    std::cout << "\n<<warn>> " << s.str() << std::endl;
-  }
-
-  void error(std::stringstream& s) final
-  {
-    err_count++;
-    std::cout << "\n<<error>> " << s.str() << std::endl;
-  }
-
-  OstreamTemp info() final { return OstreamTemp(CLOG_INFO, this); }
-  OstreamTemp warn() final { return OstreamTemp(CLOG_WARN, this); }
-  OstreamTemp error() final { return OstreamTemp(CLOG_ERROR, this); }
-  OstreamTemp sec() final { return OstreamTemp(CLOG_ERROR, this); }
-  OstreamTemp debug() final { return OstreamTemp(CLOG_DEBUG, this); }
-
-  void do_log(clog_type prio, std::stringstream& ss) final
-  {
-    switch (prio) {
-      case CLOG_DEBUG:
-        debug(ss);
-        break;
-      case CLOG_INFO:
-        info(ss);
-        break;
-      case CLOG_SEC:
-        sec(ss);
-        break;
-      case CLOG_WARN:
-        warn(ss);
-        break;
-      case CLOG_ERROR:
-      default:
-        error(ss);
-        break;
-    }
-  }
-
-  void do_log(clog_type prio, const std::string& ss) final
-  {
-    switch (prio) {
-      case CLOG_DEBUG:
-        debug() << ss;
-        break;
-      case CLOG_INFO:
-        info() << ss;
-        break;
-      case CLOG_SEC:
-        sec() << ss;
-        break;
-      case CLOG_WARN:
-        warn() << ss;
-        break;
-      case CLOG_ERROR:
-      default:
-        error() << ss;
-        break;
-    }
-  }
-
-  virtual ~MockLog() {}
-
-  int err_count{0};
-  int expected_err_count{0};
-  void set_expected_err_count(int c) { expected_err_count = c; }
-};
-
-// MockECRecPred - simple stub for IsPGRecoverablePredicate
-// Warning - this always returns true. This means we cannot test scenarios
-// where there are too many OSDs down and the PG should be incomplete
-class MockECRecPred : public IsPGRecoverablePredicate {
- public:
-  MockECRecPred() {}
-
-  bool operator()(const std::set<pg_shard_t> &_have) const override {
-    return true;
-  }
-};
 
 IsPGRecoverablePredicate *get_is_recoverable_predicate() {
   return new MockECRecPred();
 }
 
-// MockECReadPred - simple stub for IsPGReadablePredicate
-// Warning - this always returns true. This means we cannot test scenarios
-// where there are too many OSDs down and the PG should be incomplete
-class MockECReadPred : public IsPGReadablePredicate {
- public:
-  MockECReadPred() {}
-  bool operator()(const std::set<pg_shard_t> &_have) const override {
-    return true;
-  }
-};
-
 IsPGReadablePredicate *get_is_readable_predicate() {
   return new MockECReadPred();
 }
 
-// MockPGBackendListener - simple stub for PGBackend::Listener
-class MockPGBackendListener : public PGBackend::Listener {
-public:
-  pg_info_t info;
-  OSDMapRef osdmap;
-  const pg_pool_t pool;
-  PGLog log;
-  DoutPrefixProvider *dpp;
-  pg_shard_t pg_whoami;
-  std::set<pg_shard_t> shardset;
-  std::map<pg_shard_t, pg_info_t> shard_info;
-  std::map<pg_shard_t, pg_missing_t> shard_missing;
-  std::map<hobject_t, std::set<pg_shard_t>> missing_loc_shards;
-  pg_missing_tracker_t local_missing;
-
-  MockPGBackendListener(OSDMapRef osdmap, const pg_pool_t pi, DoutPrefixProvider *dpp, pg_shard_t pg_whoami) :
-    osdmap(osdmap), pool(pi), log(g_ceph_context), dpp(dpp), pg_whoami(pg_whoami) {}
-
-  // Debugging
-  DoutPrefixProvider *get_dpp() override {
-    return dpp;
-  }
-
-  // Recovery callbacks
-  void on_local_recover(
-    const hobject_t &oid,
-    const ObjectRecoveryInfo &recovery_info,
-    ObjectContextRef obc,
-    bool is_delete,
-    ObjectStore::Transaction *t) override {
-  }
-
-  void on_global_recover(
-    const hobject_t &oid,
-    const object_stat_sum_t &stat_diff,
-    bool is_delete) override {
-  }
-
-  void on_peer_recover(
-    pg_shard_t peer,
-    const hobject_t &oid,
-    const ObjectRecoveryInfo &recovery_info) override {
-  }
-
-  void begin_peer_recover(
-    pg_shard_t peer,
-    const hobject_t oid) override {
-  }
-
-  void apply_stats(
-    const hobject_t &soid,
-    const object_stat_sum_t &delta_stats) override {
-  }
-
-  void on_failed_pull(
-    const std::set<pg_shard_t> &from,
-    const hobject_t &soid,
-    const eversion_t &v) override {
-  }
-
-  void cancel_pull(const hobject_t &soid) override {
-  }
-
-  void remove_missing_object(
-    const hobject_t &oid,
-    eversion_t v,
-    Context *on_complete) override {
-  }
-
-  // Locking
-  void pg_lock() override {}
-  void pg_unlock() override {}
-  void pg_add_ref() override {}
-  void pg_dec_ref() override {}
-
-  // Context wrapping
-  Context *bless_context(Context *c) override {
-    return c;
-  }
-
-  GenContext<ThreadPool::TPHandle&> *bless_gencontext(
-    GenContext<ThreadPool::TPHandle&> *c) override {
-    return c;
-  }
-
-  GenContext<ThreadPool::TPHandle&> *bless_unlocked_gencontext(
-    GenContext<ThreadPool::TPHandle&> *c) override {
-    return c;
-  }
-
-  // Messaging
-  void send_message(int to_osd, Message *m) override {
-  }
-
-  void queue_transaction(
-    ObjectStore::Transaction&& t,
-    OpRequestRef op = OpRequestRef()) override {
-  }
-
-  void queue_transactions(
-    std::vector<ObjectStore::Transaction>& tls,
-    OpRequestRef op = OpRequestRef()) override {
-  }
-
-  epoch_t get_interval_start_epoch() const override {
-    return 1;
-  }
-
-  epoch_t get_last_peering_reset_epoch() const override {
-    return 1;
-  }
-
-  // Shard information
-  const std::set<pg_shard_t> &get_acting_recovery_backfill_shards() const override {
-    return shardset;
-  }
-
-  const std::set<pg_shard_t> &get_acting_shards() const override {
-    return shardset;
-  }
-
-  const std::set<pg_shard_t> &get_backfill_shards() const override {
-    return shardset;
-  }
-
-  std::ostream& gen_dbg_prefix(std::ostream& out) const override {
-    return out << "MockPGBackend ";
-  }
-
-  const std::map<hobject_t, std::set<pg_shard_t>> &get_missing_loc_shards() const override {
-    return missing_loc_shards;
-  }
-
-  const pg_missing_tracker_t &get_local_missing() const override {
-    return local_missing;
-  }
-
-  void add_local_next_event(const pg_log_entry_t& e) override {
-  }
-
-  const std::map<pg_shard_t, pg_missing_t> &get_shard_missing() const override {
-    return shard_missing;
-  }
-
-  const pg_missing_const_i &get_shard_missing(pg_shard_t peer) const override {
-    return local_missing;
-  }
-
-  const std::map<pg_shard_t, pg_info_t> &get_shard_info() const override {
-    return shard_info;
-  }
-
-  const PGLog &get_log() const override {
-    return log;
-  }
-
-  bool pgb_is_primary() const override {
-    return true;
-  }
-
-  const OSDMapRef& pgb_get_osdmap() const override {
-    return osdmap;
-  }
-
-  epoch_t pgb_get_osdmap_epoch() const override {
-    return osdmap->get_epoch();
-  }
-
-  const pg_info_t &get_info() const override {
-    return info;
-  }
-
-  const pg_pool_t &get_pool() const override {
-    return pool;
-  }
-
-  eversion_t get_pg_committed_to() const override {
-    return eversion_t();
-  }
-
-  ObjectContextRef get_obc(
-    const hobject_t &hoid,
-    const std::map<std::string, ceph::buffer::list, std::less<>> &attrs) override {
-    return ObjectContextRef();
-  }
-
-  bool try_lock_for_read(
-    const hobject_t &hoid,
-    ObcLockManager &manager) override {
-    return true;
-  }
-
-  void release_locks(ObcLockManager &manager) override {
-  }
-
-  void op_applied(const eversion_t &applied_version) override {
-  }
-
-  bool should_send_op(pg_shard_t peer, const hobject_t &hoid) override {
-    return true;
-  }
-
-  bool pg_is_undersized() const override {
-    return false;
-  }
-
-  bool pg_is_repair() const override {
-    return false;
-  }
-
-#if POOL_MIGRATION
-  void update_migration_watermark(const hobject_t &watermark) override {
-  }
-#endif
-
-#if POOL_MIGRATION
-  std::optional<hobject_t> consider_updating_migration_watermark(
-    std::set<hobject_t> &deleted) override {
-    return std::nullopt;
-  }
-#endif
-
-  void log_operation(
-    std::vector<pg_log_entry_t>&& logv,
-    const std::optional<pg_hit_set_history_t> &hset_history,
-    const eversion_t &trim_to,
-    const eversion_t &roll_forward_to,
-    const eversion_t &pg_committed_to,
-    bool transaction_applied,
-    ObjectStore::Transaction &t,
-    bool async = false) override {
-  }
-
-  void pgb_set_object_snap_mapping(
-    const hobject_t &soid,
-    const std::set<snapid_t> &snaps,
-    ObjectStore::Transaction *t) override {
-  }
-
-  void pgb_clear_object_snap_mapping(
-    const hobject_t &soid,
-    ObjectStore::Transaction *t) override {
-  }
-
-  void update_peer_last_complete_ondisk(
-    pg_shard_t fromosd,
-    eversion_t lcod) override {
-  }
-
-  void update_last_complete_ondisk(eversion_t lcod) override {
-  }
-
-  void update_pct(eversion_t pct) override {
-  }
-
-  void update_stats(const pg_stat_t &stat) override {
-  }
-
-  void schedule_recovery_work(
-    GenContext<ThreadPool::TPHandle&> *c,
-    uint64_t cost) override {
-  }
-
-  common::intrusive_timer &get_pg_timer() override {
-    ceph_abort("Not supported");
-  }
-
-  pg_shard_t whoami_shard() const override {
-    return pg_whoami;
-  }
-
-  spg_t primary_spg_t() const override {
-    return spg_t();
-  }
-
-  pg_shard_t primary_shard() const override {
-    return pg_shard_t();
-  }
-
-  uint64_t min_peer_features() const override {
-    return CEPH_FEATURES_ALL;
-  }
-
-  uint64_t min_upacting_features() const override {
-    return CEPH_FEATURES_ALL;
-  }
-
-  pg_feature_vec_t get_pg_acting_features() const override {
-    return pg_feature_vec_t();
-  }
-
-  hobject_t get_temp_recovery_object(
-    const hobject_t& target,
-    eversion_t version) override {
-    return hobject_t();
-  }
-
-  void send_message_osd_cluster(
-    int peer, Message *m, epoch_t from_epoch) override {
-  }
-
-  void send_message_osd_cluster(
-    std::vector<std::pair<int, Message*>>& messages, epoch_t from_epoch) override {
-  }
-
-  void send_message_osd_cluster(MessageRef, Connection *con) override {
-  }
-
-  void send_message_osd_cluster(Message *m, const ConnectionRef& con) override {
-  }
-
-  void start_mon_command(
-    std::vector<std::string>&& cmd, bufferlist&& inbl,
-    bufferlist *outbl, std::string *outs,
-    Context *onfinish) override {
-  }
-
-  ConnectionRef get_con_osd_cluster(int peer, epoch_t from_epoch) override {
-    return nullptr;
-  }
-
-  entity_name_t get_cluster_msgr_name() override {
-    return entity_name_t();
-  }
-
-  PerfCounters *get_logger() override {
-    return nullptr;
-  }
-
-  ceph_tid_t get_tid() override {
-    return 0;
-  }
-
-  OstreamTemp clog_error() override {
-    return OstreamTemp(CLOG_ERROR, nullptr);
-  }
-
-  OstreamTemp clog_warn() override {
-    return OstreamTemp(CLOG_WARN, nullptr);
-  }
-
-  bool check_failsafe_full() override {
-    return false;
-  }
-
-  void inc_osd_stat_repaired() override {
-  }
-
-  bool pg_is_remote_backfilling() override {
-    return false;
-  }
-
-  void pg_add_local_num_bytes(int64_t num_bytes) override {
-  }
-
-  void pg_sub_local_num_bytes(int64_t num_bytes) override {
-  }
-
-  void pg_add_num_bytes(int64_t num_bytes) override {
-  }
-
-  void pg_sub_num_bytes(int64_t num_bytes) override {
-  }
-
-  bool maybe_preempt_replica_scrub(const hobject_t& oid) override {
-    return false;
-  }
-
-  struct ECListener *get_eclistener() override {
-    return nullptr;
-  }
-};
-
-// MockPGBackend - simple stub for PGBackend
-class MockPGBackend : public PGBackend {
-public:
-  MockPGBackend(CephContext* cct, Listener *l, ObjectStore *store,
-                const coll_t &coll, ObjectStore::CollectionHandle &ch)
-    : PGBackend(cct, l, store, coll, ch) {}
-
-  // Recovery operations
-  RecoveryHandle *open_recovery_op() override {
-    return nullptr;
-  }
-
-  void run_recovery_op(RecoveryHandle *h, int priority) override {
-  }
-
-  int recover_object(
-    const hobject_t &hoid,
-    eversion_t v,
-    ObjectContextRef head,
-    ObjectContextRef obc,
-    RecoveryHandle *h) override {
-    return 0;
-  }
-
-  // Message handling
-  bool can_handle_while_inactive(OpRequestRef op) override {
-    return false;
-  }
-
-  bool _handle_message(OpRequestRef op) override {
-    return false;
-  }
-
-  void check_recovery_sources(const OSDMapRef& osdmap) override {
-  }
-
-  // State management
-  void on_change() override {
-  }
-
-  void clear_recovery_state() override {
-  }
-
-  // Predicates
-  IsPGRecoverablePredicate *get_is_recoverable_predicate() const override {
-    return nullptr;
-  }
-
-  IsPGReadablePredicate *get_is_readable_predicate() const override {
-    return nullptr;
-  }
-
-  bool get_ec_supports_crc_encode_decode() const override {
-    return false;
-  }
-
-  void dump_recovery_info(ceph::Formatter *f) const override {
-  }
-
-  bool ec_can_decode(const shard_id_set &available_shards) const override {
-    return false;
-  }
-
-  shard_id_map<bufferlist> ec_encode_acting_set(
-    const bufferlist &in_bl) const override {
-    return {0};
-  }
-
-  shard_id_map<bufferlist> ec_decode_acting_set(
-    const shard_id_map<bufferlist> &shard_map, int chunk_size) const override {
-    return {0};
-  }
-
-  ECUtil::stripe_info_t ec_get_sinfo() const override {
-    return {0, 0, 0};
-  }
-
-  // Transaction submission
-  void submit_transaction(
-    const hobject_t &hoid,
-    const object_stat_sum_t &delta_stats,
-    const eversion_t &at_version,
-    PGTransactionUPtr &&t,
-    const eversion_t &trim_to,
-    const eversion_t &pg_committed_to,
-    std::vector<pg_log_entry_t>&& log_entries,
-    std::optional<pg_hit_set_history_t> &hset_history,
-    Context *on_all_commit,
-    ceph_tid_t tid,
-    osd_reqid_t reqid,
-    OpRequestRef op) override {
-  }
-
-  void call_write_ordered(std::function<void(void)> &&cb) override {
-    cb();
-  }
-
-  // Object operations
-  int objects_read_sync(
-    const hobject_t &hoid,
-    uint64_t off,
-    uint64_t len,
-    uint32_t op_flags,
-    ceph::buffer::list *bl) override {
-    return 0;
-  }
-
-  void objects_read_async(
-    const hobject_t &hoid,
-    uint64_t object_size,
-    const std::list<std::pair<ec_align_t,
-      std::pair<ceph::buffer::list*, Context*>>> &to_read,
-    Context *on_complete, bool fast_read = false) override {
-  }
-
-  bool auto_repair_supported() const override {
-    return false;
-  }
-
-  uint64_t be_get_ondisk_size(uint64_t logical_size,
-                              shard_id_t shard_id,
-                              bool object_is_legacy_ec) const override {
-    return logical_size;
-  }
-
-  int be_deep_scrub(
-    const Scrub::ScrubCounterSet& io_counters,
-    const hobject_t &oid,
-    ScrubMap &map,
-    ScrubMapBuilder &pos,
-    ScrubMap::object &o) override {
-    return 0;
-  }
-};
-
-// MockPGLogEntryHandler
-//
-// This is a fully functional implementation of the PGLog::LogEntryHandler
-// interface. It calls code in PGBackend to perform the requested operations
-// although some of the stubs in MockPGBackend return questionable information
-// about the object size so the generated ObjectStore::Transaction is probably
-// not correct. The main purpose is to use partial_write to update the PWLC
-// information when appending entries to the log
-class MockPGLogEntryHandler : public PGLog::LogEntryHandler {
- public:
-  MockPGBackend *backend;
-  ObjectStore::Transaction *t;
-  MockPGLogEntryHandler(MockPGBackend *backend, ObjectStore::Transaction *t) : backend(backend), t(t) {}
-
-  // LogEntryHandler
-  void remove(const hobject_t &hoid) override {
-    dout(0) << "MockPGLogEntryHandler::remove " << hoid << dendl;
-    backend->remove(hoid, t);
-  }
-  void try_stash(const hobject_t &hoid, version_t v) override {
-    dout(0) << "MockPGLogEntryHandler::try_stash " << hoid << " " << v << dendl;
-    backend->try_stash(hoid, v, t);
-  }
-  void rollback(const pg_log_entry_t &entry) override {
-    dout(0) << "MockPGLogEntryHandler::rollback " << entry << dendl;
-    ceph_assert(entry.can_rollback());
-    backend->rollback(entry, t);
-  }
-  void rollforward(const pg_log_entry_t &entry) override {
-    dout(0) << "MockPGLogEntryHandler::rollforward " << entry << dendl;
-    backend->rollforward(entry, t);
-  }
-  void trim(const pg_log_entry_t &entry) override {
-    dout(0) << "MockPGLogEntryHandler::trim " << entry << dendl;
-    backend->trim(entry, t);
-  }
-  void partial_write(pg_info_t *info, eversion_t previous_version,
-                      const pg_log_entry_t &entry
-    ) override {
-    dout(0) << "MockPGLogEntryHandler::partial_write " << entry << dendl;
-    backend->partial_write(info, previous_version, entry);
-  }
-};
-
-// Mock PeeringListener - stub of PeeringState::PeeringListener
-// to help with testing of PeeringState. Keep track of calls
-// from PeeringState and emulate some of PrimaryLogPG/PG
-// functionality for testing purposes.
-//
-// There are some inject_* variables that can be used to help
-// tests create race hazards or test failure paths
-class MockPeeringListener : public PeeringState::PeeringListener {
- public:
-  pg_shard_t pg_whoami;
-  MockLog logger;
-  PeeringState *ps;
-  unique_ptr<MockPGBackendListener> backend_listener;
-  coll_t coll;
-  ObjectStore::CollectionHandle ch;
-  unique_ptr<MockPGBackend> backend;
-  PerfCounters* recoverystate_perf;
-  PerfCounters* logger_perf;
-  std::vector<int> next_acting;
-
-#ifdef WITH_CRIMSON
-  // Per OSD state
-  std::map<int,std::list<MessageURef>> messages;
-#else
-  // Per OSD state
-  std::map<int,std::list<MessageRef>> messages;
-#endif
-  std::vector<HeartbeatStampsRef> hb_stamps;
-  std::list<PGPeeringEventRef> events;
-  std::list<PGPeeringEventRef> stalled_events;
-
-  // By default MockPeeringListener will add events to the event queue immediately
-  // simulating the responses that PrimaryLogPG normally generates. These inject
-  // booleans can change the behavior to test other code paths
-
-  // If inject_event_stall is true then events are added to the stalled_events list
-  // and the test case must manually dispatch the event
-  bool inject_event_stall = false;
-
-  // If inject_keep_preempt is true then the preempt event for a local/remote
-  // reservation is added to the stalled_events list so the test case can later
-  // dispatch this event to test a preempted reservation
-  bool inject_keep_preempt = false;
-
-  // If inject_fail_reserve_recovery_space is true then reject backfill/pool
-  // migration requests with too full
-  bool inject_fail_reserve_recovery_space = false;
-
-  MockPeeringListener(OSDMapRef osdmap,
-                      const pg_pool_t pi,
-                      DoutPrefixProvider *dpp,
-                      pg_shard_t pg_whoami) : pg_whoami(pg_whoami) {
-    backend_listener = make_unique<MockPGBackendListener>(osdmap, pi, dpp, pg_whoami);
-    backend = make_unique<MockPGBackend>(g_ceph_context, backend_listener.get(), nullptr, coll, ch);
-    recoverystate_perf = build_recoverystate_perf(g_ceph_context);
-    g_ceph_context->get_perfcounters_collection()->add(recoverystate_perf);
-    logger_perf = build_osd_logger(g_ceph_context);
-    g_ceph_context->get_perfcounters_collection()->add(logger_perf);
-  }
-
-  // EpochSource interface
-  epoch_t get_osdmap_epoch() const override {
-    return current_epoch;
-  }
-
-  // PeeringListener interface
-  void prepare_write(
-    pg_info_t &info,
-    pg_info_t &last_written_info,
-    PastIntervals &past_intervals,
-    PGLog &pglog,
-    bool dirty_info,
-    bool dirty_big_info,
-    bool need_write_epoch,
-    ObjectStore::Transaction &t) override {
-    prepare_write_called = true;
-  }
-
-  void scrub_requested(scrub_level_t scrub_level, scrub_type_t scrub_type) override {
-    scrub_requested_called = true;
-  }
-
-  uint64_t get_snap_trimq_size() const override {
-    return snap_trimq_size;
-  }
-
-#ifdef WITH_CRIMSON
-  void send_cluster_message(
-    int osd, MessageURef m, epoch_t epoch, bool share_map_update=false) override {
-    dout(0) << "send_cluster_message to " << osd << " " << m << dendl;
-    messages[osd].push_back(m);
-    messages_sent++;
-  }
-#else
-  void send_cluster_message(
-    int osd, MessageRef m, epoch_t epoch, bool share_map_update=false) override {
-    dout(0) << "send_cluster_message to " << osd << " " << m << dendl;
-    messages[osd].push_back(m);
-    messages_sent++;
-  }
-#endif
-
-  void send_pg_created(pg_t pgid) override {
-    pg_created_sent = true;
-  }
-  ceph::signedspan get_mnow() const override {
-    return ceph::signedspan::zero();
-  }
-
-  HeartbeatStampsRef get_hb_stamps(int peer) override {
-    if (peer >= (int)hb_stamps.size()) {
-      hb_stamps.resize(peer + 1);
-    }
-    if (!hb_stamps[peer]) {
-      hb_stamps[peer] = ceph::make_ref<HeartbeatStamps>(peer);
-    }
-    return hb_stamps[peer];
-  }
-
-  void schedule_renew_lease(epoch_t plr, ceph::timespan delay) override {
-    renew_lease_scheduled = true;
-  }
-
-  void queue_check_readable(epoch_t lpr, ceph::timespan delay) override {
-    check_readable_queued = true;
-  }
-
-  void recheck_readable() override {
-    readable_rechecked = true;
-  }
-
-  unsigned get_target_pg_log_entries() const override {
-    return target_pg_log_entries;
-  }
-
-
-  bool try_flush_or_schedule_async() override {
-    return true;
-  }
-
-  void start_flush_on_transaction(ObjectStore::Transaction &t) override {
-    flush_started = true;
-  }
-
-  void on_flushed() override {
-    flushed = true;
-  }
-
-  void schedule_event_after(
-    PGPeeringEventRef event,
-    float delay) override {
-    stalled_events.push_back(std::move(event));
-    events_scheduled++;
-  }
-
-  void request_local_background_io_reservation(
-    unsigned priority,
-    PGPeeringEventURef on_grant,
-    PGPeeringEventURef on_preempt) override {
-    if (inject_event_stall) {
-      stalled_events.push_back(std::move(on_grant));
-    } else {
-      events.push_back(std::move(on_grant));
-    }
-    if (inject_keep_preempt) {
-      stalled_events.push_back(std::move(on_preempt));
-    }
-    io_reservations_requested++;
-  }
-
-  void update_local_background_io_priority(
-    unsigned priority) override {
-    io_priority_updated = true;
-  }
-
-  void cancel_local_background_io_reservation() override {
-    io_reservation_cancelled = true;
-  }
-
-  void request_remote_recovery_reservation(
-    unsigned priority,
-    PGPeeringEventURef on_grant,
-    PGPeeringEventURef on_preempt) override {
-    if (inject_event_stall) {
-      stalled_events.push_back(std::move(on_grant));
-    } else {
-      events.push_back(std::move(on_grant));
-    }
-    if (inject_keep_preempt) {
-      stalled_events.push_back(std::move(on_preempt));
-    }
-    remote_recovery_reservations_requested++;
-  }
-
-  void cancel_remote_recovery_reservation() override {
-    remote_recovery_reservation_cancelled = true;
-  }
-
-  void schedule_event_on_commit(
-    ObjectStore::Transaction &t,
-    PGPeeringEventRef on_commit) override {
-    if (inject_event_stall) {
-      stalled_events.push_back(std::move(on_commit));
-    } else {
-      events.push_back(std::move(on_commit));
-    }
-    events_on_commit_scheduled++;
-  }
-
-  void update_heartbeat_peers(std::set<int> peers) override {
-    heartbeat_peers_updated = true;
-  }
-
-  void set_probe_targets(const std::set<pg_shard_t> &probe_set) override {
-    probe_targets_set = true;
-  }
-
-  void clear_probe_targets() override {
-    probe_targets_cleared = true;
-  }
-
-  void queue_want_pg_temp(const std::vector<int> &wanted) override {
-    pg_temp_wanted = true;
-    next_acting = wanted;
-  }
-
-  void clear_want_pg_temp() override {
-    pg_temp_cleared = true;
-  }
-
-#if POOL_MIGRATION
-  void send_pg_migrated_pool() override {
-    pg_migrated_pool_sent = true;
-  }
-#endif
-
-  void publish_stats_to_osd() override {
-    stats_published = true;
-  }
-
-  void clear_publish_stats() override {
-    stats_cleared = true;
-  }
-
-  void check_recovery_sources(const OSDMapRef& newmap) override {
-    recovery_sources_checked = true;
-  }
-
-  void check_blocklisted_watchers() override {
-    blocklisted_watchers_checked = true;
-  }
-
-  void clear_primary_state() override {
-    primary_state_cleared = true;
-  }
-
-  void on_active_exit() override {
-    active_exited = true;
-  }
-
-  void on_active_actmap() override {
-    active_actmap_called = true;
-  }
-
-  void on_active_advmap(const OSDMapRef &osdmap) override {
-    active_advmap_called = true;
-  }
-
-  void on_backfill_reserved() override {
-    backfill_reserved = true;
-  }
-
-  void on_recovery_reserved() override {
-    recovery_reserved = true;
-  }
-
-  Context *on_clean() override {
-    clean_called = true;
-    return nullptr;
-  }
-
-  void on_activate(interval_set<snapid_t> snaps) override {
-    activate_called = true;
-  }
-
-  void on_change(ObjectStore::Transaction &t) override {
-    first_write_in_interval = true;
-    change_called = true;
-  }
-
-  std::pair<ghobject_t, bool> do_delete_work(
-    ObjectStore::Transaction &t, ghobject_t _next) override {
-    delete_work_done = true;
-    return std::make_pair(ghobject_t(), true);
-  }
-
-  void clear_ready_to_merge() override {
-    ready_to_merge_cleared = true;
-  }
-
-  void set_not_ready_to_merge_target(pg_t pgid, pg_t src) override {
-    not_ready_to_merge_target_set = true;
-  }
-
-  void set_not_ready_to_merge_source(pg_t pgid) override {
-    not_ready_to_merge_source_set = true;
-  }
-
-  void set_ready_to_merge_target(eversion_t lu, epoch_t les, epoch_t lec) override {
-    ready_to_merge_target_set = true;
-  }
-
-  void set_ready_to_merge_source(eversion_t lu) override {
-    ready_to_merge_source_set = true;
-  }
-
-  epoch_t cluster_osdmap_trim_lower_bound() override {
-    return 1;
-  }
-
-  void on_backfill_suspended() override {
-    backfill_suspended = true;
-  }
-
-  void on_recovery_cancelled() override {
-    recovery_cancelled = true;
-  }
-
-#if POOL_MIGRATION
-  void on_pool_migration_reserved() override {
-    pool_migration_reserved = true;
-  }
-#endif
-
-#if POOL_MIGRATION
-  void on_pool_migration_suspended() override {
-    pool_migration_suspended = true;
-  }
-#endif
-
-  bool try_reserve_recovery_space(
-    int64_t primary_num_bytes,
-    int64_t local_num_bytes) override {
-    recovery_space_reserved = true;
-    if (inject_fail_reserve_recovery_space) {
-      return false;
-    }
-    return true;
-  }
-
-  void unreserve_recovery_space() override {
-    recovery_space_unreserved = true;
-  }
-
-  PGLog::LogEntryHandlerRef get_log_handler(
-    ObjectStore::Transaction &t) override {
-    return std::make_unique<MockPGLogEntryHandler>(backend.get(), &t);
-  }
-
-  void rebuild_missing_set_with_deletes(PGLog &pglog) override {
-    missing_set_rebuilt = true;
-  }
-
-  PerfCounters &get_peering_perf() override {
-    return *recoverystate_perf;
-  }
-
-  PerfCounters &get_perf_logger() override {
-    return *logger_perf;
-  }
-
-  void log_state_enter(const char *state) override {
-    last_state_entered = string(state);
-    state_entered = true;
-  }
-
-  void log_state_exit(
-    const char *state_name, utime_t enter_time,
-    uint64_t events, utime_t event_dur) override {
-    last_state_exited = string(state_name);
-    state_exited = true;
-  }
-
-  void dump_recovery_info(ceph::Formatter *f) const override {
-    recovery_info_dumped = true;
-  }
-
-  OstreamTemp get_clog_info() override {
-    return logger.info();
-  }
-
-  OstreamTemp get_clog_error() override {
-    return logger.error();
-  }
-
-  OstreamTemp get_clog_debug() override {
-    return logger.debug();
-  }
-
-  void on_activate_complete() override {
-    dout(0) << __func__ << dendl;
-    std::list<PGPeeringEventRef> *event_queue;
-    if (inject_event_stall) {
-      event_queue = &stalled_events;
-    } else {
-      event_queue = &events;
-    }
-
-    if (ps->needs_recovery()) {
-      dout(10) << "activate not all replicas are up-to-date, queueing recovery" << dendl;
-      event_queue->push_back(
-          std::make_shared<PGPeeringEvent>(
-            get_osdmap_epoch(),
-            get_osdmap_epoch(),
-            PeeringState::DoRecovery()));
-    } else if (ps->needs_backfill()) {
-      dout(10) << "activate queueing backfill" << dendl;
-      event_queue->push_back(
-          std::make_shared<PGPeeringEvent>(
-            get_osdmap_epoch(),
-            get_osdmap_epoch(),
-            PeeringState::RequestBackfill()));
-#if POOL_MIGRATION
-    } else if (ps->needs_pool_migration()) {
-      dout(10) << "activate queueing pool migration" << dendl;
-      event_queue->push_back(
-          std::make_shared<PGPeeringEvent>(
-            get_osdmap_epoch(),
-            get_osdmap_epoch(),
-            PeeringState::DoPoolMigration()));
-#endif
-    } else {
-      dout(10) << "activate all replicas clean, no recovery" << dendl;
-      event_queue->push_back(
-          std::make_shared<PGPeeringEvent>(
-            get_osdmap_epoch(),
-            get_osdmap_epoch(),
-            PeeringState::AllReplicasRecovered()));
-    }
-    activate_complete_called = true;
-  }
-
-  void on_activate_committed() override {
-    activate_committed_called = true;
-  }
-
-  void on_new_interval() override {
-    new_interval_called = true;
-  }
-
-  void on_pool_change() override {
-    pool_changed = true;
-  }
-
-  void on_role_change() override {
-    role_changed = true;
-  }
-
-  void on_removal(ObjectStore::Transaction &t) override {
-    removal_called = true;
-  }
-
-  // Test state tracking
-  unsigned target_pg_log_entries = 100;
-  bool renew_lease_scheduled = false;
-  bool check_readable_queued = false;
-  bool readable_rechecked = false;
-  bool heartbeat_peers_updated = false;
-  bool probe_targets_set = false;
-  bool probe_targets_cleared = false;
-  bool pg_temp_wanted = false;
-  bool pg_temp_cleared = false;
-  bool pg_migrated_pool_sent = false;
-  bool stats_published = false;
-  bool stats_cleared = false;
-  bool recovery_sources_checked = false;
-  bool blocklisted_watchers_checked = false;
-  bool primary_state_cleared = false;
-  bool delete_work_done = false;
-  bool ready_to_merge_cleared = false;
-  bool not_ready_to_merge_target_set = false;
-  bool not_ready_to_merge_source_set = false;
-  bool ready_to_merge_target_set = false;
-  bool ready_to_merge_source_set = false;
-  bool backfill_suspended = false;
-  bool recovery_cancelled = false;
-  bool pool_migration_reserved = false;
-  bool pool_migration_suspended = false;
-  bool recovery_space_reserved = false;
-  bool recovery_space_unreserved = false;
-  bool missing_set_rebuilt = false;
-  string last_state_entered;
-  bool state_entered = false;
-  string last_state_exited;
-  bool state_exited = false;
-  mutable bool recovery_info_dumped = false;
-  epoch_t current_epoch = 1;
-  uint64_t snap_trimq_size = 0;
-  bool prepare_write_called = false;
-  bool scrub_requested_called = false;
-  bool pg_created_sent = false;
-  bool flush_started = false;
-  bool flushed = false;
-  bool io_priority_updated = false;
-  bool io_reservation_cancelled = false;
-  bool remote_recovery_reservation_cancelled = false;
-  bool active_exited = false;
-  bool active_actmap_called = false;
-  bool active_advmap_called = false;
-  bool backfill_reserved = false;
-  bool backfill_cancelled = false;
-  bool recovery_reserved = false;
-  bool clean_called = false;
-  bool activate_called = false;
-  bool activate_complete_called = false;
-  bool change_called = false;
-  bool activate_committed_called = false;
-  bool new_interval_called = false;
-  bool primary_status_changed = false;
-  bool pool_changed = false;
-  bool role_changed = false;
-  bool removal_called = false;
-  bool shutdown_called = false;
-  int messages_sent = 0;
-  int events_scheduled = 0;
-  int io_reservations_requested = 0;
-  int remote_recovery_reservations_requested = 0;
-  int events_on_commit_scheduled = 0;
-  bool first_write_in_interval = false;
-};
 
 // Test fixture for PeeringState tests
 class PeeringStateTest : public ::testing::Test {