chromium/chrome/browser/nearby_sharing/nearby_receive_manager_unittest.cc

// Copyright 2020 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/nearby_sharing/nearby_receive_manager.h"

#include <optional>

#include "base/test/bind.h"
#include "base/test/mock_callback.h"
#include "chrome/browser/nearby_sharing/mock_nearby_sharing_service.h"
#include "chrome/browser/nearby_sharing/share_target.h"
#include "chrome/browser/ui/webui/nearby_share/nearby_share.mojom-test-utils.h"
#include "chrome/browser/ui/webui/nearby_share/nearby_share.mojom.h"
#include "content/public/test/browser_task_environment.h"
#include "mojo/public/cpp/bindings/receiver.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"

namespace {

class FakeReceiveObserver : public nearby_share::mojom::ReceiveObserver {
 public:
  void OnHighVisibilityChanged(bool in_high_visibility) override {
    in_high_visibility_ = in_high_visibility;
  }

  void OnTransferUpdate(
      const ShareTarget& share_target,
      nearby_share::mojom::TransferMetadataPtr metadata) override {
    last_share_target_ = share_target;
    last_metadata_ = *metadata;
  }

  void OnNearbyProcessStopped() override {
    on_nearby_process_stopped_called_ = true;
  }

  void OnStartAdvertisingFailure() override {
    on_start_advertising_failure_called_ = true;
  }

  std::optional<nearby_share::mojom::TransferMetadata> last_metadata_;
  std::optional<bool> in_high_visibility_;
  ShareTarget last_share_target_;
  bool on_nearby_process_stopped_called_ = false;
  bool on_start_advertising_failure_called_ = false;
  mojo::Receiver<nearby_share::mojom::ReceiveObserver> receiver_{this};
};

class NearbyReceiveManagerTest : public testing::Test {
 public:
  using ReceiveSurfaceState = NearbySharingService::ReceiveSurfaceState;
  using StatusCodes = NearbySharingService::StatusCodes;
  using RegisterReceiveSurfaceResult =
      nearby_share::mojom::RegisterReceiveSurfaceResult;

  NearbyReceiveManagerTest()
      : transfer_metadata_(TransferMetadata::Status::kAwaitingLocalConfirmation,
                           /*progress=*/0.f,
                           /*token=*/"1234",
                           /*is_original=*/true,
                           /*is_final_status=*/false) {
    share_target_.id = base::UnguessableToken::Create();
    receive_manager_.AddReceiveObserver(
        observer_.receiver_.BindNewPipeAndPassRemote());
  }

  ~NearbyReceiveManagerTest() override = default;

 protected:
  void FlushMojoMessages() { observer_.receiver_.FlushForTesting(); }

  void ExpectRegister(StatusCodes code = StatusCodes::kOk) {
    EXPECT_CALL(sharing_service_,
                RegisterReceiveSurface(testing::_, testing::_))
        .WillOnce([=](TransferUpdateCallback* transfer_callback,
                      ReceiveSurfaceState state) {
          EXPECT_EQ(ReceiveSurfaceState::kForeground, state);
          return code;
        });
  }

  void ExpectUnregister(StatusCodes code = StatusCodes::kOk) {
    EXPECT_CALL(sharing_service_, UnregisterReceiveSurface(testing::_))
        .WillOnce(
            [=](TransferUpdateCallback* transfer_callback) { return code; });
  }

  void ExpectIsInHighVisibility(bool in_high_visibility) {
    EXPECT_CALL(sharing_service_, IsInHighVisibility())
        .WillOnce(testing::Return(in_high_visibility));
  }

  void ExpectAccept(StatusCodes code = StatusCodes::kOk) {
    EXPECT_CALL(sharing_service_, Accept(testing::_, testing::_))
        .WillOnce([=](const ShareTarget& share_target,
                      NearbySharingService::StatusCodesCallback
                          status_codes_callback) {
          std::move(status_codes_callback).Run(code);
        });
  }

