text: // Copyright 2022 The Fuchsia Authors. All rights reserved.
  // Use of this source code is governed by a BSD-style license that can be
  // found in the LICENSE file.
  
  #ifndef SRC_STORAGE_TESTING_FAKE_PAVER_H_
  #define SRC_STORAGE_TESTING_FAKE_PAVER_H_
  
  #include <fidl/fuchsia.device/cpp/wire.h>
  #include <fidl/fuchsia.paver/cpp/wire.h>
  #include <lib/async-loop/cpp/loop.h>
  #include <lib/async/dispatcher.h>
  #include <lib/fidl-async/cpp/bind.h>
  #include <lib/sync/completion.h>
  #include <lib/zircon-internal/thread_annotations.h>
  #include <threads.h>
  #include <zircon/errors.h>
  #include <zircon/time.h>
  
  #include <algorithm>
  #include <memory>
  #include <vector>
  
  #include <fbl/auto_lock.h>
  #include <fbl/mutex.h>
  #include <zxtest/zxtest.h>
  
  namespace paver_test {
  
  enum class Command {
    kUnknown,
    kInitializeAbr,
    kQueryCurrentConfiguration,
    kQueryActiveConfiguration,
    kQueryConfigurationLastSetActive,
    kQueryConfigurationStatus,
    kSetConfigurationActive,
    kSetConfigurationUnbootable,
    kSetConfigurationHealthy,
    kReadAsset,
    kWriteAsset,
    kWriteFirmware,
    kWriteVolumes,
    kWriteBootloader,
    kWriteDataFile,
    kWipeVolume,
    kInitPartitionTables,
    kWipePartitionTables,
    kDataSinkFlush,
    kBootManagerFlush,
  };
  
  struct AbrSlotData {
    bool unbootable;
    bool active;
  };
  
  struct AbrData {
    AbrSlotData slot_a;
    AbrSlotData slot_b;
  };
  
  constexpr AbrData kInitAbrData = {
      .slot_a =
          {
              .unbootable = false,
              .active = false,
          },
      .slot_b =
          {
              .unbootable = false,
              .active = false,
          },
  };
  
  class FakePaver : public fidl::WireServer<fuchsia_paver::Paver>,
                    public fidl::WireServer<fuchsia_paver::BootManager>,
                    public fidl::WireServer<fuchsia_paver::DynamicDataSink> {
   public:
    zx_status_t Connect(async_dispatcher_t* dispatcher,
                        fidl::ServerEnd<fuchsia_paver::Paver> request);
  
    void FindDataSink(FindDataSinkRequestView request,
                      FindDataSinkCompleter::Sync& _completer) override;
  
    void UseBlockDevice(UseBlockDeviceRequestView request,
                        UseBlockDeviceCompleter::Sync& _completer) override;
  
    void FindBootManager(FindBootManagerRequestView request,
                         FindBootManagerCompleter::Sync& _completer) override;
  
    void QueryCurrentConfiguration(QueryCurrentConfigurationRequestView request,
                                   QueryCurrentConfigurationCompleter::Sync& completer) override;
  
    void FindSysconfig(FindSysconfigRequestView request,
                       FindSysconfigCompleter::Sync& _completer) override;
  
    void QueryActiveConfiguration(QueryActiveConfigurationRequestView request,
                                  QueryActiveConfigurationCompleter::Sync& completer) override;
  
    void QueryConfigurationLastSetActive(
        QueryConfigurationLastSetActiveRequestView request,
        QueryConfigurationLastSetActiveCompleter::Sync& completer) override;
  
    void QueryConfigurationStatus(QueryConfigurationStatusRequestView request,
                                  QueryConfigurationStatusCompleter::Sync& completer) override;
  
    void SetConfigurationActive(SetConfigurationActiveRequestView request,
                                SetConfigurationActiveCompleter::Sync& completer) override;
  
    void SetConfigurationUnbootable(SetConfigurationUnbootableRequestView request,
                                    SetConfigurationUnbootableCompleter::Sync& completer) override;
  
    void SetConfigurationHealthy(SetConfigurationHealthyRequestView request,
                                 SetConfigurationHealthyCompleter::Sync& completer) override;
  
    void Flush(
        fidl::WireServer<fuchsia_paver::DynamicDataSink>::FlushRequestView request,
        fidl::WireServer<fuchsia_paver::DynamicDataSink>::FlushCompleter::Sync& completer) override;
  
    void Flush(
        fidl::WireServer<fuchsia_paver::BootManager>::FlushRequestView request,
        fidl::WireServer<fuchsia_paver::BootManager>::FlushCompleter::Sync& completer) override;
  
    void ReadAsset(ReadAssetRequestView request, ReadAssetCompleter::Sync& completer) override;
  
    void WriteAsset(WriteAssetRequestView request, WriteAssetCompleter::Sync& completer) override;
  
    void WriteFirmware(WriteFirmwareRequestView request,
                       WriteFirmwareCompleter::Sync& completer) override;
  
    void WriteVolumes(WriteVolumesRequestView request,
                      WriteVolumesCompleter::Sync& completer) override;
  
    void WriteBootloader(WriteBootloaderRequestView request,
                         WriteBootloaderCompleter::Sync& completer) override;
  
    void WriteDataFile(WriteDataFileRequestView request,
                       WriteDataFileCompleter::Sync& completer) override;
  
    void WipeVolume(WipeVolumeRequestView request, WipeVolumeCompleter::Sync& completer) override;
  
    void InitializePartitionTables(InitializePartitionTablesRequestView request,
                                   InitializePartitionTablesCompleter::Sync& completer) override;
  
    void WipePartitionTables(WipePartitionTablesRequestView request,
                             WipePartitionTablesCompleter::Sync& completer) override;
  
    void WaitForWritten(size_t size);
  
    const std::vector<Command> GetCommandTrace();
  
    std::string last_firmware_type() const;
    fuchsia_paver::wire::Configuration last_firmware_config() const;
    fuchsia_paver::wire::Configuration last_asset_config() const;
    fuchsia_paver::wire::Asset last_asset() const;
  
    void set_expected_payload_size(size_t size) { expected_payload_size_ = size; }
    void set_supported_firmware_type(std::string type);
    void set_abr_supported(bool supported) { abr_supported_ = supported; }
    void set_wait_for_start_signal(bool wait) { wait_for_start_signal_ = wait; }
    void set_expected_device(std::string expected);
  
    const AbrData abr_data();
  
   private:
    std::atomic<bool> wait_for_start_signal_ = false;
    sync_completion_t start_signal_;
    sync_completion_t done_signal_;
    std::atomic<size_t> signal_size_;
  
    mutable fbl::Mutex lock_;
  
    std::string last_firmware_type_ TA_GUARDED(lock_);
    fuchsia_paver::wire::Asset last_asset_ TA_GUARDED(lock_);
    fuchsia_paver::wire::Configuration last_firmware_config_ TA_GUARDED(lock_);
    fuchsia_paver::wire::Configuration last_asset_config_ TA_GUARDED(lock_);
  
    std::atomic<size_t> expected_payload_size_ = 0;
    std::string expected_block_device_ TA_GUARDED(lock_);
    std::string supported_firmware_type_ TA_GUARDED(lock_);
    std::atomic<bool> abr_supported_ = false;
    AbrData abr_data_ TA_GUARDED(lock_) = kInitAbrData;
  
    std::atomic<async_dispatcher_t*> dispatcher_ = nullptr;
  
    std::vector<Command> command_trace_ TA_GUARDED(lock_);
    void AppendCommand(Command cmd) TA_REQ(lock_) { command_trace_.push_back(cmd); }
  };
  
  }  // namespace paver_test
  
  #endif  // SRC_STORAGE_TESTING_FAKE_PAVER_H_
  