  void ExpectReject(StatusCodes code = StatusCodes::kOk) {
    EXPECT_CALL(sharing_service_, Reject(testing::_, testing::_))
        .WillOnce([=](const ShareTarget& share_target,
                      NearbySharingService::StatusCodesCallback
                          status_codes_callback) {
          std::move(status_codes_callback).Run(code);
        });
  }

  content::BrowserTaskEnvironment task_environment_;
  ShareTarget share_target_;
  TransferMetadata transfer_metadata_;
  MockNearbySharingService sharing_service_;
  FakeReceiveObserver observer_;
  NearbyReceiveManager receive_manager_{&sharing_service_};
  nearby_share::mojom::ReceiveManagerAsyncWaiter receive_manager_waiter_{
      &receive_manager_};
};

}  // namespace

TEST_F(NearbyReceiveManagerTest, Enter_Exit_Success) {
  ExpectRegister();
  RegisterReceiveSurfaceResult result = RegisterReceiveSurfaceResult::kFailure;
  receive_manager_waiter_.RegisterForegroundReceiveSurface(&result);
  EXPECT_EQ(RegisterReceiveSurfaceResult::kSuccess, result);

  ExpectUnregister();
  bool exited = false;
  receive_manager_waiter_.UnregisterForegroundReceiveSurface(&exited);
  EXPECT_TRUE(exited);

  ExpectUnregister();
}

TEST_F(NearbyReceiveManagerTest, Enter_Failed) {
  RegisterReceiveSurfaceResult result = RegisterReceiveSurfaceResult::kSuccess;
  ExpectRegister(StatusCodes::kError);
  receive_manager_waiter_.RegisterForegroundReceiveSurface(&result);
  EXPECT_EQ(RegisterReceiveSurfaceResult::kFailure, result);
  ExpectUnregister();
}

TEST_F(NearbyReceiveManagerTest, Multiple_Enter_Successful) {
  RegisterReceiveSurfaceResult result = RegisterReceiveSurfaceResult::kFailure;
  ExpectRegister(StatusCodes::kOk);
  receive_manager_waiter_.RegisterForegroundReceiveSurface(&result);
  FlushMojoMessages();
  EXPECT_EQ(RegisterReceiveSurfaceResult::kSuccess, result);

  result = RegisterReceiveSurfaceResult::kFailure;
  ExpectRegister(StatusCodes::kOk);
  receive_manager_waiter_.RegisterForegroundReceiveSurface(&result);
  FlushMojoMessages();
  EXPECT_EQ(RegisterReceiveSurfaceResult::kSuccess, result);

  ExpectUnregister();
}

TEST_F(NearbyReceiveManagerTest, Exit_Failed) {
  RegisterReceiveSurfaceResult result = RegisterReceiveSurfaceResult::kFailure;
  ExpectRegister();
  receive_manager_waiter_.RegisterForegroundReceiveSurface(&result);
  EXPECT_EQ(RegisterReceiveSurfaceResult::kSuccess, result);

  ExpectUnregister(StatusCodes::kError);
  bool exited = false;
  receive_manager_waiter_.UnregisterForegroundReceiveSurface(&exited);
  EXPECT_FALSE(exited);

  ExpectUnregister();
}

TEST_F(NearbyReceiveManagerTest, ShareTargetNotifies_Accept) {
  receive_manager_.OnTransferUpdate(share_target_, transfer_metadata_);
  FlushMojoMessages();
  EXPECT_EQ(share_target_.id, observer_.last_share_target_.id);
  ASSERT_TRUE(observer_.last_metadata_.has_value());
  EXPECT_EQ("1234", observer_.last_metadata_->token);

  ExpectAccept();
  bool success = false;
  receive_manager_waiter_.Accept(share_target_.id, &success);
  EXPECT_TRUE(success);

  ExpectUnregister();
}

TEST_F(NearbyReceiveManagerTest, ShareTargetNotifies_Reject) {
  receive_manager_.OnTransferUpdate(share_target_, transfer_metadata_);
  FlushMojoMessages();
  EXPECT_EQ(share_target_.id, observer_.last_share_target_.id);
  ASSERT_TRUE(observer_.last_metadata_.has_value());
  EXPECT_EQ("1234", observer_.last_metadata_->token);

  ExpectReject();
  bool success = false;
  receive_manager_waiter_.Reject(share_target_.id, &success);
  EXPECT_TRUE(success);

  ExpectUnregister();
}

TEST_F(NearbyReceiveManagerTest,
       ShareTargetNotifies_SenderCancelsBeforeAccept) {
  receive_manager_.OnTransferUpdate(share_target_, transfer_metadata_);
  FlushMojoMessages();
  EXPECT_EQ(share_target_.id, observer_.last_share_target_.id);
  ASSERT_TRUE(observer_.last_metadata_.has_value());
  EXPECT_EQ("1234", observer_.last_metadata_->token);

  // Simulate the sender canceling before we accept the share target and causing
  // the accept to fail before hitting the service.
  TransferMetadata transfer_metadata_final(TransferMetadata::Status::kCancelled,
                                           1.f, std::nullopt, true, true);
  receive_manager_.OnTransferUpdate(share_target_, transfer_metadata_final);
  FlushMojoMessages();

  bool success = true;
  receive_manager_waiter_.Accept(share_target_.id, &success);
  EXPECT_FALSE(success);

  ExpectUnregister();
}

TEST_F(NearbyReceiveManagerTest,
       ShareTargetNotifies_SenderCancelsBeforeReject) {
  receive_manager_.OnTransferUpdate(share_target_, transfer_metadata_);
  FlushMojoMessages();
  EXPECT_EQ(share_target_.id, observer_.last_share_target_.id);
  ASSERT_TRUE(observer_.last_metadata_.has_value());
  EXPECT_EQ("1234", observer_.last_metadata_->token);

  // Simulate the sender canceling before we reject the share target and causing
  // the reject to fail before hitting the service.
  TransferMetadata transfer_metadata_final(TransferMetadata::Status::kCancelled,
                                           1.f, std::nullopt, true, true);
  receive_manager_.OnTransferUpdate(share_target_, transfer_metadata_final);
  FlushMojoMessages();

  bool success = true;
  receive_manager_waiter_.Reject(share_target_.id, &success);
  EXPECT_FALSE(success);

  ExpectUnregister();
}

TEST_F(NearbyReceiveManagerTest, IsInHighVisibility) {
  ExpectIsInHighVisibility(true);
  bool on = false;
  receive_manager_waiter_.IsInHighVisibility(&on);
  FlushMojoMessages();
  EXPECT_TRUE(on);

  ExpectIsInHighVisibility(false);
  on = true;
  receive_manager_waiter_.IsInHighVisibility(&on);
  FlushMojoMessages();
  EXPECT_FALSE(on);

  ExpectUnregister();
}

TEST_F(NearbyReceiveManagerTest, OnHighVisibilityChangedObserver) {
  receive_manager_.OnHighVisibilityChanged(false);
  FlushMojoMessages();
  ASSERT_TRUE(observer_.in_high_visibility_.has_value());
  EXPECT_FALSE(*observer_.in_high_visibility_);

  observer_.in_high_visibility_ = std::nullopt;

  receive_manager_.OnHighVisibilityChanged(true);
  FlushMojoMessages();
  ASSERT_TRUE(observer_.in_high_visibility_.has_value());
  EXPECT_TRUE(*observer_.in_high_visibility_);

  ExpectUnregister();
}

TEST_F(NearbyReceiveManagerTest, OnStartAdvertisingFailureObserver) {
  EXPECT_FALSE(observer_.on_start_advertising_failure_called_);
  receive_manager_.OnStartAdvertisingFailure();
  FlushMojoMessages();
  EXPECT_TRUE(observer_.on_start_advertising_failure_called_);

  ExpectUnregister();
}